commit febb5404d3d384296146ab6e536c2cee2f084241 Author: Tom Englund Date: Mon May 25 12:51:54 2026 +0200 drm: refactor merging and exporting fences lets move them to drm helper instead of reinventing the wheel twice. diff --git a/src/helpers/Drm.cpp b/src/helpers/Drm.cpp index 4f3119f8..665bb786 100644 --- a/src/helpers/Drm.cpp +++ b/src/helpers/Drm.cpp @@ -4,7 +4,26 @@ #include #include #include +#include #include "Drm.hpp" +#include + +#ifdef __linux__ +#include +#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; namespace { using SDRMNodePair = std::array; @@ -67,3 +86,56 @@ bool DRM::sameGpu(int fd1, int fd2) { return same; } + +int DRM::doIoctl(int fd, unsigned long request, void* arg) { + int ret; + + do { + ret = ioctl(fd, request, arg); + } while (ret == -1 && (errno == EINTR || errno == EAGAIN)); + return ret; +} + +// https://www.kernel.org/doc/html/latest/driver-api/dma-buf.html#c.dma_buf_export_sync_file +// returns a sync file that will be signalled when dmabuf is ready to be read +CFileDescriptor DRM::exportFence(int fd) { + if (fd < 0) + return {}; + + CFileDescriptor fence; +#ifdef __linux__ + dma_buf_export_sync_file request{ + .flags = DMA_BUF_SYNC_READ, + .fd = -1, + }; + + if (doIoctl(fd, DMA_BUF_IOCTL_EXPORT_SYNC_FILE, &request) == 0) + fence = CFileDescriptor{request.fd}; +#endif + + return fence; +} + +CFileDescriptor DRM::mergeFence(const CFileDescriptor& fd1, const CFileDescriptor& fd2) { + if (!fd1.isValid() || !fd2.isValid()) + return {}; + + CFileDescriptor mergedFence; +#ifdef __linux__ + const std::string name = "merged release fence"; + struct sync_merge_data data{ + .name = {}, // zero-initialize name[] + .fd2 = fd2.get(), + .fence = -1, + }; + + std::ranges::copy_n(name.c_str(), std::min(name.size() + 1, sizeof(data.name)), data.name); + + if (doIoctl(fd1.get(), SYNC_IOC_MERGE, &data) == 0) + mergedFence = CFileDescriptor(data.fence); + else + mergedFence = {}; + +#endif + return mergedFence; +} diff --git a/src/helpers/Drm.hpp b/src/helpers/Drm.hpp index 755ee050..ac05c046 100644 --- a/src/helpers/Drm.hpp +++ b/src/helpers/Drm.hpp @@ -2,8 +2,12 @@ #include #include +#include namespace DRM { - std::optional devIDFromFD(int fd); - bool sameGpu(int fd1, int fd2); + std::optional devIDFromFD(int fd); + bool sameGpu(int fd1, int fd2); + int doIoctl(int fd, unsigned long request, void* arg); + Hyprutils::OS::CFileDescriptor exportFence(int fd); + Hyprutils::OS::CFileDescriptor mergeFence(const Hyprutils::OS::CFileDescriptor& fd1, const Hyprutils::OS::CFileDescriptor& fd2); } diff --git a/src/helpers/sync/SyncReleaser.cpp b/src/helpers/sync/SyncReleaser.cpp index fbc585d0..c65eae4e 100644 --- a/src/helpers/sync/SyncReleaser.cpp +++ b/src/helpers/sync/SyncReleaser.cpp @@ -1,21 +1,7 @@ #include "SyncReleaser.hpp" #include "SyncTimeline.hpp" #include "../../render/OpenGL.hpp" -#include - -#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 +#include "../../helpers/Drm.hpp" using namespace Hyprutils::OS; @@ -35,28 +21,9 @@ CSyncReleaser::~CSyncReleaser() { m_timeline->signal(m_point); } -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(), - .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::addSyncFileFd(const Hyprutils::OS::CFileDescriptor& syncFd) { if (m_fd.isValid()) - m_fd = mergeSyncFds(m_fd, syncFd); + m_fd = DRM::mergeFence(m_fd, syncFd); else m_fd = syncFd.duplicate(); } diff --git a/src/protocols/types/DMABuffer.cpp b/src/protocols/types/DMABuffer.cpp index 37c46338..1a3f787d 100644 --- a/src/protocols/types/DMABuffer.cpp +++ b/src/protocols/types/DMABuffer.cpp @@ -3,14 +3,9 @@ #include "../../desktop/view/LayerSurface.hpp" #include "../../render/Renderer.hpp" #include "../../helpers/Format.hpp" +#include "helpers/Drm.hpp" #include -#if defined(__linux__) -#include -#include -#endif -#include - using namespace Hyprutils::OS; using namespace Hyprgraphics::Egl; @@ -92,22 +87,11 @@ void CDMABuffer::closeFDs() { m_attrs.planes = 0; } -static int doIoctl(int fd, unsigned long request, void* arg) { - int ret; - - do { - ret = ioctl(fd, request, arg); - } while (ret == -1 && (errno == EINTR || errno == EAGAIN)); - return ret; -} - -// https://www.kernel.org/doc/html/latest/driver-api/dma-buf.html#c.dma_buf_export_sync_file -// returns a sync file that will be signalled when dmabuf is ready to be read CFileDescriptor CDMABuffer::exportSyncFile() { if (!good()) return {}; -#if !defined(__linux__) +#ifndef __linux__ return {}; #else std::vector syncFds; @@ -124,13 +108,9 @@ CFileDescriptor CDMABuffer::exportSyncFile() { continue; } - dma_buf_export_sync_file request{ - .flags = DMA_BUF_SYNC_READ, - .fd = -1, - }; - - if (doIoctl(fd, DMA_BUF_IOCTL_EXPORT_SYNC_FILE, &request) == 0) - syncFds.emplace_back(request.fd); + CFileDescriptor fence = DRM::exportFence(fd); + if (fence.isValid()) + syncFds.emplace_back(std::move(fence)); } if (syncFds.empty()) @@ -143,19 +123,7 @@ CFileDescriptor CDMABuffer::exportSyncFile() { continue; } - const std::string name = "merged release fence"; - struct sync_merge_data data{ - .name = {}, // zero-initialize name[] - .fd2 = fd.get(), - .fence = -1, - }; - - std::ranges::copy_n(name.c_str(), std::min(name.size() + 1, sizeof(data.name)), data.name); - - if (doIoctl(syncFd.get(), SYNC_IOC_MERGE, &data) == 0) - syncFd = CFileDescriptor(data.fence); - else - syncFd = {}; + syncFd = DRM::mergeFence(syncFd, fd); } return syncFd;