From 809f383d4477df754058085a3b626333c4c2fd6e Mon Sep 17 00:00:00 2001 From: Vlad Zahorodnii Date: Tue, 5 Apr 2022 17:15:57 +0300 Subject: [PATCH] Take layer-local damage regions Using the global coordinate system when specifying output layer damage regions would be very confusing. In order to make the coordinate system comprehensible, use the layer-local coordinate system. The infinite region is used to tell the Compositor when it needs to repaint the entire layer. --- src/abstract_output.cpp | 5 ++++ src/abstract_output.h | 5 ++++ src/backends/drm/drm_abstract_output.cpp | 2 +- src/backends/drm/drm_qpainter_layer.cpp | 2 +- src/backends/drm/dumb_swapchain.cpp | 5 ++-- src/backends/drm/dumb_swapchain.h | 2 +- src/backends/drm/egl_gbm_layer.cpp | 21 ++++------------- src/backends/drm/gbm_surface.cpp | 7 +++--- src/backends/drm/gbm_surface.h | 2 +- src/backends/drm/virtual_egl_gbm_layer.cpp | 2 +- src/backends/virtual/egl_gbm_backend.cpp | 2 +- src/backends/wayland/egl_wayland_backend.cpp | 4 ++-- .../scene_qpainter_wayland_backend.cpp | 10 +++----- .../wayland/scene_qpainter_wayland_backend.h | 1 - src/backends/x11/standalone/eglbackend.cpp | 2 +- src/backends/x11/standalone/glxbackend.cpp | 2 +- src/backends/x11/windowed/egl_x11_backend.cpp | 2 +- .../windowed/scene_qpainter_x11_backend.cpp | 2 +- src/composite.cpp | 10 ++++---- src/plugins/screencast/screencastmanager.cpp | 2 +- src/scene.cpp | 23 +++++++++++-------- src/scene.h | 2 ++ 22 files changed, 58 insertions(+), 57 deletions(-) diff --git a/src/abstract_output.cpp b/src/abstract_output.cpp index 6ea73ad065..4595e9a159 100644 --- a/src/abstract_output.cpp +++ b/src/abstract_output.cpp @@ -173,4 +173,9 @@ bool AbstractOutput::usesSoftwareCursor() const return true; } +QRect AbstractOutput::mapFromGlobal(const QRect &rect) const +{ + return rect.translated(-geometry().topLeft()); +} + } // namespace KWin diff --git a/src/abstract_output.h b/src/abstract_output.h index 3c65b6dee6..a8f759c0c4 100644 --- a/src/abstract_output.h +++ b/src/abstract_output.h @@ -94,6 +94,11 @@ public: explicit AbstractOutput(QObject *parent = nullptr); ~AbstractOutput() override; + /** + * Maps the specified @a rect from the global coordinate system to the output-local coords. + */ + QRect mapFromGlobal(const QRect &rect) const; + /** * Returns a dummy OutputLayer corresponding to the primary plane. * diff --git a/src/backends/drm/drm_abstract_output.cpp b/src/backends/drm/drm_abstract_output.cpp index 017852c034..81690b1445 100644 --- a/src/backends/drm/drm_abstract_output.cpp +++ b/src/backends/drm/drm_abstract_output.cpp @@ -39,7 +39,7 @@ void DrmAbstractOutput::pageFlipped(std::chrono::nanoseconds timestamp) const QVector DrmAbstractOutput::regionToRects(const QRegion ®ion) const { const int height = pixelSize().height(); - const QMatrix4x4 matrix = AbstractWaylandOutput::logicalToNativeMatrix(geometry(), scale(), transform()); + const QMatrix4x4 matrix = AbstractWaylandOutput::logicalToNativeMatrix(QRect(QPoint(0, 0), geometry().size()), scale(), transform()); QVector rects; rects.reserve(region.rectCount() * 4); for (const QRect &_rect : region) { diff --git a/src/backends/drm/drm_qpainter_layer.cpp b/src/backends/drm/drm_qpainter_layer.cpp index cc66350a1e..0289ee315a 100644 --- a/src/backends/drm/drm_qpainter_layer.cpp +++ b/src/backends/drm/drm_qpainter_layer.cpp @@ -36,7 +36,7 @@ std::optional DrmQPainterLayer::startRendering() m_swapchain = QSharedPointer::create(m_pipeline->gpu(), m_pipeline->sourceSize(), DRM_FORMAT_XRGB8888); } QRegion needsRepaint; - if (!m_swapchain->acquireBuffer(m_pipeline->output()->geometry(), &needsRepaint)) { + if (!m_swapchain->acquireBuffer(&needsRepaint)) { return std::optional(); } return needsRepaint; diff --git a/src/backends/drm/dumb_swapchain.cpp b/src/backends/drm/dumb_swapchain.cpp index e2d3f1d788..df5d032fc2 100644 --- a/src/backends/drm/dumb_swapchain.cpp +++ b/src/backends/drm/dumb_swapchain.cpp @@ -10,6 +10,7 @@ #include "dumb_swapchain.h" #include "drm_buffer.h" #include "drm_gpu.h" +#include "kwineffects.h" #include "logging.h" namespace KWin @@ -40,14 +41,14 @@ DumbSwapchain::DumbSwapchain(DrmGpu *gpu, const QSize &size, uint32_t drmFormat, } } -QSharedPointer DumbSwapchain::acquireBuffer(const QRect &geometry, QRegion *needsRepaint) +QSharedPointer DumbSwapchain::acquireBuffer(QRegion *needsRepaint) { if (m_slots.isEmpty()) { return {}; } index = (index + 1) % m_slots.count(); if (needsRepaint) { - *needsRepaint = m_damageJournal.accumulate(m_slots[index].age, geometry); + *needsRepaint = m_damageJournal.accumulate(m_slots[index].age, infiniteRegion()); } return m_slots[index].buffer; } diff --git a/src/backends/drm/dumb_swapchain.h b/src/backends/drm/dumb_swapchain.h index c1b5173ce5..c0f035ff78 100644 --- a/src/backends/drm/dumb_swapchain.h +++ b/src/backends/drm/dumb_swapchain.h @@ -27,7 +27,7 @@ class DumbSwapchain public: DumbSwapchain(DrmGpu *gpu, const QSize &size, uint32_t drmFormat, QImage::Format imageFormat = QImage::Format_RGB32); - QSharedPointer acquireBuffer(const QRect &geometry = {}, QRegion *needsRepaint = nullptr); + QSharedPointer acquireBuffer(QRegion *needsRepaint = nullptr); QSharedPointer currentBuffer() const; void releaseBuffer(QSharedPointer buffer, const QRegion &damage = {}); diff --git a/src/backends/drm/egl_gbm_layer.cpp b/src/backends/drm/egl_gbm_layer.cpp index 37ddeb435c..d68a3c3dc5 100644 --- a/src/backends/drm/egl_gbm_layer.cpp +++ b/src/backends/drm/egl_gbm_layer.cpp @@ -90,7 +90,7 @@ std::optional EglGbmLayer::startRendering() if (!m_gbmSurface->makeContextCurrent()) { return std::optional(); } - auto repaintRegion = m_gbmSurface->repaintRegion(m_pipeline->output()->geometry()); + auto repaintRegion = m_gbmSurface->repaintRegion(); // shadow buffer if (doesShadowBufferFit(m_shadowBuffer.data())) { @@ -185,7 +185,7 @@ bool EglGbmLayer::renderTestBuffer() return false; } glClear(GL_COLOR_BUFFER_BIT); - if (!endRendering(m_pipeline->output()->geometry())) { + if (!endRendering(infiniteRegion())) { return false; } return true; @@ -441,22 +441,11 @@ bool EglGbmLayer::scanout(SurfaceItem *surfaceItem) m_scanoutBuffer.reset(); return false; } - // damage tracking for screen casting - QRegion damage; - if (m_scanoutCandidate.surface == item->surface()) { - QRegion trackedDamage = surfaceItem->damage(); - surfaceItem->resetDamage(); - for (const auto &rect : trackedDamage) { - auto damageRect = QRect(rect); - damageRect.translate(m_pipeline->output()->geometry().topLeft()); - damage |= damageRect; - } - } else { - damage = m_pipeline->output()->geometry(); - } + if (m_pipeline->testScanout()) { m_currentBuffer = m_scanoutBuffer; - m_currentDamage = damage; + m_currentDamage = surfaceItem->damage(); + surfaceItem->resetDamage(); return true; } else { m_scanoutBuffer.reset(); diff --git a/src/backends/drm/gbm_surface.cpp b/src/backends/drm/gbm_surface.cpp index 7a7f6169a2..9399206764 100644 --- a/src/backends/drm/gbm_surface.cpp +++ b/src/backends/drm/gbm_surface.cpp @@ -14,6 +14,7 @@ #include "drm_backend.h" #include "drm_gpu.h" #include "egl_gbm_backend.h" +#include "kwineffects.h" #include "kwineglutils_p.h" #include "kwinglplatform.h" #include "logging.h" @@ -178,12 +179,12 @@ int GbmSurface::bufferAge() const return m_bufferAge; } -QRegion GbmSurface::repaintRegion(const QRect &geometry) const +QRegion GbmSurface::repaintRegion() const { if (m_eglBackend->supportsBufferAge()) { - return m_damageJournal.accumulate(m_bufferAge, geometry); + return m_damageJournal.accumulate(m_bufferAge, infiniteRegion()); } else { - return geometry; + return infiniteRegion(); } } diff --git a/src/backends/drm/gbm_surface.h b/src/backends/drm/gbm_surface.h index 1e57ece5fd..c80f8a6833 100644 --- a/src/backends/drm/gbm_surface.h +++ b/src/backends/drm/gbm_surface.h @@ -49,7 +49,7 @@ public: uint32_t format() const; QVector modifiers() const; int bufferAge() const; - QRegion repaintRegion(const QRect &geometry) const; + QRegion repaintRegion() const; private: gbm_surface *m_surface; diff --git a/src/backends/drm/virtual_egl_gbm_layer.cpp b/src/backends/drm/virtual_egl_gbm_layer.cpp index 21f0284914..4618a4a96f 100644 --- a/src/backends/drm/virtual_egl_gbm_layer.cpp +++ b/src/backends/drm/virtual_egl_gbm_layer.cpp @@ -79,7 +79,7 @@ std::optional VirtualEglGbmLayer::startRendering() return std::optional(); } GLRenderTarget::pushRenderTarget(m_gbmSurface->renderTarget()); - return m_gbmSurface->repaintRegion(m_output->geometry()); + return m_gbmSurface->repaintRegion(); } bool VirtualEglGbmLayer::endRendering(const QRegion &damagedRegion) diff --git a/src/backends/virtual/egl_gbm_backend.cpp b/src/backends/virtual/egl_gbm_backend.cpp index cccd9fd318..e017831db6 100644 --- a/src/backends/virtual/egl_gbm_backend.cpp +++ b/src/backends/virtual/egl_gbm_backend.cpp @@ -164,7 +164,7 @@ QRegion EglGbmBackend::beginFrame(AbstractOutput *output) if (!GLRenderTarget::currentRenderTarget()) { GLRenderTarget::pushRenderTarget(m_fbo); } - return QRegion(0, 0, screens()->size().width(), screens()->size().height()); + return infiniteRegion(); } static void convertFromGLImage(QImage &img, int w, int h) diff --git a/src/backends/wayland/egl_wayland_backend.cpp b/src/backends/wayland/egl_wayland_backend.cpp index 0a7d1ebd0c..bea12a69c8 100644 --- a/src/backends/wayland/egl_wayland_backend.cpp +++ b/src/backends/wayland/egl_wayland_backend.cpp @@ -297,7 +297,7 @@ bool EglWaylandBackend::initBufferConfigs() static QVector regionToRects(const QRegion ®ion, AbstractWaylandOutput *output) { const int height = output->modeSize().height(); - const QMatrix4x4 matrix = WaylandOutput::logicalToNativeMatrix(output->geometry(), + const QMatrix4x4 matrix = WaylandOutput::logicalToNativeMatrix(QRect(QPoint(0, 0), output->geometry().size()), output->scale(), output->transform()); @@ -385,7 +385,7 @@ QRegion EglWaylandBackend::beginFrame(AbstractOutput *output) GLRenderTarget::pushRenderTarget(eglOutput->renderTarget()); if (supportsBufferAge()) { - return eglOutput->m_damageJournal.accumulate(eglOutput->m_bufferAge, eglOutput->m_waylandOutput->geometry()); + return eglOutput->m_damageJournal.accumulate(eglOutput->m_bufferAge, infiniteRegion()); } return QRegion(); diff --git a/src/backends/wayland/scene_qpainter_wayland_backend.cpp b/src/backends/wayland/scene_qpainter_wayland_backend.cpp index 77f4c8ec2c..764873754f 100644 --- a/src/backends/wayland/scene_qpainter_wayland_backend.cpp +++ b/src/backends/wayland/scene_qpainter_wayland_backend.cpp @@ -12,6 +12,7 @@ #include "wayland_output.h" #include "composite.h" +#include "kwineffects.h" #include "logging.h" #include @@ -127,12 +128,7 @@ WaylandQPainterBufferSlot *WaylandQPainterOutput::acquire() QRegion WaylandQPainterOutput::accumulateDamage(int bufferAge) const { - return m_damageJournal.accumulate(bufferAge, m_waylandOutput->geometry()); -} - -QRegion WaylandQPainterOutput::mapToLocal(const QRegion ®ion) const -{ - return region.translated(-m_waylandOutput->geometry().topLeft()); + return m_damageJournal.accumulate(bufferAge, infiniteRegion()); } WaylandQPainterBackend::WaylandQPainterBackend(Wayland::WaylandBackend *b) @@ -174,7 +170,7 @@ void WaylandQPainterBackend::endFrame(AbstractOutput *output, const QRegion &ren WaylandQPainterOutput *rendererOutput = m_outputs[output]; Q_ASSERT(rendererOutput); - rendererOutput->present(rendererOutput->mapToLocal(damagedRegion)); + rendererOutput->present(damagedRegion); } QImage *WaylandQPainterBackend::bufferForScreen(AbstractOutput *output) diff --git a/src/backends/wayland/scene_qpainter_wayland_backend.h b/src/backends/wayland/scene_qpainter_wayland_backend.h index 0c5504085f..9fecb4b5de 100644 --- a/src/backends/wayland/scene_qpainter_wayland_backend.h +++ b/src/backends/wayland/scene_qpainter_wayland_backend.h @@ -63,7 +63,6 @@ public: void present(const QRegion &damage); QRegion accumulateDamage(int bufferAge) const; - QRegion mapToLocal(const QRegion ®ion) const; private: WaylandOutput *m_waylandOutput; diff --git a/src/backends/x11/standalone/eglbackend.cpp b/src/backends/x11/standalone/eglbackend.cpp index c715104a2a..d3ba25ae07 100644 --- a/src/backends/x11/standalone/eglbackend.cpp +++ b/src/backends/x11/standalone/eglbackend.cpp @@ -112,7 +112,7 @@ QRegion EglBackend::beginFrame(AbstractOutput *output) QRegion repaint; if (supportsBufferAge()) { - repaint = m_damageJournal.accumulate(m_bufferAge, screens()->geometry()); + repaint = m_damageJournal.accumulate(m_bufferAge, infiniteRegion()); } eglWaitNative(EGL_CORE_NATIVE_ENGINE); diff --git a/src/backends/x11/standalone/glxbackend.cpp b/src/backends/x11/standalone/glxbackend.cpp index 3ceb27c51e..8a5d0a8a5d 100644 --- a/src/backends/x11/standalone/glxbackend.cpp +++ b/src/backends/x11/standalone/glxbackend.cpp @@ -772,7 +772,7 @@ QRegion GlxBackend::beginFrame(AbstractOutput *output) GLRenderTarget::pushRenderTarget(m_renderTarget.data()); if (supportsBufferAge()) { - repaint = m_damageJournal.accumulate(m_bufferAge, screens()->geometry()); + repaint = m_damageJournal.accumulate(m_bufferAge, infiniteRegion()); } glXWaitX(); diff --git a/src/backends/x11/windowed/egl_x11_backend.cpp b/src/backends/x11/windowed/egl_x11_backend.cpp index d5e31eb645..bef3170d8a 100644 --- a/src/backends/x11/windowed/egl_x11_backend.cpp +++ b/src/backends/x11/windowed/egl_x11_backend.cpp @@ -71,7 +71,7 @@ QRegion EglX11Backend::beginFrame(AbstractOutput *output) const EglX11Output *rendererOutput = m_outputs[output]; makeContextCurrent(rendererOutput->m_eglSurface); GLRenderTarget::pushRenderTarget(rendererOutput->m_renderTarget.data()); - return output->geometry(); + return QRect(QPoint(0, 0), output->geometry().size()); } void EglX11Backend::endFrame(AbstractOutput *output, const QRegion &renderedRegion, const QRegion &damagedRegion) diff --git a/src/backends/x11/windowed/scene_qpainter_x11_backend.cpp b/src/backends/x11/windowed/scene_qpainter_x11_backend.cpp index ce66627ae9..b981405f1b 100644 --- a/src/backends/x11/windowed/scene_qpainter_x11_backend.cpp +++ b/src/backends/x11/windowed/scene_qpainter_x11_backend.cpp @@ -52,7 +52,7 @@ QImage *X11WindowedQPainterBackend::bufferForScreen(AbstractOutput *output) QRegion X11WindowedQPainterBackend::beginFrame(AbstractOutput *output) { - return output->geometry(); + return QRect(QPoint(0, 0), output->geometry().size()); } void X11WindowedQPainterBackend::endFrame(AbstractOutput *output, const QRegion &renderedRegion, const QRegion &damagedRegion) diff --git a/src/composite.cpp b/src/composite.cpp index 25e3adf78e..b7ae35c26b 100644 --- a/src/composite.cpp +++ b/src/composite.cpp @@ -434,9 +434,9 @@ void Compositor::addOutput(AbstractOutput *output) auto workspaceLayer = new RenderLayer(output->renderLoop()); workspaceLayer->setDelegate(new SceneDelegate(m_scene, output)); - workspaceLayer->setGeometry(output->geometry()); + workspaceLayer->setGeometry(QRect(QPoint(0, 0), output->geometry().size())); connect(output, &AbstractOutput::geometryChanged, workspaceLayer, [output, workspaceLayer]() { - workspaceLayer->setGeometry(output->geometry()); + workspaceLayer->setGeometry(QRect(QPoint(0, 0), output->geometry().size())); }); auto cursorLayer = new RenderLayer(output->renderLoop()); @@ -445,10 +445,10 @@ void Compositor::addOutput(AbstractOutput *output) cursorLayer->setParent(workspaceLayer); cursorLayer->setSuperlayer(workspaceLayer); - auto updateCursorLayer = [output, workspaceLayer, cursorLayer]() { + auto updateCursorLayer = [output, cursorLayer]() { const Cursor *cursor = Cursors::self()->currentCursor(); cursorLayer->setVisible(cursor->isOnOutput(output) && output->usesSoftwareCursor()); - cursorLayer->setGeometry(workspaceLayer->mapFromGlobal(cursor->geometry())); + cursorLayer->setGeometry(output->mapFromGlobal(cursor->geometry())); cursorLayer->addRepaintFull(); }; updateCursorLayer(); @@ -682,7 +682,7 @@ void Compositor::composite(RenderLoop *renderLoop) preparePaintPass(superLayer, &surfaceDamage); const QRegion repair = m_backend->beginFrame(output); - const QRegion bufferDamage = surfaceDamage.united(repair); + const QRegion bufferDamage = surfaceDamage.united(repair).intersected(superLayer->rect()); m_backend->aboutToStartPainting(output, bufferDamage); paintPass(superLayer, bufferDamage); diff --git a/src/plugins/screencast/screencastmanager.cpp b/src/plugins/screencast/screencastmanager.cpp index 6b8eb9a55e..eddfd19b38 100644 --- a/src/plugins/screencast/screencastmanager.cpp +++ b/src/plugins/screencast/screencastmanager.cpp @@ -139,7 +139,7 @@ void ScreencastManager::streamOutput(KWaylandServer::ScreencastStreamV1Interface } const QRect frame({}, streamOutput->modeSize()); - const QRegion region = streamOutput->pixelSize() != streamOutput->modeSize() ? frame : damagedRegion.translated(-streamOutput->geometry().topLeft()).intersected(frame); + const QRegion region = streamOutput->pixelSize() != streamOutput->modeSize() ? frame : damagedRegion; stream->recordFrame(region); }; connect(stream, &ScreenCastStream::startStreaming, waylandStream, [streamOutput, stream, bufferToStream] { diff --git a/src/scene.cpp b/src/scene.cpp index 8275105df8..e653c849c7 100644 --- a/src/scene.cpp +++ b/src/scene.cpp @@ -104,7 +104,7 @@ SceneDelegate::~SceneDelegate() QRegion SceneDelegate::repaints() const { - return m_scene->damage(); + return m_scene->damage().translated(-viewport().topLeft()); } SurfaceItem *SceneDelegate::scanoutCandidate() const @@ -124,7 +124,12 @@ void SceneDelegate::postPaint() void SceneDelegate::paint(const QRegion ®ion) { - m_scene->paint(region); + m_scene->paint(region.translated(viewport().topLeft())); +} + +QRect SceneDelegate::viewport() const +{ + return m_output ? m_output->geometry() : m_scene->geometry(); } //**************************************** @@ -168,9 +173,11 @@ void Scene::addRepaint(int x, int y, int width, int height) void Scene::addRepaint(const QRegion ®ion) { for (const auto &delegate : std::as_const(m_delegates)) { - const QRegion dirtyRegion = region & delegate->layer()->geometry(); + const QRect viewport = delegate->viewport(); + QRegion dirtyRegion = region & viewport; + dirtyRegion.translate(-viewport.topLeft()); if (!dirtyRegion.isEmpty()) { - delegate->layer()->addRepaint(delegate->layer()->mapFromGlobal(dirtyRegion)); + delegate->layer()->addRepaint(dirtyRegion); } } } @@ -347,7 +354,7 @@ void Scene::preparePaintGenericScreen() } } - m_paintContext.damage = QRect(QPoint(0, 0), renderTargetRect().size()); + m_paintContext.damage = renderTargetRect(); } void Scene::preparePaintSimpleScreen() @@ -384,18 +391,14 @@ void Scene::preparePaintSimpleScreen() } // Perform an occlusion cull pass, remove surface damage occluded by opaque windows. - QRegion surfaceDamage; QRegion opaque; for (int i = m_paintContext.phase2Data.size() - 1; i >= 0; --i) { const auto &paintData = m_paintContext.phase2Data.at(i); - surfaceDamage += paintData.region - opaque; + m_paintContext.damage += paintData.region - opaque; if (!(paintData.mask & (PAINT_WINDOW_TRANSLUCENT | PAINT_WINDOW_TRANSFORMED))) { opaque += paintData.opaque; } } - - m_paintContext.damage += surfaceDamage & renderTargetRect(); - m_paintContext.damage.translate(-renderTargetRect().topLeft()); } void Scene::postPaint() diff --git a/src/scene.h b/src/scene.h index 0c27a67d64..684c28c561 100644 --- a/src/scene.h +++ b/src/scene.h @@ -53,6 +53,8 @@ public: explicit SceneDelegate(Scene *scene, AbstractOutput *output, QObject *parent = nullptr); ~SceneDelegate() override; + QRect viewport() const; + QRegion repaints() const override; SurfaceItem *scanoutCandidate() const override; void prePaint() override;