From 1b58f2592ca2feca3796803918d43b2cb1c2d6c1 Mon Sep 17 00:00:00 2001 From: Quantum Date: Wed, 1 Sep 2021 22:27:36 -0400 Subject: [PATCH] [client] egl: make filters damage aware This saves a lot of GPU power for partial updates. Running testufo with lanczos downscaling and FSR upscaling consumed over 90 W, but with this commit, consumed only 75 W. --- client/renderers/EGL/CMakeLists.txt | 1 + client/renderers/EGL/desktop.c | 11 ++++----- client/renderers/EGL/filter.c | 30 +++++++++++++++++++++++++ client/renderers/EGL/filter.h | 20 +++++++++++++---- client/renderers/EGL/filter_downscale.c | 18 ++++++++++----- client/renderers/EGL/filter_ffx_cas.c | 6 ++--- client/renderers/EGL/filter_ffx_fsr1.c | 8 +++---- client/renderers/EGL/postprocess.c | 29 ++++++++++++++++++------ client/renderers/EGL/postprocess.h | 2 ++ client/renderers/EGL/shader/basic.vert | 13 ++++++----- 10 files changed, 103 insertions(+), 35 deletions(-) create mode 100644 client/renderers/EGL/filter.c diff --git a/client/renderers/EGL/CMakeLists.txt b/client/renderers/EGL/CMakeLists.txt index 790408ee..d9b473a2 100644 --- a/client/renderers/EGL/CMakeLists.txt +++ b/client/renderers/EGL/CMakeLists.txt @@ -92,6 +92,7 @@ add_library(renderer_EGL STATIC framebuffer.c postprocess.c ffx.c + filter.c filter_ffx_cas.c filter_ffx_fsr1.c filter_downscale.c diff --git a/client/renderers/EGL/desktop.c b/client/renderers/EGL/desktop.c index 5b10a814..7d06f63d 100644 --- a/client/renderers/EGL/desktop.c +++ b/client/renderers/EGL/desktop.c @@ -361,9 +361,14 @@ bool egl_desktopRender(EGL_Desktop * desktop, unsigned int outputWidth, int scaleAlgo = EGL_SCALE_NEAREST; + egl_desktopRectsMatrix((float *)desktop->matrix->data, + desktop->width, desktop->height, x, y, scaleX, scaleY, rotate); + egl_desktopRectsUpdate(desktop->mesh, rects, desktop->width, desktop->height); + if (atomic_exchange(&desktop->processFrame, false) || egl_postProcessConfigModified(desktop->pp)) - egl_postProcessRun(desktop->pp, desktop->texture, outputWidth, outputHeight); + egl_postProcessRun(desktop->pp, desktop->texture, desktop->mesh, + desktop->width, desktop->height, outputWidth, outputHeight); unsigned int finalSizeX, finalSizeY; GLuint texture = egl_postProcessGetOutput(desktop->pp, @@ -399,10 +404,6 @@ bool egl_desktopRender(EGL_Desktop * desktop, unsigned int outputWidth, scaleAlgo = desktop->scaleAlgo; } - egl_desktopRectsMatrix((float *)desktop->matrix->data, - desktop->width, desktop->height, x, y, scaleX, scaleY, rotate); - egl_desktopRectsUpdate(desktop->mesh, rects, desktop->width, desktop->height); - const struct DesktopShader * shader = &desktop->shader; EGL_Uniform uniforms[] = { diff --git a/client/renderers/EGL/filter.c b/client/renderers/EGL/filter.c new file mode 100644 index 00000000..77a27e62 --- /dev/null +++ b/client/renderers/EGL/filter.c @@ -0,0 +1,30 @@ +/** + * Looking Glass + * Copyright © 2017-2021 The Looking Glass Authors + * https://looking-glass.io + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "filter.h" + +void egl_filterRectsRender(EGL_Shader * shader, EGL_FilterRects * rects) +{ + glUniformMatrix3x2fv(egl_shaderGetUniform(shader, "transform"), + 1, GL_FALSE, rects->matrix); + glUniform2f(egl_shaderGetUniform(shader, "desktopSize"), + rects->width, rects->height); + egl_desktopRectsRender(rects->rects); +} diff --git a/client/renderers/EGL/filter.h b/client/renderers/EGL/filter.h index 5a9a75fe..af3ac5e5 100644 --- a/client/renderers/EGL/filter.h +++ b/client/renderers/EGL/filter.h @@ -23,10 +23,19 @@ #include "util.h" #include "shader.h" #include "egltypes.h" +#include "desktop_rects.h" #include "model.h" #include +typedef struct EGL_FilterRects +{ + EGL_DesktopRects * rects; + GLfloat * matrix; + int width, height; +} +EGL_FilterRects; + typedef struct EGL_Filter EGL_Filter; typedef struct EGL_FilterOps @@ -78,7 +87,8 @@ typedef struct EGL_FilterOps /* runs the filter on the provided texture * returns the processed texture as the output */ - GLuint (*run)(EGL_Filter * filter, EGL_Model * model, GLuint texture); + GLuint (*run)(EGL_Filter * filter, EGL_FilterRects * rects, + GLuint texture); /* called when the filter output is no loger needed so it can release memory * this is optional */ @@ -146,10 +156,10 @@ static inline bool egl_filterPrepare(EGL_Filter * filter) return filter->ops.prepare(filter); } -static inline GLuint egl_filterRun(EGL_Filter * filter, EGL_Model * model, - GLuint texture) +static inline GLuint egl_filterRun(EGL_Filter * filter, + EGL_FilterRects * rects, GLuint texture) { - return filter->ops.run(filter, model, texture); + return filter->ops.run(filter, rects, texture); } static inline void egl_filterRelease(EGL_Filter * filter) @@ -157,3 +167,5 @@ static inline void egl_filterRelease(EGL_Filter * filter) if (filter->ops.release) filter->ops.release(filter); } + +void egl_filterRectsRender(EGL_Shader * shader, EGL_FilterRects * rects); diff --git a/client/renderers/EGL/filter_downscale.c b/client/renderers/EGL/filter_downscale.c index 1671115a..6aaab8a1 100644 --- a/client/renderers/EGL/filter_downscale.c +++ b/client/renderers/EGL/filter_downscale.c @@ -385,8 +385,8 @@ static bool egl_filterDownscalePrepare(EGL_Filter * filter) return true; } -static GLuint egl_filterDownscaleRun(EGL_Filter * filter, EGL_Model * model, - GLuint texture) +static GLuint egl_filterDownscaleRun(EGL_Filter * filter, + EGL_FilterRects * rects, GLuint texture) { EGL_FilterDownscale * this = UPCAST(EGL_FilterDownscale, filter); @@ -395,25 +395,31 @@ static GLuint egl_filterDownscaleRun(EGL_Filter * filter, EGL_Model * model, glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, texture); + EGL_Shader * shader; + switch (this->filter) { case DOWNSCALE_NEAREST: glBindSampler(0, this->sampler[0]); - egl_shaderUse(this->nearest); + shader = this->nearest; break; case DOWNSCALE_LINEAR: glBindSampler(0, this->sampler[1]); - egl_shaderUse(this->linear); + shader = this->linear; break; case DOWNSCALE_LANCZOS2: glBindSampler(0, this->sampler[0]); - egl_shaderUse(this->lanczos2); + shader = this->lanczos2; break; + + default: + DEBUG_UNREACHABLE(); } - egl_modelRender(model); + egl_shaderUse(shader); + egl_filterRectsRender(shader, rects); return egl_framebufferGetTexture(this->fb); } diff --git a/client/renderers/EGL/filter_ffx_cas.c b/client/renderers/EGL/filter_ffx_cas.c index 26452885..8857e970 100644 --- a/client/renderers/EGL/filter_ffx_cas.c +++ b/client/renderers/EGL/filter_ffx_cas.c @@ -262,8 +262,8 @@ static bool egl_filterFFXCASPrepare(EGL_Filter * filter) return true; } -static GLuint egl_filterFFXCASRun(EGL_Filter * filter, EGL_Model * model, - GLuint texture) +static GLuint egl_filterFFXCASRun(EGL_Filter * filter, + EGL_FilterRects * rects, GLuint texture) { EGL_FilterFFXCAS * this = UPCAST(EGL_FilterFFXCAS, filter); @@ -274,7 +274,7 @@ static GLuint egl_filterFFXCASRun(EGL_Filter * filter, EGL_Model * model, glBindSampler(0, this->sampler); egl_shaderUse(this->shader); - egl_modelRender(model); + egl_filterRectsRender(this->shader, rects); return egl_framebufferGetTexture(this->fb); } diff --git a/client/renderers/EGL/filter_ffx_fsr1.c b/client/renderers/EGL/filter_ffx_fsr1.c index 4ddb8304..3db79c90 100644 --- a/client/renderers/EGL/filter_ffx_fsr1.c +++ b/client/renderers/EGL/filter_ffx_fsr1.c @@ -388,8 +388,8 @@ static bool egl_filterFFXFSR1Prepare(EGL_Filter * filter) return true; } -static GLuint egl_filterFFXFSR1Run(EGL_Filter * filter, EGL_Model * model, - GLuint texture) +static GLuint egl_filterFFXFSR1Run(EGL_Filter * filter, + EGL_FilterRects * rects, GLuint texture) { EGL_FilterFFXFSR1 * this = UPCAST(EGL_FilterFFXFSR1, filter); @@ -399,7 +399,7 @@ static GLuint egl_filterFFXFSR1Run(EGL_Filter * filter, EGL_Model * model, glBindTexture(GL_TEXTURE_2D, texture); glBindSampler(0, this->sampler); egl_shaderUse(this->easu); - egl_modelRender(model); + egl_filterRectsRender(this->easu, rects); texture = egl_framebufferGetTexture(this->easuFb); // pass 2, Rcas @@ -408,7 +408,7 @@ static GLuint egl_filterFFXFSR1Run(EGL_Filter * filter, EGL_Model * model, glBindTexture(GL_TEXTURE_2D, texture); glBindSampler(0, this->sampler); egl_shaderUse(this->rcas); - egl_modelRender(model); + egl_filterRectsRender(this->rcas, rects); texture = egl_framebufferGetTexture(this->rcasFb); return texture; diff --git a/client/renderers/EGL/postprocess.c b/client/renderers/EGL/postprocess.c index 17b4ba94..0f22dd6d 100644 --- a/client/renderers/EGL/postprocess.c +++ b/client/renderers/EGL/postprocess.c @@ -53,7 +53,7 @@ struct EGL_PostProcess unsigned int outputX, outputY; _Atomic(bool) modified; - EGL_Model * model; + EGL_DesktopRects * rects; StringList presets; char * presetDir; @@ -523,12 +523,11 @@ bool egl_postProcessInit(EGL_PostProcess ** pp) goto error_this; } - if (!egl_modelInit(&this->model)) + if (!egl_desktopRectsInit(&this->rects, 1)) { - DEBUG_ERROR("Failed to initialize the model"); + DEBUG_ERROR("Failed to initialize the desktop rects"); goto error_filters; } - egl_modelSetDefault(this->model, false); loadPresetList(this); reorderFilters(this); @@ -561,7 +560,7 @@ void egl_postProcessFree(EGL_PostProcess ** pp) if (this->presets) stringlist_free(&this->presets); - egl_modelFree(&this->model); + egl_desktopRectsFree(&this->rects); free(this->presetError); free(this); *pp = NULL; @@ -583,6 +582,7 @@ bool egl_postProcessConfigModified(EGL_PostProcess * this) } bool egl_postProcessRun(EGL_PostProcess * this, EGL_Texture * tex, + EGL_DesktopRects * rects, int desktopWidth, int desktopHeight, unsigned int targetX, unsigned int targetY) { EGL_Filter * lastFilter = NULL; @@ -592,7 +592,22 @@ bool egl_postProcessRun(EGL_PostProcess * this, EGL_Texture * tex, if (egl_textureGet(tex, &texture, &sizeX, &sizeY) != EGL_TEX_STATUS_OK) return false; - atomic_store(&this->modified, false); + if (atomic_exchange(&this->modified, false)) + { + rects = this->rects; + egl_desktopRectsUpdate(rects, NULL, desktopWidth, desktopHeight); + } + + GLfloat matrix[6]; + egl_desktopRectsMatrix(matrix, desktopWidth, desktopHeight, 0.0f, 0.0f, + 1.0f, 1.0f, LG_ROTATE_0); + + EGL_FilterRects filterRects = { + .rects = rects, + .matrix = matrix, + .width = desktopWidth, + .height = desktopHeight, + }; EGL_Filter * filter; vector_forEach(filter, &this->filters) @@ -603,7 +618,7 @@ bool egl_postProcessRun(EGL_PostProcess * this, EGL_Texture * tex, if (!egl_filterPrepare(filter)) continue; - texture = egl_filterRun(filter, this->model, texture); + texture = egl_filterRun(filter, &filterRects, texture); egl_filterGetOutputRes(filter, &sizeX, &sizeY); if (lastFilter) diff --git a/client/renderers/EGL/postprocess.h b/client/renderers/EGL/postprocess.h index 16552721..faf85941 100644 --- a/client/renderers/EGL/postprocess.h +++ b/client/renderers/EGL/postprocess.h @@ -20,6 +20,7 @@ #pragma once +#include "desktop_rects.h" #include "filter.h" #include "texture.h" @@ -39,6 +40,7 @@ bool egl_postProcessConfigModified(EGL_PostProcess * this); /* apply the filters to the supplied texture * targetX/Y is the final target output dimension hint if scalers are present */ bool egl_postProcessRun(EGL_PostProcess * this, EGL_Texture * tex, + EGL_DesktopRects * rects, int desktopWidth, int desktopHeight, unsigned int targetX, unsigned int targetY); GLuint egl_postProcessGetOutput(EGL_PostProcess * this, diff --git a/client/renderers/EGL/shader/basic.vert b/client/renderers/EGL/shader/basic.vert index c50768b8..82153dbd 100644 --- a/client/renderers/EGL/shader/basic.vert +++ b/client/renderers/EGL/shader/basic.vert @@ -1,14 +1,15 @@ #version 300 es - precision mediump float; -layout(location = 0) in vec2 uVertex; -layout(location = 1) in vec2 uUV; - +layout(location = 0) in vec2 vertex; out vec2 fragCoord; +uniform vec2 desktopSize; +uniform mat3x2 transform; + void main() { - gl_Position = vec4(uVertex, 0.0, 1.0); - fragCoord = uUV; + vec2 pos = transform * vec3(vertex, 1.0); + gl_Position = vec4(pos.x, -pos.y, 0.0, 1.0); + fragCoord = vertex / desktopSize; }