diff options
Diffstat (limited to 'src/syncobject.cpp')
| -rw-r--r-- | src/syncobject.cpp | 432 |
1 files changed, 327 insertions, 105 deletions
diff --git a/src/syncobject.cpp b/src/syncobject.cpp index 8d5e8b5..6614a9d 100644 --- a/src/syncobject.cpp +++ b/src/syncobject.cpp @@ -1,20 +1,26 @@ /* SPDX-License-Identifier: MIT */ -#include "syncobject.hpp" -#include "priv/ioctl.hpp" +#include "drm++/syncobject.hpp" +#include "drm++/helper.hpp" +#include "drm++/ioctl.hpp" -#include <cstdint> +#include <cstddef> +#include <functional> #include <optional> #include <stdexcept> #include <vector> #include <unistd.h> +#include <drm.h> using namespace drm; +using namespace drm::syncobj; -SyncObject::SyncObject(int fd, bool signal) : m_fd(fd) { +/* Binary Sync Objects */ + +SyncObject::SyncObject(int fd, bool signaled) : m_fd(fd) { drm_syncobj_create args{ - .flags = signal ? DRM_SYNCOBJ_CREATE_SIGNALED : 0U + .flags = signaled ? DRM_SYNCOBJ_CREATE_SIGNALED : 0U }; ioctl::perform(this->m_fd, DRM_IOCTL_SYNCOBJ_CREATE, args); @@ -51,13 +57,12 @@ int SyncObject::exportFd() const { return args.fd; } -void SyncObject::importSyncFile(int syncfile_fd, uint64_t point, bool close) const { +void SyncObject::importSyncFile(int syncfile_fd, 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, - .point = point + .fd = syncfile_fd }; ioctl::perform(this->m_fd, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, args); } catch (...) { @@ -73,169 +78,386 @@ void SyncObject::importSyncFile(int syncfile_fd, uint64_t point, bool close) con } } -int SyncObject::exportSyncFile(uint64_t point) const { +int SyncObject::exportSyncFile() const { drm_syncobj_handle args{ .handle = this->m_handle, - .flags = DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE, - .point = point + .flags = DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE }; ioctl::perform(this->m_fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, args); return args.fd; } -void SyncObject::registerEventFd(int eventfd_fd, uint64_t point, bool waitAvailable) const { +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); +} + +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); +} + +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 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 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); +} + +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, - .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 { +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; +} + +/* Timeline Sync Objects */ + +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 + }; + ioctl::perform(this->m_fd, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, args); + + this->m_handle = args.handle; + } catch (...) { + if (close) { + ::close(syncobj_fd); + } + + throw; + } + + if (close) { + ::close(syncobj_fd); + } +} + +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 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 + }; + ioctl::perform(this->m_fd, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, args); + } catch (...) { + if (close) { + ::close(syncfile_fd); + } + + throw; + } + + if (close) { + ::close(syncfile_fd); + } +} + +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::transfer( + const TimelineSyncObject& dest, + u64 srcPoint, + u64 destPoint +) const { drm_syncobj_transfer args{ .src_handle = this->m_handle, - .dst_handle = dstObject, + .dst_handle = dest.m_handle, .src_point = srcPoint, - .dst_point = dstPoint + .dst_point = destPoint }; 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; - } +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); +} - 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); +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); +} + +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(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; } - if (points.size() != objects.size()) { - throw std::invalid_argument("points size must match objects size"); + 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<uint64_t>(objects.data()), - .points = reinterpret_cast<uint64_t>(points.data()), - .count_handles = static_cast<uint32_t>(objects.size()) + drm_syncobj_array args{ + .handles = reinterpret_cast<u64>(handles.data()), + .count_handles = static_cast<u32>(handles.size()) }; - ioctl::perform(fd, DRM_IOCTL_SYNCOBJ_TIMELINE_SIGNAL, args); + ioctl::perform(objs.front().get().fd(), DRM_IOCTL_SYNCOBJ_SIGNAL, args); } -void SyncObject::reset(int fd, const std::vector<uint32_t>& objects) { - if (objects.empty()) { +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<uint64_t>(objects.data()), - .count_handles = static_cast<uint32_t>(objects.size()) + .handles = reinterpret_cast<u64>(handles.data()), + .count_handles = static_cast<u32>(handles.size()) }; - ioctl::perform(fd, DRM_IOCTL_SYNCOBJ_RESET, args); + ioctl::perform(objs.front().get().fd(), DRM_IOCTL_SYNCOBJ_RESET, args); } -uint32_t SyncObject::wait( - int fd, - const std::vector<uint32_t>& objects, - const std::vector<uint64_t>& points, - int64_t timeout, +SyncObject& syncobj::wait( + const std::vector<std::reference_wrapper<SyncObject>>& objs, + s64 timeout, bool waitAll, - bool waitEmpty, - bool waitAvailable, - std::optional<uint64_t> deadlineHint + WaitMode waitMode, + std::optional<u64> deadlineHint ) { - if (objects.empty()) { - return 0; + if (objs.empty()) { + throw std::invalid_argument("must wait on at least one object"); } - if (waitAvailable) { - waitEmpty = false; + std::vector<u32> handles(objs.size()); + for (size_t i = 0; i < objs.size(); ++i) { + handles.at(i) = objs.at(i).get().handle(); } - 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); + drm_syncobj_wait args{ + .handles = reinterpret_cast<u64>(handles.data()), + .timeout_nsec = timeout, + .count_handles = static_cast<u32>(handles.size()), + .flags = (waitAll ? 0U : DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL) | + (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(objs.front().get().fd(), DRM_IOCTL_SYNCOBJ_WAIT, args); - return args.first_signaled; + 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; } - if (points.size() != objects.size()) { - throw std::invalid_argument("points size must match objects size"); + 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()) + }; + ioctl::perform(objs.front().get().fd(), DRM_IOCTL_SYNCOBJ_TIMELINE_SIGNAL, args); +} + +void syncobj::wait( + const std::vector<std::reference_wrapper<TimelineSyncObject>>& objs, + const std::vector<u64>& points, + s64 timeout, + bool waitAll, + bool waitAvailable, + std::optional<u64> deadlineHint +) { + 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_wait args{ - .handles = reinterpret_cast<uint64_t>(objects.data()), - .points = reinterpret_cast<uint64_t>(points.data()), + .handles = reinterpret_cast<u64>(handles.data()), + .points = reinterpret_cast<u64>(points.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) | + .count_handles = static_cast<u32>(handles.size()), + .flags = (waitAll ? 0U : DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL) | (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_TIMELINE_WAIT, args); - - return args.first_signaled; + ioctl::perform(objs.front().get().fd(), DRM_IOCTL_SYNCOBJ_TIMELINE_WAIT, args); } -std::vector<uint64_t> SyncObject::query( - int fd, - const std::vector<uint32_t>& objects, +std::vector<u64> syncobj::query( + const std::vector<std::reference_wrapper<TimelineSyncObject>>& objs, bool lastSubmitted ) { - if (objects.empty()) { + if (objs.empty()) { return {}; } - std::vector<uint64_t> points(objects.size()); + 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<uint64_t>(objects.data()), - .points = reinterpret_cast<uint64_t>(points.data()), - .count_handles = static_cast<uint32_t>(objects.size()), + .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(fd, DRM_IOCTL_SYNCOBJ_QUERY, args); + ioctl::perform(objs.front().get().fd(), DRM_IOCTL_SYNCOBJ_QUERY, args); return points; } - -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; -} |
