[client] egl: rework post process filters and add AMD FXR

This commit is contained in:
Geoffrey McRae 2021-08-10 13:08:54 +10:00
parent 3b751a2017
commit dc0b3a8d45
14 changed files with 2441 additions and 235 deletions

View File

@ -61,6 +61,8 @@ build_shaders(
shader/splash_logo.frag shader/splash_logo.frag
shader/basic.vert shader/basic.vert
shader/ffx_cas.frag shader/ffx_cas.frag
shader/ffx_fsr1_easu.frag
shader/ffx_fsr1_rcas.frag
) )
make_defines( make_defines(

View File

@ -40,13 +40,15 @@
#include "basic.vert.h" #include "basic.vert.h"
#include "ffx_cas.frag.h" #include "ffx_cas.frag.h"
#include "ffx_fsr1_easu.frag.h"
#include "ffx_fsr1_rcas.frag.h"
struct DesktopShader struct DesktopShader
{ {
EGL_Shader * shader; EGL_Shader * shader;
GLint uTransform; GLint uTransform;
GLint uDesktopSize; GLint uDesktopSize;
GLint uTextureScale; GLint uTextureSize;
GLint uScaleAlgo; GLint uScaleAlgo;
GLint uNVGain; GLint uNVGain;
GLint uCBMode; GLint uCBMode;
@ -65,6 +67,7 @@ struct EGL_Desktop
// internals // internals
int width, height; int width, height;
LG_RendererRotate rotate; LG_RendererRotate rotate;
bool upscale;
// scale algorithm // scale algorithm
int scaleAlgo; int scaleAlgo;
@ -79,10 +82,15 @@ struct EGL_Desktop
bool useDMA; bool useDMA;
LG_RendererFormat format; LG_RendererFormat format;
EGL_Shader * ffxFSR1[2];
bool ffxFSR1Enable;
PostProcessHandle ffxFSR1Handle[2];
EGL_Uniform ffxFSR1Uniform;
EGL_Shader * ffxCAS; EGL_Shader * ffxCAS;
bool ffxCASEnable; bool ffxCASEnable;
PostProcessHandle ffxCASHandle; PostProcessHandle ffxCASHandle;
EGL_Uniform ffxUniform; EGL_Uniform ffxCASUniform;
}; };
// forwards // forwards
@ -104,20 +112,27 @@ static bool egl_initDesktopShader(
return false; return false;
} }
shader->uTransform = egl_shaderGetUniform(shader->shader, "transform" ); shader->uTransform = egl_shaderGetUniform(shader->shader, "transform" );
shader->uDesktopSize = egl_shaderGetUniform(shader->shader, "size" ); shader->uDesktopSize = egl_shaderGetUniform(shader->shader, "desktopSize");
shader->uTextureScale = egl_shaderGetUniform(shader->shader, "textureScale"); shader->uTextureSize = egl_shaderGetUniform(shader->shader, "textureSize");
shader->uScaleAlgo = egl_shaderGetUniform(shader->shader, "scaleAlgo" ); shader->uScaleAlgo = egl_shaderGetUniform(shader->shader, "scaleAlgo" );
shader->uNVGain = egl_shaderGetUniform(shader->shader, "nvGain" ); shader->uNVGain = egl_shaderGetUniform(shader->shader, "nvGain" );
shader->uCBMode = egl_shaderGetUniform(shader->shader, "cbMode" ); shader->uCBMode = egl_shaderGetUniform(shader->shader, "cbMode" );
return true; return true;
} }
static void setupFilters(EGL_Desktop * desktop) static void setupFilters(EGL_Desktop * desktop)
{ {
desktop->ffxFSR1Handle[0] =
egl_textureAddFilter(desktop->texture, desktop->ffxFSR1[0],
desktop->ffxFSR1Enable);
desktop->ffxFSR1Handle[1] =
egl_textureAddFilter(desktop->texture, desktop->ffxFSR1[1],
desktop->ffxFSR1Enable);
desktop->ffxCASHandle = desktop->ffxCASHandle =
egl_textureAddFilter(desktop->texture, desktop->ffxCAS, 1.0f, egl_textureAddFilter(desktop->texture, desktop->ffxCAS,
desktop->ffxCASEnable); desktop->ffxCASEnable);
} }
@ -173,18 +188,38 @@ bool egl_desktopInit(EGL * egl, EGL_Desktop ** desktop_, EGLDisplay * display,
desktop->scaleAlgo = option_get_int("egl", "scale" ); desktop->scaleAlgo = option_get_int("egl", "scale" );
desktop->useDMA = useDMA; desktop->useDMA = useDMA;
// AMD FidelidyFX FSR
egl_shaderInit(&desktop->ffxFSR1[0]);
egl_shaderCompile(desktop->ffxFSR1[0],
b_shader_basic_vert , b_shader_basic_vert_size,
b_shader_ffx_fsr1_easu_frag, b_shader_ffx_fsr1_easu_frag_size);
egl_shaderInit(&desktop->ffxFSR1[1]);
egl_shaderCompile(desktop->ffxFSR1[1],
b_shader_basic_vert , b_shader_basic_vert_size,
b_shader_ffx_fsr1_rcas_frag, b_shader_ffx_fsr1_rcas_frag_size);
desktop->ffxFSR1Enable = option_get_bool("eglFilter", "ffxFSR");
desktop->ffxFSR1Uniform.type = EGL_UNIFORM_TYPE_1F;
desktop->ffxFSR1Uniform.location =
egl_shaderGetUniform(desktop->ffxFSR1[1], "uSharpness");
desktop->ffxFSR1Uniform.f[0] =
option_get_float("eglFilter", "ffxFSRSharpness");
egl_shaderSetUniforms(desktop->ffxFSR1[1], &desktop->ffxFSR1Uniform, 1);
// AMD FidelidyFX CAS
egl_shaderInit(&desktop->ffxCAS); egl_shaderInit(&desktop->ffxCAS);
egl_shaderCompile(desktop->ffxCAS, egl_shaderCompile(desktop->ffxCAS,
b_shader_basic_vert , b_shader_basic_vert_size, b_shader_basic_vert , b_shader_basic_vert_size,
b_shader_ffx_cas_frag, b_shader_ffx_cas_frag_size); b_shader_ffx_cas_frag, b_shader_ffx_cas_frag_size);
desktop->ffxCASEnable = option_get_bool("eglFilter", "ffxCAS"); desktop->ffxCASEnable = option_get_bool("eglFilter", "ffxCAS");
desktop->ffxUniform.type = EGL_UNIFORM_TYPE_1F; desktop->ffxCASUniform.type = EGL_UNIFORM_TYPE_1F;
desktop->ffxUniform.location = desktop->ffxCASUniform.location =
egl_shaderGetUniform(desktop->ffxCAS, "uSharpness"); egl_shaderGetUniform(desktop->ffxCAS, "uSharpness");
desktop->ffxUniform.f[0] = desktop->ffxCASUniform.f[0] =
option_get_float("eglFilter", "ffxCASSharpness"); option_get_float("eglFilter", "ffxCASSharpness");
egl_shaderSetUniforms(desktop->ffxCAS, &desktop->ffxUniform, 1); egl_shaderSetUniforms(desktop->ffxCAS, &desktop->ffxCASUniform, 1);
setupFilters(desktop); setupFilters(desktop);
@ -222,6 +257,9 @@ void egl_desktopFree(EGL_Desktop ** desktop)
egl_shaderFree (&(*desktop)->shader.shader); egl_shaderFree (&(*desktop)->shader.shader);
egl_desktopRectsFree(&(*desktop)->mesh ); egl_desktopRectsFree(&(*desktop)->mesh );
countedBufferRelease(&(*desktop)->matrix ); countedBufferRelease(&(*desktop)->matrix );
egl_shaderFree(&(*desktop)->ffxFSR1[0]);
egl_shaderFree(&(*desktop)->ffxFSR1[1]);
egl_shaderFree(&(*desktop)->ffxCAS); egl_shaderFree(&(*desktop)->ffxCAS);
free(*desktop); free(*desktop);
@ -266,25 +304,64 @@ void egl_desktopConfigUI(EGL_Desktop * desktop)
igSliderInt("##nvgain", &desktop->nvGain, 0, desktop->nvMax, format, 0); igSliderInt("##nvgain", &desktop->nvGain, 0, desktop->nvMax, format, 0);
igPopItemWidth(); igPopItemWidth();
bool invalidateCAS = false; bool invalidateTex = false;
// AMD FidelityFX FSR
bool fsr1 = desktop->ffxFSR1Enable;
igCheckbox("AMD FidelityFX FSR", &fsr1);
if (fsr1 != desktop->ffxFSR1Enable)
{
desktop->ffxFSR1Enable = fsr1;
egl_textureEnableFilter(desktop->ffxFSR1Handle[0],
fsr1 && desktop->upscale);
egl_textureEnableFilter(desktop->ffxFSR1Handle[1],
fsr1 && desktop->upscale);
invalidateTex = true;
}
float fsr1Sharpness = desktop->ffxFSR1Uniform.f[0];
igText("Sharpness:");
igSameLine(0.0f, -1.0f);
igPushItemWidth(igGetWindowWidth() - igGetCursorPosX() -
igGetStyle()->WindowPadding.x);
igSliderFloat("##fsr1Sharpness", &fsr1Sharpness, 0.0f, 1.0f, NULL, 0);
igPopItemWidth();
if (fsr1Sharpness != desktop->ffxFSR1Uniform.f[0])
{
// enable FSR1 if the sharpness was changed
if (!fsr1)
{
fsr1 = true;
desktop->ffxFSR1Enable = fsr1;
egl_textureEnableFilter(desktop->ffxFSR1Handle[0],
fsr1 && desktop->upscale);
egl_textureEnableFilter(desktop->ffxFSR1Handle[1],
fsr1 && desktop->upscale);
}
desktop->ffxFSR1Uniform.f[0] = fsr1Sharpness;
egl_shaderSetUniforms(desktop->ffxFSR1[1], &desktop->ffxFSR1Uniform, 1);
invalidateTex = true;
}
// AMD FiedlityFX CAS
bool cas = desktop->ffxCASEnable; bool cas = desktop->ffxCASEnable;
igCheckbox("AMD FidelityFX CAS", &cas); igCheckbox("AMD FidelityFX CAS", &cas);
if (cas != desktop->ffxCASEnable) if (cas != desktop->ffxCASEnable)
{ {
desktop->ffxCASEnable = cas; desktop->ffxCASEnable = cas;
egl_textureEnableFilter(desktop->ffxCASHandle, cas); egl_textureEnableFilter(desktop->ffxCASHandle, cas);
invalidateCAS = true; invalidateTex = true;
} }
float sharpness = desktop->ffxUniform.f[0]; float casSharpness = desktop->ffxCASUniform.f[0];
igText("Sharpness:"); igText("Sharpness:");
igSameLine(0.0f, -1.0f); igSameLine(0.0f, -1.0f);
igPushItemWidth(igGetWindowWidth() - igGetCursorPosX() - igPushItemWidth(igGetWindowWidth() - igGetCursorPosX() -
igGetStyle()->WindowPadding.x); igGetStyle()->WindowPadding.x);
igSliderFloat("##casSharpness", &sharpness, 0.0f, 1.0f, NULL, 0); igSliderFloat("##casSharpness", &casSharpness, 0.0f, 1.0f, NULL, 0);
igPopItemWidth(); igPopItemWidth();
if (sharpness != desktop->ffxUniform.f[0]) if (casSharpness != desktop->ffxCASUniform.f[0])
{ {
// enable CAS if the sharpness was changed // enable CAS if the sharpness was changed
if (!cas) if (!cas)
@ -293,12 +370,12 @@ void egl_desktopConfigUI(EGL_Desktop * desktop)
desktop->ffxCASEnable = cas; desktop->ffxCASEnable = cas;
egl_textureEnableFilter(desktop->ffxCASHandle, cas); egl_textureEnableFilter(desktop->ffxCASHandle, cas);
} }
desktop->ffxUniform.f[0] = sharpness; desktop->ffxCASUniform.f[0] = casSharpness;
egl_shaderSetUniforms(desktop->ffxCAS, &desktop->ffxUniform, 1); egl_shaderSetUniforms(desktop->ffxCAS, &desktop->ffxCASUniform, 1);
invalidateCAS = true; invalidateTex = true;
} }
if (invalidateCAS) if (invalidateTex)
{ {
egl_textureInvalidate(desktop->texture); egl_textureInvalidate(desktop->texture);
app_invalidateWindow(true); app_invalidateWindow(true);
@ -379,6 +456,29 @@ bool egl_desktop_update(EGL_Desktop * desktop, const FrameBuffer * frame, int dm
return egl_textureUpdateFromFrame(desktop->texture, frame, damageRects, damageRectsCount); return egl_textureUpdateFromFrame(desktop->texture, frame, damageRects, damageRectsCount);
} }
void egl_desktopResize(EGL_Desktop * desktop, int width, int height)
{
if (width > desktop->width && height > desktop->height)
{
desktop->upscale = true;
if (desktop->ffxFSR1Enable)
{
egl_textureEnableFilter(desktop->ffxFSR1Handle[0], true);
egl_textureEnableFilter(desktop->ffxFSR1Handle[1], true);
}
egl_textureSetFilterRes(desktop->ffxFSR1Handle[0], width, height);
egl_textureSetFilterRes(desktop->ffxFSR1Handle[1], width, height);
egl_textureSetFilterRes(desktop->ffxCASHandle , width, height);
}
else
{
desktop->upscale = false;
egl_textureEnableFilter(desktop->ffxFSR1Handle[0], false);
egl_textureEnableFilter(desktop->ffxFSR1Handle[1], false);
egl_textureSetFilterRes(desktop->ffxCASHandle, 0, 0);
}
}
bool egl_desktopRender(EGL_Desktop * desktop, const float x, const float y, bool egl_desktopRender(EGL_Desktop * desktop, const float x, const float y,
const float scaleX, const float scaleY, enum EGL_DesktopScaleType scaleType, const float scaleX, const float scaleY, enum EGL_DesktopScaleType scaleType,
LG_RendererRotate rotate, const struct DamageRects * rects) LG_RendererRotate rotate, const struct DamageRects * rects)
@ -412,12 +512,14 @@ bool egl_desktopRender(EGL_Desktop * desktop, const float x, const float y,
scaleAlgo = desktop->scaleAlgo; scaleAlgo = desktop->scaleAlgo;
} }
struct Rect finalSize;
egl_textureBind(desktop->texture);
egl_textureGetFinalSize(desktop->texture, &finalSize);
egl_desktopRectsMatrix((float *)desktop->matrix->data, egl_desktopRectsMatrix((float *)desktop->matrix->data,
desktop->width, desktop->height, x, y, scaleX, scaleY, rotate); desktop->width, desktop->height, x, y, scaleX, scaleY, rotate);
egl_desktopRectsUpdate(desktop->mesh, rects, desktop->width, desktop->height); egl_desktopRectsUpdate(desktop->mesh, rects, desktop->width, desktop->height);
egl_textureBind(desktop->texture);
const struct DesktopShader * shader = &desktop->shader; const struct DesktopShader * shader = &desktop->shader;
EGL_Uniform uniforms[] = EGL_Uniform uniforms[] =
{ {
@ -432,9 +534,9 @@ bool egl_desktopRender(EGL_Desktop * desktop, const float x, const float y,
.f = { desktop->width, desktop->height }, .f = { desktop->width, desktop->height },
}, },
{ {
.type = EGL_UNIFORM_TYPE_1F, .type = EGL_UNIFORM_TYPE_2I,
.location = shader->uTextureScale, .location = shader->uTextureSize,
.f = { egl_textureGetScale(desktop->texture) }, .i = { finalSize.x, finalSize.y },
}, },
{ {
.type = EGL_UNIFORM_TYPE_M3x2FV, .type = EGL_UNIFORM_TYPE_M3x2FV,

View File

@ -45,6 +45,7 @@ void egl_desktopConfigUI(EGL_Desktop * desktop);
bool egl_desktopSetup (EGL_Desktop * desktop, const LG_RendererFormat format); bool egl_desktopSetup (EGL_Desktop * desktop, const LG_RendererFormat format);
bool egl_desktop_update(EGL_Desktop * desktop, const FrameBuffer * frame, int dmaFd, bool egl_desktop_update(EGL_Desktop * desktop, const FrameBuffer * frame, int dmaFd,
const FrameDamageRect * damageRects, int damageRectsCount); const FrameDamageRect * damageRects, int damageRectsCount);
void egl_desktopResize(EGL_Desktop * desktop, int width, int height);
bool egl_desktopRender(EGL_Desktop * desktop, const float x, const float y, bool egl_desktopRender(EGL_Desktop * desktop, const float x, const float y,
const float scaleX, const float scaleY, enum EGL_DesktopScaleType scaleType, const float scaleX, const float scaleY, enum EGL_DesktopScaleType scaleType,
LG_RendererRotate rotate, const struct DamageRects * rects); LG_RendererRotate rotate, const struct DamageRects * rects);

View File

@ -183,11 +183,25 @@ static struct Option egl_options[] =
}, },
{ {
.module = "eglFilter", .module = "eglFilter",
.name = "ffxCAS", .name = "ffxFSR",
.description = "AMD FidelityFX CAS", .description = "AMD FidelityFX FSR",
.type = OPTION_TYPE_BOOL, .type = OPTION_TYPE_BOOL,
.value.x_bool = false .value.x_bool = false
},
{
.module = "eglFilter",
.name = "ffxFSRSharpness",
.description = "AMD FidelityFX FSR Sharpness",
.type = OPTION_TYPE_FLOAT,
.value.x_float = 1.0f
},
{
.module = "eglFilter",
.name = "ffxCAS",
.description = "AMD FidelityFX CAS",
.type = OPTION_TYPE_BOOL,
.value.x_bool = false
}, },
{ {
.module = "eglFilter", .module = "eglFilter",
@ -466,6 +480,7 @@ static void egl_onResize(LG_Renderer * renderer, const int width, const int heig
ImGui_ImplOpenGL3_NewFrame(); ImGui_ImplOpenGL3_NewFrame();
egl_damageResize(this->damage, this->translateX, this->translateY, this->scaleX, this->scaleY); egl_damageResize(this->damage, this->translateX, this->translateY, this->scaleX, this->scaleY);
egl_desktopResize(this->desktop, this->width, this->height);
} }
static bool egl_onMouseShape(LG_Renderer * renderer, const LG_RendererCursor cursor, static bool egl_onMouseShape(LG_Renderer * renderer, const LG_RendererCursor cursor,

View File

@ -0,0 +1,32 @@
#if __VERSION__ == 300
vec4 textureGather(sampler2D tex, vec2 uv, int comp)
{
vec4 c0 = textureOffset(tex, uv, ivec2(0,1));
vec4 c1 = textureOffset(tex, uv, ivec2(1,1));
vec4 c2 = textureOffset(tex, uv, ivec2(1,0));
vec4 c3 = textureOffset(tex, uv, ivec2(0,0));
return vec4(c0[comp], c1[comp], c2[comp],c3[comp]);
}
#elif __VERSION__ < 300
vec4 textureGather(sampler2D tex, vec2 uv, int comp)
{
vec4 c3 = texture2D(tex, uv);
return vec4(c3[comp], c3[comp], c3[comp],c3[comp]);
}
#endif
#if __VERSION__ < 310
uint bitfieldExtract(uint val, int off, int size)
{
uint mask = uint((1 << size) - 1);
return uint(val >> off) & mask;
}
uint bitfieldInsert(uint a, uint b, int c, int d)
{
uint mask = ~(0xffffffffu << d) << c;
mask = ~mask;
a &= mask;
return a | (b << c);
}
#endif

View File

@ -3,11 +3,11 @@
layout(location = 0) in vec2 vertex; layout(location = 0) in vec2 vertex;
out highp vec2 uv; out highp vec2 uv;
uniform highp vec2 size; uniform highp vec2 desktopSize;
uniform mat3x2 transform; uniform mat3x2 transform;
void main() void main()
{ {
gl_Position = vec4(transform * vec3(vertex, 1.0), 0.0, 1.0); gl_Position = vec4(transform * vec3(vertex, 1.0), 0.0, 1.0);
uv = vertex / size; uv = vertex / desktopSize;
} }

View File

@ -13,8 +13,7 @@ out highp vec4 color;
uniform sampler2D sampler1; uniform sampler2D sampler1;
uniform int scaleAlgo; uniform int scaleAlgo;
uniform highp vec2 size; uniform highp ivec2 textureSize;
uniform highp float textureScale;
uniform highp float nvGain; uniform highp float nvGain;
uniform int cbMode; uniform int cbMode;
@ -24,7 +23,7 @@ void main()
switch (scaleAlgo) switch (scaleAlgo)
{ {
case EGL_SCALE_NEAREST: case EGL_SCALE_NEAREST:
color = texelFetch(sampler1, ivec2(uv * size * textureScale), 0); color = texelFetch(sampler1, ivec2(uv * vec2(textureSize)), 0);
break; break;
case EGL_SCALE_LINEAR: case EGL_SCALE_LINEAR:

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,8 @@
#version 300 es #version 300 es
precision mediump float; precision mediump float;
#include "compat.h"
in vec2 iFragCoord; in vec2 iFragCoord;
out vec4 fragColor; out vec4 fragColor;
@ -10,22 +11,6 @@ uniform uvec2 uInRes[8];
uniform uvec2 uOutRes; uniform uvec2 uOutRes;
uniform float uSharpness; uniform float uSharpness;
// the following are not available until verion 400 or later
// so we implement our own versions of them
uint bitfieldExtract(uint val, int off, int size)
{
uint mask = uint((1 << size) - 1);
return uint(val >> off) & mask;
}
uint bitfieldInsert(uint a, uint b, int c, int d)
{
uint mask = ~(0xffffffffu << d) << c;
mask = ~mask;
a &= mask;
return a | (b << c);
}
#define A_GPU 1 #define A_GPU 1
#define A_GLSL 1 #define A_GLSL 1

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,48 @@
#version 300 es
precision mediump float;
#include "compat.h"
in vec2 iFragCoord;
out vec4 fragColor;
uniform sampler2D iChannel0;
uniform uvec2 uInRes[8];
uniform uvec2 uOutRes;
#define A_GPU 1
#define A_GLSL 1
#define A_FULL 1
#include "ffx_a.h"
#define FSR_EASU_F 1
#define FSR_RCAS_F 1
AF4 FsrEasuRF(AF2 p){return AF4(textureGather(iChannel0, p, 0));}
AF4 FsrEasuGF(AF2 p){return AF4(textureGather(iChannel0, p, 1));}
AF4 FsrEasuBF(AF2 p){return AF4(textureGather(iChannel0, p, 2));}
#include "ffx_fsr1.h"
void main()
{
AU4 con0, con1, con2, con3;
vec2 inRes = vec2(uInRes[0]);
vec2 outRes = vec2(uOutRes);
FsrEasuCon(
con0,
con1,
con2,
con3,
inRes.x , inRes.y,
inRes.x , inRes.y,
outRes.x, outRes.y
);
vec3 color;
uvec2 point = uvec2(iFragCoord * outRes);
FsrEasuF(color, point, con0, con1, con2, con3);
fragColor = vec4(color.xyz, 1);
}

View File

@ -0,0 +1,36 @@
#version 300 es
precision mediump float;
#include "compat.h"
in vec2 iFragCoord;
out vec4 fragColor;
uniform sampler2D iChannel0;
uniform uvec2 uInRes[8];
uniform float uSharpness;
#define A_GPU 1
#define A_GLSL 1
#define A_FULL 1
#include "ffx_a.h"
AF4 FsrRcasLoadF(ASU2 p) { return texelFetch(iChannel0, ASU2(p), 0); }
void FsrRcasInputF(inout AF1 r, inout AF1 g, inout AF1 b) {}
#define FSR_RCAS_F 1
#define FSR_RCAS_DENOISE 1
#include "ffx_fsr1.h"
void main()
{
vec2 inRes = vec2(uInRes[0]);
uvec2 point = uvec2(iFragCoord * inRes);
uvec4 const0;
FsrRcasCon(const0, 1.0f - uSharpness);
FsrRcasF(fragColor.r, fragColor.g, fragColor.b, point, const0);
fragColor.a = 1.0f;
}

View File

@ -42,10 +42,10 @@ typedef struct RenderStep
EGL_Texture *owner; EGL_Texture *owner;
bool enabled; bool enabled;
bool ready;
GLuint fb; GLuint fb;
GLuint tex; GLuint tex;
EGL_Shader * shader; EGL_Shader * shader;
float scale;
unsigned int width, height; unsigned int width, height;
@ -92,8 +92,6 @@ bool egl_textureInit(EGL * egl, EGL_Texture ** texture_,
glSamplerParameteri(this->sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glSamplerParameteri(this->sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glSamplerParameteri(this->sampler, GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE); glSamplerParameteri(this->sampler, GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE);
glSamplerParameteri(this->sampler, GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE); glSamplerParameteri(this->sampler, GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE);
this->scale = 1.0f;
return true; return true;
} }
@ -126,15 +124,15 @@ void egl_textureFree(EGL_Texture ** tex)
bool setupRenderStep(EGL_Texture * this, RenderStep * step) bool setupRenderStep(EGL_Texture * this, RenderStep * step)
{ {
step->width = this->format.width * step->scale; if (step->ready && (step->width > 0 || step->height > 0))
step->height = this->format.height * step->scale; return true;
glBindTexture(GL_TEXTURE_2D, step->tex); glBindTexture(GL_TEXTURE_2D, step->tex);
glTexImage2D(GL_TEXTURE_2D, glTexImage2D(GL_TEXTURE_2D,
0, 0,
this->format.intFormat, this->format.intFormat,
step->width, step->width > 0 ? step->width : this->format.width,
step->height, step->height > 0 ? step->height : this->format.height,
0, 0,
this->format.format, this->format.format,
this->format.dataType, this->format.dataType,
@ -143,6 +141,7 @@ bool setupRenderStep(EGL_Texture * this, RenderStep * step)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_2D, 0);
step->ready = true;
return true; return true;
} }
@ -168,8 +167,7 @@ bool egl_textureSetup(EGL_Texture * this, enum EGL_PixelFormat pixFmt,
{ {
RenderStep * step; RenderStep * step;
for(ll_reset(this->render); ll_walk(this->render, (void **)&step); ) for(ll_reset(this->render); ll_walk(this->render, (void **)&step); )
if (!setupRenderStep(this, step)) step->ready = false;
return false;
} }
return this->ops.setup(this, &setup); return this->ops.setup(this, &setup);
@ -309,9 +307,25 @@ enum EGL_TexStatus egl_textureBind(EGL_Texture * this)
{ {
ringbuffer_reset(this->textures); ringbuffer_reset(this->textures);
/* configure all the filters */
for(ll_reset(this->render); ll_walk(this->render, (void **)&step); )
{
if (!step->enabled)
continue;
if (!step->ready)
setupRenderStep(this, step);
}
if ((status = this->ops.get(this, &tex)) != EGL_TEX_STATUS_OK) if ((status = this->ops.get(this, &tex)) != EGL_TEX_STATUS_OK)
return status; return status;
struct Rect finalSz =
{
.x = this->format.width,
.y = this->format.height
};
ringbuffer_push(this->textures, &(BindInfo) { ringbuffer_push(this->textures, &(BindInfo) {
.tex = tex, .tex = tex,
.width = this->format.width, .width = this->format.width,
@ -346,7 +360,13 @@ enum EGL_TexStatus egl_textureBind(EGL_Texture * this)
else else
glBindFramebuffer(GL_FRAMEBUFFER, step->fb); glBindFramebuffer(GL_FRAMEBUFFER, step->fb);
glViewport(0, 0, step->width, step->height); const struct Rect sz =
{
.x = step->width > 0 ? step->width : this->format.width,
.y = step->height > 0 ? step->height : this->format.height
};
glViewport(0, 0, sz.x, sz.y);
/* use the shader (also configures it's set uniforms) */ /* use the shader (also configures it's set uniforms) */
egl_shaderUse(step->shader); egl_shaderUse(step->shader);
@ -354,16 +374,18 @@ enum EGL_TexStatus egl_textureBind(EGL_Texture * this)
/* set the size uniforms */ /* set the size uniforms */
glUniform2uiv(step->uInRes, glUniform2uiv(step->uInRes,
ringbuffer_getCount(this->textures), bd->dimensions); ringbuffer_getCount(this->textures), bd->dimensions);
glUniform2ui(step->uOutRes, step->width, step->height); glUniform2ui(step->uOutRes, sz.x, sz.y);
/* render the scene */ /* render the scene */
egl_modelRender(this->model); egl_modelRender(this->model);
finalSz.x = sz.x;
finalSz.y = sz.y;
/* push the details into the ringbuffer for the next pass */ /* push the details into the ringbuffer for the next pass */
ringbuffer_push(this->textures, &(BindInfo) { ringbuffer_push(this->textures, &(BindInfo) {
.tex = step->tex, .tex = step->tex,
.width = step->width, .width = sz.x,
.height = step->height .height = sz.y
}); });
/* bind the textures for the next pass */ /* bind the textures for the next pass */
@ -378,6 +400,8 @@ enum EGL_TexStatus egl_textureBind(EGL_Texture * this)
egl_resetViewport(this->egl); egl_resetViewport(this->egl);
} }
this->finalWidth = finalSz.x;
this->finalHeight = finalSz.y;
this->postProcessed = true; this->postProcessed = true;
} }
else else
@ -393,7 +417,7 @@ enum EGL_TexStatus egl_textureBind(EGL_Texture * this)
} }
PostProcessHandle egl_textureAddFilter(EGL_Texture * this, EGL_Shader * shader, PostProcessHandle egl_textureAddFilter(EGL_Texture * this, EGL_Shader * shader,
float outputScale, bool enabled) bool enabled)
{ {
if (!this->render) if (!this->render)
{ {
@ -407,21 +431,10 @@ PostProcessHandle egl_textureAddFilter(EGL_Texture * this, EGL_Shader * shader,
glGenTextures(1, &step->tex); glGenTextures(1, &step->tex);
step->owner = this; step->owner = this;
step->shader = shader; step->shader = shader;
step->scale = outputScale;
step->uInRes = egl_shaderGetUniform(shader, "uInRes" ); step->uInRes = egl_shaderGetUniform(shader, "uInRes" );
step->uOutRes = egl_shaderGetUniform(shader, "uOutRes"); step->uOutRes = egl_shaderGetUniform(shader, "uOutRes");
step->enabled = enabled; step->enabled = enabled;
this->scale = outputScale;
if (this->formatValid)
if (!setupRenderStep(this, step))
{
glDeleteTextures(1, &step->tex);
free(step);
return NULL;
}
ll_push(this->render, step); ll_push(this->render, step);
return (PostProcessHandle)step; return (PostProcessHandle)step;
} }
@ -436,12 +449,33 @@ void egl_textureEnableFilter(PostProcessHandle * handle, bool enable)
egl_textureInvalidate(step->owner); egl_textureInvalidate(step->owner);
} }
void egl_textureSetFilterRes(PostProcessHandle * handle,
unsigned int x, unsigned int y)
{
RenderStep * step = (RenderStep *)handle;
if (step->width == x && step->height == y)
return;
step->width = x;
step->height = y;
step->ready = false;
egl_textureInvalidate(step->owner);
}
void egl_textureInvalidate(EGL_Texture * texture) void egl_textureInvalidate(EGL_Texture * texture)
{ {
texture->postProcessed = false; texture->postProcessed = false;
} }
float egl_textureGetScale(EGL_Texture * this) void egl_textureGetFinalSize(EGL_Texture * this, struct Rect * rect)
{ {
return this->scale; if (!this->render)
{
rect->x = this->format.width;
rect->y = this->format.height;
return;
}
rect->x = this->finalWidth;
rect->y = this->finalHeight;
} }

View File

@ -26,6 +26,7 @@
#include "model.h" #include "model.h"
#include "common/framebuffer.h" #include "common/framebuffer.h"
#include "common/ringbuffer.h" #include "common/ringbuffer.h"
#include "common/types.h"
#include "util.h" #include "util.h"
#include "ll.h" #include "ll.h"
@ -144,7 +145,7 @@ struct EGL_Texture
_Atomic(bool) updated; _Atomic(bool) updated;
bool postProcessed; bool postProcessed;
EGL_Model * model; EGL_Model * model;
float scale; unsigned int finalWidth, finalHeight;
void * bindData; void * bindData;
int bindDataSize; int bindDataSize;
@ -172,10 +173,13 @@ enum EGL_TexStatus egl_textureBind(EGL_Texture * texture);
typedef void * PostProcessHandle; typedef void * PostProcessHandle;
PostProcessHandle egl_textureAddFilter(EGL_Texture * texture, PostProcessHandle egl_textureAddFilter(EGL_Texture * texture,
EGL_Shader * shader, float outputScale, bool enabled); EGL_Shader * shader, bool enabled);
void egl_textureEnableFilter(PostProcessHandle * handle, bool enable); void egl_textureEnableFilter(PostProcessHandle * handle, bool enable);
void egl_textureSetFilterRes(PostProcessHandle * handle,
unsigned int x, unsigned int y);
void egl_textureInvalidate(EGL_Texture * texture); void egl_textureInvalidate(EGL_Texture * texture);
float egl_textureGetScale(EGL_Texture * texture); void egl_textureGetFinalSize(EGL_Texture * texture, struct Rect * rect);