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:
parent
ba000d5a4e
commit
a3b5266175
22 changed files with 76 additions and 54 deletions
|
@ -141,11 +141,6 @@ QString AbstractOutput::serialNumber() const
|
|||
return QString();
|
||||
}
|
||||
|
||||
RenderLoop *AbstractOutput::renderLoop() const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void AbstractOutput::inhibitDirectScanout()
|
||||
{
|
||||
m_directScanoutCount++;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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) {
|
||||
|
|
10
src/item.cpp
10
src/item.cpp
|
@ -255,9 +255,9 @@ void Item::scheduleRepaint(const QRegion ®ion)
|
|||
|
||||
void Item::scheduleRepaintInternal(const QRegion ®ion)
|
||||
{
|
||||
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 ®ion)
|
|||
}
|
||||
}
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -143,8 +143,8 @@ void Scene::addRepaint(const QRect &rect)
|
|||
|
||||
void Scene::addRepaint(const QRegion ®ion)
|
||||
{
|
||||
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 ®ion)
|
|||
}
|
||||
}
|
||||
} 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;
|
||||
|
|
|
@ -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 ®ion) = 0;
|
||||
friend class EffectsHandlerImpl;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in a new issue