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; };