diff options
| author | Vaxry <43317083+vaxerski@users.noreply.github.com> | 2024-07-31 20:47:26 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-07-31 21:47:26 +0200 |
| commit | 37e1411e8d94fe8f3fb678588a7df9b8f931910f (patch) | |
| tree | ce91aa3984b646f8a8569976edb8e78c85919ee5 /src/protocols/core/Compositor.cpp | |
| parent | 548968279926a73d7ff19a9a185c977c50d56756 (diff) | |
core/surface/buffer: Buffer lock/release fixes (#7110)
Diffstat (limited to 'src/protocols/core/Compositor.cpp')
| -rw-r--r-- | src/protocols/core/Compositor.cpp | 124 |
1 files changed, 77 insertions, 47 deletions
diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp index 43d3059b..81be8e46 100644 --- a/src/protocols/core/Compositor.cpp +++ b/src/protocols/core/Compositor.cpp @@ -1,5 +1,6 @@ #include "Compositor.hpp" #include "Output.hpp" +#include "Seat.hpp" #include "../types/WLBuffer.hpp" #include <algorithm> #include <ranges> @@ -9,6 +10,7 @@ #include "../PresentationTime.hpp" #include "../DRMSyncobj.hpp" #include "../../render/Renderer.hpp" +#include <cstring> #define LOGM PROTO::compositor->protoLog @@ -19,8 +21,6 @@ class CDefaultSurfaceRole : public ISurfaceRole { } }; -SP<CDefaultSurfaceRole> defaultRole = makeShared<CDefaultSurfaceRole>(); - CWLCallbackResource::CWLCallbackResource(SP<CWlCallback> resource_) : resource(resource_) { ; } @@ -63,7 +63,7 @@ CWLSurfaceResource::CWLSurfaceResource(SP<CWlSurface> resource_) : resource(reso resource->setData(this); - role = defaultRole; + role = makeShared<CDefaultSurfaceRole>(); resource->setDestroy([this](CWlSurface* r) { destroy(); }); resource->setOnDestroy([this](CWlSurface* r) { destroy(); }); @@ -75,41 +75,42 @@ CWLSurfaceResource::CWLSurfaceResource(SP<CWlSurface> resource_) : resource(reso pending.buffer.reset(); pending.texture.reset(); } else { - auto res = CWLBufferResource::fromResource(buffer); - pending.buffer = res && res->buffer ? res->buffer.lock() : nullptr; - pending.size = res && res->buffer ? res->buffer->size : Vector2D{}; - pending.texture = res && res->buffer ? res->buffer->texture : nullptr; - if (res) - res->released = false; + auto res = CWLBufferResource::fromResource(buffer); + pending.buffer = res && res->buffer ? makeShared<CHLBufferReference>(res->buffer.lock(), self.lock()) : nullptr; + pending.size = res && res->buffer ? res->buffer->size : Vector2D{}; + pending.texture = res && res->buffer ? res->buffer->texture : nullptr; + pending.bufferSize = res && res->buffer ? res->buffer->size : Vector2D{}; } - Vector2D oldBufSize = current.buffer ? current.buffer->size : Vector2D{}; - Vector2D newBufSize = pending.buffer ? pending.buffer->size : Vector2D{}; + Vector2D oldBufSize = current.buffer ? current.bufferSize : Vector2D{}; + Vector2D newBufSize = pending.buffer ? pending.bufferSize : Vector2D{}; if (oldBufSize != newBufSize || current.buffer != pending.buffer) pending.bufferDamage = CBox{{}, {INT32_MAX, INT32_MAX}}; }); resource->setCommit([this](CWlSurface* r) { - if (pending.buffer) - pending.bufferDamage.intersect(CBox{{}, pending.buffer->size}); + if (pending.texture) + pending.bufferDamage.intersect(CBox{{}, pending.bufferSize}); - if (!pending.buffer) + if (!pending.texture) pending.size = {}; else if (pending.viewport.hasDestination) pending.size = pending.viewport.destination; else if (pending.viewport.hasSource) pending.size = pending.viewport.source.size(); else { - Vector2D tfs = pending.transform % 2 == 1 ? Vector2D{pending.buffer->size.y, pending.buffer->size.x} : pending.buffer->size; + Vector2D tfs = pending.transform % 2 == 1 ? Vector2D{pending.bufferSize.y, pending.bufferSize.x} : pending.bufferSize; pending.size = tfs / pending.scale; } pending.damage.intersect(CBox{{}, pending.size}); events.precommit.emit(); - if (pending.rejected) + if (pending.rejected) { + dropPendingBuffer(); return; + } if (stateLocks <= 0) commitPendingState(); @@ -160,6 +161,14 @@ void CWLSurfaceResource::destroy() { PROTO::compositor->destroyResource(this); } +void CWLSurfaceResource::dropPendingBuffer() { + pending.buffer.reset(); +} + +void CWLSurfaceResource::dropCurrentBuffer() { + current.buffer.reset(); +} + SP<CWLSurfaceResource> CWLSurfaceResource::fromResource(wl_resource* res) { auto data = (CWLSurfaceResource*)(((CWlSurface*)wl_resource_get_user_data(res))->data()); return data ? data->self.lock() : nullptr; @@ -240,7 +249,7 @@ void CWLSurfaceResource::frame(timespec* now) { } void CWLSurfaceResource::resetRole() { - role = defaultRole; + role = makeShared<CDefaultSurfaceRole>(); } void CWLSurfaceResource::bfHelper(std::vector<SP<CWLSurfaceResource>> nodes, std::function<void(SP<CWLSurfaceResource>, const Vector2D&, void*)> fn, void* data) { @@ -254,6 +263,8 @@ void CWLSurfaceResource::bfHelper(std::vector<SP<CWLSurfaceResource>> nodes, std for (auto& c : n->subsurfaces) { if (c->zIndex >= 0) break; + if (c->surface.expired()) + continue; nodes2.push_back(c->surface.lock()); } } @@ -277,6 +288,8 @@ void CWLSurfaceResource::bfHelper(std::vector<SP<CWLSurfaceResource>> nodes, std for (auto& c : n->subsurfaces) { if (c->zIndex < 0) continue; + if (c->surface.expired()) + continue; nodes2.push_back(c->surface.lock()); } } @@ -343,14 +356,9 @@ void CWLSurfaceResource::unmap() { } void CWLSurfaceResource::releaseBuffers(bool onlyCurrent) { - if (current.buffer && !current.buffer->resource->released) - current.buffer->sendRelease(); - if (pending.buffer && !pending.buffer->resource->released && !onlyCurrent) - pending.buffer->sendRelease(); - - pending.buffer.reset(); if (!onlyCurrent) - current.buffer.reset(); + dropPendingBuffer(); + dropCurrentBuffer(); } void CWLSurfaceResource::error(int code, const std::string& str) { @@ -375,18 +383,18 @@ CBox CWLSurfaceResource::extends() { } Vector2D CWLSurfaceResource::sourceSize() { - if (!current.buffer) + if (!current.texture) return {}; if (current.viewport.hasSource) return current.viewport.source.size(); - Vector2D trc = current.transform % 2 == 1 ? Vector2D{current.buffer->size.y, current.buffer->size.x} : current.buffer->size; + Vector2D trc = current.transform % 2 == 1 ? Vector2D{current.bufferSize.y, current.bufferSize.x} : current.bufferSize; return trc / current.scale; } CRegion CWLSurfaceResource::accumulateCurrentBufferDamage() { - if (!current.buffer) + if (!current.texture) return {}; CRegion surfaceDamage = current.damage; @@ -398,7 +406,7 @@ CRegion CWLSurfaceResource::accumulateCurrentBufferDamage() { if (current.viewport.hasSource) surfaceDamage.translate(current.viewport.source.pos()); - Vector2D trc = current.transform % 2 == 1 ? Vector2D{current.buffer->size.y, current.buffer->size.x} : current.buffer->size; + 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); } @@ -421,16 +429,21 @@ void CWLSurfaceResource::commitPendingState() { pending.damage.clear(); pending.bufferDamage.clear(); - if (current.buffer && current.buffer->texture) - current.buffer->texture->m_eTransform = wlTransformToHyprutils(current.transform); + if (current.texture) + current.texture->m_eTransform = wlTransformToHyprutils(current.transform); + + if (current.buffer && current.buffer->buffer) { + current.buffer->buffer->update(accumulateCurrentBufferDamage()); - if (current.buffer && !current.buffer->resource->released) { - current.buffer->update(accumulateCurrentBufferDamage()); + // if the surface is a cursor, update the shm buffer + // TODO: don't update the entire texture + if (role->role() == SURFACE_ROLE_CURSOR) + updateCursorShm(); // release the buffer if it's synchronous as update() has done everything thats needed // so we can let the app know we're done. - if (current.buffer->isSynchronous()) - current.buffer->sendReleaseWithSurface(self.lock()); + if (current.buffer->buffer->isSynchronous()) + dropCurrentBuffer(); } // TODO: we should _accumulate_ and not replace above if sync @@ -455,20 +468,37 @@ void CWLSurfaceResource::commitPendingState() { } // for async buffers, we can only release the buffer once we are unrefing it from current. - if (previousBuffer && !previousBuffer->isSynchronous() && !previousBuffer->resource->released) { - if (previousBuffer->lockedByBackend) { - previousBuffer->hlEvents.backendRelease = previousBuffer->events.backendRelease.registerListener([this, previousBuffer](std::any data) { - if (!self.expired()) // could be dead in the dtor - previousBuffer->sendReleaseWithSurface(self.lock()); - else - previousBuffer->sendRelease(); - previousBuffer->hlEvents.backendRelease.reset(); - }); - } else - previousBuffer->sendReleaseWithSurface(self.lock()); - - previousBuffer->resource->released = true; // set it here regardless so we dont set more listeners for backendRelease + // if the backend took it, ref it with the lambda. Otherwise, the end of this scope will release it. + if (previousBuffer && previousBuffer->buffer && !previousBuffer->buffer->isSynchronous()) { + if (previousBuffer->buffer->lockedByBackend && !previousBuffer->buffer->hlEvents.backendRelease) { + previousBuffer->buffer->lock(); + previousBuffer->buffer->unlockOnBufferRelease(self); + } + } + + lastBuffer = current.buffer ? current.buffer->buffer : WP<IHLBuffer>{}; +} + +void CWLSurfaceResource::updateCursorShm() { + auto buf = current.buffer ? current.buffer : lastBuffer; + + if (!buf) + return; + + // TODO: actually use damage + auto& shmData = CCursorSurfaceRole::cursorPixelData(self.lock()); + auto shmAttrs = current.buffer->buffer->shm(); + + if (!shmAttrs.success) { + LOGM(TRACE, "updateCursorShm: ignoring, not a shm buffer"); + return; } + + // no need to end, shm. + auto [pixelData, fmt, bufLen] = current.buffer->buffer->beginDataPtr(0); + + shmData.resize(bufLen); + memcpy(shmData.data(), pixelData, bufLen); } void CWLSurfaceResource::presentFeedback(timespec* when, CMonitor* pMonitor, bool needsExplicitSync) { |
