From a3ec0c9a574c06a4ddf056fc60f92a534676c44c Mon Sep 17 00:00:00 2001 From: Vlad Zahorodnii Date: Fri, 20 Nov 2020 11:35:38 +0200 Subject: [PATCH] Delegate repaint scheduling to the Scene In order to unlock per screen rendering, we need to track repaints for every screen individually. While we could do this in the Compositor class, tracking repaints in the Scene seems a better alternative in long run because we will have to instantiate a Scene for each composited screen one day. --- composite.cpp | 42 ++++++++++++++---------------------------- composite.h | 1 - scene.cpp | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ scene.h | 13 +++++++++++++ 4 files changed, 75 insertions(+), 29 deletions(-) diff --git a/composite.cpp b/composite.cpp index 5625e8cb2c..20eb9b60aa 100644 --- a/composite.cpp +++ b/composite.cpp @@ -448,7 +448,6 @@ void Compositor::stop() delete m_scene; m_scene = nullptr; compositeTimer.stop(); - repaints_region = QRegion(); m_state = State::Off; emit compositingToggled(false); @@ -529,41 +528,26 @@ void Compositor::reinitialize() } } -void Compositor::addRepaint(int x, int y, int w, int h) +void Compositor::addRepaint(int x, int y, int width, int height) { - if (m_state != State::On) { - return; - } - repaints_region += QRegion(x, y, w, h); - scheduleRepaint(); + addRepaint(QRegion(x, y, width, height)); } -void Compositor::addRepaint(const QRect& r) +void Compositor::addRepaint(const QRect &rect) { - if (m_state != State::On) { - return; - } - repaints_region += r; - scheduleRepaint(); + addRepaint(QRegion(rect)); } -void Compositor::addRepaint(const QRegion& r) +void Compositor::addRepaint(const QRegion ®ion) { - if (m_state != State::On) { - return; + if (m_scene) { + m_scene->addRepaint(region); } - repaints_region += r; - scheduleRepaint(); } void Compositor::addRepaintFull() { - if (m_state != State::On) { - return; - } - const QSize &s = screens()->size(); - repaints_region = QRegion(0, 0, s.width(), s.height()); - scheduleRepaint(); + addRepaint(screens()->geometry()); } void Compositor::timerEvent(QTimerEvent *te) @@ -666,10 +650,6 @@ void Compositor::performCompositing() } } - QRegion repaints = repaints_region; - // clear all repaints, so that post-pass can add repaints for the next repaint - repaints_region = QRegion(); - const std::chrono::nanoseconds now = std::chrono::steady_clock::now().time_since_epoch(); const std::chrono::milliseconds presentTime = std::chrono::duration_cast(now); @@ -680,9 +660,15 @@ void Compositor::performCompositing() m_renderTimer.start(); if (kwinApp()->platform()->isPerScreenRenderingEnabled()) { for (int screenId = 0; screenId < screens()->count(); ++screenId) { + const QRegion repaints = m_scene->repaints(screenId); + m_scene->resetRepaints(screenId); + m_scene->paint(screenId, repaints, windows, presentTime); } } else { + const QRegion repaints = m_scene->repaints(-1); + m_scene->resetRepaints(-1); + m_scene->paint(-1, repaints, windows, presentTime); } m_timeSinceLastVBlank = m_renderTimer.elapsed(); diff --git a/composite.h b/composite.h index 3a6a50a93f..195e2bc042 100644 --- a/composite.h +++ b/composite.h @@ -146,7 +146,6 @@ private: QList m_unusedSupportProperties; QTimer m_unusedSupportPropertyTimer; qint64 vBlankInterval, fpsInterval; - QRegion repaints_region; qint64 m_timeSinceLastVBlank; diff --git a/scene.cpp b/scene.cpp index 26d56c72e3..c59e448b85 100644 --- a/scene.cpp +++ b/scene.cpp @@ -56,6 +56,7 @@ */ #include "scene.h" +#include "abstract_output.h" #include "platform.h" #include @@ -86,6 +87,10 @@ namespace KWin Scene::Scene(QObject *parent) : QObject(parent) { + if (kwinApp()->platform()->isPerScreenRenderingEnabled()) { + connect(screens(), &Screens::countChanged, this, &Scene::reallocRepaints); + } + reallocRepaints(); } Scene::~Scene() @@ -93,6 +98,49 @@ Scene::~Scene() Q_ASSERT(m_windows.isEmpty()); } +void Scene::addRepaint(const QRegion ®ion) +{ + if (kwinApp()->platform()->isPerScreenRenderingEnabled()) { + if (m_repaints.count() != screens()->count()) { + return; // Repaints haven't been reallocated yet, do nothing. + } + for (int screenId = 0; screenId < m_repaints.count(); ++screenId) { + AbstractOutput *output = kwinApp()->platform()->findOutput(screenId); + const QRegion dirtyRegion = region & output->geometry(); + if (!dirtyRegion.isEmpty()) { + m_repaints[screenId] += dirtyRegion; + } + } + } else { + m_repaints[0] += region; + } + + Compositor::self()->scheduleRepaint(); +} + +QRegion Scene::repaints(int screenId) const +{ + const int index = screenId == -1 ? 0 : screenId; + return m_repaints[index]; +} + +void Scene::resetRepaints(int screenId) +{ + const int index = screenId == -1 ? 0 : screenId; + m_repaints[index] = QRegion(); +} + +void Scene::reallocRepaints() +{ + if (kwinApp()->platform()->isPerScreenRenderingEnabled()) { + m_repaints.resize(screens()->count()); + } else { + m_repaints.resize(1); + } + + m_repaints.fill(infiniteRegion()); +} + // returns mask and possibly modified region void Scene::paintScreen(int* mask, const QRegion &damage, const QRegion &repaint, QRegion *updateRegion, QRegion *validRegion, diff --git a/scene.h b/scene.h index 59cb0168fd..e28219afa6 100644 --- a/scene.h +++ b/scene.h @@ -55,6 +55,17 @@ public: class EffectFrame; class Window; + /** + * Schedules a repaint for the specified @a region. + */ + void addRepaint(const QRegion ®ion); + + /** + * Returns the repaints region for output with the specified @a screenId. + */ + QRegion repaints(int screenId) const; + void resetRepaints(int screenId); + // Returns true if the ctor failed to properly initialize. virtual bool initFailed() const = 0; virtual CompositingType compositingType() const = 0; @@ -265,9 +276,11 @@ private: void paintWindowThumbnails(Scene::Window *w, const QRegion ®ion, qreal opacity, qreal brightness, qreal saturation); void paintDesktopThumbnails(Scene::Window *w); std::chrono::milliseconds m_expectedPresentTimestamp = std::chrono::milliseconds::zero(); + void reallocRepaints(); QHash< Toplevel*, Window* > m_windows; // windows in their stacking order QVector< Window* > stacking_order; + QVector m_repaints; // how many times finalPaintScreen() has been called int m_paintScreenCount = 0; };