summaryrefslogtreecommitdiff
path: root/src/protocols
diff options
context:
space:
mode:
authorVaxry <43317083+vaxerski@users.noreply.github.com>2024-07-31 20:47:26 +0100
committerGitHub <noreply@github.com>2024-07-31 21:47:26 +0200
commit37e1411e8d94fe8f3fb678588a7df9b8f931910f (patch)
treece91aa3984b646f8a8569976edb8e78c85919ee5 /src/protocols
parent548968279926a73d7ff19a9a185c977c50d56756 (diff)
core/surface/buffer: Buffer lock/release fixes (#7110)
Diffstat (limited to 'src/protocols')
-rw-r--r--src/protocols/DRMSyncobj.cpp2
-rw-r--r--src/protocols/InputMethodV2.cpp4
-rw-r--r--src/protocols/LayerShell.cpp2
-rw-r--r--src/protocols/SessionLock.cpp2
-rw-r--r--src/protocols/Viewporter.cpp4
-rw-r--r--src/protocols/XDGShell.cpp6
-rw-r--r--src/protocols/core/Compositor.cpp124
-rw-r--r--src/protocols/core/Compositor.hpp35
-rw-r--r--src/protocols/core/DataDevice.cpp8
-rw-r--r--src/protocols/core/Seat.cpp21
-rw-r--r--src/protocols/core/Seat.hpp15
-rw-r--r--src/protocols/core/Subcompositor.cpp4
-rw-r--r--src/protocols/types/Buffer.cpp56
-rw-r--r--src/protocols/types/Buffer.hpp28
-rw-r--r--src/protocols/types/SurfaceRole.hpp1
-rw-r--r--src/protocols/types/WLBuffer.cpp1
-rw-r--r--src/protocols/types/WLBuffer.hpp2
17 files changed, 232 insertions, 83 deletions
diff --git a/src/protocols/DRMSyncobj.cpp b/src/protocols/DRMSyncobj.cpp
index 41178109..33339554 100644
--- a/src/protocols/DRMSyncobj.cpp
+++ b/src/protocols/DRMSyncobj.cpp
@@ -47,7 +47,7 @@ CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(SP<CWpLinuxDrmSyncobjSurf
return;
}
- if ((acquireTimeline || releaseTimeline) && !surface->pending.buffer) {
+ if ((acquireTimeline || releaseTimeline) && !surface->pending.texture) {
resource->error(WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_BUFFER, "Missing buffer");
surface->pending.rejected = true;
return;
diff --git a/src/protocols/InputMethodV2.cpp b/src/protocols/InputMethodV2.cpp
index def4d837..fd306f09 100644
--- a/src/protocols/InputMethodV2.cpp
+++ b/src/protocols/InputMethodV2.cpp
@@ -107,14 +107,14 @@ CInputMethodPopupV2::CInputMethodPopupV2(SP<CZwpInputPopupSurfaceV2> resource_,
});
listeners.commitSurface = surface->events.commit.registerListener([this](std::any d) {
- if (pSurface->current.buffer && !mapped) {
+ if (pSurface->current.texture && !mapped) {
mapped = true;
pSurface->map();
events.map.emit();
return;
}
- if (!pSurface->current.buffer && mapped) {
+ if (!pSurface->current.texture && mapped) {
mapped = false;
pSurface->unmap();
events.unmap.emit();
diff --git a/src/protocols/LayerShell.cpp b/src/protocols/LayerShell.cpp
index 5018828e..0ed1b219 100644
--- a/src/protocols/LayerShell.cpp
+++ b/src/protocols/LayerShell.cpp
@@ -44,7 +44,7 @@ CLayerShellResource::CLayerShellResource(SP<CZwlrLayerSurfaceV1> resource_, SP<C
current = pending;
pending.committed = 0;
- bool attachedBuffer = surface->current.buffer;
+ bool attachedBuffer = surface->current.texture;
if (attachedBuffer && !configured) {
surface->error(-1, "layerSurface was not configured, but a buffer was attached");
diff --git a/src/protocols/SessionLock.cpp b/src/protocols/SessionLock.cpp
index 42df5fd6..df97413c 100644
--- a/src/protocols/SessionLock.cpp
+++ b/src/protocols/SessionLock.cpp
@@ -24,7 +24,7 @@ CSessionLockSurface::CSessionLockSurface(SP<CExtSessionLockSurfaceV1> resource_,
resource->setAckConfigure([this](CExtSessionLockSurfaceV1* r, uint32_t serial) { ackdConfigure = true; });
listeners.surfaceCommit = pSurface->events.commit.registerListener([this](std::any d) {
- if (!pSurface->current.buffer) {
+ if (!pSurface->current.texture) {
LOGM(ERR, "SessionLock attached a null buffer");
resource->error(EXT_SESSION_LOCK_SURFACE_V1_ERROR_NULL_BUFFER, "Null buffer attached");
return;
diff --git a/src/protocols/Viewporter.cpp b/src/protocols/Viewporter.cpp
index 03c5775e..78f3039f 100644
--- a/src/protocols/Viewporter.cpp
+++ b/src/protocols/Viewporter.cpp
@@ -54,13 +54,13 @@ CViewportResource::CViewportResource(SP<CWpViewport> resource_, SP<CWLSurfaceRes
});
listeners.surfacePrecommit = surface->events.precommit.registerListener([this](std::any d) {
- if (!surface || !surface->pending.buffer)
+ if (!surface || !surface->pending.texture)
return;
if (surface->pending.viewport.hasSource) {
auto& src = surface->pending.viewport.source;
- if (src.w + src.x > surface->pending.buffer->size.x || src.h + src.y > surface->pending.buffer->size.y) {
+ if (src.w + src.x > surface->pending.bufferSize.x || src.h + src.y > surface->pending.bufferSize.y) {
resource->error(WP_VIEWPORT_ERROR_BAD_VALUE, "Box doesn't fit");
surface->pending.rejected = true;
return;
diff --git a/src/protocols/XDGShell.cpp b/src/protocols/XDGShell.cpp
index cb8a5bc3..71873374 100644
--- a/src/protocols/XDGShell.cpp
+++ b/src/protocols/XDGShell.cpp
@@ -347,12 +347,12 @@ CXDGSurfaceResource::CXDGSurfaceResource(SP<CXdgSurface> resource_, SP<CXDGWMBas
if (toplevel)
toplevel->current = toplevel->pending;
- if (initialCommit && surface->pending.buffer) {
+ if (initialCommit && surface->pending.texture) {
resource->error(-1, "Buffer attached before initial commit");
return;
}
- if (surface->current.buffer && !mapped) {
+ if (surface->current.texture && !mapped) {
// this forces apps to not draw CSD.
if (toplevel)
toplevel->setMaximized(true);
@@ -363,7 +363,7 @@ CXDGSurfaceResource::CXDGSurfaceResource(SP<CXdgSurface> resource_, SP<CXDGWMBas
return;
}
- if (!surface->current.buffer && mapped) {
+ if (!surface->current.texture && mapped) {
mapped = false;
events.unmap.emit();
surface->unmap();
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) {
diff --git a/src/protocols/core/Compositor.hpp b/src/protocols/core/Compositor.hpp
index 79cd1de6..460ec755 100644
--- a/src/protocols/core/Compositor.hpp
+++ b/src/protocols/core/Compositor.hpp
@@ -84,13 +84,13 @@ class CWLSurfaceResource {
} events;
struct SState {
- 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;
- SP<IHLBuffer> buffer;
- SP<CTexture> texture;
- Vector2D offset;
- Vector2D size;
+ 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;
+ SP<CHLBufferReference> buffer; // buffer ref will be released once the buffer is no longer locked. For checking if a buffer is attached to this state, check texture.
+ SP<CTexture> texture;
+ Vector2D offset;
+ Vector2D size, bufferSize;
struct {
bool hasDestination = false;
bool hasSource = false;
@@ -116,7 +116,7 @@ class CWLSurfaceResource {
std::vector<WP<CMonitor>> enteredOutputs;
bool mapped = false;
std::vector<WP<CWLSubsurfaceResource>> subsurfaces;
- WP<ISurfaceRole> role;
+ SP<ISurfaceRole> role;
WP<CViewportResource> viewportResource;
WP<CDRMSyncobjSurfaceResource> syncobj; // may not be present
@@ -134,12 +134,21 @@ class CWLSurfaceResource {
SP<CWlSurface> resource;
wl_client* pClient = nullptr;
- int stateLocks = 0;
+ // this is for cursor dumb copy. Due to our (and wayland's...) architecture,
+ // this stupid-ass hack is used
+ WP<IHLBuffer> lastBuffer;
- void destroy();
- void releaseBuffers(bool onlyCurrent = true);
- void commitPendingState();
- void bfHelper(std::vector<SP<CWLSurfaceResource>> nodes, std::function<void(SP<CWLSurfaceResource>, const Vector2D&, void*)> fn, void* data);
+ int stateLocks = 0;
+
+ void destroy();
+ void releaseBuffers(bool onlyCurrent = true);
+ void dropPendingBuffer();
+ void dropCurrentBuffer();
+ void commitPendingState();
+ void bfHelper(std::vector<SP<CWLSurfaceResource>> nodes, std::function<void(SP<CWLSurfaceResource>, const Vector2D&, void*)> fn, void* data);
+ void updateCursorShm();
+
+ friend class CWLPointerResource;
};
class CWLCompositorResource {
diff --git a/src/protocols/core/DataDevice.cpp b/src/protocols/core/DataDevice.cpp
index 9634d569..fe3905d0 100644
--- a/src/protocols/core/DataDevice.cpp
+++ b/src/protocols/core/DataDevice.cpp
@@ -469,12 +469,12 @@ void CWLDataDeviceProtocol::initiateDrag(WP<CWLDataSourceResource> currentSource
if (dragSurface) {
dnd.dndSurfaceDestroy = dragSurface->events.destroy.registerListener([this](std::any d) { abortDrag(); });
dnd.dndSurfaceCommit = dragSurface->events.commit.registerListener([this](std::any d) {
- if (dnd.dndSurface->current.buffer && !dnd.dndSurface->mapped) {
+ if (dnd.dndSurface->current.texture && !dnd.dndSurface->mapped) {
dnd.dndSurface->map();
return;
}
- if (dnd.dndSurface->current.buffer <= 0 && dnd.dndSurface->mapped) {
+ if (dnd.dndSurface->current.texture <= 0 && dnd.dndSurface->mapped) {
dnd.dndSurface->unmap();
return;
}
@@ -660,13 +660,13 @@ void CWLDataDeviceProtocol::abortDrag() {
}
void CWLDataDeviceProtocol::renderDND(CMonitor* pMonitor, timespec* when) {
- if (!dnd.dndSurface || !dnd.dndSurface->current.buffer || !dnd.dndSurface->current.buffer->texture)
+ if (!dnd.dndSurface || !dnd.dndSurface->current.texture)
return;
const auto POS = g_pInputManager->getMouseCoordsInternal();
CBox box = CBox{POS, dnd.dndSurface->current.size}.translate(-pMonitor->vecPosition + g_pPointerManager->cursorSizeLogical() / 2.F).scale(pMonitor->scale);
- g_pHyprOpenGL->renderTexture(dnd.dndSurface->current.buffer->texture, &box, 1.F);
+ g_pHyprOpenGL->renderTexture(dnd.dndSurface->current.texture, &box, 1.F);
box = CBox{POS, dnd.dndSurface->current.size}.translate(g_pPointerManager->cursorSizeLogical() / 2.F);
g_pHyprRenderer->damageBox(&box);
diff --git a/src/protocols/core/Seat.cpp b/src/protocols/core/Seat.cpp
index 7a295372..bb6a9d4d 100644
--- a/src/protocols/core/Seat.cpp
+++ b/src/protocols/core/Seat.cpp
@@ -119,7 +119,19 @@ CWLPointerResource::CWLPointerResource(SP<CWlPointer> resource_, SP<CWLSeatResou
return;
}
- g_pSeatManager->onSetCursor(owner.lock(), serial, surf ? CWLSurfaceResource::fromResource(surf) : nullptr, {hotX, hotY});
+ auto surfResource = surf ? CWLSurfaceResource::fromResource(surf) : nullptr;
+
+ if (surfResource && surfResource->role->role() != SURFACE_ROLE_CURSOR && surfResource->role->role() != SURFACE_ROLE_UNASSIGNED) {
+ r->error(-1, "Cursor surface already has a different role");
+ return;
+ }
+
+ if (surfResource) {
+ surfResource->role = makeShared<CCursorSurfaceRole>();
+ surfResource->updateCursorShm();
+ }
+
+ g_pSeatManager->onSetCursor(owner.lock(), serial, surfResource, {hotX, hotY});
});
if (g_pSeatManager->state.pointerFocus && g_pSeatManager->state.pointerFocus->client() == resource->client())
@@ -546,3 +558,10 @@ SP<CWLSeatResource> CWLSeatProtocol::seatResourceForClient(wl_client* client) {
return nullptr;
}
+
+std::vector<uint8_t>& CCursorSurfaceRole::cursorPixelData(SP<CWLSurfaceResource> surface) {
+ RASSERT(surface->role->role() == SURFACE_ROLE_CURSOR, "cursorPixelData called on a non-cursor surface");
+
+ auto role = (CCursorSurfaceRole*)surface->role.get();
+ return role->cursorShmPixelData;
+}
diff --git a/src/protocols/core/Seat.hpp b/src/protocols/core/Seat.hpp
index 09b36056..755a9c2f 100644
--- a/src/protocols/core/Seat.hpp
+++ b/src/protocols/core/Seat.hpp
@@ -16,6 +16,7 @@
#include "wayland.hpp"
#include "../../helpers/signal/Signal.hpp"
#include "../../helpers/math/Math.hpp"
+#include "../types/SurfaceRole.hpp"
constexpr const char* HL_SEAT_NAME = "Hyprland";
@@ -27,6 +28,20 @@ class CWLKeyboardResource;
class CWLTouchResource;
class CWLSeatResource;
+class CCursorSurfaceRole : public ISurfaceRole {
+ public:
+ virtual eSurfaceRole role() {
+ return SURFACE_ROLE_CURSOR;
+ }
+
+ // gets the current pixel data from a shm surface
+ // will assert if the surface is not a cursor
+ static std::vector<uint8_t>& cursorPixelData(SP<CWLSurfaceResource> surface);
+
+ private:
+ std::vector<uint8_t> cursorShmPixelData;
+};
+
class CWLTouchResource {
public:
CWLTouchResource(SP<CWlTouch> resource_, SP<CWLSeatResource> owner_);
diff --git a/src/protocols/core/Subcompositor.cpp b/src/protocols/core/Subcompositor.cpp
index c0c1f258..90f89d91 100644
--- a/src/protocols/core/Subcompositor.cpp
+++ b/src/protocols/core/Subcompositor.cpp
@@ -80,13 +80,13 @@ CWLSubsurfaceResource::CWLSubsurfaceResource(SP<CWlSubsurface> resource_, SP<CWL
});
listeners.commitSurface = surface->events.commit.registerListener([this](std::any d) {
- if (surface->current.buffer && !surface->mapped) {
+ if (surface->current.texture && !surface->mapped) {
surface->map();
surface->events.map.emit();
return;
}
- if (!surface->current.buffer && surface->mapped) {
+ if (!surface->current.texture && surface->mapped) {
surface->events.unmap.emit();
surface->unmap();
return;
diff --git a/src/protocols/types/Buffer.cpp b/src/protocols/types/Buffer.cpp
index 0217f7e2..40f2eaf8 100644
--- a/src/protocols/types/Buffer.cpp
+++ b/src/protocols/types/Buffer.cpp
@@ -1,5 +1,10 @@
#include "Buffer.hpp"
+IHLBuffer::~IHLBuffer() {
+ if (locked() && resource)
+ sendRelease();
+}
+
void IHLBuffer::sendRelease() {
resource->sendRelease();
}
@@ -8,3 +13,54 @@ void IHLBuffer::sendReleaseWithSurface(SP<CWLSurfaceResource> surf) {
if (resource && resource->good())
resource->sendReleaseWithSurface(surf);
}
+
+void IHLBuffer::lock() {
+ nLocks++;
+}
+
+void IHLBuffer::unlock() {
+ nLocks--;
+
+ ASSERT(nLocks >= 0);
+
+ if (nLocks == 0)
+ sendRelease();
+}
+
+void IHLBuffer::unlockWithSurface(SP<CWLSurfaceResource> surf) {
+ nLocks--;
+
+ ASSERT(nLocks >= 0);
+
+ if (nLocks == 0)
+ sendReleaseWithSurface(surf);
+}
+
+bool IHLBuffer::locked() {
+ return nLocks > 0;
+}
+
+void IHLBuffer::unlockOnBufferRelease(WP<CWLSurfaceResource> surf) {
+ unlockSurface = surf;
+ hlEvents.backendRelease = events.backendRelease.registerListener([this](std::any data) {
+ if (unlockSurface.expired())
+ unlock();
+ else
+ unlockWithSurface(unlockSurface.lock());
+ hlEvents.backendRelease.reset();
+ });
+}
+
+CHLBufferReference::CHLBufferReference(SP<IHLBuffer> buffer_, SP<CWLSurfaceResource> surface_) : buffer(buffer_), surface(surface_) {
+ buffer->lock();
+}
+
+CHLBufferReference::~CHLBufferReference() {
+ if (buffer.expired())
+ return;
+
+ if (surface)
+ buffer->unlockWithSurface(surface.lock());
+ else
+ buffer->unlock();
+}
diff --git a/src/protocols/types/Buffer.hpp b/src/protocols/types/Buffer.hpp
index ba8278f3..d2157181 100644
--- a/src/protocols/types/Buffer.hpp
+++ b/src/protocols/types/Buffer.hpp
@@ -8,9 +8,7 @@
class IHLBuffer : public Aquamarine::IBuffer {
public:
- virtual ~IHLBuffer() {
- ;
- }
+ virtual ~IHLBuffer();
virtual Aquamarine::eBufferCapability caps() = 0;
virtual Aquamarine::eBufferType type() = 0;
virtual void update(const CRegion& damage) = 0;
@@ -18,6 +16,12 @@ class IHLBuffer : public Aquamarine::IBuffer {
virtual bool good() = 0;
virtual void sendRelease();
virtual void sendReleaseWithSurface(SP<CWLSurfaceResource>);
+ virtual void lock();
+ virtual void unlock();
+ virtual void unlockWithSurface(SP<CWLSurfaceResource> surf);
+ virtual bool locked();
+
+ void unlockOnBufferRelease(WP<CWLSurfaceResource> surf /* optional */);
SP<CTexture> texture;
bool opaque = false;
@@ -26,4 +30,22 @@ class IHLBuffer : public Aquamarine::IBuffer {
struct {
CHyprSignalListener backendRelease;
} hlEvents;
+
+ private:
+ int nLocks = 0;
+
+ WP<CWLSurfaceResource> unlockSurface;
+};
+
+// for ref-counting. Releases in ~dtor
+// surface optional
+class CHLBufferReference {
+ public:
+ CHLBufferReference(SP<IHLBuffer> buffer, SP<CWLSurfaceResource> surface);
+ ~CHLBufferReference();
+
+ WP<IHLBuffer> buffer;
+
+ private:
+ WP<CWLSurfaceResource> surface;
};
diff --git a/src/protocols/types/SurfaceRole.hpp b/src/protocols/types/SurfaceRole.hpp
index faaf70ee..64586f01 100644
--- a/src/protocols/types/SurfaceRole.hpp
+++ b/src/protocols/types/SurfaceRole.hpp
@@ -6,6 +6,7 @@ enum eSurfaceRole {
SURFACE_ROLE_LAYER_SHELL,
SURFACE_ROLE_EASTER_EGG,
SURFACE_ROLE_SUBSURFACE,
+ SURFACE_ROLE_CURSOR,
};
class ISurfaceRole {
diff --git a/src/protocols/types/WLBuffer.cpp b/src/protocols/types/WLBuffer.cpp
index e42094b1..d34a867d 100644
--- a/src/protocols/types/WLBuffer.cpp
+++ b/src/protocols/types/WLBuffer.cpp
@@ -29,7 +29,6 @@ bool CWLBufferResource::good() {
}
void CWLBufferResource::sendRelease() {
- released = true;
resource->sendRelease();
}
diff --git a/src/protocols/types/WLBuffer.hpp b/src/protocols/types/WLBuffer.hpp
index f4424abc..59512128 100644
--- a/src/protocols/types/WLBuffer.hpp
+++ b/src/protocols/types/WLBuffer.hpp
@@ -24,8 +24,6 @@ class CWLBufferResource {
WP<CWLBufferResource> self;
- bool released = false;
-
private:
CWLBufferResource(SP<CWlBuffer> resource_);