Skip to content

Commit f9dc208

Browse files
committed
properly release buffers in renderer
1 parent 13a4eb9 commit f9dc208

File tree

11 files changed

+63
-86
lines changed

11 files changed

+63
-86
lines changed

src/helpers/Monitor.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
#include "../macros.hpp"
44
#include "math/Math.hpp"
55
#include "../protocols/ColorManagement.hpp"
6-
#include "sync/SyncReleaser.hpp"
76
#include "../Compositor.hpp"
87
#include "../config/ConfigValue.hpp"
98
#include "../config/ConfigManager.hpp"

src/helpers/Monitor.hpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,7 @@ class CMonitor {
140140

141141
// explicit sync
142142
SP<CSyncTimeline> inTimeline;
143-
Hyprutils::OS::CFileDescriptor inFence;
144-
SP<CEGLSync> eglSync;
143+
Hyprutils::OS::CFileDescriptor inFence; // TODO: remove when aq uses CFileDescriptor
145144
uint64_t inTimelinePoint = 0;
146145

147146
PHLMONITORREF self;

src/helpers/sync/SyncReleaser.cpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,10 @@ CSyncReleaser::~CSyncReleaser() {
3535
m_timeline->signal(m_point);
3636
}
3737

38-
CFileDescriptor CSyncReleaser::mergeSyncFds(const CFileDescriptor& fd1, const CFileDescriptor& fd2) {
38+
static CFileDescriptor mergeSyncFds(const CFileDescriptor& fd1, const CFileDescriptor& fd2) {
39+
// combines the fences of both sync_fds into a dma_fence_array (https://www.kernel.org/doc/html/latest/driver-api/dma-buf.html#c.dma_fence_array_create)
40+
// with the signal_on_any param set to false, so the new sync_fd will "signal when all fences in the array signal."
41+
3942
struct sync_merge_data data{
4043
.name = "merged release fence",
4144
.fd2 = fd2.get(),
@@ -51,13 +54,11 @@ CFileDescriptor CSyncReleaser::mergeSyncFds(const CFileDescriptor& fd1, const CF
5154
return CFileDescriptor(data.fence);
5255
}
5356

54-
void CSyncReleaser::addReleaseSync(SP<CEGLSync> sync) {
57+
void CSyncReleaser::addSyncFileFd(const Hyprutils::OS::CFileDescriptor& syncFd) {
5558
if (m_fd.isValid())
56-
m_fd = mergeSyncFds(m_fd, sync->takeFd());
59+
m_fd = mergeSyncFds(m_fd, syncFd);
5760
else
58-
m_fd = sync->fd().duplicate();
59-
60-
m_sync = sync;
61+
m_fd = syncFd.duplicate();
6162
}
6263

6364
void CSyncReleaser::drop() {

src/helpers/sync/SyncReleaser.hpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,8 @@ class CSyncReleaser {
2222
// drops the releaser, will never signal anymore
2323
void drop();
2424

25-
// wait for this gpu job to finish before releasing
26-
Hyprutils::OS::CFileDescriptor mergeSyncFds(const Hyprutils::OS::CFileDescriptor& fd1, const Hyprutils::OS::CFileDescriptor& fd2);
27-
void addReleaseSync(SP<CEGLSync> sync);
25+
// wait for this sync_fd to signal before releasing
26+
void addSyncFileFd(const Hyprutils::OS::CFileDescriptor& syncFd);
2827

2928
private:
3029
SP<CSyncTimeline> m_timeline;

src/protocols/DRMSyncobj.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -105,10 +105,8 @@ CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(UP<CWpLinuxDrmSyncobjSurf
105105
surface->pending.acquire = pendingAcquire;
106106
pendingAcquire = {};
107107

108-
surface->pending.buffer.release = pendingRelease;
109-
pendingRelease = {};
110-
111-
surface->pending.buffer->syncReleaser = surface->pending.buffer.release.createSyncRelease();
108+
surface->pending.buffer->addReleasePoint(pendingRelease);
109+
pendingRelease = {};
112110
});
113111
}
114112

src/protocols/core/Compositor.cpp

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
#include "Subcompositor.hpp"
88
#include "../Viewporter.hpp"
99
#include "../../helpers/Monitor.hpp"
10-
#include "../../helpers/sync/SyncReleaser.hpp"
1110
#include "../PresentationTime.hpp"
1211
#include "../DRMSyncobj.hpp"
1312
#include "../types/DMABuffer.hpp"
@@ -518,8 +517,7 @@ void CWLSurfaceResource::commitState(SSurfaceState& state) {
518517
nullptr);
519518
}
520519

521-
// release the buffer if it's synchronous (SHM) as update() has done everything thats needed
522-
// so we can let the app know we're done.
520+
// release the buffer if it's synchronous (SHM) as updateSynchronousTexture() has copied the buffer data to a GPU tex
523521
// if it doesn't have a role, we can't release it yet, in case it gets turned into a cursor.
524522
if (current.buffer && current.buffer->isSynchronous() && role->role() != SURFACE_ROLE_UNASSIGNED)
525523
dropCurrentBuffer();
@@ -572,12 +570,6 @@ void CWLSurfaceResource::presentFeedback(const Time::steady_tp& when, PHLMONITOR
572570
else
573571
FEEDBACK->presented();
574572
PROTO::presentation->queueData(FEEDBACK);
575-
576-
if (!pMonitor || !pMonitor->inTimeline || !syncobj)
577-
return;
578-
579-
// attach explicit sync
580-
g_pHyprRenderer->explicitPresented.emplace_back(self.lock());
581573
}
582574

583575
CWLCompositorResource::CWLCompositorResource(SP<CWlCompositor> resource_) : resource(resource_) {

src/protocols/types/Buffer.cpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ IHLBuffer::~IHLBuffer() {
77

88
void IHLBuffer::sendRelease() {
99
resource->sendRelease();
10+
syncReleasers.clear();
1011
}
1112

1213
void IHLBuffer::lock() {
@@ -18,10 +19,8 @@ void IHLBuffer::unlock() {
1819

1920
ASSERT(nLocks >= 0);
2021

21-
if (nLocks == 0) {
22+
if (nLocks == 0)
2223
sendRelease();
23-
syncReleaser.reset();
24-
}
2524
}
2625

2726
bool IHLBuffer::locked() {
@@ -40,11 +39,17 @@ void IHLBuffer::onBackendRelease(const std::function<void()>& fn) {
4039
});
4140
}
4241

42+
void IHLBuffer::addReleasePoint(CDRMSyncPointState& point) {
43+
ASSERT(locked());
44+
if (point)
45+
syncReleasers.emplace_back(point.createSyncRelease());
46+
}
47+
4348
CHLBufferReference::CHLBufferReference() : buffer(nullptr) {
4449
;
4550
}
4651

47-
CHLBufferReference::CHLBufferReference(const CHLBufferReference& other) : release(other.release), buffer(other.buffer) {
52+
CHLBufferReference::CHLBufferReference(const CHLBufferReference& other) : buffer(other.buffer) {
4853
if (buffer)
4954
buffer->lock();
5055
}
@@ -64,8 +69,7 @@ CHLBufferReference& CHLBufferReference::operator=(const CHLBufferReference& othe
6469
other.buffer->lock();
6570
if (buffer)
6671
buffer->unlock();
67-
buffer = other.buffer;
68-
release = other.release;
72+
buffer = other.buffer;
6973
return *this;
7074
}
7175

src/protocols/types/Buffer.hpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,12 @@ class IHLBuffer : public Aquamarine::IBuffer {
2424
virtual bool locked();
2525

2626
void onBackendRelease(const std::function<void()>& fn);
27+
void addReleasePoint(CDRMSyncPointState& point);
2728

2829
SP<CTexture> texture;
2930
bool opaque = false;
3031
SP<CWLBufferResource> resource;
31-
UP<CSyncReleaser> syncReleaser;
32+
std::vector<UP<CSyncReleaser>> syncReleasers;
3233

3334
struct {
3435
CHyprSignalListener backendRelease;
@@ -57,8 +58,7 @@ class CHLBufferReference {
5758
operator bool() const;
5859

5960
// unlock and drop the buffer without sending release
60-
void drop();
61+
void drop();
6162

62-
CDRMSyncPointState release;
63-
SP<IHLBuffer> buffer;
63+
SP<IHLBuffer> buffer;
6464
};

src/render/Renderer.cpp

Lines changed: 21 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
#include "Renderer.hpp"
22
#include "../Compositor.hpp"
33
#include "../helpers/math/Math.hpp"
4-
#include "../helpers/sync/SyncReleaser.hpp"
54
#include <algorithm>
65
#include <aquamarine/output/Output.hpp>
76
#include <filesystem>
@@ -1553,25 +1552,6 @@ bool CHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) {
15531552
}
15541553
}
15551554

1556-
auto explicitOptions = getExplicitSyncSettings(pMonitor->output);
1557-
if (!explicitOptions.explicitEnabled)
1558-
return ok;
1559-
1560-
Debug::log(TRACE, "Explicit: {} presented", explicitPresented.size());
1561-
1562-
if (!pMonitor->eglSync)
1563-
Debug::log(TRACE, "Explicit: can't add sync, monitor has no EGLSync");
1564-
else {
1565-
for (auto const& e : explicitPresented) {
1566-
if (!e->current.buffer || !e->current.buffer->syncReleaser)
1567-
continue;
1568-
1569-
e->current.buffer->syncReleaser->addReleaseSync(pMonitor->eglSync);
1570-
}
1571-
}
1572-
1573-
explicitPresented.clear();
1574-
15751555
return ok;
15761556
}
15771557

@@ -2278,42 +2258,42 @@ void CHyprRenderer::endRender() {
22782258
g_pHyprOpenGL->m_RenderData.mouseZoomUseMouse = true;
22792259
}
22802260

2261+
// send all queued opengl commands so rendering starts happening immediately
2262+
glFlush();
2263+
22812264
if (m_eRenderMode == RENDER_MODE_FULL_FAKE)
22822265
return;
22832266

22842267
if (m_eRenderMode == RENDER_MODE_NORMAL)
22852268
PMONITOR->output->state->setBuffer(m_pCurrentBuffer);
22862269

2287-
auto explicitOptions = getExplicitSyncSettings(PMONITOR->output);
2288-
2289-
if (PMONITOR->inTimeline && explicitOptions.explicitEnabled) {
2290-
PMONITOR->eglSync = makeShared<CEGLSync>();
2291-
if (!PMONITOR->eglSync->isValid()) {
2292-
Debug::log(ERR, "renderer: couldn't create an EGLSync for out in endRender");
2293-
return;
2270+
CEGLSync eglSync = CEGLSync();
2271+
if (eglSync.isValid()) {
2272+
for (auto const& buf : usedAsyncBuffers) {
2273+
for (const auto& releaser : buf->syncReleasers) {
2274+
releaser->addSyncFileFd(eglSync.fd());
2275+
}
22942276
}
22952277

2296-
PMONITOR->inTimelinePoint++;
2297-
bool ok = PMONITOR->inTimeline->importFromSyncFileFD(PMONITOR->inTimelinePoint, PMONITOR->eglSync->fd());
2298-
if (!ok) {
2299-
Debug::log(ERR, "renderer: couldn't import from sync file fd in endRender");
2300-
return;
2301-
}
2278+
// release buffer refs with release points now, since syncReleaser handles actual buffer release based on EGLSync
2279+
std::erase_if(usedAsyncBuffers, [](const auto& buf) { return !buf->syncReleasers.empty(); });
23022280

2303-
if (m_eRenderMode == RENDER_MODE_NORMAL && explicitOptions.explicitKMSEnabled) {
2304-
PMONITOR->inFence = CFileDescriptor{PMONITOR->inTimeline->exportAsSyncFileFD(PMONITOR->inTimelinePoint)};
2305-
if (!PMONITOR->inFence.isValid()) {
2306-
Debug::log(ERR, "renderer: couldn't export from sync timeline in endRender");
2307-
return;
2308-
}
2281+
// release buffer refs without release points when EGLSync sync_file/fence is signalled
2282+
g_pEventLoopManager->doOnReadable(eglSync.fd().duplicate(), [prevbfs = std::move(usedAsyncBuffers)]() mutable { prevbfs.clear(); });
2283+
usedAsyncBuffers.clear();
23092284

2285+
if (m_eRenderMode == RENDER_MODE_NORMAL) {
2286+
PMONITOR->inFence = eglSync.takeFd();
23102287
PMONITOR->output->state->setExplicitInFence(PMONITOR->inFence.get());
23112288
}
23122289
} else {
2290+
Debug::log(ERR, "renderer: couldn't use EGLSync for explicit gpu synchronization");
2291+
2292+
// nvidia doesn't have implicit sync, so we have to explicitly wait here
23132293
if (isNvidia() && *PNVIDIAANTIFLICKER)
23142294
glFinish();
2315-
else
2316-
glFlush();
2295+
2296+
usedAsyncBuffers.clear(); // release all buffer refs and hope implicit sync works
23172297
}
23182298
}
23192299

src/render/Renderer.hpp

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -91,20 +91,20 @@ class CHyprRenderer {
9191

9292
bool m_bBlockSurfaceFeedback = false;
9393
bool m_bRenderingSnapshot = false;
94-
PHLMONITORREF m_pMostHzMonitor;
95-
bool m_bDirectScanoutBlocked = false;
94+
PHLMONITORREF m_pMostHzMonitor;
95+
bool m_bDirectScanoutBlocked = false;
9696

97-
void setSurfaceScanoutMode(SP<CWLSurfaceResource> surface, PHLMONITOR monitor); // nullptr monitor resets
98-
void initiateManualCrash();
97+
void setSurfaceScanoutMode(SP<CWLSurfaceResource> surface, PHLMONITOR monitor); // nullptr monitor resets
98+
void initiateManualCrash();
9999

100-
bool m_bCrashingInProgress = false;
101-
float m_fCrashingDistort = 0.5f;
102-
wl_event_source* m_pCrashingLoop = nullptr;
103-
wl_event_source* m_pCursorTicker = nullptr;
100+
bool m_bCrashingInProgress = false;
101+
float m_fCrashingDistort = 0.5f;
102+
wl_event_source* m_pCrashingLoop = nullptr;
103+
wl_event_source* m_pCursorTicker = nullptr;
104104

105-
CTimer m_tRenderTimer;
105+
CTimer m_tRenderTimer;
106106

107-
std::vector<SP<CWLSurfaceResource>> explicitPresented;
107+
std::vector<CHLBufferReference> usedAsyncBuffers;
108108

109109
struct {
110110
int hotspotX = 0;

src/render/pass/SurfacePassElement.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,11 @@ void CSurfacePassElement::draw(const CRegion& damage) {
129129
if (!g_pHyprRenderer->m_bBlockSurfaceFeedback)
130130
data.surface->presentFeedback(data.when, data.pMonitor->self.lock());
131131

132+
// add async (dmabuf) buffers to usedBuffers so we can handle release later
133+
// sync (shm) buffers will be released in commitState, so no need to track them here
134+
if (data.surface->current.buffer && !data.surface->current.buffer->isSynchronous())
135+
g_pHyprRenderer->usedAsyncBuffers.emplace_back(data.surface->current.buffer);
136+
132137
g_pHyprOpenGL->blend(true);
133138
}
134139

0 commit comments

Comments
 (0)