mirror of
https://github.com/gnif/LookingGlass.git
synced 2024-11-22 13:37:22 +00:00
[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:
parent
e9bf225c75
commit
1b58f2592c
@ -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
|
||||||
|
@ -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[] =
|
||||||
{
|
{
|
||||||
|
30
client/renderers/EGL/filter.c
Normal file
30
client/renderers/EGL/filter.c
Normal 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);
|
||||||
|
}
|
@ -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);
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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)
|
||||||
|
@ -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,
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user