From a04bdf235598d68e065e1697648027ffd7883147 Mon Sep 17 00:00:00 2001 From: Xaver Hugl Date: Sun, 13 Feb 2022 17:49:13 +0100 Subject: [PATCH] backends/drm: port DrmPipeline and DrmGpu to use layers Instead of having the render backends manage layers, have DrmGpu and DrmPipeline do it. This makes it possible to unify code paths for leased and normal outputs, remove some redirection and have more freedom with assigning layers to screens. --- src/backends/drm/drm_abstract_output.cpp | 11 ++ src/backends/drm/drm_abstract_output.h | 2 + src/backends/drm/drm_display_device.h | 8 +- src/backends/drm/drm_gpu.cpp | 24 ++-- src/backends/drm/drm_gpu.h | 6 +- src/backends/drm/drm_layer.h | 3 + src/backends/drm/drm_lease_output.cpp | 25 +++- src/backends/drm/drm_lease_output.h | 6 +- src/backends/drm/drm_output.cpp | 37 +++--- src/backends/drm/drm_output.h | 7 +- src/backends/drm/drm_pipeline.cpp | 115 ++++++------------ src/backends/drm/drm_pipeline.h | 16 +-- src/backends/drm/drm_pipeline_legacy.cpp | 18 +-- src/backends/drm/drm_qpainter_layer.cpp | 11 ++ src/backends/drm/drm_qpainter_layer.h | 3 + src/backends/drm/drm_render_backend.h | 28 +++++ src/backends/drm/drm_virtual_output.cpp | 22 +++- src/backends/drm/drm_virtual_output.h | 7 +- src/backends/drm/egl_gbm_backend.cpp | 60 ++++----- src/backends/drm/egl_gbm_backend.h | 13 +- src/backends/drm/egl_gbm_layer.cpp | 33 ++++- src/backends/drm/egl_gbm_layer.h | 4 + .../drm/scene_qpainter_drm_backend.cpp | 28 +++-- src/backends/drm/scene_qpainter_drm_backend.h | 14 +-- 24 files changed, 295 insertions(+), 206 deletions(-) create mode 100644 src/backends/drm/drm_render_backend.h diff --git a/src/backends/drm/drm_abstract_output.cpp b/src/backends/drm/drm_abstract_output.cpp index 5d25cd29cb..1c3e8f0f71 100644 --- a/src/backends/drm/drm_abstract_output.cpp +++ b/src/backends/drm/drm_abstract_output.cpp @@ -9,6 +9,7 @@ #include "drm_abstract_output.h" #include "drm_gpu.h" #include "drm_backend.h" +#include "renderloop_p.h" namespace KWin { @@ -30,4 +31,14 @@ QRect DrmAbstractOutput::renderGeometry() const return geometry(); } +void DrmAbstractOutput::frameFailed() const +{ + RenderLoopPrivate::get(m_renderLoop)->notifyFrameFailed(); +} + +void DrmAbstractOutput::pageFlipped(std::chrono::nanoseconds timestamp) const +{ + RenderLoopPrivate::get(m_renderLoop)->notifyFrameCompleted(timestamp); +} + } diff --git a/src/backends/drm/drm_abstract_output.h b/src/backends/drm/drm_abstract_output.h index 3de990c619..f4b8b4c5c5 100644 --- a/src/backends/drm/drm_abstract_output.h +++ b/src/backends/drm/drm_abstract_output.h @@ -24,6 +24,8 @@ public: RenderLoop *renderLoop() const override; QRect renderGeometry() const override; + void frameFailed() const override; + void pageFlipped(std::chrono::nanoseconds timestamp) const override; protected: friend class DrmGpu; diff --git a/src/backends/drm/drm_display_device.h b/src/backends/drm/drm_display_device.h index 29a8d160b4..a974012312 100644 --- a/src/backends/drm/drm_display_device.h +++ b/src/backends/drm/drm_display_device.h @@ -17,6 +17,7 @@ namespace KWin class DrmBuffer; class DrmGpu; +class DrmLayer; class DrmDisplayDevice { @@ -26,7 +27,11 @@ public: DrmGpu *gpu() const; - virtual bool present(const QSharedPointer &buffer, QRegion damagedRegion) = 0; + virtual bool present() = 0; + virtual bool testScanout() = 0; + virtual void frameFailed() const = 0; + virtual void pageFlipped(std::chrono::nanoseconds timestamp) const = 0; + virtual DrmPlane::Transformations softwareTransforms() const = 0; virtual QSize bufferSize() const = 0; virtual QSize sourceSize() const = 0; @@ -34,6 +39,7 @@ public: virtual QVector supportedModifiers(uint32_t drmFormat) const = 0; virtual int maxBpc() const = 0; virtual QRect renderGeometry() const = 0; + virtual DrmLayer *outputLayer() const = 0; protected: DrmGpu *const m_gpu; diff --git a/src/backends/drm/drm_gpu.cpp b/src/backends/drm/drm_gpu.cpp index 01f9e88453..183b700986 100644 --- a/src/backends/drm/drm_gpu.cpp +++ b/src/backends/drm/drm_gpu.cpp @@ -309,9 +309,9 @@ bool DrmGpu::updateOutputs() if (testPendingConfiguration()) { for (const auto &pipeline : qAsConst(m_pipelines)) { pipeline->applyPendingChanges(); - if (!pipeline->pending.crtc && pipeline->output()) { + if (const auto drmOutput = dynamic_cast(pipeline->displayDevice()); drmOutput && !pipeline->pending.crtc) { pipeline->pending.enabled = false; - pipeline->output()->setEnabled(false); + drmOutput->setEnabled(false); } } } else { @@ -421,6 +421,9 @@ bool DrmGpu::testPipelines() // pipelines that are enabled but not active need to be activated for the test QVector inactivePipelines; for (const auto &pipeline : qAsConst(m_pipelines)) { + if (!pipeline->pending.layer) { + pipeline->pending.layer = m_renderBackend->createLayer(pipeline->displayDevice()); + } if (!pipeline->pending.active) { pipeline->pending.active = true; inactivePipelines << pipeline; @@ -553,6 +556,7 @@ void DrmGpu::removeOutput(DrmOutput *output) qCDebug(KWIN_DRM) << "Removing output" << output; m_drmOutputs.removeOne(output); m_pipelines.removeOne(output->pipeline()); + output->pipeline()->pending.layer.reset(); m_outputs.removeOne(output); Q_EMIT outputRemoved(output); delete output; @@ -560,12 +564,17 @@ void DrmGpu::removeOutput(DrmOutput *output) EglGbmBackend *DrmGpu::eglBackend() const { - return m_eglBackend; + return dynamic_cast(m_renderBackend); } -void DrmGpu::setEglBackend(EglGbmBackend *eglBackend) +DrmRenderBackend *DrmGpu::renderBackend() const { - m_eglBackend = eglBackend; + return m_renderBackend; +} + +void DrmGpu::setRenderBackend(DrmRenderBackend *backend) +{ + m_renderBackend = backend; } DrmBackend *DrmGpu::platform() const { @@ -661,6 +670,7 @@ void DrmGpu::removeLeaseOutput(DrmLeaseOutput *output) qCDebug(KWIN_DRM) << "Removing leased output" << output; m_leaseOutputs.removeOne(output); m_pipelines.removeOne(output->pipeline()); + output->pipeline()->pending.layer.reset(); delete output; } @@ -740,10 +750,10 @@ bool DrmGpu::maybeModeset() } const bool ok = DrmPipeline::commitPipelines(pipelines, DrmPipeline::CommitMode::CommitModeset, unusedObjects()); for (DrmPipeline *pipeline : qAsConst(pipelines)) { - if (pipeline->modesetPresentPending() && pipeline->output()) { + if (pipeline->modesetPresentPending()) { pipeline->resetModesetPresentPending(); if (!ok) { - pipeline->output()->presentFailed(); + pipeline->displayDevice()->frameFailed(); } } } diff --git a/src/backends/drm/drm_gpu.h b/src/backends/drm/drm_gpu.h index 9a065d7699..48f06993e0 100644 --- a/src/backends/drm/drm_gpu.h +++ b/src/backends/drm/drm_gpu.h @@ -41,6 +41,7 @@ class DrmPipeline; class DrmAbstractOutput; class DrmVirtualOutput; class DrmLeaseOutput; +class DrmRenderBackend; class DrmGpu : public QObject { @@ -59,6 +60,7 @@ public: gbm_device *gbmDevice() const; EGLDisplay eglDisplay() const; EglGbmBackend *eglBackend() const; + DrmRenderBackend *renderBackend() const; DrmBackend *platform() const; /** * Returns the clock from which presentation timestamps are sourced. The returned value @@ -71,7 +73,7 @@ public: const QVector pipelines() const; void setEglDisplay(EGLDisplay display); - void setEglBackend(EglGbmBackend *eglBackend); + void setRenderBackend(DrmRenderBackend *backend); bool updateOutputs(); @@ -120,7 +122,7 @@ private: clockid_t m_presentationClock; gbm_device* m_gbmDevice; EGLDisplay m_eglDisplay = EGL_NO_DISPLAY; - QPointer m_eglBackend; + DrmRenderBackend *m_renderBackend; DrmBackend* const m_platform; QVector m_planes; diff --git a/src/backends/drm/drm_layer.h b/src/backends/drm/drm_layer.h index f1f7c69333..5dd0e0c68e 100644 --- a/src/backends/drm/drm_layer.h +++ b/src/backends/drm/drm_layer.h @@ -41,6 +41,9 @@ public: virtual QSharedPointer testBuffer() = 0; virtual QSharedPointer currentBuffer() const = 0; + virtual QRegion currentDamage() const = 0; + virtual bool hasDirectScanoutBuffer() const = 0; + virtual DrmDisplayDevice *displayDevice() const = 0; }; diff --git a/src/backends/drm/drm_lease_output.cpp b/src/backends/drm/drm_lease_output.cpp index 455f562211..ed7c80125b 100644 --- a/src/backends/drm/drm_lease_output.cpp +++ b/src/backends/drm/drm_lease_output.cpp @@ -32,11 +32,13 @@ DrmLeaseOutput::DrmLeaseOutput(DrmPipeline *pipeline, KWaylandServer::DrmLeaseDe , DrmDisplayDevice(pipeline->gpu()) , m_pipeline(pipeline) { + m_pipeline->setDisplayDevice(this); qCDebug(KWIN_DRM) << "offering connector" << m_pipeline->connector()->id() << "for lease"; } DrmLeaseOutput::~DrmLeaseOutput() { + m_pipeline->setDisplayDevice(nullptr); qCDebug(KWIN_DRM) << "revoking lease offer for connector" << m_pipeline->connector()->id(); } @@ -76,10 +78,13 @@ DrmPipeline *DrmLeaseOutput::pipeline() const return m_pipeline; } -bool DrmLeaseOutput::present(const QSharedPointer &buffer, QRegion damagedRegion) +bool DrmLeaseOutput::present() +{ + return false; +} + +bool DrmLeaseOutput::testScanout() { - Q_UNUSED(buffer) - Q_UNUSED(damagedRegion) return false; } @@ -122,4 +127,18 @@ QRect DrmLeaseOutput::renderGeometry() const return QRect(QPoint(), m_pipeline->sourceSize()); } +DrmLayer *DrmLeaseOutput::outputLayer() const +{ + return m_pipeline->pending.layer.data(); +} + +void DrmLeaseOutput::frameFailed() const +{ +} + +void DrmLeaseOutput::pageFlipped(std::chrono::nanoseconds timestamp) const +{ + Q_UNUSED(timestamp) +} + } diff --git a/src/backends/drm/drm_lease_output.h b/src/backends/drm/drm_lease_output.h index bd8d1cc847..90a6099d02 100644 --- a/src/backends/drm/drm_lease_output.h +++ b/src/backends/drm/drm_lease_output.h @@ -40,7 +40,7 @@ public: KWaylandServer::DrmLeaseV1Interface *lease() const; DrmPipeline *pipeline() const; - bool present(const QSharedPointer &buffer, QRegion damagedRegion) override; + bool present() override; DrmPlane::Transformations softwareTransforms() const override; QSize bufferSize() const override; QSize sourceSize() const override; @@ -48,6 +48,10 @@ public: QVector supportedModifiers(uint32_t drmFormat) const override; int maxBpc() const override; QRect renderGeometry() const override; + DrmLayer *outputLayer() const override; + bool testScanout() override; + void frameFailed() const override; + void pageFlipped(std::chrono::nanoseconds timestamp) const override; private: DrmPipeline *m_pipeline; diff --git a/src/backends/drm/drm_output.cpp b/src/backends/drm/drm_output.cpp index e8b9458b41..662e25ab88 100644 --- a/src/backends/drm/drm_output.cpp +++ b/src/backends/drm/drm_output.cpp @@ -26,6 +26,7 @@ #include "waylandoutputconfig.h" #include "dumb_swapchain.h" #include "cursor.h" +#include "drm_layer.h" // Qt #include #include @@ -45,7 +46,7 @@ DrmOutput::DrmOutput(DrmPipeline *pipeline) , m_pipeline(pipeline) , m_connector(pipeline->connector()) { - m_pipeline->setOutput(this); + m_pipeline->setDisplayDevice(this); const auto conn = m_pipeline->connector(); m_renderLoop->setRefreshRate(m_pipeline->pending.mode->refreshRate()); setSubPixelInternal(conn->subpixel()); @@ -78,7 +79,7 @@ DrmOutput::DrmOutput(DrmPipeline *pipeline) DrmOutput::~DrmOutput() { - m_pipeline->setOutput(nullptr); + m_pipeline->setDisplayDevice(nullptr); } static bool isCursorSpriteCompatible(const QImage *buffer, const QImage *sprite) @@ -318,12 +319,8 @@ void DrmOutput::updateModes() } } -bool DrmOutput::present(const QSharedPointer &buffer, QRegion damagedRegion) +bool DrmOutput::present() { - if (!buffer || buffer->bufferId() == 0) { - presentFailed(); - return false; - } RenderLoopPrivate *renderLoopPrivate = RenderLoopPrivate::get(m_renderLoop); if (m_pipeline->pending.syncMode != renderLoopPrivate->presentMode) { m_pipeline->pending.syncMode = renderLoopPrivate->presentMode; @@ -334,14 +331,21 @@ bool DrmOutput::present(const QSharedPointer &buffer, QRegion damaged setVrrPolicy(RenderLoop::VrrPolicy::Never); } } - if (m_pipeline->present(buffer)) { - Q_EMIT outputChange(damagedRegion); + if (m_pipeline->present()) { + Q_EMIT outputChange(m_pipeline->pending.layer->currentDamage()); return true; } else { + qCWarning(KWIN_DRM) << "Presentation failed!" << strerror(errno); + frameFailed(); return false; } } +bool DrmOutput::testScanout() +{ + return m_pipeline->testScanout(); +} + int DrmOutput::gammaRampSize() const { return m_pipeline->pending.crtc ? m_pipeline->pending.crtc->gammaRampSize() : 256; @@ -446,16 +450,6 @@ void DrmOutput::revertQueuedChanges() m_pipeline->revertPendingChanges(); } -void DrmOutput::pageFlipped(std::chrono::nanoseconds timestamp) -{ - RenderLoopPrivate::get(m_renderLoop)->notifyFrameCompleted(timestamp); -} - -void DrmOutput::presentFailed() -{ - RenderLoopPrivate::get(m_renderLoop)->notifyFrameFailed(); -} - int DrmOutput::maxBpc() const { auto prop = m_connector->getProp(DrmConnector::PropertyIndex::MaxBpc); @@ -477,4 +471,9 @@ DrmPlane::Transformations DrmOutput::softwareTransforms() const } } +DrmLayer *DrmOutput::outputLayer() const +{ + return m_pipeline->pending.layer.data(); +} + } diff --git a/src/backends/drm/drm_output.h b/src/backends/drm/drm_output.h index cf30ec2afd..46bc9fab36 100644 --- a/src/backends/drm/drm_output.h +++ b/src/backends/drm/drm_output.h @@ -43,25 +43,24 @@ public: DrmOutput(DrmPipeline *pipeline); ~DrmOutput() override; - bool present(const QSharedPointer &buffer, QRegion damagedRegion) override; - DrmConnector *connector() const; DrmPipeline *pipeline() const; + bool present() override; + bool testScanout() override; QSize bufferSize() const override; QSize sourceSize() const override; bool isFormatSupported(uint32_t drmFormat) const override; QVector supportedModifiers(uint32_t drmFormat) const override; DrmPlane::Transformations softwareTransforms() const override; int maxBpc() const override; + DrmLayer *outputLayer() const override; bool queueChanges(const WaylandOutputConfig &config); void applyQueuedChanges(const WaylandOutputConfig &config); void revertQueuedChanges(); void updateModes(); - void pageFlipped(std::chrono::nanoseconds timestamp); - void presentFailed(); bool usesSoftwareCursor() const override; private: diff --git a/src/backends/drm/drm_pipeline.cpp b/src/backends/drm/drm_pipeline.cpp index 115f424017..d40d6556de 100644 --- a/src/backends/drm/drm_pipeline.cpp +++ b/src/backends/drm/drm_pipeline.cpp @@ -23,6 +23,7 @@ #include "drm_backend.h" #include "egl_gbm_backend.h" #include "drm_buffer_gbm.h" +#include "drm_layer.h" #include #include @@ -31,30 +32,37 @@ namespace KWin { DrmPipeline::DrmPipeline(DrmConnector *conn) - : m_output(nullptr) + : m_displayDevice(nullptr) , m_connector(conn) { } DrmPipeline::~DrmPipeline() { - m_output = nullptr; if (m_pageflipPending && m_current.crtc) { pageFlipped({}); } } -bool DrmPipeline::present(const QSharedPointer &buffer) +bool DrmPipeline::testScanout() +{ + // TODO make the modeset check only be tested at most once per scanout cycle + if (gpu()->needsModeset()) { + return false; + } + if (gpu()->atomicModeSetting()) { + return commitPipelines({this}, CommitMode::Test); + } else { + // no other way to test than to do it. + // As we only have a maximum of one test per scanout cycle, this is fine + return presentLegacy(); + } +} + +bool DrmPipeline::present() { Q_ASSERT(pending.crtc); - Q_ASSERT(buffer); - m_primaryBuffer = buffer; - // with direct scanout disallow modesets, calling presentFailed() and logging warnings - const bool directScanout = isBufferForDirectScanout(); if (gpu()->needsModeset()) { - if (directScanout) { - return false; - } m_modesetPresentPending = true; return gpu()->maybeModeset(); } @@ -72,35 +80,22 @@ bool DrmPipeline::present(const QSharedPointer &buffer) } } if (!commitPipelines({this}, CommitMode::Commit)) { - if (directScanout) { - return false; - } - qCWarning(KWIN_DRM) << "Atomic present failed!" << strerror(errno); printDebugInfo(); - if (m_output) { - m_output->presentFailed(); - } return false; } } } else { + if (pending.layer->hasDirectScanoutBuffer()) { + // already presented + return true; + } if (!presentLegacy()) { - qCWarning(KWIN_DRM) << "Present failed!" << strerror(errno); - if (m_output) { - m_output->presentFailed(); - } return false; } } return true; } -bool DrmPipeline::isBufferForDirectScanout() const -{ - const auto buf = dynamic_cast(m_primaryBuffer.data()); - return buf && buf->clientBuffer(); -} - bool DrmPipeline::commitPipelines(const QVector &pipelines, CommitMode mode, const QVector &unusedObjects) { Q_ASSERT(!pipelines.isEmpty()); @@ -133,7 +128,7 @@ bool DrmPipeline::commitPipelinesAtomic(const QVector &pipelines, return false; }; for (const auto &pipeline : pipelines) { - if (!pipeline->checkTestBuffer()) { + if (!pipeline->pending.layer->testBuffer()) { qCWarning(KWIN_DRM) << "Checking test buffer failed for" << mode; return failed(); } @@ -197,8 +192,9 @@ bool DrmPipeline::populateAtomicValues(drmModeAtomicReq *req, uint32_t &flags) pending.crtc->setPending(DrmCrtc::PropertyIndex::VrrEnabled, pending.syncMode == RenderLoopPrivate::SyncMode::Adaptive); pending.crtc->setPending(DrmCrtc::PropertyIndex::Gamma_LUT, pending.gamma ? pending.gamma->blobId() : 0); const auto modeSize = pending.mode->size(); - pending.crtc->primaryPlane()->set(QPoint(0, 0), m_primaryBuffer ? m_primaryBuffer->size() : bufferSize(), QPoint(0, 0), modeSize); - pending.crtc->primaryPlane()->setBuffer(activePending() ? m_primaryBuffer.get() : nullptr); + const auto buffer = pending.layer->currentBuffer().data(); + pending.crtc->primaryPlane()->set(QPoint(0, 0), buffer ? buffer->size() : bufferSize(), QPoint(0, 0), modeSize); + pending.crtc->primaryPlane()->setBuffer(activePending() ? buffer : nullptr); if (pending.crtc->cursorPlane()) { pending.crtc->cursorPlane()->set(QPoint(0, 0), gpu()->cursorSize(), pending.cursorPos, gpu()->cursorSize()); @@ -271,10 +267,6 @@ uint32_t DrmPipeline::calculateUnderscan() void DrmPipeline::atomicCommitFailed() { - if (m_oldTestBuffer) { - m_primaryBuffer = m_oldTestBuffer; - m_oldTestBuffer = nullptr; - } m_connector->rollbackPending(); if (pending.crtc) { pending.crtc->rollbackPending(); @@ -287,7 +279,6 @@ void DrmPipeline::atomicCommitFailed() void DrmPipeline::atomicCommitSuccessful(CommitMode mode) { - m_oldTestBuffer = nullptr; m_connector->commitPending(); if (pending.crtc) { pending.crtc->commitPending(); @@ -303,7 +294,7 @@ void DrmPipeline::atomicCommitSuccessful(CommitMode mode) m_connector->commit(); if (pending.crtc) { pending.crtc->commit(); - pending.crtc->primaryPlane()->setNext(m_primaryBuffer); + pending.crtc->primaryPlane()->setNext(pending.layer->currentBuffer()); pending.crtc->primaryPlane()->commit(); if (pending.crtc->cursorPlane()) { pending.crtc->cursorPlane()->setNext(pending.cursorBo); @@ -317,32 +308,6 @@ void DrmPipeline::atomicCommitSuccessful(CommitMode mode) } } -bool DrmPipeline::checkTestBuffer() -{ - const auto backend = gpu()->eglBackend(); - if (!pending.crtc || (!(backend && m_output) && m_primaryBuffer && m_primaryBuffer->size() == bufferSize()) || isBufferForDirectScanout()) { - return true; - } - QSharedPointer buffer; - if (backend && m_output) { - buffer = backend->testBuffer(m_output); - } else if (backend && gpu()->gbmDevice()) { - gbm_bo *bo = gbm_bo_create(gpu()->gbmDevice(), bufferSize().width(), bufferSize().height(), DRM_FORMAT_XRGB8888, GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING); - if (!bo) { - return false; - } - buffer = QSharedPointer::create(gpu(), bo, nullptr); - } else { - buffer = QSharedPointer::create(gpu(), bufferSize(), DRM_FORMAT_XRGB8888); - } - if (buffer && buffer->bufferId()) { - m_oldTestBuffer = m_primaryBuffer; - m_primaryBuffer = buffer; - return true; - } - return false; -} - bool DrmPipeline::setCursor(const QSharedPointer &buffer, const QPoint &hotspot) { if (pending.cursorBo == buffer && pending.cursorHotspot == hotspot) { @@ -360,8 +325,8 @@ bool DrmPipeline::setCursor(const QSharedPointer &buffer, const Q } if (result) { m_next = pending; - if (m_output && (visibleBefore || isCursorVisible())) { - m_output->renderLoop()->scheduleRepaint(); + if (const auto drmOutput = dynamic_cast(m_displayDevice); drmOutput && (visibleBefore || isCursorVisible())) { + drmOutput->renderLoop()->scheduleRepaint(); } } else { pending = m_next; @@ -385,8 +350,8 @@ bool DrmPipeline::moveCursor(QPoint pos) } if (result) { m_next = pending; - if (m_output && (visibleBefore || isCursorVisible())) { - m_output->renderLoop()->scheduleRepaint(); + if (const auto drmOutput = dynamic_cast(m_displayDevice); drmOutput && (visibleBefore || isCursorVisible())) { + drmOutput->renderLoop()->scheduleRepaint(); } } else { pending = m_next; @@ -446,19 +411,12 @@ void DrmPipeline::pageFlipped(std::chrono::nanoseconds timestamp) m_current.crtc->cursorPlane()->flipBuffer(); } m_pageflipPending = false; - if (m_output) { - m_output->pageFlipped(timestamp); - } + m_displayDevice->pageFlipped(timestamp); } -void DrmPipeline::setOutput(DrmOutput *output) +void DrmPipeline::setDisplayDevice(DrmDisplayDevice *device) { - m_output = output; -} - -DrmOutput *DrmPipeline::output() const -{ - return m_output; + m_displayDevice = device; } static const QMap> legacyFormats = { @@ -541,6 +499,11 @@ DrmCrtc *DrmPipeline::currentCrtc() const return m_current.crtc; } +DrmDisplayDevice *DrmPipeline::displayDevice() const +{ + return m_displayDevice; +} + DrmGammaRamp::DrmGammaRamp(DrmGpu *gpu, const GammaRamp &lut) : m_gpu(gpu) , m_lut(lut) diff --git a/src/backends/drm/drm_pipeline.h b/src/backends/drm/drm_pipeline.h index ecc30e8164..11fda35849 100644 --- a/src/backends/drm/drm_pipeline.h +++ b/src/backends/drm/drm_pipeline.h @@ -31,6 +31,8 @@ class DrmBuffer; class DrmDumbBuffer; class GammaRamp; class DrmConnectorMode; +class DrmLayer; +class DrmDisplayDevice; class DrmGammaRamp { @@ -60,7 +62,8 @@ public: * tests the pending commit first and commits it if the test passes * if the test fails, there is a guarantee for no lasting changes */ - bool present(const QSharedPointer &buffer); + bool present(); + bool testScanout(); bool needsModeset() const; void applyPendingChanges(); @@ -91,8 +94,8 @@ public: QVector supportedModifiers(uint32_t drmFormat) const; QMap> supportedFormats() const; - void setOutput(DrmOutput *output); - DrmOutput *output() const; + void setDisplayDevice(DrmDisplayDevice *device); + DrmDisplayDevice *displayDevice() const; struct State { DrmCrtc *crtc = nullptr; @@ -104,6 +107,8 @@ public: RenderLoopPrivate::SyncMode syncMode = RenderLoopPrivate::SyncMode::Fixed; QSharedPointer gamma; + QSharedPointer layer; + QPoint cursorPos; QPoint cursorHotspot; QSharedPointer cursorBo; @@ -124,7 +129,6 @@ public: static bool commitPipelines(const QVector &pipelines, CommitMode mode, const QVector &unusedObjects = {}); private: - bool checkTestBuffer(); bool activePending() const; bool isCursorVisible() const; bool isBufferForDirectScanout() const; @@ -150,11 +154,9 @@ private: static void printFlags(uint32_t flags); static void printProps(DrmObject *object, PrintMode mode); - DrmOutput *m_output = nullptr; + DrmDisplayDevice *m_displayDevice = nullptr; DrmConnector *m_connector = nullptr; - QSharedPointer m_primaryBuffer; - QSharedPointer m_oldTestBuffer; bool m_pageflipPending = false; bool m_modesetPresentPending = false; diff --git a/src/backends/drm/drm_pipeline_legacy.cpp b/src/backends/drm/drm_pipeline_legacy.cpp index d77d13ca49..2b5f1c19eb 100644 --- a/src/backends/drm/drm_pipeline_legacy.cpp +++ b/src/backends/drm/drm_pipeline_legacy.cpp @@ -13,6 +13,7 @@ #include "drm_object_crtc.h" #include "drm_object_connector.h" #include "logging.h" +#include "drm_layer.h" #include @@ -21,33 +22,32 @@ namespace KWin bool DrmPipeline::presentLegacy() { - if ((!pending.crtc->current() || pending.crtc->current()->needsModeChange(m_primaryBuffer.get())) && !legacyModeset()) { + const auto buffer = pending.layer->currentBuffer(); + if ((!pending.crtc->current() || pending.crtc->current()->needsModeChange(buffer.get())) && !legacyModeset()) { return false; } - if (drmModePageFlip(gpu()->fd(), pending.crtc->id(), m_primaryBuffer ? m_primaryBuffer->bufferId() : 0, DRM_MODE_PAGE_FLIP_EVENT, nullptr) != 0) { - qCWarning(KWIN_DRM) << "Page flip failed:" << strerror(errno) << m_primaryBuffer; + if (drmModePageFlip(gpu()->fd(), pending.crtc->id(), buffer ? buffer->bufferId() : 0, DRM_MODE_PAGE_FLIP_EVENT, nullptr) != 0) { + qCWarning(KWIN_DRM) << "Page flip failed:" << strerror(errno) << buffer; return false; } m_pageflipPending = true; - pending.crtc->setNext(m_primaryBuffer); + pending.crtc->setNext(buffer); return true; } bool DrmPipeline::legacyModeset() { uint32_t connId = m_connector->id(); - if (!checkTestBuffer() || drmModeSetCrtc(gpu()->fd(), pending.crtc->id(), m_primaryBuffer->bufferId(), 0, 0, &connId, 1, pending.mode->nativeMode()) != 0) { + if (!pending.layer->testBuffer() || drmModeSetCrtc(gpu()->fd(), pending.crtc->id(), pending.layer->currentBuffer()->bufferId(), 0, 0, &connId, 1, pending.mode->nativeMode()) != 0) { qCWarning(KWIN_DRM) << "Modeset failed!" << strerror(errno); pending = m_next; - m_primaryBuffer = m_oldTestBuffer; return false; } - m_oldTestBuffer = nullptr; // make sure the buffer gets kept alive, or the modeset gets reverted by the kernel if (pending.crtc->current()) { - pending.crtc->setNext(m_primaryBuffer); + pending.crtc->setNext(pending.layer->currentBuffer()); } else { - pending.crtc->setCurrent(m_primaryBuffer); + pending.crtc->setCurrent(pending.layer->currentBuffer()); } return true; } diff --git a/src/backends/drm/drm_qpainter_layer.cpp b/src/backends/drm/drm_qpainter_layer.cpp index 64f6231f80..40a7e198e3 100644 --- a/src/backends/drm/drm_qpainter_layer.cpp +++ b/src/backends/drm/drm_qpainter_layer.cpp @@ -35,6 +35,7 @@ std::optional DrmQPainterLayer::startRendering() bool DrmQPainterLayer::endRendering(const QRegion &damagedRegion) { + m_currentDamage = damagedRegion; m_swapchain->releaseBuffer(m_swapchain->currentBuffer(), damagedRegion); return true; } @@ -63,9 +64,19 @@ QSharedPointer DrmQPainterLayer::currentBuffer() const return m_swapchain ? m_swapchain->currentBuffer() : nullptr; } +QRegion DrmQPainterLayer::currentDamage() const +{ + return m_currentDamage; +} + DrmDisplayDevice *DrmQPainterLayer::displayDevice() const { return m_displayDevice; } +bool DrmQPainterLayer::hasDirectScanoutBuffer() const +{ + return false; +} + } diff --git a/src/backends/drm/drm_qpainter_layer.h b/src/backends/drm/drm_qpainter_layer.h index e308bf70b9..ef3f0c8250 100644 --- a/src/backends/drm/drm_qpainter_layer.h +++ b/src/backends/drm/drm_qpainter_layer.h @@ -23,12 +23,15 @@ public: bool scanout(SurfaceItem *surfaceItem) override; QSharedPointer testBuffer() override; QSharedPointer currentBuffer() const override; + QRegion currentDamage() const override; + bool hasDirectScanoutBuffer() const override; DrmDisplayDevice *displayDevice() const override; private: bool doesSwapchainFit() const; QSharedPointer m_swapchain; + QRegion m_currentDamage; DrmDisplayDevice *const m_displayDevice; }; diff --git a/src/backends/drm/drm_render_backend.h b/src/backends/drm/drm_render_backend.h new file mode 100644 index 0000000000..b04b40cee3 --- /dev/null +++ b/src/backends/drm/drm_render_backend.h @@ -0,0 +1,28 @@ +/* + KWin - the KDE window manager + This file is part of the KDE project. + + SPDX-FileCopyrightText: 2022 Xaver Hugl + + SPDX-License-Identifier: GPL-2.0-or-later +*/ +#pragma once + +#include + +namespace KWin +{ + +class DrmLayer; +class DrmDisplayDevice; + +class DrmRenderBackend +{ +public: + virtual ~DrmRenderBackend() = default; + + virtual QSharedPointer createLayer(DrmDisplayDevice *displayDevice) const = 0; + +}; + +} diff --git a/src/backends/drm/drm_virtual_output.cpp b/src/backends/drm/drm_virtual_output.cpp index 87ee88dadd..191c2ecdea 100644 --- a/src/backends/drm/drm_virtual_output.cpp +++ b/src/backends/drm/drm_virtual_output.cpp @@ -14,9 +14,12 @@ #include "drm_gpu.h" #include "drm_backend.h" #include "logging.h" +#include "drm_layer.h" +#include "drm_render_backend.h" namespace KWin { + static int s_serial = 0; DrmVirtualOutput::DrmVirtualOutput(DrmGpu *gpu, const QSize &size) : DrmVirtualOutput(QString::number(s_serial++), gpu, size) @@ -40,20 +43,19 @@ DrmVirtualOutput::DrmVirtualOutput(const QString &name, DrmGpu *gpu, const QSize modes, QByteArray("EDID_") + name.toUtf8()); m_renderLoop->setRefreshRate(modes[m_modeIndex].refreshRate); + + m_layer = gpu->renderBackend()->createLayer(this); } DrmVirtualOutput::~DrmVirtualOutput() { } -bool DrmVirtualOutput::present(const QSharedPointer &buffer, QRegion damagedRegion) +bool DrmVirtualOutput::present() { - Q_UNUSED(damagedRegion) - - m_currentBuffer = buffer; m_vsyncMonitor->arm(); m_pageFlipPending = true; - Q_EMIT outputChange(damagedRegion); + Q_EMIT outputChange(m_layer->currentDamage()); return true; } @@ -119,4 +121,14 @@ DrmPlane::Transformations DrmVirtualOutput::softwareTransforms() const return DrmPlane::Transformation::Rotate0; } +DrmLayer *DrmVirtualOutput::outputLayer() const +{ + return m_layer.data(); +} + +bool DrmVirtualOutput::testScanout() +{ + return true; +} + } diff --git a/src/backends/drm/drm_virtual_output.h b/src/backends/drm/drm_virtual_output.h index 68cdd57ba6..6de8ed27e2 100644 --- a/src/backends/drm/drm_virtual_output.h +++ b/src/backends/drm/drm_virtual_output.h @@ -19,6 +19,7 @@ namespace KWin class SoftwareVsyncMonitor; class VirtualBackend; +class DrmLayer; class DrmVirtualOutput : public DrmAbstractOutput { @@ -28,7 +29,7 @@ public: DrmVirtualOutput(DrmGpu *gpu, const QSize &size); ~DrmVirtualOutput() override; - bool present(const QSharedPointer &buffer, QRegion damagedRegion) override; + bool present() override; QSize bufferSize() const override; QSize sourceSize() const override; @@ -39,13 +40,15 @@ public: int gammaRampSize() const override; bool setGammaRamp(const GammaRamp &gamma) override; DrmPlane::Transformations softwareTransforms() const override; + DrmLayer *outputLayer() const override; + bool testScanout() override; private: void vblank(std::chrono::nanoseconds timestamp); void setDpmsMode(DpmsMode mode) override; void updateEnablement(bool enable) override; - QSharedPointer m_currentBuffer; + QSharedPointer m_layer; bool m_pageFlipPending = true; int m_modeIndex = 0; diff --git a/src/backends/drm/egl_gbm_backend.cpp b/src/backends/drm/egl_gbm_backend.cpp index e73b56eacc..7d3764794f 100644 --- a/src/backends/drm/egl_gbm_backend.cpp +++ b/src/backends/drm/egl_gbm_backend.cpp @@ -49,20 +49,14 @@ EglGbmBackend::EglGbmBackend(DrmBackend *drmBackend) : AbstractEglBackend(drmBackend->primaryGpu()->deviceId()) , m_backend(drmBackend) { - drmBackend->primaryGpu()->setEglBackend(this); - connect(m_backend, &DrmBackend::outputAdded, this, &EglGbmBackend::addOutput); - connect(m_backend, &DrmBackend::outputRemoved, this, &EglGbmBackend::removeOutput); + drmBackend->primaryGpu()->setRenderBackend(this); setIsDirectRendering(true); } EglGbmBackend::~EglGbmBackend() { cleanup(); -} - -void EglGbmBackend::cleanupSurfaces() -{ - m_surfaces.clear(); + m_backend->primaryGpu()->setRenderBackend(nullptr); } bool EglGbmBackend::initializeEgl() @@ -124,23 +118,9 @@ bool EglGbmBackend::initRenderingContext() if (!createContext() || !makeCurrent()) { return false; } - const auto outputs = m_backend->outputs(); - for (const auto &output : outputs) { - addOutput(output); - } return true; } -void EglGbmBackend::addOutput(AbstractOutput *output) { - auto drmOutput = static_cast(output); - m_surfaces.insert(drmOutput, QSharedPointer::create(m_backend->primaryGpu(), drmOutput)); -} - -void EglGbmBackend::removeOutput(AbstractOutput *output) -{ - m_surfaces.remove(output); -} - bool EglGbmBackend::initBufferConfigs() { const EGLint config_attribs[] = { @@ -250,9 +230,8 @@ static QVector regionToRects(const QRegion ®ion, DrmAbstractOutput *o void EglGbmBackend::aboutToStartPainting(AbstractOutput *output, const QRegion &damagedRegion) { - Q_ASSERT_X(output, "aboutToStartPainting", "not using per screen rendering"); - Q_ASSERT(m_surfaces.contains(output)); - const auto &surface = m_surfaces[output]; + const auto drmOutput = static_cast(output); + const auto &surface = static_cast(drmOutput->outputLayer()); if (surface->bufferAge() > 0 && !damagedRegion.isEmpty() && supportsPartialUpdate()) { QVector rects = regionToRects(damagedRegion, static_cast(output)); const bool correct = eglSetDamageRegionKHR(eglDisplay(), surface->eglSurface(), rects.data(), rects.count()/4); @@ -274,34 +253,34 @@ SurfaceTexture *EglGbmBackend::createSurfaceTextureWayland(SurfacePixmapWayland QRegion EglGbmBackend::beginFrame(AbstractOutput *output) { - Q_ASSERT(m_surfaces.contains(output)); - return m_surfaces[output]->startRendering().value_or(QRegion()); + return static_cast(output)->outputLayer()->startRendering().value_or(QRegion()); } void EglGbmBackend::endFrame(AbstractOutput *output, const QRegion &renderedRegion, const QRegion &damagedRegion) { - Q_ASSERT(m_surfaces.contains(output)); Q_UNUSED(renderedRegion) - m_surfaces[output]->endRendering(damagedRegion); - static_cast(output)->present(m_surfaces[output]->currentBuffer(), damagedRegion); + const auto drmOutput = static_cast(output); + drmOutput->outputLayer()->endRendering(damagedRegion); + drmOutput->present(); } bool EglGbmBackend::scanout(AbstractOutput *output, SurfaceItem *surfaceItem) { - return m_surfaces[output]->scanout(surfaceItem); -} - -QSharedPointer EglGbmBackend::testBuffer(DrmAbstractOutput *output) -{ - return m_surfaces[output]->testBuffer(); + const auto drmOutput = static_cast(output); + if (drmOutput->outputLayer()->scanout(surfaceItem)) { + drmOutput->present(); + return true; + } else { + return false; + } } QSharedPointer EglGbmBackend::textureForOutput(AbstractOutput *output) const { - Q_ASSERT(m_surfaces.contains(output)); - return m_surfaces[output]->texture(); + const auto drmOutput = static_cast(output); + return static_cast(drmOutput->outputLayer())->texture(); } GbmFormat EglGbmBackend::gbmFormatForDrmFormat(uint32_t format) const @@ -352,6 +331,11 @@ EGLConfig EglGbmBackend::config(uint32_t format) const return m_configs[format]; } +QSharedPointer EglGbmBackend::createLayer(DrmDisplayDevice *displayDevice) const +{ + return QSharedPointer::create(m_backend->primaryGpu(), displayDevice); +} + bool operator==(const GbmFormat &lhs, const GbmFormat &rhs) { return lhs.drmFormat == rhs.drmFormat; diff --git a/src/backends/drm/egl_gbm_backend.h b/src/backends/drm/egl_gbm_backend.h index ac83e7c1db..7bea7ac0e0 100644 --- a/src/backends/drm/egl_gbm_backend.h +++ b/src/backends/drm/egl_gbm_backend.h @@ -6,9 +6,9 @@ SPDX-License-Identifier: GPL-2.0-or-later */ -#ifndef KWIN_EGL_GBM_BACKEND_H -#define KWIN_EGL_GBM_BACKEND_H +#pragma once #include "abstract_egl_backend.h" +#include "drm_render_backend.h" #include @@ -52,7 +52,7 @@ bool operator==(const GbmFormat &lhs, const GbmFormat &rhs); /** * @brief OpenGL Backend using Egl on a GBM surface. */ -class EglGbmBackend : public AbstractEglBackend +class EglGbmBackend : public AbstractEglBackend, public DrmRenderBackend { Q_OBJECT public: @@ -67,6 +67,7 @@ public: void init() override; bool scanout(AbstractOutput *output, SurfaceItem *surfaceItem) override; bool prefer10bpc() const override; + QSharedPointer createLayer(DrmDisplayDevice *displayDevice) const override; QSharedPointer textureForOutput(AbstractOutput *requestedOutput) const override; @@ -76,17 +77,13 @@ public: std::optional chooseFormat(DrmDisplayDevice *displyDevice) const; protected: - void cleanupSurfaces() override; void aboutToStartPainting(AbstractOutput *output, const QRegion &damage) override; private: bool initializeEgl(); bool initBufferConfigs(); bool initRenderingContext(); - void addOutput(AbstractOutput *output); - void removeOutput(AbstractOutput *output); - QMap> m_surfaces; DrmBackend *m_backend; QVector m_formats; QMap m_configs; @@ -95,5 +92,3 @@ private: }; } // namespace - -#endif diff --git a/src/backends/drm/egl_gbm_layer.cpp b/src/backends/drm/egl_gbm_layer.cpp index e3eefb2b11..aa4e7cc864 100644 --- a/src/backends/drm/egl_gbm_layer.cpp +++ b/src/backends/drm/egl_gbm_layer.cpp @@ -50,6 +50,7 @@ EglGbmLayer::~EglGbmLayer() std::optional EglGbmLayer::startRendering() { + m_scanoutBuffer.reset(); // dmabuf feedback if (!m_scanoutCandidate.attemptedThisFrame && m_scanoutCandidate.surface) { if (const auto feedback = m_scanoutCandidate.surface->dmabufFeedbackV1()) { @@ -117,13 +118,27 @@ bool EglGbmLayer::endRendering(const QRegion &damagedRegion) const auto buffer = m_gbmSurface->swapBuffersForDrm(damagedRegion); if (buffer) { m_currentBuffer = buffer; + m_currentDamage = damagedRegion; } return buffer; } +QRegion EglGbmLayer::currentDamage() const +{ + return m_currentDamage; +} + QSharedPointer EglGbmLayer::testBuffer() { if (!m_currentBuffer || !doesGbmSurfaceFit(m_gbmSurface.data())) { + if (doesGbmSurfaceFit(m_oldGbmSurface.data())) { + // re-use old surface and buffer without rendering + m_gbmSurface = m_oldGbmSurface; + if (m_gbmSurface->currentBuffer()) { + m_currentBuffer = m_gbmSurface->currentDrmBuffer(); + return m_currentBuffer; + } + } if (!renderTestBuffer() && m_importMode == MultiGpuImportMode::DumbBufferXrgb8888) { // try multi-gpu import again, this time with DRM_FORMAT_XRGB8888 renderTestBuffer(); @@ -401,10 +416,11 @@ bool EglGbmLayer::scanout(SurfaceItem *surfaceItem) } return false; } - const auto bo = QSharedPointer::create(m_displayDevice->gpu(), importedBuffer, buffer); - if (!bo->bufferId()) { + m_scanoutBuffer = QSharedPointer::create(m_displayDevice->gpu(), importedBuffer, buffer); + if (!m_scanoutBuffer->bufferId()) { // buffer can't actually be scanned out. Mesa is supposed to prevent this from happening // in gbm_bo_import but apparently that doesn't always work + m_scanoutBuffer.reset(); sendDmabufFeedback(buffer); return false; } @@ -421,10 +437,12 @@ bool EglGbmLayer::scanout(SurfaceItem *surfaceItem) } else { damage = m_displayDevice->renderGeometry(); } - if (m_displayDevice->present(bo, damage)) { - m_currentBuffer = bo; + if (m_displayDevice->testScanout()) { + m_currentBuffer = m_scanoutBuffer; + m_currentDamage = damage; return true; } else { + m_scanoutBuffer.reset(); return false; } } @@ -462,7 +480,7 @@ void EglGbmLayer::sendDmabufFeedback(KWaylandServer::LinuxDmaBufV1ClientBuffer * QSharedPointer EglGbmLayer::currentBuffer() const { - return m_currentBuffer; + return m_scanoutBuffer ? m_scanoutBuffer : m_currentBuffer; } DrmDisplayDevice *EglGbmLayer::displayDevice() const @@ -480,4 +498,9 @@ EGLSurface EglGbmLayer::eglSurface() const return m_gbmSurface ? m_gbmSurface->eglSurface() : EGL_NO_SURFACE; } +bool EglGbmLayer::hasDirectScanoutBuffer() const +{ + return m_scanoutBuffer != nullptr; +} + } diff --git a/src/backends/drm/egl_gbm_layer.h b/src/backends/drm/egl_gbm_layer.h index fe31ae2032..26b02a2de0 100644 --- a/src/backends/drm/egl_gbm_layer.h +++ b/src/backends/drm/egl_gbm_layer.h @@ -44,6 +44,8 @@ public: bool scanout(SurfaceItem *surfaceItem) override; QSharedPointer testBuffer() override; QSharedPointer currentBuffer() const override; + bool hasDirectScanoutBuffer() const override; + QRegion currentDamage() const override; QSharedPointer texture() const; DrmDisplayDevice *displayDevice() const override; @@ -76,7 +78,9 @@ private: bool attemptedThisFrame = false; } m_scanoutCandidate; + QSharedPointer m_scanoutBuffer; QSharedPointer m_currentBuffer; + QRegion m_currentDamage; QSharedPointer m_gbmSurface; QSharedPointer m_oldGbmSurface; QSharedPointer m_shadowBuffer; diff --git a/src/backends/drm/scene_qpainter_drm_backend.cpp b/src/backends/drm/scene_qpainter_drm_backend.cpp index f645f822ed..10f1cb4164 100644 --- a/src/backends/drm/scene_qpainter_drm_backend.cpp +++ b/src/backends/drm/scene_qpainter_drm_backend.cpp @@ -23,29 +23,37 @@ DrmQPainterBackend::DrmQPainterBackend(DrmBackend *backend) : QPainterBackend() , m_backend(backend) { - connect(m_backend, &DrmBackend::outputEnabled, this, [this] (const auto output) { - m_swapchains[output] = QSharedPointer::create(static_cast(output)); - }); - connect(m_backend, &DrmBackend::outputDisabled, this, [this] (const auto output) { - m_swapchains.remove(output); - }); + m_backend->primaryGpu()->setRenderBackend(this); +} + +DrmQPainterBackend::~DrmQPainterBackend() +{ + m_backend->primaryGpu()->setRenderBackend(nullptr); } QImage *DrmQPainterBackend::bufferForScreen(AbstractOutput *output) { - return static_cast(m_swapchains[output]->currentBuffer().data())->image(); + const auto drmOutput = static_cast(output); + return static_cast(drmOutput->outputLayer()->currentBuffer().data())->image(); } QRegion DrmQPainterBackend::beginFrame(AbstractOutput *output) { - return m_swapchains[output]->startRendering().value_or(QRegion()); + const auto drmOutput = static_cast(output); + return drmOutput->outputLayer()->startRendering().value_or(QRegion()); } void DrmQPainterBackend::endFrame(AbstractOutput *output, const QRegion &renderedRegion, const QRegion &damage) { Q_UNUSED(renderedRegion) - m_swapchains[output]->endRendering(damage); - static_cast(output)->present(m_swapchains[output]->currentBuffer(), output->geometry()); + const auto drmOutput = static_cast(output); + drmOutput->outputLayer()->endRendering(damage); + static_cast(output)->present(); +} + +QSharedPointer DrmQPainterBackend::createLayer(DrmDisplayDevice *displayDevice) const +{ + return QSharedPointer::create(displayDevice); } } diff --git a/src/backends/drm/scene_qpainter_drm_backend.h b/src/backends/drm/scene_qpainter_drm_backend.h index 71c6b6b34d..d32ef13d90 100644 --- a/src/backends/drm/scene_qpainter_drm_backend.h +++ b/src/backends/drm/scene_qpainter_drm_backend.h @@ -6,16 +6,15 @@ SPDX-License-Identifier: GPL-2.0-or-later */ -#ifndef KWIN_SCENE_QPAINTER_DRM_BACKEND_H -#define KWIN_SCENE_QPAINTER_DRM_BACKEND_H +#pragma once #include "qpainterbackend.h" +#include "drm_render_backend.h" +#include "dumb_swapchain.h" #include #include #include -#include "dumb_swapchain.h" - namespace KWin { @@ -23,20 +22,19 @@ class DrmBackend; class DrmAbstractOutput; class DrmQPainterLayer; -class DrmQPainterBackend : public QPainterBackend +class DrmQPainterBackend : public QPainterBackend, public DrmRenderBackend { Q_OBJECT public: DrmQPainterBackend(DrmBackend *backend); + ~DrmQPainterBackend(); QImage *bufferForScreen(AbstractOutput *output) override; QRegion beginFrame(AbstractOutput *output) override; void endFrame(AbstractOutput *output, const QRegion &renderedRegion, const QRegion &damagedRegion) override; + QSharedPointer createLayer(DrmDisplayDevice *displayDevice) const override; private: - QMap> m_swapchains; DrmBackend *m_backend; }; } - -#endif