diff options
| author | PancakeTAS <pancake@mgnet.work> | 2026-06-23 21:21:50 +0200 |
|---|---|---|
| committer | PancakeTAS <pancake@mgnet.work> | 2026-06-23 21:24:04 +0200 |
| commit | 69fe1e6c0ba19a75005f7e1ea662ac4595971e7b (patch) | |
| tree | b80b1c5b7f9413727d2fab1e745b1721d32c7971 | |
| parent | Refactor buildscript (diff) | |
Significantly reduce line count and code duplication
| -rw-r--r-- | CMakeLists.txt | 3 | ||||
| -rw-r--r-- | include/drm++/ioctl.hpp | 16 | ||||
| -rw-r--r-- | include/drm++/syncobject.hpp | 220 | ||||
| -rw-r--r-- | src/syncobject.cpp | 487 |
4 files changed, 300 insertions, 426 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index d2d5b7c..497f394 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,8 +19,7 @@ target_include_directories(drm++ SYSTEM set_target_properties(drm++ PROPERTIES CXX_STANDARD 20 - CXX_STANDARD_REQUIRED ON - CXX_VISIBILITY_PRESET hidden) + CXX_STANDARD_REQUIRED ON) set_target_properties(drm++ PROPERTIES SKIP_RPATH ON) diff --git a/include/drm++/ioctl.hpp b/include/drm++/ioctl.hpp index 1851df6..1a68dae 100644 --- a/include/drm++/ioctl.hpp +++ b/include/drm++/ioctl.hpp @@ -11,28 +11,30 @@ namespace drm::ioctl { -/// Type of ioctl() error +/// Type of ioctl() error. enum class Error : u8 { BadFileDescriptor, InvalidArgument, NotSupported, - Other //!< check errno field + Other //!< Check errno field }; -/// Exception class wrapping around ioctl() +/// Exception class wrapping around ioctl(). class Exception : public std::exception { public: - /// Construct an exception from errno + /// Construct an exception from errno. explicit Exception(int fd, unsigned long op); + /// Convert the exception into human-readable form. + std::string readable(); + + // Private access GETTER(fd) GETTER(op) GETTER(code) GETTER(syserrno) - /// Convert the exception into human-readable form. - std::string readable(); - + // Default operators and destructor DEFAULT_OPERATORS(Exception) ~Exception() override; private: diff --git a/include/drm++/syncobject.hpp b/include/drm++/syncobject.hpp index 9751559..f530c49 100644 --- a/include/drm++/syncobject.hpp +++ b/include/drm++/syncobject.hpp @@ -9,70 +9,34 @@ namespace drm::syncobj { -/// Wait modes for waiting on binary sync objects -enum class WaitMode : u8 { - NoWaitEmpty, //!< Return -EINVAL when waiting on an empty sync object - WaitEmpty, //!< Wait for empty sync objects to be filled and signaled - WaitAvailable //!< Wait for empty sync objects to be filled, but do not wait for signaling -}; - +class SyncObject; class TimelineSyncObject; -/// A (binary) synchronization object is a reference-counted container which can hold a DRM fence -/// @throws drm::ioctl::Exception on failure -class SyncObject { +/// Common base class for SyncObject and TimelineSyncObject. +class SyncObjectBase { + friend class SyncObject; + friend class TimelineSyncObject; public: - /// Create a new sync object - SyncObject(int fd, bool signaled = false); + /// Create a new sync object. + SyncObjectBase(int fd, bool signaled = false); - /// Import an existing sync object + /// Import an existing sync object. /// @param close Close syncobj_fd after import (regardless of success) - SyncObject(int fd, int syncobj_fd, bool close = true); + SyncObjectBase(int fd, int syncobj_fd, bool close = true); - /// Export a new reference to sync object, increasing the reference counter + /// Export a new reference to sync object, incrementing the reference count. [[nodiscard]] int exportFd() const; - /// Import a sync file (DRM fence) into the sync object - /// @param close Close syncfile_fd after import (regardless of success) - void importSyncFile(int syncfile_fd, bool close = true) const; - - /// Export a sync file from the DRM fence within the sync object - /// Any subsequent modifications to the sync object are not applied to the exported sync file - [[nodiscard]] int exportSyncFile() const; - - /// Transfer a DRM fence into another sync object - void transfer(const SyncObject& dest) const; - void transfer(const TimelineSyncObject& dest, u64 destPoint) const; - - /// Signal the sync object by emplacing a signaled fence into it - void signal() const; - - /// Reset the sync object by removing the fence from it - void reset() const; - - /// Wait for the sync object to be signaled - /// @param timeout Absolute timeout in nanoseconds, or zero for polling - /// @param deadlineHint Set a CLOCK_MONOTONIC deadline hint in nanoseconds on the fence - void wait( - s64 timeout, - WaitMode waitMode = WaitMode::NoWaitEmpty, - std::optional<u64> deadlineHint = std::nullopt - ) const; - - /// Register an eventfd to the sync object - /// @param waitAvailable Trigger when a fence is emplaced, not when it is signaled - void registerEventFd(int eventfd_fd, bool waitAvailable = false) const; - // Private access GETTER(fd) GETTER(handle) // Move constructor/operator - SyncObject(SyncObject&& other) noexcept : m_fd(other.m_fd), m_handle(other.m_handle) { + SyncObjectBase(SyncObjectBase&& other) noexcept : m_fd(other.m_fd), m_handle(other.m_handle) { other.m_fd = -1; // invalidate other } - SyncObject& operator=(SyncObject&& other) noexcept { + SyncObjectBase& operator=(SyncObjectBase&& other) noexcept { if (this != &other) { this->destruct(); this->m_handle = other.m_handle; @@ -84,20 +48,23 @@ public: } // Copy constructor/operator - SyncObject(const SyncObject& other) - : SyncObject(other.m_fd, other.exportFd(), true) {} + SyncObjectBase(const SyncObjectBase& other) + : SyncObjectBase(other.m_fd, other.exportFd(), true) {} - SyncObject& operator=(const SyncObject& other) { + SyncObjectBase& operator=(const SyncObjectBase& other) { if (this != &other) { const int fd{other.exportFd()}; - *this = SyncObject(other.m_fd, fd, true); + *this = SyncObjectBase(other.m_fd, fd, true); } return *this; } // Destructor - ~SyncObject(); + ~SyncObjectBase() noexcept { + this->destruct(); + } + private: int m_fd; // indicates object validity (>= 0) u32 m_handle; @@ -105,37 +72,78 @@ private: void destruct() noexcept; }; -/// A timeline synchronization object can hold multiple DRM fences, identified via a -/// monotonically increasing 64-bit unsigned integer "point" +/// Wait modes for waiting on binary sync objects. +enum class WaitMode : u8 { + NoWaitEmpty, //!< Return -EINVAL when waiting on an empty sync object + WaitEmpty, //!< Wait for empty sync objects to be filled and signaled + WaitAvailable //!< Wait for empty sync objects to be filled, but do not wait for signaling +}; + +/// A (binary) synchronization object is a reference-counted container which can hold a DRM fence. +/// Requires DRM_CAP_SYNCOBJ. /// @throws drm::ioctl::Exception on failure -class TimelineSyncObject { +class SyncObject : public SyncObjectBase { public: - /// Create a new sync object - TimelineSyncObject(int fd); + using SyncObjectBase::SyncObjectBase; + using SyncObjectBase::operator=; - /// Import an existing sync object - /// @param close Close syncobj_fd after import (regardless of success) - TimelineSyncObject(int fd, int syncobj_fd, bool close = true); + /// Import a sync file (DRM fence) into the sync object. + /// @param close Close syncfile_fd after import (regardless of success) + void importSyncFile(int syncfile_fd, bool close = true) const; - /// Export a new reference to sync object, increasing the reference counter - [[nodiscard]] int exportFd() const; + /// Export a sync file from the DRM fence within the sync object. + /// Any subsequent modifications to the sync object are not applied to the exported sync file + [[nodiscard]] int exportSyncFile() const; + + /// Transfer a DRM fence into another binary sync object. + void transfer(const SyncObject& dest) const; + void transfer(const TimelineSyncObject& dest, u64 destPoint) const; + + /// Signal the sync object by emplacing a signaled fence into it. + void signal() const; + + /// Reset the sync object by removing the fence from it. + void reset() const; + + /// Wait for the sync object to be signaled. + /// @param timeout Absolute timeout in nanoseconds, or zero for polling + /// @param deadlineHint Set a CLOCK_MONOTONIC deadline hint in nanoseconds on the fence + void wait( + s64 timeout, + WaitMode waitMode = WaitMode::NoWaitEmpty, + std::optional<u64> deadlineHint = std::nullopt + ) const; + + /// Register an eventfd to the sync object. + /// @param waitAvailable Trigger when a fence is emplaced, not when it is signaled + void registerEventFd(int eventfd_fd, bool waitAvailable = false) const; +}; - /// Import a sync file (DRM fence) into the sync object +/// A timeline synchronization object can hold multiple DRM fences, identified via a +/// monotonically increasing 64-bit unsigned integer "point". +/// Requires DRM_CAP_SYNCOBJ_TIMELINE. +/// @throws drm::ioctl::Exception on failure +class TimelineSyncObject : public SyncObjectBase { +public: + using SyncObjectBase::SyncObjectBase; + using SyncObjectBase::operator=; + + /// Import a sync file (DRM fence) into the sync object. /// @param close Close syncfile_fd after import (regardless of success) void importSyncFile(int syncfile_fd, u64 point, bool close = true) const; - /// Export a sync file from the DRM fence within the sync object - /// Any subsequent modifications to the sync object are not applied to the exported sync file + /// Export a sync file from the DRM fence within the sync object. + /// Any subsequent modifications to the sync object are not applied to the exported sync file. [[nodiscard]] int exportSyncFile(u64 point) const; - /// Transfer a DRM fence into another sync object + /// Transfer a DRM fence into another sync object. void transfer(const TimelineSyncObject& dest, u64 srcPoint, u64 destPoint) const; void transfer(const SyncObject& dest, u64 srcPoint) const; - /// Signal the sync object by emplacing a signaled fence into it + /// Signal the sync object by emplacing a signaled fence into it. void signal(u64 point) const; - /// Wait for the sync object to be signaled + /// Wait for the sync object to be signaled. /// @param timeout Absolute timeout in nanoseconds, or zero for polling /// @param waitAvailable Only wait for a fence to become available, do not wait for signaling /// @param deadlineHint Set a CLOCK_MONOTONIC deadline hint in nanoseconds on the fence @@ -146,91 +154,49 @@ public: std::optional<u64> deadlineHint = std::nullopt ) const; - /// Query the current timeline point + /// Query the current timeline point. /// @param lastSubmitted If true, query the last submitted point instead [[nodiscard]] u64 query(bool lastSubmitted = false) const; - /// Register an eventfd to the sync object + /// Register an eventfd to the sync object. /// @param waitAvailable Trigger when a fence is emplaced, not when it is signaled void registerEventFd(int eventfd_fd, u64 point, bool waitAvailable = false) const; - - // Private access - GETTER(fd) - GETTER(handle) - - // Move constructor/operator - TimelineSyncObject(TimelineSyncObject&& other) noexcept - : m_fd(other.m_fd), m_handle(other.m_handle) { - other.m_fd = -1; // invalidate other - } - - TimelineSyncObject& operator=(TimelineSyncObject&& other) noexcept { - if (this != &other) { - this->destruct(); - this->m_handle = other.m_handle; - this->m_fd = other.m_fd; - other.m_fd = -1; // invalidate other - } - - return *this; - } - - // Copy constructor/operator - TimelineSyncObject(const TimelineSyncObject& other) - : TimelineSyncObject(other.m_fd, other.exportFd(), true) {} - - TimelineSyncObject& operator=(const TimelineSyncObject& other) { - if (this != &other) { - const int fd{other.exportFd()}; - *this = TimelineSyncObject(other.m_fd, fd, true); - } - - return *this; - } - - // Destructor - ~TimelineSyncObject(); -private: - int m_fd; // indicates object validity (>= 0) - u32 m_handle; - - void destruct() noexcept; }; -/// Signal several binary sync objects at once -void signal(const std::vector<ref<SyncObject>>& objs); +/// Signal several binary sync objects at once. +void signal(const std::vector<ref<const SyncObject>>& objs); -/// Reset several binary sync objects at once -void reset(const std::vector<ref<SyncObject>>& objs); +/// Reset several binary sync objects at once. +void reset(const std::vector<ref<const SyncObject>>& objs); -// Wait on several binary sync objects at once +/// Wait on several binary sync objects at once. /// @param timeout Absolute timeout in nanoseconds, or zero for polling /// @param waitAll Wait until all sync objects are signaled /// @param deadlineHint Set a CLOCK_MONOTONIC deadline hint in nanoseconds on the fence /// @return The first signaled sync object when waitAll is false /// @throws std::invalid_argument if objs is empty -SyncObject& wait( - const std::vector<ref<SyncObject>>& objs, +const SyncObject& wait( + const std::vector<ref<const SyncObject>>& objs, s64 timeout, bool waitAll = false, WaitMode waitMode = WaitMode::NoWaitEmpty, std::optional<u64> deadlineHint = std::nullopt ); -/// Signal several timeline sync objects at once +/// Signal several timeline sync objects at once. /// @throws std::invalid_argument if objs.size() != points.size() void signal( - const std::vector<ref<TimelineSyncObject>>& objs, - const std::vector<u64>& points + const std::vector<ref<const TimelineSyncObject>>& objs, + std::vector<u64> points ); -/// Wait on several timeline sync objects at once +/// Wait on several timeline sync objects at once. /// @param timeout Absolute timeout in nanoseconds, or zero for polling /// @param waitAvailable Only wait for a fence to become available, do not wait for signaling /// @param deadlineHint Set a CLOCK_MONOTONIC deadline hint in nanoseconds on the fence /// @throws std::invalid_argument if objs.size() != points.size() void wait( - const std::vector<ref<TimelineSyncObject>>& objs, + const std::vector<ref<const TimelineSyncObject>>& objs, const std::vector<u64>& points, s64 timeout, bool waitAll = false, @@ -238,10 +204,10 @@ void wait( std::optional<u64> deadlineHint = std::nullopt ); -/// Query several timeline sync objects at once +/// Query several timeline sync objects at once. /// @param lastSubmitted If true, query the last submitted point instead std::vector<u64> query( - const std::vector<ref<TimelineSyncObject>>& objs, + const std::vector<ref<const TimelineSyncObject>>& objs, bool lastSubmitted = false ); diff --git a/src/syncobject.cpp b/src/syncobject.cpp index 6614a9d..f2d3bbc 100644 --- a/src/syncobject.cpp +++ b/src/syncobject.cpp @@ -5,20 +5,20 @@ #include "drm++/ioctl.hpp" #include <cstddef> -#include <functional> #include <optional> +#include <span> #include <stdexcept> #include <vector> -#include <unistd.h> #include <drm.h> +#include <unistd.h> using namespace drm; using namespace drm::syncobj; -/* Binary Sync Objects */ +/* Base sync object class */ -SyncObject::SyncObject(int fd, bool signaled) : m_fd(fd) { +SyncObjectBase::SyncObjectBase(int fd, bool signaled) : m_fd(fd) { drm_syncobj_create args{ .flags = signaled ? DRM_SYNCOBJ_CREATE_SIGNALED : 0U }; @@ -27,7 +27,7 @@ SyncObject::SyncObject(int fd, bool signaled) : m_fd(fd) { this->m_handle = args.handle; } -SyncObject::SyncObject(int fd, int syncobj_fd, bool close) : m_fd(fd) { +SyncObjectBase::SyncObjectBase(int fd, int syncobj_fd, bool close) : m_fd(fd) { try { drm_syncobj_handle args{ .fd = syncobj_fd @@ -48,7 +48,7 @@ SyncObject::SyncObject(int fd, int syncobj_fd, bool close) : m_fd(fd) { } } -int SyncObject::exportFd() const { +int SyncObjectBase::exportFd() const { drm_syncobj_handle args{ .handle = this->m_handle, }; @@ -57,305 +57,241 @@ int SyncObject::exportFd() const { return args.fd; } -void SyncObject::importSyncFile(int syncfile_fd, bool close) const { +void SyncObjectBase::destruct() noexcept { + if (this->m_fd < 0) { + return; + } + + drm_syncobj_destroy args{ + .handle = this->m_handle + }; try { - drm_syncobj_handle args{ - .handle = this->m_handle, - .flags = DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE, - .fd = syncfile_fd - }; - ioctl::perform(this->m_fd, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, args); - } catch (...) { + ioctl::perform(this->m_fd, DRM_IOCTL_SYNCOBJ_DESTROY, args); + } catch(...) { + (void) 0; // not much we can do about the leak + } + + this->m_fd = -1; +} + +/* Importing/exporting sync fiels */ + +namespace { + void importSyncFile(int fd, u32 syncobj, int syncfile_fd, u64 point, bool close) { + try { + drm_syncobj_handle args{ + .handle = syncobj, + .flags = DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE + | (point != 0 ? DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_TIMELINE : 0U), + .fd = syncfile_fd, + .point = point + }; + ioctl::perform(fd, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, args); + } catch (...) { + if (close) { + ::close(syncfile_fd); + } + + throw; + } + if (close) { ::close(syncfile_fd); } - - throw; } + int exportSyncFile(int fd, u32 syncobj, u64 point) { + drm_syncobj_handle args{ + .handle = syncobj, + .flags = DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE + | (point != 0 ? DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_TIMELINE : 0U), + .point = point + }; + ioctl::perform(fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, args); - if (close) { - ::close(syncfile_fd); + return args.fd; } } +void SyncObject::importSyncFile(int syncfile_fd, bool close) const { + ::importSyncFile(this->m_fd, this->m_handle, syncfile_fd, 0, close); +} int SyncObject::exportSyncFile() const { - drm_syncobj_handle args{ - .handle = this->m_handle, - .flags = DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE - }; - ioctl::perform(this->m_fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, args); + return ::exportSyncFile(this->m_fd, this->m_handle, 0); +} +void TimelineSyncObject::importSyncFile(int syncfile_fd, u64 point, bool close) const { + ::importSyncFile(this->m_fd, this->m_handle, syncfile_fd, point, close); +} +int TimelineSyncObject::exportSyncFile(u64 point) const { + return ::exportSyncFile(this->m_fd, this->m_handle, point); +} - return args.fd; +/* Transfer operations */ + +namespace { + void transfer(int fd, u32 src, u32 dst, u64 srcPoint, u64 dstPoint) { + drm_syncobj_transfer args{ + .src_handle = src, + .dst_handle = dst, + .src_point = srcPoint, + .dst_point = dstPoint + }; + ioctl::perform(fd, DRM_IOCTL_SYNCOBJ_TRANSFER, args); + } } void SyncObject::transfer(const SyncObject& dest) const { - drm_syncobj_transfer args{ - .src_handle = this->m_handle, - .dst_handle = dest.m_handle - }; - ioctl::perform(this->m_fd, DRM_IOCTL_SYNCOBJ_TRANSFER, args); + ::transfer(this->m_fd, this->m_handle, dest.m_handle, 0, 0); } - void SyncObject::transfer(const TimelineSyncObject& dest, u64 destPoint) const { - drm_syncobj_transfer args{ - .src_handle = this->m_handle, - .dst_handle = dest.handle(), - .dst_point = destPoint - }; - ioctl::perform(this->m_fd, DRM_IOCTL_SYNCOBJ_TRANSFER, args); + ::transfer(this->m_fd, this->m_handle, dest.m_handle, 0, destPoint); } - -void SyncObject::signal() const { - drm_syncobj_array args{ - .handles = reinterpret_cast<u64>(&this->m_handle), - .count_handles = 1 - }; - ioctl::perform(this->m_fd, DRM_IOCTL_SYNCOBJ_SIGNAL, args); +void TimelineSyncObject::transfer(const TimelineSyncObject& dest, + u64 srcPoint, u64 destPoint) const { + ::transfer(this->m_fd, this->m_handle, dest.m_handle, srcPoint, destPoint); } - -void SyncObject::reset() const { - drm_syncobj_array args{ - .handles = reinterpret_cast<u64>(&this->m_handle), - .count_handles = 1 - }; - ioctl::perform(this->m_fd, DRM_IOCTL_SYNCOBJ_RESET, args); +void TimelineSyncObject::transfer(const SyncObject& dest, u64 srcPoint) const { + ::transfer(this->m_fd, this->m_handle, dest.m_handle, srcPoint, 0); } -void SyncObject::wait( - s64 timeout, - WaitMode waitMode, - std::optional<u64> deadlineHint -) const { - drm_syncobj_wait args{ - .handles = reinterpret_cast<u64>(&this->m_handle), - .timeout_nsec = timeout, - .count_handles = 1, - .flags = (waitMode == WaitMode::WaitEmpty ? DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT : 0U) | - (waitMode == WaitMode::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(this->m_fd, DRM_IOCTL_SYNCOBJ_WAIT, args); +/* Registering eventfds */ + +namespace { + void registerEventFd(int fd, u32 syncobj, int eventfd_fd, u64 point, bool waitAvailable) { + drm_syncobj_eventfd args{ + .handle = syncobj, + .flags = waitAvailable ? DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE : 0U, + .point = point, + .fd = eventfd_fd + }; + ioctl::perform(fd, DRM_IOCTL_SYNCOBJ_EVENTFD, args); + } } void SyncObject::registerEventFd(int eventfd_fd, bool waitAvailable) const { - drm_syncobj_eventfd args{ - .handle = this->m_handle, - .flags = waitAvailable ? DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE : 0U, - .fd = eventfd_fd - }; - ioctl::perform(this->m_fd, DRM_IOCTL_SYNCOBJ_EVENTFD, args); + ::registerEventFd(this->m_fd, this->m_handle, eventfd_fd, 0, waitAvailable); } - -void SyncObject::destruct() noexcept { - if (this->m_fd < 0) { - return; - } - - drm_syncobj_destroy args{ - .handle = this->m_handle - }; - try { - ioctl::perform(this->m_fd, DRM_IOCTL_SYNCOBJ_DESTROY, args); - } catch(...) { - (void) 0; // not much we can do about the leak - } - - this->m_fd = -1; +void TimelineSyncObject::registerEventFd(int eventfd_fd, u64 point, bool waitAvailable) const { + ::registerEventFd(this->m_fd, this->m_handle, eventfd_fd, point, waitAvailable); } -/* Timeline Sync Objects */ +/* Binary signal & reset operations */ -TimelineSyncObject::TimelineSyncObject(int fd) : m_fd(fd) { - drm_syncobj_create args{ - .flags = 0U - }; - ioctl::perform(this->m_fd, DRM_IOCTL_SYNCOBJ_CREATE, args); - - this->m_handle = args.handle; -} - -TimelineSyncObject::TimelineSyncObject(int fd, int syncobj_fd, bool close) : m_fd(fd) { - try { - drm_syncobj_handle args{ - .fd = syncobj_fd +namespace { + template<unsigned long OP> + void signal(int fd, std::span<const u32> syncobjs) { + drm_syncobj_array args{ + .handles = reinterpret_cast<u64>(syncobjs.data()), + .count_handles = static_cast<u32>(syncobjs.size()) }; - ioctl::perform(this->m_fd, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, args); + ioctl::perform(fd, OP, args); + } + template<unsigned long OP> + void signalBulk(const std::vector<ref<const SyncObject>>& syncobjs) { + if (syncobjs.empty()) { + return; + } - this->m_handle = args.handle; - } catch (...) { - if (close) { - ::close(syncobj_fd); + std::vector<u32> handles(syncobjs.size()); + for (size_t i = 0; i < syncobjs.size(); ++i) { + handles.at(i) = syncobjs.at(i).get().handle(); } - throw; - } - - if (close) { - ::close(syncobj_fd); + ::signal<OP>(syncobjs.front().get().fd(), handles); } } -int TimelineSyncObject::exportFd() const { - drm_syncobj_handle args{ - .handle = this->m_handle, - }; - ioctl::perform(this->m_fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, args); - - return args.fd; +void SyncObject::signal() const { + ::signal<DRM_IOCTL_SYNCOBJ_SIGNAL>(this->m_fd, std::span(&this->m_handle, 1)); +} +void SyncObject::reset() const { + ::signal<DRM_IOCTL_SYNCOBJ_RESET>(this->m_fd, std::span(&this->m_handle, 1)); +} +void syncobj::signal(const std::vector<ref<const SyncObject>>& objs) { + ::signalBulk<DRM_IOCTL_SYNCOBJ_SIGNAL>(objs); +} +void syncobj::reset(const std::vector<ref<const SyncObject>>& objs) { + ::signalBulk<DRM_IOCTL_SYNCOBJ_RESET>(objs); } -void TimelineSyncObject::importSyncFile(int syncfile_fd, u64 point, bool close) const { - try { - drm_syncobj_handle args{ - .handle = this->m_handle, - .flags = DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE - | DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_TIMELINE, - .fd = syncfile_fd, - .point = point +/* Timeline signal & query operations */ + +namespace { + template<unsigned long OP> + void signal(int fd, std::span<const u32> syncobjs, std::span<u64> points, bool lastSubmitted) { + drm_syncobj_timeline_array args{ + .handles = reinterpret_cast<u64>(syncobjs.data()), + .points = reinterpret_cast<u64>(points.data()), + .count_handles = static_cast<u32>(syncobjs.size()), + .flags = lastSubmitted ? DRM_SYNCOBJ_QUERY_FLAGS_LAST_SUBMITTED : 0U }; - ioctl::perform(this->m_fd, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, args); - } catch (...) { - if (close) { - ::close(syncfile_fd); + ioctl::perform(fd, OP, args); + } + template<unsigned long OP> + void signalBulk(const std::vector<ref<const TimelineSyncObject>>& syncobjs, + std::span<u64> points, bool lastSubmitted) { + if (syncobjs.empty()) { + return; } - throw; - } + if (syncobjs.size() != points.size()) { + throw std::invalid_argument("syncobjs and points must have the same size"); + } - if (close) { - ::close(syncfile_fd); + std::vector<u32> handles(syncobjs.size()); + for (size_t i = 0; i < syncobjs.size(); ++i) { + handles.at(i) = syncobjs.at(i).get().handle(); + } + + ::signal<OP>(syncobjs.front().get().fd(), handles, points, lastSubmitted); } } -int TimelineSyncObject::exportSyncFile(u64 point) const { - drm_syncobj_handle args{ - .handle = this->m_handle, - .flags = DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE - | DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_TIMELINE, - .point = point - }; - ioctl::perform(this->m_fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, args); - - return args.fd; +void TimelineSyncObject::signal(u64 point) const { + ::signal<DRM_IOCTL_SYNCOBJ_TIMELINE_SIGNAL>(this->m_fd, + std::span(&this->m_handle, 1), std::span(&point, 1), false); } - -void TimelineSyncObject::transfer( - const TimelineSyncObject& dest, - u64 srcPoint, - u64 destPoint -) const { - drm_syncobj_transfer args{ - .src_handle = this->m_handle, - .dst_handle = dest.m_handle, - .src_point = srcPoint, - .dst_point = destPoint - }; - ioctl::perform(this->m_fd, DRM_IOCTL_SYNCOBJ_TRANSFER, args); +u64 TimelineSyncObject::query(bool lastSubmitted) const { + u64 point{}; + ::signal<DRM_IOCTL_SYNCOBJ_QUERY>(this->m_fd, + std::span(&this->m_handle, 1), std::span(&point, 1), lastSubmitted); + return point; } - -void TimelineSyncObject::transfer(const SyncObject& dest, u64 srcPoint) const { - drm_syncobj_transfer args{ - .src_handle = this->m_handle, - .dst_handle = dest.handle(), - .src_point = srcPoint - }; - ioctl::perform(this->m_fd, DRM_IOCTL_SYNCOBJ_TRANSFER, args); +void syncobj::signal( + const std::vector<ref<const TimelineSyncObject>>& objs, + std::vector<u64> points +) { + ::signalBulk<DRM_IOCTL_SYNCOBJ_TIMELINE_SIGNAL>(objs, points, false); } - -void TimelineSyncObject::signal(u64 point) const { - drm_syncobj_timeline_array args{ - .handles = reinterpret_cast<u64>(&this->m_handle), - .points = reinterpret_cast<u64>(&point), - .count_handles = 1 - }; - ioctl::perform(this->m_fd, DRM_IOCTL_SYNCOBJ_TIMELINE_SIGNAL, args); +std::vector<u64> syncobj::query( + const std::vector<ref<const TimelineSyncObject>>& objs, + bool lastSubmitted +) { + std::vector<u64> points(objs.size()); + ::signalBulk<DRM_IOCTL_SYNCOBJ_QUERY>(objs, points, lastSubmitted); + return points; } -void TimelineSyncObject::wait( +/* Wait operations */ + +void SyncObject::wait( s64 timeout, - u64 point, - bool waitAvailable, + WaitMode waitMode, std::optional<u64> deadlineHint ) const { - drm_syncobj_timeline_wait args{ + drm_syncobj_wait args{ .handles = reinterpret_cast<u64>(&this->m_handle), - .points = reinterpret_cast<u64>(&point), .timeout_nsec = timeout, .count_handles = 1, - .flags = (waitAvailable ? DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE : 0U) | + .flags = (waitMode == WaitMode::WaitEmpty ? DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT : 0U) | + (waitMode == WaitMode::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(this->m_fd, DRM_IOCTL_SYNCOBJ_WAIT, args); } -u64 TimelineSyncObject::query(bool lastSubmitted) const { - u64 point{}; - - drm_syncobj_timeline_array args{ - .handles = reinterpret_cast<u64>(&this->m_handle), - .points = reinterpret_cast<u64>(&point), - .count_handles = 1, - .flags = lastSubmitted ? DRM_SYNCOBJ_QUERY_FLAGS_LAST_SUBMITTED : 0U - }; - ioctl::perform(this->m_fd, DRM_IOCTL_SYNCOBJ_QUERY, args); - - return point; -} - -void TimelineSyncObject::registerEventFd( - int eventfd_fd, - u64 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); -} - -/* Bulk Operations */ - -void syncobj::signal(const std::vector<std::reference_wrapper<SyncObject>>& objs) { - if (objs.empty()) { - return; - } - - std::vector<u32> handles(objs.size()); - for (size_t i = 0; i < objs.size(); ++i) { - handles.at(i) = objs.at(i).get().handle(); - } - - drm_syncobj_array args{ - .handles = reinterpret_cast<u64>(handles.data()), - .count_handles = static_cast<u32>(handles.size()) - }; - ioctl::perform(objs.front().get().fd(), DRM_IOCTL_SYNCOBJ_SIGNAL, args); -} - -void syncobj::reset(const std::vector<std::reference_wrapper<SyncObject>>& objs) { - if (objs.empty()) { - return; - } - - std::vector<u32> handles(objs.size()); - for (size_t i = 0; i < objs.size(); ++i) { - handles.at(i) = objs.at(i).get().handle(); - } - - drm_syncobj_array args{ - .handles = reinterpret_cast<u64>(handles.data()), - .count_handles = static_cast<u32>(handles.size()) - }; - ioctl::perform(objs.front().get().fd(), DRM_IOCTL_SYNCOBJ_RESET, args); -} - -SyncObject& syncobj::wait( - const std::vector<std::reference_wrapper<SyncObject>>& objs, +const SyncObject& syncobj::wait( + const std::vector<ref<const SyncObject>>& objs, s64 timeout, bool waitAll, WaitMode waitMode, @@ -385,29 +321,26 @@ SyncObject& syncobj::wait( return objs.at(args.first_signaled).get(); } -void syncobj::signal( - const std::vector<std::reference_wrapper<TimelineSyncObject>>& objs, - const std::vector<u64>& points -) { - if (objs.empty()) { - return; - } - - std::vector<u32> handles(objs.size()); - for (size_t i = 0; i < objs.size(); ++i) { - handles.at(i) = objs.at(i).get().handle(); - } - - drm_syncobj_timeline_array args{ - .handles = reinterpret_cast<u64>(handles.data()), - .points = reinterpret_cast<u64>(points.data()), - .count_handles = static_cast<u32>(handles.size()) +void TimelineSyncObject::wait( + s64 timeout, + u64 point, + bool waitAvailable, + std::optional<u64> deadlineHint +) const { + drm_syncobj_timeline_wait args{ + .handles = reinterpret_cast<u64>(&this->m_handle), + .points = reinterpret_cast<u64>(&point), + .timeout_nsec = timeout, + .count_handles = 1, + .flags = (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(objs.front().get().fd(), DRM_IOCTL_SYNCOBJ_TIMELINE_SIGNAL, args); + ioctl::perform(this->m_fd, DRM_IOCTL_SYNCOBJ_WAIT, args); } void syncobj::wait( - const std::vector<std::reference_wrapper<TimelineSyncObject>>& objs, + const std::vector<ref<const TimelineSyncObject>>& objs, const std::vector<u64>& points, s64 timeout, bool waitAll, @@ -435,29 +368,3 @@ void syncobj::wait( }; ioctl::perform(objs.front().get().fd(), DRM_IOCTL_SYNCOBJ_TIMELINE_WAIT, args); } - -std::vector<u64> syncobj::query( - const std::vector<std::reference_wrapper<TimelineSyncObject>>& objs, - bool lastSubmitted -) { - if (objs.empty()) { - return {}; - } - - std::vector<u32> handles(objs.size()); - for (size_t i = 0; i < objs.size(); ++i) { - handles.at(i) = objs.at(i).get().handle(); - } - - std::vector<u64> points(objs.size()); - - drm_syncobj_timeline_array args{ - .handles = reinterpret_cast<u64>(handles.data()), - .points = reinterpret_cast<u64>(points.data()), - .count_handles = static_cast<u32>(handles.size()), - .flags = lastSubmitted ? DRM_SYNCOBJ_QUERY_FLAGS_LAST_SUBMITTED : 0U - }; - ioctl::perform(objs.front().get().fd(), DRM_IOCTL_SYNCOBJ_QUERY, args); - - return points; -} |
