diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index eda5c7332..20f959de4 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -691,7 +691,6 @@ CConfigManager::CConfigManager() { registerConfigVar("render:expand_undersized_textures", Hyprlang::INT{1}); registerConfigVar("render:xp_mode", Hyprlang::INT{0}); registerConfigVar("render:ctm_animation", Hyprlang::INT{2}); - registerConfigVar("render:allow_early_buffer_release", Hyprlang::INT{1}); registerConfigVar("render:cm_fs_passthrough", Hyprlang::INT{1}); registerConfigVar("ecosystem:no_update_news", Hyprlang::INT{0}); diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index ce30b8e79..710224250 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -1391,16 +1391,17 @@ bool CMonitor::attemptDirectScanout() { auto explicitOptions = g_pHyprRenderer->getExplicitSyncSettings(output); - bool DOEXPLICIT = PSURFACE->syncobj && PSURFACE->syncobj->current.acquireTimeline && PSURFACE->syncobj->current.acquireTimeline->timeline && explicitOptions.explicitKMSEnabled; + bool DOEXPLICIT = PSURFACE->syncobj && PSURFACE->current.buffer && PSURFACE->current.buffer->acquire && explicitOptions.explicitKMSEnabled; if (DOEXPLICIT) { // wait for surface's explicit fence if present - CFileDescriptor fd = PSURFACE->syncobj->current.acquireTimeline->timeline->exportAsSyncFileFD(PSURFACE->syncobj->current.acquirePoint); - if (fd.isValid()) { - Debug::log(TRACE, "attemptDirectScanout: setting IN_FENCE for aq to {}", fd.get()); - output->state->setExplicitInFence(fd.get()); - } else + inFence = PSURFACE->current.buffer->acquire->exportAsFD(); + if (inFence.isValid()) { + Debug::log(TRACE, "attemptDirectScanout: setting IN_FENCE for aq to {}", inFence.get()); + output->state->setExplicitInFence(inFence.get()); + } else { Debug::log(TRACE, "attemptDirectScanout: failed to acquire an sync file fd for aq IN_FENCE"); - DOEXPLICIT = fd.isValid(); + DOEXPLICIT = false; + } } commitSeq++; @@ -1425,7 +1426,7 @@ bool CMonitor::attemptDirectScanout() { Debug::log(LOG, "Entered a direct scanout to {:x}: \"{}\"", (uintptr_t)PCANDIDATE.get(), PCANDIDATE->m_szTitle); } - if (!PBUFFER->lockedByBackend) + if (!PBUFFER->lockedByBackend || PBUFFER->hlEvents.backendRelease) return true; // lock buffer while DRM/KMS is using it, then release it when page flip happens since DRM/KMS should be done by then diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index 10e807a05..36959aa28 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -138,11 +138,12 @@ class CMonitor { SMonitorRule activeMonitorRule; // explicit sync - SP inTimeline; - SP outTimeline; - uint64_t commitSeq = 0; + SP inTimeline; + SP outTimeline; + Hyprutils::OS::CFileDescriptor inFence; + uint64_t commitSeq = 0; - PHLMONITORREF self; + PHLMONITORREF self; // mirroring PHLMONITORREF pMirrorOf; diff --git a/src/helpers/sync/SyncReleaser.cpp b/src/helpers/sync/SyncReleaser.cpp index 198495ab6..fca7d7c2b 100644 --- a/src/helpers/sync/SyncReleaser.cpp +++ b/src/helpers/sync/SyncReleaser.cpp @@ -1,25 +1,65 @@ #include "SyncReleaser.hpp" #include "SyncTimeline.hpp" #include "../../render/OpenGL.hpp" +#include -CSyncReleaser::CSyncReleaser(WP timeline_, uint64_t point_) : timeline(timeline_), point(point_) { +#if defined(__linux__) +#include +#else +struct sync_merge_data { + char name[32]; + __s32 fd2; + __s32 fence; + __u32 flags; + __u32 pad; +}; +#define SYNC_IOC_MAGIC '>' +#define SYNC_IOC_MERGE _IOWR(SYNC_IOC_MAGIC, 3, struct sync_merge_data) +#endif + +using namespace Hyprutils::OS; + +CSyncReleaser::CSyncReleaser(SP timeline, uint64_t point) : m_timeline(timeline), m_point(point) { ; } CSyncReleaser::~CSyncReleaser() { - if (timeline.expired()) + if (!m_timeline) { + Debug::log(ERR, "CSyncReleaser destructing without a timeline"); return; + } - if (sync) - timeline->importFromSyncFileFD(point, sync->fd()); + if (m_fd.isValid()) + m_timeline->importFromSyncFileFD(m_point, m_fd); else - timeline->signal(point); + m_timeline->signal(m_point); } -void CSyncReleaser::addReleaseSync(SP sync_) { - sync = sync_; +CFileDescriptor CSyncReleaser::mergeSyncFds(const CFileDescriptor& fd1, const CFileDescriptor& fd2) { + struct sync_merge_data data{ + .name = "merged release fence", + .fd2 = fd2.get(), + .fence = -1, + }; + int err = -1; + do { + err = ioctl(fd1.get(), SYNC_IOC_MERGE, &data); + } while (err == -1 && (errno == EINTR || errno == EAGAIN)); + if (err < 0) + return CFileDescriptor{}; + else + return CFileDescriptor(data.fence); +} + +void CSyncReleaser::addReleaseSync(SP sync) { + if (m_fd.isValid()) + m_fd = mergeSyncFds(m_fd, sync->takeFD()); + else + m_fd = sync->fd().duplicate(); + + m_sync = sync; } void CSyncReleaser::drop() { - timeline.reset(); -} \ No newline at end of file + m_timeline.reset(); +} diff --git a/src/helpers/sync/SyncReleaser.hpp b/src/helpers/sync/SyncReleaser.hpp index e21d2e34b..f04e85c1b 100644 --- a/src/helpers/sync/SyncReleaser.hpp +++ b/src/helpers/sync/SyncReleaser.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "../memory/Memory.hpp" /* @@ -15,17 +16,19 @@ class CEGLSync; class CSyncReleaser { public: - CSyncReleaser(WP timeline_, uint64_t point_); + CSyncReleaser(SP 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 sync); + Hyprutils::OS::CFileDescriptor mergeSyncFds(const Hyprutils::OS::CFileDescriptor& fd1, const Hyprutils::OS::CFileDescriptor& fd2); + void addReleaseSync(SP sync); private: - WP timeline; - uint64_t point = 0; - SP sync; + SP m_timeline; + uint64_t m_point = 0; + Hyprutils::OS::CFileDescriptor m_fd; + SP m_sync; }; diff --git a/src/helpers/sync/SyncTimeline.cpp b/src/helpers/sync/SyncTimeline.cpp index 46b617bc6..d11205bc3 100644 --- a/src/helpers/sync/SyncTimeline.cpp +++ b/src/helpers/sync/SyncTimeline.cpp @@ -33,6 +33,13 @@ SP 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 +131,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 ba65e004d..bfd704161 100644 --- a/src/helpers/sync/SyncTimeline.hpp +++ b/src/helpers/sync/SyncTimeline.hpp @@ -34,6 +34,7 @@ class CSyncTimeline { bool addWaiter(const std::function& 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 from, uint64_t fromPoint, uint64_t toPoint); diff --git a/src/protocols/DRMSyncobj.cpp b/src/protocols/DRMSyncobj.cpp index 38aab305a..406b55e03 100644 --- a/src/protocols/DRMSyncobj.cpp +++ b/src/protocols/DRMSyncobj.cpp @@ -4,11 +4,82 @@ #include "core/Compositor.hpp" #include "../helpers/sync/SyncTimeline.hpp" #include "../Compositor.hpp" +#include "render/OpenGL.hpp" #include using namespace Hyprutils::OS; -CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(SP resource_, SP surface_) : surface(surface_), resource(resource_) { +CDRMSyncPointState::CDRMSyncPointState(WP resource_, uint64_t point_, bool acquirePoint) : + m_resource(resource_), m_point(point_), m_acquirePoint(acquirePoint) {} + +const uint64_t& CDRMSyncPointState::point() { + return m_point; +} + +WP CDRMSyncPointState::resource() { + return m_resource; +} + +WP CDRMSyncPointState::timeline() { + if (expired()) { + Debug::log(ERR, "CDRMSyncPointState: getting a timeline on a expired point"); + return {}; + } + + return m_resource->timeline; +} + +bool CDRMSyncPointState::expired() { + return !m_resource || !m_resource->timeline; +} + +UP CDRMSyncPointState::createSyncRelease() { + if (expired()) { + Debug::log(ERR, "CDRMSyncPointState: creating a sync releaser on an expired point"); + return nullptr; + } + + if (m_releaseTaken) + Debug::log(ERR, "CDRMSyncPointState: creating a sync releaser on an already created SyncRelease"); + + m_releaseTaken = true; + return makeUnique(m_resource->timeline, m_point); +} + +bool CDRMSyncPointState::addWaiter(const std::function& waiter) { + if (expired()) { + Debug::log(ERR, "CDRMSyncPointState: adding a waiter on an expired point"); + return false; + } + + m_acquireCommitted = true; + return m_resource->timeline->addWaiter(waiter, m_point, 0u); +} + +bool CDRMSyncPointState::comitted() { + return m_acquireCommitted; +} + +CFileDescriptor CDRMSyncPointState::exportAsFD() { + if (expired()) { + Debug::log(ERR, "CDRMSyncPointState: exporting a FD on an expired point"); + return {}; + } + + return m_resource->timeline->exportAsSyncFileFD(m_point); +} + +void CDRMSyncPointState::signal() { + if (expired()) { + Debug::log(ERR, "CDRMSyncPointState: signaling on an expired point"); + return; + } + + m_resource->timeline->signal(m_point); +} + +CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(UP&& resource_, SP surface_) : + surface(surface_), resource(std::move(resource_)) { if UNLIKELY (!good()) return; @@ -23,9 +94,8 @@ CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(SPsetSetReleasePoint([this](CWpLinuxDrmSyncobjSurfaceV1* r, wl_resource* timeline_, uint32_t hi, uint32_t lo) { @@ -34,77 +104,102 @@ CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(SPevents.precommit.registerListener([this](std::any d) { - if ((pending.acquireTimeline || pending.releaseTimeline) && !surface->pending.texture) { - resource->error(WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_BUFFER, "Missing buffer"); - surface->pending.rejected = true; + if (!surface->pending.buffer && surface->pending.newBuffer && !surface->pending.texture) { + removeAllWaiters(); + surface->commitPendingState(surface->pending); + return; // null buffer attached. + } + + if (!surface->pending.buffer && !surface->pending.newBuffer && surface->current.buffer) { + surface->current.bufferDamage.clear(); + surface->current.damage.clear(); + surface->commitPendingState(surface->current); + return; // no new buffer, but we still have current around and a commit happend, commit current again. + } + + if (!surface->pending.buffer && !surface->pending.newBuffer && !surface->current.buffer) { + surface->commitPendingState(surface->pending); // no pending buffer, no current buffer. probably first commit return; } - 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"); - surface->pending.rejected = true; - return; + if (!pendingAcquire.expired()) { + surface->pending.buffer->acquire = makeUnique(std::move(pendingAcquire)); + pendingAcquire = {}; } - if (!pending.acquireTimeline) + if (!pendingRelease.expired()) { + surface->pending.buffer->release = makeUnique(std::move(pendingRelease)); + pendingRelease = {}; + } + + if (protocolError()) return; - if (pending.acquireTimeline && pending.releaseTimeline && pending.acquireTimeline == pending.releaseTimeline) { - if (pending.acquirePoint >= pending.releasePoint) { - 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; + const auto& state = pendingStates.emplace_back(makeShared(surface->pending)); + surface->pending.damage.clear(); + surface->pending.bufferDamage.clear(); + surface->pending.newBuffer = false; + surface->pending.buffer.reset(); + + state->buffer->buffer->syncReleaser = state->buffer->release->createSyncRelease(); + state->buffer->acquire->addWaiter([this, surf = surface, wp = CWeakPointer(*std::prev(pendingStates.end()))] { + if (!surf) 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(); - return; - } - - if (materialized.value()) - return; - - surface->lockPendingState(); - pending.acquireTimeline->timeline->addWaiter([this]() { surface->unlockPendingState(); }, pending.acquirePoint, DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE); + surf->commitPendingState(*wp.lock()); + std::erase(pendingStates, wp); + }); }); +} - 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; +void CDRMSyncobjSurfaceResource::removeAllWaiters() { + for (auto& s : pendingStates) { + if (s && s->buffer && s->buffer->acquire && !s->buffer->acquire->expired()) + s->buffer->acquire->resource()->timeline->removeAllWaiters(); + } + + pendingStates.clear(); +} + +CDRMSyncobjSurfaceResource::~CDRMSyncobjSurfaceResource() { + removeAllWaiters(); +} + +bool CDRMSyncobjSurfaceResource::protocolError() { + if (!surface->pending.texture) { + resource->error(WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_BUFFER, "Missing buffer"); + surface->pending.rejected = true; + return true; + } + + if (!!surface->pending.buffer->acquire != !!surface->pending.buffer->release) { + resource->error(surface->pending.buffer->acquire ? 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 true; + } + + if (surface->pending.buffer->acquire->timeline() == surface->pending.buffer->release->timeline()) { + if (surface->pending.buffer->acquire->point() >= surface->pending.buffer->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 true; } + } - if (pending.acquireTimeline) { - current.acquireTimeline = pending.acquireTimeline; - current.acquirePoint = pending.acquirePoint; - } - - pending.releaseTimeline.reset(); - pending.acquireTimeline.reset(); - }); + return false; } bool CDRMSyncobjSurfaceResource::good() { return resource->resource(); } -CDRMSyncobjTimelineResource::CDRMSyncobjTimelineResource(SP resource_, CFileDescriptor&& fd_) : fd(std::move(fd_)), resource(resource_) { +CDRMSyncobjTimelineResource::CDRMSyncobjTimelineResource(UP&& resource_, CFileDescriptor&& fd_) : fd(std::move(fd_)), resource(std::move(resource_)) { if UNLIKELY (!good()) return; @@ -121,16 +216,20 @@ CDRMSyncobjTimelineResource::CDRMSyncobjTimelineResource(SP CDRMSyncobjTimelineResource::fromResource(wl_resource* res) { - auto data = (CDRMSyncobjTimelineResource*)(((CWpLinuxDrmSyncobjTimelineV1*)wl_resource_get_user_data(res))->data()); - return data ? data->self.lock() : nullptr; +WP CDRMSyncobjTimelineResource::fromResource(wl_resource* res) { + for (const auto& r : PROTO::sync->m_vTimelines) { + if (r && r->resource && r->resource->resource() == res) + return r; + } + + return {}; } bool CDRMSyncobjTimelineResource::good() { return resource->resource(); } -CDRMSyncobjManagerResource::CDRMSyncobjManagerResource(SP resource_) : resource(resource_) { +CDRMSyncobjManagerResource::CDRMSyncobjManagerResource(UP&& resource_) : resource(std::move(resource_)) { if UNLIKELY (!good()) return; @@ -154,28 +253,28 @@ CDRMSyncobjManagerResource::CDRMSyncobjManagerResource(SP(makeShared(resource->client(), resource->version(), id), SURF); + const auto& RESOURCE = PROTO::sync->m_vSurfaces.emplace_back( + makeUnique(makeUnique(resource->client(), resource->version(), id), SURF)); if UNLIKELY (!RESOURCE->good()) { resource->noMemory(); + PROTO::sync->m_vSurfaces.pop_back(); return; } - PROTO::sync->m_vSurfaces.emplace_back(RESOURCE); SURF->syncobj = RESOURCE; LOGM(LOG, "New linux_syncobj at {:x} for surface {:x}", (uintptr_t)RESOURCE.get(), (uintptr_t)SURF.get()); }); resource->setImportTimeline([this](CWpLinuxDrmSyncobjManagerV1* r, uint32_t id, int32_t fd) { - auto RESOURCE = makeShared(makeShared(resource->client(), resource->version(), id), CFileDescriptor{fd}); + const auto& RESOURCE = PROTO::sync->m_vTimelines.emplace_back( + makeUnique(makeUnique(resource->client(), resource->version(), id), CFileDescriptor{fd})); if UNLIKELY (!RESOURCE->good()) { resource->noMemory(); + PROTO::sync->m_vTimelines.pop_back(); return; } - PROTO::sync->m_vTimelines.emplace_back(RESOURCE); - RESOURCE->self = RESOURCE; - LOGM(LOG, "New linux_drm_timeline at {:x}", (uintptr_t)RESOURCE.get()); }); } @@ -184,12 +283,10 @@ bool CDRMSyncobjManagerResource::good() { return resource->resource(); } -CDRMSyncobjProtocol::CDRMSyncobjProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { - drmFD = g_pCompositor->m_iDRMFD; -} +CDRMSyncobjProtocol::CDRMSyncobjProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name), drmFD(g_pCompositor->m_iDRMFD) {} void CDRMSyncobjProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { - const auto RESOURCE = m_vManagers.emplace_back(makeShared(makeShared(client, ver, id))); + const auto& RESOURCE = m_vManagers.emplace_back(makeUnique(makeUnique(client, ver, id))); if UNLIKELY (!RESOURCE->good()) { wl_client_post_no_memory(client); diff --git a/src/protocols/DRMSyncobj.hpp b/src/protocols/DRMSyncobj.hpp index 9895dff17..78905d3d2 100644 --- a/src/protocols/DRMSyncobj.hpp +++ b/src/protocols/DRMSyncobj.hpp @@ -2,64 +2,95 @@ #include #include "WaylandProtocol.hpp" +#include "helpers/sync/SyncReleaser.hpp" #include "linux-drm-syncobj-v1.hpp" #include "../helpers/signal/Signal.hpp" +#include "types/SurfaceState.hpp" #include +#include class CWLSurfaceResource; class CDRMSyncobjTimelineResource; class CSyncTimeline; +struct SSurfaceState; + +class CDRMSyncPointState { + public: + CDRMSyncPointState() = default; + CDRMSyncPointState(WP resource_, uint64_t point_, bool acquirePoint); + ~CDRMSyncPointState() = default; + + const uint64_t& point(); + WP resource(); + WP timeline(); + bool expired(); + Hyprutils::Memory::CUniquePointer createSyncRelease(); + bool addWaiter(const std::function& waiter); + bool comitted(); + Hyprutils::OS::CFileDescriptor exportAsFD(); + void signal(); + + private: + WP m_resource = {}; + uint64_t m_point = 0; + WP m_timeline = {}; + bool m_acquirePoint = false; + bool m_acquireCommitted = false; + bool m_releaseTaken = false; +}; class CDRMSyncobjSurfaceResource { public: - CDRMSyncobjSurfaceResource(SP resource_, SP surface_); + CDRMSyncobjSurfaceResource(UP&& resource_, SP surface_); + ~CDRMSyncobjSurfaceResource(); - bool good(); - - WP surface; - struct { - WP acquireTimeline, releaseTimeline; - uint64_t acquirePoint = 0, releasePoint = 0; - } current, pending; + bool protocolError(); + bool good(); private: - SP resource; + void removeAllWaiters(); + WP surface; + UP resource; + + CDRMSyncPointState pendingAcquire; + CDRMSyncPointState pendingRelease; + std::vector> pendingStates; struct { CHyprSignalListener surfacePrecommit; - CHyprSignalListener surfaceCommit; } listeners; }; class CDRMSyncobjTimelineResource { public: - CDRMSyncobjTimelineResource(SP resource_, Hyprutils::OS::CFileDescriptor&& fd_); + CDRMSyncobjTimelineResource(UP&& resource_, Hyprutils::OS::CFileDescriptor&& fd_); ~CDRMSyncobjTimelineResource() = default; - static SP fromResource(wl_resource*); + static WP fromResource(wl_resource*); bool good(); - WP self; Hyprutils::OS::CFileDescriptor fd; SP timeline; private: - SP resource; + UP resource; }; class CDRMSyncobjManagerResource { public: - CDRMSyncobjManagerResource(SP resource_); + CDRMSyncobjManagerResource(UP&& resource_); + ~CDRMSyncobjManagerResource() = default; bool good(); private: - SP resource; + UP resource; }; class CDRMSyncobjProtocol : public IWaylandProtocol { public: CDRMSyncobjProtocol(const wl_interface* iface, const int& ver, const std::string& name); + ~CDRMSyncobjProtocol() = default; virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id); @@ -69,9 +100,9 @@ class CDRMSyncobjProtocol : public IWaylandProtocol { void destroyResource(CDRMSyncobjSurfaceResource* resource); // - std::vector> m_vManagers; - std::vector> m_vTimelines; - std::vector> m_vSurfaces; + std::vector> m_vManagers; + std::vector> m_vTimelines; + std::vector> m_vSurfaces; // int drmFD = -1; diff --git a/src/protocols/LinuxDMABUF.cpp b/src/protocols/LinuxDMABUF.cpp index b7b915948..720222852 100644 --- a/src/protocols/LinuxDMABUF.cpp +++ b/src/protocols/LinuxDMABUF.cpp @@ -111,6 +111,9 @@ CLinuxDMABuffer::CLinuxDMABuffer(uint32_t id, wl_client* client, Aquamarine::SDM } CLinuxDMABuffer::~CLinuxDMABuffer() { + if (buffer && buffer->resource) + buffer->resource->sendRelease(); + buffer.reset(); listeners.bufferResourceDestroy.reset(); } diff --git a/src/protocols/LinuxDMABUF.hpp b/src/protocols/LinuxDMABUF.hpp index 6c9678787..d55ce8a7f 100644 --- a/src/protocols/LinuxDMABUF.hpp +++ b/src/protocols/LinuxDMABUF.hpp @@ -97,6 +97,7 @@ class CLinuxDMABUFFeedbackResource { class CLinuxDMABUFResource { public: CLinuxDMABUFResource(SP resource_); + ~CLinuxDMABUFResource() = default; bool good(); void sendMods(); diff --git a/src/protocols/SinglePixel.cpp b/src/protocols/SinglePixel.cpp index 4d643a53d..c383dbb3b 100644 --- a/src/protocols/SinglePixel.cpp +++ b/src/protocols/SinglePixel.cpp @@ -24,6 +24,11 @@ CSinglePixelBuffer::CSinglePixelBuffer(uint32_t id, wl_client* client, CHyprColo Debug::log(ERR, "Failed creating a single pixel texture: null texture id"); } +CSinglePixelBuffer::~CSinglePixelBuffer() { + if (resource) + resource->sendRelease(); +} + Aquamarine::eBufferCapability CSinglePixelBuffer::caps() { return Aquamarine::eBufferCapability::BUFFER_CAPABILITY_DATAPTR; } diff --git a/src/protocols/SinglePixel.hpp b/src/protocols/SinglePixel.hpp index bd0607d6d..478f3e354 100644 --- a/src/protocols/SinglePixel.hpp +++ b/src/protocols/SinglePixel.hpp @@ -9,7 +9,7 @@ class CSinglePixelBuffer : public IHLBuffer { public: CSinglePixelBuffer(uint32_t id, wl_client* client, CHyprColor col); - virtual ~CSinglePixelBuffer() = default; + virtual ~CSinglePixelBuffer(); virtual Aquamarine::eBufferCapability caps(); virtual Aquamarine::eBufferType type(); diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp index f7af95041..a9fe33dbb 100644 --- a/src/protocols/core/Compositor.cpp +++ b/src/protocols/core/Compositor.cpp @@ -113,8 +113,8 @@ CWLSurfaceResource::CWLSurfaceResource(SP resource_) : resource(reso return; } - if (stateLocks <= 0) - commitPendingState(); + if (!syncobj) + commitPendingState(pending); }); 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}); }); @@ -428,29 +428,14 @@ CRegion CWLSurfaceResource::accumulateCurrentBufferDamage() { return surfaceDamage.scale(current.scale).transform(wlTransformToHyprutils(invertTransform(current.transform)), trc.x, trc.y).add(current.bufferDamage); } -void CWLSurfaceResource::lockPendingState() { - stateLocks++; -} - -void CWLSurfaceResource::unlockPendingState() { - stateLocks--; - if (stateLocks <= 0) - commitPendingState(); -} - -void CWLSurfaceResource::commitPendingState() { - static auto PDROP = CConfigValue("render:allow_early_buffer_release"); - current = pending; - pending.damage.clear(); - pending.bufferDamage.clear(); - pending.newBuffer = false; - if (!*PDROP) - dropPendingBuffer(); // at this point current.buffer holds the same SP and we don't use pending anymore - - events.roleCommit.emit(); - - if (syncobj && syncobj->current.releaseTimeline && syncobj->current.releaseTimeline->timeline && current.buffer && current.buffer->buffer) - current.buffer->releaser = makeShared(syncobj->current.releaseTimeline->timeline, syncobj->current.releasePoint); +void CWLSurfaceResource::commitPendingState(SSurfaceState& state) { + if (state.newBuffer) { + state.newBuffer = false; + current = state; + state.damage.clear(); + state.bufferDamage.clear(); + state.buffer.reset(); + } if (current.texture) current.texture->m_eTransform = wlTransformToHyprutils(current.transform); @@ -463,14 +448,6 @@ void CWLSurfaceResource::commitPendingState() { // TODO: don't update the entire texture if (role->role() == SURFACE_ROLE_CURSOR && !DAMAGE.empty()) updateCursorShm(DAMAGE); - - // release the buffer if it's synchronous as update() has done everything thats needed - // so we can let the app know we're done. - // Some clients aren't ready to receive a release this early. Should be fine to release it on the next commitPendingState. - if (current.buffer->buffer->isSynchronous() && *PDROP) { - dropCurrentBuffer(); - dropPendingBuffer(); // at this point current.buffer holds the same SP and we don't use pending anymore - } } // TODO: we should _accumulate_ and not replace above if sync @@ -494,11 +471,16 @@ void CWLSurfaceResource::commitPendingState() { nullptr); } - lastBuffer = current.buffer ? current.buffer->buffer : WP{}; + // 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 (!syncobj && current.buffer && current.buffer->buffer && current.buffer->buffer->isSynchronous()) { + // dropCurrentBuffer(); // lets not drop it at all, it will get dropped on next commit if a new buffer arrives. + // solves flickering on nonsyncobj apps on explicit sync. + // } } void CWLSurfaceResource::updateCursorShm(CRegion damage) { - auto buf = current.buffer ? current.buffer->buffer : lastBuffer; + auto buf = current.buffer ? current.buffer->buffer : WP{}; if UNLIKELY (!buf) return; diff --git a/src/protocols/core/Compositor.hpp b/src/protocols/core/Compositor.hpp index 396900179..f958528c5 100644 --- a/src/protocols/core/Compositor.hpp +++ b/src/protocols/core/Compositor.hpp @@ -16,6 +16,7 @@ #include "../../helpers/math/Math.hpp" #include "../types/Buffer.hpp" #include "../types/SurfaceRole.hpp" +#include "../types/SurfaceState.hpp" class CWLOutputResource; class CMonitor; @@ -77,42 +78,15 @@ class CWLSurfaceResource { Vector2D sourceSize(); struct { - CSignal precommit; // before commit - CSignal roleCommit; // commit for role objects, before regular commit - CSignal commit; // after commit + CSignal precommit; // before commit + CSignal commit; // after commit CSignal map; CSignal unmap; CSignal newSubsurface; CSignal destroy; } 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 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 texture; - Vector2D offset; - Vector2D size, bufferSize; - struct { - bool hasDestination = false; - bool hasSource = false; - Vector2D destination; - CBox source; - } viewport; - bool rejected = false; - bool newBuffer = false; - - // - void reset() { - damage.clear(); - bufferDamage.clear(); - transform = WL_OUTPUT_TRANSFORM_NORMAL; - scale = 1; - offset = {}; - size = {}; - } - } current, pending; + SSurfaceState current, pending; std::vector> callbacks; WP self; @@ -130,28 +104,20 @@ class CWLSurfaceResource { SP findFirstPreorder(std::function)> fn); CRegion accumulateCurrentBufferDamage(); void presentFeedback(timespec* when, PHLMONITOR pMonitor, bool discarded = false); - void lockPendingState(); - void unlockPendingState(); + void commitPendingState(SSurfaceState& state); // returns a pair: found surface (null if not found) and surface local coords. // localCoords param is relative to 0,0 of this surface std::pair, Vector2D> at(const Vector2D& localCoords, bool allowsInput = false); private: - SP resource; - wl_client* pClient = nullptr; - - // this is for cursor dumb copy. Due to our (and wayland's...) architecture, - // this stupid-ass hack is used - WP lastBuffer; - - int stateLocks = 0; + SP resource; + wl_client* pClient = nullptr; void destroy(); void releaseBuffers(bool onlyCurrent = true); void dropPendingBuffer(); void dropCurrentBuffer(); - void commitPendingState(); void bfHelper(std::vector> const& nodes, std::function, const Vector2D&, void*)> fn, void* data); SP findFirstPreorderHelper(SP root, std::function)> fn); void updateCursorShm(CRegion damage = CBox{0, 0, INT16_MAX, INT16_MAX}); diff --git a/src/protocols/core/Shm.cpp b/src/protocols/core/Shm.cpp index e0e625604..37a48fd31 100644 --- a/src/protocols/core/Shm.cpp +++ b/src/protocols/core/Shm.cpp @@ -37,6 +37,11 @@ CWLSHMBuffer::CWLSHMBuffer(SP pool_, uint32_t id, int32_t of Debug::log(ERR, "Failed creating a shm texture: null texture id"); } +CWLSHMBuffer::~CWLSHMBuffer() { + if (resource) + resource->sendRelease(); +} + Aquamarine::eBufferCapability CWLSHMBuffer::caps() { return Aquamarine::eBufferCapability::BUFFER_CAPABILITY_DATAPTR; } diff --git a/src/protocols/core/Shm.hpp b/src/protocols/core/Shm.hpp index fef821cb3..fa5f29a40 100644 --- a/src/protocols/core/Shm.hpp +++ b/src/protocols/core/Shm.hpp @@ -33,7 +33,7 @@ class CSHMPool { class CWLSHMBuffer : public IHLBuffer { public: CWLSHMBuffer(SP pool, uint32_t id, int32_t offset, const Vector2D& size, int32_t stride, uint32_t fmt); - virtual ~CWLSHMBuffer() = default; + virtual ~CWLSHMBuffer(); virtual Aquamarine::eBufferCapability caps(); virtual Aquamarine::eBufferType type(); diff --git a/src/protocols/types/Buffer.cpp b/src/protocols/types/Buffer.cpp index 9fb6294f9..2623435ba 100644 --- a/src/protocols/types/Buffer.cpp +++ b/src/protocols/types/Buffer.cpp @@ -18,8 +18,10 @@ void IHLBuffer::unlock() { ASSERT(nLocks >= 0); - if (nLocks == 0) + if (nLocks == 0) { sendRelease(); + syncReleaser.reset(); + } } bool IHLBuffer::locked() { @@ -43,7 +45,7 @@ CHLBufferReference::CHLBufferReference(SP buffer_, SPunlock(); diff --git a/src/protocols/types/Buffer.hpp b/src/protocols/types/Buffer.hpp index bd02e2db4..79cc6ce6f 100644 --- a/src/protocols/types/Buffer.hpp +++ b/src/protocols/types/Buffer.hpp @@ -3,6 +3,7 @@ #include "../../defines.hpp" #include "../../render/Texture.hpp" #include "./WLBuffer.hpp" +#include "protocols/DRMSyncobj.hpp" #include @@ -26,6 +27,7 @@ class IHLBuffer : public Aquamarine::IBuffer { SP texture; bool opaque = false; SP resource; + UP syncReleaser; struct { CHyprSignalListener backendRelease; @@ -43,8 +45,9 @@ class CHLBufferReference { CHLBufferReference(SP buffer, SP surface); ~CHLBufferReference(); - WP buffer; - SP releaser; + WP buffer; + UP acquire; + UP release; private: WP surface; diff --git a/src/protocols/types/DMABuffer.cpp b/src/protocols/types/DMABuffer.cpp index 3f53225c2..2e39bf79f 100644 --- a/src/protocols/types/DMABuffer.cpp +++ b/src/protocols/types/DMABuffer.cpp @@ -36,6 +36,9 @@ CDMABuffer::CDMABuffer(uint32_t id, wl_client* client, Aquamarine::SDMABUFAttrs } CDMABuffer::~CDMABuffer() { + if (resource) + resource->sendRelease(); + closeFDs(); } diff --git a/src/protocols/types/SurfaceState.hpp b/src/protocols/types/SurfaceState.hpp new file mode 100644 index 000000000..cd9be5caa --- /dev/null +++ b/src/protocols/types/SurfaceState.hpp @@ -0,0 +1,35 @@ +#pragma once + +#include "../../helpers/math/Math.hpp" +#include "../WaylandProtocol.hpp" + +class CHLBufferReference; +class CTexture; + +struct SSurfaceState { + 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 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 texture; + Vector2D offset; + Vector2D size, bufferSize; + struct { + bool hasDestination = false; + bool hasSource = false; + Vector2D destination; + CBox source; + } viewport; + bool rejected = false; + bool newBuffer = false; + + // + void reset() { + damage.clear(); + bufferDamage.clear(); + transform = WL_OUTPUT_TRANSFORM_NORMAL; + scale = 1; + offset = {}; + size = {}; + } +}; diff --git a/src/protocols/types/WLBuffer.cpp b/src/protocols/types/WLBuffer.cpp index 4bd115a2b..f2b81c002 100644 --- a/src/protocols/types/WLBuffer.cpp +++ b/src/protocols/types/WLBuffer.cpp @@ -5,7 +5,7 @@ #include "../../helpers/sync/SyncTimeline.hpp" #include -CWLBufferResource::CWLBufferResource(SP resource_) : resource(resource_) { +CWLBufferResource::CWLBufferResource(WP resource_) : resource(resource_.lock()) { if UNLIKELY (!good()) return; @@ -40,7 +40,7 @@ SP CWLBufferResource::fromResource(wl_resource* res) { return data ? data->self.lock() : nullptr; } -SP CWLBufferResource::create(SP resource) { +SP CWLBufferResource::create(WP resource) { auto p = SP(new CWLBufferResource(resource)); p->self = p; return p; diff --git a/src/protocols/types/WLBuffer.hpp b/src/protocols/types/WLBuffer.hpp index 3894affc4..c7e21d4cd 100644 --- a/src/protocols/types/WLBuffer.hpp +++ b/src/protocols/types/WLBuffer.hpp @@ -11,7 +11,7 @@ class CWLSurfaceResource; class CWLBufferResource { public: - static SP create(SP resource); + static SP create(WP resource); static SP fromResource(wl_resource* res); bool good(); @@ -23,7 +23,7 @@ class CWLBufferResource { WP self; private: - CWLBufferResource(SP resource_); + CWLBufferResource(WP resource_); SP resource; diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index a8a38bac2..86e81efb6 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -1292,16 +1292,16 @@ void CHyprOpenGLImpl::renderTexture(SP tex, const CBox& box, float alp } void CHyprOpenGLImpl::renderTextureWithDamage(SP tex, const CBox& box, const CRegion& damage, float alpha, int round, float roundingPower, bool discardActive, - bool allowCustomUV, SP waitTimeline, uint64_t waitPoint) { + bool allowCustomUV) { RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!"); - renderTextureInternalWithDamage(tex, box, alpha, damage, round, roundingPower, discardActive, false, allowCustomUV, true, waitTimeline, waitPoint); + renderTextureInternalWithDamage(tex, box, alpha, damage, round, roundingPower, discardActive, false, allowCustomUV, true); scissor(nullptr); } void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP tex, const CBox& box, float alpha, const CRegion& damage, int round, float roundingPower, bool discardActive, - bool noAA, bool allowCustomUV, bool allowDim, SP waitTimeline, uint64_t waitPoint) { + bool noAA, bool allowCustomUV, bool allowDim) { RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!"); RASSERT((tex->m_iTexID > 0), "Attempted to draw nullptr texture!"); @@ -1324,15 +1324,8 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP tex, const CB if (m_bEndFrame || TRANSFORMS_MATCH) TRANSFORM = wlTransformToHyprutils(invertTransform(m_RenderData.pMonitor->transform)); - Mat3x3 matrix = m_RenderData.monitorProjection.projectBox(newBox, TRANSFORM, newBox.rot); - Mat3x3 glMatrix = m_RenderData.projection.copy().multiply(matrix); - - if (waitTimeline != nullptr) { - if (!waitForTimelinePoint(waitTimeline, waitPoint)) { - Debug::log(ERR, "renderTextureInternalWithDamage: failed to wait for explicit sync point {}", waitPoint); - return; - } - } + Mat3x3 matrix = m_RenderData.monitorProjection.projectBox(newBox, TRANSFORM, newBox.rot); + Mat3x3 glMatrix = m_RenderData.projection.copy().multiply(matrix); CShader* shader = nullptr; @@ -2915,11 +2908,11 @@ std::vector CHyprOpenGLImpl::getDRMFormats() { return drmFormats; } -SP CHyprOpenGLImpl::createEGLSync(CFileDescriptor fenceFD) { +SP CHyprOpenGLImpl::createEGLSync(int fenceFD) { std::vector attribs; CFileDescriptor dupFd; - if (fenceFD.isValid()) { - dupFd = fenceFD.duplicate(); + if (fenceFD >= 0) { + dupFd = CFileDescriptor{fcntl(fenceFD, F_DUPFD_CLOEXEC, 0)}; if (!dupFd.isValid()) { Debug::log(ERR, "createEGLSync: dup failed"); return nullptr; @@ -2953,27 +2946,6 @@ SP CHyprOpenGLImpl::createEGLSync(CFileDescriptor fenceFD) { return eglsync; } -bool CHyprOpenGLImpl::waitForTimelinePoint(SP timeline, uint64_t point) { - auto fd = timeline->exportAsSyncFileFD(point); - if (!fd.isValid()) { - Debug::log(ERR, "waitForTimelinePoint: failed to get a fd from explicit timeline"); - return false; - } - - auto sync = g_pHyprOpenGL->createEGLSync(std::move(fd)); - if (!sync) { - Debug::log(ERR, "waitForTimelinePoint: failed to get an eglsync from explicit timeline"); - return false; - } - - if (!sync->wait()) { - Debug::log(ERR, "waitForTimelinePoint: failed to wait on an eglsync from explicit timeline"); - return false; - } - - return true; -} - void SRenderModifData::applyToBox(CBox& box) { if (!enabled) return; @@ -3043,17 +3015,10 @@ CEGLSync::~CEGLSync() { Debug::log(ERR, "eglDestroySyncKHR failed"); } +CFileDescriptor&& CEGLSync::takeFD() { + return std::move(m_iFd); +} + CFileDescriptor& CEGLSync::fd() { return m_iFd; } - -bool CEGLSync::wait() { - if (sync == EGL_NO_SYNC_KHR) - return false; - - if (g_pHyprOpenGL->m_sProc.eglWaitSyncKHR(g_pHyprOpenGL->m_pEglDisplay, sync, 0) != EGL_TRUE) { - Debug::log(ERR, "eglWaitSyncKHR failed"); - return false; - } - return true; -} diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp index 110795918..3933bfc43 100644 --- a/src/render/OpenGL.hpp +++ b/src/render/OpenGL.hpp @@ -148,10 +148,10 @@ class CEGLSync { public: ~CEGLSync(); - EGLSyncKHR sync = nullptr; + EGLSyncKHR sync = nullptr; - Hyprutils::OS::CFileDescriptor& fd(); - bool wait(); + Hyprutils::OS::CFileDescriptor&& takeFD(); + Hyprutils::OS::CFileDescriptor& fd(); private: CEGLSync() = default; @@ -177,7 +177,7 @@ class CHyprOpenGLImpl { void renderRectWithDamage(const CBox&, const CHyprColor&, const CRegion& damage, int round = 0, float roundingPower = 2.0f); void renderTexture(SP, const CBox&, float a, int round = 0, float roundingPower = 2.0f, bool discardActive = false, bool allowCustomUV = false); void renderTextureWithDamage(SP, const CBox&, const CRegion& damage, float a, int round = 0, float roundingPower = 2.0f, bool discardActive = false, - bool allowCustomUV = false, SP waitTimeline = nullptr, uint64_t waitPoint = 0); + bool allowCustomUV = false); void renderTextureWithBlur(SP, const CBox&, float a, SP pSurface, int round = 0, float roundingPower = 2.0f, bool blockBlurOptimization = false, float blurA = 1.f, float overallA = 1.f); void renderRoundedShadow(const CBox&, int round, float roundingPower, int range, const CHyprColor& color, float a = 1.0); @@ -230,8 +230,7 @@ class CHyprOpenGLImpl { uint32_t getPreferredReadFormat(PHLMONITOR pMonitor); std::vector getDRMFormats(); EGLImageKHR createEGLImage(const Aquamarine::SDMABUFAttrs& attrs); - SP createEGLSync(Hyprutils::OS::CFileDescriptor fenceFD); - bool waitForTimelinePoint(SP timeline, uint64_t point); + SP createEGLSync(int fence = -1); SCurrentRenderData m_RenderData; @@ -315,7 +314,7 @@ class CHyprOpenGLImpl { CFramebuffer* blurMainFramebufferWithDamage(float a, CRegion* damage); void renderTextureInternalWithDamage(SP, const CBox& box, float a, const CRegion& damage, int round = 0, float roundingPower = 2.0f, bool discardOpaque = false, - bool noAA = false, bool allowCustomUV = false, bool allowDim = false, SP = nullptr, uint64_t waitPoint = 0); + bool noAA = false, bool allowCustomUV = false, bool allowDim = false); void renderTexturePrimitive(SP tex, const CBox& box); void renderSplash(cairo_t* const, cairo_surface_t* const, double offset, const Vector2D& size); diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 88de1adab..e7d3630aa 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1450,13 +1450,6 @@ static hdr_output_metadata createHDRMetadata(SImageDescription settings, A bool CHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) { pMonitor->commitSeq++; - // apply timelines for explicit sync - // save inFD otherwise reset will reset it - CFileDescriptor inFD{pMonitor->output->state->state().explicitInFence}; - pMonitor->output->state->resetExplicitFences(); - if (inFD.isValid()) - pMonitor->output->state->setExplicitInFence(inFD.get()); - static auto PPASS = CConfigValue("render:cm_fs_passthrough"); const bool PHDR = pMonitor->imageDescription.transferFunction == CM_TRANSFER_FUNCTION_ST2084_PQ; @@ -1517,7 +1510,7 @@ bool CHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) { bool ok = pMonitor->state.commit(); if (!ok) { - if (inFD.isValid()) { + if (pMonitor->inFence.isValid()) { Debug::log(TRACE, "Monitor state commit failed, retrying without a fence"); pMonitor->output->state->resetExplicitFences(); ok = pMonitor->state.commit(); @@ -1537,21 +1530,20 @@ bool CHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) { return ok; Debug::log(TRACE, "Explicit: {} presented", explicitPresented.size()); - auto sync = g_pHyprOpenGL->createEGLSync({}); + auto sync = g_pHyprOpenGL->createEGLSync(pMonitor->inFence.get()); if (!sync) 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->buffer || !e->current.buffer->buffer->syncReleaser) continue; - e->current.buffer->releaser->addReleaseSync(sync); + e->current.buffer->buffer->syncReleaser->addReleaseSync(sync); } } explicitPresented.clear(); - pMonitor->output->state->resetExplicitFences(); return ok; @@ -2269,7 +2261,7 @@ void CHyprRenderer::endRender() { auto explicitOptions = getExplicitSyncSettings(PMONITOR->output); if (PMONITOR->inTimeline && explicitOptions.explicitEnabled && explicitOptions.explicitKMSEnabled) { - auto sync = g_pHyprOpenGL->createEGLSync({}); + auto sync = g_pHyprOpenGL->createEGLSync(); if (!sync) { Debug::log(ERR, "renderer: couldn't create an EGLSync for out in endRender"); return; @@ -2281,13 +2273,13 @@ void CHyprRenderer::endRender() { return; } - auto fd = PMONITOR->inTimeline->exportAsSyncFileFD(PMONITOR->commitSeq); - if (!fd.isValid()) { + PMONITOR->inFence = CFileDescriptor{PMONITOR->inTimeline->exportAsSyncFileFD(PMONITOR->commitSeq)}; + if (!PMONITOR->inFence.isValid()) { Debug::log(ERR, "renderer: couldn't export from sync timeline in endRender"); return; } - PMONITOR->output->state->setExplicitInFence(fd.take()); + PMONITOR->output->state->setExplicitInFence(PMONITOR->inFence.get()); } else { if (isNvidia() && *PNVIDIAANTIFLICKER) glFinish(); diff --git a/src/render/pass/SurfacePassElement.cpp b/src/render/pass/SurfacePassElement.cpp index 46c6d2214..813ab8ea4 100644 --- a/src/render/pass/SurfacePassElement.cpp +++ b/src/render/pass/SurfacePassElement.cpp @@ -51,14 +51,6 @@ void CSurfacePassElement::draw(const CRegion& damage) { if (!TEXTURE->m_iTexID) 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)) { - Debug::log(ERR, "Renderer: failed to wait for explicit timeline"); - return; - } - } - const auto INTERACTIVERESIZEINPROGRESS = data.pWindow && g_pInputManager->currentlyDraggedWindow && g_pInputManager->dragMode == MBIND_RESIZE; TRACY_GPU_ZONE("RenderSurface");