[client] egl: add support to map HDR to SDR

This commit is contained in:
Geoffrey McRae 2023-04-26 16:26:33 +10:00
parent 99333a03c1
commit ad43969c1a
5 changed files with 127 additions and 2 deletions

View File

@ -72,6 +72,7 @@ LG_RendererRotate;
typedef struct LG_RendererFormat
{
FrameType type; // frame type
bool hdr; // if the frame is HDR or not
unsigned int screenWidth; // actual width of the host
unsigned int screenHeight; // actual height of the host
unsigned int frameWidth; // width of frame transmitted

View File

@ -50,6 +50,7 @@ struct DesktopShader
GLint uScaleAlgo;
GLint uNVGain;
GLint uCBMode;
GLint uIsHDR;
};
struct EGL_Desktop
@ -64,6 +65,7 @@ struct EGL_Desktop
// internals
int width, height;
bool hdr;
LG_RendererRotate rotate;
bool useSpice;
@ -113,6 +115,7 @@ static bool egl_initDesktopShader(
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" );
return true;
}
@ -303,6 +306,7 @@ bool egl_desktopSetup(EGL_Desktop * desktop, const LG_RendererFormat format)
desktop->width = format.frameWidth;
desktop->height = format.frameHeight;
desktop->hdr = format.hdr;
if (!egl_textureSetup(
desktop->texture,
@ -481,6 +485,11 @@ bool egl_desktopRender(EGL_Desktop * desktop, unsigned int outputWidth,
.type = EGL_UNIFORM_TYPE_1I,
.location = shader->uCBMode,
.f = { desktop->cbMode }
},
{
.type = EGL_UNIFORM_TYPE_1I,
.location = shader->uIsHDR,
.i = { desktop->hdr }
}
};

View File

@ -9,6 +9,7 @@ precision highp float;
#define EGL_SCALE_MAX 3
#include "color_blind.h"
#include "hdr.h"
in vec2 uv;
out vec4 color;
@ -19,6 +20,7 @@ uniform int scaleAlgo;
uniform float nvGain;
uniform int cbMode;
uniform bool isHDR;
void main()
{
@ -38,6 +40,9 @@ void main()
}
}
if (isHDR)
color.rgb = mapToSDR(color.rgb);
if (cbMode > 0)
color = cbTransform(color, cbMode);

View File

@ -0,0 +1,108 @@
/*
_______ _____ __ __ ____ __
/ ____(_)___ ___ ____ ___ ____ _ / ___// /_ ____ _____/ /__ _____ / __ \____ ______/ /__
/ / / / __ \/ _ \/ __ `__ \/ __ `/ \__ \/ __ \/ __ `/ __ / _ \/ ___/ / /_/ / __ `/ ___/ //_/
/ /___/ / / / / __/ / / / / / /_/ / ___/ / / / / /_/ / /_/ / __/ / / ____/ /_/ / /__/ ,<
\____/_/_/ /_/\___/_/ /_/ /_/\__,_/ /____/_/ /_/\__,_/\__,_/\___/_/ /_/ \__,_/\___/_/|_|
http://en.sbence.hu/ Shader: Try to get the SDR part of HDR content
*/
/**
* Translated to GLSL, original source is:
* https://github.com/VoidXH/Cinema-Shader-Pack
*/
// 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
const float m1inv = 16384.0 / 2610.0;
const float m2inv = 32.0 / 2523.0;
const float c1 = 3424.0 / 4096.0;
const float c2 = 2413.0 / 128.0;
const float c3 = 2392.0 / 128.0;
float minGain(vec3 pixel) { return min(pixel.r, min(pixel.g, pixel.b)); }
float maxGain(vec3 pixel) { return max(pixel.r, max(pixel.g, pixel.b)); }
float midGain(vec3 pixel)
{
return pixel.r < pixel.g ?
(pixel.r < pixel.b ?
min(pixel.g, pixel.b) : // min = r
min(pixel.r, pixel.g)) : // min = b
(pixel.g < pixel.b ?
min(pixel.r, pixel.b) : // min = g
min(pixel.r, pixel.g)); // min = b
}
vec3 compress(vec3 pixel)
{
float gain = maxGain(pixel);
return pixel * (gain < knee ? gain : knee + max(gain - knee, 0.0) * compressor) / gain;
}
vec3 fixClip(vec3 pixel)
{
// keep the (mid - min) / (max - min) ratio
float preMin = minGain(pixel);
float preMid = midGain(pixel);
float preMax = maxGain(pixel);
vec3 clip = clamp(pixel, 0.0, 1.0);
float postMin = minGain(clip);
float postMid = midGain(clip);
float postMax = maxGain(clip);
float ratio = (preMid - preMin) / (preMax - preMin);
float newMid = ratio * (postMax - postMin) + postMin;
return vec3(clip.r != postMid ? clip.r : newMid,
clip.g != postMid ? clip.g : newMid,
clip.b != postMid ? clip.b : newMid);
}
// Returns luminance in nits
vec3 pq2lin(vec3 pq)
{
vec3 p = pow(pq, vec3(m2inv));
vec3 d = max(p - c1, vec3(0.0)) / (c2 - c3 * p);
return pow(d, vec3(m1inv)) * gain;
}
vec3 srgb2lin(vec3 c)
{
vec3 v = c / 12.92;
vec3 v2 = pow((c + vec3(0.055)) / 1.055, vec3(2.4));
vec3 threshold = vec3(0.04045);
vec3 result = mix(v, v2, greaterThanEqual(c, threshold));
return result;
}
vec3 lin2srgb(vec3 c)
{
vec3 v = c * 12.92;
vec3 v2 = pow(c, vec3(1.0/2.4)) * 1.055 - 0.055;
vec3 threshold = vec3(0.0031308);
vec3 result = mix(v, v2, greaterThanEqual(c, threshold));
return result;
}
// in linear space
vec3 bt2020to709(vec3 bt2020)
{
return vec3(
bt2020.r * 1.6605 + bt2020.g * -0.5876 + bt2020.b * -0.0728,
bt2020.r * -0.1246 + bt2020.g * 1.1329 + bt2020.b * -0.0083,
bt2020.r * -0.0182 + bt2020.g * -0.1006 + bt2020.b * 1.1187);
}
vec3 mapToSDR(vec3 color)
{
vec3 lin = bt2020to709(pq2lin(color.rgb));
return lin2srgb(compress(lin));
}

View File

@ -631,6 +631,7 @@ int main_frameThread(void * unused)
lgrFormat.frameHeight = frame->frameHeight;
lgrFormat.stride = frame->stride;
lgrFormat.pitch = frame->pitch;
lgrFormat.hdr = frame->flags & FRAME_FLAG_HDR;
if (frame->flags & FRAME_FLAG_TRUNCATED)
{
@ -695,11 +696,12 @@ int main_frameThread(void * unused)
g_state.formatValid = true;
formatVer = frame->formatVer;
DEBUG_INFO("Format: %s %ux%u stride:%u pitch:%u rotation:%d",
DEBUG_INFO("Format: %s %ux%u stride:%u pitch:%u rotation:%d hdr:%d",
FrameTypeStr[frame->type],
frame->frameWidth, frame->frameHeight,
frame->stride, frame->pitch,
frame->rotation);
frame->rotation,
frame->flags & FRAME_FLAG_HDR ? 1 : 0);
LG_LOCK(g_state.lgrLock);
if (!RENDERER(onFrameFormat, lgrFormat))