diff options
| author | PancakeTAS <pancake@mgnet.work> | 2026-05-18 11:21:25 +0200 |
|---|---|---|
| committer | PancakeTAS <pancake@mgnet.work> | 2026-05-18 11:21:25 +0200 |
| commit | ee13963e4088ebe7164f8a51bf97bc0f8b5e0af1 (patch) | |
| tree | c13996a27cd9105f89cc7de78bfdc77f3f8b0a10 | |
| parent | Implement (non-timeline) sync objects (diff) | |
Extend sync objects with timeline support
| -rw-r--r-- | src/syncobject.cpp | 103 | ||||
| -rw-r--r-- | src/syncobject.hpp | 67 |
2 files changed, 151 insertions, 19 deletions
diff --git a/src/syncobject.cpp b/src/syncobject.cpp index 59c06fd..8d5e8b5 100644 --- a/src/syncobject.cpp +++ b/src/syncobject.cpp @@ -5,6 +5,7 @@ #include <cstdint> #include <optional> +#include <stdexcept> #include <vector> #include <unistd.h> @@ -50,12 +51,13 @@ int SyncObject::exportFd() const { return args.fd; } -void SyncObject::importSyncFile(int syncfile_fd, bool close) const { +void SyncObject::importSyncFile(int syncfile_fd, uint64_t point, bool close) const { try { drm_syncobj_handle args{ .handle = this->m_handle, .flags = DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE, - .fd = syncfile_fd + .fd = syncfile_fd, + .point = point }; ioctl::perform(this->m_fd, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, args); } catch (...) { @@ -71,26 +73,64 @@ void SyncObject::importSyncFile(int syncfile_fd, bool close) const { } } -int SyncObject::exportSyncFile() const { +int SyncObject::exportSyncFile(uint64_t point) const { drm_syncobj_handle args{ .handle = this->m_handle, - .flags = DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE + .flags = DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE, + .point = point }; ioctl::perform(this->m_fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, args); return args.fd; } -void SyncObject::signal(int fd, const std::vector<uint32_t>& objects) { +void SyncObject::registerEventFd(int eventfd_fd, uint64_t point, bool waitAvailable) const { + drm_syncobj_eventfd args{ + .handle = this->m_handle, + .flags = waitAvailable ? DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE : 0U, + .point = point, + .fd = eventfd_fd + }; + ioctl::perform(this->m_fd, DRM_IOCTL_SYNCOBJ_EVENTFD, args); +} + +void SyncObject::transfer(uint32_t dstObject, uint64_t srcPoint, uint64_t dstPoint) const { + drm_syncobj_transfer args{ + .src_handle = this->m_handle, + .dst_handle = dstObject, + .src_point = srcPoint, + .dst_point = dstPoint + }; + ioctl::perform(this->m_fd, DRM_IOCTL_SYNCOBJ_TRANSFER, args); +} + +void SyncObject::signal( + int fd, + const std::vector<uint32_t>& objects, + const std::vector<uint64_t>& points +) { if (objects.empty()) { return; } - drm_syncobj_array args{ + if (points.empty()) { + drm_syncobj_array args{ + .handles = reinterpret_cast<uint64_t>(objects.data()), + .count_handles = static_cast<uint32_t>(objects.size()) + }; + ioctl::perform(fd, DRM_IOCTL_SYNCOBJ_SIGNAL, args); + } + + if (points.size() != objects.size()) { + throw std::invalid_argument("points size must match objects size"); + } + + drm_syncobj_timeline_array args{ .handles = reinterpret_cast<uint64_t>(objects.data()), + .points = reinterpret_cast<uint64_t>(points.data()), .count_handles = static_cast<uint32_t>(objects.size()) }; - ioctl::perform(fd, DRM_IOCTL_SYNCOBJ_SIGNAL, args); + ioctl::perform(fd, DRM_IOCTL_SYNCOBJ_TIMELINE_SIGNAL, args); } void SyncObject::reset(int fd, const std::vector<uint32_t>& objects) { @@ -108,6 +148,7 @@ void SyncObject::reset(int fd, const std::vector<uint32_t>& objects) { uint32_t SyncObject::wait( int fd, const std::vector<uint32_t>& objects, + const std::vector<uint64_t>& points, int64_t timeout, bool waitAll, bool waitEmpty, @@ -122,8 +163,30 @@ uint32_t SyncObject::wait( waitEmpty = false; } - drm_syncobj_wait args{ + if (points.empty()) { + drm_syncobj_wait args{ + .handles = reinterpret_cast<uint64_t>(objects.data()), + .timeout_nsec = timeout, + .count_handles = static_cast<uint32_t>(objects.size()), + .flags = + (waitAll ? DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL : 0U) | + (waitEmpty ? DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT : 0U) | + (waitAvailable ? DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE : 0U) | + (deadlineHint.has_value() ? DRM_SYNCOBJ_WAIT_FLAGS_WAIT_DEADLINE : 0U), + .deadline_nsec = deadlineHint.value_or(0) + }; + ioctl::perform(fd, DRM_IOCTL_SYNCOBJ_WAIT, args); + + return args.first_signaled; + } + + if (points.size() != objects.size()) { + throw std::invalid_argument("points size must match objects size"); + } + + drm_syncobj_timeline_wait args{ .handles = reinterpret_cast<uint64_t>(objects.data()), + .points = reinterpret_cast<uint64_t>(points.data()), .timeout_nsec = timeout, .count_handles = static_cast<uint32_t>(objects.size()), .flags = @@ -133,11 +196,33 @@ uint32_t SyncObject::wait( (deadlineHint.has_value() ? DRM_SYNCOBJ_WAIT_FLAGS_WAIT_DEADLINE : 0U), .deadline_nsec = deadlineHint.value_or(0) }; - ioctl::perform(fd, DRM_IOCTL_SYNCOBJ_WAIT, args); + ioctl::perform(fd, DRM_IOCTL_SYNCOBJ_TIMELINE_WAIT, args); return args.first_signaled; } +std::vector<uint64_t> SyncObject::query( + int fd, + const std::vector<uint32_t>& objects, + bool lastSubmitted +) { + if (objects.empty()) { + return {}; + } + + std::vector<uint64_t> points(objects.size()); + + drm_syncobj_timeline_array args{ + .handles = reinterpret_cast<uint64_t>(objects.data()), + .points = reinterpret_cast<uint64_t>(points.data()), + .count_handles = static_cast<uint32_t>(objects.size()), + .flags = lastSubmitted ? DRM_SYNCOBJ_QUERY_FLAGS_LAST_SUBMITTED : 0U + }; + ioctl::perform(fd, DRM_IOCTL_SYNCOBJ_QUERY, args); + + return points; +} + void SyncObject::destruct() noexcept { if (this->m_fd < 0) { return; diff --git a/src/syncobject.hpp b/src/syncobject.hpp index cf30078..6221753 100644 --- a/src/syncobject.hpp +++ b/src/syncobject.hpp @@ -63,10 +63,11 @@ namespace drm { /// Import a sync file (DRM fence) into the sync object /// /// @param syncfile_fd File descriptor to import + /// @param point Timeline point to export for timeline sync objects /// @param close Close the file descriptor after import (regardless of success) /// @throws drm::ioctl::Exception on failure /// - void importSyncFile(int syncfile_fd, bool close = true) const; + void importSyncFile(int syncfile_fd, uint64_t point = 0, bool close = true) const; /// /// Export a sync file from the DRM fence within the sync object @@ -74,19 +75,48 @@ namespace drm { /// Any subsequent modifications to the sync object are not applied to /// the exported sync file. /// + /// @param point Timeline point to export for timeline sync objects /// @throws drm::ioctl::Exception on failure /// @returns Exported file descriptor /// - [[nodiscard]] int exportSyncFile() const; + [[nodiscard]] int exportSyncFile(uint64_t point = 0) const; + + /// + /// Register an eventfd to be signaled by a sync object + /// + /// @param eventfd_fd File descriptor to signal + /// @param point Timeline point to signal for timeline sync objects + /// @param waitAvailable Only wait for a fence to be available, as opposed to signaled. + /// @throws drm::ioctl::Exception on failure + /// + void registerEventFd(int eventfd_fd, uint64_t point = 0, bool waitAvailable = false) const; + + /// + /// Copy a DRM fence into another sync object + /// + /// @param dstObject Destination sync object handle + /// @param srcPoint Timeline point to copy from + /// @param dstPoint Timeline point to copy into + /// @throws drm::ioctl::Exception on failure + /// + void transfer(uint32_t dstObject, uint64_t srcPoint = 0, uint64_t dstPoint = 0) const; /// /// Emplace signaled fences into a list of sync objects /// + /// When not using timeline sync objects, pass an empty list of timeline points. + /// /// @param fd DRM node file descriptor /// @param objects List of sync object handles + /// @param points List of timeline points to signal for each sync object /// @throws drm::ioctl::Exception on failure + /// @throws std::invalid_argument invalid points size /// - static void signal(int fd, const std::vector<uint32_t>& objects); + static void signal( + int fd, + const std::vector<uint32_t>& objects, + const std::vector<uint64_t>& points = {} + ); /// /// Remove the DRM fence from a list of sync objects @@ -97,16 +127,11 @@ namespace drm { /// static void reset(int fd, const std::vector<uint32_t>& objects); - /// How to handle empty sync objects when waiting - enum class EmptyFlags { - /// Return -EINVAL if any sync object is empty - Throw, - /// Block until a fen - }; - /// /// Wait for a list of sync objects to be signaled /// + /// When not using timeline sync objects, pass an empty list of timeline points. + /// /// If waitEmpty or waitAvailable is not set, any empty sync object will result in /// an error. /// @@ -116,18 +141,21 @@ namespace drm { /// /// @param fd DRM node file descriptor /// @param objects List of sync object handles + /// @param points List of timeline points to wait on for each sync object /// @param timeout Absolute timeout in nanoseconds, or zero for polling /// @param waitAll Wait for all sync objects, as opposed to a single one /// @param waitEmpty Wait for sync objects, which do not yet have a fence emplaced /// @param waitAvailable Only wait for a fence to be available, as opposed to signaled. /// @param deadlineHint Set a CLOCK_MONOTONIC deadline hint in nanoseconds on all fences /// @throws drm::ioctl::Exception on failure + /// @throws std::invalid_argument invalid points size /// @return Handle which was signaled first, when waitAll is false. /// [[nodiscard]] static uint32_t wait( int fd, const std::vector<uint32_t>& objects, + const std::vector<uint64_t>& points = {}, int64_t timeout = 0, bool waitAll = false, bool waitEmpty = false, @@ -135,6 +163,24 @@ namespace drm { std::optional<uint64_t> deadlineHint = std::nullopt ); + /// + /// Query the timeline points of a list of sync objects + /// + /// This should only be used with timeline sync objects. + /// + /// @param fd DRM node file descriptor + /// @param objects List of sync object handles + /// @param lastSubmitted Query the last submitted instead of signaled point. + /// @throws drm::ioctl::Exception on failure + /// @returns List of timeline points + /// + [[nodiscard]] + static std::vector<uint64_t> query( + int fd, + const std::vector<uint32_t>& objects, + bool lastSubmitted = false + ); + // Into handle operator uint32_t() const { return this->m_handle; } @@ -175,4 +221,5 @@ namespace drm { void destruct() noexcept; }; + } |
