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.
This commit is contained in:
Vlad Zahorodnii 2020-11-20 11:35:38 +02:00
parent 992e88de50
commit a3ec0c9a57
4 changed files with 75 additions and 29 deletions

View file

@ -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 &region)
{
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<std::chrono::milliseconds>(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();

View file

@ -146,7 +146,6 @@ private:
QList<xcb_atom_t> m_unusedSupportProperties;
QTimer m_unusedSupportPropertyTimer;
qint64 vBlankInterval, fpsInterval;
QRegion repaints_region;
qint64 m_timeSinceLastVBlank;

View file

@ -56,6 +56,7 @@
*/
#include "scene.h"
#include "abstract_output.h"
#include "platform.h"
#include <QQuickWindow>
@ -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 &region)
{
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,

13
scene.h
View file

@ -55,6 +55,17 @@ public:
class EffectFrame;
class Window;
/**
* Schedules a repaint for the specified @a region.
*/
void addRepaint(const QRegion &region);
/**
* 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 &region, 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<QRegion> m_repaints;
// how many times finalPaintScreen() has been called
int m_paintScreenCount = 0;
};