From 0cd04bd666665bfdeafc0f55a93e532cd8978827 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 26 Mar 2025 15:11:19 +0000 Subject: [PATCH] surfacestate: track and apply updated state fixes #9729 --- src/protocols/DRMSyncobj.cpp | 11 +++++--- src/protocols/core/Compositor.cpp | 42 ++++++++++++++++++---------- src/protocols/types/SurfaceState.cpp | 34 ++++++++++++++++++++++ src/protocols/types/SurfaceState.hpp | 18 ++++++++++-- 4 files changed, 85 insertions(+), 20 deletions(-) diff --git a/src/protocols/DRMSyncobj.cpp b/src/protocols/DRMSyncobj.cpp index 5238d1fb1..0a4ca439a 100644 --- a/src/protocols/DRMSyncobj.cpp +++ b/src/protocols/DRMSyncobj.cpp @@ -75,20 +75,22 @@ CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(UPevents.precommit.registerListener([this](std::any d) { - if (!surface->pending.buffer && surface->pending.newBuffer && !surface->pending.texture) { + const bool PENDING_HAS_NEW_BUFFER = surface->pending.updated & SSurfaceState::eUpdatedProperties::SURFACE_UPDATED_BUFFER; + + if (!surface->pending.buffer && PENDING_HAS_NEW_BUFFER && !surface->pending.texture) { removeAllWaiters(); surface->commitPendingState(surface->pending); return; // null buffer attached. } - if (!surface->pending.buffer && !surface->pending.newBuffer && surface->current.buffer) { + if (!surface->pending.buffer && !PENDING_HAS_NEW_BUFFER && surface->current.buffer) { surface->current.bufferDamage.clear(); surface->current.damage.clear(); surface->commitPendingState(surface->current); return; // no new buffer, but we still have current around and a commit happend, commit current again. } - if (!surface->pending.buffer && !surface->pending.newBuffer && !surface->current.buffer) { + if (!surface->pending.buffer && !PENDING_HAS_NEW_BUFFER && !surface->current.buffer) { surface->commitPendingState(surface->pending); // no pending buffer, no current buffer. probably first commit return; } @@ -109,7 +111,8 @@ CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(UP(surface->pending)); surface->pending.damage.clear(); surface->pending.bufferDamage.clear(); - surface->pending.newBuffer = false; + surface->pending.updated &= ~SSurfaceState::eUpdatedProperties::SURFACE_UPDATED_BUFFER; + surface->pending.updated &= ~SSurfaceState::eUpdatedProperties::SURFACE_UPDATED_DAMAGE; surface->pending.buffer.reset(); state->buffer->buffer->syncReleaser = state->buffer->release->createSyncRelease(); diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp index 2dd374a8a..974207a47 100644 --- a/src/protocols/core/Compositor.cpp +++ b/src/protocols/core/Compositor.cpp @@ -71,8 +71,8 @@ CWLSurfaceResource::CWLSurfaceResource(SP resource_) : resource(reso resource->setOnDestroy([this](CWlSurface* r) { destroy(); }); resource->setAttach([this](CWlSurface* r, wl_resource* buffer, int32_t x, int32_t y) { - pending.offset = {x, y}; - pending.newBuffer = true; + pending.offset = {x, y}; + pending.updated |= SSurfaceState::eUpdatedProperties::SURFACE_UPDATED_BUFFER | SSurfaceState::eUpdatedProperties::SURFACE_UPDATED_OFFSET; if (!buffer) { pending.buffer.reset(); @@ -119,11 +119,23 @@ CWLSurfaceResource::CWLSurfaceResource(SP resource_) : resource(reso commitPendingState(pending); }); - resource->setDamage([this](CWlSurface* r, int32_t x, int32_t y, int32_t w, int32_t h) { pending.damage.add(CBox{x, y, w, h}); }); - resource->setDamageBuffer([this](CWlSurface* r, int32_t x, int32_t y, int32_t w, int32_t h) { pending.bufferDamage.add(CBox{x, y, w, h}); }); + resource->setDamage([this](CWlSurface* r, int32_t x, int32_t y, int32_t w, int32_t h) { + pending.updated |= SSurfaceState::eUpdatedProperties::SURFACE_UPDATED_DAMAGE; + pending.damage.add(CBox{x, y, w, h}); + }); + resource->setDamageBuffer([this](CWlSurface* r, int32_t x, int32_t y, int32_t w, int32_t h) { + pending.updated |= SSurfaceState::eUpdatedProperties::SURFACE_UPDATED_DAMAGE; + pending.bufferDamage.add(CBox{x, y, w, h}); + }); - resource->setSetBufferScale([this](CWlSurface* r, int32_t scale) { pending.scale = scale; }); - resource->setSetBufferTransform([this](CWlSurface* r, uint32_t tr) { pending.transform = (wl_output_transform)tr; }); + resource->setSetBufferScale([this](CWlSurface* r, int32_t scale) { + pending.updated |= SSurfaceState::eUpdatedProperties::SURFACE_UPDATED_SCALE; + pending.scale = scale; + }); + resource->setSetBufferTransform([this](CWlSurface* r, uint32_t tr) { + pending.updated |= SSurfaceState::eUpdatedProperties::SURFACE_UPDATED_TRANSFORM; + pending.transform = (wl_output_transform)tr; + }); resource->setSetInputRegion([this](CWlSurface* r, wl_resource* region) { if (!region) { @@ -131,6 +143,8 @@ CWLSurfaceResource::CWLSurfaceResource(SP resource_) : resource(reso return; } + pending.updated |= SSurfaceState::eUpdatedProperties::SURFACE_UPDATED_INPUT; + auto RG = CWLRegionResource::fromResource(region); pending.input = RG->region; }); @@ -141,13 +155,18 @@ CWLSurfaceResource::CWLSurfaceResource(SP resource_) : resource(reso return; } + pending.updated |= SSurfaceState::eUpdatedProperties::SURFACE_UPDATED_OPAQUE; + auto RG = CWLRegionResource::fromResource(region); pending.opaque = RG->region; }); resource->setFrame([this](CWlSurface* r, uint32_t id) { callbacks.emplace_back(makeShared(makeShared(pClient, 1, id))); }); - resource->setOffset([this](CWlSurface* r, int32_t x, int32_t y) { pending.offset = {x, y}; }); + resource->setOffset([this](CWlSurface* r, int32_t x, int32_t y) { + pending.updated |= SSurfaceState::eUpdatedProperties::SURFACE_UPDATED_OFFSET; + pending.offset = {x, y}; + }); } CWLSurfaceResource::~CWLSurfaceResource() { @@ -403,13 +422,8 @@ CBox CWLSurfaceResource::extends() { void CWLSurfaceResource::commitPendingState(SSurfaceState& state) { auto lastTexture = current.texture; - if (state.newBuffer) { - state.newBuffer = false; - current = state; - state.damage.clear(); - state.bufferDamage.clear(); - state.buffer.reset(); - } + current.updateFrom(state); + state.updated = 0; if (current.buffer) { if (current.buffer->buffer->isSynchronous()) diff --git a/src/protocols/types/SurfaceState.cpp b/src/protocols/types/SurfaceState.cpp index 6f9636ff3..bb58b9ae3 100644 --- a/src/protocols/types/SurfaceState.cpp +++ b/src/protocols/types/SurfaceState.cpp @@ -56,3 +56,37 @@ void SSurfaceState::reset() { offset = {}; size = {}; } + +void SSurfaceState::updateFrom(SSurfaceState& ref) { + updated = ref.updated; + + if (ref.updated & SURFACE_UPDATED_BUFFER) { + *this = ref; + ref.damage.clear(); + ref.bufferDamage.clear(); + ref.buffer.reset(); + } else { + if (ref.updated & SURFACE_UPDATED_DAMAGE) { + damage = ref.damage; + bufferDamage = ref.bufferDamage; + } + + if (ref.updated & SURFACE_UPDATED_INPUT) + input = ref.input; + + if (ref.updated & SURFACE_UPDATED_OPAQUE) + opaque = ref.opaque; + + if (ref.updated & SURFACE_UPDATED_OFFSET) + offset = ref.offset; + + if (ref.updated & SURFACE_UPDATED_SCALE) + scale = ref.scale; + + if (ref.updated & SURFACE_UPDATED_VIEWPORT) + viewport = ref.viewport; + + if (ref.updated & SURFACE_UPDATED_TRANSFORM) + transform = ref.transform; + } +} diff --git a/src/protocols/types/SurfaceState.hpp b/src/protocols/types/SurfaceState.hpp index b50937594..4c995bb0a 100644 --- a/src/protocols/types/SurfaceState.hpp +++ b/src/protocols/types/SurfaceState.hpp @@ -7,6 +7,17 @@ class CHLBufferReference; class CTexture; struct SSurfaceState { + enum eUpdatedProperties : uint8_t { + SURFACE_UPDATED_OPAQUE = 1 << 0, + SURFACE_UPDATED_INPUT = 1 << 1, + SURFACE_UPDATED_DAMAGE = 1 << 2, + SURFACE_UPDATED_SCALE = 1 << 3, + SURFACE_UPDATED_BUFFER = 1 << 4, + SURFACE_UPDATED_OFFSET = 1 << 5, + SURFACE_UPDATED_VIEWPORT = 1 << 6, + SURFACE_UPDATED_TRANSFORM = 1 << 7, + }; + CRegion opaque, input = CBox{{}, {INT32_MAX, INT32_MAX}}, damage, bufferDamage = CBox{{}, {INT32_MAX, INT32_MAX}} /* initial damage */; wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL; int scale = 1; @@ -20,12 +31,15 @@ struct SSurfaceState { Vector2D destination; CBox source; } viewport; - bool rejected = false; - bool newBuffer = false; + bool rejected = false; + uint8_t updated = 0; // eUpdatedProperties. Stores what the last update changed Vector2D sourceSize(); // Translates damage into bufferDamage, clearing damage and returning the updated bufferDamage CRegion accumulateBufferDamage(); void updateSynchronousTexture(SP lastTexture); void reset(); + // updates this state from a reference state. Mutates the reference state. If a new buffer is committed, + // reference state gets its damage and buffer cleared. + void updateFrom(SSurfaceState& ref); };