/* SPDX-License-Identifier: MIT */ #include "syncobject.hpp" #include "priv/ioctl.hpp" #include #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, 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, .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 SyncObject::exportSyncFile(uint64_t point) const { drm_syncobj_handle args{ .handle = this->m_handle, .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::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& objects, const std::vector& points ) { if (objects.empty()) { return; } if (points.empty()) { drm_syncobj_array args{ .handles = reinterpret_cast(objects.data()), .count_handles = static_cast(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(objects.data()), .points = reinterpret_cast(points.data()), .count_handles = static_cast(objects.size()) }; ioctl::perform(fd, DRM_IOCTL_SYNCOBJ_TIMELINE_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, const std::vector& points, int64_t timeout, bool waitAll, bool waitEmpty, bool waitAvailable, std::optional deadlineHint ) { if (objects.empty()) { return 0; } if (waitAvailable) { waitEmpty = false; } if (points.empty()) { 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; } if (points.size() != objects.size()) { throw std::invalid_argument("points size must match objects size"); } drm_syncobj_timeline_wait args{ .handles = reinterpret_cast(objects.data()), .points = reinterpret_cast(points.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_TIMELINE_WAIT, args); return args.first_signaled; } std::vector SyncObject::query( int fd, const std::vector& objects, bool lastSubmitted ) { if (objects.empty()) { return {}; } std::vector points(objects.size()); drm_syncobj_timeline_array args{ .handles = reinterpret_cast(objects.data()), .points = reinterpret_cast(points.data()), .count_handles = static_cast(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; } 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; }