mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-07-21 06:42:02 +00:00
[client] egl: correct CAS processing for HDR
Convert HDR scRGB input to normalized linear Rec.2020 before CAS, then convert the filtered result back to scRGB. Use the content metadata to select an appropriate normalization peak while leaving SDR unchanged. This follows AMD's documented recommendation for applying CAS to HDR content and prevents HDR highlights from being clamped and dimmed.
This commit is contained in:
@@ -42,6 +42,13 @@
|
|||||||
#include "postprocess.h"
|
#include "postprocess.h"
|
||||||
#include "filters.h"
|
#include "filters.h"
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
HDR_PEAK_LUMINANCE_MIN = 80,
|
||||||
|
HDR_PEAK_LUMINANCE_DEFAULT = 10000,
|
||||||
|
HDR_PEAK_LUMINANCE_MAX = 10000
|
||||||
|
};
|
||||||
|
|
||||||
struct DesktopShader
|
struct DesktopShader
|
||||||
{
|
{
|
||||||
EGL_Shader * shader;
|
EGL_Shader * shader;
|
||||||
@@ -482,12 +489,24 @@ bool egl_desktopRender(EGL_Desktop * desktop, unsigned int outputWidth,
|
|||||||
|
|
||||||
*fullFrame = false;
|
*fullFrame = false;
|
||||||
const bool hdr = desktop->hdr && !desktop->useSpice;
|
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) ||
|
const bool processFrame = atomic_exchange(&desktop->processFrame, false) ||
|
||||||
egl_postProcessConfigModified(desktop->pp);
|
egl_postProcessConfigModified(desktop->pp);
|
||||||
if (processFrame &&
|
if (processFrame &&
|
||||||
egl_postProcessRun(desktop->pp, tex, desktop->mesh,
|
egl_postProcessRun(desktop->pp, tex, desktop->mesh,
|
||||||
width, height, outputWidth, outputHeight, dma,
|
width, height, outputWidth, outputHeight, dma,
|
||||||
hdr && desktop->hdrPQ) &&
|
hdr && desktop->hdrPQ, (float)hdrPeak) &&
|
||||||
egl_postProcessNeedsFullFrame(desktop->pp))
|
egl_postProcessNeedsFullFrame(desktop->pp))
|
||||||
{
|
{
|
||||||
/* The filter output may have changed everywhere, but this only applies to
|
/* The filter output may have changed everywhere, but this only applies to
|
||||||
|
|||||||
@@ -33,6 +33,8 @@ typedef struct EGL_FilterRects
|
|||||||
EGL_DesktopRects * rects;
|
EGL_DesktopRects * rects;
|
||||||
GLfloat * matrix;
|
GLfloat * matrix;
|
||||||
int width, height;
|
int width, height;
|
||||||
|
/* zero for SDR, otherwise the HDR signal peak in cd/m² */
|
||||||
|
float hdrPeak;
|
||||||
}
|
}
|
||||||
EGL_FilterRects;
|
EGL_FilterRects;
|
||||||
|
|
||||||
|
|||||||
@@ -29,12 +29,15 @@
|
|||||||
#include "basic.vert.h"
|
#include "basic.vert.h"
|
||||||
#include "ffx_cas.frag.h"
|
#include "ffx_cas.frag.h"
|
||||||
|
|
||||||
|
#define CAS_SCRGB_REFERENCE_WHITE 80.0f
|
||||||
|
|
||||||
typedef struct EGL_FilterFFXCAS
|
typedef struct EGL_FilterFFXCAS
|
||||||
{
|
{
|
||||||
EGL_Filter base;
|
EGL_Filter base;
|
||||||
|
|
||||||
EGL_Shader * shader;
|
EGL_Shader * shader;
|
||||||
EGL_Uniform * uConsts;
|
EGL_Uniform * uConsts;
|
||||||
|
EGL_Uniform * uHDRScale;
|
||||||
EGL_Effect * effect;
|
EGL_Effect * effect;
|
||||||
EGL_EffectPass * pass;
|
EGL_EffectPass * pass;
|
||||||
bool enable;
|
bool enable;
|
||||||
@@ -133,6 +136,7 @@ static bool egl_filterFFXCASInit(EGL_Filter ** filter)
|
|||||||
}
|
}
|
||||||
|
|
||||||
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);
|
egl_filterFFXCASLoadState(&this->base);
|
||||||
|
|
||||||
*filter = &this->base;
|
*filter = &this->base;
|
||||||
@@ -270,6 +274,10 @@ static EGL_Texture * egl_filterFFXCASRun(EGL_Filter * filter,
|
|||||||
{
|
{
|
||||||
EGL_FilterFFXCAS * this = UPCAST(EGL_FilterFFXCAS, 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);
|
return egl_effectRun(this->effect, rects, texture);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -876,7 +876,8 @@ static bool configureChain(EGL_PostProcess * this, EGL_PixelFormat pixFmt,
|
|||||||
|
|
||||||
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,
|
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)
|
if (targetX == 0 && targetY == 0)
|
||||||
DEBUG_FATAL("targetX || targetY == 0");
|
DEBUG_FATAL("targetX || targetY == 0");
|
||||||
@@ -922,6 +923,7 @@ bool egl_postProcessRun(EGL_PostProcess * this, EGL_Texture * tex,
|
|||||||
.matrix = this->matrix,
|
.matrix = this->matrix,
|
||||||
.width = desktopWidth,
|
.width = desktopWidth,
|
||||||
.height = desktopHeight,
|
.height = desktopHeight,
|
||||||
|
.hdrPeak = hdrPeak,
|
||||||
};
|
};
|
||||||
|
|
||||||
EGL_Texture * texture = tex;
|
EGL_Texture * texture = tex;
|
||||||
|
|||||||
@@ -47,7 +47,8 @@ bool egl_postProcessNeedsFullFrame(EGL_PostProcess * this);
|
|||||||
* 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,
|
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. */
|
/* Return the current output texture and whether it remains PQ encoded. */
|
||||||
EGL_Texture * egl_postProcessGetOutput(EGL_PostProcess * this,
|
EGL_Texture * egl_postProcessGetOutput(EGL_PostProcess * this,
|
||||||
|
|||||||
@@ -5,12 +5,14 @@ precision highp float;
|
|||||||
precision highp int;
|
precision highp int;
|
||||||
|
|
||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
|
#include "hdr.h"
|
||||||
|
|
||||||
in vec2 fragCoord;
|
in vec2 fragCoord;
|
||||||
out vec4 fragColor;
|
out vec4 fragColor;
|
||||||
|
|
||||||
uniform sampler2D sampler1;
|
uniform sampler2D sampler1;
|
||||||
uniform uvec4 uConsts[2];
|
uniform uvec4 uConsts[2];
|
||||||
|
uniform float uHDRScale;
|
||||||
|
|
||||||
#define A_GPU 1
|
#define A_GPU 1
|
||||||
#define A_GLSL 1
|
#define A_GLSL 1
|
||||||
@@ -19,7 +21,11 @@ uniform uvec4 uConsts[2];
|
|||||||
|
|
||||||
vec3 imageLoad(ivec2 point)
|
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)
|
AF3 CasLoad(ASU2 p)
|
||||||
@@ -39,4 +45,9 @@ void main()
|
|||||||
CasFilter(
|
CasFilter(
|
||||||
fragColor.r, fragColor.g, fragColor.b,
|
fragColor.r, fragColor.g, fragColor.b,
|
||||||
point, uConsts[0], uConsts[1], true);
|
point, uConsts[0], uConsts[1], true);
|
||||||
|
|
||||||
|
if (uHDRScale > 0.0)
|
||||||
|
fragColor.rgb = bt2020to709(fragColor.rgb) / uHDRScale;
|
||||||
|
|
||||||
|
fragColor.a = 1.0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user