mirror of
https://github.com/gnif/LookingGlass.git
synced 2024-11-22 13:37:22 +00:00
[client] egl: make it possible to configure HDR to SDR mapping
This commit is contained in:
parent
844a37a276
commit
78df2073ff
@ -51,6 +51,8 @@ struct DesktopShader
|
|||||||
GLint uNVGain;
|
GLint uNVGain;
|
||||||
GLint uCBMode;
|
GLint uCBMode;
|
||||||
GLint uIsHDR;
|
GLint uIsHDR;
|
||||||
|
GLint uMapHDRtoSDR;
|
||||||
|
GLint uMapHDRGain;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct EGL_Desktop
|
struct EGL_Desktop
|
||||||
@ -85,6 +87,11 @@ struct EGL_Desktop
|
|||||||
bool useDMA;
|
bool useDMA;
|
||||||
LG_RendererFormat format;
|
LG_RendererFormat format;
|
||||||
|
|
||||||
|
// map HDR content to SDR
|
||||||
|
bool mapHDRtoSDR;
|
||||||
|
int peakLuminance;
|
||||||
|
int maxCLL;
|
||||||
|
|
||||||
EGL_PostProcess * pp;
|
EGL_PostProcess * pp;
|
||||||
_Atomic(bool) processFrame;
|
_Atomic(bool) processFrame;
|
||||||
};
|
};
|
||||||
@ -110,12 +117,14 @@ 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, "desktopSize");
|
shader->uDesktopSize = egl_shaderGetUniform(shader->shader, "desktopSize" );
|
||||||
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" );
|
||||||
shader->uIsHDR = egl_shaderGetUniform(shader->shader, "isHDR" );
|
shader->uIsHDR = egl_shaderGetUniform(shader->shader, "isHDR" );
|
||||||
|
shader->uMapHDRtoSDR = egl_shaderGetUniform(shader->shader, "mapHDRtoSDR" );
|
||||||
|
shader->uMapHDRGain = egl_shaderGetUniform(shader->shader, "mapHDRGain" );
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -184,6 +193,10 @@ 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;
|
||||||
|
|
||||||
|
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))
|
if (!egl_postProcessInit(&desktop->pp))
|
||||||
{
|
{
|
||||||
DEBUG_ERROR("Failed to initialize the post process manager");
|
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);
|
igSliderInt("##nvgain", &desktop->nvGain, 0, desktop->nvMax, format, 0);
|
||||||
igPopItemWidth();
|
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)
|
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->useDMA && texture == desktop->texture ?
|
||||||
&desktop->dmaShader : &desktop->shader;
|
&desktop->dmaShader : &desktop->shader;
|
||||||
|
|
||||||
|
const float mapHDRGain =
|
||||||
|
desktop->maxCLL / desktop->peakLuminance;
|
||||||
|
|
||||||
EGL_Uniform uniforms[] =
|
EGL_Uniform uniforms[] =
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
@ -490,6 +514,16 @@ bool egl_desktopRender(EGL_Desktop * desktop, unsigned int outputWidth,
|
|||||||
.type = EGL_UNIFORM_TYPE_1I,
|
.type = EGL_UNIFORM_TYPE_1I,
|
||||||
.location = shader->uIsHDR,
|
.location = shader->uIsHDR,
|
||||||
.i = { desktop->hdr }
|
.i = { desktop->hdr }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.type = EGL_UNIFORM_TYPE_1I,
|
||||||
|
.location = shader->uMapHDRtoSDR,
|
||||||
|
.i = { desktop->mapHDRtoSDR }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.type = EGL_UNIFORM_TYPE_1F,
|
||||||
|
.location = shader->uMapHDRGain,
|
||||||
|
.f = { mapHDRGain }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -202,6 +202,27 @@ static struct Option egl_options[] =
|
|||||||
.type = OPTION_TYPE_BOOL,
|
.type = OPTION_TYPE_BOOL,
|
||||||
.value.x_bool = true
|
.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}
|
{0}
|
||||||
};
|
};
|
||||||
|
@ -21,6 +21,8 @@ uniform int scaleAlgo;
|
|||||||
uniform float nvGain;
|
uniform float nvGain;
|
||||||
uniform int cbMode;
|
uniform int cbMode;
|
||||||
uniform bool isHDR;
|
uniform bool isHDR;
|
||||||
|
uniform bool mapHDRtoSDR;
|
||||||
|
uniform float mapHDRGain;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
@ -40,8 +42,8 @@ void main()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isHDR)
|
if (isHDR && mapHDRtoSDR)
|
||||||
color.rgb = mapToSDR(color.rgb);
|
color.rgb = mapToSDR(color.rgb, mapHDRGain);
|
||||||
|
|
||||||
if (cbMode > 0)
|
if (cbMode > 0)
|
||||||
color = cbTransform(color, cbMode);
|
color = cbTransform(color, cbMode);
|
||||||
|
@ -13,14 +13,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Configuration ---------------------------------------------------------------
|
// Configuration ---------------------------------------------------------------
|
||||||
const float peakLuminance = 250.0; // Peak playback screen luminance in nits
|
|
||||||
const float knee = 0.75; // Compressor knee position
|
const float knee = 0.75; // Compressor knee position
|
||||||
const float ratio = 4.0; // Compressor ratio: 1 = disabled, <1 = expander
|
const float ratio = 4.0; // Compressor ratio: 1 = disabled, <1 = expander
|
||||||
const float maxCLL = 10000.0; // Maximum content light level in nits
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
// Precalculated values
|
// Precalculated values
|
||||||
const float gain = maxCLL / peakLuminance;
|
|
||||||
const float compressor = 1.0 / ratio;
|
const float compressor = 1.0 / ratio;
|
||||||
|
|
||||||
// PQ constants
|
// PQ constants
|
||||||
@ -43,10 +40,11 @@ float midGain(vec3 pixel)
|
|||||||
min(pixel.r, pixel.g)); // min = b
|
min(pixel.r, pixel.g)); // min = b
|
||||||
}
|
}
|
||||||
|
|
||||||
vec3 compress(vec3 pixel)
|
vec3 compress(vec3 pixel, float gain)
|
||||||
{
|
{
|
||||||
float gain = maxGain(pixel);
|
float maxGain = maxGain(pixel);
|
||||||
return pixel * (gain < knee ? gain : knee + max(gain - knee, 0.0) * compressor) / gain;
|
return pixel * (maxGain < knee ? maxGain :
|
||||||
|
knee + max(maxGain - knee, 0.0) * compressor) / maxGain;
|
||||||
}
|
}
|
||||||
|
|
||||||
vec3 fixClip(vec3 pixel)
|
vec3 fixClip(vec3 pixel)
|
||||||
@ -67,7 +65,7 @@ vec3 fixClip(vec3 pixel)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Returns luminance in nits
|
// Returns luminance in nits
|
||||||
vec3 pq2lin(vec3 pq)
|
vec3 pq2lin(vec3 pq, float gain)
|
||||||
{
|
{
|
||||||
vec3 p = pow(pq, vec3(m2inv));
|
vec3 p = pow(pq, vec3(m2inv));
|
||||||
vec3 d = max(p - c1, vec3(0.0)) / (c2 - c3 * p);
|
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);
|
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));
|
vec3 lin = bt2020to709(pq2lin(color.rgb, gain));
|
||||||
return lin2srgb(compress(lin));
|
return lin2srgb(compress(lin, gain));
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user