summaryrefslogtreecommitdiff
path: root/src/syncobject.cpp
diff options
context:
space:
mode:
authorPancakeTAS <pancake@mgnet.work>2026-05-18 15:51:33 +0200
committerPancakeTAS <pancake@mgnet.work>2026-05-18 15:51:33 +0200
commit9d2e04c95285825a196205163eebd945a362fb5e (patch)
tree59fdd2cfad0d3d548e54b54740806d7604218b89 /src/syncobject.cpp
parentExtend sync objects with timeline support (diff)
Split public/private API into respective locations
Diffstat (limited to 'src/syncobject.cpp')
-rw-r--r--src/syncobject.cpp432
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;
-}