backends/drm: use the post-blending color pipeline for direct scanout

This makes direct scanout of SDR content on an HDR screen and vice versa possible,
as well as direct scanout while night color is active or the brightness isn't 100%.
This commit is contained in:
Xaver Hugl 2024-07-03 23:17:42 +02:00
parent 2799c270b4
commit 0704319235
6 changed files with 32 additions and 5 deletions

View file

@ -55,6 +55,7 @@ std::optional<OutputLayerBeginFrameInfo> EglGbmLayer::doBeginFrame()
// as the hardware cursor is more important than an incorrectly blended cursor edge
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->colorDescription(), m_pipeline->output()->effectiveChannelFactors(), m_pipeline->iccProfile(), m_pipeline->output()->needsColormanagement());
}
@ -105,9 +106,7 @@ bool EglGbmLayer::doAttemptScanout(GraphicsBuffer *buffer, const ColorDescriptio
if (m_pipeline->output()->needsColormanagement()) {
pipeline.addInverseTransferFunction(m_pipeline->colorDescription().transferFunction(), m_pipeline->colorDescription().referenceLuminance());
}
if (!pipeline.isIdentity()) {
return false;
}
m_colorPipeline = pipeline;
// kernel documentation says that
// "Devices that dont support subpixel plane coordinates can ignore the fractional part."
// so we need to make sure that doesn't cause a difference vs the composited result
@ -157,4 +156,9 @@ std::optional<QSize> EglGbmLayer::fixedSize() const
{
return m_type == DrmPlane::TypeIndex::Cursor ? std::make_optional(m_pipeline->gpu()->cursorSize()) : std::nullopt;
}
const ColorPipeline &EglGbmLayer::colorPipeline() const
{
return m_colorPipeline;
}
}

View file

@ -37,11 +37,13 @@ public:
DrmDevice *scanoutDevice() const override;
QHash<uint32_t, QList<uint64_t>> supportedDrmFormats() const override;
std::optional<QSize> fixedSize() const override;
const ColorPipeline &colorPipeline() const override;
private:
bool doAttemptScanout(GraphicsBuffer *buffer, const ColorDescription &color, const std::shared_ptr<OutputFrame> &frame) override;
std::shared_ptr<DrmFramebuffer> m_scanoutBuffer;
ColorPipeline m_colorPipeline;
EglGbmLayerSurface m_surface;
};

View file

@ -36,4 +36,9 @@ DrmPipelineLayer::DrmPipelineLayer(DrmPipeline *pipeline, DrmPlane::TypeIndex ty
, m_type(type)
{
}
const ColorPipeline &DrmPipelineLayer::colorPipeline() const
{
return m_colorPipeline;
}
}

View file

@ -7,6 +7,7 @@
SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include "core/colorpipeline.h"
#include "core/outputlayer.h"
#include "drm_plane.h"
@ -39,9 +40,11 @@ public:
virtual bool checkTestBuffer() = 0;
virtual std::shared_ptr<DrmFramebuffer> currentBuffer() const = 0;
virtual const ColorPipeline &colorPipeline() const;
protected:
DrmPipeline *const m_pipeline;
const DrmPlane::TypeIndex m_type;
ColorPipeline m_colorPipeline;
};
}

View file

@ -213,12 +213,20 @@ DrmPipeline::Error DrmPipeline::prepareAtomicPresentation(DrmAtomicCommit *commi
commit->setVrr(m_pending.crtc, m_pending.presentationMode == PresentationMode::AdaptiveSync || m_pending.presentationMode == PresentationMode::AdaptiveAsync);
}
if (m_cursorLayer->isEnabled() && m_primaryLayer->colorPipeline() != m_cursorLayer->colorPipeline()) {
return DrmPipeline::Error::InvalidArguments;
}
if (!m_pending.crtcColorPipeline.isIdentity() && !m_primaryLayer->colorPipeline().isIdentity()) {
// TODO merge the pipelines instead?
return DrmPipeline::Error::InvalidArguments;
}
const auto &colorPipeline = m_pending.crtcColorPipeline.isIdentity() ? m_primaryLayer->colorPipeline() : m_pending.crtcColorPipeline;
if (!m_pending.crtc->postBlendingPipeline) {
if (!m_pending.crtcColorPipeline.isIdentity()) {
if (!colorPipeline.isIdentity()) {
return Error::InvalidArguments;
}
} else {
if (!m_pending.crtc->postBlendingPipeline->matchPipeline(commit, m_pending.crtcColorPipeline)) {
if (!m_pending.crtc->postBlendingPipeline->matchPipeline(commit, colorPipeline)) {
return Error::InvalidArguments;
}
}

View file

@ -102,6 +102,11 @@ DrmPipeline::Error DrmPipeline::applyPendingChangesLegacy()
drmModeSetCursor(gpu()->fd(), m_pending.crtc->id(), 0, 0, 0);
}
if (activePending()) {
if (!m_primaryLayer->colorPipeline().isIdentity() || !m_cursorLayer->colorPipeline().isIdentity()) {
// while it's technically possible to set CRTC color management properties,
// it may result in glitches
return DrmPipeline::Error::InvalidArguments;
}
const bool shouldEnableVrr = m_pending.presentationMode == PresentationMode::AdaptiveSync || m_pending.presentationMode == PresentationMode::AdaptiveAsync;
if (m_pending.crtc->vrrEnabled.isValid() && !m_pending.crtc->vrrEnabled.setPropertyLegacy(shouldEnableVrr)) {
qCWarning(KWIN_DRM) << "Setting vrr failed!" << strerror(errno);