summaryrefslogtreecommitdiff
path: root/src/helpers/sync/SyncTimeline.cpp
diff options
context:
space:
mode:
authorVaxry <43317083+vaxerski@users.noreply.github.com>2024-07-21 13:09:54 +0200
committerGitHub <noreply@github.com>2024-07-21 13:09:54 +0200
commit016da234d0e852de3ef20eb2e89ac58d2a85f6e7 (patch)
tree496085987176551b0794fffc069877d44943e2f1 /src/helpers/sync/SyncTimeline.cpp
parentf642fb97df5c69267a03452533de383ff8023570 (diff)
Core: Move to aquamarine (#6608)
Moves Hyprland from wlroots to aquamarine for the backend. --------- Signed-off-by: Vaxry <vaxry@vaxry.net> Co-authored-by: Mihai Fufezan <mihai@fufexan.net> Co-authored-by: Jan Beich <jbeich@FreeBSD.org> Co-authored-by: vaxerski <vaxerski@users.noreply.github.com> Co-authored-by: UjinT34 <41110182+UjinT34@users.noreply.github.com> Co-authored-by: Tom Englund <tomenglund26@gmail.com> Co-authored-by: Ikalco <73481042+ikalco@users.noreply.github.com> Co-authored-by: diniamo <diniamo53@gmail.com>
Diffstat (limited to 'src/helpers/sync/SyncTimeline.cpp')
-rw-r--r--src/helpers/sync/SyncTimeline.cpp190
1 files changed, 190 insertions, 0 deletions
diff --git a/src/helpers/sync/SyncTimeline.cpp b/src/helpers/sync/SyncTimeline.cpp
new file mode 100644
index 00000000..352120ea
--- /dev/null
+++ b/src/helpers/sync/SyncTimeline.cpp
@@ -0,0 +1,190 @@
+#include "SyncTimeline.hpp"
+#include "../../defines.hpp"
+#include "../../managers/eventLoop/EventLoopManager.hpp"
+
+#include <xf86drm.h>
+#include <sys/eventfd.h>
+
+SP<CSyncTimeline> CSyncTimeline::create(int drmFD_) {
+ auto timeline = SP<CSyncTimeline>(new CSyncTimeline);
+ timeline->drmFD = drmFD_;
+ timeline->self = timeline;
+
+ if (drmSyncobjCreate(drmFD_, 0, &timeline->handle)) {
+ Debug::log(ERR, "CSyncTimeline: failed to create a drm syncobj??");
+ return nullptr;
+ }
+
+ return timeline;
+}
+
+SP<CSyncTimeline> CSyncTimeline::create(int drmFD_, int drmSyncobjFD) {
+ auto timeline = SP<CSyncTimeline>(new CSyncTimeline);
+ timeline->drmFD = drmFD_;
+ timeline->self = timeline;
+
+ if (drmSyncobjFDToHandle(drmFD_, drmSyncobjFD, &timeline->handle)) {
+ Debug::log(ERR, "CSyncTimeline: failed to create a drm syncobj from fd??");
+ return nullptr;
+ }
+
+ return timeline;
+}
+
+CSyncTimeline::~CSyncTimeline() {
+ if (handle == 0)
+ return;
+
+ drmSyncobjDestroy(drmFD, handle);
+}
+
+std::optional<bool> CSyncTimeline::check(uint64_t point, uint32_t flags) {
+#ifdef __FreeBSD__
+ constexpr int ETIME_ERR = ETIMEDOUT;
+#else
+ constexpr int ETIME_ERR = ETIME;
+#endif
+
+ uint32_t signaled = 0;
+ int ret = drmSyncobjTimelineWait(drmFD, &handle, &point, 1, 0, flags, &signaled);
+ if (ret != 0 && ret != -ETIME_ERR) {
+ Debug::log(ERR, "CSyncTimeline::check: drmSyncobjTimelineWait failed");
+ return std::nullopt;
+ }
+
+ return ret == 0;
+}
+
+static int handleWaiterFD(int fd, uint32_t mask, void* data) {
+ auto waiter = (CSyncTimeline::SWaiter*)data;
+
+ if (mask & (WL_EVENT_HANGUP | WL_EVENT_ERROR)) {
+ Debug::log(ERR, "handleWaiterFD: eventfd error");
+ return 0;
+ }
+
+ if (mask & WL_EVENT_READABLE) {
+ uint64_t value = 0;
+ if (read(fd, &value, sizeof(value)) <= 0)
+ Debug::log(ERR, "handleWaiterFD: failed to read from eventfd");
+ }
+
+ wl_event_source_remove(waiter->source);
+ waiter->source = nullptr;
+
+ if (waiter->fn)
+ waiter->fn();
+
+ if (waiter->timeline)
+ waiter->timeline->removeWaiter(waiter);
+
+ return 0;
+}
+
+bool CSyncTimeline::addWaiter(const std::function<void()>& waiter, uint64_t point, uint32_t flags) {
+ auto w = makeShared<SWaiter>();
+ w->fn = waiter;
+ w->timeline = self;
+
+ int eventFD = eventfd(0, EFD_CLOEXEC);
+
+ if (eventFD < 0) {
+ Debug::log(ERR, "CSyncTimeline::addWaiter: failed to acquire an eventfd");
+ return false;
+ }
+
+ drm_syncobj_eventfd syncobjEventFD = {
+ .handle = handle,
+ .flags = flags,
+ .point = point,
+ .fd = eventFD,
+ };
+
+ if (drmIoctl(drmFD, DRM_IOCTL_SYNCOBJ_EVENTFD, &syncobjEventFD) != 0) {
+ Debug::log(ERR, "CSyncTimeline::addWaiter: drmIoctl failed");
+ close(eventFD);
+ return false;
+ }
+
+ w->source = wl_event_loop_add_fd(g_pEventLoopManager->m_sWayland.loop, eventFD, WL_EVENT_READABLE, ::handleWaiterFD, w.get());
+ if (!w->source) {
+ Debug::log(ERR, "CSyncTimeline::addWaiter: wl_event_loop_add_fd failed");
+ close(eventFD);
+ return false;
+ }
+
+ waiters.emplace_back(w);
+
+ return true;
+}
+
+void CSyncTimeline::removeWaiter(SWaiter* w) {
+ if (w->source) {
+ wl_event_source_remove(w->source);
+ w->source = nullptr;
+ }
+ std::erase_if(waiters, [w](const auto& e) { return e.get() == w; });
+}
+
+int CSyncTimeline::exportAsSyncFileFD(uint64_t src) {
+ int sync = -1;
+
+ uint32_t syncHandle = 0;
+ if (drmSyncobjCreate(drmFD, 0, &syncHandle)) {
+ Debug::log(ERR, "exportAsSyncFileFD: drmSyncobjCreate failed");
+ return -1;
+ }
+
+ if (drmSyncobjTransfer(drmFD, syncHandle, 0, handle, src, 0)) {
+ Debug::log(ERR, "exportAsSyncFileFD: drmSyncobjTransfer failed");
+ drmSyncobjDestroy(drmFD, syncHandle);
+ return -1;
+ }
+
+ if (drmSyncobjExportSyncFile(drmFD, syncHandle, &sync)) {
+ Debug::log(ERR, "exportAsSyncFileFD: drmSyncobjExportSyncFile failed");
+ drmSyncobjDestroy(drmFD, syncHandle);
+ return -1;
+ }
+
+ drmSyncobjDestroy(drmFD, syncHandle);
+ return sync;
+}
+
+bool CSyncTimeline::importFromSyncFileFD(uint64_t dst, int fd) {
+ uint32_t syncHandle = 0;
+
+ if (drmSyncobjCreate(drmFD, 0, &syncHandle)) {
+ Debug::log(ERR, "importFromSyncFileFD: drmSyncobjCreate failed");
+ return false;
+ }
+
+ if (drmSyncobjImportSyncFile(drmFD, syncHandle, fd)) {
+ Debug::log(ERR, "importFromSyncFileFD: drmSyncobjImportSyncFile failed");
+ drmSyncobjDestroy(drmFD, syncHandle);
+ return false;
+ }
+
+ if (drmSyncobjTransfer(drmFD, handle, dst, syncHandle, 0, 0)) {
+ Debug::log(ERR, "importFromSyncFileFD: drmSyncobjTransfer failed");
+ drmSyncobjDestroy(drmFD, syncHandle);
+ return false;
+ }
+
+ drmSyncobjDestroy(drmFD, syncHandle);
+ return true;
+}
+
+bool CSyncTimeline::transfer(SP<CSyncTimeline> from, uint64_t fromPoint, uint64_t toPoint) {
+ if (drmFD != from->drmFD) {
+ Debug::log(ERR, "CSyncTimeline::transfer: cannot transfer timelines between gpus, {} -> {}", from->drmFD, drmFD);
+ return false;
+ }
+
+ if (drmSyncobjTransfer(drmFD, handle, toPoint, from->handle, fromPoint, 0)) {
+ Debug::log(ERR, "CSyncTimeline::transfer: drmSyncobjTransfer failed");
+ return false;
+ }
+
+ return true;
+}