diff --git a/client/renderers/EGL/desktop.c b/client/renderers/EGL/desktop.c index 0d79e6ab..1b33c797 100644 --- a/client/renderers/EGL/desktop.c +++ b/client/renderers/EGL/desktop.c @@ -51,6 +51,8 @@ struct DesktopShader GLint uNVGain; GLint uCBMode; GLint uIsHDR; + GLint uMapHDRtoSDR; + GLint uMapHDRGain; }; struct EGL_Desktop @@ -85,6 +87,11 @@ struct EGL_Desktop bool useDMA; LG_RendererFormat format; + // map HDR content to SDR + bool mapHDRtoSDR; + int peakLuminance; + int maxCLL; + EGL_PostProcess * pp; _Atomic(bool) processFrame; }; @@ -110,12 +117,14 @@ static bool egl_initDesktopShader( return false; } - shader->uTransform = egl_shaderGetUniform(shader->shader, "transform" ); - shader->uDesktopSize = egl_shaderGetUniform(shader->shader, "desktopSize"); - shader->uScaleAlgo = egl_shaderGetUniform(shader->shader, "scaleAlgo" ); - shader->uNVGain = egl_shaderGetUniform(shader->shader, "nvGain" ); - shader->uCBMode = egl_shaderGetUniform(shader->shader, "cbMode" ); - shader->uIsHDR = egl_shaderGetUniform(shader->shader, "isHDR" ); + shader->uTransform = egl_shaderGetUniform(shader->shader, "transform" ); + shader->uDesktopSize = egl_shaderGetUniform(shader->shader, "desktopSize" ); + shader->uScaleAlgo = egl_shaderGetUniform(shader->shader, "scaleAlgo" ); + shader->uNVGain = egl_shaderGetUniform(shader->shader, "nvGain" ); + shader->uCBMode = egl_shaderGetUniform(shader->shader, "cbMode" ); + shader->uIsHDR = egl_shaderGetUniform(shader->shader, "isHDR" ); + shader->uMapHDRtoSDR = egl_shaderGetUniform(shader->shader, "mapHDRtoSDR" ); + shader->uMapHDRGain = egl_shaderGetUniform(shader->shader, "mapHDRGain" ); return true; } @@ -184,6 +193,10 @@ bool egl_desktopInit(EGL * egl, EGL_Desktop ** desktop_, EGLDisplay * display, desktop->scaleAlgo = option_get_int("egl", "scale" ); desktop->useDMA = useDMA; + desktop->mapHDRtoSDR = option_get_bool("egl", "mapHDRtoSDR" ); + desktop->peakLuminance = option_get_int ("egl", "peakLuminance"); + desktop->maxCLL = option_get_int ("egl", "maxCLL" ); + if (!egl_postProcessInit(&desktop->pp)) { DEBUG_ERROR("Failed to initialize the post process manager"); @@ -274,6 +287,14 @@ void egl_desktopConfigUI(EGL_Desktop * desktop) } igSliderInt("##nvgain", &desktop->nvGain, 0, desktop->nvMax, format, 0); igPopItemWidth(); + + igSeparator(); + igCheckbox("Map HDR content to SDR", &desktop->mapHDRtoSDR); + igSliderInt("Peak Luminance", &desktop->peakLuminance, 1, 10000, + "%d nits", + ImGuiInputTextFlags_CharsDecimal); + igSliderInt("Max content light level (nits)", &desktop->maxCLL, 1, 10000, + "%d nits", ImGuiInputTextFlags_CharsDecimal); } bool egl_desktopSetup(EGL_Desktop * desktop, const LG_RendererFormat format) @@ -458,6 +479,9 @@ bool egl_desktopRender(EGL_Desktop * desktop, unsigned int outputWidth, desktop->useDMA && texture == desktop->texture ? &desktop->dmaShader : &desktop->shader; + const float mapHDRGain = + desktop->maxCLL / desktop->peakLuminance; + EGL_Uniform uniforms[] = { { @@ -490,6 +514,16 @@ bool egl_desktopRender(EGL_Desktop * desktop, unsigned int outputWidth, .type = EGL_UNIFORM_TYPE_1I, .location = shader->uIsHDR, .i = { desktop->hdr } + }, + { + .type = EGL_UNIFORM_TYPE_1I, + .location = shader->uMapHDRtoSDR, + .i = { desktop->mapHDRtoSDR } + }, + { + .type = EGL_UNIFORM_TYPE_1F, + .location = shader->uMapHDRGain, + .f = { mapHDRGain } } }; diff --git a/client/renderers/EGL/egl.c b/client/renderers/EGL/egl.c index 0e025dce..74a67723 100644 --- a/client/renderers/EGL/egl.c +++ b/client/renderers/EGL/egl.c @@ -202,6 +202,27 @@ static struct Option egl_options[] = .type = OPTION_TYPE_BOOL, .value.x_bool = true }, + { + .module = "egl", + .name = "mapHDRtoSDR", + .description = "Map HDR content to the SDR color space", + .type = OPTION_TYPE_BOOL, + .value.x_bool = true + }, + { + .module = "egl", + .name = "peakLuminance", + .description = "The peak luminance level in nits for HDR to SDR mapping", + .type = OPTION_TYPE_INT, + .value.x_int = 250, + }, + { + .module = "egl", + .name = "maxCLL", + .description = "Maximum content light level in nits for HDR to SDR mapping", + .type = OPTION_TYPE_INT, + .value.x_int = 10000, + }, {0} }; diff --git a/client/renderers/EGL/shader/desktop_rgb.frag b/client/renderers/EGL/shader/desktop_rgb.frag index f0b0755b..dcb566b8 100644 --- a/client/renderers/EGL/shader/desktop_rgb.frag +++ b/client/renderers/EGL/shader/desktop_rgb.frag @@ -21,6 +21,8 @@ uniform int scaleAlgo; uniform float nvGain; uniform int cbMode; uniform bool isHDR; +uniform bool mapHDRtoSDR; +uniform float mapHDRGain; void main() { @@ -40,8 +42,8 @@ void main() } } - if (isHDR) - color.rgb = mapToSDR(color.rgb); + if (isHDR && mapHDRtoSDR) + color.rgb = mapToSDR(color.rgb, mapHDRGain); if (cbMode > 0) color = cbTransform(color, cbMode); diff --git a/client/renderers/EGL/shader/hdr.h b/client/renderers/EGL/shader/hdr.h index 11ea9860..d6ac986d 100644 --- a/client/renderers/EGL/shader/hdr.h +++ b/client/renderers/EGL/shader/hdr.h @@ -13,14 +13,11 @@ */ // Configuration --------------------------------------------------------------- -const float peakLuminance = 250.0; // Peak playback screen luminance in nits const float knee = 0.75; // Compressor knee position const float ratio = 4.0; // Compressor ratio: 1 = disabled, <1 = expander -const float maxCLL = 10000.0; // Maximum content light level in nits // ----------------------------------------------------------------------------- // Precalculated values -const float gain = maxCLL / peakLuminance; const float compressor = 1.0 / ratio; // PQ constants @@ -43,10 +40,11 @@ float midGain(vec3 pixel) min(pixel.r, pixel.g)); // min = b } -vec3 compress(vec3 pixel) +vec3 compress(vec3 pixel, float gain) { - float gain = maxGain(pixel); - return pixel * (gain < knee ? gain : knee + max(gain - knee, 0.0) * compressor) / gain; + float maxGain = maxGain(pixel); + return pixel * (maxGain < knee ? maxGain : + knee + max(maxGain - knee, 0.0) * compressor) / maxGain; } vec3 fixClip(vec3 pixel) @@ -67,7 +65,7 @@ vec3 fixClip(vec3 pixel) } // Returns luminance in nits -vec3 pq2lin(vec3 pq) +vec3 pq2lin(vec3 pq, float gain) { vec3 p = pow(pq, vec3(m2inv)); vec3 d = max(p - c1, vec3(0.0)) / (c2 - c3 * p); @@ -101,8 +99,8 @@ vec3 bt2020to709(vec3 bt2020) bt2020.r * -0.0182 + bt2020.g * -0.1006 + bt2020.b * 1.1187); } -vec3 mapToSDR(vec3 color) +vec3 mapToSDR(vec3 color, float gain) { - vec3 lin = bt2020to709(pq2lin(color.rgb)); - return lin2srgb(compress(lin)); + vec3 lin = bt2020to709(pq2lin(color.rgb, gain)); + return lin2srgb(compress(lin, gain)); }