Drop Platform::renderLoop()

Having a render loop in the Platform has always been awkward. Another
way to interpret the platform not supporting per screen rendering would
be that all outputs share the same render loop.

On X11, Scene::painted_screen is going to correspond to the primary
screen, we should not rely on this assumption though!
This commit is contained in:
Vlad Zahorodnii 2022-02-05 15:20:17 +02:00
parent ba000d5a4e
commit a3b5266175
22 changed files with 76 additions and 54 deletions

View file

@ -141,11 +141,6 @@ QString AbstractOutput::serialNumber() const
return QString();
}
RenderLoop *AbstractOutput::renderLoop() const
{
return nullptr;
}
void AbstractOutput::inhibitDirectScanout()
{
m_directScanoutCount++;

View file

@ -180,10 +180,10 @@ public:
virtual QString serialNumber() const;
/**
* Returns the RenderLoop for this output. This function returns @c null if the
* underlying platform doesn't support per-screen rendering mode.
* Returns the RenderLoop for this output. If the platform does not support per screen
* rendering, all outputs will share the same render loop.
*/
virtual RenderLoop *renderLoop() const;
virtual RenderLoop *renderLoop() const = 0;
void inhibitDirectScanout();
void uninhibitDirectScanout();

View file

@ -46,7 +46,7 @@ EglBackend::~EglBackend()
// No completion events will be received for in-flight frames, this may lock the
// render loop. We need to ensure that the render loop is back to its initial state
// if the render backend is about to be destroyed.
RenderLoopPrivate::get(kwinApp()->platform()->renderLoop())->invalidate();
RenderLoopPrivate::get(m_backend->renderLoop())->invalidate();
}
SurfaceTexture *EglBackend::createSurfaceTextureX11(SurfacePixmapX11 *texture)

View file

