diff --git a/src/backends/drm/drm_egl_layer.cpp b/src/backends/drm/drm_egl_layer.cpp index 03bf86ed77..6350b2fcc7 100644 --- a/src/backends/drm/drm_egl_layer.cpp +++ b/src/backends/drm/drm_egl_layer.cpp @@ -94,6 +94,13 @@ bool EglGbmLayer::scanout(SurfaceItem *surfaceItem) return false; } const auto surface = item->surface(); + // kernel documentation says that + // "Devices that don’t 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 + m_bufferSourceBox = surface->bufferSourceBox().toRect(); + if (surface->bufferSourceBox() != m_bufferSourceBox) { + return false; + } const auto neededTransform = surface->bufferTransform().combine(m_pipeline->output()->transform().inverted()); const auto plane = m_pipeline->crtc()->primaryPlane(); if (neededTransform != OutputTransform::Kind::Normal && (!plane || !plane->supportsTransformation(neededTransform))) { @@ -160,4 +167,9 @@ OutputTransform EglGbmLayer::hardwareTransform() const { return m_scanoutBuffer ? m_scanoutTransform : OutputTransform::Normal; } + +QRect EglGbmLayer::bufferSourceBox() const +{ + return m_scanoutBuffer ? m_bufferSourceBox : QRect(QPoint(0, 0), m_surface.currentBuffer()->buffer()->size()); +} } diff --git a/src/backends/drm/drm_egl_layer.h b/src/backends/drm/drm_egl_layer.h index 9b67b05157..5c6e7064ad 100644 --- a/src/backends/drm/drm_egl_layer.h +++ b/src/backends/drm/drm_egl_layer.h @@ -39,6 +39,7 @@ public: void releaseBuffers() override; std::chrono::nanoseconds queryRenderTime() const override; OutputTransform hardwareTransform() const override; + QRect bufferSourceBox() const override; private: std::shared_ptr m_scanoutBuffer; @@ -46,6 +47,7 @@ private: OutputTransform m_scanoutTransform = OutputTransform::Kind::Normal; // the output transform the buffer is made for OutputTransform m_scanoutBufferTransform = OutputTransform::Kind::Normal; + QRect m_bufferSourceBox; QRegion m_currentDamage; EglGbmLayerSurface m_surface; diff --git a/src/backends/drm/drm_layer.cpp b/src/backends/drm/drm_layer.cpp index 4c5dfda0ac..e944ae2e6f 100644 --- a/src/backends/drm/drm_layer.cpp +++ b/src/backends/drm/drm_layer.cpp @@ -7,6 +7,8 @@ SPDX-License-Identifier: GPL-2.0-or-later */ #include "drm_layer.h" +#include "core/graphicsbuffer.h" +#include "drm_buffer.h" #include "drm_pipeline.h" #include @@ -36,4 +38,10 @@ OutputTransform DrmPipelineLayer::hardwareTransform() const { return OutputTransform::Kind::Normal; } + +QRect DrmPipelineLayer::bufferSourceBox() const +{ + const auto buffer = currentBuffer(); + return buffer ? QRect(QPoint(0, 0), currentBuffer()->buffer()->size()) : QRect(); +} } diff --git a/src/backends/drm/drm_layer.h b/src/backends/drm/drm_layer.h index 89846efcc5..a0c37fbf20 100644 --- a/src/backends/drm/drm_layer.h +++ b/src/backends/drm/drm_layer.h @@ -39,6 +39,7 @@ public: virtual bool checkTestBuffer() = 0; virtual std::shared_ptr currentBuffer() const = 0; virtual OutputTransform hardwareTransform() const; + virtual QRect bufferSourceBox() const; protected: DrmPipeline *const m_pipeline; diff --git a/src/backends/drm/drm_pipeline.cpp b/src/backends/drm/drm_pipeline.cpp index 9bd47b315d..6e9233b2e2 100644 --- a/src/backends/drm/drm_pipeline.cpp +++ b/src/backends/drm/drm_pipeline.cpp @@ -266,7 +266,7 @@ DrmPipeline::Error DrmPipeline::prepareAtomicPresentation(DrmAtomicCommit *commi } else if (planeTransform != DrmPlane::Transformation::Rotate0) { return Error::InvalidArguments; } - primary->set(commit, QPoint(0, 0), fb->buffer()->size(), centerBuffer(transform.map(fb->buffer()->size()), m_pending.mode->size())); + primary->set(commit, m_primaryLayer->bufferSourceBox(), centerBuffer(transform.map(fb->buffer()->size()), m_pending.mode->size())); commit->addBuffer(m_pending.crtc->primaryPlane(), fb); if (fb->buffer()->dmabufAttributes()->format == DRM_FORMAT_NV12) { if (!primary->colorEncoding.isValid() || !primary->colorRange.isValid()) { @@ -283,12 +283,17 @@ void DrmPipeline::prepareAtomicCursor(DrmAtomicCommit *commit) { auto plane = m_pending.crtc->cursorPlane(); const auto layer = cursorLayer(); - plane->set(commit, QPoint(0, 0), gpu()->cursorSize(), QRect(layer->position().toPoint(), gpu()->cursorSize())); - commit->addProperty(plane->crtcId, layer->isEnabled() ? m_pending.crtc->id() : 0); - commit->addBuffer(plane, layer->isEnabled() ? layer->currentBuffer() : nullptr); - if (plane->vmHotspotX.isValid() && plane->vmHotspotY.isValid()) { - commit->addProperty(plane->vmHotspotX, std::round(layer->hotspot().x())); - commit->addProperty(plane->vmHotspotY, std::round(layer->hotspot().y())); + if (layer->isEnabled()) { + plane->set(commit, layer->bufferSourceBox(), QRect(layer->position().toPoint(), gpu()->cursorSize())); + commit->addProperty(plane->crtcId, m_pending.crtc->id()); + commit->addBuffer(plane, layer->currentBuffer()); + if (plane->vmHotspotX.isValid() && plane->vmHotspotY.isValid()) { + commit->addProperty(plane->vmHotspotX, std::round(layer->hotspot().x())); + commit->addProperty(plane->vmHotspotY, std::round(layer->hotspot().y())); + } + } else { + commit->addProperty(plane->crtcId, 0); + commit->addBuffer(plane, nullptr); } } diff --git a/src/backends/drm/drm_pipeline_legacy.cpp b/src/backends/drm/drm_pipeline_legacy.cpp index 80a1afa7e3..f8a955b016 100644 --- a/src/backends/drm/drm_pipeline_legacy.cpp +++ b/src/backends/drm/drm_pipeline_legacy.cpp @@ -30,6 +30,9 @@ DrmPipeline::Error DrmPipeline::presentLegacy() return err; } const auto buffer = m_primaryLayer->currentBuffer(); + if (m_primaryLayer->bufferSourceBox() != QRect(QPoint(0, 0), buffer->buffer()->size())) { + return Error::InvalidArguments; + } auto commit = std::make_unique(this, buffer); if (!commit->doPageflip(m_pending.presentationMode)) { qCWarning(KWIN_DRM) << "Page flip failed:" << strerror(errno); @@ -50,7 +53,11 @@ DrmPipeline::Error DrmPipeline::legacyModeset() if (!m_primaryLayer->checkTestBuffer()) { return Error::TestBufferFailed; } - auto commit = std::make_unique(this, m_primaryLayer->currentBuffer()); + const auto buffer = m_primaryLayer->currentBuffer(); + if (m_primaryLayer->bufferSourceBox() != QRect(QPoint(0, 0), buffer->buffer()->size())) { + return Error::InvalidArguments; + } + auto commit = std::make_unique(this, buffer); if (!commit->doModeset(m_connector, m_pending.mode.get())) { qCWarning(KWIN_DRM) << "Modeset failed!" << strerror(errno); return errnoToError(); diff --git a/src/backends/drm/drm_plane.cpp b/src/backends/drm/drm_plane.cpp index 903f5b5d19..fc06a13112 100644 --- a/src/backends/drm/drm_plane.cpp +++ b/src/backends/drm/drm_plane.cpp @@ -126,14 +126,13 @@ bool DrmPlane::updateProperties() return true; } -void DrmPlane::set(DrmAtomicCommit *commit, const QPoint &srcPos, const QSize &srcSize, const QRect &dst) +void DrmPlane::set(DrmAtomicCommit *commit, const QRect &src, const QRect &dst) { // Src* are in 16.16 fixed point format - commit->addProperty(srcX, srcPos.x() << 16); - commit->addProperty(srcX, srcPos.x() << 16); - commit->addProperty(srcY, srcPos.y() << 16); - commit->addProperty(srcW, srcSize.width() << 16); - commit->addProperty(srcH, srcSize.height() << 16); + commit->addProperty(srcX, src.x() << 16); + commit->addProperty(srcY, src.y() << 16); + commit->addProperty(srcW, src.width() << 16); + commit->addProperty(srcH, src.height() << 16); commit->addProperty(crtcX, dst.x()); commit->addProperty(crtcY, dst.y()); commit->addProperty(crtcW, dst.width()); diff --git a/src/backends/drm/drm_plane.h b/src/backends/drm/drm_plane.h index 6121a726fc..05be8cebca 100644 --- a/src/backends/drm/drm_plane.h +++ b/src/backends/drm/drm_plane.h @@ -41,7 +41,7 @@ public: void setCurrentBuffer(const std::shared_ptr &b); void releaseCurrentBuffer(); - void set(DrmAtomicCommit *commit, const QPoint &srcPos, const QSize &srcSize, const QRect &dst); + void set(DrmAtomicCommit *commit, const QRect &src, const QRect &dst); enum class TypeIndex : uint64_t { Overlay = 0,