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.
wilder/Plasma/6.3
Xaver Hugl 1 year ago
parent 21b1132695
commit e49bbec8a8
  1. 4
      src/backends/drm/drm_egl_layer.cpp
  2. 28
      src/backends/drm/drm_output.cpp
  3. 2
      src/backends/drm/drm_output.h

@ -57,7 +57,7 @@ std::optional<OutputLayerBeginFrameInfo> EglGbmLayer::doBeginFrame()
m_scanoutBuffer.reset(); m_scanoutBuffer.reset();
m_colorPipeline = ColorPipeline{}; 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(), 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) 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); ColorPipeline pipeline = ColorPipeline::create(color, m_pipeline->output()->scanoutColorDescription(), intent);
if (m_pipeline->output()->needsChannelFactorFallback()) { if (m_pipeline->output()->needsChannelFactorFallback()) {
pipeline.addTransferFunction(m_pipeline->output()->scanoutColorDescription().transferFunction()); 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()); pipeline.addInverseTransferFunction(m_pipeline->output()->scanoutColorDescription().transferFunction());
} }
m_colorPipeline = pipeline; m_colorPipeline = pipeline;

@ -405,7 +405,10 @@ ColorDescription DrmOutput::createColorDescription(const std::shared_ptr<OutputC
// HDR screens are weird, sending them the min. luminance from the EDID does *not* make all of them present the darkest luminance the display can show // HDR screens are weird, sending them the min. luminance from the EDID does *not* make all of them present the darkest luminance the display can show
// to work around that, (unless overridden by the user), assume the min. luminance of the transfer function instead // to work around that, (unless overridden by the user), assume the min. luminance of the transfer function instead
const double minBrightness = effectiveHdr ? props->minBrightnessOverride.value_or(m_state.minBrightnessOverride).value_or(TransferFunction::defaultMinLuminanceFor(TransferFunction::PerceptualQuantizer)) : transferFunction.minLuminance; const double minBrightness = effectiveHdr ? props->minBrightnessOverride.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<OutputChangeSet> &props) void DrmOutput::applyQueuedChanges(const std::shared_ptr<OutputChangeSet> &props)
@ -472,9 +475,12 @@ void DrmOutput::setBrightnessDevice(BrightnessDevice *device)
} else { } else {
device->setBrightness(m_state.brightness); device->setBrightness(m_state.brightness);
} }
// reset the brightness factors
tryKmsColorOffloading();
} }
// reset the brightness factors
State next = m_state;
next.colorDescription = createColorDescription(std::make_shared<OutputChangeSet>());
setState(next);
tryKmsColorOffloading();
} }
void DrmOutput::revertQueuedChanges() void DrmOutput::revertQueuedChanges()
@ -516,7 +522,7 @@ void DrmOutput::tryKmsColorOffloading()
} }
// TODO this doesn't allow using only a CTM for night light offloading // 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? // 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 double maxLuminance = colorDescription().maxHdrLuminance().value_or(colorDescription().referenceLuminance());
const ColorDescription optimal = colorDescription().transferFunction().type == TransferFunction::gamma22 ? colorDescription() : colorDescription().withTransferFunction(TransferFunction(TransferFunction::gamma22, 0, maxLuminance)); const ColorDescription optimal = colorDescription().transferFunction().type == TransferFunction::gamma22 ? colorDescription() : colorDescription().withTransferFunction(TransferFunction(TransferFunction::gamma22, 0, maxLuminance));
ColorPipeline colorPipeline = ColorPipeline::create(optimal, colorDescription(), RenderingIntent::RelativeColorimetric); ColorPipeline colorPipeline = ColorPipeline::create(optimal, colorDescription(), RenderingIntent::RelativeColorimetric);
@ -543,19 +549,11 @@ bool DrmOutput::needsChannelFactorFallback() const
return m_channelFactorsNeedShaderFallback; 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 // normalize red to be the original brightness value again
adaptedChannelFactors *= m_channelFactors.x() / adaptedChannelFactors.x(); return ret * m_channelFactors.x() / ret.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;
}
} }
const ColorDescription &DrmOutput::scanoutColorDescription() const const ColorDescription &DrmOutput::scanoutColorDescription() const

@ -61,7 +61,7 @@ public:
/** /**
* channel factors adapted to the target color space + brightness setting multiplied in * channel factors adapted to the target color space + brightness setting multiplied in
*/ */
QVector3D effectiveChannelFactors() const; QVector3D adaptedChannelFactors() const;
void updateConnectorProperties(); void updateConnectorProperties();
/** /**

Loading…
Cancel
Save