diff --git a/src/item.cpp b/src/item.cpp index e842ba982e..cffce2044a 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -5,6 +5,12 @@ */ #include "item.h" +#include "abstract_output.h" +#include "composite.h" +#include "main.h" +#include "platform.h" +#include "renderloop.h" +#include "screens.h" namespace KWin { @@ -13,11 +19,24 @@ Item::Item(Scene::Window *window, Item *parent) : m_window(window) { setParentItem(parent); + + if (kwinApp()->platform()->isPerScreenRenderingEnabled()) { + connect(kwinApp()->platform(), &Platform::outputEnabled, this, &Item::reallocRepaints); + connect(kwinApp()->platform(), &Platform::outputDisabled, this, &Item::reallocRepaints); + } + reallocRepaints(); } Item::~Item() { setParentItem(nullptr); + + for (int i = 0; i < m_repaints.count(); ++i) { + const QRegion dirty = repaints(i); + if (!dirty.isEmpty()) { + Compositor::self()->addRepaint(dirty); + } + } } int Item::x() const @@ -325,12 +344,39 @@ void Item::stackChildren(const QList &children) void Item::scheduleRepaint(const QRegion ®ion) { - window()->addLayerRepaint(mapToGlobal(region)); + 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]; + const QRegion dirtyRegion = globalRegion & output->geometry(); + if (!dirtyRegion.isEmpty()) { + m_repaints[screenId] += dirtyRegion; + output->renderLoop()->scheduleRepaint(); + } + } + } else { + m_repaints[0] += globalRegion; + kwinApp()->platform()->renderLoop()->scheduleRepaint(); + } } void Item::scheduleRepaint() { - window()->scheduleRepaint(); + 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(); + } + } + } else { + kwinApp()->platform()->renderLoop()->scheduleRepaint(); + } } void Item::preprocess() @@ -342,4 +388,32 @@ void Item::discardQuads() window()->discardQuads(); } +QRegion Item::repaints(int screen) 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]; +} + +void Item::resetRepaints(int screen) +{ + Q_ASSERT(!m_repaints.isEmpty()); + const int index = screen != -1 ? screen : 0; + m_repaints[index] = QRegion(); +} + +void Item::reallocRepaints() +{ + if (kwinApp()->platform()->isPerScreenRenderingEnabled()) { + m_repaints.resize(kwinApp()->platform()->enabledOutputs().count()); + } else { + m_repaints.resize(1); + } + + m_repaints.fill(infiniteRegion()); +} + } // namespace KWin diff --git a/src/item.h b/src/item.h index 05177678de..0196f4a58e 100644 --- a/src/item.h +++ b/src/item.h @@ -93,6 +93,8 @@ public: void scheduleRepaint(const QRegion ®ion); void scheduleRepaint(); + QRegion repaints(int screen) const; + void resetRepaints(int screen); Q_SIGNALS: /** @@ -126,6 +128,7 @@ private: void addChild(Item *item); void removeChild(Item *item); void updateBoundingRect(); + void reallocRepaints(); Scene::Window *m_window; QPointer m_parentItem; @@ -135,6 +138,7 @@ private: int m_y = 0; int m_width = 0; int m_height = 0; + QVector m_repaints; friend class Scene::Window; }; diff --git a/src/scene.cpp b/src/scene.cpp index 58eb1380b4..6841a73920 100644 --- a/src/scene.cpp +++ b/src/scene.cpp @@ -229,6 +229,16 @@ void Scene::finalPaintScreen(int mask, const QRegion ®ion, ScreenPaintData& d Q_EMIT frameRendered(); } +static void resetRepaintsHelper(Item *item, int screen) +{ + item->resetRepaints(screen); + + const auto childItems = item->childItems(); + for (Item *childItem : childItems) { + resetRepaintsHelper(childItem, screen); + } +} + // The generic painting code that can handle even transformations. // It simply paints bottom-to-top. void Scene::paintGenericScreen(int orig_mask, const ScreenPaintData &) @@ -242,7 +252,7 @@ void Scene::paintGenericScreen(int orig_mask, const ScreenPaintData &) // Reset the repaint_region. // This has to be done here because many effects schedule a repaint for // the next frame within Effects::prePaintWindow. - w->resetRepaints(painted_screen); + resetRepaintsHelper(w->windowItem(), painted_screen); WindowPrePaintData data; data.mask = orig_mask | (w->isOpaque() ? PAINT_WINDOW_OPAQUE : PAINT_WINDOW_TRANSLUCENT); @@ -280,6 +290,17 @@ void Scene::paintGenericScreen(int orig_mask, const ScreenPaintData &) } } +static void accumulateRepaints(Item *item, int screen, QRegion *repaints) +{ + *repaints += item->repaints(screen); + item->resetRepaints(screen); + + const auto childItems = item->childItems(); + for (Item *childItem : childItems) { + accumulateRepaints(childItem, screen, repaints); + } +} + // The optimized case without any transformations at all. // It can paint only the requested region and can use clipping // to reduce painting and improve performance. @@ -301,16 +322,11 @@ void Scene::paintSimpleScreen(int orig_mask, const QRegion ®ion) data.mask = orig_mask | (window->isOpaque() ? PAINT_WINDOW_OPAQUE : PAINT_WINDOW_TRANSLUCENT); window->resetPaintingEnabled(); data.paint = region; - data.paint |= window->repaints(painted_screen); + accumulateRepaints(window->windowItem(), painted_screen, &data.paint); // Let the scene window update the window pixmap tree. window->preprocess(window->windowItem()); - // Reset the repaint_region. - // This has to be done here because many effects schedule a repaint for - // the next frame within Effects::prePaintWindow. - window->resetRepaints(painted_screen); - // Clip out the decoration for opaque windows; the decoration is drawn in the second pass opaqueFullscreen = false; // TODO: do we care about unmanged windows here (maybe input windows?) AbstractClient *client = dynamic_cast(toplevel); @@ -751,12 +767,6 @@ Scene::Window::Window(Toplevel *client, QObject *parent) , disable_painting(0) , cached_quad_list(nullptr) { - if (kwinApp()->platform()->isPerScreenRenderingEnabled()) { - connect(kwinApp()->platform(), &Platform::outputEnabled, this, &Window::reallocRepaints); - connect(kwinApp()->platform(), &Platform::outputDisabled, this, &Window::reallocRepaints); - } - reallocRepaints(); - if (qobject_cast(client)) { m_windowItem.reset(new WindowItemWayland(this)); } else if (qobject_cast(client) || qobject_cast(client)) { @@ -773,12 +783,6 @@ Scene::Window::Window(Toplevel *client, QObject *parent) Scene::Window::~Window() { - for (int i = 0; i < m_repaints.count(); ++i) { - const QRegion dirty = repaints(i); - if (!dirty.isEmpty()) { - Compositor::self()->addRepaint(dirty); - } - } } void Scene::Window::updateToplevel(Deleted *deleted) @@ -1117,55 +1121,6 @@ void Scene::Window::preprocess(Item *item) } } -void Scene::Window::addLayerRepaint(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]; - const QRegion dirtyRegion = region & output->geometry(); - if (!dirtyRegion.isEmpty()) { - m_repaints[screenId] += dirtyRegion; - output->renderLoop()->scheduleRepaint(); - } - } - } else { - m_repaints[0] += region; - kwinApp()->platform()->renderLoop()->scheduleRepaint(); - } -} - -QRegion Scene::Window::repaints(int screen) 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]; -} - -void Scene::Window::resetRepaints(int screen) -{ - Q_ASSERT(!m_repaints.isEmpty()); - const int index = screen != -1 ? screen : 0; - m_repaints[index] = QRegion(); -} - -void Scene::Window::reallocRepaints() -{ - if (kwinApp()->platform()->isPerScreenRenderingEnabled()) { - m_repaints.resize(kwinApp()->platform()->enabledOutputs().count()); - } else { - m_repaints.resize(1); - } - - m_repaints.fill(infiniteRegion()); -} - WindowItem *Scene::Window::windowItem() const { return m_windowItem.data(); @@ -1181,20 +1136,6 @@ ShadowItem *Scene::Window::shadowItem() const return m_windowItem->shadowItem(); } -void Scene::Window::scheduleRepaint() -{ - if (kwinApp()->platform()->isPerScreenRenderingEnabled()) { - const QVector outputs = kwinApp()->platform()->enabledOutputs(); - for (AbstractOutput *output : outputs) { - if (window()->isOnOutput(output)) { - output->renderLoop()->scheduleRepaint(); - } - } - } else { - kwinApp()->platform()->renderLoop()->scheduleRepaint(); - } -} - void Scene::Window::updateWindowPosition() { m_windowItem->setPosition(pos()); diff --git a/src/scene.h b/src/scene.h index f28346c8e7..7954e7672e 100644 --- a/src/scene.h +++ b/src/scene.h @@ -360,13 +360,9 @@ public: void unreferencePreviousPixmap(); void discardQuads(); void preprocess(Item *item); - void addLayerRepaint(const QRegion ®ion); - QRegion repaints(int screen) const; - void resetRepaints(int screen); WindowItem *windowItem() const; SurfaceItem *surfaceItem() const; ShadowItem *shadowItem() const; - void scheduleRepaint(); virtual QSharedPointer windowTexture() { return {}; @@ -385,9 +381,7 @@ private: void unreferencePreviousPixmap_helper(SurfaceItem *item); void updateWindowPosition(); - void reallocRepaints(); - QVector m_repaints; int disable_painting; mutable QScopedPointer cached_quad_list; QScopedPointer m_windowItem; diff --git a/src/toplevel.cpp b/src/toplevel.cpp index 6026aa5a47..22460ce126 100644 --- a/src/toplevel.cpp +++ b/src/toplevel.cpp @@ -308,10 +308,9 @@ void Toplevel::addRepaint(int x, int y, int width, int height) void Toplevel::addRepaint(const QRegion ®ion) { - if (!effectWindow() || !effectWindow()->sceneWindow()) { - return; + if (auto item = windowItem()) { + item->scheduleRepaint(region); } - effectWindow()->sceneWindow()->addLayerRepaint(region.translated(pos())); } void Toplevel::addLayerRepaint(const QRect &rect) @@ -326,10 +325,7 @@ void Toplevel::addLayerRepaint(int x, int y, int width, int height) void Toplevel::addLayerRepaint(const QRegion ®ion) { - if (!effectWindow() || !effectWindow()->sceneWindow()) { - return; - } - effectWindow()->sceneWindow()->addLayerRepaint(region); + addRepaint(region.translated(-pos())); } void Toplevel::addRepaintFull()