diff --git a/client/renderers/EGL/desktop.c b/client/renderers/EGL/desktop.c index 2a9baa7d..f8f70597 100644 --- a/client/renderers/EGL/desktop.c +++ b/client/renderers/EGL/desktop.c @@ -42,6 +42,13 @@ #include "postprocess.h" #include "filters.h" +enum +{ + HDR_PEAK_LUMINANCE_MIN = 80, + HDR_PEAK_LUMINANCE_DEFAULT = 10000, + HDR_PEAK_LUMINANCE_MAX = 10000 +}; + struct DesktopShader { EGL_Shader * shader; @@ -482,12 +489,24 @@ bool egl_desktopRender(EGL_Desktop * desktop, unsigned int outputWidth, *fullFrame = false; const bool hdr = desktop->hdr && !desktop->useSpice; + uint32_t hdrPeak = 0; + if (hdr) + { + hdrPeak = max(desktop->format.hdrMaxDisplayLuminance, + desktop->format.hdrMaxContentLightLevel); + if (!hdrPeak) + hdrPeak = HDR_PEAK_LUMINANCE_DEFAULT; + else + hdrPeak = clamp(hdrPeak, + HDR_PEAK_LUMINANCE_MIN, HDR_PEAK_LUMINANCE_MAX); + } + const bool processFrame = atomic_exchange(&desktop->processFrame, false) || egl_postProcessConfigModified(desktop->pp); if (processFrame && egl_postProcessRun(desktop->pp, tex, desktop->mesh, width, height, outputWidth, outputHeight, dma, - hdr && desktop->hdrPQ) && + hdr && desktop->hdrPQ, (float)hdrPeak) && egl_postProcessNeedsFullFrame(desktop->pp)) { /* The filter output may have changed everywhere, but this only applies to diff --git a/client/renderers/EGL/filter.h b/client/renderers/EGL/filter.h index acb43d7a..09498d42 100644 --- a/client/renderers/EGL/filter.h +++ b/client/renderers/EGL/filter.h @@ -33,6 +33,8 @@ typedef struct EGL_FilterRects EGL_DesktopRects * rects; GLfloat * matrix; int width, height; + /* zero for SDR, otherwise the HDR signal peak in cd/m² */ + float hdrPeak; } EGL_FilterRects; diff --git a/client/renderers/EGL/filter_ffx_cas.c b/client/renderers/EGL/filter_ffx_cas.c index 0af01e74..2feb04c0 100644 --- a/client/renderers/EGL/filter_ffx_cas.c +++ b/client/renderers/EGL/filter_ffx_cas.c @@ -29,12 +29,15 @@ #include "basic.vert.h" #include "ffx_cas.frag.h" +#define CAS_SCRGB_REFERENCE_WHITE 80.0f + typedef struct EGL_FilterFFXCAS { EGL_Filter base; EGL_Shader * shader; EGL_Uniform * uConsts; + EGL_Uniform * uHDRScale; EGL_Effect * effect; EGL_EffectPass * pass; bool enable; @@ -132,7 +135,8 @@ static bool egl_filterFFXCASInit(EGL_Filter ** filter) goto error_effect; } - this->uConsts = egl_shaderGetUniform(this->shader, "uConsts"); + this->uConsts = egl_shaderGetUniform(this->shader, "uConsts" ); + this->uHDRScale = egl_shaderGetUniform(this->shader, "uHDRScale"); egl_filterFFXCASLoadState(&this->base); *filter = &this->base; @@ -270,6 +274,10 @@ static EGL_Texture * egl_filterFFXCASRun(EGL_Filter * filter, { EGL_FilterFFXCAS * this = UPCAST(EGL_FilterFFXCAS, filter); + const float hdrScale = rects->hdrPeak > 0.0f ? + CAS_SCRGB_REFERENCE_WHITE / rects->hdrPeak : 0.0f; + egl_uniform1f(this->uHDRScale, hdrScale); + return egl_effectRun(this->effect, rects, texture); } diff --git a/client/renderers/EGL/postprocess.c b/client/renderers/EGL/postprocess.c index 4052eb60..15119bfe 100644 --- a/client/renderers/EGL/postprocess.c +++ b/client/renderers/EGL/postprocess.c @@ -876,7 +876,8 @@ static bool configureChain(EGL_PostProcess * this, EGL_PixelFormat pixFmt, bool egl_postProcessRun(EGL_PostProcess * this, EGL_Texture * tex, EGL_DesktopRects * rects, int desktopWidth, int desktopHeight, - unsigned int targetX, unsigned int targetY, bool useDMA, bool hdrPQ) + unsigned int targetX, unsigned int targetY, bool useDMA, bool hdrPQ, + float hdrPeak) { if (targetX == 0 && targetY == 0) DEBUG_FATAL("targetX || targetY == 0"); @@ -918,10 +919,11 @@ bool egl_postProcessRun(EGL_PostProcess * this, EGL_Texture * tex, } EGL_FilterRects filterRects = { - .rects = rects, - .matrix = this->matrix, - .width = desktopWidth, - .height = desktopHeight, + .rects = rects, + .matrix = this->matrix, + .width = desktopWidth, + .height = desktopHeight, + .hdrPeak = hdrPeak, }; EGL_Texture * texture = tex; diff --git a/client/renderers/EGL/postprocess.h b/client/renderers/EGL/postprocess.h index 063bc738..64029f95 100644 --- a/client/renderers/EGL/postprocess.h +++ b/client/renderers/EGL/postprocess.h @@ -47,7 +47,8 @@ bool egl_postProcessNeedsFullFrame(EGL_PostProcess * this); * 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, bool useDMA, bool hdrPQ); + unsigned int targetX, unsigned int targetY, bool useDMA, bool hdrPQ, + float hdrPeak); /* Return the current output texture and whether it remains PQ encoded. */ EGL_Texture * egl_postProcessGetOutput(EGL_PostProcess * this, diff --git a/client/renderers/EGL/shader/ffx_cas.frag b/client/renderers/EGL/shader/ffx_cas.frag index b98150ad..273e888d 100644 --- a/client/renderers/EGL/shader/ffx_cas.frag +++ b/client/renderers/EGL/shader/ffx_cas.frag @@ -5,12 +5,14 @@ precision highp float; precision highp int; #include "compat.h" +#include "hdr.h" in vec2 fragCoord; out vec4 fragColor; uniform sampler2D sampler1; uniform uvec4 uConsts[2]; +uniform float uHDRScale; #define A_GPU 1 #define A_GLSL 1 @@ -19,7 +21,11 @@ uniform uvec4 uConsts[2]; vec3 imageLoad(ivec2 point) { - return texelFetch(sampler1, point, 0).rgb; + vec3 color = texelFetch(sampler1, point, 0).rgb; + if (uHDRScale > 0.0) + color = max(bt709to2020(color * uHDRScale), vec3(0.0)); + + return color; } AF3 CasLoad(ASU2 p) @@ -39,4 +45,9 @@ void main() CasFilter( fragColor.r, fragColor.g, fragColor.b, point, uConsts[0], uConsts[1], true); + + if (uHDRScale > 0.0) + fragColor.rgb = bt2020to709(fragColor.rgb) / uHDRScale; + + fragColor.a = 1.0; }