[client] egl: make the bgr_bgra filter generic for 24-bit formats

This commit is contained in:
Geoffrey McRae 2023-11-08 20:29:42 +11:00
parent 3843afa927
commit c0e09e13a5
12 changed files with 154 additions and 59 deletions

View file

@ -56,7 +56,7 @@ build_shaders(
shader/damage.vert shader/damage.vert
shader/damage.frag shader/damage.frag
shader/basic.vert shader/basic.vert
shader/convert_bgr_bgra.frag shader/convert_24bit.frag
shader/ffx_cas.frag shader/ffx_cas.frag
shader/ffx_fsr1_easu.frag shader/ffx_fsr1_easu.frag
shader/ffx_fsr1_rcas.frag shader/ffx_fsr1_rcas.frag
@ -88,7 +88,7 @@ add_library(renderer_EGL STATIC
postprocess.c postprocess.c
ffx.c ffx.c
filter.c filter.c
filter_bgr_bgra.c filter_24bit.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

@ -100,7 +100,7 @@ static bool cursorTexInit(struct CursorTex * t,
} }
if (!egl_shaderCompile(t->shader, if (!egl_shaderCompile(t->shader,
vertex_code, vertex_size, fragment_code, fragment_size, false)) vertex_code, vertex_size, fragment_code, fragment_size, false, NULL))
{ {
DEBUG_ERROR("Failed to compile the cursor shader"); DEBUG_ERROR("Failed to compile the cursor shader");
return false; return false;

View file

@ -77,7 +77,7 @@ bool egl_damageInit(EGL_Damage ** damage)
if (!egl_shaderCompile((*damage)->shader, if (!egl_shaderCompile((*damage)->shader,
b_shader_damage_vert, b_shader_damage_vert_size, b_shader_damage_vert, b_shader_damage_vert_size,
b_shader_damage_frag, b_shader_damage_frag_size, b_shader_damage_frag, b_shader_damage_frag_size,
false)) false, NULL))
{ {
DEBUG_ERROR("Failed to compile the damage shader"); DEBUG_ERROR("Failed to compile the damage shader");
return false; return false;

View file

@ -114,7 +114,7 @@ static bool egl_initDesktopShader(
if (!egl_shaderCompile(shader->shader, if (!egl_shaderCompile(shader->shader,
vertex_code , vertex_size, vertex_code , vertex_size,
fragment_code, fragment_size, fragment_code, fragment_size,
useDMA)) useDMA, NULL))
{ {
return false; return false;
} }
@ -207,7 +207,7 @@ bool egl_desktopInit(EGL * egl, EGL_Desktop ** desktop_, EGLDisplay * display,
} }
// this MUST be first // this MUST be first
egl_postProcessAdd(desktop->pp, &egl_filterBGRtoBGRAOps); egl_postProcessAdd(desktop->pp, &egl_filter24bitOps);
egl_postProcessAdd(desktop->pp, &egl_filterDownscaleOps); egl_postProcessAdd(desktop->pp, &egl_filterDownscaleOps);
egl_postProcessAdd(desktop->pp, &egl_filterFFXCASOps ); egl_postProcessAdd(desktop->pp, &egl_filterFFXCASOps );

View file

@ -29,14 +29,15 @@
#include "cimgui.h" #include "cimgui.h"
#include "basic.vert.h" #include "basic.vert.h"
#include "convert_bgr_bgra.frag.h" #include "convert_24bit.frag.h"
typedef struct EGL_FilterBGRtoBGRA typedef struct EGL_Filter24bit
{ {
EGL_Filter base; EGL_Filter base;
bool enable; bool enable;
EGL_PixelFormat format;
int useDMA; int useDMA;
unsigned int width, height; unsigned int width, height;
unsigned int desktopWidth, desktopHeight; unsigned int desktopWidth, desktopHeight;
@ -48,11 +49,11 @@ typedef struct EGL_FilterBGRtoBGRA
EGL_Framebuffer * fb; EGL_Framebuffer * fb;
GLuint sampler[2]; GLuint sampler[2];
} }
EGL_FilterBGRtoBGRA; EGL_Filter24bit;
static bool egl_filterBGRtoBGRAInit(EGL_Filter ** filter) static bool egl_filter24bitInit(EGL_Filter ** filter)
{ {
EGL_FilterBGRtoBGRA * this = calloc(1, sizeof(*this)); EGL_Filter24bit * this = calloc(1, sizeof(*this));
if (!this) if (!this)
{ {
DEBUG_ERROR("Failed to allocate ram"); DEBUG_ERROR("Failed to allocate ram");
@ -94,9 +95,9 @@ error_this:
return false; return false;
} }
static void egl_filterBGRtoBGRAFree(EGL_Filter * filter) static void egl_filter24bitFree(EGL_Filter * filter)
{ {
EGL_FilterBGRtoBGRA * this = UPCAST(EGL_FilterBGRtoBGRA, filter); EGL_Filter24bit * this = UPCAST(EGL_Filter24bit, filter);
egl_shaderFree(&this->shader); egl_shaderFree(&this->shader);
egl_framebufferFree(&this->fb); egl_framebufferFree(&this->fb);
@ -104,22 +105,28 @@ static void egl_filterBGRtoBGRAFree(EGL_Filter * filter)
free(this); free(this);
} }
static bool egl_filterBGRtoBGRASetup(EGL_Filter * filter, static bool egl_filter24bitSetup(EGL_Filter * filter,
enum EGL_PixelFormat pixFmt, unsigned int width, unsigned int height, enum EGL_PixelFormat pixFmt, unsigned int width, unsigned int height,
unsigned int desktopWidth, unsigned int desktopHeight, unsigned int desktopWidth, unsigned int desktopHeight,
bool useDMA) bool useDMA)
{ {
EGL_FilterBGRtoBGRA * this = UPCAST(EGL_FilterBGRtoBGRA, filter); EGL_Filter24bit * this = UPCAST(EGL_Filter24bit, filter);
if (pixFmt != EGL_PF_BGR_32 && pixFmt != EGL_PF_RGB_24) if (pixFmt != EGL_PF_BGR_32 && pixFmt != EGL_PF_RGB_24)
return false; return false;
if (this->useDMA != useDMA) if (this->useDMA != useDMA || this->format != pixFmt)
{ {
EGL_ShaderDefine defines[] =
{
{"OUTPUT", pixFmt == EGL_PF_BGR_32 ? "fragColor.bgra" : "fragColor.rgba" },
{0}
};
if (!egl_shaderCompile(this->shader, if (!egl_shaderCompile(this->shader,
b_shader_basic_vert , b_shader_basic_vert_size, b_shader_basic_vert , b_shader_basic_vert_size,
b_shader_convert_bgr_bgra_frag, b_shader_convert_bgr_bgra_frag_size, b_shader_convert_24bit_frag, b_shader_convert_24bit_frag_size,
useDMA) useDMA, defines)
) )
{ {
DEBUG_ERROR("Failed to compile the shader"); DEBUG_ERROR("Failed to compile the shader");
@ -144,6 +151,7 @@ static bool egl_filterBGRtoBGRASetup(EGL_Filter * filter,
if (!egl_framebufferSetup(this->fb, pixFmt, desktopWidth, desktopHeight)) if (!egl_framebufferSetup(this->fb, pixFmt, desktopWidth, desktopHeight))
return false; return false;
this->format = pixFmt;
this->width = width; this->width = width;
this->height = height; this->height = height;
this->desktopWidth = desktopWidth; this->desktopWidth = desktopWidth;
@ -153,17 +161,17 @@ static bool egl_filterBGRtoBGRASetup(EGL_Filter * filter,
return true; return true;
} }
static void egl_filterBGRtoBGRAGetOutputRes(EGL_Filter * filter, static void egl_filter24bitGetOutputRes(EGL_Filter * filter,
unsigned int *width, unsigned int *height) unsigned int *width, unsigned int *height)
{ {
EGL_FilterBGRtoBGRA * this = UPCAST(EGL_FilterBGRtoBGRA, filter); EGL_Filter24bit * this = UPCAST(EGL_Filter24bit, filter);
*width = this->desktopWidth; *width = this->desktopWidth;
*height = this->desktopHeight; *height = this->desktopHeight;
} }
static bool egl_filterBGRtoBGRAPrepare(EGL_Filter * filter) static bool egl_filter24bitPrepare(EGL_Filter * filter)
{ {
EGL_FilterBGRtoBGRA * this = UPCAST(EGL_FilterBGRtoBGRA, filter); EGL_Filter24bit * this = UPCAST(EGL_Filter24bit, filter);
if (this->prepared) if (this->prepared)
return true; return true;
@ -176,10 +184,10 @@ static bool egl_filterBGRtoBGRAPrepare(EGL_Filter * filter)
return true; return true;
} }
static EGL_Texture * egl_filterBGRtoBGRARun(EGL_Filter * filter, static EGL_Texture * egl_filter24bitRun(EGL_Filter * filter,
EGL_FilterRects * rects, EGL_Texture * texture) EGL_FilterRects * rects, EGL_Texture * texture)
{ {
EGL_FilterBGRtoBGRA * this = UPCAST(EGL_FilterBGRtoBGRA, filter); EGL_Filter24bit * this = UPCAST(EGL_Filter24bit, filter);
egl_framebufferBind(this->fb); egl_framebufferBind(this->fb);
@ -194,19 +202,19 @@ static EGL_Texture * egl_filterBGRtoBGRARun(EGL_Filter * filter,
return egl_framebufferGetTexture(this->fb); return egl_framebufferGetTexture(this->fb);
} }
EGL_FilterOps egl_filterBGRtoBGRAOps = EGL_FilterOps egl_filter24bitOps =
{ {
.id = "bgrtobgra", .id = "24bit",
.name = "BGRtoBGRA", .name = "24bit",
.type = EGL_FILTER_TYPE_INTERNAL, .type = EGL_FILTER_TYPE_INTERNAL,
.earlyInit = NULL, .earlyInit = NULL,
.init = egl_filterBGRtoBGRAInit, .init = egl_filter24bitInit,
.free = egl_filterBGRtoBGRAFree, .free = egl_filter24bitFree,
.imguiConfig = NULL, .imguiConfig = NULL,
.saveState = NULL, .saveState = NULL,
.loadState = NULL, .loadState = NULL,
.setup = egl_filterBGRtoBGRASetup, .setup = egl_filter24bitSetup,
.getOutputRes = egl_filterBGRtoBGRAGetOutputRes, .getOutputRes = egl_filter24bitGetOutputRes,
.prepare = egl_filterBGRtoBGRAPrepare, .prepare = egl_filter24bitPrepare,
.run = egl_filterBGRtoBGRARun .run = egl_filter24bitRun
}; };

View file

@ -316,7 +316,7 @@ static bool egl_filterDownscaleSetup(EGL_Filter * filter,
b_shader_basic_vert , b_shader_basic_vert_size, b_shader_basic_vert , b_shader_basic_vert_size,
b_shader_downscale_frag, b_shader_downscale_frag,
b_shader_downscale_frag_size, b_shader_downscale_frag_size,
useDMA) useDMA, NULL)
) )
{ {
DEBUG_ERROR("Failed to compile the shader"); DEBUG_ERROR("Failed to compile the shader");
@ -327,7 +327,7 @@ static bool egl_filterDownscaleSetup(EGL_Filter * filter,
b_shader_basic_vert, b_shader_basic_vert_size, b_shader_basic_vert, b_shader_basic_vert_size,
b_shader_downscale_linear_frag, b_shader_downscale_linear_frag,
b_shader_downscale_linear_frag_size, b_shader_downscale_linear_frag_size,
useDMA) useDMA, NULL)
) )
{ {
DEBUG_ERROR("Failed to compile the shader"); DEBUG_ERROR("Failed to compile the shader");
@ -338,7 +338,7 @@ static bool egl_filterDownscaleSetup(EGL_Filter * filter,
b_shader_basic_vert, b_shader_basic_vert_size, b_shader_basic_vert, b_shader_basic_vert_size,
b_shader_downscale_lanczos2_frag, b_shader_downscale_lanczos2_frag,
b_shader_downscale_lanczos2_frag_size, b_shader_downscale_lanczos2_frag_size,
useDMA) useDMA, NULL)
) )
{ {
DEBUG_ERROR("Failed to compile the shader"); DEBUG_ERROR("Failed to compile the shader");

View file

@ -222,7 +222,7 @@ static bool egl_filterFFXCASSetup(EGL_Filter * filter,
if (!egl_shaderCompile(this->shader, if (!egl_shaderCompile(this->shader,
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,
useDMA) useDMA, NULL)
) )
{ {
DEBUG_ERROR("Failed to compile the shader"); DEBUG_ERROR("Failed to compile the shader");

View file

@ -127,7 +127,7 @@ static bool egl_filterFFXFSR1Init(EGL_Filter ** filter)
if (!egl_shaderCompile(this->rcas, if (!egl_shaderCompile(this->rcas,
b_shader_basic_vert , b_shader_basic_vert_size, b_shader_basic_vert , b_shader_basic_vert_size,
b_shader_ffx_fsr1_rcas_frag, b_shader_ffx_fsr1_rcas_frag_size, b_shader_ffx_fsr1_rcas_frag, b_shader_ffx_fsr1_rcas_frag_size,
false) false, NULL)
) )
{ {
DEBUG_ERROR("Failed to compile the Rcas shader"); DEBUG_ERROR("Failed to compile the Rcas shader");
@ -336,7 +336,7 @@ static bool egl_filterFFXFSR1Setup(EGL_Filter * filter,
if (!egl_shaderCompile(this->easu, if (!egl_shaderCompile(this->easu,
b_shader_basic_vert , b_shader_basic_vert_size, b_shader_basic_vert , b_shader_basic_vert_size,
b_shader_ffx_fsr1_easu_frag, b_shader_ffx_fsr1_easu_frag_size, b_shader_ffx_fsr1_easu_frag, b_shader_ffx_fsr1_easu_frag_size,
useDMA) useDMA, NULL)
) )
{ {
DEBUG_ERROR("Failed to compile the Easu shader"); DEBUG_ERROR("Failed to compile the Easu shader");

View file

@ -20,7 +20,7 @@
#pragma once #pragma once
extern EGL_FilterOps egl_filterBGRtoBGRAOps; extern EGL_FilterOps egl_filter24bitOps;
extern EGL_FilterOps egl_filterDownscaleOps; extern EGL_FilterOps egl_filterDownscaleOps;
extern EGL_FilterOps egl_filterFFXCASOps; extern EGL_FilterOps egl_filterFFXCASOps;
extern EGL_FilterOps egl_filterFFXFSR1Ops; extern EGL_FilterOps egl_filterFFXFSR1Ops;

View file

@ -65,7 +65,8 @@ void egl_shaderFree(EGL_Shader ** shader)
} }
bool egl_shaderLoad(EGL_Shader * this, bool egl_shaderLoad(EGL_Shader * this,
const char * vertex_file, const char * fragment_file, bool useDMA) const char * vertex_file, const char * fragment_file, bool useDMA,
const EGL_ShaderDefine * defines)
{ {
char * vertex_code, * fragment_code; char * vertex_code, * fragment_code;
size_t vertex_size, fragment_size; size_t vertex_size, fragment_size;
@ -89,7 +90,7 @@ bool egl_shaderLoad(EGL_Shader * this,
bool ret = egl_shaderCompile(this, bool ret = egl_shaderCompile(this,
vertex_code, vertex_size, fragment_code, fragment_size, vertex_code, vertex_size, fragment_code, fragment_size,
useDMA); useDMA, defines);
free(vertex_code); free(vertex_code);
free(fragment_code); free(fragment_code);
@ -210,8 +211,12 @@ static bool shaderCompile(EGL_Shader * this, const char * vertex_code,
bool egl_shaderCompile(EGL_Shader * this, const char * vertex_code, bool egl_shaderCompile(EGL_Shader * this, const char * vertex_code,
size_t vertex_size, const char * fragment_code, size_t fragment_size, size_t vertex_size, const char * fragment_code, size_t fragment_size,
bool useDMA) bool useDMA, const EGL_ShaderDefine * defines)
{ {
bool result = false;
char * processed = NULL;
char * newCode = NULL;
if (useDMA) if (useDMA)
{ {
const char * search = "sampler2D"; const char * search = "sampler2D";
@ -225,12 +230,13 @@ bool egl_shaderCompile(EGL_Shader * this, const char * vertex_code,
src += strlen(search); src += strlen(search);
} }
const int diff = (strlen(replace) - strlen(search)) * instances; const int diff = (strlen(replace) - strlen(search)) * instances;
char * newCode = malloc(fragment_size + diff + 1); const int newLen = fragment_size + diff;
newCode = malloc(newLen + 1);
if (!newCode) if (!newCode)
{ {
DEBUG_ERROR("Out of memory"); DEBUG_ERROR("Out of memory");
return false; goto exit;
} }
src = fragment_code; src = fragment_code;
@ -250,20 +256,94 @@ bool egl_shaderCompile(EGL_Shader * this, const char * vertex_code,
const int final = fragment_size - (src - fragment_code); const int final = fragment_size - (src - fragment_code);
memcpy(dst, src, final); memcpy(dst, src, final);
dst[final] = 0; dst[final] = '\0';
bool result = shaderCompile( fragment_code = newCode;
this, fragment_size = newLen;
vertex_code, vertex_size,
newCode , fragment_size + diff);
free(newCode);
return result;
} }
return shaderCompile(this, if (defines)
{
// find the end of any existing lines starting with #
bool newLine = true;
bool skip = false;
int insertPos = 0;
for(int i = 0; i < fragment_size; ++i)
{
if (skip)
{
if (fragment_code[i] == '\n')
skip = false;
continue;
}
switch(fragment_code[i])
{
case '\n':
newLine = true;
continue;
case ' ':
case '\t':
case '\r':
continue;
case '#':
if (newLine)
{
skip = true;
continue;
}
//fallthrough
default:
newLine = false;
break;
}
if (!newLine)
{
insertPos = i - 1;
break;
}
}
int processedLen = fragment_size;
const char * defineFormat = "#define %s %s\n";
for(const EGL_ShaderDefine * define = defines; define->name; ++define)
processedLen += snprintf(NULL, 0, defineFormat, define->name, define->value);
processed = malloc(processedLen);
if (!processed)
{
DEBUG_ERROR("Out of memory");
goto exit;
}
memcpy(processed, fragment_code, insertPos);
int offset = insertPos;
for(const EGL_ShaderDefine * define = defines; define->name; ++define)
offset += sprintf(processed + offset, defineFormat,
define->name, define->value);
memcpy(
processed + offset,
fragment_code + insertPos,
fragment_size - insertPos);
fragment_code = processed;
fragment_size = processedLen;
}
result = shaderCompile(this,
vertex_code , vertex_size, vertex_code , vertex_size,
fragment_code, fragment_size); fragment_code, fragment_size);
exit:
free(processed);
free(newCode);
return result;
} }
void egl_shaderSetUniforms(EGL_Shader * this, EGL_Uniform * uniforms, int count) void egl_shaderSetUniforms(EGL_Shader * this, EGL_Uniform * uniforms, int count)

View file

@ -93,15 +93,22 @@ typedef struct EGL_Uniform
} }
EGL_Uniform; EGL_Uniform;
typedef struct EGL_ShaderDefine
{
const char * name;
const char * value;
}
EGL_ShaderDefine;
bool egl_shaderInit(EGL_Shader ** shader); bool egl_shaderInit(EGL_Shader ** shader);
void egl_shaderFree(EGL_Shader ** shader); void egl_shaderFree(EGL_Shader ** shader);
bool egl_shaderLoad(EGL_Shader * model, const char * vertex_file, bool egl_shaderLoad(EGL_Shader * model, const char * vertex_file,
const char * fragment_file, bool useDMA); const char * fragment_file, bool useDMA, const EGL_ShaderDefine * defines);
bool egl_shaderCompile(EGL_Shader * model, const char * vertex_code, bool egl_shaderCompile(EGL_Shader * model, const char * vertex_code,
size_t vertex_size, const char * fragment_code, size_t fragment_size, size_t vertex_size, const char * fragment_code, size_t fragment_size,
bool useDMA); bool useDMA, const EGL_ShaderDefine * defines);
void egl_shaderSetUniforms(EGL_Shader * shader, EGL_Uniform * uniforms, void egl_shaderSetUniforms(EGL_Shader * shader, EGL_Uniform * uniforms,
int count); int count);

View file

@ -23,7 +23,7 @@ void main()
uint trd = (outputPos.x * 3u + 2u) / 4u; uint trd = (outputPos.x * 3u + 2u) / 4u;
vec4 color_2 = texelFetch(sampler1, ivec2(trd, outputPos.y), 0); vec4 color_2 = texelFetch(sampler1, ivec2(trd, outputPos.y), 0);
fragColor.bgra = vec4( OUTPUT = vec4(
color_0.barg[outputPos.x % 4u], color_0.barg[outputPos.x % 4u],
color_1.gbar[outputPos.x % 4u], color_1.gbar[outputPos.x % 4u],
color_2.rgba[outputPos.x % 4u], color_2.rgba[outputPos.x % 4u],