From 2819a3cb4f59f4e731c51ceceff894bbd8d7cb2d Mon Sep 17 00:00:00 2001 From: Vlad Zahorodnii Date: Thu, 5 May 2022 20:36:23 +0300 Subject: [PATCH] scene: Decouple Item from Workspace and Output Currently, Item schedules repaints taking output geometry into account, but that's going to work poorly for cases other than workspace scene. Moving from Output to SceneDelegate also allows us to unify some X11 and Wayland specific code paths in Item. Furthermore, it ensures that effects->paintScreen() won't remove pending repaints for the output. --- src/effects.cpp | 7 ++++- src/scene/decorationitem.h | 1 + src/scene/item.cpp | 54 ++++++++++++++++---------------------- src/scene/item.h | 12 +++++---- src/scene/scene.cpp | 33 ++++++++++++++--------- src/scene/scene.h | 5 +++- 6 files changed, 60 insertions(+), 52 deletions(-) diff --git a/src/effects.cpp b/src/effects.cpp index ad6d21691b..106fb0712c 100644 --- a/src/effects.cpp +++ b/src/effects.cpp @@ -1859,7 +1859,12 @@ void EffectsHandlerImpl::renderScreen(EffectScreen *screen) renderTarget.setDevicePixelRatio(screen->devicePixelRatio()); auto output = static_cast(screen)->platformOutput(); - m_scene->prePaint(output); + + RenderLayer layer(output->renderLoop()); + SceneDelegate delegate(m_scene, output); + delegate.setLayer(&layer); + + m_scene->prePaint(&delegate); m_scene->paint(&renderTarget, output->geometry()); m_scene->postPaint(); } diff --git a/src/scene/decorationitem.h b/src/scene/decorationitem.h index 0fb4fdde6a..ca8eb7ee82 100644 --- a/src/scene/decorationitem.h +++ b/src/scene/decorationitem.h @@ -18,6 +18,7 @@ namespace KWin class Window; class Deleted; +class Output; namespace Decoration { diff --git a/src/scene/item.cpp b/src/scene/item.cpp index 5bcf06a5ea..73d1bcbeb1 100644 --- a/src/scene/item.cpp +++ b/src/scene/item.cpp @@ -6,20 +6,19 @@ #include "scene/item.h" #include "composite.h" -#include "core/output.h" +#include "core/renderlayer.h" #include "core/renderloop.h" -#include "main.h" #include "scene/scene.h" #include "utils/common.h" -#include "workspace.h" namespace KWin { Item::Item(Item *parent) + : m_scene(Compositor::self()->scene()) { setParentItem(parent); - connect(workspace(), &Workspace::outputRemoved, this, &Item::removeRepaints); + connect(m_scene, &Scene::delegateRemoved, this, &Item::removeRepaints); } Item::~Item() @@ -27,7 +26,7 @@ Item::~Item() setParentItem(nullptr); for (const auto &dirty : std::as_const(m_repaints)) { if (!dirty.isEmpty()) { - Compositor::self()->scene()->addRepaint(dirty); + m_scene->addRepaint(dirty); } } } @@ -293,19 +292,14 @@ void Item::scheduleRepaint(const QRegion ®ion) void Item::scheduleRepaintInternal(const QRegion ®ion) { - const QList outputs = workspace()->outputs(); const QRegion globalRegion = mapToGlobal(region); - if (kwinApp()->operationMode() != Application::OperationModeX11) { - for (const auto &output : outputs) { - const QRegion dirtyRegion = globalRegion & output->geometry(); - if (!dirtyRegion.isEmpty()) { - m_repaints[output] += dirtyRegion; - output->renderLoop()->scheduleRepaint(this); - } + const QList delegates = m_scene->delegates(); + for (SceneDelegate *delegate : delegates) { + const QRegion dirtyRegion = globalRegion & delegate->viewport(); + if (!dirtyRegion.isEmpty()) { + m_repaints[delegate] += dirtyRegion; + delegate->layer()->loop()->scheduleRepaint(this); } - } else { - m_repaints[outputs.constFirst()] += globalRegion; - outputs.constFirst()->renderLoop()->scheduleRepaint(this); } } @@ -314,16 +308,12 @@ void Item::scheduleFrame() if (!isVisible()) { return; } - const QList outputs = workspace()->outputs(); - if (kwinApp()->operationMode() != Application::OperationModeX11) { - const QRect geometry = mapToGlobal(rect()).toAlignedRect(); - for (const Output *output : outputs) { - if (output->geometry().intersects(geometry)) { - output->renderLoop()->scheduleRepaint(this); - } + const QRect geometry = mapToGlobal(rect()).toRect(); + const QList delegates = m_scene->delegates(); + for (SceneDelegate *delegate : delegates) { + if (delegate->viewport().intersects(geometry)) { + delegate->layer()->loop()->scheduleRepaint(this); } - } else { - outputs.constFirst()->renderLoop()->scheduleRepaint(this); } } @@ -349,19 +339,19 @@ WindowQuadList Item::quads() const return m_quads.value(); } -QRegion Item::repaints(Output *output) const +QRegion Item::repaints(SceneDelegate *delegate) const { - return m_repaints.value(output); + return m_repaints.value(delegate); } -void Item::resetRepaints(Output *output) +void Item::resetRepaints(SceneDelegate *delegate) { - m_repaints.insert(output, QRegion()); + m_repaints.insert(delegate, QRegion()); } -void Item::removeRepaints(Output *output) +void Item::removeRepaints(SceneDelegate *delegate) { - m_repaints.remove(output); + m_repaints.remove(delegate); } bool Item::explicitVisible() const @@ -401,7 +391,7 @@ void Item::updateEffectiveVisibility() m_effectiveVisible = effectiveVisible; if (!m_effectiveVisible) { - Compositor::self()->scene()->addRepaint(mapToGlobal(boundingRect()).toAlignedRect()); + m_scene->addRepaint(mapToGlobal(boundingRect()).toAlignedRect()); } else { scheduleRepaintInternal(boundingRect().toAlignedRect()); } diff --git a/src/scene/item.h b/src/scene/item.h index 220f9fc517..709edcda35 100644 --- a/src/scene/item.h +++ b/src/scene/item.h @@ -18,7 +18,8 @@ namespace KWin { -class Output; +class SceneDelegate; +class Scene; /** * The Item class is the base class for items in the scene. @@ -101,8 +102,8 @@ public: void scheduleRepaint(const QRectF ®ion); void scheduleRepaint(const QRegion ®ion); void scheduleFrame(); - QRegion repaints(Output *output) const; - void resetRepaints(Output *output); + QRegion repaints(SceneDelegate *delegate) const; + void resetRepaints(SceneDelegate *delegate); WindowQuadList quads() const; virtual void preprocess(); @@ -137,8 +138,9 @@ private: bool computeEffectiveVisibility() const; void updateEffectiveVisibility(); - void removeRepaints(Output *output); + void removeRepaints(SceneDelegate *delegate); + Scene *m_scene; QPointer m_parentItem; QList m_childItems; QMatrix4x4 m_transform; @@ -149,7 +151,7 @@ private: int m_z = 0; bool m_explicitVisible = true; bool m_effectiveVisible = true; - QMap m_repaints; + QMap m_repaints; mutable std::optional m_quads; mutable std::optional> m_sortedChildItems; }; diff --git a/src/scene/scene.cpp b/src/scene/scene.cpp index 93a67bb117..2b8b33f441 100644 --- a/src/scene/scene.cpp +++ b/src/scene/scene.cpp @@ -111,7 +111,7 @@ SurfaceItem *SceneDelegate::scanoutCandidate() const void SceneDelegate::prePaint() { - m_scene->prePaint(m_output); + m_scene->prePaint(this); } void SceneDelegate::postPaint() @@ -124,6 +124,11 @@ void SceneDelegate::paint(RenderTarget *renderTarget, const QRegion ®ion) m_scene->paint(renderTarget, region.translated(viewport().topLeft())); } +Output *SceneDelegate::output() const +{ + return m_output; +} + QRect SceneDelegate::viewport() const { return m_output ? m_output->geometry() : m_scene->geometry(); @@ -235,6 +240,7 @@ void Scene::addDelegate(SceneDelegate *delegate) void Scene::removeDelegate(SceneDelegate *delegate) { m_delegates.removeOne(delegate); + Q_EMIT delegateRemoved(delegate); } static SurfaceItem *findTopMostSurface(SurfaceItem *item) @@ -286,16 +292,17 @@ SurfaceItem *Scene::scanoutCandidate() const return candidate; } -void Scene::prePaint(Output *output) +void Scene::prePaint(SceneDelegate *delegate) { createStackingOrder(); + painted_delegate = delegate; if (kwinApp()->operationMode() == Application::OperationModeX11) { painted_screen = workspace()->outputs().constFirst(); m_renderer->setRenderTargetRect(geometry()); m_renderer->setRenderTargetScale(1); } else { - painted_screen = output; + painted_screen = painted_delegate->output(); m_renderer->setRenderTargetRect(painted_screen->fractionalGeometry()); m_renderer->setRenderTargetScale(painted_screen->scale()); } @@ -336,31 +343,31 @@ void Scene::prePaint(Output *output) } } -static void resetRepaintsHelper(Item *item, Output *output) +static void resetRepaintsHelper(Item *item, SceneDelegate *delegate) { - item->resetRepaints(output); + item->resetRepaints(delegate); const auto childItems = item->childItems(); for (Item *childItem : childItems) { - resetRepaintsHelper(childItem, output); + resetRepaintsHelper(childItem, delegate); } } -static void accumulateRepaints(Item *item, Output *output, QRegion *repaints) +static void accumulateRepaints(Item *item, SceneDelegate *delegate, QRegion *repaints) { - *repaints += item->repaints(output); - item->resetRepaints(output); + *repaints += item->repaints(delegate); + item->resetRepaints(delegate); const auto childItems = item->childItems(); for (Item *childItem : childItems) { - accumulateRepaints(childItem, output, repaints); + accumulateRepaints(childItem, delegate, repaints); } } void Scene::preparePaintGenericScreen() { for (WindowItem *windowItem : std::as_const(stacking_order)) { - resetRepaintsHelper(windowItem, painted_screen); + resetRepaintsHelper(windowItem, painted_delegate); WindowPrePaintData data; data.mask = m_paintContext.mask; @@ -384,7 +391,7 @@ void Scene::preparePaintSimpleScreen() Window *window = windowItem->window(); WindowPrePaintData data; data.mask = m_paintContext.mask; - accumulateRepaints(windowItem, painted_screen, &data.paint); + accumulateRepaints(windowItem, painted_delegate, &data.paint); // Clip out the decoration for opaque windows; the decoration is drawn in the second pass. if (window->opacity() == 1.0) { @@ -419,7 +426,7 @@ void Scene::preparePaintSimpleScreen() } if (m_dndIcon) { - accumulateRepaints(m_dndIcon.get(), painted_screen, &m_paintContext.damage); + accumulateRepaints(m_dndIcon.get(), painted_delegate, &m_paintContext.damage); } } diff --git a/src/scene/scene.h b/src/scene/scene.h index bc03a93367..6deefd6c27 100644 --- a/src/scene/scene.h +++ b/src/scene/scene.h @@ -51,6 +51,7 @@ public: explicit SceneDelegate(Scene *scene, Output *output, QObject *parent = nullptr); ~SceneDelegate() override; + Output *output() const; QRect viewport() const; QRegion repaints() const override; @@ -90,7 +91,7 @@ public: void removeDelegate(SceneDelegate *delegate); SurfaceItem *scanoutCandidate() const; - void prePaint(Output *output); + void prePaint(SceneDelegate *delegate); void postPaint(); void paint(RenderTarget *renderTarget, const QRegion ®ion); @@ -146,6 +147,7 @@ public: Q_SIGNALS: void preFrameRender(); void frameRendered(); + void delegateRemoved(SceneDelegate *delegate); protected: void createStackingOrder(); @@ -185,6 +187,7 @@ protected: // The screen that is being currently painted Output *painted_screen = nullptr; + SceneDelegate *painted_delegate = nullptr; // windows in their stacking order QVector stacking_order;