From baf77bec541ef02659153a59118801c8002d7fdc Mon Sep 17 00:00:00 2001 From: PancakeTAS Date: Mon, 18 May 2026 10:45:34 +0200 Subject: Implement (non-timeline) sync objects --- src/syncobject.cpp | 156 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 156 insertions(+) create mode 100644 src/syncobject.cpp (limited to 'src/syncobject.cpp') diff --git a/src/syncobject.cpp b/src/syncobject.cpp new file mode 100644 index 0000000..59c06fd --- /dev/null +++ b/src/syncobject.cpp @@ -0,0 +1,156 @@ +/* SPDX-License-Identifier: MIT */ + +#include "syncobject.hpp" +#include "priv/ioctl.hpp" + +#include +#include +#include + +#include + +using namespace drm; + +SyncObject::SyncObject(int fd, bool signal) : m_fd(fd) { + drm_syncobj_create args{ + .flags = signal ? DRM_SYNCOBJ_CREATE_SIGNALED : 0U + }; + ioctl::perform(this->m_fd, DRM_IOCTL_SYNCOBJ_CREATE, args); + + this->m_handle = args.handle; +} + +SyncObject::SyncObject(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 SyncObject::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::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 + }; + 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 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 args.fd; +} + +void SyncObject::signal(int fd, const std::vector& objects) { + if (objects.empty()) { + return; + } + + drm_syncobj_array args{ + .handles = reinterpret_cast(objects.data()), + .count_handles = static_cast(objects.size()) + }; + ioctl::perform(fd, DRM_IOCTL_SYNCOBJ_SIGNAL, args); +} + +void SyncObject::reset(int fd, const std::vector& objects) { + if (objects.empty()) { + return; + } + + drm_syncobj_array args{ + .handles = reinterpret_cast(objects.data()), + .count_handles = static_cast(objects.size()) + }; + ioctl::perform(fd, DRM_IOCTL_SYNCOBJ_RESET, args); +} + +uint32_t SyncObject::wait( + int fd, + const std::vector& objects, + int64_t timeout, + bool waitAll, + bool waitEmpty, + bool waitAvailable, + std::optional deadlineHint +) { + if (objects.empty()) { + return 0; + } + + if (waitAvailable) { + waitEmpty = false; + } + + drm_syncobj_wait args{ + .handles = reinterpret_cast(objects.data()), + .timeout_nsec = timeout, + .count_handles = static_cast(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; +} + +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; +} -- cgit v1.3.1