[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.
This commit is contained in:
Quantum 2021-09-01 22:27:36 -04:00 committed by Geoffrey McRae
parent e9bf225c75
commit 1b58f2592c
10 changed files with 103 additions and 35 deletions

View File

@ -92,6 +92,7 @@ add_library(renderer_EGL STATIC
framebuffer.c framebuffer.c
postprocess.c postprocess.c
ffx.c ffx.c
filter.c
filter_ffx_cas.c filter_ffx_cas.c
filter_ffx_fsr1.c filter_ffx_fsr1.c
filter_downscale.c filter_downscale.c

View File

@ -361,9 +361,14 @@ bool egl_desktopRender(EGL_Desktop * desktop, unsigned int outputWidth,
int scaleAlgo = EGL_SCALE_NEAREST; 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) || if (atomic_exchange(&desktop->processFrame, false) ||
egl_postProcessConfigModified(desktop->pp)) 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; unsigned int finalSizeX, finalSizeY;
GLuint texture = egl_postProcessGetOutput(desktop->pp, GLuint texture = egl_postProcessGetOutput(desktop->pp,
@ -399,10 +404,6 @@ bool egl_desktopRender(EGL_Desktop * desktop, unsigned int outputWidth,
scaleAlgo = desktop->scaleAlgo; 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; const struct DesktopShader * shader = &desktop->shader;
EGL_Uniform uniforms[] = EGL_Uniform uniforms[] =
{ {

View File

@ -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);
}

View File

@ -23,10 +23,19 @@
#include "util.h" #include "util.h"
#include "shader.h" #include "shader.h"
#include "egltypes.h" #include "egltypes.h"
#include "desktop_rects.h"
#include "model.h" #include "model.h"
#include <string.h> #include <string.h>
typedef struct EGL_FilterRects
{
EGL_DesktopRects * rects;
GLfloat * matrix;
int width, height;
}
EGL_FilterRects;
typedef struct EGL_Filter EGL_Filter; typedef struct EGL_Filter EGL_Filter;
typedef struct EGL_FilterOps typedef struct EGL_FilterOps
@ -78,7 +87,8 @@ typedef struct EGL_FilterOps
/* runs the filter on the provided texture /* runs the filter on the provided texture
* returns the processed texture as the output */ * 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 /* called when the filter output is no loger needed so it can release memory
* this is optional */ * this is optional */
@ -146,10 +156,10 @@ static inline bool egl_filterPrepare(EGL_Filter * filter)
return filter->ops.prepare(filter); return filter->ops.prepare(filter);
} }
static inline GLuint egl_filterRun(EGL_Filter * filter, EGL_Model * model, static inline GLuint egl_filterRun(EGL_Filter * filter,
GLuint texture) 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) static inline void egl_filterRelease(EGL_Filter * filter)
@ -157,3 +167,5 @@ static inline void egl_filterRelease(EGL_Filter * filter)
if (filter->ops.release) if (filter->ops.release)
filter->ops.release(filter); filter->ops.release(filter);
} }
void egl_filterRectsRender(EGL_Shader * shader, EGL_FilterRects * rects);

View File

@ -385,8 +385,8 @@ static bool egl_filterDownscalePrepare(EGL_Filter * filter)
return true; return true;
} }
static GLuint egl_filterDownscaleRun(EGL_Filter * filter, EGL_Model * model, static GLuint egl_filterDownscaleRun(EGL_Filter * filter,
GLuint texture) EGL_FilterRects * rects, GLuint texture)
{ {
EGL_FilterDownscale * this = UPCAST(EGL_FilterDownscale, filter); EGL_FilterDownscale * this = UPCAST(EGL_FilterDownscale, filter);
@ -395,25 +395,31 @@ static GLuint egl_filterDownscaleRun(EGL_Filter * filter, EGL_Model * model,
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture); glBindTexture(GL_TEXTURE_2D, texture);
EGL_Shader * shader;
switch (this->filter) switch (this->filter)
{ {
case DOWNSCALE_NEAREST: case DOWNSCALE_NEAREST:
glBindSampler(0, this->sampler[0]); glBindSampler(0, this->sampler[0]);
egl_shaderUse(this->nearest); shader = this->nearest;
break; break;
case DOWNSCALE_LINEAR: case DOWNSCALE_LINEAR:
glBindSampler(0, this->sampler[1]); glBindSampler(0, this->sampler[1]);
egl_shaderUse(this->linear); shader = this->linear;
break; break;
case DOWNSCALE_LANCZOS2: case DOWNSCALE_LANCZOS2:
glBindSampler(0, this->sampler[0]); glBindSampler(0, this->sampler[0]);
egl_shaderUse(this->lanczos2); shader = this->lanczos2;
break; break;
default:
DEBUG_UNREACHABLE();
} }
egl_modelRender(model); egl_shaderUse(shader);
egl_filterRectsRender(shader, rects);
return egl_framebufferGetTexture(this->fb); return egl_framebufferGetTexture(this->fb);
} }

View File

@ -262,8 +262,8 @@ static bool egl_filterFFXCASPrepare(EGL_Filter * filter)
return true; return true;
} }
static GLuint egl_filterFFXCASRun(EGL_Filter * filter, EGL_Model * model, static GLuint egl_filterFFXCASRun(EGL_Filter * filter,
GLuint texture) EGL_FilterRects * rects, GLuint texture)
{ {
EGL_FilterFFXCAS * this = UPCAST(EGL_FilterFFXCAS, filter); 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); glBindSampler(0, this->sampler);
egl_shaderUse(this->shader); egl_shaderUse(this->shader);
egl_modelRender(model); egl_filterRectsRender(this->shader, rects);
return egl_framebufferGetTexture(this->fb); return egl_framebufferGetTexture(this->fb);
} }

