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.
This commit is contained in:
Vlad Zahorodnii 2022-04-05 17:15:57 +03:00
parent 1cf3804f60
commit 809f383d44
22 changed files with 58 additions and 57 deletions

View file

@ -173,4 +173,9 @@ bool AbstractOutput::usesSoftwareCursor() const
return true;
}
QRect AbstractOutput::mapFromGlobal(const QRect &rect) const
{
return rect.translated(-geometry().topLeft());
}
} // namespace KWin

View file

@ -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.
*

View file

@ -39,7 +39,7 @@ void DrmAbstractOutput::pageFlipped(std::chrono::nanoseconds timestamp) const
QVector<int32_t> DrmAbstractOutput::regionToRects(const QRegion &region) 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<EGLint> rects;
rects.reserve(region.rectCount() * 4);
for (const QRect &_rect : region) {

View file

@ -36,7 +36,7 @@ std::optional<QRegion> DrmQPainterLayer::startRendering()
m_swapchain = QSharedPointer<DumbSwapchain>::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<QRegion>();
}
return needsRepaint;

View file

@ -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<DrmDumbBuffer> DumbSwapchain::acquireBuffer(const QRect &geometry, QRegion *needsRepaint)
QSharedPointer<DrmDumbBuffer> 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;
}

View file

@ -27,7 +27,7 @@ class DumbSwapchain
public:
DumbSwapchain(DrmGpu *gpu, const QSize &size, uint32_t drmFormat, QImage::Format imageFormat = QImage::Format_RGB32);
QSharedPointer<DrmDumbBuffer> acquireBuffer(const QRect &geometry = {}, QRegion *needsRepaint = nullptr);
QSharedPointer<DrmDumbBuffer> acquireBuffer(QRegion *needsRepaint = nullptr);
QSharedPointer<DrmDumbBuffer> currentBuffer() const;
void releaseBuffer(QSharedPointer<DrmDumbBuffer> buffer, const QRegion &damage = {});

View file

@ -90,7 +90,7 @@ std::optional<QRegion> EglGbmLayer::startRendering()
if (!m_gbmSurface->makeContextCurrent()) {
return std::optional<QRegion>();
}
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();

View file

@ -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();
}
}

View file

@ -49,7 +49,7 @@ public:
uint32_t format() const;
QVector<uint64_t> modifiers() const;
int bufferAge() const;
QRegion repaintRegion(const QRect &geometry) const;
QRegion repaintRegion() const;
private:
gbm_surface *m_surface;

View file

@ -79,7 +79,7 @@ std::optional<QRegion> VirtualEglGbmLayer::startRendering()
return std::optional<QRegion>();
}
GLRenderTarget::pushRenderTarget(m_gbmSurface->renderTarget());
return m_gbmSurface->repaintRegion(m_output->geometry());
return m_gbmSurface->repaintRegion();
}
bool VirtualEglGbmLayer::endRendering(const QRegion &damagedRegion)

View file

@ -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)

View file

@ -297,7 +297,7 @@ bool EglWaylandBackend::initBufferConfigs()
static QVector<EGLint> regionToRects(const QRegion &region, 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();

View file

@ -12,6 +12,7 @@
#include "wayland_output.h"
#include "composite.h"
#include "kwineffects.h"
#include "logging.h"
#include <KWayland/Client/buffer.h>
@ -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 &region) 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)

View file

@ -63,7 +63,6 @@ public:
void present(const QRegion &damage);
QRegion accumulateDamage(int bufferAge) const;
QRegion mapToLocal(const QRegion &region) const;
private:
WaylandOutput *m_waylandOutput;

View file

@ -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);

View file

@ -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();

View file

@ -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)

View file

@ -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)

View file

@ -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);

View file

@ -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] {

View file

@ -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 &region)
{
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 &region)
{
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()

View file

@ -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;