diff --git a/src/composite.cpp b/src/composite.cpp index 618d3e7677..5e88c364fc 100644 --- a/src/composite.cpp +++ b/src/composite.cpp @@ -393,16 +393,6 @@ void Compositor::handleOutputDisabled(AbstractOutput *output) unregisterRenderLoop(output->renderLoop()); } -int Compositor::screenForRenderLoop(RenderLoop *renderLoop) const -{ - Q_ASSERT(m_renderLoops.contains(renderLoop)); - AbstractOutput *output = m_renderLoops.value(renderLoop); - if (!output) { - return -1; - } - return kwinApp()->platform()->enabledOutputs().indexOf(output); -} - void Compositor::scheduleRepaint() { for (auto it = m_renderLoops.constBegin(); it != m_renderLoops.constEnd(); ++it) { @@ -585,9 +575,9 @@ void Compositor::handleFrameRequested(RenderLoop *renderLoop) void Compositor::composite(RenderLoop *renderLoop) { - const int screenId = screenForRenderLoop(renderLoop); + const auto &output = m_renderLoops[renderLoop]; - fTraceDuration("Paint (", screens()->name(screenId), ")"); + fTraceDuration("Paint (", output ? output->name() : QStringLiteral("screens"), ")"); // Create a list of all windows in the stacking order QList windows = Workspace::self()->xStackingOrder(); @@ -617,10 +607,10 @@ void Compositor::composite(RenderLoop *renderLoop) } } - const QRegion repaints = m_scene->repaints(screenId); - m_scene->resetRepaints(screenId); + const QRegion repaints = m_scene->repaints(output); + m_scene->resetRepaints(output); - m_scene->paint(screenId, repaints, windows, renderLoop); + m_scene->paint(output, repaints, windows, renderLoop); if (waylandServer()) { const std::chrono::milliseconds frameTime = @@ -634,7 +624,7 @@ void Compositor::composite(RenderLoop *renderLoop) !(window->isLockScreen() || window->isInputMethod())) { continue; } - if (!window->isOnScreen(screenId)) { + if (!window->isOnOutput(output)) { continue; } if (auto surface = window->surface()) { diff --git a/src/composite.h b/src/composite.h index 4e720f559d..1615e315a1 100644 --- a/src/composite.h +++ b/src/composite.h @@ -130,7 +130,6 @@ private: void releaseCompositorSelection(); void deleteUnusedSupportProperties(); - int screenForRenderLoop(RenderLoop *renderLoop) const; void registerRenderLoop(RenderLoop *renderLoop, AbstractOutput *output); void unregisterRenderLoop(RenderLoop *renderLoop); diff --git a/src/item.cpp b/src/item.cpp index 9fd9cea2fa..8905c521f1 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -19,20 +19,13 @@ namespace KWin Item::Item(Item *parent) { setParentItem(parent); - - if (kwinApp()->platform()->isPerScreenRenderingEnabled()) { - connect(kwinApp()->platform(), &Platform::outputEnabled, this, &Item::reallocRepaints); - connect(kwinApp()->platform(), &Platform::outputDisabled, this, &Item::reallocRepaints); - } - reallocRepaints(); + connect(kwinApp()->platform(), &Platform::outputDisabled, this, &Item::removeRepaints); } Item::~Item() { setParentItem(nullptr); - - for (int i = 0; i < m_repaints.count(); ++i) { - const QRegion dirty = repaints(i); + for (const auto &dirty : qAsConst(m_repaints)) { if (!dirty.isEmpty()) { Compositor::self()->addRepaint(dirty); } @@ -262,19 +255,15 @@ void Item::scheduleRepaintInternal(const QRegion ®ion) const QRegion globalRegion = mapToGlobal(region); if (kwinApp()->platform()->isPerScreenRenderingEnabled()) { const QVector outputs = kwinApp()->platform()->enabledOutputs(); - if (m_repaints.count() != outputs.count()) { - return; // Repaints haven't been reallocated yet, do nothing. - } - for (int screenId = 0; screenId < m_repaints.count(); ++screenId) { - AbstractOutput *output = outputs[screenId]; + for (const auto &output : outputs) { const QRegion dirtyRegion = globalRegion & output->geometry(); if (!dirtyRegion.isEmpty()) { - m_repaints[screenId] += dirtyRegion; + m_repaints[output] += dirtyRegion; output->renderLoop()->scheduleRepaint(); } } } else { - m_repaints[0] += globalRegion; + m_repaints[nullptr] += globalRegion; kwinApp()->platform()->renderLoop()->scheduleRepaint(); } } @@ -319,32 +308,19 @@ WindowQuadList Item::quads() const return m_quads.value(); } -QRegion Item::repaints(int screen) const +QRegion Item::repaints(AbstractOutput *output) const { - Q_ASSERT(!m_repaints.isEmpty()); - const int index = screen != -1 ? screen : 0; - if (m_repaints[index] == infiniteRegion()) { - return QRect(QPoint(0, 0), screens()->size()); - } - return m_repaints[index]; + return m_repaints.value(output, QRect(QPoint(0, 0), screens()->size())); } -void Item::resetRepaints(int screen) +void Item::resetRepaints(AbstractOutput *output) { - Q_ASSERT(!m_repaints.isEmpty()); - const int index = screen != -1 ? screen : 0; - m_repaints[index] = QRegion(); + m_repaints.insert(output, QRegion()); } -void Item::reallocRepaints() +void Item::removeRepaints(AbstractOutput *output) { - if (kwinApp()->platform()->isPerScreenRenderingEnabled()) { - m_repaints.resize(kwinApp()->platform()->enabledOutputs().count()); - } else { - m_repaints.resize(1); - } - - m_repaints.fill(infiniteRegion()); + m_repaints.remove(output); } bool Item::isVisible() const diff --git a/src/item.h b/src/item.h index a01ec23bf5..92fb7dbc9e 100644 --- a/src/item.h +++ b/src/item.h @@ -17,6 +17,8 @@ namespace KWin { +class AbstractOutput; + /** * The Item class is the base class for items in the scene. */ @@ -85,8 +87,8 @@ public: void scheduleRepaint(const QRegion ®ion); void scheduleFrame(); - QRegion repaints(int screen) const; - void resetRepaints(int screen); + QRegion repaints(AbstractOutput *output) const; + void resetRepaints(AbstractOutput *output); WindowQuadList quads() const; virtual void preprocess(); @@ -116,11 +118,11 @@ private: void removeChild(Item *item); void updateBoundingRect(); void scheduleRepaintInternal(const QRegion ®ion); - void reallocRepaints(); void markSortedChildItemsDirty(); bool computeEffectiveVisibility() const; void updateEffectiveVisibility(); + void removeRepaints(AbstractOutput *output); QPointer m_parentItem; QList m_childItems; @@ -131,7 +133,7 @@ private: int m_z = 0; bool m_visible = true; bool m_effectiveVisible = true; - QVector m_repaints; + QMap m_repaints; mutable std::optional m_quads; mutable std::optional> m_sortedChildItems; }; diff --git a/src/platformsupport/scenes/opengl/openglbackend.cpp b/src/platformsupport/scenes/opengl/openglbackend.cpp index c3e546a0fb..134b70947a 100644 --- a/src/platformsupport/scenes/opengl/openglbackend.cpp +++ b/src/platformsupport/scenes/opengl/openglbackend.cpp @@ -40,9 +40,9 @@ OverlayWindow* OpenGLBackend::overlayWindow() const return nullptr; } -bool OpenGLBackend::scanout(int screenId, SurfaceItem *surfaceItem) +bool OpenGLBackend::scanout(AbstractOutput *output, SurfaceItem *surfaceItem) { - Q_UNUSED(screenId) + Q_UNUSED(output) Q_UNUSED(surfaceItem) return false; } @@ -66,16 +66,16 @@ QSharedPointer OpenGLBackend::textureForOutput(AbstractOutput* return {}; } -void OpenGLBackend::aboutToStartPainting(int screenId, const QRegion &damage) +void OpenGLBackend::aboutToStartPainting(AbstractOutput *output, const QRegion &damage) { - Q_UNUSED(screenId) + Q_UNUSED(output) Q_UNUSED(damage) } -bool OpenGLBackend::directScanoutAllowed(int screen) const +bool OpenGLBackend::directScanoutAllowed(AbstractOutput *output) const { - Q_UNUSED(screen); + Q_UNUSED(output); return false; } diff --git a/src/platformsupport/scenes/opengl/openglbackend.h b/src/platformsupport/scenes/opengl/openglbackend.h index c58983a8b3..bfb1507007 100644 --- a/src/platformsupport/scenes/opengl/openglbackend.h +++ b/src/platformsupport/scenes/opengl/openglbackend.h @@ -60,16 +60,16 @@ public: * * @p damage contains the reported damage as suggested by windows and effects on prepaint calls. */ - virtual void aboutToStartPainting(int screenId, const QRegion &damage); + virtual void aboutToStartPainting(AbstractOutput *output, const QRegion &damage); virtual bool makeCurrent() = 0; virtual void doneCurrent() = 0; - virtual QRegion beginFrame(int screenId) = 0; - virtual void endFrame(int screenId, const QRegion &damage, const QRegion &damagedRegion) = 0; + virtual QRegion beginFrame(AbstractOutput *output) = 0; + virtual void endFrame(AbstractOutput *output, const QRegion &damage, const QRegion &damagedRegion) = 0; /** * Tries to directly scan out a surface to the screen) * @return if the scanout fails (or is not supported on the specified screen) */ - virtual bool scanout(int screenId, SurfaceItem *surfaceItem); + virtual bool scanout(AbstractOutput *output, SurfaceItem *surfaceItem); /** * @brief Returns the OverlayWindow used by the backend. @@ -121,7 +121,7 @@ public: { return m_haveNativeFence; } - virtual bool directScanoutAllowed(int screen) const; + virtual bool directScanoutAllowed(AbstractOutput *output) const; /** * The backend specific extensions (e.g. EGL/GLX extensions). diff --git a/src/platformsupport/scenes/qpainter/qpainterbackend.h b/src/platformsupport/scenes/qpainter/qpainterbackend.h index 857e6816ee..337d930509 100644 --- a/src/platformsupport/scenes/qpainter/qpainterbackend.h +++ b/src/platformsupport/scenes/qpainter/qpainterbackend.h @@ -22,6 +22,7 @@ namespace KWin class PlatformSurfaceTexture; class SurfacePixmapInternal; class SurfacePixmapWayland; +class AbstractOutput; class QPainterBackend : public QObject { @@ -33,8 +34,8 @@ public: PlatformSurfaceTexture *createPlatformSurfaceTextureInternal(SurfacePixmapInternal *pixmap); PlatformSurfaceTexture *createPlatformSurfaceTextureWayland(SurfacePixmapWayland *pixmap); - virtual void endFrame(int screenId, const QRegion &damage) = 0; - virtual QRegion beginFrame(int screenId) = 0; + virtual void endFrame(AbstractOutput *output, const QRegion &damage) = 0; + virtual QRegion beginFrame(AbstractOutput *output) = 0; /** * @brief Whether the creation of the Backend failed. * @@ -52,7 +53,7 @@ public: * @param screenId The id of the screen as used in Screens * @todo Get a better identifier for screen then a counter variable */ - virtual QImage *bufferForScreen(int screenId) = 0; + virtual QImage *bufferForScreen(AbstractOutput *output) = 0; protected: QPainterBackend(); diff --git a/src/plugins/platforms/drm/abstract_egl_drm_backend.h b/src/plugins/platforms/drm/abstract_egl_drm_backend.h index b977d2dfcf..80aec19d68 100644 --- a/src/plugins/platforms/drm/abstract_egl_drm_backend.h +++ b/src/plugins/platforms/drm/abstract_egl_drm_backend.h @@ -26,7 +26,7 @@ class AbstractEglDrmBackend : public AbstractEglBackend Q_OBJECT public: - virtual int screenCount() const = 0; + virtual bool hasOutput(AbstractOutput *output) const = 0; virtual bool addOutput(DrmAbstractOutput *output) = 0; virtual void removeOutput(DrmAbstractOutput *output) = 0; virtual bool swapBuffers(DrmAbstractOutput *output, const QRegion &dirty) { diff --git a/src/plugins/platforms/drm/egl_gbm_backend.cpp b/src/plugins/platforms/drm/egl_gbm_backend.cpp index 562f592d6e..bdbd9ac42e 100644 --- a/src/plugins/platforms/drm/egl_gbm_backend.cpp +++ b/src/plugins/platforms/drm/egl_gbm_backend.cpp @@ -140,16 +140,15 @@ bool EglGbmBackend::initRenderingContext() return true; } -bool EglGbmBackend::resetOutput(Output &output, DrmAbstractOutput *drmOutput) +bool EglGbmBackend::resetOutput(Output &output) { - output.output = drmOutput; - const QSize size = drmOutput->sourceSize(); - QVector modifiers = drmOutput->supportedModifiers(m_gbmFormat); + const QSize size = output.output->sourceSize(); + QVector modifiers = output.output->supportedModifiers(m_gbmFormat); QSharedPointer gbmSurface; if (modifiers.isEmpty()) { int flags = GBM_BO_USE_RENDERING; - if (drmOutput->gpu() == m_gpu) { + if (output.output->gpu() == m_gpu) { flags |= GBM_BO_USE_SCANOUT; } else { flags |= GBM_BO_USE_LINEAR; @@ -173,7 +172,7 @@ bool EglGbmBackend::resetOutput(Output &output, DrmAbstractOutput *drmOutput) output.current = {}; output.current.gbmSurface = gbmSurface; - if (size == drmOutput->pixelSize()) { + if (size == output.output->pixelSize()) { output.current.shadowBuffer = nullptr; } else { makeContextCurrent(output.current); @@ -187,58 +186,37 @@ bool EglGbmBackend::resetOutput(Output &output, DrmAbstractOutput *drmOutput) bool EglGbmBackend::addOutput(DrmAbstractOutput *drmOutput) { + Output newOutput; + newOutput.output = drmOutput; if (isPrimary()) { - Output newOutput; - if (!resetOutput(newOutput, drmOutput)) { + if (!resetOutput(newOutput)) { return false; } - if (drmOutput->gpu() == m_gpu) { - m_outputs << newOutput; - } else { - m_secondaryGpuOutputs << newOutput; - } } else { - Output newOutput; - newOutput.output = drmOutput; if (!renderingBackend()->addOutput(drmOutput)) { return false; } - m_outputs << newOutput; } + m_outputs.insert(drmOutput, newOutput); return true; } void EglGbmBackend::removeOutput(DrmAbstractOutput *drmOutput) { - QVector &outputs = drmOutput->gpu() == m_gpu ? m_outputs : m_secondaryGpuOutputs; - auto it = std::find_if(outputs.begin(), outputs.end(), - [drmOutput] (const Output &output) { - return output.output == drmOutput; - } - ); - if (it == outputs.end()) { - return; - } + Q_ASSERT(m_outputs.contains(drmOutput)); if (isPrimary()) { // shadow buffer needs context current for destruction makeCurrent(); } else { - renderingBackend()->removeOutput((*it).output); + renderingBackend()->removeOutput(drmOutput); } - outputs.erase(it); + m_outputs.remove(drmOutput); } bool EglGbmBackend::swapBuffers(DrmAbstractOutput *drmOutput, const QRegion &dirty) { - auto it = std::find_if(m_secondaryGpuOutputs.begin(), m_secondaryGpuOutputs.end(), - [drmOutput] (const Output &output) { - return output.output == drmOutput; - } - ); - if (it == m_secondaryGpuOutputs.end()) { - return false; - } - Output &output = *it; + Q_ASSERT(m_outputs.contains(drmOutput)); + Output &output = m_outputs[drmOutput]; renderFramebufferToSurface(output); if (output.current.gbmSurface->swapBuffers()) { cleanupRenderData(output.old); @@ -251,15 +229,8 @@ bool EglGbmBackend::swapBuffers(DrmAbstractOutput *drmOutput, const QRegion &dir 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) { - return output.output == drmOutput; - } - ); - if (it == m_secondaryGpuOutputs.end()) { - return false; - } - auto bo = it->current.gbmSurface->currentBuffer(); + Q_ASSERT(m_outputs.contains(drmOutput)); + auto bo = m_outputs[drmOutput].current.gbmSurface->currentBuffer(); if (!bo->map(GBM_BO_TRANSFER_READ)) { return false; } @@ -272,15 +243,8 @@ bool EglGbmBackend::exportFramebuffer(DrmAbstractOutput *drmOutput, void *data, bool EglGbmBackend::exportFramebufferAsDmabuf(DrmAbstractOutput *drmOutput, int *fds, int *strides, int *offsets, uint32_t *num_fds, uint32_t *format, uint64_t *modifier) { - auto it = std::find_if(m_secondaryGpuOutputs.begin(), m_secondaryGpuOutputs.end(), - [drmOutput] (const Output &output) { - return output.output == drmOutput; - } - ); - if (it == m_secondaryGpuOutputs.end()) { - return -1; - } - auto bo = it->current.gbmSurface->currentBuffer()->getBo(); + Q_ASSERT(m_outputs.contains(drmOutput)); + auto bo = m_outputs[drmOutput].current.gbmSurface->currentBuffer()->getBo(); if (gbm_bo_get_handle_for_plane(bo, 0).s32 != -1) { *num_fds = gbm_bo_get_plane_count(bo); for (uint32_t i = 0; i < *num_fds; i++) { @@ -312,15 +276,8 @@ bool EglGbmBackend::exportFramebufferAsDmabuf(DrmAbstractOutput *drmOutput, int QRegion EglGbmBackend::beginFrameForSecondaryGpu(DrmAbstractOutput *drmOutput) { - auto it = std::find_if(m_secondaryGpuOutputs.begin(), m_secondaryGpuOutputs.end(), - [drmOutput] (const Output &output) { - return output.output == drmOutput; - } - ); - if (it == m_secondaryGpuOutputs.end()) { - return QRegion(); - } - return prepareRenderingForOutput(*it); + Q_ASSERT(m_outputs.contains(drmOutput)); + return prepareRenderingForOutput(m_outputs[drmOutput]); } QSharedPointer EglGbmBackend::importFramebuffer(Output &output, const QRegion &dirty) const @@ -489,10 +446,11 @@ static QVector regionToRects(const QRegion ®ion, AbstractWaylandOutpu return rects; } -void EglGbmBackend::aboutToStartPainting(int screenId, const QRegion &damagedRegion) +void EglGbmBackend::aboutToStartPainting(AbstractOutput *drmOutput, const QRegion &damagedRegion) { - Q_ASSERT_X(screenId != -1, "aboutToStartPainting", "not using per screen rendering"); - const Output &output = m_outputs.at(screenId); + Q_ASSERT_X(drmOutput, "aboutToStartPainting", "not using per screen rendering"); + Q_ASSERT(m_outputs.contains(drmOutput)); + const Output &output = m_outputs[drmOutput]; if (output.current.bufferAge > 0 && !damagedRegion.isEmpty() && supportsPartialUpdate()) { const QRegion region = damagedRegion & output.output->geometry(); @@ -521,9 +479,10 @@ void EglGbmBackend::setViewport(const Output &output) const glViewport(0, 0, size.width(), size.height()); } -QRegion EglGbmBackend::beginFrame(int screenId) +QRegion EglGbmBackend::beginFrame(AbstractOutput *drmOutput) { - Output &output = m_outputs[screenId]; + Q_ASSERT(m_outputs.contains(drmOutput)); + Output &output = m_outputs[drmOutput]; if (output.surfaceInterface) { qCDebug(KWIN_DRM) << "Direct scanout stopped on output" << output.output->name(); } @@ -562,7 +521,7 @@ QRegion EglGbmBackend::prepareRenderingForOutput(Output &output) output.current = output.old; output.old = {}; } else { - resetOutput(output, output.output); + resetOutput(output); } } makeContextCurrent(output.current); @@ -580,9 +539,10 @@ QRegion EglGbmBackend::prepareRenderingForOutput(Output &output) return geometry; } -QSharedPointer EglGbmBackend::endFrameWithBuffer(int screenId, const QRegion &dirty) +QSharedPointer EglGbmBackend::endFrameWithBuffer(AbstractOutput *drmOutput, const QRegion &dirty) { - Output &output = m_outputs[screenId]; + Q_ASSERT(m_outputs.contains(drmOutput)); + Output &output = m_outputs[drmOutput]; if (isPrimary()) { renderFramebufferToSurface(output); auto buffer = output.current.gbmSurface->swapBuffersForDrm(); @@ -595,16 +555,17 @@ QSharedPointer EglGbmBackend::endFrameWithBuffer(int screenId, const } } -void EglGbmBackend::endFrame(int screenId, const QRegion &renderedRegion, +void EglGbmBackend::endFrame(AbstractOutput *drmOutput, const QRegion &renderedRegion, const QRegion &damagedRegion) { + Q_ASSERT(m_outputs.contains(drmOutput)); Q_UNUSED(renderedRegion) - Output &output = m_outputs[screenId]; + Output &output = m_outputs[drmOutput]; cleanupRenderData(output.old); const QRegion dirty = damagedRegion.intersected(output.output->geometry()); - QSharedPointer buffer = endFrameWithBuffer(screenId, dirty); + QSharedPointer buffer = endFrameWithBuffer(drmOutput, dirty); if (!buffer || !output.output->present(buffer, dirty)) { RenderLoopPrivate *renderLoopPrivate = RenderLoopPrivate::get(output.output->renderLoop()); renderLoopPrivate->notifyFrameFailed(); @@ -620,8 +581,9 @@ void EglGbmBackend::updateBufferAge(Output &output, const QRegion &dirty) } } -bool EglGbmBackend::scanout(int screenId, SurfaceItem *surfaceItem) +bool EglGbmBackend::scanout(AbstractOutput *drmOutput, SurfaceItem *surfaceItem) { + Q_ASSERT(m_outputs.contains(drmOutput)); SurfaceItemWayland *item = qobject_cast(surfaceItem); if (!item) { return false; @@ -636,7 +598,7 @@ bool EglGbmBackend::scanout(int screenId, SurfaceItem *surfaceItem) if (!buffer) { return false; } - Output &output = m_outputs[screenId]; + Output &output = m_outputs[drmOutput]; if (buffer->size() != output.output->modeSize()) { return false; } @@ -714,41 +676,21 @@ bool EglGbmBackend::scanout(int screenId, SurfaceItem *surfaceItem) QSharedPointer EglGbmBackend::renderTestFrame(DrmAbstractOutput *output) { - for (int i = 0; i < m_outputs.count(); i++) { - if (m_outputs[i].output == output) { - beginFrame(i); - glClear(GL_COLOR_BUFFER_BIT); - return endFrameWithBuffer(i, output->geometry()); - } - } - return nullptr; + beginFrame(output); + glClear(GL_COLOR_BUFFER_BIT); + return endFrameWithBuffer(output, output->geometry()); } -QSharedPointer EglGbmBackend::textureForOutput(AbstractOutput *abstractOutput) const +QSharedPointer EglGbmBackend::textureForOutput(AbstractOutput *output) const { - auto itOutput = std::find_if(m_outputs.begin(), m_outputs.end(), - [abstractOutput] (const auto &output) { - return output.output == abstractOutput; - } - ); - if (itOutput == m_outputs.end()) { - itOutput = std::find_if(m_secondaryGpuOutputs.begin(), m_secondaryGpuOutputs.end(), - [abstractOutput] (const auto &output) { - return output.output == abstractOutput; - } - ); - if (itOutput == m_secondaryGpuOutputs.end()) { - return {}; - } - } - - DrmAbstractOutput *drmOutput = itOutput->output; - if (itOutput->current.shadowBuffer) { - const auto glTexture = QSharedPointer::create(itOutput->current.shadowBuffer->texture(), GL_RGBA8, drmOutput->pixelSize()); + Q_ASSERT(m_outputs.contains(output)); + auto &renderOutput = m_outputs[output]; + if (renderOutput.current.shadowBuffer) { + const auto glTexture = QSharedPointer::create(renderOutput.current.shadowBuffer->texture(), GL_RGBA8, output->pixelSize()); glTexture->setYInverted(true); return glTexture; } - GbmBuffer *gbmBuffer = itOutput->current.gbmSurface->currentBuffer().get(); + GbmBuffer *gbmBuffer = renderOutput.current.gbmSurface->currentBuffer().get(); if (!gbmBuffer) { qCWarning(KWIN_DRM) << "Failed to record frame: No gbm buffer!"; return {}; @@ -759,12 +701,17 @@ QSharedPointer EglGbmBackend::textureForOutput(AbstractOutput *abstra return {}; } - return QSharedPointer::create(eglDisplay(), image, GL_RGBA8, drmOutput->modeSize()); + return QSharedPointer::create(eglDisplay(), image, GL_RGBA8, static_cast(output)->modeSize()); } -bool EglGbmBackend::directScanoutAllowed(int screen) const +bool EglGbmBackend::directScanoutAllowed(AbstractOutput *output) const { - return !m_backend->usesSoftwareCursor() && !m_outputs[screen].output->directScanoutInhibited(); + return !m_backend->usesSoftwareCursor() && output->directScanoutInhibited(); +} + +bool EglGbmBackend::hasOutput(AbstractOutput *output) const +{ + return m_outputs.contains(output); } } diff --git a/src/plugins/platforms/drm/egl_gbm_backend.h b/src/plugins/platforms/drm/egl_gbm_backend.h index 048985fccc..c5142b2af6 100644 --- a/src/plugins/platforms/drm/egl_gbm_backend.h +++ b/src/plugins/platforms/drm/egl_gbm_backend.h @@ -47,17 +47,14 @@ public: PlatformSurfaceTexture *createPlatformSurfaceTextureInternal(SurfacePixmapInternal *pixmap) override; PlatformSurfaceTexture *createPlatformSurfaceTextureWayland(SurfacePixmapWayland *pixmap) override; - QRegion beginFrame(int screenId) override; - void endFrame(int screenId, const QRegion &damage, const QRegion &damagedRegion) override; + QRegion beginFrame(AbstractOutput *output) override; + void endFrame(AbstractOutput *output, const QRegion &damage, const QRegion &damagedRegion) override; void init() override; - bool scanout(int screenId, SurfaceItem *surfaceItem) override; + bool scanout(AbstractOutput *output, SurfaceItem *surfaceItem) override; QSharedPointer textureForOutput(AbstractOutput *requestedOutput) const override; - int screenCount() const override { - return m_outputs.count(); - } - + bool hasOutput(AbstractOutput *output) const override; bool addOutput(DrmAbstractOutput *output) override; void removeOutput(DrmAbstractOutput *output) override; bool swapBuffers(DrmAbstractOutput *output, const QRegion &dirty) override; @@ -65,13 +62,13 @@ public: bool exportFramebufferAsDmabuf(DrmAbstractOutput *output, int *fds, int *strides, int *offsets, uint32_t *num_fds, uint32_t *format, uint64_t *modifier) override; QRegion beginFrameForSecondaryGpu(DrmAbstractOutput *output) override; - bool directScanoutAllowed(int screen) const override; + bool directScanoutAllowed(AbstractOutput *output) const override; QSharedPointer renderTestFrame(DrmAbstractOutput *output) override; protected: void cleanupSurfaces() override; - void aboutToStartPainting(int screenId, const QRegion &damage) override; + void aboutToStartPainting(AbstractOutput *output, const QRegion &damage) override; private: bool initializeEgl(); @@ -99,7 +96,7 @@ private: }; bool doesRenderFit(DrmAbstractOutput *output, const Output::RenderData &render); - bool resetOutput(Output &output, DrmAbstractOutput *drmOutput); + bool resetOutput(Output &output); bool makeContextCurrent(const Output::RenderData &output) const; void setViewport(const Output &output) const; @@ -107,13 +104,12 @@ private: void renderFramebufferToSurface(Output &output); QRegion prepareRenderingForOutput(Output &output); QSharedPointer importFramebuffer(Output &output, const QRegion &dirty) const; - QSharedPointer endFrameWithBuffer(int screenId, const QRegion &dirty); + QSharedPointer endFrameWithBuffer(AbstractOutput *output, const QRegion &dirty); void updateBufferAge(Output &output, const QRegion &dirty); void cleanupRenderData(Output::RenderData &output); - QVector m_outputs; - QVector m_secondaryGpuOutputs; + QMap m_outputs; uint32_t m_gbmFormat; friend class EglGbmTexture; diff --git a/src/plugins/platforms/drm/egl_multi_backend.cpp b/src/plugins/platforms/drm/egl_multi_backend.cpp index adbe7d44fc..afaf4cfdc1 100644 --- a/src/plugins/platforms/drm/egl_multi_backend.cpp +++ b/src/plugins/platforms/drm/egl_multi_backend.cpp @@ -57,28 +57,19 @@ void EglMultiBackend::init() m_initialized = true; } -QRegion EglMultiBackend::beginFrame(int screenId) +QRegion EglMultiBackend::beginFrame(AbstractOutput *output) { - int internalScreenId; - AbstractEglBackend *backend = findBackend(screenId, internalScreenId); - Q_ASSERT(backend != nullptr); - return backend->beginFrame(internalScreenId); + return findBackend(output)->beginFrame(output); } -void EglMultiBackend::endFrame(int screenId, const QRegion &damage, const QRegion &damagedRegion) +void EglMultiBackend::endFrame(AbstractOutput *output, const QRegion &damage, const QRegion &damagedRegion) { - int internalScreenId; - AbstractEglBackend *backend = findBackend(screenId, internalScreenId); - Q_ASSERT(backend != nullptr); - backend->endFrame(internalScreenId, damage, damagedRegion); + findBackend(output)->endFrame(output, damage, damagedRegion); } -bool EglMultiBackend::scanout(int screenId, SurfaceItem *surfaceItem) +bool EglMultiBackend::scanout(AbstractOutput *output, SurfaceItem *surfaceItem) { - int internalScreenId; - AbstractEglBackend *backend = findBackend(screenId, internalScreenId); - Q_ASSERT(backend != nullptr); - return backend->scanout(internalScreenId, surfaceItem); + return findBackend(output)->scanout(output, surfaceItem); } bool EglMultiBackend::makeCurrent() @@ -107,26 +98,20 @@ QSharedPointer EglMultiBackend::textureForOutput(AbstractOutput *requ return m_backends[0]->textureForOutput(requestedOutput); } -AbstractEglDrmBackend *EglMultiBackend::findBackend(int screenId, int& internalScreenId) const +AbstractEglDrmBackend *EglMultiBackend::findBackend(AbstractOutput *output) const { - int screens = 0; - for (int i = 0; i < m_backends.count(); i++) { - if (screenId < screens + m_backends[i]->screenCount()) { - internalScreenId = screenId - screens; - return m_backends[i]; + for (const auto &backend : qAsConst(m_backends)) { + if (backend->hasOutput(output)) { + return backend; } - screens += m_backends[i]->screenCount(); } - qCDebug(KWIN_DRM) << "could not find backend!" << screenId << "/" << screens; + Q_UNREACHABLE(); return nullptr; } -bool EglMultiBackend::directScanoutAllowed(int screenId) const +bool EglMultiBackend::directScanoutAllowed(AbstractOutput *output) const { - int internalScreenId; - AbstractEglBackend *backend = findBackend(screenId, internalScreenId); - Q_ASSERT(backend != nullptr); - return backend->directScanoutAllowed(internalScreenId); + return findBackend(output)->directScanoutAllowed(output); } void EglMultiBackend::addGpu(DrmGpu *gpu) diff --git a/src/plugins/platforms/drm/egl_multi_backend.h b/src/plugins/platforms/drm/egl_multi_backend.h index 111ecdf823..52eb549a41 100644 --- a/src/plugins/platforms/drm/egl_multi_backend.h +++ b/src/plugins/platforms/drm/egl_multi_backend.h @@ -24,9 +24,9 @@ public: void init() override; - QRegion beginFrame(int screenId) override; - void endFrame(int screenId, const QRegion &damage, const QRegion &damagedRegion) override; - bool scanout(int screenId, SurfaceItem *surfaceItem) override; + QRegion beginFrame(AbstractOutput *output) override; + void endFrame(AbstractOutput *output, const QRegion &damage, const QRegion &damagedRegion) override; + bool scanout(AbstractOutput *output, SurfaceItem *surfaceItem) override; bool makeCurrent() override; void doneCurrent() override; @@ -35,7 +35,7 @@ public: PlatformSurfaceTexture *createPlatformSurfaceTextureWayland(SurfacePixmapWayland *pixmap) override; QSharedPointer textureForOutput(AbstractOutput *requestedOutput) const override; - bool directScanoutAllowed(int screen) const override; + bool directScanoutAllowed(AbstractOutput *output) const override; public Q_SLOTS: void addGpu(DrmGpu *gpu); @@ -46,7 +46,7 @@ private: QVector m_backends; bool m_initialized = false; - AbstractEglDrmBackend *findBackend(int screenId, int& internalScreenId) const; + AbstractEglDrmBackend *findBackend(AbstractOutput *output) const; }; } diff --git a/src/plugins/platforms/drm/egl_stream_backend.cpp b/src/plugins/platforms/drm/egl_stream_backend.cpp index b6eb3599ea..7579ab4cce 100644 --- a/src/plugins/platforms/drm/egl_stream_backend.cpp +++ b/src/plugins/platforms/drm/egl_stream_backend.cpp @@ -298,9 +298,9 @@ bool EglStreamBackend::initRenderingContext() return !m_outputs.isEmpty() && makeContextCurrent(m_outputs.first()); } -bool EglStreamBackend::resetOutput(Output &o, DrmOutput *drmOutput) +bool EglStreamBackend::resetOutput(Output &o) { - o.output = drmOutput; + const auto &drmOutput = o.output; QSize sourceSize = drmOutput->sourceSize(); if (isPrimary()) { @@ -385,7 +385,8 @@ bool EglStreamBackend::addOutput(DrmAbstractOutput *output) DrmOutput *drmOutput = qobject_cast(output); if (drmOutput) { Output o; - if (!resetOutput(o, drmOutput)) { + o.output = drmOutput; + if (!resetOutput(o)) { return false; } if (!isPrimary() && !renderingBackend()->addOutput(drmOutput)) { @@ -394,18 +395,10 @@ bool EglStreamBackend::addOutput(DrmAbstractOutput *output) 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); + resetOutput(m_outputs[drmOutput]); } ); - m_outputs << o; + m_outputs.insert(output, o); return true; } else { return false; @@ -490,9 +483,10 @@ PlatformSurfaceTexture *EglStreamBackend::createPlatformSurfaceTextureWayland(Su return new EglStreamSurfaceTextureWayland(this, pixmap); } -QRegion EglStreamBackend::beginFrame(int screenId) +QRegion EglStreamBackend::beginFrame(AbstractOutput *drmOutput) { - const Output &o = m_outputs.at(screenId); + Q_ASSERT(m_outputs.contains(drmOutput)); + const Output &o = m_outputs[drmOutput]; if (isPrimary()) { makeContextCurrent(o); if (o.shadowBuffer) { @@ -504,13 +498,12 @@ QRegion EglStreamBackend::beginFrame(int screenId) } } -void EglStreamBackend::endFrame(int screenId, const QRegion &renderedRegion, const QRegion &damagedRegion) +void EglStreamBackend::endFrame(AbstractOutput *output, const QRegion &renderedRegion, const QRegion &damagedRegion) { + Q_ASSERT(m_outputs.contains(output)); Q_UNUSED(renderedRegion); - Output &renderOutput = m_outputs[screenId]; - DrmOutput *drmOutput = renderOutput.output; - + Output &renderOutput = m_outputs[output]; bool frameFailed = false; QSharedPointer buffer; @@ -524,13 +517,13 @@ void EglStreamBackend::endFrame(int screenId, const QRegion &renderedRegion, con frameFailed = true; } } else { - if (!renderingBackend()->swapBuffers(drmOutput, damagedRegion.intersected(drmOutput->geometry()))) { - qCCritical(KWIN_DRM) << "swapping buffers on render backend for" << drmOutput << "failed!"; + if (!renderingBackend()->swapBuffers(static_cast(output), damagedRegion.intersected(output->geometry()))) { + qCCritical(KWIN_DRM) << "swapping buffers on render backend for" << output << "failed!"; frameFailed = true; } buffer = renderOutput.dumbSwapchain->acquireBuffer(); - if (!frameFailed && !renderingBackend()->exportFramebuffer(drmOutput, buffer->data(), buffer->size(), buffer->stride())) { - qCCritical(KWIN_DRM) << "importing framebuffer from render backend for" << drmOutput << "failed!"; + if (!frameFailed && !renderingBackend()->exportFramebuffer(static_cast(output), buffer->data(), buffer->size(), buffer->stride())) { + qCCritical(KWIN_DRM) << "importing framebuffer from render backend for" << output << "failed!"; frameFailed = true; } } @@ -539,11 +532,11 @@ void EglStreamBackend::endFrame(int screenId, const QRegion &renderedRegion, con } if (frameFailed) { - RenderLoopPrivate *renderLoopPrivate = RenderLoopPrivate::get(drmOutput->renderLoop()); + RenderLoopPrivate *renderLoopPrivate = RenderLoopPrivate::get(output->renderLoop()); renderLoopPrivate->notifyFrameFailed(); } else if (isPrimary()) { EGLAttrib acquireAttribs[] = { - EGL_DRM_FLIP_EVENT_DATA_NV, (EGLAttrib)drmOutput, + EGL_DRM_FLIP_EVENT_DATA_NV, (EGLAttrib)output, EGL_NONE, }; if (!pEglStreamConsumerAcquireAttribNV(eglDisplay(), renderOutput.eglStream, acquireAttribs)) { @@ -554,15 +547,9 @@ void EglStreamBackend::endFrame(int screenId, const QRegion &renderedRegion, con QSharedPointer EglStreamBackend::renderTestFrame(DrmAbstractOutput *drmOutput) { - auto it = std::find_if(m_outputs.begin(), m_outputs.end(), - [drmOutput] (const Output &o) { - return o.output == drmOutput; - } - ); - if (it == m_outputs.end()) { - return nullptr; - } - auto buffer = (*it).dumbSwapchain ? (*it).dumbSwapchain->currentBuffer() : (*it).buffer; + Q_ASSERT(m_outputs.contains(drmOutput)); + auto &output = m_outputs[drmOutput]; + auto buffer = output.dumbSwapchain ? output.dumbSwapchain->currentBuffer() : output.buffer; auto size = drmOutput->sourceSize(); if (buffer->size() == size) { return buffer; @@ -571,6 +558,11 @@ QSharedPointer EglStreamBackend::renderTestFrame(DrmAbstractOutput *d } } +bool EglStreamBackend::hasOutput(AbstractOutput *output) const +{ + return m_outputs.contains(output); +} + /************************************************ * EglTexture ************************************************/ diff --git a/src/plugins/platforms/drm/egl_stream_backend.h b/src/plugins/platforms/drm/egl_stream_backend.h index 20e971b94b..91c40adad9 100644 --- a/src/plugins/platforms/drm/egl_stream_backend.h +++ b/src/plugins/platforms/drm/egl_stream_backend.h @@ -33,14 +33,11 @@ public: ~EglStreamBackend() override; PlatformSurfaceTexture *createPlatformSurfaceTextureInternal(SurfacePixmapInternal *pixmap) override; PlatformSurfaceTexture *createPlatformSurfaceTextureWayland(SurfacePixmapWayland *pixmap) override; - QRegion beginFrame(int screenId) override; - void endFrame(int screenId, const QRegion &damage, const QRegion &damagedRegion) override; + QRegion beginFrame(AbstractOutput *output) override; + void endFrame(AbstractOutput *output, const QRegion &damage, const QRegion &damagedRegion) override; void init() override; - int screenCount() const override { - return m_outputs.count(); - } - + bool hasOutput(AbstractOutput *output) const override; bool addOutput(DrmAbstractOutput *output) override; void removeOutput(DrmAbstractOutput *output) override; @@ -74,11 +71,11 @@ private: // for operation as secondary GPU QSharedPointer dumbSwapchain; }; - bool resetOutput(Output &output, DrmOutput *drmOutput); + bool resetOutput(Output &output); bool makeContextCurrent(const Output &output); void cleanupOutput(Output &output); - QVector m_outputs; + QMap m_outputs; KWaylandServer::EglStreamControllerInterface *m_eglStreamControllerInterface; QHash m_streamTextures; diff --git a/src/plugins/platforms/drm/scene_qpainter_drm_backend.cpp b/src/plugins/platforms/drm/scene_qpainter_drm_backend.cpp index d57605f4f7..bc388eba63 100644 --- a/src/plugins/platforms/drm/scene_qpainter_drm_backend.cpp +++ b/src/plugins/platforms/drm/scene_qpainter_drm_backend.cpp @@ -45,31 +45,24 @@ void DrmQPainterBackend::initOutput(DrmAbstractOutput *output) Output o; o.swapchain = QSharedPointer::create(m_gpu, output->pixelSize()); o.output = output; - m_outputs << o; + m_outputs.insert(output, o); connect(output, &DrmOutput::modeChanged, this, [output, this] { - auto it = std::find_if(m_outputs.begin(), m_outputs.end(), - [output] (const auto &o) { - return o.output == output; - } - ); - if (it == m_outputs.end()) { - return; - } - it->swapchain = QSharedPointer::create(m_gpu, output->pixelSize()); - it->damageJournal.setCapacity(it->swapchain->slotCount()); + auto &o = m_outputs[output]; + o.swapchain = QSharedPointer::create(m_gpu, output->pixelSize()); + o.damageJournal.setCapacity(o.swapchain->slotCount()); } ); } -QImage *DrmQPainterBackend::bufferForScreen(int screenId) +QImage *DrmQPainterBackend::bufferForScreen(AbstractOutput *output) { - return m_outputs[screenId].swapchain->currentBuffer()->image(); + return m_outputs[output].swapchain->currentBuffer()->image(); } -QRegion DrmQPainterBackend::beginFrame(int screenId) +QRegion DrmQPainterBackend::beginFrame(AbstractOutput *output) { - Output *rendererOutput = &m_outputs[screenId]; + Output *rendererOutput = &m_outputs[output]; int bufferAge; rendererOutput->swapchain->acquireBuffer(&bufferAge); @@ -77,9 +70,9 @@ QRegion DrmQPainterBackend::beginFrame(int screenId) return rendererOutput->damageJournal.accumulate(bufferAge, rendererOutput->output->geometry()); } -void DrmQPainterBackend::endFrame(int screenId, const QRegion &damage) +void DrmQPainterBackend::endFrame(AbstractOutput *output, const QRegion &damage) { - Output &rendererOutput = m_outputs[screenId]; + Output &rendererOutput = m_outputs[output]; DrmAbstractOutput *drmOutput = rendererOutput.output; QSharedPointer back = rendererOutput.swapchain->currentBuffer(); diff --git a/src/plugins/platforms/drm/scene_qpainter_drm_backend.h b/src/plugins/platforms/drm/scene_qpainter_drm_backend.h index 7e4c28fe96..6d29abf841 100644 --- a/src/plugins/platforms/drm/scene_qpainter_drm_backend.h +++ b/src/plugins/platforms/drm/scene_qpainter_drm_backend.h @@ -31,9 +31,9 @@ class DrmQPainterBackend : public QPainterBackend public: DrmQPainterBackend(DrmBackend *backend, DrmGpu *gpu); - QImage *bufferForScreen(int screenId) override; - QRegion beginFrame(int screenId) override; - void endFrame(int screenId, const QRegion &damage) override; + QImage *bufferForScreen(AbstractOutput *output) override; + QRegion beginFrame(AbstractOutput *output) override; + void endFrame(AbstractOutput *output, const QRegion &damage) override; private: void initOutput(DrmAbstractOutput *output); @@ -42,7 +42,7 @@ private: QSharedPointer swapchain; DamageJournal damageJournal; }; - QVector m_outputs; + QMap m_outputs; DrmBackend *m_backend; DrmGpu *m_gpu; }; diff --git a/src/plugins/platforms/fbdev/scene_qpainter_fb_backend.cpp b/src/plugins/platforms/fbdev/scene_qpainter_fb_backend.cpp index 1c7454e503..f76a9459b2 100644 --- a/src/plugins/platforms/fbdev/scene_qpainter_fb_backend.cpp +++ b/src/plugins/platforms/fbdev/scene_qpainter_fb_backend.cpp @@ -63,28 +63,26 @@ void FramebufferQPainterBackend::deactivate() FramebufferQPainterBackend::~FramebufferQPainterBackend() = default; -QImage* FramebufferQPainterBackend::bufferForScreen(int screenId) +QImage* FramebufferQPainterBackend::bufferForScreen(AbstractOutput *output) { - Q_UNUSED(screenId) + Q_UNUSED(output) return &m_renderBuffer; } -QRegion FramebufferQPainterBackend::beginFrame(int screenId) +QRegion FramebufferQPainterBackend::beginFrame(AbstractOutput *output) { - return screens()->geometry(screenId); + return output->geometry(); } -void FramebufferQPainterBackend::endFrame(int screenId, const QRegion &damage) +void FramebufferQPainterBackend::endFrame(AbstractOutput *output, const QRegion &damage) { - Q_UNUSED(screenId) Q_UNUSED(damage) if (!kwinApp()->platform()->session()->isActive()) { return; } - FramebufferOutput *output = static_cast(m_backend->findOutput(screenId)); - output->vsyncMonitor()->arm(); + static_cast(output)->vsyncMonitor()->arm(); QPainter p(&m_backBuffer); p.drawImage(QPoint(0, 0), m_backend->isBGR() ? m_renderBuffer.rgbSwapped() : m_renderBuffer); diff --git a/src/plugins/platforms/fbdev/scene_qpainter_fb_backend.h b/src/plugins/platforms/fbdev/scene_qpainter_fb_backend.h index 50fa816ff6..be6ca590b3 100644 --- a/src/plugins/platforms/fbdev/scene_qpainter_fb_backend.h +++ b/src/plugins/platforms/fbdev/scene_qpainter_fb_backend.h @@ -24,9 +24,9 @@ public: FramebufferQPainterBackend(FramebufferBackend *backend); ~FramebufferQPainterBackend() override; - QImage *bufferForScreen(int screenId) override; - QRegion beginFrame(int screenId) override; - void endFrame(int screenId, const QRegion &damage) override; + QImage *bufferForScreen(AbstractOutput *output) override; + QRegion beginFrame(AbstractOutput *output) override; + void endFrame(AbstractOutput *output, const QRegion &damage) override; private: void reactivate(); diff --git a/src/plugins/platforms/virtual/egl_gbm_backend.cpp b/src/plugins/platforms/virtual/egl_gbm_backend.cpp index 926b948b0e..dabdd633e9 100644 --- a/src/plugins/platforms/virtual/egl_gbm_backend.cpp +++ b/src/plugins/platforms/virtual/egl_gbm_backend.cpp @@ -150,9 +150,9 @@ PlatformSurfaceTexture *EglGbmBackend::createPlatformSurfaceTextureWayland(Surfa return new BasicEGLSurfaceTextureWayland(this, pixmap); } -QRegion EglGbmBackend::beginFrame(int screenId) +QRegion EglGbmBackend::beginFrame(AbstractOutput *output) { - Q_UNUSED(screenId) + Q_UNUSED(output) if (!GLRenderTarget::isRenderTargetBound()) { GLRenderTarget::pushRenderTarget(m_fbo); } @@ -190,14 +190,13 @@ static void convertFromGLImage(QImage &img, int w, int h) img = img.mirrored(); } -void EglGbmBackend::endFrame(int screenId, const QRegion &renderedRegion, const QRegion &damagedRegion) +void EglGbmBackend::endFrame(AbstractOutput *output, const QRegion &renderedRegion, const QRegion &damagedRegion) { Q_UNUSED(renderedRegion) Q_UNUSED(damagedRegion) glFlush(); - VirtualOutput *output = static_cast(m_backend->findOutput(screenId)); - output->vsyncMonitor()->arm(); + static_cast(output)->vsyncMonitor()->arm(); if (m_backend->saveFrames()) { QImage img = QImage(QSize(m_backBuffer->width(), m_backBuffer->height()), QImage::Format_ARGB32); diff --git a/src/plugins/platforms/virtual/egl_gbm_backend.h b/src/plugins/platforms/virtual/egl_gbm_backend.h index 9a78e5f475..03e6869415 100644 --- a/src/plugins/platforms/virtual/egl_gbm_backend.h +++ b/src/plugins/platforms/virtual/egl_gbm_backend.h @@ -28,8 +28,8 @@ public: ~EglGbmBackend() override; PlatformSurfaceTexture *createPlatformSurfaceTextureInternal(SurfacePixmapInternal *pixmap) override; PlatformSurfaceTexture *createPlatformSurfaceTextureWayland(SurfacePixmapWayland *pixmap) override; - QRegion beginFrame(int screenId) override; - void endFrame(int screenId, const QRegion &renderedRegion, const QRegion &damagedRegion) override; + QRegion beginFrame(AbstractOutput *output) override; + void endFrame(AbstractOutput *output, const QRegion &renderedRegion, const QRegion &damagedRegion) override; void init() override; private: diff --git a/src/plugins/platforms/virtual/scene_qpainter_virtual_backend.cpp b/src/plugins/platforms/virtual/scene_qpainter_virtual_backend.cpp index 1f8761edb4..1b37ee0ff8 100644 --- a/src/plugins/platforms/virtual/scene_qpainter_virtual_backend.cpp +++ b/src/plugins/platforms/virtual/scene_qpainter_virtual_backend.cpp @@ -27,35 +27,35 @@ VirtualQPainterBackend::VirtualQPainterBackend(VirtualBackend *backend) VirtualQPainterBackend::~VirtualQPainterBackend() = default; -QImage *VirtualQPainterBackend::bufferForScreen(int screen) +QImage *VirtualQPainterBackend::bufferForScreen(AbstractOutput *output) { - return &m_backBuffers[screen]; + return &m_backBuffers[output]; } -QRegion VirtualQPainterBackend::beginFrame(int screenId) +QRegion VirtualQPainterBackend::beginFrame(AbstractOutput *output) { - return screens()->geometry(screenId); + return output->geometry(); } void VirtualQPainterBackend::createOutputs() { m_backBuffers.clear(); - for (int i = 0; i < screens()->count(); ++i) { - QImage buffer(screens()->size(i) * screens()->scale(i), QImage::Format_RGB32); + const auto outputs = m_backend->enabledOutputs(); + for (const auto &output : outputs) { + QImage buffer(output->pixelSize(), QImage::Format_RGB32); buffer.fill(Qt::black); - m_backBuffers << buffer; + m_backBuffers.insert(output, buffer); } } -void VirtualQPainterBackend::endFrame(int screenId, const QRegion &damage) +void VirtualQPainterBackend::endFrame(AbstractOutput *output, const QRegion &damage) { Q_UNUSED(damage) - VirtualOutput *output = static_cast(m_backend->findOutput(screenId)); - output->vsyncMonitor()->arm(); + static_cast(output)->vsyncMonitor()->arm(); if (m_backend->saveFrames()) { - m_backBuffers[screenId].save(QStringLiteral("%1/screen%2-%3.png").arg(m_backend->screenshotDirPath(), QString::number(screenId), QString::number(m_frameCounter++))); + m_backBuffers[output].save(QStringLiteral("%1/%s-%3.png").arg(m_backend->screenshotDirPath(), output->name(), QString::number(m_frameCounter++))); } } diff --git a/src/plugins/platforms/virtual/scene_qpainter_virtual_backend.h b/src/plugins/platforms/virtual/scene_qpainter_virtual_backend.h index 2883832661..fab4b0c54c 100644 --- a/src/plugins/platforms/virtual/scene_qpainter_virtual_backend.h +++ b/src/plugins/platforms/virtual/scene_qpainter_virtual_backend.h @@ -13,6 +13,7 @@ #include #include +#include namespace KWin { @@ -26,14 +27,14 @@ public: VirtualQPainterBackend(VirtualBackend *backend); ~VirtualQPainterBackend() override; - QImage *bufferForScreen(int screenId) override; - QRegion beginFrame(int screenId) override; - void endFrame(int screenId, const QRegion &damage) override; + QImage *bufferForScreen(AbstractOutput *output) override; + QRegion beginFrame(AbstractOutput *output) override; + void endFrame(AbstractOutput *output, const QRegion &damage) override; private: void createOutputs(); - QVector m_backBuffers; + QMap m_backBuffers; VirtualBackend *m_backend; int m_frameCounter = 0; }; diff --git a/src/plugins/platforms/wayland/egl_wayland_backend.cpp b/src/plugins/platforms/wayland/egl_wayland_backend.cpp index 9879d21afc..e5c6571566 100644 --- a/src/plugins/platforms/wayland/egl_wayland_backend.cpp +++ b/src/plugins/platforms/wayland/egl_wayland_backend.cpp @@ -141,11 +141,12 @@ void EglWaylandBackend::cleanupSurfaces() bool EglWaylandBackend::createEglWaylandOutput(AbstractOutput *waylandOutput) { - auto *output = new EglWaylandOutput(static_cast(waylandOutput), this); + const auto &output = new EglWaylandOutput(static_cast(waylandOutput), this); if (!output->init(this)) { + delete output; return false; } - m_outputs << output; + m_outputs.insert(waylandOutput, output); return true; } @@ -298,15 +299,16 @@ static QVector regionToRects(const QRegion ®ion, AbstractWaylandOutpu return rects; } -void EglWaylandBackend::aboutToStartPainting(int screenId, const QRegion &damagedRegion) +void EglWaylandBackend::aboutToStartPainting(AbstractOutput *output, const QRegion &damagedRegion) { - Q_ASSERT_X(screenId != -1, "aboutToStartPainting", "not using per screen rendering"); - EglWaylandOutput *output = m_outputs.at(screenId); - if (output->m_bufferAge > 0 && !damagedRegion.isEmpty() && supportsPartialUpdate()) { - const QRegion region = damagedRegion & output->m_waylandOutput->geometry(); + Q_ASSERT_X(output, "aboutToStartPainting", "not using per screen rendering"); + Q_ASSERT(m_outputs.contains(output)); + const auto &eglOutput = m_outputs[output]; + if (eglOutput->m_bufferAge > 0 && !damagedRegion.isEmpty() && supportsPartialUpdate()) { + const QRegion region = damagedRegion & eglOutput->m_waylandOutput->geometry(); - QVector rects = regionToRects(region, output->m_waylandOutput); - const bool correct = eglSetDamageRegionKHR(eglDisplay(), output->m_eglSurface, + QVector rects = regionToRects(region, eglOutput->m_waylandOutput); + const bool correct = eglSetDamageRegionKHR(eglDisplay(), eglOutput->m_eglSurface, rects.data(), rects.count()/4); if (!correct) { qCWarning(KWIN_WAYLAND_BACKEND) << "failed eglSetDamageRegionKHR" << eglGetError(); @@ -350,27 +352,29 @@ PlatformSurfaceTexture *EglWaylandBackend::createPlatformSurfaceTextureWayland(S return new BasicEGLSurfaceTextureWayland(this, pixmap); } -QRegion EglWaylandBackend::beginFrame(int screenId) +QRegion EglWaylandBackend::beginFrame(AbstractOutput *output) { + Q_ASSERT(m_outputs.contains(output)); eglWaitNative(EGL_CORE_NATIVE_ENGINE); - auto *output = m_outputs.at(screenId); - makeContextCurrent(output); + const auto &eglOutput = m_outputs[output]; + makeContextCurrent(eglOutput); if (supportsBufferAge()) { - return output->m_damageJournal.accumulate(output->m_bufferAge, output->m_waylandOutput->geometry()); + return eglOutput->m_damageJournal.accumulate(eglOutput->m_bufferAge, eglOutput->m_waylandOutput->geometry()); } return QRegion(); } -void EglWaylandBackend::endFrame(int screenId, const QRegion &renderedRegion, const QRegion &damagedRegion) +void EglWaylandBackend::endFrame(AbstractOutput *output, const QRegion &renderedRegion, const QRegion &damagedRegion) { + Q_ASSERT(m_outputs.contains(output)); Q_UNUSED(renderedRegion); - EglWaylandOutput *output = m_outputs[screenId]; - QRegion damage = damagedRegion.intersected(output->m_waylandOutput->geometry()); - presentOnSurface(output, damage); + const auto &eglOutput = m_outputs[output]; + QRegion damage = damagedRegion.intersected(eglOutput->m_waylandOutput->geometry()); + presentOnSurface(eglOutput, damage); if (supportsBufferAge()) { - output->m_damageJournal.add(damage); + eglOutput->m_damageJournal.add(damage); } } diff --git a/src/plugins/platforms/wayland/egl_wayland_backend.h b/src/plugins/platforms/wayland/egl_wayland_backend.h index 8cb8ec5495..96f73bb763 100644 --- a/src/plugins/platforms/wayland/egl_wayland_backend.h +++ b/src/plugins/platforms/wayland/egl_wayland_backend.h @@ -71,15 +71,15 @@ public: PlatformSurfaceTexture *createPlatformSurfaceTextureInternal(SurfacePixmapInternal *pixmap) override; PlatformSurfaceTexture *createPlatformSurfaceTextureWayland(SurfacePixmapWayland *pixmap) override; - QRegion beginFrame(int screenId) override; - void endFrame(int screenId, const QRegion &damage, const QRegion &damagedRegion) override; + QRegion beginFrame(AbstractOutput *output) override; + void endFrame(AbstractOutput *output, const QRegion &damage, const QRegion &damagedRegion) override; void init() override; bool havePlatformBase() const { return m_havePlatformBase; } - void aboutToStartPainting(int screenId, const QRegion &damage) override; + void aboutToStartPainting(AbstractOutput *output, const QRegion &damage) override; private: bool initializeEgl(); @@ -95,7 +95,7 @@ private: void presentOnSurface(EglWaylandOutput *output, const QRegion &damagedRegion); WaylandBackend *m_backend; - QVector m_outputs; + QMap m_outputs; bool m_havePlatformBase; friend class EglWaylandTexture; }; diff --git a/src/plugins/platforms/wayland/scene_qpainter_wayland_backend.cpp b/src/plugins/platforms/wayland/scene_qpainter_wayland_backend.cpp index 977bd92ab8..5761b50b10 100644 --- a/src/plugins/platforms/wayland/scene_qpainter_wayland_backend.cpp +++ b/src/plugins/platforms/wayland/scene_qpainter_wayland_backend.cpp @@ -169,25 +169,25 @@ void WaylandQPainterBackend::createOutput(AbstractOutput *waylandOutput) { auto *output = new WaylandQPainterOutput(static_cast(waylandOutput), this); output->init(m_backend->shmPool()); - m_outputs << output; + m_outputs.insert(waylandOutput, output); } -void WaylandQPainterBackend::endFrame(int screenId, const QRegion &damage) +void WaylandQPainterBackend::endFrame(AbstractOutput *output, const QRegion &damage) { - WaylandQPainterOutput *rendererOutput = m_outputs.value(screenId); + WaylandQPainterOutput *rendererOutput = m_outputs[output]; Q_ASSERT(rendererOutput); rendererOutput->present(rendererOutput->mapToLocal(damage)); } -QImage *WaylandQPainterBackend::bufferForScreen(int screenId) +QImage *WaylandQPainterBackend::bufferForScreen(AbstractOutput *output) { - return &m_outputs[screenId]->back()->image; + return &m_outputs[output]->back()->image; } -QRegion WaylandQPainterBackend::beginFrame(int screenId) +QRegion WaylandQPainterBackend::beginFrame(AbstractOutput *output) { - WaylandQPainterOutput *rendererOutput = m_outputs.value(screenId); + WaylandQPainterOutput *rendererOutput = m_outputs[output]; Q_ASSERT(rendererOutput); WaylandQPainterBufferSlot *slot = rendererOutput->acquire(); diff --git a/src/plugins/platforms/wayland/scene_qpainter_wayland_backend.h b/src/plugins/platforms/wayland/scene_qpainter_wayland_backend.h index c2672f5903..11635f7051 100644 --- a/src/plugins/platforms/wayland/scene_qpainter_wayland_backend.h +++ b/src/plugins/platforms/wayland/scene_qpainter_wayland_backend.h @@ -83,17 +83,17 @@ public: explicit WaylandQPainterBackend(WaylandBackend *b); ~WaylandQPainterBackend() override; - QImage *bufferForScreen(int screenId) override; + QImage *bufferForScreen(AbstractOutput *output) override; - void endFrame(int screenId, const QRegion& damage) override; - QRegion beginFrame(int screenId) override; + void endFrame(AbstractOutput *output, const QRegion& damage) override; + QRegion beginFrame(AbstractOutput *output) override; private: void createOutput(AbstractOutput *waylandOutput); void frameRendered(); WaylandBackend *m_backend; - QVector m_outputs; + QMap m_outputs; }; } diff --git a/src/plugins/platforms/x11/standalone/eglbackend.cpp b/src/plugins/platforms/x11/standalone/eglbackend.cpp index 465dc58943..d627d63952 100644 --- a/src/plugins/platforms/x11/standalone/eglbackend.cpp +++ b/src/plugins/platforms/x11/standalone/eglbackend.cpp @@ -88,9 +88,9 @@ void EglBackend::screenGeometryChanged() m_bufferAge = 0; } -QRegion EglBackend::beginFrame(int screenId) +QRegion EglBackend::beginFrame(AbstractOutput *output) { - Q_UNUSED(screenId) + Q_UNUSED(output) makeCurrent(); const QSize size = screens()->size(); @@ -106,9 +106,9 @@ QRegion EglBackend::beginFrame(int screenId) return repaint; } -void EglBackend::endFrame(int screenId, const QRegion &renderedRegion, const QRegion &damagedRegion) +void EglBackend::endFrame(AbstractOutput *output, const QRegion &renderedRegion, const QRegion &damagedRegion) { - Q_UNUSED(screenId) + Q_UNUSED(output) // Start the software vsync monitor. There is no any reliable way to determine when // eglSwapBuffers() or eglSwapBuffersWithDamageEXT() completes. diff --git a/src/plugins/platforms/x11/standalone/eglbackend.h b/src/plugins/platforms/x11/standalone/eglbackend.h index af6399e197..e49f4df8e3 100644 --- a/src/plugins/platforms/x11/standalone/eglbackend.h +++ b/src/plugins/platforms/x11/standalone/eglbackend.h @@ -31,8 +31,8 @@ public: void init() override; PlatformSurfaceTexture *createPlatformSurfaceTextureX11(SurfacePixmapX11 *texture) override; - QRegion beginFrame(int screenId) override; - void endFrame(int screenId, const QRegion &damage, const QRegion &damagedRegion) override; + QRegion beginFrame(AbstractOutput *output) override; + void endFrame(AbstractOutput *output, const QRegion &damage, const QRegion &damagedRegion) override; private: void screenGeometryChanged(); diff --git a/src/plugins/platforms/x11/standalone/glxbackend.cpp b/src/plugins/platforms/x11/standalone/glxbackend.cpp index 5254dd5be4..881adbdbab 100644 --- a/src/plugins/platforms/x11/standalone/glxbackend.cpp +++ b/src/plugins/platforms/x11/standalone/glxbackend.cpp @@ -739,9 +739,9 @@ PlatformSurfaceTexture *GlxBackend::createPlatformSurfaceTextureX11(SurfacePixma return new GlxSurfaceTextureX11(this, pixmap); } -QRegion GlxBackend::beginFrame(int screenId) +QRegion GlxBackend::beginFrame(AbstractOutput *output) { - Q_UNUSED(screenId) + Q_UNUSED(output) QRegion repaint; makeCurrent(); @@ -758,9 +758,9 @@ QRegion GlxBackend::beginFrame(int screenId) return repaint; } -void GlxBackend::endFrame(int screenId, const QRegion &renderedRegion, const QRegion &damagedRegion) +void GlxBackend::endFrame(AbstractOutput *output, const QRegion &renderedRegion, const QRegion &damagedRegion) { - Q_UNUSED(screenId) + Q_UNUSED(output) // If the GLX_INTEL_swap_event extension is not used for getting presentation feedback, // assume that the frame will be presented at the next vblank event, this is racy. diff --git a/src/plugins/platforms/x11/standalone/glxbackend.h b/src/plugins/platforms/x11/standalone/glxbackend.h index fffe349062..7a0c88c4d2 100644 --- a/src/plugins/platforms/x11/standalone/glxbackend.h +++ b/src/plugins/platforms/x11/standalone/glxbackend.h @@ -72,8 +72,8 @@ public: GlxBackend(Display *display, X11StandalonePlatform *backend); ~GlxBackend() override; PlatformSurfaceTexture *createPlatformSurfaceTextureX11(SurfacePixmapX11 *pixmap) override; - QRegion beginFrame(int screenId) override; - void endFrame(int screenId, const QRegion &damage, const QRegion &damagedRegion) override; + QRegion beginFrame(AbstractOutput *output) override; + void endFrame(AbstractOutput *output, const QRegion &damage, const QRegion &damagedRegion) override; bool makeCurrent() override; void doneCurrent() override; OverlayWindow* overlayWindow() const override; diff --git a/src/plugins/platforms/x11/windowed/egl_x11_backend.cpp b/src/plugins/platforms/x11/windowed/egl_x11_backend.cpp index f839d67990..57ddf67906 100644 --- a/src/plugins/platforms/x11/windowed/egl_x11_backend.cpp +++ b/src/plugins/platforms/x11/windowed/egl_x11_backend.cpp @@ -47,12 +47,13 @@ void EglX11Backend::cleanupSurfaces() bool EglX11Backend::createSurfaces() { - for (int i = 0; i < screens()->count(); ++i) { - EGLSurface s = createSurface(m_backend->windowForScreen(i)); + const auto &outputs = m_backend->outputs(); + for (const auto &output : outputs) { + EGLSurface s = createSurface(m_backend->windowForScreen(output)); if (s == EGL_NO_SURFACE) { return false; } - m_surfaces << s; + m_surfaces.insert(output, s); } if (m_surfaces.isEmpty()) { return false; @@ -61,29 +62,26 @@ bool EglX11Backend::createSurfaces() return true; } -QRegion EglX11Backend::beginFrame(int screenId) +QRegion EglX11Backend::beginFrame(AbstractOutput *output) { - makeContextCurrent(m_surfaces.at(screenId)); - setupViewport(screenId); - return screens()->geometry(screenId); + makeContextCurrent(m_surfaces[output]); + setupViewport(output); + return output->geometry(); } -void EglX11Backend::setupViewport(int screenId) +void EglX11Backend::setupViewport(AbstractOutput *output) { - qreal scale = screens()->scale(screenId); - const QSize size = screens()->geometry(screenId).size() * scale; + const QSize size = output->pixelSize() * output->scale(); glViewport(0, 0, size.width(), size.height()); } -void EglX11Backend::endFrame(int screenId, const QRegion &renderedRegion, const QRegion &damagedRegion) +void EglX11Backend::endFrame(AbstractOutput *output, const QRegion &renderedRegion, const QRegion &damagedRegion) { Q_UNUSED(damagedRegion) - X11WindowedOutput *output = static_cast(kwinApp()->platform()->findOutput(screenId)); - output->vsyncMonitor()->arm(); + static_cast(output)->vsyncMonitor()->arm(); - const QRect &outputGeometry = screens()->geometry(screenId); - presentSurface(m_surfaces.at(screenId), renderedRegion, outputGeometry); + presentSurface(m_surfaces[output], renderedRegion, output->geometry()); } void EglX11Backend::presentSurface(EGLSurface surface, const QRegion &damage, const QRect &screenGeometry) diff --git a/src/plugins/platforms/x11/windowed/egl_x11_backend.h b/src/plugins/platforms/x11/windowed/egl_x11_backend.h index 9f442ff8ed..46b3f28373 100644 --- a/src/plugins/platforms/x11/windowed/egl_x11_backend.h +++ b/src/plugins/platforms/x11/windowed/egl_x11_backend.h @@ -10,6 +10,8 @@ #define KWIN_EGL_X11_BACKEND_H #include "eglonxbackend.h" +#include + namespace KWin { @@ -29,18 +31,18 @@ public: PlatformSurfaceTexture *createPlatformSurfaceTextureInternal(SurfacePixmapInternal *pixmap) override; PlatformSurfaceTexture *createPlatformSurfaceTextureWayland(SurfacePixmapWayland *pixmap) override; void init() override; - QRegion beginFrame(int screenId) override; - void endFrame(int screenId, const QRegion &damage, const QRegion &damagedRegion) override; + QRegion beginFrame(AbstractOutput *output) override; + void endFrame(AbstractOutput *output, const QRegion &damage, const QRegion &damagedRegion) override; protected: void cleanupSurfaces() override; bool createSurfaces() override; private: - void setupViewport(int screenId); + void setupViewport(AbstractOutput *output); void presentSurface(EGLSurface surface, const QRegion &damage, const QRect &screenGeometry); - QVector m_surfaces; + QMap m_surfaces; X11WindowedBackend *m_backend; }; diff --git a/src/plugins/platforms/x11/windowed/scene_qpainter_x11_backend.cpp b/src/plugins/platforms/x11/windowed/scene_qpainter_x11_backend.cpp index 68571be399..6155b5b615 100644 --- a/src/plugins/platforms/x11/windowed/scene_qpainter_x11_backend.cpp +++ b/src/plugins/platforms/x11/windowed/scene_qpainter_x11_backend.cpp @@ -35,32 +35,31 @@ void X11WindowedQPainterBackend::createOutputs() { qDeleteAll(m_outputs); m_outputs.clear(); - for (int i = 0; i < screens()->count(); ++i) { + const auto &outputs = m_backend->outputs(); + for (const auto &x11Output : outputs) { Output *output = new Output; - output->window = m_backend->windowForScreen(i); - output->buffer = QImage(screens()->size(i) * screens()->scale(i), QImage::Format_RGB32); + output->window = m_backend->windowForScreen(x11Output); + output->buffer = QImage(x11Output->pixelSize() * x11Output->scale(), QImage::Format_RGB32); output->buffer.fill(Qt::black); - m_outputs << output; + m_outputs.insert(x11Output, output); } } -QImage *X11WindowedQPainterBackend::bufferForScreen(int screen) +QImage *X11WindowedQPainterBackend::bufferForScreen(AbstractOutput *output) { - return &m_outputs.at(screen)->buffer; + return &m_outputs[output]->buffer; } -QRegion X11WindowedQPainterBackend::beginFrame(int screenId) +QRegion X11WindowedQPainterBackend::beginFrame(AbstractOutput *output) { - Q_UNUSED(screenId) - return screens()->geometry(screenId); + return output->geometry(); } -void X11WindowedQPainterBackend::endFrame(int screenId, const QRegion &damage) +void X11WindowedQPainterBackend::endFrame(AbstractOutput *output, const QRegion &damage) { Q_UNUSED(damage) - X11WindowedOutput *output = static_cast(kwinApp()->platform()->findOutput(screenId)); - output->vsyncMonitor()->arm(); + static_cast(output)->vsyncMonitor()->arm(); xcb_connection_t *c = m_backend->connection(); const xcb_window_t window = m_backend->window(); @@ -69,7 +68,7 @@ void X11WindowedQPainterBackend::endFrame(int screenId, const QRegion &damage) xcb_create_gc(c, m_gc, window, 0, nullptr); } - Output *rendererOutput = m_outputs.value(screenId); + Output *rendererOutput = m_outputs[output]; Q_ASSERT(rendererOutput); // TODO: only update changes? diff --git a/src/plugins/platforms/x11/windowed/scene_qpainter_x11_backend.h b/src/plugins/platforms/x11/windowed/scene_qpainter_x11_backend.h index f9e00fc44e..4587048116 100644 --- a/src/plugins/platforms/x11/windowed/scene_qpainter_x11_backend.h +++ b/src/plugins/platforms/x11/windowed/scene_qpainter_x11_backend.h @@ -14,6 +14,7 @@ #include #include #include +#include #include @@ -29,9 +30,9 @@ public: X11WindowedQPainterBackend(X11WindowedBackend *backend); ~X11WindowedQPainterBackend() override; - QImage *bufferForScreen(int screenId) override; - QRegion beginFrame(int screenId) override; - void endFrame(int screenId, const QRegion &damage) override; + QImage *bufferForScreen(AbstractOutput *output) override; + QRegion beginFrame(AbstractOutput *output) override; + void endFrame(AbstractOutput *output, const QRegion &damage) override; private: void createOutputs(); @@ -41,7 +42,7 @@ private: xcb_window_t window; QImage buffer; }; - QVector m_outputs; + QMap m_outputs; }; } diff --git a/src/plugins/platforms/x11/windowed/x11windowed_backend.cpp b/src/plugins/platforms/x11/windowed/x11windowed_backend.cpp index e14924f4a1..ff897290f4 100644 --- a/src/plugins/platforms/x11/windowed/x11windowed_backend.cpp +++ b/src/plugins/platforms/x11/windowed/x11windowed_backend.cpp @@ -525,12 +525,17 @@ void X11WindowedBackend::warpPointer(const QPointF &globalPos) xcb_flush(m_connection); } -xcb_window_t X11WindowedBackend::windowForScreen(int screen) const +xcb_window_t X11WindowedBackend::windowForScreen(AbstractOutput *output) const { - if (screen > m_outputs.count()) { + if (!output) { return XCB_WINDOW_NONE; } - return m_outputs.at(screen)->window(); + return static_cast(output)->window(); +} + +xcb_window_t X11WindowedBackend::window() const +{ + return m_outputs.first()->window(); } Outputs X11WindowedBackend::outputs() const diff --git a/src/plugins/platforms/x11/windowed/x11windowed_backend.h b/src/plugins/platforms/x11/windowed/x11windowed_backend.h index 804597a1a9..a3b6144ff7 100644 --- a/src/plugins/platforms/x11/windowed/x11windowed_backend.h +++ b/src/plugins/platforms/x11/windowed/x11windowed_backend.h @@ -47,10 +47,8 @@ public: int screenNumer() const { return m_screenNumber; } - xcb_window_t window() const { - return windowForScreen(0); - } - xcb_window_t windowForScreen(int screen) const; + xcb_window_t window() const; + xcb_window_t windowForScreen(AbstractOutput *output) const; Display *display() const { return m_display; } diff --git a/src/plugins/scenes/opengl/scene_opengl.cpp b/src/plugins/scenes/opengl/scene_opengl.cpp index ff748e3340..fa86259133 100644 --- a/src/plugins/scenes/opengl/scene_opengl.cpp +++ b/src/plugins/scenes/opengl/scene_opengl.cpp @@ -34,6 +34,7 @@ #include "shadowitem.h" #include "surfaceitem.h" #include "windowitem.h" +#include "abstract_output.h" #include #include @@ -342,9 +343,9 @@ void SceneOpenGL2::paintCursor(const QRegion &rendered) glDisable(GL_BLEND); } -void SceneOpenGL::aboutToStartPainting(int screenId, const QRegion &damage) +void SceneOpenGL::aboutToStartPainting(AbstractOutput *output, const QRegion &damage) { - m_backend->aboutToStartPainting(screenId, damage); + m_backend->aboutToStartPainting(output, damage); } static SurfaceItem *findTopMostSurface(SurfaceItem *item) @@ -357,14 +358,14 @@ static SurfaceItem *findTopMostSurface(SurfaceItem *item) } } -void SceneOpenGL::paint(int screenId, const QRegion &damage, const QList &toplevels, +void SceneOpenGL::paint(AbstractOutput *output, const QRegion &damage, const QList &toplevels, RenderLoop *renderLoop) { if (m_resetOccurred) { return; // A graphics reset has occurred, do nothing. } - painted_screen = screenId; + painted_screen = output; // actually paint the frame, flushed with the NEXT frame createStackingOrder(toplevels); @@ -373,9 +374,9 @@ void SceneOpenGL::paint(int screenId, const QRegion &damage, const QListgeometry(screenId); - scaling = screens()->scale(screenId); + if (output) { + geo = output->geometry(); + scaling = output->scale(); } else { geo = screens()->geometry(); scaling = 1; @@ -391,7 +392,7 @@ void SceneOpenGL::paint(int screenId, const QRegion &damage, const QList=0; i--) { Window *window = stacking_order[i]; Toplevel *toplevel = window->window(); - if (toplevel->isOnScreen(screenId) && window->isVisible() && toplevel->opacity() > 0) { + if (output && toplevel->isOnOutput(output) && window->isVisible() && toplevel->opacity() > 0) { AbstractClient *c = dynamic_cast(toplevel); if (!c || !c->isFullScreen()) { break; @@ -420,14 +421,14 @@ void SceneOpenGL::paint(int screenId, const QRegion &damage, const QListsetFullscreenSurface(fullscreenSurface); bool directScanout = false; - if (m_backend->directScanoutAllowed(screenId) && !static_cast(effects)->blocksDirectScanout()) { - directScanout = m_backend->scanout(screenId, fullscreenSurface); + if (m_backend->directScanoutAllowed(output) && !static_cast(effects)->blocksDirectScanout()) { + directScanout = m_backend->scanout(output, fullscreenSurface); } if (directScanout) { renderLoop->endFrame(); } else { // prepare rendering makescontext current on the output - repaint = m_backend->beginFrame(screenId); + repaint = m_backend->beginFrame(output); GLVertexBuffer::setVirtualScreenGeometry(geo); GLRenderTarget::setVirtualScreenGeometry(geo); @@ -440,7 +441,7 @@ void SceneOpenGL::paint(int screenId, const QRegion &damage, const QListisGLES() && screenId == -1) { + if (!GLPlatform::instance()->isGLES() && !output) { const QSize &screenSize = screens()->size(); const QRegion displayRegion(0, 0, screenSize.width(), screenSize.height()); @@ -458,7 +459,7 @@ void SceneOpenGL::paint(int screenId, const QRegion &damage, const QListendFrame(); GLVertexBuffer::streamingBuffer()->endOfFrame(); - m_backend->endFrame(screenId, valid, update); + m_backend->endFrame(output, valid, update); GLVertexBuffer::streamingBuffer()->framePosted(); } } diff --git a/src/plugins/scenes/opengl/scene_opengl.h b/src/plugins/scenes/opengl/scene_opengl.h index 7f62b6af0f..1a9fa347aa 100644 --- a/src/plugins/scenes/opengl/scene_opengl.h +++ b/src/plugins/scenes/opengl/scene_opengl.h @@ -32,7 +32,7 @@ public: class EffectFrame; ~SceneOpenGL() override; bool initFailed() const override; - void paint(int screenId, const QRegion &damage, const QList &windows, + void paint(AbstractOutput *output, const QRegion &damage, const QList &windows, RenderLoop *renderLoop) override; Scene::EffectFrame *createEffectFrame(EffectFrameImpl *frame) override; Shadow *createShadow(Toplevel *toplevel) override; @@ -62,7 +62,7 @@ public: protected: SceneOpenGL(OpenGLBackend *backend, QObject *parent = nullptr); void paintBackground(const QRegion ®ion) override; - void aboutToStartPainting(int screenId, const QRegion &damage) override; + void aboutToStartPainting(AbstractOutput *output, const QRegion &damage) override; void extendPaintRegion(QRegion ®ion, bool opaqueFullscreen) override; QMatrix4x4 transformation(int mask, const ScreenPaintData &data) const; void paintDesktop(int desktop, int mask, const QRegion ®ion, ScreenPaintData &data) override; diff --git a/src/plugins/scenes/qpainter/scene_qpainter.cpp b/src/plugins/scenes/qpainter/scene_qpainter.cpp index c704cccb39..9473c27065 100644 --- a/src/plugins/scenes/qpainter/scene_qpainter.cpp +++ b/src/plugins/scenes/qpainter/scene_qpainter.cpp @@ -22,6 +22,7 @@ #include "toplevel.h" #include "platform.h" #include "windowitem.h" +#include "abstract_output.h" #include // Qt @@ -79,18 +80,18 @@ void SceneQPainter::paintGenericScreen(int mask, const ScreenPaintData &data) m_painter->restore(); } -void SceneQPainter::paint(int screenId, const QRegion &damage, const QList &toplevels, +void SceneQPainter::paint(AbstractOutput *output, const QRegion &damage, const QList &toplevels, RenderLoop *renderLoop) { Q_ASSERT(kwinApp()->platform()->isPerScreenRenderingEnabled()); - painted_screen = screenId; + painted_screen = output; createStackingOrder(toplevels); - const QRegion repaint = m_backend->beginFrame(screenId); - const QRect geometry = screens()->geometry(screenId); + const QRegion repaint = m_backend->beginFrame(output); + const QRect geometry = output->geometry(); - QImage *buffer = m_backend->bufferForScreen(screenId); + QImage *buffer = m_backend->bufferForScreen(output); if (buffer && !buffer->isNull()) { renderLoop->beginFrame(); m_painter->begin(buffer); @@ -102,7 +103,7 @@ void SceneQPainter::paint(int screenId, const QRegion &damage, const QListend(); renderLoop->endFrame(); - m_backend->endFrame(screenId, updateRegion); + m_backend->endFrame(output, updateRegion); } // do cleanup @@ -159,9 +160,9 @@ Shadow *SceneQPainter::createShadow(Toplevel *toplevel) return new SceneQPainterShadow(toplevel); } -QImage *SceneQPainter::qpainterRenderBuffer(int screenId) const +QImage *SceneQPainter::qpainterRenderBuffer(AbstractOutput *output) const { - return m_backend->bufferForScreen(screenId); + return m_backend->bufferForScreen(output); } //**************************************** diff --git a/src/plugins/scenes/qpainter/scene_qpainter.h b/src/plugins/scenes/qpainter/scene_qpainter.h index b89fd93056..8b2a608082 100644 --- a/src/plugins/scenes/qpainter/scene_qpainter.h +++ b/src/plugins/scenes/qpainter/scene_qpainter.h @@ -24,7 +24,7 @@ class KWIN_EXPORT SceneQPainter : public Scene public: ~SceneQPainter() override; OverlayWindow* overlayWindow() const override; - void paint(int screenId, const QRegion &damage, const QList &windows, + void paint(AbstractOutput *output, const QRegion &damage, const QList &windows, RenderLoop *renderLoop) override; void paintGenericScreen(int mask, const ScreenPaintData &data) override; CompositingType compositingType() const override; @@ -40,7 +40,7 @@ public: } QPainter *scenePainter() const override; - QImage *qpainterRenderBuffer(int screenId) const override; + QImage *qpainterRenderBuffer(AbstractOutput *output) const override; QPainterBackend *backend() const { return m_backend.data(); diff --git a/src/scene.cpp b/src/scene.cpp index 9305d8d887..29f26483aa 100644 --- a/src/scene.cpp +++ b/src/scene.cpp @@ -85,11 +85,7 @@ namespace KWin Scene::Scene(QObject *parent) : QObject(parent) { - if (kwinApp()->platform()->isPerScreenRenderingEnabled()) { - connect(kwinApp()->platform(), &Platform::outputEnabled, this, &Scene::reallocRepaints); - connect(kwinApp()->platform(), &Platform::outputDisabled, this, &Scene::reallocRepaints); - } - reallocRepaints(); + connect(kwinApp()->platform(), &Platform::outputDisabled, this, &Scene::removeRepaints); } Scene::~Scene() @@ -101,14 +97,10 @@ void Scene::addRepaint(const QRegion ®ion) { if (kwinApp()->platform()->isPerScreenRenderingEnabled()) { const QVector outputs = kwinApp()->platform()->enabledOutputs(); - if (m_repaints.count() != outputs.count()) { - return; // Repaints haven't been reallocated yet, do nothing. - } - for (int screenId = 0; screenId < m_repaints.count(); ++screenId) { - AbstractOutput *output = outputs[screenId]; + for (const auto &output : outputs) { const QRegion dirtyRegion = region & output->geometry(); if (!dirtyRegion.isEmpty()) { - m_repaints[screenId] += dirtyRegion; + m_repaints[output] += dirtyRegion; output->renderLoop()->scheduleRepaint(); } } @@ -118,27 +110,19 @@ void Scene::addRepaint(const QRegion ®ion) } } -QRegion Scene::repaints(int screenId) const +QRegion Scene::repaints(AbstractOutput *output) const { - const int index = screenId == -1 ? 0 : screenId; - return m_repaints[index]; + return m_repaints.value(output, infiniteRegion()); } -void Scene::resetRepaints(int screenId) +void Scene::resetRepaints(AbstractOutput *output) { - const int index = screenId == -1 ? 0 : screenId; - m_repaints[index] = QRegion(); + m_repaints.insert(output, QRegion()); } -void Scene::reallocRepaints() +void Scene::removeRepaints(AbstractOutput *output) { - if (kwinApp()->platform()->isPerScreenRenderingEnabled()) { - m_repaints.resize(kwinApp()->platform()->enabledOutputs().count()); - } else { - m_repaints.resize(1); - } - - m_repaints.fill(infiniteRegion()); + m_repaints.remove(output); } // returns mask and possibly modified region @@ -164,7 +148,7 @@ void Scene::paintScreen(const QRegion &damage, const QRegion &repaint, QRegion region = damage; - auto screen = effects->findScreen(painted_screen); + auto screen = effects->findScreen(kwinApp()->platform()->enabledOutputs().indexOf(painted_screen)); ScreenPrePaintData pdata; pdata.mask = (damage == displayRegion) ? 0 : PAINT_SCREEN_REGION; pdata.paint = region; @@ -221,13 +205,13 @@ void Scene::finalPaintScreen(int mask, const QRegion ®ion, ScreenPaintData& d paintSimpleScreen(mask, region); } -static void resetRepaintsHelper(Item *item, int screen) +static void resetRepaintsHelper(Item *item, AbstractOutput *output) { - item->resetRepaints(screen); + item->resetRepaints(output); const auto childItems = item->childItems(); for (Item *childItem : childItems) { - resetRepaintsHelper(childItem, screen); + resetRepaintsHelper(childItem, output); } } @@ -273,14 +257,14 @@ void Scene::paintGenericScreen(int orig_mask, const ScreenPaintData &) } } -static void accumulateRepaints(Item *item, int screen, QRegion *repaints) +static void accumulateRepaints(Item *item, AbstractOutput *output, QRegion *repaints) { - *repaints += item->repaints(screen); - item->resetRepaints(screen); + *repaints += item->repaints(output); + item->resetRepaints(output); const auto childItems = item->childItems(); for (Item *childItem : childItems) { - accumulateRepaints(childItem, screen, repaints); + accumulateRepaints(childItem, output, repaints); } } @@ -503,9 +487,9 @@ void Scene::paintDesktop(int desktop, int mask, const QRegion ®ion, ScreenPai static_cast(effects)->paintDesktop(desktop, mask, region, data); } -void Scene::aboutToStartPainting(int screenId, const QRegion &damage) +void Scene::aboutToStartPainting(AbstractOutput *output, const QRegion &damage) { - Q_UNUSED(screenId) + Q_UNUSED(output) Q_UNUSED(damage) } @@ -554,9 +538,9 @@ QPainter *Scene::scenePainter() const return nullptr; } -QImage *Scene::qpainterRenderBuffer(int screenId) const +QImage *Scene::qpainterRenderBuffer(AbstractOutput *output) const { - Q_UNUSED(screenId) + Q_UNUSED(output) return nullptr; } diff --git a/src/scene.h b/src/scene.h index 2f115011d4..a28852b43f 100644 --- a/src/scene.h +++ b/src/scene.h @@ -59,10 +59,10 @@ public: void addRepaint(const QRegion ®ion); /** - * Returns the repaints region for output with the specified @a screenId. + * Returns the repaints region for output with the specified @a output. */ - QRegion repaints(int screenId) const; - void resetRepaints(int screenId); + QRegion repaints(AbstractOutput *output) const; + void resetRepaints(AbstractOutput *output); // Returns true if the ctor failed to properly initialize. virtual bool initFailed() const = 0; @@ -72,7 +72,7 @@ public: // The entry point for the main part of the painting pass. // returns the time since the last vblank signal - if there's one // ie. "what of this frame is lost to painting" - virtual void paint(int screenId, const QRegion &damage, const QList &windows, + virtual void paint(AbstractOutput *output, const QRegion &damage, const QList &windows, RenderLoop *renderLoop) = 0; /** @@ -159,7 +159,7 @@ public: * The render buffer used by a QPainter based compositor. * Default implementation returns @c nullptr. */ - virtual QImage *qpainterRenderBuffer(int screenId) const; + virtual QImage *qpainterRenderBuffer(AbstractOutput *output) const; /** * The backend specific extensions (e.g. EGL/GLX extensions). @@ -214,7 +214,7 @@ protected: * * @p damage contains the reported damage as suggested by windows and effects on prepaint calls. */ - virtual void aboutToStartPainting(int screenId, const QRegion &damage); + virtual void aboutToStartPainting(AbstractOutput *output, const QRegion &damage); // called after all effects had their paintWindow() called void finalPaintWindow(EffectWindowImpl* w, int mask, const QRegion ®ion, WindowPaintData& data); // shared implementation, starts painting the window @@ -245,15 +245,15 @@ protected: // The dirty region before it was unioned with repaint_region QRegion damaged_region; // The screen that is being currently painted - int painted_screen = -1; + AbstractOutput *painted_screen = nullptr; // windows in their stacking order QVector< Window* > stacking_order; private: + void removeRepaints(AbstractOutput *output); std::chrono::milliseconds m_expectedPresentTimestamp = std::chrono::milliseconds::zero(); - void reallocRepaints(); QHash< Toplevel*, Window* > m_windows; - QVector m_repaints; + QMap m_repaints; // how many times finalPaintScreen() has been called int m_paintScreenCount = 0; };