From 6384f4acf4e2988bcb35d3dfc5821f07867a34d0 Mon Sep 17 00:00:00 2001 From: Lee Bousfield Date: Sat, 22 Mar 2025 11:13:44 -0500 Subject: core/compositor: Correctly track SHM buffer damage (#9678) --- src/protocols/DRMSyncobj.cpp | 2 +- src/protocols/Viewporter.cpp | 2 +- src/protocols/XDGShell.cpp | 2 +- src/protocols/core/Compositor.cpp | 53 +++++++++----------------------- src/protocols/core/Compositor.hpp | 3 +- src/protocols/core/Shm.cpp | 11 ++----- src/protocols/core/Shm.hpp | 2 -- src/protocols/types/SurfaceState.cpp | 58 ++++++++++++++++++++++++++++++++++++ src/protocols/types/SurfaceState.hpp | 18 +++++------ 9 files changed, 85 insertions(+), 66 deletions(-) create mode 100644 src/protocols/types/SurfaceState.cpp (limited to 'src/protocols') diff --git a/src/protocols/DRMSyncobj.cpp b/src/protocols/DRMSyncobj.cpp index 943aad4d..5238d1fb 100644 --- a/src/protocols/DRMSyncobj.cpp +++ b/src/protocols/DRMSyncobj.cpp @@ -137,7 +137,7 @@ CDRMSyncobjSurfaceResource::~CDRMSyncobjSurfaceResource() { } bool CDRMSyncobjSurfaceResource::protocolError() { - if (!surface->pending.texture) { + if (!surface->pending.buffer) { resource->error(WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_BUFFER, "Missing buffer"); surface->pending.rejected = true; return true; diff --git a/src/protocols/Viewporter.cpp b/src/protocols/Viewporter.cpp index 4964bead..d14e7ee5 100644 --- a/src/protocols/Viewporter.cpp +++ b/src/protocols/Viewporter.cpp @@ -52,7 +52,7 @@ CViewportResource::CViewportResource(SP resource_, SPevents.precommit.registerListener([this](std::any d) { - if (!surface || !surface->pending.texture) + if (!surface || !surface->pending.buffer) return; if (surface->pending.viewport.hasSource) { diff --git a/src/protocols/XDGShell.cpp b/src/protocols/XDGShell.cpp index 9424a9d6..db274e3c 100644 --- a/src/protocols/XDGShell.cpp +++ b/src/protocols/XDGShell.cpp @@ -387,7 +387,7 @@ CXDGSurfaceResource::CXDGSurfaceResource(SP resource_, SPcurrent = toplevel->pending; - if UNLIKELY (initialCommit && surface->pending.texture) { + if UNLIKELY (initialCommit && surface->pending.buffer) { resource->error(-1, "Buffer attached before initial commit"); return; } diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp index 6b47b503..5462fbe9 100644 --- a/src/protocols/core/Compositor.cpp +++ b/src/protocols/core/Compositor.cpp @@ -12,6 +12,7 @@ #include "../DRMSyncobj.hpp" #include "../../render/Renderer.hpp" #include "config/ConfigValue.hpp" +#include "render/Texture.hpp" #include class CDefaultSurfaceRole : public ISurfaceRole { @@ -91,10 +92,10 @@ CWLSurfaceResource::CWLSurfaceResource(SP resource_) : resource(reso }); resource->setCommit([this](CWlSurface* r) { - if (pending.texture) + if (pending.buffer) pending.bufferDamage.intersect(CBox{{}, pending.bufferSize}); - if (!pending.texture) + if (!pending.buffer) pending.size = {}; else if (pending.viewport.hasDestination) pending.size = pending.viewport.destination; @@ -399,36 +400,8 @@ CBox CWLSurfaceResource::extends() { return full.getExtents(); } -Vector2D CWLSurfaceResource::sourceSize() { - if UNLIKELY (!current.texture) - return {}; - - if UNLIKELY (current.viewport.hasSource) - return current.viewport.source.size(); - - Vector2D trc = current.transform % 2 == 1 ? Vector2D{current.bufferSize.y, current.bufferSize.x} : current.bufferSize; - return trc / current.scale; -} - -CRegion CWLSurfaceResource::accumulateCurrentBufferDamage() { - if UNLIKELY (!current.texture) - return {}; - - CRegion surfaceDamage = current.damage; - if (current.viewport.hasDestination) { - Vector2D scale = sourceSize() / current.viewport.destination; - surfaceDamage.scale(scale); - } - - if (current.viewport.hasSource) - surfaceDamage.translate(current.viewport.source.pos()); - - Vector2D trc = current.transform % 2 == 1 ? Vector2D{current.bufferSize.y, current.bufferSize.x} : current.bufferSize; - - return surfaceDamage.scale(current.scale).transform(wlTransformToHyprutils(invertTransform(current.transform)), trc.x, trc.y).add(current.bufferDamage); -} - void CWLSurfaceResource::commitPendingState(SSurfaceState& state) { + auto lastTexture = current.texture; if (state.newBuffer) { state.newBuffer = false; current = state; @@ -437,20 +410,19 @@ void CWLSurfaceResource::commitPendingState(SSurfaceState& state) { state.buffer.reset(); } - if (current.texture) - current.texture->m_eTransform = wlTransformToHyprutils(current.transform); - if (current.buffer) { - const auto DAMAGE = accumulateCurrentBufferDamage(); - current.buffer->buffer->update(DAMAGE); + if (current.buffer->buffer->isSynchronous()) + current.updateSynchronousTexture(lastTexture); // if the surface is a cursor, update the shm buffer // TODO: don't update the entire texture - if (role->role() == SURFACE_ROLE_CURSOR && !DAMAGE.empty()) - updateCursorShm(DAMAGE); + if (role->role() == SURFACE_ROLE_CURSOR) + updateCursorShm(current.accumulateBufferDamage()); } - // TODO: we should _accumulate_ and not replace above if sync + if (current.texture) + current.texture->m_eTransform = wlTransformToHyprutils(current.transform); + if (role->role() == SURFACE_ROLE_SUBSURFACE) { auto subsurface = ((CSubsurfaceRole*)role.get())->subsurface.lock(); if (subsurface->sync) @@ -478,6 +450,9 @@ void CWLSurfaceResource::commitPendingState(SSurfaceState& state) { } void CWLSurfaceResource::updateCursorShm(CRegion damage) { + if (damage.empty()) + return; + auto buf = current.buffer ? current.buffer->buffer : SP{}; if UNLIKELY (!buf) diff --git a/src/protocols/core/Compositor.hpp b/src/protocols/core/Compositor.hpp index f958528c..5d2240a7 100644 --- a/src/protocols/core/Compositor.hpp +++ b/src/protocols/core/Compositor.hpp @@ -11,6 +11,7 @@ #include #include #include "../WaylandProtocol.hpp" +#include "render/Texture.hpp" #include "wayland.hpp" #include "../../helpers/signal/Signal.hpp" #include "../../helpers/math/Math.hpp" @@ -75,7 +76,6 @@ class CWLSurfaceResource { SP getResource(); CBox extends(); void resetRole(); - Vector2D sourceSize(); struct { CSignal precommit; // before commit @@ -102,7 +102,6 @@ class CWLSurfaceResource { void breadthfirst(std::function, const Vector2D&, void*)> fn, void* data); SP findFirstPreorder(std::function)> fn); - CRegion accumulateCurrentBufferDamage(); void presentFeedback(timespec* when, PHLMONITOR pMonitor, bool discarded = false); void commitPendingState(SSurfaceState& state); diff --git a/src/protocols/core/Shm.cpp b/src/protocols/core/Shm.cpp index 37a48fd3..420b4a3f 100644 --- a/src/protocols/core/Shm.cpp +++ b/src/protocols/core/Shm.cpp @@ -22,19 +22,12 @@ CWLSHMBuffer::CWLSHMBuffer(SP pool_, uint32_t id, int32_t of offset = offset_; opaque = NFormatUtils::isFormatOpaque(NFormatUtils::shmToDRM(fmt_)); - texture = makeShared(NFormatUtils::shmToDRM(fmt), (uint8_t*)pool->data + offset, stride, size_); - resource = CWLBufferResource::create(makeShared(pool_->resource->client(), 1, id)); listeners.bufferResourceDestroy = events.destroy.registerListener([this](std::any d) { listeners.bufferResourceDestroy.reset(); PROTO::shm->destroyResource(this); }); - - success = texture->m_iTexID; - - if UNLIKELY (!success) - Debug::log(ERR, "Failed creating a shm texture: null texture id"); } CWLSHMBuffer::~CWLSHMBuffer() { @@ -74,11 +67,11 @@ void CWLSHMBuffer::endDataPtr() { } bool CWLSHMBuffer::good() { - return success; + return true; } void CWLSHMBuffer::update(const CRegion& damage) { - texture->update(NFormatUtils::shmToDRM(fmt), (uint8_t*)pool->data + offset, stride, damage); + ; } CSHMPool::CSHMPool(CFileDescriptor fd_, size_t size_) : fd(std::move(fd_)), size(size_), data(mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd.get(), 0)) { diff --git a/src/protocols/core/Shm.hpp b/src/protocols/core/Shm.hpp index fa5f29a4..61b26f12 100644 --- a/src/protocols/core/Shm.hpp +++ b/src/protocols/core/Shm.hpp @@ -50,8 +50,6 @@ class CWLSHMBuffer : public IHLBuffer { SP pool; private: - bool success = false; - struct { CHyprSignalListener bufferResourceDestroy; } listeners; diff --git a/src/protocols/types/SurfaceState.cpp b/src/protocols/types/SurfaceState.cpp new file mode 100644 index 00000000..6f9636ff --- /dev/null +++ b/src/protocols/types/SurfaceState.cpp @@ -0,0 +1,58 @@ +#include "SurfaceState.hpp" +#include "helpers/Format.hpp" +#include "protocols/types/Buffer.hpp" +#include "render/Texture.hpp" + +Vector2D SSurfaceState::sourceSize() { + if UNLIKELY (!texture) + return {}; + + if UNLIKELY (viewport.hasSource) + return viewport.source.size(); + + Vector2D trc = transform % 2 == 1 ? Vector2D{bufferSize.y, bufferSize.x} : bufferSize; + return trc / scale; +} + +CRegion SSurfaceState::accumulateBufferDamage() { + if (damage.empty()) + return bufferDamage; + + CRegion surfaceDamage = damage; + if (viewport.hasDestination) { + Vector2D scale = sourceSize() / viewport.destination; + surfaceDamage.scale(scale); + } + + if (viewport.hasSource) + surfaceDamage.translate(viewport.source.pos()); + + Vector2D trc = transform % 2 == 1 ? Vector2D{bufferSize.y, bufferSize.x} : bufferSize; + + bufferDamage = surfaceDamage.scale(scale).transform(wlTransformToHyprutils(invertTransform(transform)), trc.x, trc.y).add(bufferDamage); + damage.clear(); + return bufferDamage; +} + +void SSurfaceState::updateSynchronousTexture(SP lastTexture) { + auto [dataPtr, fmt, size] = buffer->buffer->beginDataPtr(0); + if (dataPtr) { + auto drmFmt = NFormatUtils::shmToDRM(fmt); + auto stride = bufferSize.y ? size / bufferSize.y : 0; + if (lastTexture && lastTexture->m_isSynchronous && lastTexture->m_vSize == bufferSize) { + texture = lastTexture; + texture->update(drmFmt, dataPtr, stride, accumulateBufferDamage()); + } else + texture = makeShared(drmFmt, dataPtr, stride, bufferSize); + } + buffer->buffer->endDataPtr(); +} + +void SSurfaceState::reset() { + damage.clear(); + bufferDamage.clear(); + transform = WL_OUTPUT_TRANSFORM_NORMAL; + scale = 1; + offset = {}; + size = {}; +} diff --git a/src/protocols/types/SurfaceState.hpp b/src/protocols/types/SurfaceState.hpp index cd9be5ca..b5093759 100644 --- a/src/protocols/types/SurfaceState.hpp +++ b/src/protocols/types/SurfaceState.hpp @@ -20,16 +20,12 @@ struct SSurfaceState { Vector2D destination; CBox source; } viewport; - bool rejected = false; - bool newBuffer = false; + bool rejected = false; + bool newBuffer = false; - // - void reset() { - damage.clear(); - bufferDamage.clear(); - transform = WL_OUTPUT_TRANSFORM_NORMAL; - scale = 1; - offset = {}; - size = {}; - } + Vector2D sourceSize(); + // Translates damage into bufferDamage, clearing damage and returning the updated bufferDamage + CRegion accumulateBufferDamage(); + void updateSynchronousTexture(SP lastTexture); + void reset(); }; -- cgit v1.2.3