@ -90,8 +90,8 @@ bool SwapEventFilter::event(xcb_generic_event_t *event)
// it's CLOCK_MONOTONIC, so no special conversions are needed.
const std::chrono::microseconds timestamp((uint64_t(swapEvent->ust_hi) << 32) | swapEvent->ust_lo);
RenderLoopPrivate *renderLoopPrivate = RenderLoopPrivate::get(kwinApp()->platform()->renderLoop());
renderLoopPrivate->notifyFrameCompleted(timestamp);
const auto platform = static_cast<X11StandalonePlatform *>(kwinApp()->platform());
RenderLoopPrivate::get(platform->renderLoop())->notifyFrameCompleted(timestamp);
return true;
}
@ -122,7 +122,7 @@ GlxBackend::~GlxBackend()
// No completion events will be received for in-flight frames, this may lock the
// render loop. We need to ensure that the render loop is back to its initial state
// if the render backend is about to be destroyed.
RenderLoopPrivate::get(kwinApp()->platform()->renderLoop())->invalidate();
RenderLoopPrivate::get(m_backend->renderLoop())->invalidate();
if (isFailed()) {
m_overlayWindow->destroy();

View file

@ -23,6 +23,16 @@ QString X11Output::name() const
return m_name;
}
RenderLoop *X11Output::renderLoop() const
{
return m_loop;
}
void X11Output::setRenderLoop(RenderLoop *loop)
{
m_loop = loop;
}
int X11Output::xineramaNumber() const
{
return m_xineramaNumber;

View file

@ -32,6 +32,9 @@ public:
QString name() const override;
RenderLoop *renderLoop() const override;
void setRenderLoop(RenderLoop *loop);
int xineramaNumber() const;
void setXineramaNumber(int number);
@ -54,6 +57,7 @@ private:
void setCrtc(xcb_randr_crtc_t crtc);
void setGammaRampSize(int size);
RenderLoop *m_loop = nullptr;
xcb_randr_crtc_t m_crtc = XCB_NONE;
QString m_name;
QRect m_geometry;

View file

@ -531,6 +531,7 @@ void X11StandalonePlatform::doUpdateOutputs()
// drm platform do this.
Xcb::RandR::CrtcGamma gamma(crtcs[i]);
output->setRenderLoop(m_renderLoop);
output->setCrtc(crtcs[i]);
output->setGammaRampSize(gamma.isNull() ? 0 : gamma->size);
output->setGeometry(geometry);
@ -560,7 +561,7 @@ void X11StandalonePlatform::doUpdateOutputs()
// The workspace handles having no outputs poorly. If the last output is about to be
// removed, create a dummy output to avoid crashing.
if (changed.isEmpty() && added.isEmpty()) {
auto dummyOutput = new X11PlaceholderOutput();
auto dummyOutput = new X11PlaceholderOutput(m_renderLoop);
m_outputs << dummyOutput;
Q_EMIT outputAdded(dummyOutput);
Q_EMIT outputEnabled(dummyOutput);

View file

@ -21,6 +21,7 @@
namespace KWin
{
class RenderLoop;
class XInputIntegration;
class WindowSelector;
class X11EventFilter;
@ -64,7 +65,7 @@ public:
void scheduleUpdateOutputs();
void updateOutputs();
RenderLoop *renderLoop() const override;
RenderLoop *renderLoop() const;
Outputs outputs() const override;
Outputs enabledOutputs() const override;

View file

@ -10,11 +10,17 @@
namespace KWin
{
X11PlaceholderOutput::X11PlaceholderOutput(QObject *parent)
X11PlaceholderOutput::X11PlaceholderOutput(RenderLoop *loop, QObject *parent)
: AbstractOutput(parent)
, m_loop(loop)
{
}
RenderLoop *X11PlaceholderOutput::renderLoop() const
{
return m_loop;
}
QString X11PlaceholderOutput::name() const
{
return QStringLiteral("Placeholder-0");

View file

@ -16,12 +16,16 @@ class X11PlaceholderOutput : public AbstractOutput
Q_OBJECT
public:
explicit X11PlaceholderOutput(QObject *parent = nullptr);
explicit X11PlaceholderOutput(RenderLoop *loop, QObject *parent = nullptr);
RenderLoop *renderLoop() const override;
QString name() const override;
QRect geometry() const override;
int refreshRate() const override;
QSize pixelSize() const override;
private:
RenderLoop *m_loop;
};
} // namespace KWin

View file

@ -351,18 +351,17 @@ void Compositor::startupWithWorkspace()
Q_ASSERT(m_scene);
m_scene->initialize();
const Platform *platform = kwinApp()->platform();
if (platform->isPerScreenRenderingEnabled()) {
const QVector<AbstractOutput *> outputs = platform->enabledOutputs();
const QVector<AbstractOutput *> outputs = kwinApp()->platform()->enabledOutputs();
if (kwinApp()->platform()->isPerScreenRenderingEnabled()) {
for (AbstractOutput *output : outputs) {
registerRenderLoop(output->renderLoop(), output);
}
connect(platform, &Platform::outputEnabled,
connect(kwinApp()->platform(), &Platform::outputEnabled,
this, &Compositor::handleOutputEnabled);
connect(platform, &Platform::outputDisabled,
connect(kwinApp()->platform(), &Platform::outputDisabled,
this, &Compositor::handleOutputDisabled);
} else {
registerRenderLoop(platform->renderLoop(), nullptr);
registerRenderLoop(outputs.constFirst()->renderLoop(), nullptr);
}
m_state = State::On;
@ -397,6 +396,17 @@ void Compositor::startupWithWorkspace()
m_scene->addRepaintFull();
}
AbstractOutput *Compositor::findOutput(RenderLoop *loop) const
{
const auto outputs = kwinApp()->platform()->enabledOutputs();
for (AbstractOutput *output : outputs) {
if (output->renderLoop() == loop) {
return output;
}
}
return nullptr;
}
void Compositor::registerRenderLoop(RenderLoop *renderLoop, AbstractOutput *output)
{
Q_ASSERT(!m_renderLoops.contains(renderLoop));
@ -622,8 +632,8 @@ void Compositor::composite(RenderLoop *renderLoop)
return;
}
const auto &output = m_renderLoops[renderLoop];
fTraceDuration("Paint (", output ? output->name() : QStringLiteral("screens"), ")");
AbstractOutput *output = findOutput(renderLoop);
fTraceDuration("Paint (", output->name(), ")");
const auto windows = windowsToRender();

View file

@ -135,6 +135,8 @@ private:
bool attemptOpenGLCompositing();
bool attemptQPainterCompositing();
AbstractOutput *findOutput(RenderLoop *loop) const;
State m_state = State::Off;
CompositorSelectionOwner *m_selectionOwner = nullptr;
QTimer m_releaseSelectionTimer;

View file

@ -60,7 +60,7 @@ void ColorPickerEffect::postPaintScreen()
{
effects->postPaintScreen();
if (m_scheduledPosition != QPoint(-1, -1) && (!m_paintedScreen || m_paintedScreen->geometry().contains(m_scheduledPosition))) {
if (m_scheduledPosition != QPoint(-1, -1) && effects->renderTargetRect().contains(m_scheduledPosition)) {
uint8_t data[3];
const QRect geo = effects->renderTargetRect();
const QPoint screenPosition(m_scheduledPosition.x() - geo.x(), m_scheduledPosition.y() - geo.y());

View file

@ -268,7 +268,7 @@ void ScreenShotEffect::takeScreenShot(ScreenShotWindowData *screenshot)
bool ScreenShotEffect::takeScreenShot(ScreenShotAreaData *screenshot)
{
if (!m_paintedScreen) {
if (!effects->waylandDisplay()) {
// On X11, all screens are painted simultaneously and there is no native HiDPI support.
QImage snapshot = blitScreenshot(screenshot->area);
if (screenshot->flags & ScreenShotIncludeCursor) {

View file

@ -255,9 +255,9 @@ void Item::scheduleRepaint(const QRegion &region)
void Item::scheduleRepaintInternal(const QRegion &region)
{
const QVector<AbstractOutput *> outputs = kwinApp()->platform()->enabledOutputs();
const QRegion globalRegion = mapToGlobal(region);
if (kwinApp()->platform()->isPerScreenRenderingEnabled()) {
const QVector<AbstractOutput *> outputs = kwinApp()->platform()->enabledOutputs();
for (const auto &output : outputs) {
const QRegion dirtyRegion = globalRegion & output->geometry();
if (!dirtyRegion.isEmpty()) {
@ -266,8 +266,8 @@ void Item::scheduleRepaintInternal(const QRegion &region)
}
}
} else {
m_repaints[nullptr] += globalRegion;
kwinApp()->platform()->renderLoop()->scheduleRepaint(this);
m_repaints[outputs.constFirst()] += globalRegion;
outputs.constFirst()->renderLoop()->scheduleRepaint(this);
}
}
@ -276,16 +276,16 @@ void Item::scheduleFrame()
if (!isVisible()) {
return;
}
const QVector<AbstractOutput *> outputs = kwinApp()->platform()->enabledOutputs();
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(this);
}
}
} else {
kwinApp()->platform()->renderLoop()->scheduleRepaint(this);
outputs.constFirst()->renderLoop()->scheduleRepaint(this);
}
}

View file

@ -3186,7 +3186,7 @@ public:
QMatrix4x4 projectionMatrix() const;
/**
* Returns the currently rendered screen. Only set for per-screen rendering, e.g. Wayland.
* Returns the currently rendered screen. It's always the primary screen on X11.
*/
EffectScreen *screen() const;

View file

@ -432,11 +432,6 @@ void Platform::setPerScreenRenderingEnabled(bool enabled)
m_isPerScreenRenderingEnabled = enabled;
}
RenderLoop *Platform::renderLoop() const
{
return nullptr;
}
AbstractOutput *Platform::createVirtualOutput(const QString &name, const QSize &size, double scale)
{
Q_UNUSED(name);

View file

@ -37,7 +37,6 @@ class OpenGLBackend;
class Outline;
class OutlineVisual;
class QPainterBackend;
class RenderLoop;
class Scene;
class ScreenEdges;
class Session;
@ -344,12 +343,6 @@ public:
*/
bool isPerScreenRenderingEnabled() const;
/**
* If the Platform doesn't support per screen rendering, this function returns the
* RenderLoop that drives compositing.
*/
virtual RenderLoop *renderLoop() const;
virtual AbstractOutput *createVirtualOutput(const QString &name, const QSize &size, qreal scaling);
virtual void removeVirtualOutput(AbstractOutput *output);

View file

@ -143,8 +143,8 @@ void Scene::addRepaint(const QRect &rect)
void Scene::addRepaint(const QRegion &region)
{
const QVector<AbstractOutput *> outputs = kwinApp()->platform()->enabledOutputs();
if (kwinApp()->platform()->isPerScreenRenderingEnabled()) {
const QVector<AbstractOutput *> outputs = kwinApp()->platform()->enabledOutputs();
for (const auto &output : outputs) {
const QRegion dirtyRegion = region & output->geometry();
if (!dirtyRegion.isEmpty()) {
@ -153,8 +153,8 @@ void Scene::addRepaint(const QRegion &region)
}
}
} else {
m_repaints[0] += region;
kwinApp()->platform()->renderLoop()->scheduleRepaint();
m_repaints[outputs.constFirst()] += region;
outputs.constFirst()->renderLoop()->scheduleRepaint();
}
}
@ -261,16 +261,17 @@ void Scene::paintScreen(AbstractOutput *output, const QList<Toplevel *> &topleve
setRenderTargetScale(output->scale());
QRegion update, valid;
paintScreen(renderTargetRect(), QRect(), &update, &valid, output->renderLoop());
paintScreen(renderTargetRect(), QRect(), &update, &valid);
clearStackingOrder();
}
// returns mask and possibly modified region
void Scene::paintScreen(const QRegion &damage, const QRegion &repaint,
QRegion *updateRegion, QRegion *validRegion, RenderLoop *renderLoop)
QRegion *updateRegion, QRegion *validRegion)
{
const QRegion displayRegion(geometry());
const RenderLoop *renderLoop = painted_screen->renderLoop();
const std::chrono::milliseconds presentTime =
std::chrono::duration_cast<std::chrono::milliseconds>(renderLoop->nextPresentationTimestamp());
@ -289,7 +290,7 @@ void Scene::paintScreen(const QRegion &damage, const QRegion &repaint,
QRegion region = damage;
auto screen = painted_screen ? EffectScreenImpl::get(painted_screen) : nullptr;
auto screen = EffectScreenImpl::get(painted_screen);
ScreenPrePaintData pdata;
pdata.mask = (damage == displayRegion) ? 0 : PAINT_SCREEN_REGION;
pdata.paint = region;

View file

@ -209,7 +209,7 @@ protected:
void clearStackingOrder();
// shared implementation, starts painting the screen
void paintScreen(const QRegion &damage, const QRegion &repaint,
QRegion *updateRegion, QRegion *validRegion, RenderLoop *renderLoop);
QRegion *updateRegion, QRegion *validRegion);
// Render cursor texture in case hardware cursor is disabled/non-applicable
virtual void paintCursor(AbstractOutput *output, const QRegion &region) = 0;
friend class EffectsHandlerImpl;

View file

@ -195,7 +195,7 @@ void SceneOpenGL::paint(AbstractOutput *output, const QRegion &damage, const QLi
QRegion valid;
QRegion repaint;
if (output) {
if (kwinApp()->platform()->isPerScreenRenderingEnabled()) {
setRenderTargetRect(output->geometry());
setRenderTargetScale(output->scale());
} else {
@ -248,7 +248,7 @@ void SceneOpenGL::paint(AbstractOutput *output, const QRegion &damage, const QLi
repaint = m_backend->beginFrame(output);
GLVertexBuffer::streamingBuffer()->beginFrame();
paintScreen(damage.intersected(renderTargetRect()), repaint, &update, &valid, renderLoop); // call generic implementation
paintScreen(damage.intersected(renderTargetRect()), repaint, &update, &valid);
paintCursor(output, valid);
renderLoop->endFrame();

View file

@ -86,7 +86,7 @@ void SceneQPainter::paint(AbstractOutput *output, const QRegion &damage, const Q
m_painter->setWindow(geometry);
QRegion updateRegion, validRegion;
paintScreen(damage.intersected(geometry), repaint, &updateRegion, &validRegion, renderLoop);
paintScreen(damage.intersected(geometry), repaint, &updateRegion, &validRegion);
paintCursor(output, updateRegion);
m_painter->end();