diff --git a/src/abstract_wayland_output.cpp b/src/abstract_wayland_output.cpp index 3b7fb74b6e..8961614990 100644 --- a/src/abstract_wayland_output.cpp +++ b/src/abstract_wayland_output.cpp @@ -386,4 +386,14 @@ RenderLoop::VrrPolicy AbstractWaylandOutput::vrrPolicy() const return renderLoop()->vrrPolicy(); } +bool AbstractWaylandOutput::isPlaceholder() const +{ + return m_isPlaceholder; +} + +void AbstractWaylandOutput::setPlaceholder(bool isPlaceholder) +{ + m_isPlaceholder = isPlaceholder; +} + } diff --git a/src/abstract_wayland_output.h b/src/abstract_wayland_output.h index ce95278b14..4a98a08f4a 100644 --- a/src/abstract_wayland_output.h +++ b/src/abstract_wayland_output.h @@ -151,6 +151,8 @@ public: void setVrrPolicy(RenderLoop::VrrPolicy policy); RenderLoop::VrrPolicy vrrPolicy() const; + bool isPlaceholder() const; + Q_SIGNALS: void modeChanged(); void outputChange(const QRegion &damagedRegion); @@ -195,6 +197,7 @@ protected: void setCapabilityInternal(Capability capability, bool on = true); void setSubPixelInternal(SubPixel subPixel); void setOverscanInternal(uint32_t overscan); + void setPlaceholder(bool isPlaceholder); QSize orientateSize(const QSize &size) const; @@ -219,6 +222,7 @@ private: int m_recorders = 0; bool m_isEnabled = true; bool m_internal = false; + bool m_isPlaceholder = false; uint32_t m_overscan = 0; }; diff --git a/src/plugins/platforms/drm/CMakeLists.txt b/src/plugins/platforms/drm/CMakeLists.txt index f12fdb9978..2a59269acc 100644 --- a/src/plugins/platforms/drm/CMakeLists.txt +++ b/src/plugins/platforms/drm/CMakeLists.txt @@ -15,6 +15,8 @@ set(DRM_SOURCES dumb_swapchain.cpp shadowbuffer.cpp drm_pipeline.cpp + drm_abstract_output.cpp + drm_virtual_output.cpp ) if (HAVE_GBM) @@ -34,7 +36,7 @@ endif() add_library(KWinWaylandDrmBackend MODULE ${DRM_SOURCES}) set_target_properties(KWinWaylandDrmBackend PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/org.kde.kwin.waylandbackends/") -target_link_libraries(KWinWaylandDrmBackend kwin Libdrm::Libdrm SceneQPainterBackend SceneOpenGLBackend) +target_link_libraries(KWinWaylandDrmBackend kwin Libdrm::Libdrm SceneQPainterBackend SceneOpenGLBackend VsyncSupport) if (HAVE_GBM) target_link_libraries(KWinWaylandDrmBackend gbm::gbm) diff --git a/src/plugins/platforms/drm/abstract_egl_drm_backend.h b/src/plugins/platforms/drm/abstract_egl_drm_backend.h index 25be32f6ca..ef6a493c83 100644 --- a/src/plugins/platforms/drm/abstract_egl_drm_backend.h +++ b/src/plugins/platforms/drm/abstract_egl_drm_backend.h @@ -19,6 +19,7 @@ class DrmBackend; class DrmGpu; class DrmOutput; class DrmBuffer; +class DrmAbstractOutput; class AbstractEglDrmBackend : public AbstractEglBackend { @@ -26,27 +27,27 @@ class AbstractEglDrmBackend : public AbstractEglBackend public: virtual int screenCount() const = 0; - virtual bool addOutput(DrmOutput *output) = 0; - virtual void removeOutput(DrmOutput *output) = 0; - virtual bool swapBuffers(DrmOutput *output, const QRegion &dirty) { + virtual bool addOutput(DrmAbstractOutput *output) = 0; + virtual void removeOutput(DrmAbstractOutput *output) = 0; + virtual bool swapBuffers(DrmAbstractOutput *output, const QRegion &dirty) { Q_UNUSED(output) Q_UNUSED(dirty) return false; } - virtual bool exportFramebuffer(DrmOutput *output, void *data, const QSize &size, uint32_t stride) { + virtual bool exportFramebuffer(DrmAbstractOutput *output, void *data, const QSize &size, uint32_t stride) { Q_UNUSED(output) Q_UNUSED(data) Q_UNUSED(size) Q_UNUSED(stride) return false; } - virtual int exportFramebufferAsDmabuf(DrmOutput *output, uint32_t *format, uint32_t *stride) { + virtual int exportFramebufferAsDmabuf(DrmAbstractOutput *output, uint32_t *format, uint32_t *stride) { Q_UNUSED(output) Q_UNUSED(format) Q_UNUSED(stride) return 0; } - virtual QRegion beginFrameForSecondaryGpu(DrmOutput *output) { + virtual QRegion beginFrameForSecondaryGpu(DrmAbstractOutput *output) { Q_UNUSED(output) return QRegion(); } @@ -55,7 +56,7 @@ public: return m_gpu; } - virtual QSharedPointer renderTestFrame(DrmOutput *output) = 0; + virtual QSharedPointer renderTestFrame(DrmAbstractOutput *output) = 0; static AbstractEglDrmBackend *renderingBackend() { return static_cast(primaryBackend()); diff --git a/src/plugins/platforms/drm/drm_abstract_output.cpp b/src/plugins/platforms/drm/drm_abstract_output.cpp new file mode 100644 index 0000000000..84023e1735 --- /dev/null +++ b/src/plugins/platforms/drm/drm_abstract_output.cpp @@ -0,0 +1,59 @@ +/* + KWin - the KDE window manager + This file is part of the KDE project. + + SPDX-FileCopyrightText: 2021 Xaver Hugl + + SPDX-License-Identifier: GPL-2.0-or-later +*/ +#include "drm_abstract_output.h" +#include "drm_gpu.h" +#include "drm_backend.h" + +namespace KWin +{ + +DrmAbstractOutput::DrmAbstractOutput(DrmGpu *gpu) + : AbstractWaylandOutput(gpu->platform()) + , m_renderLoop(new RenderLoop(this)) + , m_gpu(gpu) +{ +} + +bool DrmAbstractOutput::initCursor(const QSize &cursorSize) +{ + Q_UNUSED(cursorSize) + return true; +} + +bool DrmAbstractOutput::showCursor() +{ + return true; +} + +bool DrmAbstractOutput::hideCursor() +{ + return true; +} + +bool DrmAbstractOutput::updateCursor() +{ + return true; +} + +bool DrmAbstractOutput::moveCursor() +{ + return true; +} + +DrmGpu *DrmAbstractOutput::gpu() const +{ + return m_gpu; +} + +RenderLoop *DrmAbstractOutput::renderLoop() const +{ + return m_renderLoop; +} + +} diff --git a/src/plugins/platforms/drm/drm_abstract_output.h b/src/plugins/platforms/drm/drm_abstract_output.h new file mode 100644 index 0000000000..619158c760 --- /dev/null +++ b/src/plugins/platforms/drm/drm_abstract_output.h @@ -0,0 +1,55 @@ +/* + KWin - the KDE window manager + This file is part of the KDE project. + + SPDX-FileCopyrightText: 2021 Xaver Hugl + + SPDX-License-Identifier: GPL-2.0-or-later +*/ +#pragma once + +#include "abstract_wayland_output.h" + +namespace KWin +{ + +class DrmBackend; +class DrmGpu; +class DrmBuffer; +class GbmBuffer; + +class DrmAbstractOutput : public AbstractWaylandOutput +{ + Q_OBJECT +public: + + virtual bool initCursor(const QSize &cursorSize); + virtual bool showCursor(); + virtual bool hideCursor(); + virtual bool updateCursor(); + virtual bool moveCursor(); + + virtual bool present(const QSharedPointer &buffer, QRegion damagedRegion) = 0; + + virtual bool isDpmsEnabled() const = 0; + virtual GbmBuffer *currentBuffer() const = 0; + virtual QSize sourceSize() const = 0; + + DrmGpu *gpu() const; + RenderLoop *renderLoop() const override; + +protected: + friend class DrmBackend; + friend class DrmGpu; + DrmAbstractOutput(DrmGpu *gpu); + + virtual void updateMode(int modeIndex) override { + Q_UNUSED(modeIndex) + } + virtual void updateMode(uint32_t width, uint32_t height, uint32_t refreshRate) = 0; + + RenderLoop *m_renderLoop; + DrmGpu *m_gpu; +}; + +} diff --git a/src/plugins/platforms/drm/drm_backend.cpp b/src/plugins/platforms/drm/drm_backend.cpp index b37e973477..669880447d 100644 --- a/src/plugins/platforms/drm/drm_backend.cpp +++ b/src/plugins/platforms/drm/drm_backend.cpp @@ -21,6 +21,10 @@ #include "session.h" #include "udev.h" #include "wayland_server.h" +#include "drm_gpu.h" +#include "egl_multi_backend.h" +#include "drm_pipeline.h" +#include "drm_virtual_output.h" #if HAVE_GBM #include "egl_gbm_backend.h" #include @@ -142,19 +146,23 @@ void DrmBackend::reactivate() m_active = true; for (const auto &output : qAsConst(m_outputs)) { - output->pipeline()->updateProperties(); - if (output->isEnabled()) { - if (output->gpu()->atomicModeSetting() && !output->pipeline()->isConnected()) { - output->pipeline()->setActive(false); + if (auto drmOutput = qobject_cast(output)) { + drmOutput->pipeline()->updateProperties(); + if (drmOutput->isEnabled()) { + if (drmOutput->gpu()->atomicModeSetting() && !drmOutput->pipeline()->isConnected()) { + drmOutput->pipeline()->setActive(false); + } + drmOutput->showCursor(); + } else { + drmOutput->pipeline()->setActive(false); } - output->renderLoop()->uninhibit(); - output->showCursor(); - } else { - output->pipeline()->setActive(false); } + output->renderLoop()->uninhibit(); } for (const auto &output : qAsConst(m_outputs)) { - output->pipeline()->setActive(output->isEnabled()); + if (auto drmOutput = qobject_cast(output)) { + drmOutput->pipeline()->setActive(output->isEnabled()); + } } if (Compositor *compositor = Compositor::self()) { @@ -173,9 +181,8 @@ void DrmBackend::deactivate() return; } - for (DrmOutput *output : qAsConst(m_outputs)) { + for (const auto &output : qAsConst(m_outputs)) { if (output->isEnabled()) { - output->hideCursor(); output->renderLoop()->inhibit(); } } @@ -318,7 +325,7 @@ DrmGpu *DrmBackend::addGpu(const QString &fileName) return gpu; } -void DrmBackend::addOutput(DrmOutput *o) +void DrmBackend::addOutput(DrmAbstractOutput *o) { m_outputs.append(o); m_enabledOutputs.append(o); @@ -326,7 +333,7 @@ void DrmBackend::addOutput(DrmOutput *o) Q_EMIT outputEnabled(o); } -void DrmBackend::removeOutput(DrmOutput *o) +void DrmBackend::removeOutput(DrmAbstractOutput *o) { if (m_enabledOutputs.removeOne(o)) { Q_EMIT outputDisabled(o); @@ -351,19 +358,38 @@ void DrmBackend::updateOutputs() } } - std::sort(m_outputs.begin(), m_outputs.end(), [] (DrmOutput *a, DrmOutput *b) { return a->pipeline()->connector()->id() < b->pipeline()->connector()->id(); }); + if (m_outputs.isEmpty()) { + qCDebug(KWIN_DRM) << "adding placeholder output"; + m_placeHolderOutput = primaryGpu()->createVirtualOutput(); + // placeholder doesn't actually need to render anything + m_placeHolderOutput->renderLoop()->inhibit(); + } else if (m_placeHolderOutput && m_outputs.count() > 1) { + qCDebug(KWIN_DRM) << "removing placeholder output"; + primaryGpu()->removeVirtualOutput(m_placeHolderOutput); + m_placeHolderOutput = nullptr; + } + + std::sort(m_outputs.begin(), m_outputs.end(), [] (DrmAbstractOutput *a, DrmAbstractOutput *b) { + auto da = qobject_cast(a); + auto db = qobject_cast(b); + if (da && !db) { + return true; + } else if (da && db) { + return da->pipeline()->connector()->id() < db->pipeline()->connector()->id(); + } else { + return false; + } + }); if (oldOutputs != m_outputs) { readOutputsConfiguration(); } - if (!m_outputs.isEmpty()) { - Q_EMIT screensQueried(); - } + Q_EMIT screensQueried(); } namespace KWinKScreenIntegration { /// See KScreen::Output::hashMd5 - QString outputHash(DrmOutput *output) + QString outputHash(DrmAbstractOutput *output) { QCryptographicHash hash(QCryptographicHash::Md5); if (!output->edid().isEmpty()) { @@ -375,7 +401,7 @@ namespace KWinKScreenIntegration } /// See KScreen::Config::connectedOutputsHash in libkscreen - QString connectedOutputsHash(const QVector &outputs) + QString connectedOutputsHash(const QVector &outputs) { QStringList hashedOutputs; hashedOutputs.reserve(outputs.count()); @@ -387,7 +413,7 @@ namespace KWinKScreenIntegration return QString::fromLatin1(hash.toHex()); } - QMap outputsConfig(const QVector &outputs) + QMap outputsConfig(const QVector &outputs) { const QString kscreenJsonPath = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("kscreen/") % connectedOutputsHash(outputs)); if (kscreenJsonPath.isEmpty()) { @@ -407,7 +433,7 @@ namespace KWinKScreenIntegration return {}; } - QMap ret; + QMap ret; const auto outputsJson = doc.array(); for (const auto &outputJson : outputsJson) { const auto outputObject = outputJson.toObject(); @@ -479,7 +505,7 @@ void DrmBackend::readOutputsConfiguration() } } -void DrmBackend::enableOutput(DrmOutput *output, bool enable) +void DrmBackend::enableOutput(DrmAbstractOutput *output, bool enable) { if (enable) { Q_ASSERT(!m_enabledOutputs.contains(output)); @@ -547,7 +573,7 @@ void DrmBackend::updateCursor() bool success = true; - for (DrmOutput *output : qAsConst(m_outputs)) { + for (DrmAbstractOutput *output : qAsConst(m_outputs)) { success = output->updateCursor(); if (!success) { qCDebug(KWIN_DRM) << "Failed to update cursor on output" << output->name(); diff --git a/src/plugins/platforms/drm/drm_backend.h b/src/plugins/platforms/drm/drm_backend.h index 0e6d6df90d..f26c7bf791 100644 --- a/src/plugins/platforms/drm/drm_backend.h +++ b/src/plugins/platforms/drm/drm_backend.h @@ -25,9 +25,10 @@ class Udev; class UdevMonitor; class UdevDevice; -class DrmOutput; +class DrmAbstractOutput; class Cursor; class DrmGpu; +class DrmVirtualOutput; class KWIN_EXPORT DrmBackend : public Platform { @@ -46,14 +47,14 @@ public: Outputs outputs() const override; Outputs enabledOutputs() const override; - QVector drmOutputs() const { + QVector drmOutputs() const { return m_outputs; } - QVector drmEnabledOutputs() const { + QVector drmEnabledOutputs() const { return m_enabledOutputs; } - void enableOutput(DrmOutput *output, bool enable); + void enableOutput(DrmAbstractOutput *output, bool enable); void createDpmsFilter(); void checkOutputsAreOn(); @@ -81,8 +82,8 @@ protected: private: friend class DrmGpu; - void addOutput(DrmOutput* output); - void removeOutput(DrmOutput* output); + void addOutput(DrmAbstractOutput* output); + void removeOutput(DrmAbstractOutput* output); void activate(bool active); void reactivate(); void deactivate(); @@ -97,10 +98,11 @@ private: QScopedPointer m_udev; QScopedPointer m_udevMonitor; Session *m_session = nullptr; - // active output pipelines (planes + crtc + encoder + connector) - QVector m_outputs; - // active and enabled pipelines (above + wl_output) - QVector m_enabledOutputs; + // all outputs, enabled and disabled + QVector m_outputs; + // only enabled outputs + QVector m_enabledOutputs; + DrmVirtualOutput *m_placeHolderOutput = nullptr; bool m_active = false; QVector m_gpus; diff --git a/src/plugins/platforms/drm/drm_gpu.cpp b/src/plugins/platforms/drm/drm_gpu.cpp index 405d7ec8f3..38449a9f53 100644 --- a/src/plugins/platforms/drm/drm_gpu.cpp +++ b/src/plugins/platforms/drm/drm_gpu.cpp @@ -19,6 +19,7 @@ #include "renderloop_p.h" #include "main.h" #include "drm_pipeline.h" +#include "drm_virtual_output.h" #if HAVE_GBM #include "egl_gbm_backend.h" @@ -91,7 +92,11 @@ DrmGpu::~DrmGpu() waitIdle(); const auto outputs = m_outputs; for (const auto &output : outputs) { - removeOutput(output); + if (auto drmOutput = qobject_cast(output)) { + removeOutput(drmOutput); + } else { + removeVirtualOutput(dynamic_cast(output)); + } } if (m_eglDisplay != EGL_NO_DISPLAY) { eglTerminate(m_eglDisplay); @@ -219,14 +224,14 @@ bool DrmGpu::updateOutputs() // check for outputs which got removed QVector removedOutputs; - auto it = m_outputs.begin(); - while (it != m_outputs.end()) { + auto it = m_drmOutputs.begin(); + while (it != m_drmOutputs.end()) { if (connectedOutputs.contains(*it)) { it++; continue; } DrmOutput *removed = *it; - it = m_outputs.erase(it); + it = m_drmOutputs.erase(it); removedOutputs.append(removed); } @@ -272,7 +277,7 @@ bool DrmGpu::updateOutputs() } auto pipeline = new DrmPipeline(this, con, crtc, primary); - DrmOutput *output = new DrmOutput(m_backend, this, pipeline); + DrmOutput *output = new DrmOutput(this, pipeline); // outputEnabled only adds it to the render backend but not to the platform // this is necessary for accurate pipeline tests @@ -296,6 +301,7 @@ bool DrmGpu::updateOutputs() qCDebug(KWIN_DRM, "For new output %s on GPU %s use mode %dx%d@%d", qPrintable(output->name()), qPrintable(m_devNode), output->modeSize().width(), output->modeSize().height(), output->refreshRate()); connectedOutputs << output; + m_outputs << output; outputDone = true; break; } @@ -304,8 +310,7 @@ bool DrmGpu::updateOutputs() } } } - std::sort(connectedOutputs.begin(), connectedOutputs.end(), [] (DrmOutput *a, DrmOutput *b) { return a->m_pipeline->connector()->id() < b->m_pipeline->connector()->id(); }); - m_outputs = connectedOutputs; + m_drmOutputs = connectedOutputs; for(DrmOutput *removedOutput : removedOutputs) { removeOutput(removedOutput); @@ -318,10 +323,10 @@ bool DrmGpu::updateOutputs() DrmOutput *DrmGpu::findOutput(quint32 connector) { - auto it = std::find_if(m_outputs.constBegin(), m_outputs.constEnd(), [connector] (DrmOutput *o) { + auto it = std::find_if(m_drmOutputs.constBegin(), m_drmOutputs.constEnd(), [connector] (DrmOutput *o) { return o->m_pipeline->connector()->id() == connector; }); - if (it != m_outputs.constEnd()) { + if (it != m_drmOutputs.constEnd()) { return *it; } return nullptr; @@ -345,7 +350,7 @@ void DrmGpu::waitIdle() { m_socketNotifier->setEnabled(false); while (true) { - const bool idle = std::all_of(m_outputs.constBegin(), m_outputs.constEnd(), [](DrmOutput *output){ + const bool idle = std::all_of(m_drmOutputs.constBegin(), m_drmOutputs.constEnd(), [](DrmOutput *output){ return !output->m_pageFlipPending; }); if (idle) { @@ -397,7 +402,6 @@ static void pageFlipHandler(int fd, unsigned int frame, unsigned int sec, unsign { Q_UNUSED(fd) Q_UNUSED(frame) - auto backend = dynamic_cast(kwinApp()->platform()); if (!backend) { return; @@ -444,6 +448,7 @@ void DrmGpu::dispatchEvents() void DrmGpu::removeOutput(DrmOutput *output) { + m_drmOutputs.removeOne(output); m_outputs.removeOne(output); Q_EMIT outputDisabled(output); Q_EMIT outputRemoved(output); @@ -476,4 +481,23 @@ const QVector DrmGpu::pipelines() const return m_pipelines; } +DrmVirtualOutput *DrmGpu::createVirtualOutput() +{ + auto output = new DrmVirtualOutput(this); + output->setPlaceholder(true); + m_outputs << output; + Q_EMIT outputEnabled(output); + Q_EMIT outputAdded(output); + return output; +} + +void DrmGpu::removeVirtualOutput(DrmVirtualOutput *output) +{ + if (m_outputs.removeOne(output)) { + Q_EMIT outputDisabled(output); + Q_EMIT outputRemoved(output); + delete output; + } +} + } diff --git a/src/plugins/platforms/drm/drm_gpu.h b/src/plugins/platforms/drm/drm_gpu.h index c8d0450da7..b6ef14b025 100644 --- a/src/plugins/platforms/drm/drm_gpu.h +++ b/src/plugins/platforms/drm/drm_gpu.h @@ -31,6 +31,8 @@ class DrmConnector; class DrmBackend; class AbstractEglDrmBackend; class DrmPipeline; +class DrmAbstractOutput; +class DrmVirtualOutput; class DrmGpu : public QObject { @@ -40,7 +42,7 @@ public: ~DrmGpu(); // getters - QVector outputs() const { + QVector outputs() const { return m_outputs; } @@ -97,11 +99,14 @@ public: DrmBackend *platform() const; const QVector pipelines() const; + DrmVirtualOutput *createVirtualOutput(); + void removeVirtualOutput(DrmVirtualOutput *output); + Q_SIGNALS: - void outputAdded(DrmOutput *output); - void outputRemoved(DrmOutput *output); - void outputEnabled(DrmOutput *output); - void outputDisabled(DrmOutput *output); + void outputAdded(DrmAbstractOutput *output); + void outputRemoved(DrmAbstractOutput *output); + void outputEnabled(DrmAbstractOutput *output); + void outputDisabled(DrmAbstractOutput *output); protected: friend class DrmBackend; @@ -138,7 +143,9 @@ private: QVector m_connectors; // pipelines QVector m_pipelines; - QVector m_outputs; + QVector m_drmOutputs; + // includes virtual outputs + QVector m_outputs; }; } diff --git a/src/plugins/platforms/drm/drm_output.cpp b/src/plugins/platforms/drm/drm_output.cpp index a8b9ba6ebc..a26a91b372 100644 --- a/src/plugins/platforms/drm/drm_output.cpp +++ b/src/plugins/platforms/drm/drm_output.cpp @@ -12,6 +12,9 @@ #include "drm_object_connector.h" #include "drm_gpu.h" #include "drm_pipeline.h" +#if HAVE_GBM +#include "drm_buffer_gbm.h" +#endif #include "composite.h" #include "cursor.h" @@ -34,12 +37,9 @@ namespace KWin { -DrmOutput::DrmOutput(DrmBackend *backend, DrmGpu *gpu, DrmPipeline *pipeline) - : AbstractWaylandOutput(backend) - , m_backend(backend) - , m_gpu(gpu) +DrmOutput::DrmOutput(DrmGpu *gpu, DrmPipeline *pipeline) + : DrmAbstractOutput(gpu) , m_pipeline(pipeline) - , m_renderLoop(new RenderLoop(this)) { m_pipeline->setUserData(this); auto conn = m_pipeline->connector(); @@ -72,11 +72,6 @@ DrmOutput::~DrmOutput() } } -RenderLoop *DrmOutput::renderLoop() const -{ - return m_renderLoop; -} - bool DrmOutput::initCursor(const QSize &cursorSize) { m_cursor = QSharedPointer::create(m_gpu, cursorSize); @@ -214,7 +209,7 @@ void DrmOutput::initOutputDevice() void DrmOutput::updateEnablement(bool enable) { if (m_pipeline->setActive(enable)) { - m_backend->enableOutput(this, enable); + m_gpu->platform()->enableOutput(this, enable); } else { qCCritical(KWIN_DRM) << "failed to update enablement to" << enable; } @@ -228,7 +223,7 @@ void DrmOutput::setDpmsMode(DpmsMode mode) m_turnOffTimer.start(); } if (isEnabled()) { - m_backend->createDpmsFilter(); + m_gpu->platform()->createDpmsFilter(); } } else { m_turnOffTimer.stop(); @@ -255,13 +250,13 @@ void DrmOutput::setDrmDpmsMode(DpmsMode mode) setDpmsModeInternal(mode); if (active) { m_renderLoop->uninhibit(); - m_backend->checkOutputsAreOn(); + m_gpu->platform()->checkOutputsAreOn(); if (Compositor *compositor = Compositor::self()) { compositor->addRepaintFull(); } } else { m_renderLoop->inhibit(); - m_backend->createDpmsFilter(); + m_gpu->platform()->createDpmsFilter(); } } else { qCCritical(KWIN_DRM) << "failed to set active to" << active; @@ -293,11 +288,6 @@ DrmPlane::Transformations outputToPlaneTransform(DrmOutput::Transform transform) } } -bool DrmOutput::hardwareTransforms() const -{ - return m_pipeline->transformation() == outputToPlaneTransform(transform()); -} - void DrmOutput::updateTransform(Transform transform) { const auto planeTransform = outputToPlaneTransform(transform); @@ -309,7 +299,7 @@ void DrmOutput::updateTransform(Transform transform) } // show cursor only if is enabled, i.e if pointer device is present - if (!m_backend->isCursorHidden() && !m_backend->usesSoftwareCursor()) { + if (!m_gpu->platform()->isCursorHidden() && !m_gpu->platform()->usesSoftwareCursor()) { // the cursor might need to get rotated showCursor(); updateCursor(); @@ -394,9 +384,13 @@ DrmPipeline *DrmOutput::pipeline() const return m_pipeline; } -DrmBuffer *DrmOutput::currentBuffer() const +GbmBuffer *DrmOutput::currentBuffer() const { - return m_pipeline->currentBuffer(); +#if HAVE_GBM + return dynamic_cast(m_pipeline->currentBuffer()); +#else + return nullptr; +#endif } bool DrmOutput::isDpmsEnabled() const @@ -404,4 +398,9 @@ bool DrmOutput::isDpmsEnabled() const return m_pipeline->isActive(); } +QSize DrmOutput::sourceSize() const +{ + return m_pipeline->sourceSize(); +} + } diff --git a/src/plugins/platforms/drm/drm_output.h b/src/plugins/platforms/drm/drm_output.h index d8fca89e95..b7886319be 100644 --- a/src/plugins/platforms/drm/drm_output.h +++ b/src/plugins/platforms/drm/drm_output.h @@ -9,7 +9,7 @@ #ifndef KWIN_DRM_OUTPUT_H #define KWIN_DRM_OUTPUT_H -#include "abstract_wayland_output.h" +#include "drm_abstract_output.h" #include "drm_pointer.h" #include "drm_object.h" #include "drm_object_plane.h" @@ -34,44 +34,31 @@ class Cursor; class DrmGpu; class DrmPipeline; -class KWIN_EXPORT DrmOutput : public AbstractWaylandOutput +class KWIN_EXPORT DrmOutput : public DrmAbstractOutput { Q_OBJECT public: ///deletes the output, calling this whilst a page flip is pending will result in an error ~DrmOutput() override; - RenderLoop *renderLoop() const override; + bool initCursor(const QSize &cursorSize) override; + bool showCursor() override; + bool hideCursor() override; + bool updateCursor() override; + bool moveCursor() override; - bool showCursor(); - bool hideCursor(); - bool updateCursor(); - bool moveCursor(); - bool present(const QSharedPointer &buffer, QRegion damagedRegion); + bool present(const QSharedPointer &buffer, QRegion damagedRegion) override; void pageFlipped(); - bool isDpmsEnabled() const; + bool isDpmsEnabled() const override; DrmPipeline *pipeline() const; - DrmBuffer *currentBuffer() const; - - bool initCursor(const QSize &cursorSize); - - /** - * Drm planes might be capable of realizing the current output transform without usage - * of compositing. This is a getter to query the current state of that - * - * @return true if the hardware realizes the transform without further assistance - */ - bool hardwareTransforms() const; - - DrmGpu *gpu() { - return m_gpu; - } + GbmBuffer *currentBuffer() const override; + QSize sourceSize() const override; private: friend class DrmGpu; friend class DrmBackend; - DrmOutput(DrmBackend *backend, DrmGpu* gpu, DrmPipeline *pipeline); + DrmOutput(DrmGpu* gpu, DrmPipeline *pipeline); void initOutputDevice(); bool isCurrentMode(const drmModeModeInfo *mode) const; @@ -80,17 +67,14 @@ private: void setDrmDpmsMode(DpmsMode mode); void setDpmsMode(DpmsMode mode) override; void updateMode(int modeIndex) override; - void updateMode(uint32_t width, uint32_t height, uint32_t refreshRate); + void updateMode(uint32_t width, uint32_t height, uint32_t refreshRate) override; void updateTransform(Transform transform) override; int gammaRampSize() const override; bool setGammaRamp(const GammaRamp &gamma) override; void setOverscan(uint32_t overscan) override; - DrmBackend *m_backend; - DrmGpu *m_gpu; DrmPipeline *m_pipeline; - RenderLoop *m_renderLoop; QSharedPointer m_cursor; bool m_pageFlipPending = false; diff --git a/src/plugins/platforms/drm/drm_pipeline.cpp b/src/plugins/platforms/drm/drm_pipeline.cpp index 6b8571c4c8..ac38520cd0 100644 --- a/src/plugins/platforms/drm/drm_pipeline.cpp +++ b/src/plugins/platforms/drm/drm_pipeline.cpp @@ -19,7 +19,7 @@ #include "drm_buffer.h" #include "cursor.h" #include "session.h" -#include "abstract_output.h" +#include "drm_output.h" #include "drm_backend.h" #if HAVE_GBM diff --git a/src/plugins/platforms/drm/drm_virtual_output.cpp b/src/plugins/platforms/drm/drm_virtual_output.cpp new file mode 100644 index 0000000000..35ed1c2fa1 --- /dev/null +++ b/src/plugins/platforms/drm/drm_virtual_output.cpp @@ -0,0 +1,108 @@ +/* + KWin - the KDE window manager + This file is part of the KDE project. + + SPDX-FileCopyrightText: 2018 Roman Gilg + SPDX-FileCopyrightText: 2021 Xaver Hugl + + SPDX-License-Identifier: GPL-2.0-or-later +*/ +#include "drm_virtual_output.h" + +#include "renderloop_p.h" +#include "softwarevsyncmonitor.h" +#include "drm_gpu.h" +#include "drm_backend.h" +#include "logging.h" +#if HAVE_GBM +#include "drm_buffer_gbm.h" +#endif + +namespace KWin +{ + +DrmVirtualOutput::DrmVirtualOutput(DrmGpu *gpu) + : DrmAbstractOutput(gpu) + , m_vsyncMonitor(SoftwareVsyncMonitor::create(this)) +{ + connect(m_vsyncMonitor, &VsyncMonitor::vblankOccurred, this, &DrmVirtualOutput::vblank); + + static int s_serial = 0; + m_identifier = s_serial++; + setName("Virtual-" + QString::number(m_identifier)); + m_modeIndex = 0; + QVector modes = {{{1920, 1080}, 60000, AbstractWaylandOutput::ModeFlags(AbstractWaylandOutput::ModeFlag::Current) | AbstractWaylandOutput::ModeFlag::Preferred, 0}}; + initialize(QByteArray("model_").append(QByteArray::number(m_identifier)), + QByteArray("manufacturer_").append(QByteArray::number(m_identifier)), + QByteArray("eisa_").append(QByteArray::number(m_identifier)), + QByteArray("serial_").append(QByteArray::number(m_identifier)), + modes[m_modeIndex].size, modes, QByteArray("EDID_").append(QByteArray::number(m_identifier))); + m_renderLoop->setRefreshRate(modes[m_modeIndex].refreshRate); +} + +DrmVirtualOutput::~DrmVirtualOutput() +{ +} + +bool DrmVirtualOutput::present(const QSharedPointer &buffer, QRegion damagedRegion) +{ + Q_UNUSED(damagedRegion) + + m_currentBuffer = buffer; + m_vsyncMonitor->arm(); + m_pageFlipPending = true; + Q_EMIT outputChange(damagedRegion); + return true; +} + +void DrmVirtualOutput::vblank(std::chrono::nanoseconds timestamp) +{ + if (m_pageFlipPending) { + RenderLoopPrivate *renderLoopPrivate = RenderLoopPrivate::get(m_renderLoop); + renderLoopPrivate->notifyFrameCompleted(timestamp); + } +} + +void DrmVirtualOutput::updateMode(int modeIndex) +{ + Q_UNUSED(modeIndex) +} + +void DrmVirtualOutput::updateMode(uint32_t width, uint32_t height, uint32_t refreshRate) +{ + Q_UNUSED(width) + Q_UNUSED(height) + Q_UNUSED(refreshRate) +} + +void DrmVirtualOutput::setDpmsMode(DpmsMode mode) +{ + setDpmsModeInternal(mode); + m_dpmsEnabled = mode == DpmsMode::On; +} + +bool DrmVirtualOutput::isDpmsEnabled() const +{ + return m_dpmsEnabled; +} + +void DrmVirtualOutput::updateEnablement(bool enable) +{ + gpu()->platform()->enableOutput(this, enable); +} + +QSize DrmVirtualOutput::sourceSize() const +{ + return pixelSize(); +} + +GbmBuffer *DrmVirtualOutput::currentBuffer() const +{ +#if HAVE_GBM + return dynamic_cast(m_currentBuffer.get()); +#else + return nullptr; +#endif +} + +} diff --git a/src/plugins/platforms/drm/drm_virtual_output.h b/src/plugins/platforms/drm/drm_virtual_output.h new file mode 100644 index 0000000000..6ad02a58b8 --- /dev/null +++ b/src/plugins/platforms/drm/drm_virtual_output.h @@ -0,0 +1,60 @@ +/* + KWin - the KDE window manager + This file is part of the KDE project. + + SPDX-FileCopyrightText: 2018 Roman Gilg + SPDX-FileCopyrightText: 2021 Xaver Hugl + + SPDX-License-Identifier: GPL-2.0-or-later +*/ +#pragma once + +#include "drm_abstract_output.h" + +#include +#include + +namespace KWin +{ + +class SoftwareVsyncMonitor; +class VirtualBackend; + +class DrmVirtualOutput : public DrmAbstractOutput +{ + Q_OBJECT +public: + DrmVirtualOutput(DrmGpu *gpu); + ~DrmVirtualOutput() override; + + bool present(const QSharedPointer &buffer, QRegion damagedRegion) override; + GbmBuffer *currentBuffer() const override; + QSize sourceSize() const override; + bool isDpmsEnabled() const override; + + int gammaRampSize() const override { + return 200; + } + bool setGammaRamp(const GammaRamp &gamma) override { + Q_UNUSED(gamma); + return true; + } + + +private: + void vblank(std::chrono::nanoseconds timestamp); + void updateMode(int modeIndex) override; + void updateMode(uint32_t width, uint32_t height, uint32_t refreshRate) override; + void setDpmsMode(DpmsMode mode) override; + void updateEnablement(bool enable) override; + + QSharedPointer m_currentBuffer; + bool m_pageFlipPending = true; + int m_modeIndex = 0; + bool m_dpmsEnabled = true; + + int m_identifier; + SoftwareVsyncMonitor *m_vsyncMonitor; +}; + +} diff --git a/src/plugins/platforms/drm/egl_gbm_backend.cpp b/src/plugins/platforms/drm/egl_gbm_backend.cpp index 584f091911..cd33326f66 100644 --- a/src/plugins/platforms/drm/egl_gbm_backend.cpp +++ b/src/plugins/platforms/drm/egl_gbm_backend.cpp @@ -144,10 +144,10 @@ bool EglGbmBackend::initRenderingContext() } return true; } -bool EglGbmBackend::resetOutput(Output &output, DrmOutput *drmOutput) +bool EglGbmBackend::resetOutput(Output &output, DrmAbstractOutput *drmOutput) { output.output = drmOutput; - const QSize size = drmOutput->pipeline()->sourceSize(); + const QSize size = drmOutput->sourceSize(); int flags = GBM_BO_USE_RENDERING; if (drmOutput->gpu() == m_gpu) { flags |= GBM_BO_USE_SCANOUT; @@ -164,7 +164,7 @@ bool EglGbmBackend::resetOutput(Output &output, DrmOutput *drmOutput) output.current = {}; output.current.gbmSurface = gbmSurface; - if (output.output->hardwareTransforms()) { + if (size == drmOutput->pixelSize()) { output.current.shadowBuffer = nullptr; } else { makeContextCurrent(output.current); @@ -176,7 +176,7 @@ bool EglGbmBackend::resetOutput(Output &output, DrmOutput *drmOutput) return true; } -bool EglGbmBackend::addOutput(DrmOutput *drmOutput) +bool EglGbmBackend::addOutput(DrmAbstractOutput *drmOutput) { if (isPrimary()) { Output newOutput; @@ -199,7 +199,7 @@ bool EglGbmBackend::addOutput(DrmOutput *drmOutput) return true; } -void EglGbmBackend::removeOutput(DrmOutput *drmOutput) +void EglGbmBackend::removeOutput(DrmAbstractOutput *drmOutput) { QVector &outputs = drmOutput->gpu() == m_gpu ? m_outputs : m_secondaryGpuOutputs; auto it = std::find_if(outputs.begin(), outputs.end(), @@ -219,7 +219,7 @@ void EglGbmBackend::removeOutput(DrmOutput *drmOutput) outputs.erase(it); } -bool EglGbmBackend::swapBuffers(DrmOutput *drmOutput, const QRegion &dirty) +bool EglGbmBackend::swapBuffers(DrmAbstractOutput *drmOutput, const QRegion &dirty) { auto it = std::find_if(m_secondaryGpuOutputs.begin(), m_secondaryGpuOutputs.end(), [drmOutput] (const Output &output) { @@ -240,7 +240,7 @@ bool EglGbmBackend::swapBuffers(DrmOutput *drmOutput, const QRegion &dirty) } } -bool EglGbmBackend::exportFramebuffer(DrmOutput *drmOutput, void *data, const QSize &size, uint32_t stride) +bool EglGbmBackend::exportFramebuffer(DrmAbstractOutput *drmOutput, void *data, const QSize &size, uint32_t stride) { auto it = std::find_if(m_secondaryGpuOutputs.begin(), m_secondaryGpuOutputs.end(), [drmOutput] (const Output &output) { @@ -261,9 +261,8 @@ bool EglGbmBackend::exportFramebuffer(DrmOutput *drmOutput, void *data, const QS return memcpy(data, bo->mappedData(), size.height() * stride); } -int EglGbmBackend::exportFramebufferAsDmabuf(DrmOutput *output, uint32_t *format, uint32_t *stride) +int EglGbmBackend::exportFramebufferAsDmabuf(DrmAbstractOutput *drmOutput, uint32_t *format, uint32_t *stride) { - DrmOutput *drmOutput = static_cast(output); auto it = std::find_if(m_secondaryGpuOutputs.begin(), m_secondaryGpuOutputs.end(), [drmOutput] (const Output &output) { return output.output == drmOutput; @@ -283,7 +282,7 @@ int EglGbmBackend::exportFramebufferAsDmabuf(DrmOutput *output, uint32_t *format return fd; } -QRegion EglGbmBackend::beginFrameForSecondaryGpu(DrmOutput *drmOutput) +QRegion EglGbmBackend::beginFrameForSecondaryGpu(DrmAbstractOutput *drmOutput) { auto it = std::find_if(m_secondaryGpuOutputs.begin(), m_secondaryGpuOutputs.end(), [drmOutput] (const Output &output) { @@ -492,12 +491,12 @@ QRegion EglGbmBackend::beginFrame(int screenId) } } -bool EglGbmBackend::doesRenderFit(DrmOutput *output, const Output::RenderData &render) +bool EglGbmBackend::doesRenderFit(DrmAbstractOutput *output, const Output::RenderData &render) { if (!render.gbmSurface) { return false; } - QSize surfaceSize = output->pipeline()->sourceSize(); + QSize surfaceSize = output->sourceSize(); if (surfaceSize != render.gbmSurface->size()) { return false; } @@ -558,13 +557,12 @@ void EglGbmBackend::endFrame(int screenId, const QRegion &renderedRegion, Q_UNUSED(renderedRegion) Output &output = m_outputs[screenId]; - DrmOutput *drmOutput = output.output; cleanupRenderData(output.old); const QRegion dirty = damagedRegion.intersected(output.output->geometry()); QSharedPointer buffer = endFrameWithBuffer(screenId, dirty); if (!buffer || !output.output->present(buffer, dirty)) { - RenderLoopPrivate *renderLoopPrivate = RenderLoopPrivate::get(drmOutput->renderLoop()); + RenderLoopPrivate *renderLoopPrivate = RenderLoopPrivate::get(output.output->renderLoop()); renderLoopPrivate->notifyFrameFailed(); return; } @@ -667,7 +665,7 @@ bool EglGbmBackend::scanout(int screenId, SurfaceItem *surfaceItem) } } -QSharedPointer EglGbmBackend::renderTestFrame(DrmOutput *output) +QSharedPointer EglGbmBackend::renderTestFrame(DrmAbstractOutput *output) { for (int i = 0; i < m_outputs.count(); i++) { if (m_outputs[i].output == output) { @@ -697,7 +695,7 @@ QSharedPointer EglGbmBackend::textureForOutput(AbstractOutput *abstra } } - DrmOutput *drmOutput = itOutput->output; + DrmAbstractOutput *drmOutput = itOutput->output; if (itOutput->current.shadowBuffer) { const auto glTexture = QSharedPointer::create(itOutput->current.shadowBuffer->texture(), GL_RGBA8, drmOutput->pixelSize()); glTexture->setYInverted(true); diff --git a/src/plugins/platforms/drm/egl_gbm_backend.h b/src/plugins/platforms/drm/egl_gbm_backend.h index 90a524888f..82b45f63e7 100644 --- a/src/plugins/platforms/drm/egl_gbm_backend.h +++ b/src/plugins/platforms/drm/egl_gbm_backend.h @@ -58,16 +58,16 @@ public: return m_outputs.count(); } - bool addOutput(DrmOutput *output) override; - void removeOutput(DrmOutput *output) override; - bool swapBuffers(DrmOutput *output, const QRegion &dirty) override; - bool exportFramebuffer(DrmOutput *output, void *data, const QSize &size, uint32_t stride) override; - int exportFramebufferAsDmabuf(DrmOutput *output, uint32_t *format, uint32_t *stride) override; - QRegion beginFrameForSecondaryGpu(DrmOutput *output) override; + bool addOutput(DrmAbstractOutput *output) override; + void removeOutput(DrmAbstractOutput *output) override; + bool swapBuffers(DrmAbstractOutput *output, const QRegion &dirty) override; + bool exportFramebuffer(DrmAbstractOutput *output, void *data, const QSize &size, uint32_t stride) override; + int exportFramebufferAsDmabuf(DrmAbstractOutput *output, uint32_t *format, uint32_t *stride) override; + QRegion beginFrameForSecondaryGpu(DrmAbstractOutput *output) override; bool directScanoutAllowed(int screen) const override; - QSharedPointer renderTestFrame(DrmOutput *output) override; + QSharedPointer renderTestFrame(DrmAbstractOutput *output) override; protected: void cleanupSurfaces() override; @@ -83,7 +83,7 @@ private: DumbBuffer }; struct Output { - DrmOutput *output = nullptr; + DrmAbstractOutput *output = nullptr; struct RenderData { QSharedPointer shadowBuffer; QSharedPointer gbmSurface; @@ -98,8 +98,8 @@ private: KWaylandServer::SurfaceInterface *surfaceInterface = nullptr; }; - bool doesRenderFit(DrmOutput *output, const Output::RenderData &render); - bool resetOutput(Output &output, DrmOutput *drmOutput); + bool doesRenderFit(DrmAbstractOutput *output, const Output::RenderData &render); + bool resetOutput(Output &output, DrmAbstractOutput *drmOutput); bool makeContextCurrent(const Output::RenderData &output) const; void setViewport(const Output &output) const; diff --git a/src/plugins/platforms/drm/egl_stream_backend.cpp b/src/plugins/platforms/drm/egl_stream_backend.cpp index ae97494ee1..0e59f662e2 100644 --- a/src/plugins/platforms/drm/egl_stream_backend.cpp +++ b/src/plugins/platforms/drm/egl_stream_backend.cpp @@ -281,7 +281,7 @@ void EglStreamBackend::init() } else { // secondary NVidia GPUs only import dumb buffers const auto outputs = m_gpu->outputs(); - for (DrmOutput *drmOutput : outputs) { + for (DrmAbstractOutput *drmOutput : outputs) { addOutput(drmOutput); } } @@ -296,7 +296,7 @@ bool EglStreamBackend::initRenderingContext() } const auto outputs = m_gpu->outputs(); - for (DrmOutput *drmOutput : outputs) { + for (DrmAbstractOutput *drmOutput : outputs) { addOutput(drmOutput); } return !m_outputs.isEmpty() && makeContextCurrent(m_outputs.first()); @@ -305,7 +305,7 @@ bool EglStreamBackend::initRenderingContext() bool EglStreamBackend::resetOutput(Output &o, DrmOutput *drmOutput) { o.output = drmOutput; - QSize sourceSize = drmOutput->pipeline()->sourceSize(); + QSize sourceSize = drmOutput->sourceSize(); if (isPrimary()) { // dumb buffer used for modesetting @@ -366,7 +366,7 @@ bool EglStreamBackend::resetOutput(Output &o, DrmOutput *drmOutput) o.eglStream = stream; o.eglSurface = eglSurface; - if (!drmOutput->hardwareTransforms()) { + if (sourceSize != drmOutput->pixelSize()) { makeContextCurrent(o); o.shadowBuffer = QSharedPointer::create(o.output->pixelSize()); if (!o.shadowBuffer->isComplete()) { @@ -383,35 +383,40 @@ bool EglStreamBackend::resetOutput(Output &o, DrmOutput *drmOutput) return true; } -bool EglStreamBackend::addOutput(DrmOutput *drmOutput) +bool EglStreamBackend::addOutput(DrmAbstractOutput *output) { - Q_ASSERT(drmOutput->gpu() == m_gpu); - Output o; - if (!resetOutput(o, drmOutput)) { - return false; - } - if (!isPrimary() && !renderingBackend()->addOutput(drmOutput)) { - return false; - } - - connect(drmOutput, &DrmOutput::modeChanged, this, - [drmOutput, this] { - auto it = std::find_if(m_outputs.begin(), m_outputs.end(), - [drmOutput] (const auto &o) { - return o.output == drmOutput; - } - ); - if (it == m_outputs.end()) { - return; - } - resetOutput(*it, drmOutput); + Q_ASSERT(output->gpu() == m_gpu); + DrmOutput *drmOutput = qobject_cast(output); + if (drmOutput) { + Output o; + if (!resetOutput(o, drmOutput)) { + return false; } - ); - m_outputs << o; - return true; + if (!isPrimary() && !renderingBackend()->addOutput(drmOutput)) { + return false; + } + + connect(drmOutput, &DrmOutput::modeChanged, this, + [drmOutput, this] { + auto it = std::find_if(m_outputs.begin(), m_outputs.end(), + [drmOutput] (const auto &o) { + return o.output == drmOutput; + } + ); + if (it == m_outputs.end()) { + return; + } + resetOutput(*it, drmOutput); + } + ); + m_outputs << o; + return true; + } else { + return false; + } } -void EglStreamBackend::removeOutput(DrmOutput *drmOutput) +void EglStreamBackend::removeOutput(DrmAbstractOutput *drmOutput) { Q_ASSERT(drmOutput->gpu() == m_gpu); auto it = std::find_if(m_outputs.begin(), m_outputs.end(), @@ -551,7 +556,7 @@ void EglStreamBackend::endFrame(int screenId, const QRegion &renderedRegion, con } } -QSharedPointer EglStreamBackend::renderTestFrame(DrmOutput *drmOutput) +QSharedPointer EglStreamBackend::renderTestFrame(DrmAbstractOutput *drmOutput) { auto it = std::find_if(m_outputs.begin(), m_outputs.end(), [drmOutput] (const Output &o) { @@ -562,7 +567,7 @@ QSharedPointer EglStreamBackend::renderTestFrame(DrmOutput *drmOutput return nullptr; } auto buffer = (*it).dumbSwapchain ? (*it).dumbSwapchain->currentBuffer() : (*it).buffer; - auto size = drmOutput->pipeline()->sourceSize(); + auto size = drmOutput->sourceSize(); if (buffer->size() == size) { return buffer; } else { diff --git a/src/plugins/platforms/drm/egl_stream_backend.h b/src/plugins/platforms/drm/egl_stream_backend.h index a01b9c7ce3..20e971b94b 100644 --- a/src/plugins/platforms/drm/egl_stream_backend.h +++ b/src/plugins/platforms/drm/egl_stream_backend.h @@ -17,7 +17,7 @@ namespace KWin { -class DrmOutput; +class DrmAbstractOutput; class DrmDumbBuffer; class DumbSwapchain; class ShadowBuffer; @@ -41,10 +41,10 @@ public: return m_outputs.count(); } - bool addOutput(DrmOutput *output) override; - void removeOutput(DrmOutput *output) override; + bool addOutput(DrmAbstractOutput *output) override; + void removeOutput(DrmAbstractOutput *output) override; - QSharedPointer renderTestFrame(DrmOutput *output) override; + QSharedPointer renderTestFrame(DrmAbstractOutput *output) override; protected: void cleanupSurfaces() override; diff --git a/src/plugins/platforms/drm/scene_qpainter_drm_backend.cpp b/src/plugins/platforms/drm/scene_qpainter_drm_backend.cpp index 0d410dfa20..d57605f4f7 100644 --- a/src/plugins/platforms/drm/scene_qpainter_drm_backend.cpp +++ b/src/plugins/platforms/drm/scene_qpainter_drm_backend.cpp @@ -26,7 +26,7 @@ DrmQPainterBackend::DrmQPainterBackend(DrmBackend *backend, DrmGpu *gpu) } connect(m_gpu, &DrmGpu::outputEnabled, this, &DrmQPainterBackend::initOutput); connect(m_gpu, &DrmGpu::outputDisabled, this, - [this] (DrmOutput *o) { + [this] (DrmAbstractOutput *o) { auto it = std::find_if(m_outputs.begin(), m_outputs.end(), [o] (const Output &output) { return output.output == o; @@ -40,7 +40,7 @@ DrmQPainterBackend::DrmQPainterBackend(DrmBackend *backend, DrmGpu *gpu) ); } -void DrmQPainterBackend::initOutput(DrmOutput *output) +void DrmQPainterBackend::initOutput(DrmAbstractOutput *output) { Output o; o.swapchain = QSharedPointer::create(m_gpu, output->pixelSize()); @@ -80,7 +80,7 @@ QRegion DrmQPainterBackend::beginFrame(int screenId) void DrmQPainterBackend::endFrame(int screenId, const QRegion &damage) { Output &rendererOutput = m_outputs[screenId]; - DrmOutput *drmOutput = rendererOutput.output; + DrmAbstractOutput *drmOutput = rendererOutput.output; QSharedPointer back = rendererOutput.swapchain->currentBuffer(); rendererOutput.swapchain->releaseBuffer(back); diff --git a/src/plugins/platforms/drm/scene_qpainter_drm_backend.h b/src/plugins/platforms/drm/scene_qpainter_drm_backend.h index 5d26e687ad..7e4c28fe96 100644 --- a/src/plugins/platforms/drm/scene_qpainter_drm_backend.h +++ b/src/plugins/platforms/drm/scene_qpainter_drm_backend.h @@ -22,7 +22,7 @@ namespace KWin class DrmBackend; class DrmDumbBuffer; -class DrmOutput; +class DrmAbstractOutput; class DrmGpu; class DrmQPainterBackend : public QPainterBackend @@ -36,9 +36,9 @@ public: void endFrame(int screenId, const QRegion &damage) override; private: - void initOutput(DrmOutput *output); + void initOutput(DrmAbstractOutput *output); struct Output { - DrmOutput *output; + DrmAbstractOutput *output; QSharedPointer swapchain; DamageJournal damageJournal; }; diff --git a/src/plugins/platforms/drm/shadowbuffer.cpp b/src/plugins/platforms/drm/shadowbuffer.cpp index 4b99bbad6d..14074a27c6 100644 --- a/src/plugins/platforms/drm/shadowbuffer.cpp +++ b/src/plugins/platforms/drm/shadowbuffer.cpp @@ -67,7 +67,7 @@ ShadowBuffer::~ShadowBuffer() glDeleteFramebuffers(1, &m_framebuffer); } -void ShadowBuffer::render(DrmOutput *output) +void ShadowBuffer::render(DrmAbstractOutput *output) { const auto size = output->modeSize(); glViewport(0, 0, size.width(), size.height()); diff --git a/src/plugins/platforms/drm/shadowbuffer.h b/src/plugins/platforms/drm/shadowbuffer.h index 6fc2ec3bd4..dfb3bf535b 100644 --- a/src/plugins/platforms/drm/shadowbuffer.h +++ b/src/plugins/platforms/drm/shadowbuffer.h @@ -14,7 +14,7 @@ namespace KWin { -class DrmOutput; +class DrmAbstractOutput; class ShadowBuffer { @@ -25,7 +25,7 @@ public: bool isComplete() const; void bind(); - void render(DrmOutput *output); + void render(DrmAbstractOutput *output); int texture() const; diff --git a/src/wayland_server.cpp b/src/wayland_server.cpp index dac6f60271..506059e45c 100644 --- a/src/wayland_server.cpp +++ b/src/wayland_server.cpp @@ -325,23 +325,33 @@ void WaylandServer::initPlatform() void WaylandServer::handleOutputAdded(AbstractOutput *output) { auto o = static_cast(output); - m_waylandOutputDevices.insert(o, new WaylandOutputDevice(o)); + if (!o->isPlaceholder()) { + m_waylandOutputDevices.insert(o, new WaylandOutputDevice(o)); + } } void WaylandServer::handleOutputRemoved(AbstractOutput *output) { - delete m_waylandOutputDevices.take(static_cast(output)); + auto o = static_cast(output); + if (!o->isPlaceholder()) { + delete m_waylandOutputDevices.take(o); + } } void WaylandServer::handleOutputEnabled(AbstractOutput *output) { auto o = static_cast(output); - m_waylandOutputs.insert(o, new WaylandOutput(o)); + if (!o->isPlaceholder()) { + m_waylandOutputs.insert(o, new WaylandOutput(o)); + } } void WaylandServer::handleOutputDisabled(AbstractOutput *output) { - delete m_waylandOutputs.take(static_cast(output)); + auto o = static_cast(output); + if (!o->isPlaceholder()) { + delete m_waylandOutputs.take(o); + } } AbstractWaylandOutput *WaylandServer::findOutput(KWaylandServer::OutputInterface *outputIface) const