[client] wayland: implement HDR support

This commit is contained in:
Geoffrey McRae
2026-07-15 19:48:31 +10:00
committed by Geoffrey McRae
parent 28973ac4b1
commit 364485ded8
16 changed files with 623 additions and 30 deletions

View File

@@ -91,6 +91,7 @@ struct EGL_Desktop
// map HDR content to SDR
bool mapHDRtoSDR;
bool nativeHDR;
int peakLuminance;
int maxCLL;
@@ -548,7 +549,7 @@ bool egl_desktopRender(EGL_Desktop * desktop, unsigned int outputWidth,
{
.type = EGL_UNIFORM_TYPE_1I,
.location = shader->uCBMode,
.f = { desktop->cbMode }
.i = { desktop->cbMode }
},
{
.type = EGL_UNIFORM_TYPE_1I,
@@ -558,7 +559,7 @@ bool egl_desktopRender(EGL_Desktop * desktop, unsigned int outputWidth,
{
.type = EGL_UNIFORM_TYPE_1I,
.location = shader->uMapHDRtoSDR,
.i = { desktop->mapHDRtoSDR }
.i = { desktop->mapHDRtoSDR && !desktop->nativeHDR }
},
{
.type = EGL_UNIFORM_TYPE_1F,
@@ -568,7 +569,7 @@ bool egl_desktopRender(EGL_Desktop * desktop, unsigned int outputWidth,
{
.type = EGL_UNIFORM_TYPE_1I,
.location = shader->uMapHDRPQ,
.f = { desktop->hdrPQ }
.i = { desktop->hdrPQ }
}
};
@@ -579,6 +580,11 @@ bool egl_desktopRender(EGL_Desktop * desktop, unsigned int outputWidth,
return true;
}
void egl_desktopSetNativeHDR(EGL_Desktop * desktop, bool nativeHDR)
{
desktop->nativeHDR = nativeHDR;
}
void egl_desktopSpiceConfigure(EGL_Desktop * desktop, int width, int height)
{
if (!desktop->spiceTexture)

View File

@@ -42,6 +42,7 @@ bool egl_desktopInit(EGL * egl, EGL_Desktop ** desktop, EGLDisplay * display,
void egl_desktopFree(EGL_Desktop ** desktop);
void egl_desktopConfigUI(EGL_Desktop * desktop);
void egl_desktopSetNativeHDR(EGL_Desktop * desktop, bool nativeHDR);
bool egl_desktopSetup (EGL_Desktop * desktop, const LG_RendererFormat format);
bool egl_desktopUpdate(EGL_Desktop * desktop, const FrameBuffer * frame, int dmaFd,
const FrameDamageRect * damageRects, int damageRectsCount);

View File

@@ -121,6 +121,9 @@ struct Inst
bool showSpice;
int spiceWidth, spiceHeight;
bool configSupportsHDR; // true if we probed FP16 or 10-bit EGL config
bool hdr; // true if current frame format is HDR
};
static struct Option egl_options[] =
@@ -607,6 +610,26 @@ static bool egl_onFrameFormat(LG_Renderer * renderer, const LG_RendererFormat fo
egl_cursorSetScale(this->cursor, scale);
}
// Track HDR state and warn if HDR frames arrive without any HDR path
this->hdr = format.hdr;
if (format.hdr)
{
bool nativeHDR = false;
app_getProp(LG_DS_NATIVE_HDR, &nativeHDR);
if (!this->configSupportsHDR && !nativeHDR)
DEBUG_WARN("HDR frames being displayed on an 8-bit EGL surface "
"without a color-managed compositor; tones may be incorrect");
}
// If the display server supports native HDR (via setHDRImageDescription),
// disable software tone-mapping to avoid double tone-mapping.
// However, if the last call to setHDRImageDescription actually failed
// (e.g., compositor missing required primaries), keep tone-mapping on.
bool nativeHDR = false;
app_getProp(LG_DS_NATIVE_HDR, &nativeHDR);
egl_desktopSetNativeHDR(this->desktop,
format.hdr && nativeHDR && !app_getHDRDescFailed());
egl_update_scale_type(this);
egl_damageSetup(this->damage, format.frameWidth, format.frameHeight);
@@ -774,22 +797,51 @@ static bool egl_renderStartup(LG_Renderer * renderer, bool useDMA)
}
}
EGLint attr[] =
// Probe for best available color depth: FP16 → 10-bit → 8-bit
static const struct { EGLint r, g, b, a, depth; const char * desc; } configs[] =
{
EGL_BUFFER_SIZE , 30,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_SAMPLE_BUFFERS , maxSamples > 0 ? 1 : 0,
EGL_SAMPLES , maxSamples,
EGL_NONE
{ 16, 16, 16, 0, 48, "FP16 (RGBA16F)" },
{ 10, 10, 10, 2, 32, "10-bit (RGBA10)" },
{ 8, 8, 8, 0, 24, "8-bit (RGBA8)" },
};
EGLint num_config;
const char * configDesc = NULL;
int chosen = -1;
EGLint num_config;
if (!eglChooseConfig(this->display, attr, &this->configs, 1, &num_config))
for (int i = 0; i < (int)(sizeof(configs) / sizeof(configs[0])); ++i)
{
DEBUG_ERROR("Failed to choose config (eglError: 0x%x)", eglGetError());
EGLint attr[] =
{
EGL_RED_SIZE , configs[i].r,
EGL_GREEN_SIZE , configs[i].g,
EGL_BLUE_SIZE , configs[i].b,
EGL_ALPHA_SIZE , configs[i].a,
EGL_BUFFER_SIZE , configs[i].depth,
EGL_RENDERABLE_TYPE , EGL_OPENGL_ES2_BIT,
EGL_SAMPLE_BUFFERS , maxSamples > 0 ? 1 : 0,
EGL_SAMPLES , maxSamples,
EGL_NONE
};
if (eglChooseConfig(this->display, attr, &this->configs, 1, &num_config) &&
num_config > 0)
{
configDesc = configs[i].desc;
chosen = i;
break;
}
}
if (chosen < 0)
{
DEBUG_ERROR("Failed to choose any EGL config");
return false;
}
this->configSupportsHDR = chosen <= 1; // FP16 or 10-bit
DEBUG_INFO("EGL config: %s%s", configDesc,
this->configSupportsHDR ? " (HDR capable)" : "");
const EGLint surfattr[] =
{
EGL_RENDER_BUFFER, this->opt.doubleBuffer ? EGL_BACK_BUFFER : EGL_SINGLE_BUFFER,