diff --git a/src/backends/drm/drm_egl_cursor_layer.cpp b/src/backends/drm/drm_egl_cursor_layer.cpp index be28502f62..19e0c539d0 100644 --- a/src/backends/drm/drm_egl_cursor_layer.cpp +++ b/src/backends/drm/drm_egl_cursor_layer.cpp @@ -25,7 +25,7 @@ EglGbmCursorLayer::EglGbmCursorLayer(EglGbmBackend *eglBackend, DrmPipeline *pip { } -std::optional EglGbmCursorLayer::beginFrame() +std::optional EglGbmCursorLayer::doBeginFrame() { if (m_pipeline->amdgpuVrrWorkaroundActive()) { return std::nullopt; @@ -36,7 +36,7 @@ std::optional EglGbmCursorLayer::beginFrame() return m_surface.startRendering(m_pipeline->gpu()->cursorSize(), m_pipeline->output()->transform().combine(OutputTransform::FlipY), m_pipeline->cursorFormats(), m_pipeline->colorDescription(), m_pipeline->output()->channelFactors(), m_pipeline->iccProfile(), m_pipeline->output()->needsColormanagement()); } -bool EglGbmCursorLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) +bool EglGbmCursorLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) { return m_surface.endRendering(damagedRegion); } diff --git a/src/backends/drm/drm_egl_cursor_layer.h b/src/backends/drm/drm_egl_cursor_layer.h index 3307cffc7e..8e2ebf26ba 100644 --- a/src/backends/drm/drm_egl_cursor_layer.h +++ b/src/backends/drm/drm_egl_cursor_layer.h @@ -27,8 +27,8 @@ class EglGbmCursorLayer : public DrmPipelineLayer public: EglGbmCursorLayer(EglGbmBackend *eglBackend, DrmPipeline *pipeline); - std::optional beginFrame() override; - bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override; + std::optional doBeginFrame() override; + bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override; std::shared_ptr currentBuffer() const override; bool checkTestBuffer() override; void releaseBuffers() override; diff --git a/src/backends/drm/drm_egl_layer.cpp b/src/backends/drm/drm_egl_layer.cpp index df701c2a5c..f9e7c7a8ea 100644 --- a/src/backends/drm/drm_egl_layer.cpp +++ b/src/backends/drm/drm_egl_layer.cpp @@ -33,14 +33,14 @@ EglGbmLayer::EglGbmLayer(EglGbmBackend *eglBackend, DrmPipeline *pipeline) { } -std::optional EglGbmLayer::beginFrame() +std::optional EglGbmLayer::doBeginFrame() { m_scanoutBuffer.reset(); return m_surface.startRendering(m_pipeline->mode()->size(), m_pipeline->output()->transform().combine(OutputTransform::FlipY), m_pipeline->formats(), m_pipeline->colorDescription(), m_pipeline->output()->channelFactors(), m_pipeline->iccProfile(), m_pipeline->output()->needsColormanagement()); } -bool EglGbmLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) +bool EglGbmLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) { return m_surface.endRendering(damagedRegion); } @@ -54,7 +54,7 @@ std::shared_ptr EglGbmLayer::texture() const { if (m_scanoutBuffer) { const auto ret = m_surface.eglBackend()->importDmaBufAsTexture(*m_scanoutBuffer->buffer()->dmabufAttributes()); - ret->setContentTransform(m_scanoutBufferTransform.combine(OutputTransform::FlipY)); + ret->setContentTransform(offloadTransform().combine(OutputTransform::FlipY)); return ret; } else { return m_surface.texture(); @@ -66,7 +66,7 @@ ColorDescription EglGbmLayer::colorDescription() const return m_surface.colorDescription(); } -bool EglGbmLayer::doAttemptScanout(GraphicsBuffer *buffer, const QRectF &sourceRect, const QSizeF &size, OutputTransform transform, const ColorDescription &color) +bool EglGbmLayer::doAttemptScanout(GraphicsBuffer *buffer, const ColorDescription &color) { static bool valid; static const bool directScanoutDisabled = qEnvironmentVariableIntValue("KWIN_DRM_NO_DIRECT_SCANOUT", &valid) == 1 && valid; @@ -80,21 +80,17 @@ bool EglGbmLayer::doAttemptScanout(GraphicsBuffer *buffer, const QRectF &sourceR // 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 = sourceRect.toRect(); - if (sourceRect != m_bufferSourceBox) { + if (sourceRect() != sourceRect().toRect()) { return false; } - const auto neededTransform = transform.combine(m_pipeline->output()->transform().inverted()); const auto plane = m_pipeline->crtc()->primaryPlane(); - if (neededTransform != OutputTransform::Kind::Normal && (!plane || !plane->supportsTransformation(neededTransform))) { + if (offloadTransform() != OutputTransform::Kind::Normal && (!plane || !plane->supportsTransformation(offloadTransform()))) { return false; } // importing a buffer from another GPU without an explicit modifier can mess up the buffer format if (buffer->dmabufAttributes()->modifier == DRM_FORMAT_MOD_INVALID && m_pipeline->gpu()->platform()->gpuCount() > 1) { return false; } - m_scanoutTransform = neededTransform; - m_scanoutBufferTransform = transform; m_scanoutBuffer = m_pipeline->gpu()->importBuffer(buffer, FileDescriptor{}); if (m_scanoutBuffer && m_pipeline->testScanout()) { m_surface.forgetDamage(); // TODO: Use absolute frame sequence numbers for indexing the DamageJournal. It's more flexible and less error-prone @@ -121,16 +117,6 @@ std::chrono::nanoseconds EglGbmLayer::queryRenderTime() const return m_surface.queryRenderTime(); } -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()); -} - DrmDevice *EglGbmLayer::scanoutDevice() const { return m_pipeline->gpu()->drmDevice(); diff --git a/src/backends/drm/drm_egl_layer.h b/src/backends/drm/drm_egl_layer.h index 314e6bcf49..e29c2659fe 100644 --- a/src/backends/drm/drm_egl_layer.h +++ b/src/backends/drm/drm_egl_layer.h @@ -27,28 +27,21 @@ class EglGbmLayer : public DrmPipelineLayer public: EglGbmLayer(EglGbmBackend *eglBackend, DrmPipeline *pipeline); - std::optional beginFrame() override; - bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override; + std::optional doBeginFrame() override; + bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override; bool checkTestBuffer() override; std::shared_ptr currentBuffer() const override; std::shared_ptr texture() const override; ColorDescription colorDescription() const; void releaseBuffers() override; std::chrono::nanoseconds queryRenderTime() const override; - OutputTransform hardwareTransform() const override; - QRect bufferSourceBox() const override; DrmDevice *scanoutDevice() const override; QHash> supportedDrmFormats() const override; private: - bool doAttemptScanout(GraphicsBuffer *buffer, const QRectF &sourceRect, const QSizeF &size, OutputTransform transform, const ColorDescription &color) override; + bool doAttemptScanout(GraphicsBuffer *buffer, const ColorDescription &color) override; std::shared_ptr m_scanoutBuffer; - // the transform the drm plane will apply to the buffer - OutputTransform m_scanoutTransform = OutputTransform::Kind::Normal; - // the output transform the buffer is made for - OutputTransform m_scanoutBufferTransform = OutputTransform::Kind::Normal; - QRect m_bufferSourceBox; EglGbmLayerSurface m_surface; }; diff --git a/src/backends/drm/drm_gpu.cpp b/src/backends/drm/drm_gpu.cpp index df392d1cdf..f07d48a3ce 100644 --- a/src/backends/drm/drm_gpu.cpp +++ b/src/backends/drm/drm_gpu.cpp @@ -442,6 +442,17 @@ DrmPipeline::Error DrmGpu::testPendingConfiguration() return c1->crtcId.value() > c2->crtcId.value(); }); } + // reset all outputs to their most basic configuration (primary plane without scaling) + // for the test, and set the target rects appropriately + for (const auto output : std::as_const(m_drmOutputs)) { + if (!output->lease()) { + const auto primary = output->primaryLayer(); + primary->setTargetRect(QRect(QPoint(0, 0), output->connector()->pipeline()->mode()->size())); + primary->setSourceRect(QRect(QPoint(0, 0), output->connector()->pipeline()->mode()->size())); + primary->setEnabled(true); + output->cursorLayer()->setEnabled(false); + } + } return checkCrtcAssignment(connectors, crtcs); } diff --git a/src/backends/drm/drm_layer.cpp b/src/backends/drm/drm_layer.cpp index 41da5dce2e..920be5868e 100644 --- a/src/backends/drm/drm_layer.cpp +++ b/src/backends/drm/drm_layer.cpp @@ -9,6 +9,7 @@ #include "drm_layer.h" #include "core/graphicsbuffer.h" #include "drm_buffer.h" +#include "drm_output.h" #include "drm_pipeline.h" #include @@ -17,6 +18,11 @@ namespace KWin { +DrmOutputLayer::DrmOutputLayer(Output *output) + : OutputLayer(output) +{ +} + DrmOutputLayer::~DrmOutputLayer() = default; std::shared_ptr DrmOutputLayer::texture() const @@ -25,18 +31,8 @@ std::shared_ptr DrmOutputLayer::texture() const } DrmPipelineLayer::DrmPipelineLayer(DrmPipeline *pipeline) - : m_pipeline(pipeline) + : DrmOutputLayer(pipeline->output()) + , m_pipeline(pipeline) { } - -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 0624a2185d..1ae9c954d7 100644 --- a/src/backends/drm/drm_layer.h +++ b/src/backends/drm/drm_layer.h @@ -24,6 +24,7 @@ class DrmPipeline; class DrmOutputLayer : public OutputLayer { public: + explicit DrmOutputLayer(Output *output); virtual ~DrmOutputLayer(); virtual std::shared_ptr texture() const; @@ -37,8 +38,6 @@ 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 189add861b..6257e386b7 100644 --- a/src/backends/drm/drm_pipeline.cpp +++ b/src/backends/drm/drm_pipeline.cpp @@ -211,21 +211,6 @@ DrmPipeline::Error DrmPipeline::prepareAtomicCommit(DrmAtomicCommit *commit, Com return Error::None; } -static QRect centerBuffer(const QSize &bufferSize, const QSize &modeSize) -{ - const double widthScale = bufferSize.width() / double(modeSize.width()); - const double heightScale = bufferSize.height() / double(modeSize.height()); - if (widthScale > heightScale) { - const QSize size = bufferSize / widthScale; - const uint32_t yOffset = (modeSize.height() - size.height()) / 2; - return QRect(QPoint(0, yOffset), size); - } else { - const QSize size = bufferSize / heightScale; - const uint32_t xOffset = (modeSize.width() - size.width()) / 2; - return QRect(QPoint(xOffset, 0), size); - } -} - DrmPipeline::Error DrmPipeline::prepareAtomicPresentation(DrmAtomicCommit *commit) { commit->setPresentationMode(m_pending.presentationMode); @@ -256,7 +241,7 @@ DrmPipeline::Error DrmPipeline::prepareAtomicPresentation(DrmAtomicCommit *commi return Error::InvalidArguments; } const auto primary = m_pending.crtc->primaryPlane(); - const auto transform = m_primaryLayer->hardwareTransform(); + const auto transform = m_primaryLayer->offloadTransform(); const auto planeTransform = DrmPlane::outputTransformToPlaneTransform(transform); if (primary->rotation.isValid()) { if (!primary->rotation.hasEnum(planeTransform)) { @@ -266,7 +251,7 @@ DrmPipeline::Error DrmPipeline::prepareAtomicPresentation(DrmAtomicCommit *commi } else if (planeTransform != DrmPlane::Transformation::Rotate0) { return Error::InvalidArguments; } - primary->set(commit, m_primaryLayer->bufferSourceBox(), centerBuffer(transform.map(fb->buffer()->size()), m_pending.mode->size())); + primary->set(commit, m_primaryLayer->sourceRect().toRect(), m_primaryLayer->targetRect()); commit->addBuffer(m_pending.crtc->primaryPlane(), fb); if (fb->buffer()->dmabufAttributes()->format == DRM_FORMAT_NV12) { if (!primary->colorEncoding.isValid() || !primary->colorRange.isValid()) { @@ -284,7 +269,7 @@ void DrmPipeline::prepareAtomicCursor(DrmAtomicCommit *commit) auto plane = m_pending.crtc->cursorPlane(); const auto layer = cursorLayer(); if (layer->isEnabled()) { - plane->set(commit, layer->bufferSourceBox(), QRect(layer->position().toPoint(), gpu()->cursorSize())); + plane->set(commit, layer->sourceRect().toRect(), layer->targetRect()); commit->addProperty(plane->crtcId, m_pending.crtc->id()); commit->addBuffer(plane, layer->currentBuffer()); if (plane->vmHotspotX.isValid() && plane->vmHotspotY.isValid()) { diff --git a/src/backends/drm/drm_pipeline_legacy.cpp b/src/backends/drm/drm_pipeline_legacy.cpp index f8a955b016..dc85b675aa 100644 --- a/src/backends/drm/drm_pipeline_legacy.cpp +++ b/src/backends/drm/drm_pipeline_legacy.cpp @@ -30,7 +30,7 @@ DrmPipeline::Error DrmPipeline::presentLegacy() return err; } const auto buffer = m_primaryLayer->currentBuffer(); - if (m_primaryLayer->bufferSourceBox() != QRect(QPoint(0, 0), buffer->buffer()->size())) { + if (m_primaryLayer->sourceRect() != m_primaryLayer->targetRect() || m_primaryLayer->targetRect() != QRect(QPoint(0, 0), buffer->buffer()->size())) { return Error::InvalidArguments; } auto commit = std::make_unique(this, buffer); @@ -54,7 +54,7 @@ DrmPipeline::Error DrmPipeline::legacyModeset() return Error::TestBufferFailed; } const auto buffer = m_primaryLayer->currentBuffer(); - if (m_primaryLayer->bufferSourceBox() != QRect(QPoint(0, 0), buffer->buffer()->size())) { + if (m_primaryLayer->sourceRect() != QRect(QPoint(0, 0), buffer->buffer()->size())) { return Error::InvalidArguments; } auto commit = std::make_unique(this, buffer); @@ -184,8 +184,8 @@ bool DrmPipeline::setCursorLegacy() struct drm_mode_cursor2 arg = { .flags = DRM_MODE_CURSOR_BO | DRM_MODE_CURSOR_MOVE, .crtc_id = m_pending.crtc->id(), - .x = int32_t(m_cursorLayer->position().x()), - .y = int32_t(m_cursorLayer->position().y()), + .x = int32_t(m_cursorLayer->targetRect().x()), + .y = int32_t(m_cursorLayer->targetRect().y()), .width = (uint32_t)gpu()->cursorSize().width(), .height = (uint32_t)gpu()->cursorSize().height(), .handle = handle, diff --git a/src/backends/drm/drm_qpainter_layer.cpp b/src/backends/drm/drm_qpainter_layer.cpp index acc19171df..4e39c451d8 100644 --- a/src/backends/drm/drm_qpainter_layer.cpp +++ b/src/backends/drm/drm_qpainter_layer.cpp @@ -26,7 +26,7 @@ DrmQPainterLayer::DrmQPainterLayer(DrmPipeline *pipeline) { } -std::optional DrmQPainterLayer::beginFrame() +std::optional DrmQPainterLayer::doBeginFrame() { if (!doesSwapchainFit()) { m_swapchain = std::make_shared(m_pipeline->gpu()->drmDevice()->allocator(), m_pipeline->mode()->size(), DRM_FORMAT_XRGB8888); @@ -46,7 +46,7 @@ std::optional DrmQPainterLayer::beginFrame() }; } -bool DrmQPainterLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) +bool DrmQPainterLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) { m_renderTime = std::chrono::steady_clock::now() - m_renderStart; m_currentFramebuffer = m_pipeline->gpu()->importBuffer(m_currentBuffer->buffer(), FileDescriptor{}); @@ -111,7 +111,7 @@ DrmCursorQPainterLayer::DrmCursorQPainterLayer(DrmPipeline *pipeline) { } -std::optional DrmCursorQPainterLayer::beginFrame() +std::optional DrmCursorQPainterLayer::doBeginFrame() { if (!m_swapchain) { m_swapchain = std::make_shared(m_pipeline->gpu()->drmDevice()->allocator(), m_pipeline->gpu()->cursorSize(), DRM_FORMAT_ARGB8888); @@ -127,7 +127,7 @@ std::optional DrmCursorQPainterLayer::beginFrame() }; } -bool DrmCursorQPainterLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) +bool DrmCursorQPainterLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) { m_renderTime = std::chrono::steady_clock::now() - m_renderStart; m_currentFramebuffer = m_pipeline->gpu()->importBuffer(m_currentBuffer->buffer(), FileDescriptor{}); @@ -169,11 +169,11 @@ QHash> DrmCursorQPainterLayer::supportedDrmFormats() c } DrmVirtualQPainterLayer::DrmVirtualQPainterLayer(DrmVirtualOutput *output) - : m_output(output) + : DrmOutputLayer(output) { } -std::optional DrmVirtualQPainterLayer::beginFrame() +std::optional DrmVirtualQPainterLayer::doBeginFrame() { if (m_image.isNull() || m_image.size() != m_output->modeSize()) { m_image = QImage(m_output->modeSize(), QImage::Format_RGB32); @@ -185,7 +185,7 @@ std::optional DrmVirtualQPainterLayer::beginFrame() }; } -bool DrmVirtualQPainterLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) +bool DrmVirtualQPainterLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) { m_renderTime = std::chrono::steady_clock::now() - m_renderStart; return true; diff --git a/src/backends/drm/drm_qpainter_layer.h b/src/backends/drm/drm_qpainter_layer.h index 0c249ebeb2..273e28fda3 100644 --- a/src/backends/drm/drm_qpainter_layer.h +++ b/src/backends/drm/drm_qpainter_layer.h @@ -27,8 +27,8 @@ class DrmQPainterLayer : public DrmPipelineLayer public: DrmQPainterLayer(DrmPipeline *pipeline); - std::optional beginFrame() override; - bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override; + std::optional doBeginFrame() override; + bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override; bool checkTestBuffer() override; std::shared_ptr currentBuffer() const override; void releaseBuffers() override; @@ -52,8 +52,8 @@ class DrmCursorQPainterLayer : public DrmPipelineLayer public: DrmCursorQPainterLayer(DrmPipeline *pipeline); - std::optional beginFrame() override; - bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override; + std::optional doBeginFrame() override; + bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override; bool checkTestBuffer() override; std::shared_ptr currentBuffer() const override; @@ -75,8 +75,8 @@ class DrmVirtualQPainterLayer : public DrmOutputLayer public: DrmVirtualQPainterLayer(DrmVirtualOutput *output); - std::optional beginFrame() override; - bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override; + std::optional doBeginFrame() override; + bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override; void releaseBuffers() override; std::chrono::nanoseconds queryRenderTime() const override; @@ -85,7 +85,6 @@ public: private: QImage m_image; - DrmVirtualOutput *const m_output; std::chrono::steady_clock::time_point m_renderStart; std::chrono::nanoseconds m_renderTime; }; diff --git a/src/backends/drm/drm_virtual_egl_layer.cpp b/src/backends/drm/drm_virtual_egl_layer.cpp index 290d077e80..a2b165c1d8 100644 --- a/src/backends/drm/drm_virtual_egl_layer.cpp +++ b/src/backends/drm/drm_virtual_egl_layer.cpp @@ -27,14 +27,14 @@ namespace KWin { VirtualEglGbmLayer::VirtualEglGbmLayer(EglGbmBackend *eglBackend, DrmVirtualOutput *output) - : m_output(output) + : DrmOutputLayer(output) , m_eglBackend(eglBackend) { } VirtualEglGbmLayer::~VirtualEglGbmLayer() = default; -std::optional VirtualEglGbmLayer::beginFrame() +std::optional VirtualEglGbmLayer::doBeginFrame() { // gbm surface if (doesGbmSwapchainFit(m_gbmSwapchain.get())) { @@ -79,7 +79,7 @@ std::optional VirtualEglGbmLayer::beginFrame() }; } -bool VirtualEglGbmLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) +bool VirtualEglGbmLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) { m_query->end(); glFlush(); @@ -134,7 +134,7 @@ std::shared_ptr VirtualEglGbmLayer::texture() const return nullptr; } -bool VirtualEglGbmLayer::doAttemptScanout(GraphicsBuffer *buffer, const QRectF &sourceRect, const QSizeF &targetSize, OutputTransform transform, const ColorDescription &color) +bool VirtualEglGbmLayer::doAttemptScanout(GraphicsBuffer *buffer, const ColorDescription &color) { static bool valid; static const bool directScanoutDisabled = qEnvironmentVariableIntValue("KWIN_DRM_NO_DIRECT_SCANOUT", &valid) == 1 && valid; @@ -142,7 +142,7 @@ bool VirtualEglGbmLayer::doAttemptScanout(GraphicsBuffer *buffer, const QRectF & return false; } - if (sourceRect != QRectF(QPointF(0, 0), targetSize) || targetSize != m_output->modeSize() || targetSize != buffer->size()) { + if (sourceRect() != targetRect() || targetRect().topLeft() != QPointF(0, 0) || targetRect().size() != m_output->modeSize() || targetRect().size() != buffer->size() || offloadTransform() != OutputTransform::Kind::Normal) { return false; } m_scanoutBuffer = buffer; diff --git a/src/backends/drm/drm_virtual_egl_layer.h b/src/backends/drm/drm_virtual_egl_layer.h index e1805f2004..36b774d42a 100644 --- a/src/backends/drm/drm_virtual_egl_layer.h +++ b/src/backends/drm/drm_virtual_egl_layer.h @@ -34,8 +34,8 @@ public: VirtualEglGbmLayer(EglGbmBackend *eglBackend, DrmVirtualOutput *output); ~VirtualEglGbmLayer() override; - std::optional beginFrame() override; - bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override; + std::optional doBeginFrame() override; + bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override; std::shared_ptr texture() const override; void releaseBuffers() override; @@ -45,7 +45,7 @@ public: const ColorDescription &colorDescription() const; private: - bool doAttemptScanout(GraphicsBuffer *buffer, const QRectF &sourceRect, const QSizeF &targetSize, OutputTransform transform, const ColorDescription &color) override; + bool doAttemptScanout(GraphicsBuffer *buffer, const ColorDescription &color) override; std::shared_ptr createGbmSwapchain() const; bool doesGbmSwapchainFit(EglSwapchain *swapchain) const; @@ -58,7 +58,6 @@ private: std::shared_ptr m_currentSlot; std::unique_ptr m_query; - DrmVirtualOutput *const m_output; EglGbmBackend *const m_eglBackend; }; diff --git a/src/backends/virtual/virtual_egl_backend.cpp b/src/backends/virtual/virtual_egl_backend.cpp index ab401d48d3..b2ebc3e54e 100644 --- a/src/backends/virtual/virtual_egl_backend.cpp +++ b/src/backends/virtual/virtual_egl_backend.cpp @@ -24,8 +24,8 @@ namespace KWin { VirtualEglLayer::VirtualEglLayer(Output *output, VirtualEglBackend *backend) - : m_backend(backend) - , m_output(output) + : OutputLayer(output) + , m_backend(backend) { } @@ -34,7 +34,7 @@ std::shared_ptr VirtualEglLayer::texture() const return m_current->texture(); } -std::optional VirtualEglLayer::beginFrame() +std::optional VirtualEglLayer::doBeginFrame() { m_backend->makeCurrent(); @@ -62,7 +62,7 @@ std::optional VirtualEglLayer::beginFrame() }; } -bool VirtualEglLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) +bool VirtualEglLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) { m_query->end(); glFlush(); // flush pending rendering commands. diff --git a/src/backends/virtual/virtual_egl_backend.h b/src/backends/virtual/virtual_egl_backend.h index d4850cc3f2..dd2d6f97b7 100644 --- a/src/backends/virtual/virtual_egl_backend.h +++ b/src/backends/virtual/virtual_egl_backend.h @@ -30,8 +30,8 @@ class VirtualEglLayer : public OutputLayer public: VirtualEglLayer(Output *output, VirtualEglBackend *backend); - std::optional beginFrame() override; - bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override; + std::optional doBeginFrame() override; + bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override; std::shared_ptr texture() const; std::chrono::nanoseconds queryRenderTime() const override; @@ -40,7 +40,6 @@ public: private: VirtualEglBackend *const m_backend; - Output *m_output; std::shared_ptr m_swapchain; std::shared_ptr m_current; std::unique_ptr m_query; diff --git a/src/backends/virtual/virtual_qpainter_backend.cpp b/src/backends/virtual/virtual_qpainter_backend.cpp index a1f8c46d3e..3ccb7a3f5e 100644 --- a/src/backends/virtual/virtual_qpainter_backend.cpp +++ b/src/backends/virtual/virtual_qpainter_backend.cpp @@ -21,7 +21,7 @@ namespace KWin { VirtualQPainterLayer::VirtualQPainterLayer(Output *output, VirtualQPainterBackend *backend) - : m_output(output) + : OutputLayer(output) , m_backend(backend) { } @@ -30,7 +30,7 @@ VirtualQPainterLayer::~VirtualQPainterLayer() { } -std::optional VirtualQPainterLayer::beginFrame() +std::optional VirtualQPainterLayer::doBeginFrame() { const QSize nativeSize(m_output->modeSize()); if (!m_swapchain || m_swapchain->size() != nativeSize) { @@ -49,7 +49,7 @@ std::optional VirtualQPainterLayer::beginFrame() }; } -bool VirtualQPainterLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) +bool VirtualQPainterLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) { m_renderTime = std::chrono::steady_clock::now() - m_renderStart; return true; diff --git a/src/backends/virtual/virtual_qpainter_backend.h b/src/backends/virtual/virtual_qpainter_backend.h index 4010fae91b..0230e7aa26 100644 --- a/src/backends/virtual/virtual_qpainter_backend.h +++ b/src/backends/virtual/virtual_qpainter_backend.h @@ -32,15 +32,14 @@ public: VirtualQPainterLayer(Output *output, VirtualQPainterBackend *backend); ~VirtualQPainterLayer() override; - std::optional beginFrame() override; - bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override; + std::optional doBeginFrame() override; + bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override; QImage *image(); std::chrono::nanoseconds queryRenderTime() const override; DrmDevice *scanoutDevice() const override; QHash> supportedDrmFormats() const override; private: - Output *const m_output; VirtualQPainterBackend *const m_backend; std::unique_ptr m_swapchain; std::shared_ptr m_current; diff --git a/src/backends/wayland/wayland_egl_backend.cpp b/src/backends/wayland/wayland_egl_backend.cpp index 4b49642470..b8ce7dcc5e 100644 --- a/src/backends/wayland/wayland_egl_backend.cpp +++ b/src/backends/wayland/wayland_egl_backend.cpp @@ -37,7 +37,7 @@ namespace Wayland static const bool bufferAgeEnabled = qEnvironmentVariable("KWIN_USE_BUFFER_AGE") != QStringLiteral("0"); WaylandEglPrimaryLayer::WaylandEglPrimaryLayer(WaylandOutput *output, WaylandEglBackend *backend) - : m_waylandOutput(output) + : OutputLayer(output) , m_backend(backend) { } @@ -56,14 +56,14 @@ std::shared_ptr WaylandEglPrimaryLayer::texture() const return m_buffer->texture(); } -std::optional WaylandEglPrimaryLayer::beginFrame() +std::optional WaylandEglPrimaryLayer::doBeginFrame() { if (!m_backend->openglContext()->makeCurrent()) { qCCritical(KWIN_WAYLAND_BACKEND) << "Make Context Current failed"; return std::nullopt; } - const QSize nativeSize = m_waylandOutput->modeSize(); + const QSize nativeSize = m_output->modeSize(); if (!m_swapchain || m_swapchain->size() != nativeSize) { const QHash> formatTable = m_backend->backend()->display()->linuxDmabuf()->formats(); uint32_t format = DRM_FORMAT_INVALID; @@ -102,7 +102,7 @@ std::optional WaylandEglPrimaryLayer::beginFrame() }; } -bool WaylandEglPrimaryLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) +bool WaylandEglPrimaryLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) { m_query->end(); // Flush rendering commands to the dmabuf. @@ -116,14 +116,14 @@ bool WaylandEglPrimaryLayer::endFrame(const QRegion &renderedRegion, const QRegi return true; } -bool WaylandEglPrimaryLayer::doAttemptScanout(GraphicsBuffer *buffer, const QRectF &sourceRect, const QSizeF &targetSize, OutputTransform transform, const ColorDescription &color) +bool WaylandEglPrimaryLayer::doAttemptScanout(GraphicsBuffer *buffer, const ColorDescription &color) { Q_ASSERT(!m_presentationBuffer); // TODO use viewporter to relax this check - if (sourceRect != QRectF(QPointF(0, 0), targetSize) || targetSize != m_waylandOutput->modeSize()) { + if (sourceRect() != targetRect() || targetRect() != QRectF(QPointF(0, 0), m_output->modeSize())) { return false; } - if (transform != OutputTransform::Kind::Normal || color != ColorDescription::sRGB) { + if (offloadTransform() != OutputTransform::Kind::Normal || color != ColorDescription::sRGB) { return false; } m_presentationBuffer = m_backend->backend()->importBuffer(buffer); @@ -132,10 +132,11 @@ bool WaylandEglPrimaryLayer::doAttemptScanout(GraphicsBuffer *buffer, const QRec void WaylandEglPrimaryLayer::present() { - KWayland::Client::Surface *surface = m_waylandOutput->surface(); + const auto waylandOutput = static_cast(m_output); + KWayland::Client::Surface *surface = waylandOutput->surface(); surface->attachBuffer(m_presentationBuffer); surface->damage(m_damageJournal.lastDamage()); - surface->setScale(std::ceil(m_waylandOutput->scale())); + surface->setScale(std::ceil(waylandOutput->scale())); surface->commit(); m_presentationBuffer = nullptr; } @@ -157,7 +158,7 @@ QHash> WaylandEglPrimaryLayer::supportedDrmFormats() c } WaylandEglCursorLayer::WaylandEglCursorLayer(WaylandOutput *output, WaylandEglBackend *backend) - : m_output(output) + : OutputLayer(output) , m_backend(backend) { } @@ -167,14 +168,14 @@ WaylandEglCursorLayer::~WaylandEglCursorLayer() m_backend->openglContext()->makeCurrent(); } -std::optional WaylandEglCursorLayer::beginFrame() +std::optional WaylandEglCursorLayer::doBeginFrame() { if (!m_backend->openglContext()->makeCurrent()) { qCCritical(KWIN_WAYLAND_BACKEND) << "Make Context Current failed"; return std::nullopt; } - const auto tmp = size().expandedTo(QSize(64, 64)); + const auto tmp = targetRect().size().expandedTo(QSize(64, 64)); const QSize bufferSize(std::ceil(tmp.width()), std::ceil(tmp.height())); if (!m_swapchain || m_swapchain->size() != bufferSize) { const QHash> formatTable = m_backend->backend()->display()->linuxDmabuf()->formats(); @@ -213,7 +214,7 @@ std::optional WaylandEglCursorLayer::beginFrame() }; } -bool WaylandEglCursorLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) +bool WaylandEglCursorLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) { m_query->end(); // Flush rendering commands to the dmabuf. @@ -222,7 +223,7 @@ bool WaylandEglCursorLayer::endFrame(const QRegion &renderedRegion, const QRegio wl_buffer *buffer = m_backend->backend()->importBuffer(m_buffer->buffer()); Q_ASSERT(buffer); - m_output->cursor()->update(buffer, scale(), hotspot().toPoint()); + static_cast(m_output)->cursor()->update(buffer, scale(), hotspot().toPoint()); EGLNativeFence releaseFence{m_backend->eglDisplayObject()}; m_swapchain->release(m_buffer, releaseFence.takeFileDescriptor()); diff --git a/src/backends/wayland/wayland_egl_backend.h b/src/backends/wayland/wayland_egl_backend.h index 5f5da9f087..2410a0759f 100644 --- a/src/backends/wayland/wayland_egl_backend.h +++ b/src/backends/wayland/wayland_egl_backend.h @@ -42,15 +42,14 @@ public: std::shared_ptr texture() const; void present(); - std::optional beginFrame() override; - bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override; + std::optional doBeginFrame() override; + bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override; std::chrono::nanoseconds queryRenderTime() const override; - bool doAttemptScanout(GraphicsBuffer *buffer, const QRectF &sourceRect, const QSizeF &targetSize, OutputTransform transform, const ColorDescription &color) override; + bool doAttemptScanout(GraphicsBuffer *buffer, const ColorDescription &color) override; DrmDevice *scanoutDevice() const override; QHash> supportedDrmFormats() const override; private: - WaylandOutput *m_waylandOutput; DamageJournal m_damageJournal; std::shared_ptr m_swapchain; std::shared_ptr m_buffer; @@ -69,8 +68,8 @@ public: WaylandEglCursorLayer(WaylandOutput *output, WaylandEglBackend *backend); ~WaylandEglCursorLayer() override; - std::optional beginFrame() override; - bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override; + std::optional doBeginFrame() override; + bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override; std::chrono::nanoseconds queryRenderTime() const override; DrmDevice *scanoutDevice() const override; QHash> supportedDrmFormats() const override; diff --git a/src/backends/wayland/wayland_qpainter_backend.cpp b/src/backends/wayland/wayland_qpainter_backend.cpp index 3b159beede..165dfe21d4 100644 --- a/src/backends/wayland/wayland_qpainter_backend.cpp +++ b/src/backends/wayland/wayland_qpainter_backend.cpp @@ -26,7 +26,8 @@ namespace Wayland { WaylandQPainterPrimaryLayer::WaylandQPainterPrimaryLayer(WaylandOutput *output, WaylandQPainterBackend *backend) - : m_waylandOutput(output) + : OutputLayer(output) + , m_waylandOutput(output) , m_backend(backend) { } @@ -54,7 +55,7 @@ QRegion WaylandQPainterPrimaryLayer::accumulateDamage(int bufferAge) const return m_damageJournal.accumulate(bufferAge, infiniteRegion()); } -std::optional WaylandQPainterPrimaryLayer::beginFrame() +std::optional WaylandQPainterPrimaryLayer::doBeginFrame() { const QSize nativeSize(m_waylandOutput->modeSize()); if (!m_swapchain || m_swapchain->size() != nativeSize) { @@ -73,7 +74,7 @@ std::optional WaylandQPainterPrimaryLayer::beginFrame }; } -bool WaylandQPainterPrimaryLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) +bool WaylandQPainterPrimaryLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) { m_renderTime = std::chrono::steady_clock::now() - m_renderStart; m_damageJournal.add(damagedRegion); @@ -96,7 +97,7 @@ QHash> WaylandQPainterPrimaryLayer::supportedDrmFormat } WaylandQPainterCursorLayer::WaylandQPainterCursorLayer(WaylandOutput *output, WaylandQPainterBackend *backend) - : m_output(output) + : OutputLayer(output) , m_backend(backend) { } @@ -105,9 +106,9 @@ WaylandQPainterCursorLayer::~WaylandQPainterCursorLayer() { } -std::optional WaylandQPainterCursorLayer::beginFrame() +std::optional WaylandQPainterCursorLayer::doBeginFrame() { - const auto tmp = size().expandedTo(QSize(64, 64)); + const auto tmp = targetRect().size().expandedTo(QSize(64, 64)); const QSize bufferSize(std::ceil(tmp.width()), std::ceil(tmp.height())); if (!m_swapchain || m_swapchain->size() != bufferSize) { m_swapchain = std::make_unique(m_backend->graphicsBufferAllocator(), bufferSize, DRM_FORMAT_ARGB8888); @@ -125,13 +126,13 @@ std::optional WaylandQPainterCursorLayer::beginFrame( }; } -bool WaylandQPainterCursorLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) +bool WaylandQPainterCursorLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) { m_renderTime = std::chrono::steady_clock::now() - m_renderStart; - wl_buffer *buffer = m_output->backend()->importBuffer(m_back->buffer()); + wl_buffer *buffer = static_cast(m_output)->backend()->importBuffer(m_back->buffer()); Q_ASSERT(buffer); - m_output->cursor()->update(buffer, scale(), hotspot().toPoint()); + static_cast(m_output)->cursor()->update(buffer, scale(), hotspot().toPoint()); m_swapchain->release(m_back); return true; } diff --git a/src/backends/wayland/wayland_qpainter_backend.h b/src/backends/wayland/wayland_qpainter_backend.h index 55ec70f59b..325606c2b4 100644 --- a/src/backends/wayland/wayland_qpainter_backend.h +++ b/src/backends/wayland/wayland_qpainter_backend.h @@ -37,8 +37,8 @@ public: WaylandQPainterPrimaryLayer(WaylandOutput *output, WaylandQPainterBackend *backend); ~WaylandQPainterPrimaryLayer() override; - std::optional beginFrame() override; - bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override; + std::optional doBeginFrame() override; + bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override; std::chrono::nanoseconds queryRenderTime() const override; DrmDevice *scanoutDevice() const override; QHash> supportedDrmFormats() const override; @@ -68,14 +68,13 @@ public: WaylandQPainterCursorLayer(WaylandOutput *output, WaylandQPainterBackend *backend); ~WaylandQPainterCursorLayer() override; - std::optional beginFrame() override; - bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override; + std::optional doBeginFrame() override; + bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override; std::chrono::nanoseconds queryRenderTime() const override; DrmDevice *scanoutDevice() const override; QHash> supportedDrmFormats() const override; private: - WaylandOutput *m_output; WaylandQPainterBackend *m_backend; std::unique_ptr m_swapchain; std::shared_ptr m_back; diff --git a/src/backends/x11/standalone/x11_standalone_egl_backend.cpp b/src/backends/x11/standalone/x11_standalone_egl_backend.cpp index d3284ba647..5112bb201d 100644 --- a/src/backends/x11/standalone/x11_standalone_egl_backend.cpp +++ b/src/backends/x11/standalone/x11_standalone_egl_backend.cpp @@ -31,16 +31,17 @@ namespace KWin { EglLayer::EglLayer(EglBackend *backend) - : m_backend(backend) + : OutputLayer(nullptr) + , m_backend(backend) { } -std::optional EglLayer::beginFrame() +std::optional EglLayer::doBeginFrame() { return m_backend->beginFrame(); } -bool EglLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) +bool EglLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) { m_backend->endFrame(renderedRegion, damagedRegion); return true; diff --git a/src/backends/x11/standalone/x11_standalone_egl_backend.h b/src/backends/x11/standalone/x11_standalone_egl_backend.h index f53484762e..b67cf89c54 100644 --- a/src/backends/x11/standalone/x11_standalone_egl_backend.h +++ b/src/backends/x11/standalone/x11_standalone_egl_backend.h @@ -35,8 +35,8 @@ class EglLayer : public OutputLayer public: EglLayer(EglBackend *backend); - std::optional beginFrame() override; - bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override; + std::optional doBeginFrame() override; + bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override; std::chrono::nanoseconds queryRenderTime() const override; DrmDevice *scanoutDevice() const override; QHash> supportedDrmFormats() const override; diff --git a/src/backends/x11/standalone/x11_standalone_glx_backend.cpp b/src/backends/x11/standalone/x11_standalone_glx_backend.cpp index 2b503e012a..a673cbb30e 100644 --- a/src/backends/x11/standalone/x11_standalone_glx_backend.cpp +++ b/src/backends/x11/standalone/x11_standalone_glx_backend.cpp @@ -99,16 +99,17 @@ bool SwapEventFilter::event(xcb_generic_event_t *event) } GlxLayer::GlxLayer(GlxBackend *backend) - : m_backend(backend) + : OutputLayer(nullptr) + , m_backend(backend) { } -std::optional GlxLayer::beginFrame() +std::optional GlxLayer::doBeginFrame() { - return m_backend->beginFrame(); + return m_backend->doBeginFrame(); } -bool GlxLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) +bool GlxLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) { m_backend->endFrame(renderedRegion, damagedRegion); return true; @@ -660,7 +661,7 @@ std::unique_ptr GlxBackend::createSurfaceTextureX11(SurfacePixma return std::make_unique(this, pixmap); } -OutputLayerBeginFrameInfo GlxBackend::beginFrame() +OutputLayerBeginFrameInfo GlxBackend::doBeginFrame() { QRegion repaint; makeCurrent(); diff --git a/src/backends/x11/standalone/x11_standalone_glx_backend.h b/src/backends/x11/standalone/x11_standalone_glx_backend.h index 0807bae4f8..31ef5ca4f1 100644 --- a/src/backends/x11/standalone/x11_standalone_glx_backend.h +++ b/src/backends/x11/standalone/x11_standalone_glx_backend.h @@ -63,8 +63,8 @@ class GlxLayer : public OutputLayer public: GlxLayer(GlxBackend *backend); - std::optional beginFrame() override; - bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override; + std::optional doBeginFrame() override; + bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override; std::chrono::nanoseconds queryRenderTime() const override; DrmDevice *scanoutDevice() const override; QHash> supportedDrmFormats() const override; @@ -84,7 +84,7 @@ public: GlxBackend(::Display *display, X11StandaloneBackend *backend); ~GlxBackend() override; std::unique_ptr createSurfaceTextureX11(SurfacePixmapX11 *pixmap) override; - OutputLayerBeginFrameInfo beginFrame(); + OutputLayerBeginFrameInfo doBeginFrame(); void endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion); std::chrono::nanoseconds queryRenderTime(); void present(Output *output, const std::shared_ptr &frame) override; diff --git a/src/backends/x11/windowed/x11_windowed_egl_backend.cpp b/src/backends/x11/windowed/x11_windowed_egl_backend.cpp index a11466313a..c84b01278c 100644 --- a/src/backends/x11/windowed/x11_windowed_egl_backend.cpp +++ b/src/backends/x11/windowed/x11_windowed_egl_backend.cpp @@ -22,7 +22,8 @@ namespace KWin { X11WindowedEglPrimaryLayer::X11WindowedEglPrimaryLayer(X11WindowedEglBackend *backend, X11WindowedOutput *output) - : m_output(output) + : OutputLayer(output) + , m_output(output) , m_backend(backend) { } @@ -31,7 +32,7 @@ X11WindowedEglPrimaryLayer::~X11WindowedEglPrimaryLayer() { } -std::optional X11WindowedEglPrimaryLayer::beginFrame() +std::optional X11WindowedEglPrimaryLayer::doBeginFrame() { if (!m_backend->openglContext()->makeCurrent()) { return std::nullopt; @@ -68,7 +69,7 @@ std::optional X11WindowedEglPrimaryLayer::beginFrame( }; } -bool X11WindowedEglPrimaryLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) +bool X11WindowedEglPrimaryLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) { m_query->end(); return true; @@ -129,7 +130,7 @@ QHash> X11WindowedEglPrimaryLayer::supportedDrmFormats } X11WindowedEglCursorLayer::X11WindowedEglCursorLayer(X11WindowedEglBackend *backend, X11WindowedOutput *output) - : m_output(output) + : OutputLayer(output) , m_backend(backend) { } @@ -141,13 +142,13 @@ X11WindowedEglCursorLayer::~X11WindowedEglCursorLayer() m_texture.reset(); } -std::optional X11WindowedEglCursorLayer::beginFrame() +std::optional X11WindowedEglCursorLayer::doBeginFrame() { if (!m_backend->openglContext()->makeCurrent()) { return std::nullopt; } - const auto tmp = size().expandedTo(QSize(64, 64)); + const auto tmp = targetRect().size().expandedTo(QSize(64, 64)); const QSize bufferSize(std::ceil(tmp.width()), std::ceil(tmp.height())); if (!m_texture || m_texture->size() != bufferSize) { m_texture = GLTexture::allocate(GL_RGBA8, bufferSize); @@ -166,7 +167,7 @@ std::optional X11WindowedEglCursorLayer::beginFrame() }; } -bool X11WindowedEglCursorLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) +bool X11WindowedEglCursorLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) { QImage buffer(m_framebuffer->size(), QImage::Format_RGBA8888_Premultiplied); @@ -174,7 +175,7 @@ bool X11WindowedEglCursorLayer::endFrame(const QRegion &renderedRegion, const QR glReadPixels(0, 0, buffer.width(), buffer.height(), GL_RGBA, GL_UNSIGNED_BYTE, buffer.bits()); GLFramebuffer::popFramebuffer(); - m_output->cursor()->update(buffer.mirrored(false, true), hotspot()); + static_cast(m_output)->cursor()->update(buffer.mirrored(false, true), hotspot()); m_query->end(); return true; diff --git a/src/backends/x11/windowed/x11_windowed_egl_backend.h b/src/backends/x11/windowed/x11_windowed_egl_backend.h index b901b258f3..684a7efd8a 100644 --- a/src/backends/x11/windowed/x11_windowed_egl_backend.h +++ b/src/backends/x11/windowed/x11_windowed_egl_backend.h @@ -28,8 +28,8 @@ public: X11WindowedEglPrimaryLayer(X11WindowedEglBackend *backend, X11WindowedOutput *output); ~X11WindowedEglPrimaryLayer() override; - std::optional beginFrame() override; - bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override; + std::optional doBeginFrame() override; + bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override; std::chrono::nanoseconds queryRenderTime() const override; DrmDevice *scanoutDevice() const override; QHash> supportedDrmFormats() const override; @@ -53,14 +53,13 @@ public: X11WindowedEglCursorLayer(X11WindowedEglBackend *backend, X11WindowedOutput *output); ~X11WindowedEglCursorLayer() override; - std::optional beginFrame() override; - bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override; + std::optional doBeginFrame() override; + bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override; std::chrono::nanoseconds queryRenderTime() const override; DrmDevice *scanoutDevice() const override; QHash> supportedDrmFormats() const override; private: - X11WindowedOutput *const m_output; X11WindowedEglBackend *const m_backend; std::unique_ptr m_framebuffer; std::unique_ptr m_texture; diff --git a/src/backends/x11/windowed/x11_windowed_qpainter_backend.cpp b/src/backends/x11/windowed/x11_windowed_qpainter_backend.cpp index 80200795fd..f2b712893d 100644 --- a/src/backends/x11/windowed/x11_windowed_qpainter_backend.cpp +++ b/src/backends/x11/windowed/x11_windowed_qpainter_backend.cpp @@ -23,7 +23,8 @@ namespace KWin { X11WindowedQPainterPrimaryLayer::X11WindowedQPainterPrimaryLayer(X11WindowedOutput *output, X11WindowedQPainterBackend *backend) - : m_output(output) + : OutputLayer(output) + , m_output(output) , m_backend(backend) { } @@ -32,7 +33,7 @@ X11WindowedQPainterPrimaryLayer::~X11WindowedQPainterPrimaryLayer() { } -std::optional X11WindowedQPainterPrimaryLayer::beginFrame() +std::optional X11WindowedQPainterPrimaryLayer::doBeginFrame() { const QSize bufferSize = m_output->modeSize(); if (!m_swapchain || m_swapchain->size() != bufferSize) { @@ -54,7 +55,7 @@ std::optional X11WindowedQPainterPrimaryLayer::beginF }; } -bool X11WindowedQPainterPrimaryLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) +bool X11WindowedQPainterPrimaryLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) { m_renderTime = std::chrono::steady_clock::now() - m_renderStart; return true; @@ -106,13 +107,14 @@ QHash> X11WindowedQPainterPrimaryLayer::supportedDrmFo } X11WindowedQPainterCursorLayer::X11WindowedQPainterCursorLayer(X11WindowedOutput *output) - : m_output(output) + : OutputLayer(output) + , m_output(output) { } -std::optional X11WindowedQPainterCursorLayer::beginFrame() +std::optional X11WindowedQPainterCursorLayer::doBeginFrame() { - const auto tmp = size().expandedTo(QSize(64, 64)); + const auto tmp = targetRect().size().expandedTo(QSize(64, 64)); const QSize bufferSize(std::ceil(tmp.width()), std::ceil(tmp.height())); if (m_buffer.size() != bufferSize) { m_buffer = QImage(bufferSize, QImage::Format_ARGB32_Premultiplied); @@ -130,7 +132,7 @@ std::chrono::nanoseconds X11WindowedQPainterCursorLayer::queryRenderTime() const return m_renderTime; } -bool X11WindowedQPainterCursorLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) +bool X11WindowedQPainterCursorLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) { m_renderTime = std::chrono::steady_clock::now() - m_renderStart; m_output->cursor()->update(m_buffer, hotspot()); diff --git a/src/backends/x11/windowed/x11_windowed_qpainter_backend.h b/src/backends/x11/windowed/x11_windowed_qpainter_backend.h index 6fb979682c..04e20367ab 100644 --- a/src/backends/x11/windowed/x11_windowed_qpainter_backend.h +++ b/src/backends/x11/windowed/x11_windowed_qpainter_backend.h @@ -34,8 +34,8 @@ public: X11WindowedQPainterPrimaryLayer(X11WindowedOutput *output, X11WindowedQPainterBackend *backend); ~X11WindowedQPainterPrimaryLayer() override; - std::optional beginFrame() override; - bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override; + std::optional doBeginFrame() override; + bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override; std::chrono::nanoseconds queryRenderTime() const override; DrmDevice *scanoutDevice() const override; QHash> supportedDrmFormats() const override; @@ -58,8 +58,8 @@ class X11WindowedQPainterCursorLayer : public OutputLayer public: explicit X11WindowedQPainterCursorLayer(X11WindowedOutput *output); - std::optional beginFrame() override; - bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override; + std::optional doBeginFrame() override; + bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override; std::chrono::nanoseconds queryRenderTime() const override; DrmDevice *scanoutDevice() const override; QHash> supportedDrmFormats() const override; diff --git a/src/compositor_wayland.cpp b/src/compositor_wayland.cpp index 5cb74763ca..5b7b8bbe29 100644 --- a/src/compositor_wayland.cpp +++ b/src/compositor_wayland.cpp @@ -256,6 +256,21 @@ void WaylandCompositor::stop() Q_EMIT compositingToggled(false); } +static QRect centerBuffer(const QSizeF &bufferSize, const QSize &modeSize) +{ + const double widthScale = bufferSize.width() / double(modeSize.width()); + const double heightScale = bufferSize.height() / double(modeSize.height()); + if (widthScale > heightScale) { + const QSize size = (bufferSize / widthScale).toSize(); + const uint32_t yOffset = (modeSize.height() - size.height()) / 2; + return QRect(QPoint(0, yOffset), size); + } else { + const QSize size = (bufferSize / heightScale).toSize(); + const uint32_t xOffset = (modeSize.width() - size.width()) / 2; + return QRect(QPoint(xOffset, 0), size); + } +} + void WaylandCompositor::composite(RenderLoop *renderLoop) { if (m_backend->checkGraphicsReset()) { @@ -305,6 +320,7 @@ void WaylandCompositor::composite(RenderLoop *renderLoop) return sublayer->isVisible(); }); if (scanoutPossible) { + primaryLayer->setTargetRect(centerBuffer(output->transform().map(scanoutCandidate->size()), output->modeSize())); directScanout = primaryLayer->attemptScanout(scanoutCandidate); } } else { @@ -312,6 +328,7 @@ void WaylandCompositor::composite(RenderLoop *renderLoop) } if (!directScanout) { + primaryLayer->setTargetRect(QRect(QPoint(0, 0), output->modeSize())); if (auto beginInfo = primaryLayer->beginFrame()) { auto &[renderTarget, repaint] = beginInfo.value(); @@ -392,9 +409,8 @@ void WaylandCompositor::addOutput(Output *output) bufferSize = *fixedSize; nativeCursorRect = output->transform().map(QRectF(outputLocalRect.topLeft() * output->scale(), bufferSize), output->pixelSize()); } - outputLayer->setPosition(nativeCursorRect.topLeft()); outputLayer->setHotspot(output->transform().map(cursor->hotspot() * output->scale(), bufferSize)); - outputLayer->setSize(bufferSize); + outputLayer->setTargetRect(QRect(nativeCursorRect.topLeft().toPoint(), bufferSize)); if (auto beginInfo = outputLayer->beginFrame()) { const RenderTarget &renderTarget = beginInfo->renderTarget; @@ -437,8 +453,8 @@ void WaylandCompositor::addOutput(Output *output) if (outputLayer) { if (outputLayer->isEnabled()) { const QRectF nativeCursorRect = output->transform() - .map(QRectF(outputLocalRect.topLeft() * output->scale(), outputLayer->size()), output->pixelSize()); - outputLayer->setPosition(nativeCursorRect.topLeft()); + .map(QRectF(outputLocalRect.topLeft() * output->scale(), outputLayer->targetRect().size()), output->pixelSize()); + outputLayer->setTargetRect(QRect(nativeCursorRect.topLeft().toPoint(), outputLayer->targetRect().size())); hardwareCursor = output->updateCursorLayer(); } else if (!cursorLayer->isVisible() && !forceSoftwareCursor) { // this is for the case that the cursor wasn't visible because it was on a different output before diff --git a/src/core/outputlayer.cpp b/src/core/outputlayer.cpp index f3a98bed61..8e27c9bafc 100644 --- a/src/core/outputlayer.cpp +++ b/src/core/outputlayer.cpp @@ -12,8 +12,8 @@ namespace KWin { -OutputLayer::OutputLayer(QObject *parent) - : QObject(parent) +OutputLayer::OutputLayer(Output *output) + : m_output(output) { } @@ -37,16 +37,6 @@ void OutputLayer::setHotspot(const QPointF &hotspot) m_hotspot = hotspot; } -QSizeF OutputLayer::size() const -{ - return m_size; -} - -void OutputLayer::setSize(const QSizeF &size) -{ - m_size = size; -} - std::optional OutputLayer::fixedSize() const { return std::nullopt; @@ -72,7 +62,7 @@ bool OutputLayer::needsRepaint() const return !m_repaints.isEmpty(); } -bool OutputLayer::doAttemptScanout(GraphicsBuffer *buffer, const QRectF &sourceRect, const QSizeF &targetSize, OutputTransform transform, const ColorDescription &color) +bool OutputLayer::doAttemptScanout(GraphicsBuffer *buffer, const ColorDescription &color) { return false; } @@ -97,7 +87,11 @@ bool OutputLayer::attemptScanout(SurfaceItem *surfaceItem) surfaceItem->setScanoutHint(scanoutDevice(), supportedDrmFormats()); return false; } - const bool ret = doAttemptScanout(buffer, surfaceItem->bufferSourceBox(), surfaceItem->destinationSize(), surfaceItem->bufferTransform(), surfaceItem->colorDescription()); + m_sourceRect = surfaceItem->bufferSourceBox(); + m_bufferTransform = surfaceItem->bufferTransform(); + const auto desiredTransform = m_output ? m_output->transform() : OutputTransform::Kind::Normal; + m_offloadTransform = m_bufferTransform.combine(desiredTransform.inverted()); + const bool ret = doAttemptScanout(buffer, surfaceItem->colorDescription()); if (ret) { surfaceItem->resetDamage(); // ensure the pixmap is updated when direct scanout ends @@ -106,6 +100,19 @@ bool OutputLayer::attemptScanout(SurfaceItem *surfaceItem) return ret; } +std::optional OutputLayer::beginFrame() +{ + m_sourceRect = QRectF(QPointF(0, 0), m_targetRect.size()); + m_bufferTransform = m_output ? m_output->transform() : OutputTransform::Kind::Normal; + m_offloadTransform = OutputTransform::Kind::Normal; + return doBeginFrame(); +} + +bool OutputLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) +{ + return doEndFrame(renderedRegion, damagedRegion); +} + void OutputLayer::notifyNoScanoutCandidate() { if (m_scanoutCandidate) { @@ -114,16 +121,6 @@ void OutputLayer::notifyNoScanoutCandidate() } } -void OutputLayer::setPosition(const QPointF &position) -{ - m_position = position; -} - -QPointF OutputLayer::position() const -{ - return m_position; -} - void OutputLayer::setEnabled(bool enable) { m_enabled = enable; @@ -134,6 +131,36 @@ bool OutputLayer::isEnabled() const return m_enabled; } +QRectF OutputLayer::sourceRect() const +{ + return m_sourceRect; +} + +void OutputLayer::setSourceRect(const QRectF &rect) +{ + m_sourceRect = rect; +} + +OutputTransform OutputLayer::offloadTransform() const +{ + return m_offloadTransform; +} + +OutputTransform OutputLayer::bufferTransform() const +{ + return m_bufferTransform; +} + +QRect OutputLayer::targetRect() const +{ + return m_targetRect; +} + +void OutputLayer::setTargetRect(const QRect &rect) +{ + m_targetRect = rect; +} + } // namespace KWin #include "moc_outputlayer.cpp" diff --git a/src/core/outputlayer.h b/src/core/outputlayer.h index f681b2ca5b..3f0b5d0056 100644 --- a/src/core/outputlayer.h +++ b/src/core/outputlayer.h @@ -32,7 +32,7 @@ class KWIN_EXPORT OutputLayer : public QObject { Q_OBJECT public: - explicit OutputLayer(QObject *parent = nullptr); + explicit OutputLayer(Output *output); qreal scale() const; void setScale(qreal scale); @@ -40,8 +40,6 @@ public: QPointF hotspot() const; void setHotspot(const QPointF &hotspot); - QSizeF size() const; - void setSize(const QSizeF &size); /** * For most drm drivers, the buffer used for the cursor has to have a fixed size. * If such a fixed size is required by the backend, this function should return it @@ -53,20 +51,14 @@ public: void addRepaint(const QRegion ®ion); bool needsRepaint() const; - /** - * @arg position in device coordinates - */ - void setPosition(const QPointF &position); - QPointF position() const; - /** * Enables or disables this layer. Note that disabling the primary layer will cause problems */ void setEnabled(bool enable); bool isEnabled() const; - virtual std::optional beginFrame() = 0; - virtual bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) = 0; + std::optional beginFrame(); + bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion); /** * Tries to import the newest buffer of the surface for direct scanout @@ -87,16 +79,40 @@ public: virtual DrmDevice *scanoutDevice() const = 0; virtual QHash> supportedDrmFormats() const = 0; + /** + * Returns the source rect this output layer should sample from, in buffer local coordinates + */ + QRectF sourceRect() const; + void setSourceRect(const QRectF &rect); + /** + * Returns the target rect this output layer should be shown at, in device coordinates + */ + QRect targetRect() const; + void setTargetRect(const QRect &rect); + /** + * Returns the transform this layer will apply to content passed to it + */ + OutputTransform offloadTransform() const; + /** + * Returns the transform a buffer passed into this layer already has + */ + OutputTransform bufferTransform() const; + protected: - virtual bool doAttemptScanout(GraphicsBuffer *buffer, const QRectF &sourceRect, const QSizeF &targetSize, OutputTransform transform, const ColorDescription &color); + virtual bool doAttemptScanout(GraphicsBuffer *buffer, const ColorDescription &color); + virtual std::optional doBeginFrame() = 0; + virtual bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) = 0; QRegion m_repaints; QPointF m_hotspot; - QPointF m_position; - QSizeF m_size; + QRectF m_sourceRect; + QRect m_targetRect; qreal m_scale = 1.0; bool m_enabled = false; + OutputTransform m_offloadTransform = OutputTransform::Kind::Normal; + OutputTransform m_bufferTransform = OutputTransform::Kind::Normal; QPointer m_scanoutCandidate; + Output *const m_output; }; } // namespace KWin