Add debian/patches/sync.patch

This commit is contained in:
ferreo 2025-02-20 18:18:26 +01:00
parent ec43241cf1
commit e565035151

438
debian/patches/sync.patch vendored Normal file
View File

@ -0,0 +1,438 @@
From 7d74ba21c822ca1761a6d3f14555ea3a7e8aba9d Mon Sep 17 00:00:00 2001
From: Tom Englund <tomenglund26@gmail.com>
Date: Tue, 18 Feb 2025 15:29:53 +0100
Subject: [PATCH] syncobj: use eventfd instead of stalling fd checks
use eventfd and add it to the event loop and when it recieves a signal
release the buffer, this means we dont stall entire compositor when
waiting for materilisation of the fd. and change its related usage, this
also means we need to store release points that can popup in a container
and signal them all on buffer release.
im not sure why directscanout previously manually tried to signal
releasepoints. remove that and let the buffers releaser handle it.
---
src/helpers/Monitor.cpp | 16 +-----
src/helpers/sync/SyncReleaser.cpp | 4 --
src/helpers/sync/SyncReleaser.hpp | 3 -
src/helpers/sync/SyncTimeline.cpp | 17 ++++++
src/helpers/sync/SyncTimeline.hpp | 1 +
src/protocols/DRMSyncobj.cpp | 78 +++++++++++++-------------
src/protocols/DRMSyncobj.hpp | 16 ++++--
src/protocols/core/Compositor.cpp | 17 +++---
src/protocols/core/Compositor.hpp | 4 +-
src/protocols/types/Buffer.hpp | 4 +-
src/render/Renderer.cpp | 5 +-
src/render/pass/SurfacePassElement.cpp | 4 +-
12 files changed, 87 insertions(+), 82 deletions(-)
diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp
index 24db3ea4b2d..6aa75ce9f95 100644
--- a/src/helpers/Monitor.cpp
+++ b/src/helpers/Monitor.cpp
@@ -1315,10 +1315,10 @@ bool CMonitor::attemptDirectScanout() {
auto explicitOptions = g_pHyprRenderer->getExplicitSyncSettings(output);
// wait for the explicit fence if present, and if kms explicit is allowed
- bool DOEXPLICIT = PSURFACE->syncobj && PSURFACE->syncobj->current.acquireTimeline && PSURFACE->syncobj->current.acquireTimeline->timeline && explicitOptions.explicitKMSEnabled;
+ bool DOEXPLICIT = PSURFACE->syncobj && PSURFACE->syncobj->acquire.resource && PSURFACE->syncobj->acquire.resource->timeline && explicitOptions.explicitKMSEnabled;
CFileDescriptor explicitWaitFD;
if (DOEXPLICIT) {
- explicitWaitFD = PSURFACE->syncobj->current.acquireTimeline->timeline->exportAsSyncFileFD(PSURFACE->syncobj->current.acquirePoint);
+ explicitWaitFD = PSURFACE->syncobj->acquire.resource->timeline->exportAsSyncFileFD(PSURFACE->syncobj->acquire.point);
if (!explicitWaitFD.isValid())
Debug::log(TRACE, "attemptDirectScanout: failed to acquire an explicit wait fd");
}
@@ -1352,18 +1352,6 @@ bool CMonitor::attemptDirectScanout() {
lastScanout = PCANDIDATE;
Debug::log(LOG, "Entered a direct scanout to {:x}: \"{}\"", (uintptr_t)PCANDIDATE.get(), PCANDIDATE->m_szTitle);
}
-
- // delay explicit sync feedback until kms release of the buffer
- if (DOEXPLICIT) {
- Debug::log(TRACE, "attemptDirectScanout: Delaying explicit sync release feedback until kms release");
- PSURFACE->current.buffer->releaser->drop();
-
- PSURFACE->current.buffer->buffer->hlEvents.backendRelease2 = PSURFACE->current.buffer->buffer->events.backendRelease.registerListener([PSURFACE](std::any d) {
- const bool DOEXPLICIT = PSURFACE->syncobj && PSURFACE->syncobj->current.releaseTimeline && PSURFACE->syncobj->current.releaseTimeline->timeline;
- if (DOEXPLICIT)
- PSURFACE->syncobj->current.releaseTimeline->timeline->signal(PSURFACE->syncobj->current.releasePoint);
- });
- }
} else {
Debug::log(TRACE, "attemptDirectScanout: failed to scanout surface");
lastScanout.reset();
diff --git a/src/helpers/sync/SyncReleaser.cpp b/src/helpers/sync/SyncReleaser.cpp
index 198495ab6da..9fc6422b3cb 100644
--- a/src/helpers/sync/SyncReleaser.cpp
+++ b/src/helpers/sync/SyncReleaser.cpp
@@ -19,7 +19,3 @@ CSyncReleaser::~CSyncReleaser() {
void CSyncReleaser::addReleaseSync(SP<CEGLSync> sync_) {
sync = sync_;
}
-
-void CSyncReleaser::drop() {
- timeline.reset();
-}
\ No newline at end of file
diff --git a/src/helpers/sync/SyncReleaser.hpp b/src/helpers/sync/SyncReleaser.hpp
index e21d2e34bd2..ca571c1631c 100644
--- a/src/helpers/sync/SyncReleaser.hpp
+++ b/src/helpers/sync/SyncReleaser.hpp
@@ -18,9 +18,6 @@ class CSyncReleaser {
CSyncReleaser(WP<CSyncTimeline> timeline_, uint64_t point_);
~CSyncReleaser();
- // drops the releaser, will never signal anymore
- void drop();
-
// wait for this gpu job to finish before releasing
void addReleaseSync(SP<CEGLSync> sync);
diff --git a/src/helpers/sync/SyncTimeline.cpp b/src/helpers/sync/SyncTimeline.cpp
index 46b617bc6d6..c2e8b001b6e 100644
--- a/src/helpers/sync/SyncTimeline.cpp
+++ b/src/helpers/sync/SyncTimeline.cpp
@@ -33,6 +33,12 @@ SP<CSyncTimeline> CSyncTimeline::create(int drmFD_, int drmSyncobjFD) {
}
CSyncTimeline::~CSyncTimeline() {
+ for (auto& w : waiters) {
+ if (w->source) {
+ wl_event_source_remove(w->source);
+ w->source = nullptr;
+ }
+ }
if (handle == 0)
return;
@@ -124,6 +130,17 @@ void CSyncTimeline::removeWaiter(SWaiter* w) {
std::erase_if(waiters, [w](const auto& e) { return e.get() == w; });
}
+void CSyncTimeline::removeAllWaiters() {
+ for (auto& w : waiters) {
+ if (w->source) {
+ wl_event_source_remove(w->source);
+ w->source = nullptr;
+ }
+ }
+
+ waiters.clear();
+}
+
CFileDescriptor CSyncTimeline::exportAsSyncFileFD(uint64_t src) {
int sync = -1;
diff --git a/src/helpers/sync/SyncTimeline.hpp b/src/helpers/sync/SyncTimeline.hpp
index ba65e004d0b..bfd70416106 100644
--- a/src/helpers/sync/SyncTimeline.hpp
+++ b/src/helpers/sync/SyncTimeline.hpp
@@ -34,6 +34,7 @@ class CSyncTimeline {
bool addWaiter(const std::function<void()>& waiter, uint64_t point, uint32_t flags);
void removeWaiter(SWaiter*);
+ void removeAllWaiters();
Hyprutils::OS::CFileDescriptor exportAsSyncFileFD(uint64_t src);
bool importFromSyncFileFD(uint64_t dst, Hyprutils::OS::CFileDescriptor& fd);
bool transfer(SP<CSyncTimeline> from, uint64_t fromPoint, uint64_t toPoint);
diff --git a/src/protocols/DRMSyncobj.cpp b/src/protocols/DRMSyncobj.cpp
index 38aab305af3..425794814c9 100644
--- a/src/protocols/DRMSyncobj.cpp
+++ b/src/protocols/DRMSyncobj.cpp
@@ -8,6 +8,11 @@
#include <fcntl.h>
using namespace Hyprutils::OS;
+CDRMSyncobjSurfaceResource::TimeLineState::~TimeLineState() {
+ if (resource)
+ resource->timeline->removeAllWaiters();
+}
+
CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(SP<CWpLinuxDrmSyncobjSurfaceV1> resource_, SP<CWLSurfaceResource> surface_) : surface(surface_), resource(resource_) {
if UNLIKELY (!good())
return;
@@ -23,9 +28,9 @@ CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(SP<CWpLinuxDrmSyncobjSurf
return;
}
- auto timeline = CDRMSyncobjTimelineResource::fromResource(timeline_);
- pending.acquireTimeline = timeline;
- pending.acquirePoint = ((uint64_t)hi << 32) | (uint64_t)lo;
+ auto timeline = CDRMSyncobjTimelineResource::fromResource(timeline_);
+ acquire.resource = timeline;
+ acquire.point = ((uint64_t)hi << 32) | (uint64_t)lo;
});
resource->setSetReleasePoint([this](CWpLinuxDrmSyncobjSurfaceV1* r, wl_resource* timeline_, uint32_t hi, uint32_t lo) {
@@ -34,13 +39,14 @@ CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(SP<CWpLinuxDrmSyncobjSurf
return;
}
- auto timeline = CDRMSyncobjTimelineResource::fromResource(timeline_);
- pending.releaseTimeline = timeline;
- pending.releasePoint = ((uint64_t)hi << 32) | (uint64_t)lo;
+ auto timeline = CDRMSyncobjTimelineResource::fromResource(timeline_);
+ release.resource = timeline;
+ release.point = ((uint64_t)hi << 32) | (uint64_t)lo;
+ releasePoints.emplace_back(makeUnique<CSyncReleaser>(release.resource->timeline, release.point));
});
listeners.surfacePrecommit = surface->events.precommit.registerListener([this](std::any d) {
- if ((pending.acquireTimeline || pending.releaseTimeline) && !surface->pending.texture) {
+ if ((acquire.resource || release.resource) && !surface->pending.texture) {
resource->error(WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_BUFFER, "Missing buffer");
surface->pending.rejected = true;
return;
@@ -49,57 +55,49 @@ CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(SP<CWpLinuxDrmSyncobjSurf
if (!surface->pending.newBuffer)
return; // this commit does not change the state here
- if (!!pending.acquireTimeline != !!pending.releaseTimeline) {
- resource->error(pending.acquireTimeline ? WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_RELEASE_POINT : WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_ACQUIRE_POINT,
- "Missing timeline");
+ if (!!acquire.resource != !!release.resource) {
+ resource->error(acquire.resource ? WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_RELEASE_POINT : WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_ACQUIRE_POINT, "Missing timeline");
surface->pending.rejected = true;
return;
}
- if (!pending.acquireTimeline)
- return;
-
- if (pending.acquireTimeline && pending.releaseTimeline && pending.acquireTimeline == pending.releaseTimeline) {
- if (pending.acquirePoint >= pending.releasePoint) {
+ if (acquire.resource && release.resource && acquire.resource == release.resource) {
+ if (acquire.point >= release.point) {
resource->error(WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_CONFLICTING_POINTS, "Acquire and release points are on the same timeline, and acquire >= release");
surface->pending.rejected = true;
return;
}
}
- // wait for the acquire timeline to materialize
- auto materialized = pending.acquireTimeline->timeline->check(pending.acquirePoint, DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE);
- if (!materialized.has_value()) {
- LOGM(ERR, "Failed to check the acquire timeline");
- resource->noMemory();
+ if (!acquire.resource)
return;
- }
- if (materialized.value())
- return;
-
- surface->lockPendingState();
- pending.acquireTimeline->timeline->addWaiter([this]() { surface->unlockPendingState(); }, pending.acquirePoint, DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE);
- });
-
- listeners.surfaceCommit = surface->events.roleCommit.registerListener([this](std::any d) {
- // apply timelines if new ones have been attached, otherwise don't touch
- // the current ones
- if (pending.releaseTimeline) {
- current.releaseTimeline = pending.releaseTimeline;
- current.releasePoint = pending.releasePoint;
+ if (acquireWaiting) {
+ acquire.resource->timeline->removeAllWaiters();
+ surface->unlockPendingState(); // unref for the new potential ref.
}
- if (pending.acquireTimeline) {
- current.acquireTimeline = pending.acquireTimeline;
- current.acquirePoint = pending.acquirePoint;
+ if (acquire.resource->timeline->addWaiter(
+ [this]() {
+ if (surface.expired())
+ return;
+
+ surface->unlockPendingState();
+ surface->commitPendingState();
+ acquireWaiting = false;
+ },
+ acquire.point, 0u)) {
+ surface->lockPendingState();
+ acquireWaiting = true;
}
-
- pending.releaseTimeline.reset();
- pending.acquireTimeline.reset();
});
}
+CDRMSyncobjSurfaceResource::~CDRMSyncobjSurfaceResource() {
+ if (acquire.resource)
+ acquire.resource->timeline->removeAllWaiters();
+}
+
bool CDRMSyncobjSurfaceResource::good() {
return resource->resource();
}
diff --git a/src/protocols/DRMSyncobj.hpp b/src/protocols/DRMSyncobj.hpp
index 9895dff17e3..6512ed419d8 100644
--- a/src/protocols/DRMSyncobj.hpp
+++ b/src/protocols/DRMSyncobj.hpp
@@ -2,6 +2,7 @@
#include <vector>
#include "WaylandProtocol.hpp"
+#include "helpers/sync/SyncReleaser.hpp"
#include "linux-drm-syncobj-v1.hpp"
#include "../helpers/signal/Signal.hpp"
#include <hyprutils/os/FileDescriptor.hpp>
@@ -13,21 +14,26 @@ class CSyncTimeline;
class CDRMSyncobjSurfaceResource {
public:
CDRMSyncobjSurfaceResource(SP<CWpLinuxDrmSyncobjSurfaceV1> resource_, SP<CWLSurfaceResource> surface_);
+ ~CDRMSyncobjSurfaceResource();
bool good();
WP<CWLSurfaceResource> surface;
- struct {
- WP<CDRMSyncobjTimelineResource> acquireTimeline, releaseTimeline;
- uint64_t acquirePoint = 0, releasePoint = 0;
- } current, pending;
+ struct TimeLineState {
+ WP<CDRMSyncobjTimelineResource> resource;
+ uint64_t point = 0;
+
+ ~TimeLineState();
+ } acquire, release;
+
+ std::vector<UP<CSyncReleaser>> releasePoints;
private:
SP<CWpLinuxDrmSyncobjSurfaceV1> resource;
+ bool acquireWaiting = false;
struct {
CHyprSignalListener surfacePrecommit;
- CHyprSignalListener surfaceCommit;
} listeners;
};
diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp
index 92c3c425d7c..0674743ea9e 100644
--- a/src/protocols/core/Compositor.cpp
+++ b/src/protocols/core/Compositor.cpp
@@ -113,8 +113,7 @@ CWLSurfaceResource::CWLSurfaceResource(SP<CWlSurface> resource_) : resource(reso
return;
}
- if (stateLocks <= 0)
- commitPendingState();
+ commitPendingState();
});
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}); });
@@ -412,16 +411,17 @@ CRegion CWLSurfaceResource::accumulateCurrentBufferDamage() {
}
void CWLSurfaceResource::lockPendingState() {
- stateLocks++;
+ stateLocked = true;
}
void CWLSurfaceResource::unlockPendingState() {
- stateLocks--;
- if (stateLocks <= 0)
- commitPendingState();
+ stateLocked = false;
}
void CWLSurfaceResource::commitPendingState() {
+ if (stateLocked && syncobj)
+ return;
+
static auto PDROP = CConfigValue<Hyprlang::INT>("render:allow_early_buffer_release");
auto const previousBuffer = current.buffer;
current = pending;
@@ -433,8 +433,9 @@ void CWLSurfaceResource::commitPendingState() {
events.roleCommit.emit();
- if (syncobj && syncobj->current.releaseTimeline && syncobj->current.releaseTimeline->timeline && current.buffer && current.buffer->buffer)
- current.buffer->releaser = makeShared<CSyncReleaser>(syncobj->current.releaseTimeline->timeline, syncobj->current.releasePoint);
+ if (syncobj && syncobj->release.resource && syncobj->release.resource->timeline && current.buffer && current.buffer->buffer) {
+ current.buffer->releaser = std::move(syncobj->releasePoints);
+ }
if (current.texture)
current.texture->m_eTransform = wlTransformToHyprutils(current.transform);
diff --git a/src/protocols/core/Compositor.hpp b/src/protocols/core/Compositor.hpp
index aaaf9b1a9cb..fdc0c5001d3 100644
--- a/src/protocols/core/Compositor.hpp
+++ b/src/protocols/core/Compositor.hpp
@@ -131,6 +131,7 @@ class CWLSurfaceResource {
void presentFeedback(timespec* when, PHLMONITOR pMonitor, bool discarded = false);
void lockPendingState();
void unlockPendingState();
+ void commitPendingState();
// returns a pair: found surface (null if not found) and surface local coords.
// localCoords param is relative to 0,0 of this surface
@@ -144,13 +145,12 @@ class CWLSurfaceResource {
// this stupid-ass hack is used
WP<IHLBuffer> lastBuffer;
- int stateLocks = 0;
+ bool stateLocked = false;
void destroy();
void releaseBuffers(bool onlyCurrent = true);
void dropPendingBuffer();
void dropCurrentBuffer();
- void commitPendingState();
void bfHelper(std::vector<SP<CWLSurfaceResource>> const& nodes, std::function<void(SP<CWLSurfaceResource>, const Vector2D&, void*)> fn, void* data);
void updateCursorShm(CRegion damage = CBox{0, 0, INT16_MAX, INT16_MAX});
diff --git a/src/protocols/types/Buffer.hpp b/src/protocols/types/Buffer.hpp
index 7d84dce7390..03f4fe97d0e 100644
--- a/src/protocols/types/Buffer.hpp
+++ b/src/protocols/types/Buffer.hpp
@@ -43,8 +43,8 @@ class CHLBufferReference {
CHLBufferReference(SP<IHLBuffer> buffer, SP<CWLSurfaceResource> surface);
~CHLBufferReference();
- WP<IHLBuffer> buffer;
- SP<CSyncReleaser> releaser;
+ WP<IHLBuffer> buffer;
+ std::vector<UP<CSyncReleaser>> releaser;
private:
WP<CWLSurfaceResource> surface;
diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp
index b61f1c3eb5b..41a8577e471 100644
--- a/src/render/Renderer.cpp
+++ b/src/render/Renderer.cpp
@@ -1568,10 +1568,11 @@ bool CHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) {
Debug::log(TRACE, "Explicit: can't add sync, EGLSync failed");
else {
for (auto const& e : explicitPresented) {
- if (!e->current.buffer || !e->current.buffer->releaser)
+ if (!e->current.buffer || e->current.buffer->releaser.empty())
continue;
- e->current.buffer->releaser->addReleaseSync(sync);
+ for (auto& r : e->current.buffer->releaser)
+ r->addReleaseSync(sync);
}
}
diff --git a/src/render/pass/SurfacePassElement.cpp b/src/render/pass/SurfacePassElement.cpp
index a5d3d7c001a..e6e03b99773 100644
--- a/src/render/pass/SurfacePassElement.cpp
+++ b/src/render/pass/SurfacePassElement.cpp
@@ -50,8 +50,8 @@ void CSurfacePassElement::draw(const CRegion& damage) {
return;
// explicit sync: wait for the timeline, if any
- if (data.surface->syncobj && data.surface->syncobj->current.acquireTimeline) {
- if (!g_pHyprOpenGL->waitForTimelinePoint(data.surface->syncobj->current.acquireTimeline->timeline, data.surface->syncobj->current.acquirePoint)) {
+ if (data.surface->syncobj && data.surface->syncobj->acquire.resource) {
+ if (!g_pHyprOpenGL->waitForTimelinePoint(data.surface->syncobj->acquire.resource->timeline, data.surface->syncobj->acquire.point)) {
Debug::log(ERR, "Renderer: failed to wait for explicit timeline");
return;
}