From a3b5266175ecd4bf0b4b6e4006e3535de5f98f8d Mon Sep 17 00:00:00 2001 From: Vlad Zahorodnii Date: Sat, 5 Feb 2022 15:20:17 +0200 Subject: [PATCH] Drop Platform::renderLoop() Having a render loop in the Platform has always been awkward. Another way to interpret the platform not supporting per screen rendering would be that all outputs share the same render loop. On X11, Scene::painted_screen is going to correspond to the primary screen, we should not rely on this assumption though! --- src/abstract_output.cpp | 5 ---- src/abstract_output.h | 6 ++--- src/backends/x11/standalone/eglbackend.cpp | 2 +- src/backends/x11/standalone/glxbackend.cpp | 6 ++--- src/backends/x11/standalone/x11_output.cpp | 10 +++++++ src/backends/x11/standalone/x11_output.h | 4 +++ src/backends/x11/standalone/x11_platform.cpp | 3 ++- src/backends/x11/standalone/x11_platform.h | 3 ++- .../x11/standalone/x11placeholderoutput.cpp | 8 +++++- .../x11/standalone/x11placeholderoutput.h | 6 ++++- src/composite.cpp | 26 +++++++++++++------ src/composite.h | 2 ++ src/effects/colorpicker/colorpicker.cpp | 2 +- src/effects/screenshot/screenshot.cpp | 2 +- src/item.cpp | 10 +++---- src/libkwineffects/kwineffects.h | 2 +- src/platform.cpp | 5 ---- src/platform.h | 7 ----- src/scene.cpp | 13 +++++----- src/scene.h | 2 +- src/scenes/opengl/scene_opengl.cpp | 4 +-- src/scenes/qpainter/scene_qpainter.cpp | 2 +- 22 files changed, 76 insertions(+), 54 deletions(-) diff --git a/src/abstract_output.cpp b/src/abstract_output.cpp index 832838f8c6..985edaed78 100644 --- a/src/abstract_output.cpp +++ b/src/abstract_output.cpp @@ -141,11 +141,6 @@ QString AbstractOutput::serialNumber() const return QString(); } -RenderLoop *AbstractOutput::renderLoop() const -{ - return nullptr; -} - void AbstractOutput::inhibitDirectScanout() { m_directScanoutCount++; diff --git a/src/abstract_output.h b/src/abstract_output.h index dd74a175d6..07a6d979f4 100644 --- a/src/abstract_output.h +++ b/src/abstract_output.h @@ -180,10 +180,10 @@ public: virtual QString serialNumber() const; /** - * Returns the RenderLoop for this output. This function returns @c null if the - * underlying platform doesn't support per-screen rendering mode. + * Returns the RenderLoop for this output. If the platform does not support per screen + * rendering, all outputs will share the same render loop. */ - virtual RenderLoop *renderLoop() const; + virtual RenderLoop *renderLoop() const = 0; void inhibitDirectScanout(); void uninhibitDirectScanout(); diff --git a/src/backends/x11/standalone/eglbackend.cpp b/src/backends/x11/standalone/eglbackend.cpp index 5143b5f2ed..99750d2d08 100644 --- a/src/backends/x11/standalone/eglbackend.cpp +++ b/src/backends/x11/standalone/eglbackend.cpp @@ -46,7 +46,7 @@ EglBackend::~EglBackend() // No completion events will be received for in-flight frames, this may lock the // render loop. We need to ensure that the render loop is back to its initial state // if the render backend is about to be destroyed. - RenderLoopPrivate::get(kwinApp()->platform()->renderLoop())->invalidate(); + RenderLoopPrivate::get(m_backend->renderLoop())->invalidate(); } SurfaceTexture *EglBackend::createSurfaceTextureX11(SurfacePixmapX11 *texture) diff --git a/src/backends/x11/standalone/glxbackend.cpp b/src/backends/x11/standalone/glxbackend.cpp index 6546342b52..d039ec5613 100644 --- a/src/backends/x11/standalone/glxbackend.cpp +++ b/src/backends/x11/standalone/glxbackend.cpp @@ -90,8 +90,8 @@ bool SwapEventFilter::event(xcb_generic_event_t *event) // it's CLOCK_MONOTONIC, so no special conversions are needed. const std::chrono::microseconds timestamp((uint64_t(swapEvent->ust_hi) << 32) | swapEvent->ust_lo); - RenderLoopPrivate *renderLoopPrivate = RenderLoopPrivate::get(kwinApp()->platform()->renderLoop()); - renderLoopPrivate->notifyFrameCompleted(timestamp); + const auto platform = static_cast(kwinApp()->platform()); + RenderLoopPrivate::get(platform->renderLoop())->notifyFrameCompleted(timestamp); return true; } @@ -122,7 +122,7 @@ GlxBackend::~GlxBackend() // No completion events will be received for in-flight frames, this may lock the // render loop. We need to ensure that the render loop is back to its initial state // if the render backend is about to be destroyed. - RenderLoopPrivate::get(kwinApp()->platform()->renderLoop())->invalidate(); + RenderLoopPrivate::get(m_backend->renderLoop())->invalidate(); if (isFailed()) { m_overlayWindow->destroy(); diff --git a/src/backends/x11/standalone/x11_output.cpp b/src/backends/x11/standalone/x11_output.cpp index 6032762258..7c0df9c83f 100644 --- a/src/backends/x11/standalone/x11_output.cpp +++ b/src/backends/x11/standalone/x11_output.cpp @@ -23,6 +23,16 @@ QString X11Output::name() const return m_name; } +RenderLoop *X11Output::renderLoop() const +{ + return m_loop; +} + +void X11Output::setRenderLoop(RenderLoop *loop) +{ + m_loop = loop; +} + int X11Output::xineramaNumber() const { return m_xineramaNumber; diff --git a/src/backends/x11/standalone/x11_output.h b/src/backends/x11/standalone/x11_output.h index b3df14723b..bf20b2a80f 100644 --- a/src/backends/x11/standalone/x11_output.h +++ b/src/backends/x11/standalone/x11_output.h @@ -32,6 +32,9 @@ public: QString name() const override; + RenderLoop *renderLoop() const override; + void setRenderLoop(RenderLoop *loop); + int xineramaNumber() const; void setXineramaNumber(int number); @@ -54,6 +57,7 @@ private: void setCrtc(xcb_randr_crtc_t crtc); void setGammaRampSize(int size); + RenderLoop *m_loop = nullptr; xcb_randr_crtc_t m_crtc = XCB_NONE; QString m_name; QRect m_geometry; diff --git a/src/backends/x11/standalone/x11_platform.cpp b/src/backends/x11/standalone/x11_platform.cpp index d4d96533d5..3d5cc48846 100644 --- a/src/backends/x11/standalone/x11_platform.cpp +++ b/src/backends/x11/standalone/x11_platform.cpp @@ -531,6 +531,7 @@ void X11StandalonePlatform::doUpdateOutputs() // drm platform do this. Xcb::RandR::CrtcGamma gamma(crtcs[i]); + output->setRenderLoop(m_renderLoop); output->setCrtc(crtcs[i]); output->setGammaRampSize(gamma.isNull() ? 0 : gamma->size); output->setGeometry(geometry); @@ -560,7 +561,7 @@ void X11StandalonePlatform::doUpdateOutputs() // The workspace handles having no outputs poorly. If the last output is about to be // removed, create a dummy output to avoid crashing. if (changed.isEmpty() && added.isEmpty()) { - auto dummyOutput = new X11PlaceholderOutput(); + auto dummyOutput = new X11PlaceholderOutput(m_renderLoop); m_outputs << dummyOutput; Q_EMIT outputAdded(dummyOutput); Q_EMIT outputEnabled(dummyOutput); diff --git a/src/backends/x11/standalone/x11_platform.h b/src/backends/x11/standalone/x11_platform.h index b1c22dada7..86f4d86e1b 100644 --- a/src/backends/x11/standalone/x11_platform.h +++ b/src/backends/x11/standalone/x11_platform.h @@ -21,6 +21,7 @@ namespace KWin { +class RenderLoop; class XInputIntegration; class WindowSelector; class X11EventFilter; @@ -64,7 +65,7 @@ public: void scheduleUpdateOutputs(); void updateOutputs(); - RenderLoop *renderLoop() const override; + RenderLoop *renderLoop() const; Outputs outputs() const override; Outputs enabledOutputs() const override; diff --git a/src/backends/x11/standalone/x11placeholderoutput.cpp b/src/backends/x11/standalone/x11placeholderoutput.cpp index abc2263b4f..7a48f11eff 100644 --- a/src/backends/x11/standalone/x11placeholderoutput.cpp +++ b/src/backends/x11/standalone/x11placeholderoutput.cpp @@ -10,11 +10,17 @@ namespace KWin { -X11PlaceholderOutput::X11PlaceholderOutput(QObject *parent) +X11PlaceholderOutput::X11PlaceholderOutput(RenderLoop *loop, QObject *parent) : AbstractOutput(parent) + , m_loop(loop) { } +RenderLoop *X11PlaceholderOutput::renderLoop() const +{ + return m_loop; +} + QString X11PlaceholderOutput::name() const { return QStringLiteral("Placeholder-0"); diff --git a/src/backends/x11/standalone/x11placeholderoutput.h b/src/backends/x11/standalone/x11placeholderoutput.h index 9f4ba4e8ac..a046c18b62 100644 --- a/src/backends/x11/standalone/x11placeholderoutput.h +++ b/src/backends/x11/standalone/x11placeholderoutput.h @@ -16,12 +16,16 @@ class X11PlaceholderOutput : public AbstractOutput Q_OBJECT public: - explicit X11PlaceholderOutput(QObject *parent = nullptr); + explicit X11PlaceholderOutput(RenderLoop *loop, QObject *parent = nullptr); + RenderLoop *renderLoop() const override; QString name() const override; QRect geometry() const override; int refreshRate() const override; QSize pixelSize() const override; + +private: + RenderLoop *m_loop; }; } // namespace KWin diff --git a/src/composite.cpp b/src/composite.cpp index 3a77e12b61..ed30452c0c 100644 --- a/src/composite.cpp +++ b/src/composite.cpp @@ -351,18 +351,17 @@ void Compositor::startupWithWorkspace() Q_ASSERT(m_scene); m_scene->initialize(); - const Platform *platform = kwinApp()->platform(); - if (platform->isPerScreenRenderingEnabled()) { - const QVector outputs = platform->enabledOutputs(); + const QVector outputs = kwinApp()->platform()->enabledOutputs(); + if (kwinApp()->platform()->isPerScreenRenderingEnabled()) { for (AbstractOutput *output : outputs) { registerRenderLoop(output->renderLoop(), output); } - connect(platform, &Platform::outputEnabled, + connect(kwinApp()->platform(), &Platform::outputEnabled, this, &Compositor::handleOutputEnabled); - connect(platform, &Platform::outputDisabled, + connect(kwinApp()->platform(), &Platform::outputDisabled, this, &Compositor::handleOutputDisabled); } else { - registerRenderLoop(platform->renderLoop(), nullptr); + registerRenderLoop(outputs.constFirst()->renderLoop(), nullptr); } m_state = State::On; @@ -397,6 +396,17 @@ void Compositor::startupWithWorkspace() m_scene->addRepaintFull(); } +AbstractOutput *Compositor::findOutput(RenderLoop *loop) const +{ + const auto outputs = kwinApp()->platform()->enabledOutputs(); + for (AbstractOutput *output : outputs) { + if (output->renderLoop() == loop) { + return output; + } + } + return nullptr; +} + void Compositor::registerRenderLoop(RenderLoop *renderLoop, AbstractOutput *output) { Q_ASSERT(!m_renderLoops.contains(renderLoop)); @@ -622,8 +632,8 @@ void Compositor::composite(RenderLoop *renderLoop) return; } - const auto &output = m_renderLoops[renderLoop]; - fTraceDuration("Paint (", output ? output->name() : QStringLiteral("screens"), ")"); + AbstractOutput *output = findOutput(renderLoop); + fTraceDuration("Paint (", output->name(), ")"); const auto windows = windowsToRender(); diff --git a/src/composite.h b/src/composite.h index c70d7506f5..c61a996f44 100644 --- a/src/composite.h +++ b/src/composite.h @@ -135,6 +135,8 @@ private: bool attemptOpenGLCompositing(); bool attemptQPainterCompositing(); + AbstractOutput *findOutput(RenderLoop *loop) const; + State m_state = State::Off; CompositorSelectionOwner *m_selectionOwner = nullptr; QTimer m_releaseSelectionTimer; diff --git a/src/effects/colorpicker/colorpicker.cpp b/src/effects/colorpicker/colorpicker.cpp index eb921c7512..088f68ed9d 100644 --- a/src/effects/colorpicker/colorpicker.cpp +++ b/src/effects/colorpicker/colorpicker.cpp @@ -60,7 +60,7 @@ void ColorPickerEffect::postPaintScreen() { effects->postPaintScreen(); - if (m_scheduledPosition != QPoint(-1, -1) && (!m_paintedScreen || m_paintedScreen->geometry().contains(m_scheduledPosition))) { + if (m_scheduledPosition != QPoint(-1, -1) && effects->renderTargetRect().contains(m_scheduledPosition)) { uint8_t data[3]; const QRect geo = effects->renderTargetRect(); const QPoint screenPosition(m_scheduledPosition.x() - geo.x(), m_scheduledPosition.y() - geo.y()); diff --git a/src/effects/screenshot/screenshot.cpp b/src/effects/screenshot/screenshot.cpp index d3603d5d72..92d2bfbc4b 100644 --- a/src/effects/screenshot/screenshot.cpp +++ b/src/effects/screenshot/screenshot.cpp @@ -268,7 +268,7 @@ void ScreenShotEffect::takeScreenShot(ScreenShotWindowData *screenshot) bool ScreenShotEffect::takeScreenShot(ScreenShotAreaData *screenshot) { - if (!m_paintedScreen) { + if (!effects->waylandDisplay()) { // On X11, all screens are painted simultaneously and there is no native HiDPI support. QImage snapshot = blitScreenshot(screenshot->area); if (screenshot->flags & ScreenShotIncludeCursor) { diff --git a/src/item.cpp b/src/item.cpp index 7e6771f02e..74ba5b8d30 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -255,9 +255,9 @@ void Item::scheduleRepaint(const QRegion ®ion) void Item::scheduleRepaintInternal(const QRegion ®ion) { + const QVector outputs = kwinApp()->platform()->enabledOutputs(); const QRegion globalRegion = mapToGlobal(region); if (kwinApp()->platform()->isPerScreenRenderingEnabled()) { - const QVector outputs = kwinApp()->platform()->enabledOutputs(); for (const auto &output : outputs) { const QRegion dirtyRegion = globalRegion & output->geometry(); if (!dirtyRegion.isEmpty()) { @@ -266,8 +266,8 @@ void Item::scheduleRepaintInternal(const QRegion ®ion) } } } else { - m_repaints[nullptr] += globalRegion; - kwinApp()->platform()->renderLoop()->scheduleRepaint(this); + m_repaints[outputs.constFirst()] += globalRegion; + outputs.constFirst()->renderLoop()->scheduleRepaint(this); } } @@ -276,16 +276,16 @@ void Item::scheduleFrame() if (!isVisible()) { return; } + const QVector outputs = kwinApp()->platform()->enabledOutputs(); if (kwinApp()->platform()->isPerScreenRenderingEnabled()) { const QRect geometry = mapToGlobal(rect()); - const QVector outputs = kwinApp()->platform()->enabledOutputs(); for (const AbstractOutput *output : outputs) { if (output->geometry().intersects(geometry)) { output->renderLoop()->scheduleRepaint(this); } } } else { - kwinApp()->platform()->renderLoop()->scheduleRepaint(this); + outputs.constFirst()->renderLoop()->scheduleRepaint(this); } } diff --git a/src/libkwineffects/kwineffects.h b/src/libkwineffects/kwineffects.h index 1a43ac636b..446dc29343 100644 --- a/src/libkwineffects/kwineffects.h +++ b/src/libkwineffects/kwineffects.h @@ -3186,7 +3186,7 @@ public: QMatrix4x4 projectionMatrix() const; /** - * Returns the currently rendered screen. Only set for per-screen rendering, e.g. Wayland. + * Returns the currently rendered screen. It's always the primary screen on X11. */ EffectScreen *screen() const; diff --git a/src/platform.cpp b/src/platform.cpp index d601bae32d..258bf50a2d 100644 --- a/src/platform.cpp +++ b/src/platform.cpp @@ -432,11 +432,6 @@ void Platform::setPerScreenRenderingEnabled(bool enabled) m_isPerScreenRenderingEnabled = enabled; } -RenderLoop *Platform::renderLoop() const -{ - return nullptr; -} - AbstractOutput *Platform::createVirtualOutput(const QString &name, const QSize &size, double scale) { Q_UNUSED(name); diff --git a/src/platform.h b/src/platform.h index 14f70583ee..7b6f144323 100644 --- a/src/platform.h +++ b/src/platform.h @@ -37,7 +37,6 @@ class OpenGLBackend; class Outline; class OutlineVisual; class QPainterBackend; -class RenderLoop; class Scene; class ScreenEdges; class Session; @@ -344,12 +343,6 @@ public: */ bool isPerScreenRenderingEnabled() const; - /** - * If the Platform doesn't support per screen rendering, this function returns the - * RenderLoop that drives compositing. - */ - virtual RenderLoop *renderLoop() const; - virtual AbstractOutput *createVirtualOutput(const QString &name, const QSize &size, qreal scaling); virtual void removeVirtualOutput(AbstractOutput *output); diff --git a/src/scene.cpp b/src/scene.cpp index e7e0a5a885..d1f50bf076 100644 --- a/src/scene.cpp +++ b/src/scene.cpp @@ -143,8 +143,8 @@ void Scene::addRepaint(const QRect &rect) void Scene::addRepaint(const QRegion ®ion) { + const QVector outputs = kwinApp()->platform()->enabledOutputs(); if (kwinApp()->platform()->isPerScreenRenderingEnabled()) { - const QVector outputs = kwinApp()->platform()->enabledOutputs(); for (const auto &output : outputs) { const QRegion dirtyRegion = region & output->geometry(); if (!dirtyRegion.isEmpty()) { @@ -153,8 +153,8 @@ void Scene::addRepaint(const QRegion ®ion) } } } else { - m_repaints[0] += region; - kwinApp()->platform()->renderLoop()->scheduleRepaint(); + m_repaints[outputs.constFirst()] += region; + outputs.constFirst()->renderLoop()->scheduleRepaint(); } } @@ -261,16 +261,17 @@ void Scene::paintScreen(AbstractOutput *output, const QList &topleve setRenderTargetScale(output->scale()); QRegion update, valid; - paintScreen(renderTargetRect(), QRect(), &update, &valid, output->renderLoop()); + paintScreen(renderTargetRect(), QRect(), &update, &valid); clearStackingOrder(); } // returns mask and possibly modified region void Scene::paintScreen(const QRegion &damage, const QRegion &repaint, - QRegion *updateRegion, QRegion *validRegion, RenderLoop *renderLoop) + QRegion *updateRegion, QRegion *validRegion) { const QRegion displayRegion(geometry()); + const RenderLoop *renderLoop = painted_screen->renderLoop(); const std::chrono::milliseconds presentTime = std::chrono::duration_cast(renderLoop->nextPresentationTimestamp()); @@ -289,7 +290,7 @@ void Scene::paintScreen(const QRegion &damage, const QRegion &repaint, QRegion region = damage; - auto screen = painted_screen ? EffectScreenImpl::get(painted_screen) : nullptr; + auto screen = EffectScreenImpl::get(painted_screen); ScreenPrePaintData pdata; pdata.mask = (damage == displayRegion) ? 0 : PAINT_SCREEN_REGION; pdata.paint = region; diff --git a/src/scene.h b/src/scene.h index fd7b7a612d..27a31176d2 100644 --- a/src/scene.h +++ b/src/scene.h @@ -209,7 +209,7 @@ protected: void clearStackingOrder(); // shared implementation, starts painting the screen void paintScreen(const QRegion &damage, const QRegion &repaint, - QRegion *updateRegion, QRegion *validRegion, RenderLoop *renderLoop); + QRegion *updateRegion, QRegion *validRegion); // Render cursor texture in case hardware cursor is disabled/non-applicable virtual void paintCursor(AbstractOutput *output, const QRegion ®ion) = 0; friend class EffectsHandlerImpl; diff --git a/src/scenes/opengl/scene_opengl.cpp b/src/scenes/opengl/scene_opengl.cpp index 7785ccff13..48352cdce2 100644 --- a/src/scenes/opengl/scene_opengl.cpp +++ b/src/scenes/opengl/scene_opengl.cpp @@ -195,7 +195,7 @@ void SceneOpenGL::paint(AbstractOutput *output, const QRegion &damage, const QLi QRegion valid; QRegion repaint; - if (output) { + if (kwinApp()->platform()->isPerScreenRenderingEnabled()) { setRenderTargetRect(output->geometry()); setRenderTargetScale(output->scale()); } else { @@ -248,7 +248,7 @@ void SceneOpenGL::paint(AbstractOutput *output, const QRegion &damage, const QLi repaint = m_backend->beginFrame(output); GLVertexBuffer::streamingBuffer()->beginFrame(); - paintScreen(damage.intersected(renderTargetRect()), repaint, &update, &valid, renderLoop); // call generic implementation + paintScreen(damage.intersected(renderTargetRect()), repaint, &update, &valid); paintCursor(output, valid); renderLoop->endFrame(); diff --git a/src/scenes/qpainter/scene_qpainter.cpp b/src/scenes/qpainter/scene_qpainter.cpp index 6f8d0e8df7..2ea7e12b7f 100644 --- a/src/scenes/qpainter/scene_qpainter.cpp +++ b/src/scenes/qpainter/scene_qpainter.cpp @@ -86,7 +86,7 @@ void SceneQPainter::paint(AbstractOutput *output, const QRegion &damage, const Q m_painter->setWindow(geometry); QRegion updateRegion, validRegion; - paintScreen(damage.intersected(geometry), repaint, &updateRegion, &validRegion, renderLoop); + paintScreen(damage.intersected(geometry), repaint, &updateRegion, &validRegion); paintCursor(output, updateRegion); m_painter->end();