summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorIkalco <73481042+ikalco@users.noreply.github.com>2025-04-30 11:35:25 -0500
committerGitHub <noreply@github.com>2025-04-30 18:35:25 +0200
commit2ee5118d7a4a59d3ccfaed305bfc05c79cea7637 (patch)
tree7c113e64071edbc260060df7e60af9c915b3986a /src
parent5d005f11fa218d26ed2cf6ce75cd9aac9c2c00e5 (diff)
render: properly release rendered buffers (#9807)
* cleanup eglSync * properly release buffers in renderer * add renderingDoneCallback and use it in screencopy * use static constructor for CEGLSync
Diffstat (limited to 'src')
-rw-r--r--src/helpers/Monitor.cpp5
-rw-r--r--src/helpers/Monitor.hpp5
-rw-r--r--src/helpers/sync/SyncReleaser.cpp13
-rw-r--r--src/helpers/sync/SyncReleaser.hpp7
-rw-r--r--src/protocols/DRMSyncobj.cpp6
-rw-r--r--src/protocols/Screencopy.cpp18
-rw-r--r--src/protocols/core/Compositor.cpp10
-rw-r--r--src/protocols/types/Buffer.cpp16
-rw-r--r--src/protocols/types/Buffer.hpp8
-rw-r--r--src/render/OpenGL.cpp79
-rw-r--r--src/render/OpenGL.hpp12
-rw-r--r--src/render/Renderer.cpp70
-rw-r--r--src/render/Renderer.hpp22
-rw-r--r--src/render/pass/SurfacePassElement.cpp5
14 files changed, 117 insertions, 159 deletions
diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp
index cd394c19..4ee0166f 100644
--- a/src/helpers/Monitor.cpp
+++ b/src/helpers/Monitor.cpp
@@ -3,7 +3,6 @@
#include "../macros.hpp"
#include "math/Math.hpp"
#include "../protocols/ColorManagement.hpp"
-#include "sync/SyncReleaser.hpp"
#include "../Compositor.hpp"
#include "../config/ConfigValue.hpp"
#include "../config/ConfigManager.hpp"
@@ -61,10 +60,6 @@ void CMonitor::onConnect(bool noRule) {
g_pEventLoopManager->doLater([] { g_pConfigManager->ensurePersistentWorkspacesPresent(); });
- if (output->supportsExplicit) {
- inTimeline = CSyncTimeline::create(output->getBackend()->drmFD());
- }
-
listeners.frame = output->events.frame.registerListener([this](std::any d) { onMonitorFrame(); });
listeners.commit = output->events.commit.registerListener([this](std::any d) {
if (true) { // FIXME: E->state->committed & WLR_OUTPUT_STATE_BUFFER
diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp
index 2ce6b626..88252ab4 100644
--- a/src/helpers/Monitor.hpp
+++ b/src/helpers/Monitor.hpp
@@ -139,10 +139,7 @@ class CMonitor {
SMonitorRule activeMonitorRule;
// explicit sync
- SP<CSyncTimeline> inTimeline;
- Hyprutils::OS::CFileDescriptor inFence;
- SP<CEGLSync> eglSync;
- uint64_t inTimelinePoint = 0;
+ Hyprutils::OS::CFileDescriptor inFence; // TODO: remove when aq uses CFileDescriptor
PHLMONITORREF self;
diff --git a/src/helpers/sync/SyncReleaser.cpp b/src/helpers/sync/SyncReleaser.cpp
index fca7d7c2..66d7667f 100644
--- a/src/helpers/sync/SyncReleaser.cpp
+++ b/src/helpers/sync/SyncReleaser.cpp
@@ -35,7 +35,10 @@ CSyncReleaser::~CSyncReleaser() {
m_timeline->signal(m_point);
}
-CFileDescriptor CSyncReleaser::mergeSyncFds(const CFileDescriptor& fd1, const CFileDescriptor& fd2) {
+static CFileDescriptor mergeSyncFds(const CFileDescriptor& fd1, const CFileDescriptor& fd2) {
+ // 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)
+ // with the signal_on_any param set to false, so the new sync_fd will "signal when all fences in the array signal."
+
struct sync_merge_data data{
.name = "merged release fence",
.fd2 = fd2.get(),
@@ -51,13 +54,11 @@ CFileDescriptor CSyncReleaser::mergeSyncFds(const CFileDescriptor& fd1, const CF
return CFileDescriptor(data.fence);
}
-void CSyncReleaser::addReleaseSync(SP<CEGLSync> sync) {
+void CSyncReleaser::addSyncFileFd(const Hyprutils::OS::CFileDescriptor& syncFd) {
if (m_fd.isValid())
- m_fd = mergeSyncFds(m_fd, sync->takeFD());
+ m_fd = mergeSyncFds(m_fd, syncFd);
else
- m_fd = sync->fd().duplicate();
-
- m_sync = sync;
+ m_fd = syncFd.duplicate();
}
void CSyncReleaser::drop() {
diff --git a/src/helpers/sync/SyncReleaser.hpp b/src/helpers/sync/SyncReleaser.hpp
index f04e85c1..0063171d 100644
--- a/src/helpers/sync/SyncReleaser.hpp
+++ b/src/helpers/sync/SyncReleaser.hpp
@@ -12,7 +12,6 @@
*/
class CSyncTimeline;
-class CEGLSync;
class CSyncReleaser {
public:
@@ -22,13 +21,11 @@ class CSyncReleaser {
// drops the releaser, will never signal anymore
void drop();
- // wait for this gpu job to finish before releasing
- Hyprutils::OS::CFileDescriptor mergeSyncFds(const Hyprutils::OS::CFileDescriptor& fd1, const Hyprutils::OS::CFileDescriptor& fd2);
- void addReleaseSync(SP<CEGLSync> sync);
+ // wait for this sync_fd to signal before releasing
+ void addSyncFileFd(const Hyprutils::OS::CFileDescriptor& syncFd);
private:
SP<CSyncTimeline> m_timeline;
uint64_t m_point = 0;
Hyprutils::OS::CFileDescriptor m_fd;
- SP<CEGLSync> m_sync;
};
diff --git a/src/protocols/DRMSyncobj.cpp b/src/protocols/DRMSyncobj.cpp
index 5d04d53f..48a80dcc 100644
--- a/src/protocols/DRMSyncobj.cpp
+++ b/src/protocols/DRMSyncobj.cpp
@@ -105,10 +105,8 @@ CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(UP<CWpLinuxDrmSyncobjSurf
surface->pending.acquire = pendingAcquire;
pendingAcquire = {};
- surface->pending.buffer.release = pendingRelease;
- pendingRelease = {};
-
- surface->pending.buffer->syncReleaser = surface->pending.buffer.release.createSyncRelease();
+ surface->pending.buffer->addReleasePoint(pendingRelease);
+ pendingRelease = {};
});
}
diff --git a/src/protocols/Screencopy.cpp b/src/protocols/Screencopy.cpp
index 3862dddd..6727bcf4 100644
--- a/src/protocols/Screencopy.cpp
+++ b/src/protocols/Screencopy.cpp
@@ -221,21 +221,11 @@ void CScreencopyFrame::copyDmabuf(std::function<void(bool)> callback) {
}
g_pHyprOpenGL->m_RenderData.blockScreenShader = true;
- g_pHyprRenderer->endRender();
- auto explicitOptions = g_pHyprRenderer->getExplicitSyncSettings(pMonitor->output);
- if (pMonitor->inTimeline && explicitOptions.explicitEnabled) {
- if (pMonitor->inTimeline->addWaiter(
- [callback, sync = pMonitor->eglSync]() {
- LOGM(TRACE, "Copied frame via dma with explicit sync");
- callback(true);
- },
- pMonitor->inTimelinePoint, 0))
- return;
- // on explicit sync failure, fallthrough to immediate callback
- }
- LOGM(TRACE, "Copied frame via dma");
- callback(true);
+ g_pHyprRenderer->endRender([callback]() {
+ LOGM(TRACE, "Copied frame via dma");
+ callback(true);
+ });
}
bool CScreencopyFrame::copyShm() {
diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp
index 23b14dd3..cf28b240 100644
--- a/src/protocols/core/Compositor.cpp
+++ b/src/protocols/core/Compositor.cpp
@@ -7,7 +7,6 @@
#include "Subcompositor.hpp"
#include "../Viewporter.hpp"
#include "../../helpers/Monitor.hpp"
-#include "../../helpers/sync/SyncReleaser.hpp"
#include "../PresentationTime.hpp"
#include "../DRMSyncobj.hpp"
#include "../types/DMABuffer.hpp"
@@ -518,8 +517,7 @@ void CWLSurfaceResource::commitState(SSurfaceState& state) {
nullptr);
}
- // release the buffer if it's synchronous (SHM) as update() has done everything thats needed
- // so we can let the app know we're done.
+ // release the buffer if it's synchronous (SHM) as updateSynchronousTexture() has copied the buffer data to a GPU tex
// if it doesn't have a role, we can't release it yet, in case it gets turned into a cursor.
if (current.buffer && current.buffer->isSynchronous() && role->role() != SURFACE_ROLE_UNASSIGNED)
dropCurrentBuffer();
@@ -572,12 +570,6 @@ void CWLSurfaceResource::presentFeedback(const Time::steady_tp& when, PHLMONITOR
else
FEEDBACK->presented();
PROTO::presentation->queueData(FEEDBACK);
-
- if (!pMonitor || !pMonitor->inTimeline || !syncobj)
- return;
-
- // attach explicit sync
- g_pHyprRenderer->explicitPresented.emplace_back(self.lock());
}
CWLCompositorResource::CWLCompositorResource(SP<CWlCompositor> resource_) : resource(resource_) {
diff --git a/src/protocols/types/Buffer.cpp b/src/protocols/types/Buffer.cpp
index 22745c06..73155c29 100644
--- a/src/protocols/types/Buffer.cpp
+++ b/src/protocols/types/Buffer.cpp
@@ -7,6 +7,7 @@ IHLBuffer::~IHLBuffer() {
void IHLBuffer::sendRelease() {
resource->sendRelease();
+ syncReleasers.clear();
}
void IHLBuffer::lock() {
@@ -18,10 +19,8 @@ void IHLBuffer::unlock() {
ASSERT(nLocks >= 0);
- if (nLocks == 0) {
+ if (nLocks == 0)
sendRelease();
- syncReleaser.reset();
- }
}
bool IHLBuffer::locked() {
@@ -40,11 +39,17 @@ void IHLBuffer::onBackendRelease(const std::function<void()>& fn) {
});
}
+void IHLBuffer::addReleasePoint(CDRMSyncPointState& point) {
+ ASSERT(locked());
+ if (point)
+ syncReleasers.emplace_back(point.createSyncRelease());
+}
+
CHLBufferReference::CHLBufferReference() : buffer(nullptr) {
;
}
-CHLBufferReference::CHLBufferReference(const CHLBufferReference& other) : release(other.release), buffer(other.buffer) {
+CHLBufferReference::CHLBufferReference(const CHLBufferReference& other) : buffer(other.buffer) {
if (buffer)
buffer->lock();
}
@@ -64,8 +69,7 @@ CHLBufferReference& CHLBufferReference::operator=(const CHLBufferReference& othe
other.buffer->lock();
if (buffer)
buffer->unlock();
- buffer = other.buffer;
- release = other.release;
+ buffer = other.buffer;
return *this;
}
diff --git a/src/protocols/types/Buffer.hpp b/src/protocols/types/Buffer.hpp
index 1bf7583c..e4821ac0 100644
--- a/src/protocols/types/Buffer.hpp
+++ b/src/protocols/types/Buffer.hpp
@@ -24,11 +24,12 @@ class IHLBuffer : public Aquamarine::IBuffer {
virtual bool locked();
void onBackendRelease(const std::function<void()>& fn);
+ void addReleasePoint(CDRMSyncPointState& point);
SP<CTexture> texture;
bool opaque = false;
SP<CWLBufferResource> resource;
- UP<CSyncReleaser> syncReleaser;
+ std::vector<UP<CSyncReleaser>> syncReleasers;
struct {
CHyprSignalListener backendRelease;
@@ -57,8 +58,7 @@ class CHLBufferReference {
operator bool() const;
// unlock and drop the buffer without sending release
- void drop();
+ void drop();
- CDRMSyncPointState release;
- SP<IHLBuffer> buffer;
+ SP<IHLBuffer> buffer;
};
diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp
index a6cc176a..2a0cbe5a 100644
--- a/src/render/OpenGL.cpp
+++ b/src/render/OpenGL.cpp
@@ -3090,44 +3090,6 @@ std::vector<SDRMFormat> CHyprOpenGLImpl::getDRMFormats() {
return drmFormats;
}
-SP<CEGLSync> CHyprOpenGLImpl::createEGLSync(int fenceFD) {
- std::vector<EGLint> attribs;
- CFileDescriptor dupFd;
- if (fenceFD >= 0) {
- dupFd = CFileDescriptor{fcntl(fenceFD, F_DUPFD_CLOEXEC, 0)};
- if (!dupFd.isValid()) {
- Debug::log(ERR, "createEGLSync: dup failed");
- return nullptr;
- }
- // reserve number of elements to avoid reallocations
- attribs.reserve(3);
- attribs.push_back(EGL_SYNC_NATIVE_FENCE_FD_ANDROID);
- attribs.push_back(dupFd.get());
- attribs.push_back(EGL_NONE);
- }
-
- EGLSyncKHR sync = m_sProc.eglCreateSyncKHR(m_pEglDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, attribs.data());
- if (sync == EGL_NO_SYNC_KHR) {
- Debug::log(ERR, "eglCreateSyncKHR failed");
- return nullptr;
- } else
- dupFd.take(); // eglCreateSyncKHR only takes ownership on success
-
- // we need to flush otherwise we might not get a valid fd
- glFlush();
-
- int fd = g_pHyprOpenGL->m_sProc.eglDupNativeFenceFDANDROID(g_pHyprOpenGL->m_pEglDisplay, sync);
- if (fd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
- Debug::log(ERR, "eglDupNativeFenceFDANDROID failed");
- return nullptr;
- }
-
- auto eglsync = SP<CEGLSync>(new CEGLSync);
- eglsync->sync = sync;
- eglsync->m_iFd = CFileDescriptor{fd};
- return eglsync;
-}
-
void SRenderModifData::applyToBox(CBox& box) {
if (!enabled)
return;
@@ -3189,18 +3151,47 @@ float SRenderModifData::combinedScale() {
return scale;
}
+UP<CEGLSync> CEGLSync::create() {
+ EGLSyncKHR sync = g_pHyprOpenGL->m_sProc.eglCreateSyncKHR(g_pHyprOpenGL->m_pEglDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr);
+
+ if (sync == EGL_NO_SYNC_KHR) {
+ Debug::log(ERR, "eglCreateSyncKHR failed");
+ return nullptr;
+ }
+
+ // we need to flush otherwise we might not get a valid fd
+ glFlush();
+
+ int fd = g_pHyprOpenGL->m_sProc.eglDupNativeFenceFDANDROID(g_pHyprOpenGL->m_pEglDisplay, sync);
+ if (fd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
+ Debug::log(ERR, "eglDupNativeFenceFDANDROID failed");
+ return nullptr;
+ }
+
+ UP<CEGLSync> eglSync(new CEGLSync);
+ eglSync->m_fd = CFileDescriptor(fd);
+ eglSync->m_sync = sync;
+ eglSync->m_valid = true;
+
+ return eglSync;
+}
+
CEGLSync::~CEGLSync() {
- if (sync == EGL_NO_SYNC_KHR)
+ if (m_sync == EGL_NO_SYNC_KHR)
return;
- if (g_pHyprOpenGL && g_pHyprOpenGL->m_sProc.eglDestroySyncKHR(g_pHyprOpenGL->m_pEglDisplay, sync) != EGL_TRUE)
+ if (g_pHyprOpenGL && g_pHyprOpenGL->m_sProc.eglDestroySyncKHR(g_pHyprOpenGL->m_pEglDisplay, m_sync) != EGL_TRUE)
Debug::log(ERR, "eglDestroySyncKHR failed");
}
-CFileDescriptor&& CEGLSync::takeFD() {
- return std::move(m_iFd);
+CFileDescriptor& CEGLSync::fd() {
+ return m_fd;
}
-CFileDescriptor& CEGLSync::fd() {
- return m_iFd;
+CFileDescriptor&& CEGLSync::takeFd() {
+ return std::move(m_fd);
+}
+
+bool CEGLSync::isValid() {
+ return m_valid && m_sync != EGL_NO_SYNC_KHR && m_fd.isValid();
}
diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp
index 414ba103..21602d07 100644
--- a/src/render/OpenGL.hpp
+++ b/src/render/OpenGL.hpp
@@ -150,17 +150,20 @@ struct SCurrentRenderData {
class CEGLSync {
public:
- ~CEGLSync();
+ static UP<CEGLSync> create();
- EGLSyncKHR sync = nullptr;
+ ~CEGLSync();
- Hyprutils::OS::CFileDescriptor&& takeFD();
Hyprutils::OS::CFileDescriptor& fd();
+ Hyprutils::OS::CFileDescriptor&& takeFd();
+ bool isValid();
private:
CEGLSync() = default;
- Hyprutils::OS::CFileDescriptor m_iFd;
+ Hyprutils::OS::CFileDescriptor m_fd;
+ EGLSyncKHR m_sync = EGL_NO_SYNC_KHR;
+ bool m_valid = false;
friend class CHyprOpenGLImpl;
};
@@ -234,7 +237,6 @@ class CHyprOpenGLImpl {
uint32_t getPreferredReadFormat(PHLMONITOR pMonitor);
std::vector<SDRMFormat> getDRMFormats();
EGLImageKHR createEGLImage(const Aquamarine::SDMABUFAttrs& attrs);
- SP<CEGLSync> createEGLSync(int fence = -1);
bool initShaders();
bool m_bShadersInitialized = false;
diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp
index 0db305af..93d3620f 100644
--- a/src/render/Renderer.cpp
+++ b/src/render/Renderer.cpp
@@ -1,7 +1,6 @@
#include "Renderer.hpp"
#include "../Compositor.hpp"
#include "../helpers/math/Math.hpp"
-#include "../helpers/sync/SyncReleaser.hpp"
#include <algorithm>
#include <aquamarine/output/Output.hpp>
#include <filesystem>
@@ -1571,25 +1570,6 @@ bool CHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) {
}
}
- auto explicitOptions = getExplicitSyncSettings(pMonitor->output);
- if (!explicitOptions.explicitEnabled)
- return ok;
-
- Debug::log(TRACE, "Explicit: {} presented", explicitPresented.size());
-
- if (!pMonitor->eglSync)
- Debug::log(TRACE, "Explicit: can't add sync, monitor has no EGLSync");
- else {
- for (auto const& e : explicitPresented) {
- if (!e->current.buffer || !e->current.buffer->syncReleaser)
- continue;
-
- e->current.buffer->syncReleaser->addReleaseSync(pMonitor->eglSync);
- }
- }
-
- explicitPresented.clear();
-
return ok;
}
@@ -2275,7 +2255,7 @@ bool CHyprRenderer::beginRender(PHLMONITOR pMonitor, CRegion& damage, eRenderMod
return true;
}
-void CHyprRenderer::endRender() {
+void CHyprRenderer::endRender(const std::function<void()>& renderingDoneCallback) {
const auto PMONITOR = g_pHyprOpenGL->m_RenderData.pMonitor;
static auto PNVIDIAANTIFLICKER = CConfigValue<Hyprlang::INT>("opengl:nvidia_anti_flicker");
@@ -2296,42 +2276,48 @@ void CHyprRenderer::endRender() {
g_pHyprOpenGL->m_RenderData.mouseZoomUseMouse = true;
}
+ // send all queued opengl commands so rendering starts happening immediately
+ glFlush();
+
if (m_eRenderMode == RENDER_MODE_FULL_FAKE)
return;
if (m_eRenderMode == RENDER_MODE_NORMAL)
PMONITOR->output->state->setBuffer(m_pCurrentBuffer);
- auto explicitOptions = getExplicitSyncSettings(PMONITOR->output);
-
- if (PMONITOR->inTimeline && explicitOptions.explicitEnabled) {
- PMONITOR->eglSync = g_pHyprOpenGL->createEGLSync();
- if (!PMONITOR->eglSync) {
- Debug::log(ERR, "renderer: couldn't create an EGLSync for out in endRender");
- return;
+ UP<CEGLSync> eglSync = CEGLSync::create();
+ if (eglSync && eglSync->isValid()) {
+ for (auto const& buf : usedAsyncBuffers) {
+ for (const auto& releaser : buf->syncReleasers) {
+ releaser->addSyncFileFd(eglSync->fd());
+ }
}
- PMONITOR->inTimelinePoint++;
- bool ok = PMONITOR->inTimeline->importFromSyncFileFD(PMONITOR->inTimelinePoint, PMONITOR->eglSync->fd());
- if (!ok) {
- Debug::log(ERR, "renderer: couldn't import from sync file fd in endRender");
- return;
- }
+ // release buffer refs with release points now, since syncReleaser handles actual buffer release based on EGLSync
+ std::erase_if(usedAsyncBuffers, [](const auto& buf) { return !buf->syncReleasers.empty(); });
- if (m_eRenderMode == RENDER_MODE_NORMAL && explicitOptions.explicitKMSEnabled) {
- PMONITOR->inFence = CFileDescriptor{PMONITOR->inTimeline->exportAsSyncFileFD(PMONITOR->inTimelinePoint)};
- if (!PMONITOR->inFence.isValid()) {
- Debug::log(ERR, "renderer: couldn't export from sync timeline in endRender");
- return;
- }
+ // release buffer refs without release points when EGLSync sync_file/fence is signalled
+ g_pEventLoopManager->doOnReadable(eglSync->fd().duplicate(), [renderingDoneCallback, prevbfs = std::move(usedAsyncBuffers)]() mutable {
+ prevbfs.clear();
+ if (renderingDoneCallback)
+ renderingDoneCallback();
+ });
+ usedAsyncBuffers.clear();
+ if (m_eRenderMode == RENDER_MODE_NORMAL) {
+ PMONITOR->inFence = eglSync->takeFd();
PMONITOR->output->state->setExplicitInFence(PMONITOR->inFence.get());
}
} else {
+ Debug::log(ERR, "renderer: couldn't use EGLSync for explicit gpu synchronization");
+
+ // nvidia doesn't have implicit sync, so we have to explicitly wait here
if (isNvidia() && *PNVIDIAANTIFLICKER)
glFinish();
- else
- glFlush();
+
+ usedAsyncBuffers.clear(); // release all buffer refs and hope implicit sync works
+ if (renderingDoneCallback)
+ renderingDoneCallback();
}
}
diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp
index 553965a4..37e1e91f 100644
--- a/src/render/Renderer.hpp
+++ b/src/render/Renderer.hpp
@@ -87,24 +87,24 @@ class CHyprRenderer {
// if RENDER_MODE_NORMAL, provided damage will be written to.
// otherwise, it will be the one used.
bool beginRender(PHLMONITOR pMonitor, CRegion& damage, eRenderMode mode = RENDER_MODE_NORMAL, SP<IHLBuffer> buffer = {}, CFramebuffer* fb = nullptr, bool simple = false);
- void endRender();
+ void endRender(const std::function<void()>& renderingDoneCallback = {});
bool m_bBlockSurfaceFeedback = false;
bool m_bRenderingSnapshot = false;
- PHLMONITORREF m_pMostHzMonitor;
- bool m_bDirectScanoutBlocked = false;
+ PHLMONITORREF m_pMostHzMonitor;
+ bool m_bDirectScanoutBlocked = false;
- void setSurfaceScanoutMode(SP<CWLSurfaceResource> surface, PHLMONITOR monitor); // nullptr monitor resets
- void initiateManualCrash();
+ void setSurfaceScanoutMode(SP<CWLSurfaceResource> surface, PHLMONITOR monitor); // nullptr monitor resets
+ void initiateManualCrash();
- bool m_bCrashingInProgress = false;
- float m_fCrashingDistort = 0.5f;
- wl_event_source* m_pCrashingLoop = nullptr;
- wl_event_source* m_pCursorTicker = nullptr;
+ bool m_bCrashingInProgress = false;
+ float m_fCrashingDistort = 0.5f;
+ wl_event_source* m_pCrashingLoop = nullptr;
+ wl_event_source* m_pCursorTicker = nullptr;
- CTimer m_tRenderTimer;
+ CTimer m_tRenderTimer;
- std::vector<SP<CWLSurfaceResource>> explicitPresented;
+ std::vector<CHLBufferReference> usedAsyncBuffers;
struct {
int hotspotX = 0;
diff --git a/src/render/pass/SurfacePassElement.cpp b/src/render/pass/SurfacePassElement.cpp
index c47c76ce..22e61a23 100644
--- a/src/render/pass/SurfacePassElement.cpp
+++ b/src/render/pass/SurfacePassElement.cpp
@@ -129,6 +129,11 @@ void CSurfacePassElement::draw(const CRegion& damage) {
if (!g_pHyprRenderer->m_bBlockSurfaceFeedback)
data.surface->presentFeedback(data.when, data.pMonitor->self.lock());
+ // add async (dmabuf) buffers to usedBuffers so we can handle release later
+ // sync (shm) buffers will be released in commitState, so no need to track them here
+ if (data.surface->current.buffer && !data.surface->current.buffer->isSynchronous())
+ g_pHyprRenderer->usedAsyncBuffers.emplace_back(data.surface->current.buffer);
+
g_pHyprOpenGL->blend(true);
}