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:
parent
1cf3804f60
commit
809f383d44
22 changed files with 58 additions and 57 deletions
|
@ -173,4 +173,9 @@ bool AbstractOutput::usesSoftwareCursor() const
|
|||
return true;
|
||||
}
|
||||
|
||||
QRect AbstractOutput::mapFromGlobal(const QRect &rect) const
|
||||
{
|
||||
return rect.translated(-geometry().topLeft());
|
||||
}
|
||||
|
||||
} // namespace KWin
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -39,7 +39,7 @@ void DrmAbstractOutput::pageFlipped(std::chrono::nanoseconds timestamp) const
|
|||
QVector<int32_t> 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<EGLint> rects;
|
||||
rects.reserve(region.rectCount() * 4);
|
||||
for (const QRect &_rect : region) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 = {});
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -297,7 +297,7 @@ bool EglWaylandBackend::initBufferConfigs()
|
|||
static QVector<EGLint> 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();
|
||||
|
|
|
@ -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 ®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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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] {
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue