From e49bbec8a85f64d40f88d38008d1dfde806ce412 Mon Sep 17 00:00:00 2001 From: Xaver Hugl Date: Thu, 26 Sep 2024 15:51:48 +0200 Subject: [PATCH] backends/drm: adjust software brightness by changing the reference luminance This simplifies the pipeline slightly, and allows for the HDR headroom between the new reference luminance and the max. luminance of the screen to be used. --- src/backends/drm/drm_egl_layer.cpp | 4 ++-- src/backends/drm/drm_output.cpp | 28 +++++++++++++--------------- src/backends/drm/drm_output.h | 2 +- 3 files changed, 16 insertions(+), 18 deletions(-) diff --git a/src/backends/drm/drm_egl_layer.cpp b/src/backends/drm/drm_egl_layer.cpp index 7b7c19c215..d673b1c6db 100644 --- a/src/backends/drm/drm_egl_layer.cpp +++ b/src/backends/drm/drm_egl_layer.cpp @@ -57,7 +57,7 @@ std::optional EglGbmLayer::doBeginFrame() m_scanoutBuffer.reset(); m_colorPipeline = ColorPipeline{}; return m_surface.startRendering(targetRect().size(), m_pipeline->output()->transform().combine(OutputTransform::FlipY), m_pipeline->formats(m_type), m_pipeline->output()->scanoutColorDescription(), - m_pipeline->output()->needsChannelFactorFallback() ? m_pipeline->output()->effectiveChannelFactors() : QVector3D(1, 1, 1), m_pipeline->iccProfile(), m_pipeline->output()->scale()); + m_pipeline->output()->needsChannelFactorFallback() ? m_pipeline->output()->adaptedChannelFactors() : QVector3D(1, 1, 1), m_pipeline->iccProfile(), m_pipeline->output()->scale()); } bool EglGbmLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion, OutputFrame *frame) @@ -105,7 +105,7 @@ bool EglGbmLayer::doImportScanoutBuffer(GraphicsBuffer *buffer, const ColorDescr ColorPipeline pipeline = ColorPipeline::create(color, m_pipeline->output()->scanoutColorDescription(), intent); if (m_pipeline->output()->needsChannelFactorFallback()) { pipeline.addTransferFunction(m_pipeline->output()->scanoutColorDescription().transferFunction()); - pipeline.addMultiplier(m_pipeline->output()->effectiveChannelFactors()); + pipeline.addMultiplier(m_pipeline->output()->adaptedChannelFactors()); pipeline.addInverseTransferFunction(m_pipeline->output()->scanoutColorDescription().transferFunction()); } m_colorPipeline = pipeline; diff --git a/src/backends/drm/drm_output.cpp b/src/backends/drm/drm_output.cpp index b102ad0d7c..470c425314 100644 --- a/src/backends/drm/drm_output.cpp +++ b/src/backends/drm/drm_output.cpp @@ -405,7 +405,10 @@ ColorDescription DrmOutput::createColorDescription(const std::shared_ptrminBrightnessOverride.value_or(m_state.minBrightnessOverride).value_or(TransferFunction::defaultMinLuminanceFor(TransferFunction::PerceptualQuantizer)) : transferFunction.minLuminance; - return ColorDescription(containerColorimetry, transferFunction, referenceLuminance, minBrightness, maxAverageBrightness, maxPeakBrightness, masteringColorimetry, sdrColorimetry); + + const double brightnessFactor = !m_brightnessDevice || effectiveHdr ? props->brightness.value_or(m_state.brightness) : 1.0; + const double effectiveReferenceLuminance = 25 + (referenceLuminance - 25) * brightnessFactor; + return ColorDescription(containerColorimetry, transferFunction, effectiveReferenceLuminance, minBrightness, maxAverageBrightness, maxPeakBrightness, masteringColorimetry, sdrColorimetry); } void DrmOutput::applyQueuedChanges(const std::shared_ptr &props) @@ -472,9 +475,12 @@ void DrmOutput::setBrightnessDevice(BrightnessDevice *device) } else { device->setBrightness(m_state.brightness); } - // reset the brightness factors - tryKmsColorOffloading(); } + // reset the brightness factors + State next = m_state; + next.colorDescription = createColorDescription(std::make_shared()); + setState(next); + tryKmsColorOffloading(); } void DrmOutput::revertQueuedChanges() @@ -516,7 +522,7 @@ void DrmOutput::tryKmsColorOffloading() } // TODO this doesn't allow using only a CTM for night light offloading // maybe relax correctness in that case and apply night light in non-linear space? - const QVector3D channelFactors = effectiveChannelFactors(); + const QVector3D channelFactors = adaptedChannelFactors(); const double maxLuminance = colorDescription().maxHdrLuminance().value_or(colorDescription().referenceLuminance()); const ColorDescription optimal = colorDescription().transferFunction().type == TransferFunction::gamma22 ? colorDescription() : colorDescription().withTransferFunction(TransferFunction(TransferFunction::gamma22, 0, maxLuminance)); ColorPipeline colorPipeline = ColorPipeline::create(optimal, colorDescription(), RenderingIntent::RelativeColorimetric); @@ -543,19 +549,11 @@ bool DrmOutput::needsChannelFactorFallback() const return m_channelFactorsNeedShaderFallback; } -QVector3D DrmOutput::effectiveChannelFactors() const +QVector3D DrmOutput::adaptedChannelFactors() const { - QVector3D adaptedChannelFactors = ColorDescription::sRGB.toOther(colorDescription(), RenderingIntent::RelativeColorimetric) * m_channelFactors; + const QVector3D ret = ColorDescription::sRGB.toOther(colorDescription(), RenderingIntent::RelativeColorimetric) * m_channelFactors; // normalize red to be the original brightness value again - adaptedChannelFactors *= m_channelFactors.x() / adaptedChannelFactors.x(); - if (m_state.highDynamicRange || !m_brightnessDevice) { - // enforce a minimum of 25 nits for the reference luminance - constexpr double minLuminance = 25; - const double brightnessFactor = (m_state.brightness * (1 - (minLuminance / m_state.referenceLuminance))) + (minLuminance / m_state.referenceLuminance); - return adaptedChannelFactors * brightnessFactor; - } else { - return adaptedChannelFactors; - } + return ret * m_channelFactors.x() / ret.x(); } const ColorDescription &DrmOutput::scanoutColorDescription() const diff --git a/src/backends/drm/drm_output.h b/src/backends/drm/drm_output.h index 8c010d4606..af7e6bbb71 100644 --- a/src/backends/drm/drm_output.h +++ b/src/backends/drm/drm_output.h @@ -61,7 +61,7 @@ public: /** * channel factors adapted to the target color space + brightness setting multiplied in */ - QVector3D effectiveChannelFactors() const; + QVector3D adaptedChannelFactors() const; void updateConnectorProperties(); /**