From b530a5b66d8a3611ab9361045d86c0fcbdc62a25 Mon Sep 17 00:00:00 2001 From: Xaver Hugl Date: Tue, 15 Feb 2022 22:27:54 +0100 Subject: [PATCH] backends/drm: fix layer destruction Layers need to release their resources whenever the render backend gets replaced. --- src/backends/drm/CMakeLists.txt | 1 + src/backends/drm/drm_backend.cpp | 23 +++++++- src/backends/drm/drm_backend.h | 5 ++ src/backends/drm/drm_gpu.cpp | 29 ++++----- src/backends/drm/drm_gpu.h | 6 +- src/backends/drm/drm_layer.cpp | 28 +++++++++ src/backends/drm/drm_layer.h | 12 +++- src/backends/drm/drm_qpainter_layer.cpp | 13 ++-- src/backends/drm/drm_qpainter_layer.h | 5 +- src/backends/drm/drm_render_backend.h | 2 +- src/backends/drm/drm_virtual_output.cpp | 7 ++- src/backends/drm/drm_virtual_output.h | 2 + src/backends/drm/egl_gbm_backend.cpp | 14 +++-- src/backends/drm/egl_gbm_backend.h | 6 +- src/backends/drm/egl_gbm_layer.cpp | 59 +++++++++++-------- src/backends/drm/egl_gbm_layer.h | 8 +-- src/backends/drm/gbm_surface.cpp | 29 ++++----- src/backends/drm/gbm_surface.h | 3 +- .../drm/scene_qpainter_drm_backend.cpp | 6 +- src/backends/drm/scene_qpainter_drm_backend.h | 5 +- 20 files changed, 172 insertions(+), 91 deletions(-) create mode 100644 src/backends/drm/drm_layer.cpp diff --git a/src/backends/drm/CMakeLists.txt b/src/backends/drm/CMakeLists.txt index b28f23192e..0a788ebad0 100644 --- a/src/backends/drm/CMakeLists.txt +++ b/src/backends/drm/CMakeLists.txt @@ -14,6 +14,7 @@ set(DRM_SOURCES dumb_swapchain.cpp shadowbuffer.cpp drm_display_device.cpp + drm_layer.cpp drm_pipeline.cpp drm_pipeline_legacy.cpp drm_abstract_output.cpp diff --git a/src/backends/drm/drm_backend.cpp b/src/backends/drm/drm_backend.cpp index c55bb8ea55..73c59a81ad 100644 --- a/src/backends/drm/drm_backend.cpp +++ b/src/backends/drm/drm_backend.cpp @@ -28,6 +28,7 @@ #include "waylandoutputconfig.h" #include "egl_gbm_backend.h" #include "gbm_dmabuf.h" +#include "drm_render_backend.h" // KF5 #include #include @@ -550,7 +551,13 @@ OpenGLBackend *DrmBackend::createOpenGLBackend() void DrmBackend::sceneInitialized() { - updateOutputs(); + if (m_outputs.isEmpty()) { + updateOutputs(); + } else { + for (const auto &gpu : qAsConst(m_gpus)) { + gpu->recreateSurfaces(); + } + } } QVector DrmBackend::supportedCompositors() const @@ -593,8 +600,8 @@ void DrmBackend::removeVirtualOutput(AbstractOutput *output) DmaBufTexture *DrmBackend::createDmaBufTexture(const QSize &size) { - if (primaryGpu()->eglBackend() && primaryGpu()->gbmDevice()) { - primaryGpu()->eglBackend()->makeCurrent(); + if (const auto eglBackend = dynamic_cast(m_renderBackend); eglBackend && primaryGpu()->gbmDevice()) { + eglBackend->makeCurrent(); return GbmDmaBuf::createBuffer(size, primaryGpu()->gbmDevice()); } else { return nullptr; @@ -664,4 +671,14 @@ bool DrmBackend::applyOutputChanges(const WaylandOutputConfig &config) return true; } +void DrmBackend::setRenderBackend(DrmRenderBackend *backend) +{ + m_renderBackend = backend; +} + +DrmRenderBackend *DrmBackend::renderBackend() const +{ + return m_renderBackend; +} + } diff --git a/src/backends/drm/drm_backend.h b/src/backends/drm/drm_backend.h index 5a91bf17de..895eecb008 100644 --- a/src/backends/drm/drm_backend.h +++ b/src/backends/drm/drm_backend.h @@ -30,6 +30,7 @@ class DrmAbstractOutput; class Cursor; class DrmGpu; class DrmVirtualOutput; +class DrmRenderBackend; class KWIN_EXPORT DrmBackend : public Platform { @@ -67,6 +68,9 @@ public: bool isActive() const; + void setRenderBackend(DrmRenderBackend *backend); + DrmRenderBackend *renderBackend() const; + public Q_SLOTS: void turnOutputsOn(); void sceneInitialized() override; @@ -105,6 +109,7 @@ private: QVector m_gpus; QScopedPointer m_dpmsFilter; QScopedPointer m_placeholderFilter; + DrmRenderBackend *m_renderBackend = nullptr; }; diff --git a/src/backends/drm/drm_gpu.cpp b/src/backends/drm/drm_gpu.cpp index 183b700986..ea5a414912 100644 --- a/src/backends/drm/drm_gpu.cpp +++ b/src/backends/drm/drm_gpu.cpp @@ -422,7 +422,7 @@ bool DrmGpu::testPipelines() QVector inactivePipelines; for (const auto &pipeline : qAsConst(m_pipelines)) { if (!pipeline->pending.layer) { - pipeline->pending.layer = m_renderBackend->createLayer(pipeline->displayDevice()); + pipeline->pending.layer = m_platform->renderBackend()->createLayer(pipeline->displayDevice()); } if (!pipeline->pending.active) { pipeline->pending.active = true; @@ -562,21 +562,6 @@ void DrmGpu::removeOutput(DrmOutput *output) delete output; } -EglGbmBackend *DrmGpu::eglBackend() const -{ - return dynamic_cast(m_renderBackend); -} - -DrmRenderBackend *DrmGpu::renderBackend() const -{ - return m_renderBackend; -} - -void DrmGpu::setRenderBackend(DrmRenderBackend *backend) -{ - m_renderBackend = backend; -} - DrmBackend *DrmGpu::platform() const { return m_platform; } @@ -782,4 +767,16 @@ QSize DrmGpu::cursorSize() const return m_cursorSize; } +void DrmGpu::recreateSurfaces() +{ + for (const auto &pipeline : qAsConst(m_pipelines)) { + pipeline->pending.layer = m_platform->renderBackend()->createLayer(pipeline->displayDevice()); + } + for (const auto &output : qAsConst(m_outputs)) { + if (const auto virtualOutput = qobject_cast(output)) { + virtualOutput->recreateSurface(); + } + } +} + } diff --git a/src/backends/drm/drm_gpu.h b/src/backends/drm/drm_gpu.h index 48f06993e0..97c2d8ddc2 100644 --- a/src/backends/drm/drm_gpu.h +++ b/src/backends/drm/drm_gpu.h @@ -59,8 +59,6 @@ public: bool isNVidia() const; 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 @@ -73,7 +71,6 @@ public: const QVector pipelines() const; void setEglDisplay(EGLDisplay display); - void setRenderBackend(DrmRenderBackend *backend); bool updateOutputs(); @@ -89,6 +86,8 @@ public: bool needsModeset() const; bool maybeModeset(); + void recreateSurfaces(); + Q_SIGNALS: void outputAdded(DrmAbstractOutput *output); void outputRemoved(DrmAbstractOutput *output); @@ -122,7 +121,6 @@ private: clockid_t m_presentationClock; gbm_device* m_gbmDevice; EGLDisplay m_eglDisplay = EGL_NO_DISPLAY; - DrmRenderBackend *m_renderBackend; DrmBackend* const m_platform; QVector m_planes; diff --git a/src/backends/drm/drm_layer.cpp b/src/backends/drm/drm_layer.cpp new file mode 100644 index 0000000000..611b801c57 --- /dev/null +++ b/src/backends/drm/drm_layer.cpp @@ -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 +*/ +#include "drm_layer.h" + +namespace KWin +{ + +DrmLayer::DrmLayer(KWin::DrmDisplayDevice* device) + : m_displayDevice(device) +{ +} + +DrmLayer::~DrmLayer() = default; + +DrmDisplayDevice *DrmLayer::displayDevice() const +{ + return m_displayDevice; +} + +} + +#include "drm_layer.moc" diff --git a/src/backends/drm/drm_layer.h b/src/backends/drm/drm_layer.h index 5dd0e0c68e..06ce00c62e 100644 --- a/src/backends/drm/drm_layer.h +++ b/src/backends/drm/drm_layer.h @@ -11,6 +11,7 @@ #include #include #include +#include namespace KWin { @@ -19,10 +20,12 @@ class SurfaceItem; class DrmBuffer; class DrmDisplayDevice; -class DrmLayer +class DrmLayer : public QObject { + Q_OBJECT public: - virtual ~DrmLayer() = default; + DrmLayer(DrmDisplayDevice *device); + virtual ~DrmLayer(); virtual std::optional startRendering() = 0; virtual bool endRendering(const QRegion &damagedRegion) = 0; @@ -44,7 +47,10 @@ public: virtual QRegion currentDamage() const = 0; virtual bool hasDirectScanoutBuffer() const = 0; - virtual DrmDisplayDevice *displayDevice() const = 0; + DrmDisplayDevice *displayDevice() const; + +protected: + DrmDisplayDevice *const m_displayDevice; }; } diff --git a/src/backends/drm/drm_qpainter_layer.cpp b/src/backends/drm/drm_qpainter_layer.cpp index 40a7e198e3..c66df420cf 100644 --- a/src/backends/drm/drm_qpainter_layer.cpp +++ b/src/backends/drm/drm_qpainter_layer.cpp @@ -10,6 +10,9 @@ #include "dumb_swapchain.h" #include "drm_abstract_output.h" #include "drm_buffer.h" +#include "scene_qpainter_drm_backend.h" +#include "drm_gpu.h" +#include "drm_backend.h" #include @@ -17,8 +20,11 @@ namespace KWin { DrmQPainterLayer::DrmQPainterLayer(DrmDisplayDevice *displayDevice) - : m_displayDevice(displayDevice) + : DrmLayer(displayDevice) { + connect(static_cast(displayDevice->gpu()->platform()->renderBackend()), &DrmQPainterBackend::aboutToBeDestroyed, this, [this]() { + m_swapchain.reset(); + }); } std::optional DrmQPainterLayer::startRendering() @@ -69,11 +75,6 @@ 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 ef3f0c8250..edfebe050e 100644 --- a/src/backends/drm/drm_qpainter_layer.h +++ b/src/backends/drm/drm_qpainter_layer.h @@ -14,7 +14,8 @@ namespace KWin class DumbSwapchain; -class DrmQPainterLayer : public DrmLayer { +class DrmQPainterLayer : public DrmLayer +{ public: DrmQPainterLayer(DrmDisplayDevice *displayDevice); @@ -25,14 +26,12 @@ public: 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 index b04b40cee3..243f664ba4 100644 --- a/src/backends/drm/drm_render_backend.h +++ b/src/backends/drm/drm_render_backend.h @@ -21,7 +21,7 @@ class DrmRenderBackend public: virtual ~DrmRenderBackend() = default; - virtual QSharedPointer createLayer(DrmDisplayDevice *displayDevice) const = 0; + virtual QSharedPointer createLayer(DrmDisplayDevice *displayDevice) = 0; }; diff --git a/src/backends/drm/drm_virtual_output.cpp b/src/backends/drm/drm_virtual_output.cpp index 191c2ecdea..b198f7c441 100644 --- a/src/backends/drm/drm_virtual_output.cpp +++ b/src/backends/drm/drm_virtual_output.cpp @@ -44,7 +44,7 @@ DrmVirtualOutput::DrmVirtualOutput(const QString &name, DrmGpu *gpu, const QSize QByteArray("EDID_") + name.toUtf8()); m_renderLoop->setRefreshRate(modes[m_modeIndex].refreshRate); - m_layer = gpu->renderBackend()->createLayer(this); + recreateSurface(); } DrmVirtualOutput::~DrmVirtualOutput() @@ -131,4 +131,9 @@ bool DrmVirtualOutput::testScanout() return true; } +void DrmVirtualOutput::recreateSurface() +{ + m_layer = m_gpu->platform()->renderBackend()->createLayer(this); +} + } diff --git a/src/backends/drm/drm_virtual_output.h b/src/backends/drm/drm_virtual_output.h index 6de8ed27e2..24ab437872 100644 --- a/src/backends/drm/drm_virtual_output.h +++ b/src/backends/drm/drm_virtual_output.h @@ -43,6 +43,8 @@ public: DrmLayer *outputLayer() const override; bool testScanout() override; + void recreateSurface(); + private: void vblank(std::chrono::nanoseconds timestamp); void setDpmsMode(DpmsMode mode) override; diff --git a/src/backends/drm/egl_gbm_backend.cpp b/src/backends/drm/egl_gbm_backend.cpp index 7d3764794f..a480012264 100644 --- a/src/backends/drm/egl_gbm_backend.cpp +++ b/src/backends/drm/egl_gbm_backend.cpp @@ -49,14 +49,15 @@ EglGbmBackend::EglGbmBackend(DrmBackend *drmBackend) : AbstractEglBackend(drmBackend->primaryGpu()->deviceId()) , m_backend(drmBackend) { - drmBackend->primaryGpu()->setRenderBackend(this); + drmBackend->setRenderBackend(this); setIsDirectRendering(true); } EglGbmBackend::~EglGbmBackend() { + Q_EMIT aboutToBeDestroyed(); cleanup(); - m_backend->primaryGpu()->setRenderBackend(nullptr); + m_backend->setRenderBackend(nullptr); } bool EglGbmBackend::initializeEgl() @@ -331,9 +332,14 @@ EGLConfig EglGbmBackend::config(uint32_t format) const return m_configs[format]; } -QSharedPointer EglGbmBackend::createLayer(DrmDisplayDevice *displayDevice) const +QSharedPointer EglGbmBackend::createLayer(DrmDisplayDevice *displayDevice) { - return QSharedPointer::create(m_backend->primaryGpu(), displayDevice); + return QSharedPointer::create(this, displayDevice); +} + +DrmGpu *EglGbmBackend::gpu() const +{ + return m_backend->primaryGpu(); } bool operator==(const GbmFormat &lhs, const GbmFormat &rhs) diff --git a/src/backends/drm/egl_gbm_backend.h b/src/backends/drm/egl_gbm_backend.h index 7bea7ac0e0..e454e2640e 100644 --- a/src/backends/drm/egl_gbm_backend.h +++ b/src/backends/drm/egl_gbm_backend.h @@ -67,7 +67,7 @@ public: void init() override; bool scanout(AbstractOutput *output, SurfaceItem *surfaceItem) override; bool prefer10bpc() const override; - QSharedPointer createLayer(DrmDisplayDevice *displayDevice) const override; + QSharedPointer createLayer(DrmDisplayDevice *displayDevice) override; QSharedPointer textureForOutput(AbstractOutput *requestedOutput) const override; @@ -75,6 +75,10 @@ public: EGLConfig config(uint32_t format) const; GbmFormat gbmFormatForDrmFormat(uint32_t format) const; std::optional chooseFormat(DrmDisplayDevice *displyDevice) const; + DrmGpu *gpu() const; + +Q_SIGNALS: + void aboutToBeDestroyed(); protected: void aboutToStartPainting(AbstractOutput *output, const QRegion &damage) override; diff --git a/src/backends/drm/egl_gbm_layer.cpp b/src/backends/drm/egl_gbm_layer.cpp index aa4e7cc864..0938c73618 100644 --- a/src/backends/drm/egl_gbm_layer.cpp +++ b/src/backends/drm/egl_gbm_layer.cpp @@ -19,6 +19,7 @@ #include "egl_dmabuf.h" #include "surfaceitem_wayland.h" #include "kwineglimagetexture.h" +#include "drm_backend.h" #include "KWaylandServer/surface_interface.h" #include "KWaylandServer/linuxdmabufv1clientbuffer.h" @@ -32,20 +33,31 @@ namespace KWin { -EglGbmLayer::EglGbmLayer(DrmGpu *renderGpu, DrmDisplayDevice *displayDevice) - : m_displayDevice(displayDevice) - , m_renderGpu(renderGpu) +EglGbmLayer::EglGbmLayer(EglGbmBackend *eglBackend, DrmDisplayDevice *displayDevice) + : DrmLayer(displayDevice) + , m_eglBackend(eglBackend) { + connect(eglBackend, &EglGbmBackend::aboutToBeDestroyed, this, &EglGbmLayer::destroyResources); } EglGbmLayer::~EglGbmLayer() { - if (m_gbmSurface && m_shadowBuffer && m_gbmSurface->makeContextCurrent()) { - m_shadowBuffer.reset(); - } - if (m_oldGbmSurface && m_oldShadowBuffer && m_oldGbmSurface->makeContextCurrent()) { - m_oldShadowBuffer.reset(); + destroyResources(); +} + +void EglGbmLayer::destroyResources() +{ + if (m_shadowBuffer || m_oldShadowBuffer) { + if (m_gbmSurface) { + m_gbmSurface->makeContextCurrent(); + } else if (m_oldGbmSurface) { + m_oldGbmSurface->makeContextCurrent(); + } } + m_shadowBuffer.reset(); + m_oldShadowBuffer.reset(); + m_gbmSurface.reset(); + m_oldGbmSurface.reset(); } std::optional EglGbmLayer::startRendering() @@ -87,7 +99,7 @@ std::optional EglGbmLayer::startRendering() m_shadowBuffer = m_oldShadowBuffer; } else { if (m_displayDevice->softwareTransforms() != DrmPlane::Transformations(DrmPlane::Transformation::Rotate0)) { - const auto format = m_renderGpu->eglBackend()->gbmFormatForDrmFormat(m_gbmSurface->format()); + const auto format = m_eglBackend->gbmFormatForDrmFormat(m_gbmSurface->format()); m_shadowBuffer = QSharedPointer::create(m_displayDevice->sourceSize(), format); if (!m_shadowBuffer->isComplete()) { return std::optional(); @@ -164,37 +176,37 @@ bool EglGbmLayer::createGbmSurface() static bool modifiersEnvSet = false; static const bool modifiersEnv = qEnvironmentVariableIntValue("KWIN_DRM_USE_MODIFIERS", &modifiersEnvSet) != 0; - auto format = m_renderGpu->eglBackend()->chooseFormat(m_displayDevice); + auto format = m_eglBackend->chooseFormat(m_displayDevice); if (!format || m_importMode == MultiGpuImportMode::DumbBufferXrgb8888) { format = DRM_FORMAT_XRGB8888; } const auto modifiers = m_displayDevice->supportedModifiers(format.value()); const auto size = m_displayDevice->bufferSize(); - const auto config = m_renderGpu->eglBackend()->config(format.value()); - const bool allowModifiers = m_renderGpu->addFB2ModifiersSupported() && m_displayDevice->gpu()->addFB2ModifiersSupported() - && ((m_renderGpu->isNVidia() && !modifiersEnvSet) || (modifiersEnvSet && modifiersEnv)); + const auto config = m_eglBackend->config(format.value()); + const bool allowModifiers = m_eglBackend->gpu()->addFB2ModifiersSupported() && m_displayDevice->gpu()->addFB2ModifiersSupported() + && ((m_eglBackend->gpu()->isNVidia() && !modifiersEnvSet) || (modifiersEnvSet && modifiersEnv)); QSharedPointer gbmSurface; #if HAVE_GBM_BO_GET_FD_FOR_PLANE if (!allowModifiers) { #else // modifiers have to be disabled with multi-gpu if gbm_bo_get_fd_for_plane is not available - if (!allowModifiers || m_displayDevice->gpu() != m_renderGpu) { + if (!allowModifiers || m_displayDevice->gpu() != m_eglBackend->gpu()) { #endif int flags = GBM_BO_USE_RENDERING; - if (m_displayDevice->gpu() == m_renderGpu) { + if (m_displayDevice->gpu() == m_eglBackend->gpu()) { flags |= GBM_BO_USE_SCANOUT; } else { flags |= GBM_BO_USE_LINEAR; } - gbmSurface = QSharedPointer::create(m_renderGpu, size, format.value(), flags, config); + gbmSurface = QSharedPointer::create(m_eglBackend->gpu(), size, format.value(), flags, config); } else { - gbmSurface = QSharedPointer::create(m_renderGpu, size, format.value(), modifiers, config); + gbmSurface = QSharedPointer::create(m_eglBackend->gpu(), size, format.value(), modifiers, config); if (!gbmSurface->isValid()) { // the egl / gbm implementation may reject the modifier list from another gpu // as a fallback use linear, to at least make CPU copy more efficient const QVector linear = {DRM_FORMAT_MOD_LINEAR}; - gbmSurface = QSharedPointer::create(m_renderGpu, size, format.value(), linear, config); + gbmSurface = QSharedPointer::create(m_eglBackend->gpu(), size, format.value(), linear, config); } } if (!gbmSurface->isValid()) { @@ -237,12 +249,12 @@ QSharedPointer EglGbmLayer::texture() const qCWarning(KWIN_DRM) << "Failed to record frame: No gbm buffer!"; return nullptr; } - EGLImageKHR image = eglCreateImageKHR(m_renderGpu->eglDisplay(), nullptr, EGL_NATIVE_PIXMAP_KHR, gbmBuffer->getBo(), nullptr); + EGLImageKHR image = eglCreateImageKHR(m_eglBackend->eglDisplay(), nullptr, EGL_NATIVE_PIXMAP_KHR, gbmBuffer->getBo(), nullptr); if (image == EGL_NO_IMAGE_KHR) { qCWarning(KWIN_DRM) << "Failed to record frame: Error creating EGLImageKHR - " << glGetError(); return nullptr; } - return QSharedPointer::create(m_renderGpu->eglDisplay(), image, GL_RGBA8, m_displayDevice->sourceSize()); + return QSharedPointer::create(m_eglBackend->eglDisplay(), image, GL_RGBA8, m_displayDevice->sourceSize()); } QSharedPointer EglGbmLayer::importBuffer() @@ -455,7 +467,7 @@ void EglGbmLayer::sendDmabufFeedback(KWaylandServer::LinuxDmaBufV1ClientBuffer * if (const auto &drmOutput = dynamic_cast(m_displayDevice); drmOutput && m_scanoutCandidate.surface->dmabufFeedbackV1()) { QVector scanoutTranches; const auto &drmFormats = drmOutput->pipeline()->supportedFormats(); - const auto tranches = m_renderGpu->eglBackend()->dmabuf()->tranches(); + const auto tranches = m_eglBackend->dmabuf()->tranches(); for (const auto &tranche : tranches) { KWaylandServer::LinuxDmaBufV1Feedback::Tranche scanoutTranche; for (auto it = tranche.formatTable.constBegin(); it != tranche.formatTable.constEnd(); it++) { @@ -483,11 +495,6 @@ QSharedPointer EglGbmLayer::currentBuffer() const return m_scanoutBuffer ? m_scanoutBuffer : m_currentBuffer; } -DrmDisplayDevice *EglGbmLayer::displayDevice() const -{ - return m_displayDevice; -} - int EglGbmLayer::bufferAge() const { return m_gbmSurface ? m_gbmSurface->bufferAge() : 0; diff --git a/src/backends/drm/egl_gbm_layer.h b/src/backends/drm/egl_gbm_layer.h index 26b02a2de0..9ae3dacab2 100644 --- a/src/backends/drm/egl_gbm_layer.h +++ b/src/backends/drm/egl_gbm_layer.h @@ -32,11 +32,12 @@ class DrmBuffer; class DrmGpu; class SurfaceItem; class GLTexture; +class EglGbmBackend; class EglGbmLayer : public DrmLayer { public: - EglGbmLayer(DrmGpu *renderGpu, DrmDisplayDevice *displayDevice); + EglGbmLayer(EglGbmBackend *eglBackend, DrmDisplayDevice *displayDevice); ~EglGbmLayer(); std::optional startRendering() override; @@ -48,7 +49,6 @@ public: QRegion currentDamage() const override; QSharedPointer texture() const; - DrmDisplayDevice *displayDevice() const override; int bufferAge() const; EGLSurface eglSurface() const; @@ -59,6 +59,7 @@ private: bool doesSwapchainFit(DumbSwapchain *swapchain) const; void sendDmabufFeedback(KWaylandServer::LinuxDmaBufV1ClientBuffer *failedBuffer); bool renderTestBuffer(); + void destroyResources(); QSharedPointer importBuffer(); QSharedPointer importDmabuf(); @@ -88,8 +89,7 @@ private: QSharedPointer m_importSwapchain; QSharedPointer m_oldImportSwapchain; - DrmDisplayDevice *const m_displayDevice; - DrmGpu *const m_renderGpu; + EglGbmBackend *const m_eglBackend; }; } diff --git a/src/backends/drm/gbm_surface.cpp b/src/backends/drm/gbm_surface.cpp index 404ce9095f..77169fd3e3 100644 --- a/src/backends/drm/gbm_surface.cpp +++ b/src/backends/drm/gbm_surface.cpp @@ -16,13 +16,14 @@ #include "logging.h" #include "kwineglutils_p.h" #include "kwinglplatform.h" +#include "drm_backend.h" namespace KWin { GbmSurface::GbmSurface(DrmGpu *gpu, const QSize &size, uint32_t format, uint32_t flags, EGLConfig config) : m_surface(gbm_surface_create(gpu->gbmDevice(), size.width(), size.height(), format, flags)) - , m_gpu(gpu) + , m_eglBackend(static_cast(gpu->platform()->renderBackend())) , m_size(size) , m_format(format) , m_renderTarget(new GLRenderTarget(0, size)) @@ -31,7 +32,7 @@ GbmSurface::GbmSurface(DrmGpu *gpu, const QSize &size, uint32_t format, uint32_t qCCritical(KWIN_DRM) << "Could not create gbm surface!" << strerror(errno); return; } - m_eglSurface = eglCreatePlatformWindowSurfaceEXT(m_gpu->eglDisplay(), config, m_surface, nullptr); + m_eglSurface = eglCreatePlatformWindowSurfaceEXT(m_eglBackend->eglDisplay(), config, m_surface, nullptr); if (m_eglSurface == EGL_NO_SURFACE) { qCCritical(KWIN_DRM) << "Creating EGL surface failed!" << getEglErrorString(); } @@ -39,7 +40,7 @@ GbmSurface::GbmSurface(DrmGpu *gpu, const QSize &size, uint32_t format, uint32_t GbmSurface::GbmSurface(DrmGpu *gpu, const QSize &size, uint32_t format, QVector modifiers, EGLConfig config) : m_surface(gbm_surface_create_with_modifiers(gpu->gbmDevice(), size.width(), size.height(), format, modifiers.isEmpty() ? nullptr : modifiers.constData(), modifiers.count())) - , m_gpu(gpu) + , m_eglBackend(static_cast(gpu->platform()->renderBackend())) , m_size(size) , m_format(format) , m_modifiers(modifiers) @@ -49,7 +50,7 @@ GbmSurface::GbmSurface(DrmGpu *gpu, const QSize &size, uint32_t format, QVector< qCCritical(KWIN_DRM) << "Could not create gbm surface!" << strerror(errno); return; } - m_eglSurface = eglCreatePlatformWindowSurfaceEXT(m_gpu->eglDisplay(), config, m_surface, nullptr); + m_eglSurface = eglCreatePlatformWindowSurfaceEXT(m_eglBackend->eglDisplay(), config, m_surface, nullptr); if (m_eglSurface == EGL_NO_SURFACE) { qCCritical(KWIN_DRM) << "Creating EGL surface failed!" << getEglErrorString(); } @@ -62,7 +63,7 @@ GbmSurface::~GbmSurface() buffer->releaseBuffer(); } if (m_eglSurface != EGL_NO_SURFACE) { - eglDestroySurface(m_gpu->eglDisplay(), m_eglSurface); + eglDestroySurface(m_eglBackend->eglDisplay(), m_eglSurface); } if (m_surface) { gbm_surface_destroy(m_surface); @@ -71,7 +72,7 @@ GbmSurface::~GbmSurface() bool GbmSurface::makeContextCurrent() const { - if (eglMakeCurrent(m_gpu->eglDisplay(), m_eglSurface, m_eglSurface, m_gpu->eglBackend()->context()) == EGL_FALSE) { + if (eglMakeCurrent(m_eglBackend->eglDisplay(), m_eglSurface, m_eglSurface, m_eglBackend->context()) == EGL_FALSE) { qCCritical(KWIN_DRM) << "eglMakeCurrent failed:" << getEglErrorString(); return false; } @@ -83,7 +84,7 @@ bool GbmSurface::makeContextCurrent() const QSharedPointer GbmSurface::swapBuffersForDrm(const QRegion &dirty) { - auto error = eglSwapBuffers(m_gpu->eglDisplay(), m_eglSurface); + auto error = eglSwapBuffers(m_eglBackend->eglDisplay(), m_eglSurface); if (error != EGL_TRUE) { qCCritical(KWIN_DRM) << "an error occurred while swapping buffers" << getEglErrorString(); return nullptr; @@ -92,15 +93,15 @@ QSharedPointer GbmSurface::swapBuffersForDrm(const QRegion &dirty) if (!bo) { return nullptr; } - auto buffer = QSharedPointer::create(m_gpu, this, bo); + auto buffer = QSharedPointer::create(m_eglBackend->gpu(), this, bo); m_currentBuffer = buffer; m_lockedBuffers << m_currentBuffer.get(); if (!buffer->bufferId()) { return nullptr; } m_currentDrmBuffer = buffer; - if (m_gpu->eglBackend()->supportsBufferAge()) { - eglQuerySurface(m_gpu->eglDisplay(), m_eglSurface, EGL_BUFFER_AGE_EXT, &m_bufferAge); + if (m_eglBackend->supportsBufferAge()) { + eglQuerySurface(m_eglBackend->eglDisplay(), m_eglSurface, EGL_BUFFER_AGE_EXT, &m_bufferAge); m_damageJournal.add(dirty); } return buffer; @@ -108,7 +109,7 @@ QSharedPointer GbmSurface::swapBuffersForDrm(const QRegion &dirty) QSharedPointer GbmSurface::swapBuffers(const QRegion &dirty) { - auto error = eglSwapBuffers(m_gpu->eglDisplay(), m_eglSurface); + auto error = eglSwapBuffers(m_eglBackend->eglDisplay(), m_eglSurface); if (error != EGL_TRUE) { qCCritical(KWIN_DRM) << "an error occurred while swapping buffers" << getEglErrorString(); return nullptr; @@ -119,8 +120,8 @@ QSharedPointer GbmSurface::swapBuffers(const QRegion &dirty) } m_currentBuffer = QSharedPointer::create(this, bo); m_lockedBuffers << m_currentBuffer.get(); - if (m_gpu->eglBackend()->supportsBufferAge()) { - eglQuerySurface(m_gpu->eglDisplay(), m_eglSurface, EGL_BUFFER_AGE_EXT, &m_bufferAge); + if (m_eglBackend->supportsBufferAge()) { + eglQuerySurface(m_eglBackend->eglDisplay(), m_eglSurface, EGL_BUFFER_AGE_EXT, &m_bufferAge); m_damageJournal.add(dirty); } return m_currentBuffer; @@ -179,7 +180,7 @@ int GbmSurface::bufferAge() const QRegion GbmSurface::repaintRegion(const QRect &geometry) const { - if (m_gpu->eglBackend()->supportsBufferAge()) { + if (m_eglBackend->supportsBufferAge()) { return m_damageJournal.accumulate(m_bufferAge, geometry); } else { return geometry; diff --git a/src/backends/drm/gbm_surface.h b/src/backends/drm/gbm_surface.h index 367e55260d..67a9633122 100644 --- a/src/backends/drm/gbm_surface.h +++ b/src/backends/drm/gbm_surface.h @@ -24,6 +24,7 @@ namespace KWin { class GLRenderTarget; +class EglGbmBackend; class GbmSurface { @@ -52,7 +53,7 @@ public: private: gbm_surface *m_surface; - DrmGpu *m_gpu; + EglGbmBackend *const m_eglBackend; EGLSurface m_eglSurface = EGL_NO_SURFACE; QSize m_size; const uint32_t m_format; diff --git a/src/backends/drm/scene_qpainter_drm_backend.cpp b/src/backends/drm/scene_qpainter_drm_backend.cpp index 10f1cb4164..a85566e345 100644 --- a/src/backends/drm/scene_qpainter_drm_backend.cpp +++ b/src/backends/drm/scene_qpainter_drm_backend.cpp @@ -23,12 +23,12 @@ DrmQPainterBackend::DrmQPainterBackend(DrmBackend *backend) : QPainterBackend() , m_backend(backend) { - m_backend->primaryGpu()->setRenderBackend(this); + m_backend->setRenderBackend(this); } DrmQPainterBackend::~DrmQPainterBackend() { - m_backend->primaryGpu()->setRenderBackend(nullptr); + m_backend->setRenderBackend(nullptr); } QImage *DrmQPainterBackend::bufferForScreen(AbstractOutput *output) @@ -51,7 +51,7 @@ void DrmQPainterBackend::endFrame(AbstractOutput *output, const QRegion &rendere static_cast(output)->present(); } -QSharedPointer DrmQPainterBackend::createLayer(DrmDisplayDevice *displayDevice) const +QSharedPointer DrmQPainterBackend::createLayer(DrmDisplayDevice *displayDevice) { 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 d32ef13d90..17ab602d75 100644 --- a/src/backends/drm/scene_qpainter_drm_backend.h +++ b/src/backends/drm/scene_qpainter_drm_backend.h @@ -32,7 +32,10 @@ public: 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; + QSharedPointer createLayer(DrmDisplayDevice *displayDevice) override; + +Q_SIGNALS: + void aboutToBeDestroyed(); private: DrmBackend *m_backend;