Move repaint scheduling logic to Item
Currently, items depend on scene windows for creating pixmaps, repaint scheduling, and caching quads. This change moves repaint scheduling from scene windows to items to make the scene items depend less on scene windows. In hindsight, we may clean up the repaint scheduling machinery further by introducing view objects.
This commit is contained in:
parent
386814176b
commit
506214a632
5 changed files with 106 additions and 97 deletions
78
src/item.cpp
78
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<Item *> &children)
|
|||
|
||||
void Item::scheduleRepaint(const QRegion ®ion)
|
||||
{
|
||||
window()->addLayerRepaint(mapToGlobal(region));
|
||||
const QRegion globalRegion = mapToGlobal(region);
|
||||
if (kwinApp()->platform()->isPerScreenRenderingEnabled()) {
|
||||
const QVector<AbstractOutput *> 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<AbstractOutput *> 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
|
||||
|
|
|
@ -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<Item> m_parentItem;
|
||||
|
@ -135,6 +138,7 @@ private:
|
|||
int m_y = 0;
|
||||
int m_width = 0;
|
||||
int m_height = 0;
|
||||
QVector<QRegion> m_repaints;
|
||||
|
||||
friend class Scene::Window;
|
||||
};
|
||||
|
|
105
src/scene.cpp
105
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<AbstractClient *>(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<WaylandClient *>(client)) {
|
||||
m_windowItem.reset(new WindowItemWayland(this));
|
||||
} else if (qobject_cast<X11Client *>(client) || qobject_cast<Unmanaged *>(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<AbstractOutput *> 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<AbstractOutput *> 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());
|
||||
|
|
|
@ -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<GLTexture> windowTexture() {
|
||||
return {};
|
||||
|
@ -385,9 +381,7 @@ private:
|
|||
void unreferencePreviousPixmap_helper(SurfaceItem *item);
|
||||
|
||||
void updateWindowPosition();
|
||||
void reallocRepaints();
|
||||
|
||||
QVector<QRegion> m_repaints;
|
||||
int disable_painting;
|
||||
mutable QScopedPointer<WindowQuadList> cached_quad_list;
|
||||
QScopedPointer<WindowItem> m_windowItem;
|
||||
|
|
|
@ -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()
|
||||
|
|
Loading…
Reference in a new issue