View File

@ -388,8 +388,8 @@ static bool egl_filterFFXFSR1Prepare(EGL_Filter * filter)
return true; return true;
} }
static GLuint egl_filterFFXFSR1Run(EGL_Filter * filter, EGL_Model * model, static GLuint egl_filterFFXFSR1Run(EGL_Filter * filter,
GLuint texture) EGL_FilterRects * rects, GLuint texture)
{ {
EGL_FilterFFXFSR1 * this = UPCAST(EGL_FilterFFXFSR1, filter); 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); glBindTexture(GL_TEXTURE_2D, texture);
glBindSampler(0, this->sampler); glBindSampler(0, this->sampler);
egl_shaderUse(this->easu); egl_shaderUse(this->easu);
egl_modelRender(model); egl_filterRectsRender(this->easu, rects);
texture = egl_framebufferGetTexture(this->easuFb); texture = egl_framebufferGetTexture(this->easuFb);
// pass 2, Rcas // pass 2, Rcas
@ -408,7 +408,7 @@ static GLuint egl_filterFFXFSR1Run(EGL_Filter * filter, EGL_Model * model,
glBindTexture(GL_TEXTURE_2D, texture); glBindTexture(GL_TEXTURE_2D, texture);
glBindSampler(0, this->sampler); glBindSampler(0, this->sampler);
egl_shaderUse(this->rcas); egl_shaderUse(this->rcas);
egl_modelRender(model); egl_filterRectsRender(this->rcas, rects);
texture = egl_framebufferGetTexture(this->rcasFb); texture = egl_framebufferGetTexture(this->rcasFb);
return texture; return texture;

View File

@ -53,7 +53,7 @@ struct EGL_PostProcess
unsigned int outputX, outputY; unsigned int outputX, outputY;
_Atomic(bool) modified; _Atomic(bool) modified;
EGL_Model * model; EGL_DesktopRects * rects;
StringList presets; StringList presets;
char * presetDir; char * presetDir;
@ -523,12 +523,11 @@ bool egl_postProcessInit(EGL_PostProcess ** pp)
goto error_this; 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; goto error_filters;
} }
egl_modelSetDefault(this->model, false);
loadPresetList(this); loadPresetList(this);
reorderFilters(this); reorderFilters(this);
@ -561,7 +560,7 @@ void egl_postProcessFree(EGL_PostProcess ** pp)
if (this->presets) if (this->presets)
stringlist_free(&this->presets); stringlist_free(&this->presets);
egl_modelFree(&this->model); egl_desktopRectsFree(&this->rects);
free(this->presetError); free(this->presetError);
free(this); free(this);
*pp = NULL; *pp = NULL;
@ -583,6 +582,7 @@ bool egl_postProcessConfigModified(EGL_PostProcess * this)
} }
bool egl_postProcessRun(EGL_PostProcess * this, EGL_Texture * tex, bool egl_postProcessRun(EGL_PostProcess * this, EGL_Texture * tex,
EGL_DesktopRects * rects, int desktopWidth, int desktopHeight,
unsigned int targetX, unsigned int targetY) unsigned int targetX, unsigned int targetY)
{ {
EGL_Filter * lastFilter = NULL; 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) if (egl_textureGet(tex, &texture, &sizeX, &sizeY) != EGL_TEX_STATUS_OK)
return false; 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; EGL_Filter * filter;
vector_forEach(filter, &this->filters) vector_forEach(filter, &this->filters)
@ -603,7 +618,7 @@ bool egl_postProcessRun(EGL_PostProcess * this, EGL_Texture * tex,
if (!egl_filterPrepare(filter)) if (!egl_filterPrepare(filter))
continue; continue;
texture = egl_filterRun(filter, this->model, texture); texture = egl_filterRun(filter, &filterRects, texture);
egl_filterGetOutputRes(filter, &sizeX, &sizeY); egl_filterGetOutputRes(filter, &sizeX, &sizeY);
if (lastFilter) if (lastFilter)

View File

@ -20,6 +20,7 @@
#pragma once #pragma once
#include "desktop_rects.h"
#include "filter.h" #include "filter.h"
#include "texture.h" #include "texture.h"
@ -39,6 +40,7 @@ bool egl_postProcessConfigModified(EGL_PostProcess * this);
/* apply the filters to the supplied texture /* apply the filters to the supplied texture
* targetX/Y is the final target output dimension hint if scalers are present */ * targetX/Y is the final target output dimension hint if scalers are present */
bool egl_postProcessRun(EGL_PostProcess * this, EGL_Texture * tex, bool egl_postProcessRun(EGL_PostProcess * this, EGL_Texture * tex,
EGL_DesktopRects * rects, int desktopWidth, int desktopHeight,
unsigned int targetX, unsigned int targetY); unsigned int targetX, unsigned int targetY);
GLuint egl_postProcessGetOutput(EGL_PostProcess * this, GLuint egl_postProcessGetOutput(EGL_PostProcess * this,

View File

@ -1,14 +1,15 @@
#version 300 es #version 300 es
precision mediump float; precision mediump float;
layout(location = 0) in vec2 uVertex; layout(location = 0) in vec2 vertex;
layout(location = 1) in vec2 uUV;
out vec2 fragCoord; out vec2 fragCoord;
uniform vec2 desktopSize;
uniform mat3x2 transform;
void main() void main()
{ {
gl_Position = vec4(uVertex, 0.0, 1.0); vec2 pos = transform * vec3(vertex, 1.0);
fragCoord = uUV; gl_Position = vec4(pos.x, -pos.y, 0.0, 1.0);
fragCoord = vertex / desktopSize;
} }