wlr_drm_syncobj_timeline is a synchronization primitive based on drm_syncobj timelines. They are heavily inspired from Vulkan timeline semaphores [1]. [1]: https://www.khronos.org/blog/vulkan-timeline-semaphoresmaster
parent
f464213447
commit
7fc00ef777
@ -0,0 +1,71 @@
|
|||||||
|
#ifndef WLR_RENDER_DRM_SYNCOBJ_H
|
||||||
|
#define WLR_RENDER_DRM_SYNCOBJ_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A synchronization timeline.
|
||||||
|
*
|
||||||
|
* Timelines are used to synchronize accesses to buffers. Given a producer
|
||||||
|
* (writing contents to a buffer) and a consumer (reading from the buffer), the
|
||||||
|
* compositor needs to synchronize back-and-forth between these two users. The
|
||||||
|
* consumer needs to wait for the producer to signal that they're done with the
|
||||||
|
* writes, and the producer needs to wait for the consumer to signal that
|
||||||
|
* they're done with the reads.
|
||||||
|
*
|
||||||
|
* Timelines provide synchronization points in the form of monotonically
|
||||||
|
* increasing 64-bit integer values.
|
||||||
|
*
|
||||||
|
* wlroots timelines are designed after Vulkan timeline semaphores. For more
|
||||||
|
* information on the Vulkan APIs, see:
|
||||||
|
* https://www.khronos.org/blog/vulkan-timeline-semaphores
|
||||||
|
*
|
||||||
|
* wlroots timelines are powered by DRM synchronization objects (drm_syncobj):
|
||||||
|
* https://dri.freedesktop.org/docs/drm/gpu/drm-mm.html#drm-sync-objects
|
||||||
|
*/
|
||||||
|
struct wlr_drm_syncobj_timeline {
|
||||||
|
int drm_fd;
|
||||||
|
uint32_t handle;
|
||||||
|
|
||||||
|
// private state
|
||||||
|
|
||||||
|
size_t n_refs;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new synchronization timeline.
|
||||||
|
*/
|
||||||
|
struct wlr_drm_syncobj_timeline *wlr_drm_syncobj_timeline_create(int drm_fd);
|
||||||
|
/**
|
||||||
|
* Reference a synchronization timeline.
|
||||||
|
*/
|
||||||
|
struct wlr_drm_syncobj_timeline *wlr_drm_syncobj_timeline_ref(struct wlr_drm_syncobj_timeline *timeline);
|
||||||
|
/**
|
||||||
|
* Unreference a synchronization timeline.
|
||||||
|
*/
|
||||||
|
void wlr_drm_syncobj_timeline_unref(struct wlr_drm_syncobj_timeline *timeline);
|
||||||
|
/**
|
||||||
|
* Export a timeline point as a sync_file FD.
|
||||||
|
*
|
||||||
|
* The returned sync_file will be signalled when the provided point is
|
||||||
|
* signalled on the timeline.
|
||||||
|
*
|
||||||
|
* This allows inter-operation with other APIs which don't support drm_syncobj
|
||||||
|
* yet. The synchronization point needs to have already materialized:
|
||||||
|
* wait-before-signal is not supported.
|
||||||
|
*/
|
||||||
|
int wlr_drm_syncobj_timeline_export_sync_file(struct wlr_drm_syncobj_timeline *timeline,
|
||||||
|
uint64_t src_point);
|
||||||
|
/**
|
||||||
|
* Import a timeline point from a sync_file FD.
|
||||||
|
*
|
||||||
|
* The provided timeline point will be signalled when the provided sync_file is.
|
||||||
|
*
|
||||||
|
* This allows inter-operation with other APIs which don't support drm_syncobj
|
||||||
|
* yet.
|
||||||
|
*/
|
||||||
|
bool wlr_drm_syncobj_timeline_import_sync_file(struct wlr_drm_syncobj_timeline *timeline,
|
||||||
|
uint64_t dst_point, int sync_file_fd);
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,98 @@
|
|||||||
|
#include <assert.h>
|
||||||
|
#include <xf86drm.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <wlr/render/drm_syncobj.h>
|
||||||
|
#include <wlr/util/log.h>
|
||||||
|
|
||||||
|
struct wlr_drm_syncobj_timeline *wlr_drm_syncobj_timeline_create(int drm_fd) {
|
||||||
|
struct wlr_drm_syncobj_timeline *timeline = calloc(1, sizeof(*timeline));
|
||||||
|
if (timeline == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
timeline->drm_fd = drm_fd;
|
||||||
|
timeline->n_refs = 1;
|
||||||
|
|
||||||
|
if (drmSyncobjCreate(drm_fd, 0, &timeline->handle) != 0) {
|
||||||
|
wlr_log_errno(WLR_ERROR, "drmSyncobjCreate failed");
|
||||||
|
free(timeline);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return timeline;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_drm_syncobj_timeline *wlr_drm_syncobj_timeline_ref(struct wlr_drm_syncobj_timeline *timeline) {
|
||||||
|
timeline->n_refs++;
|
||||||
|
return timeline;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wlr_drm_syncobj_timeline_unref(struct wlr_drm_syncobj_timeline *timeline) {
|
||||||
|
if (timeline == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(timeline->n_refs > 0);
|
||||||
|
timeline->n_refs--;
|
||||||
|
if (timeline->n_refs > 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
drmSyncobjDestroy(timeline->drm_fd, timeline->handle);
|
||||||
|
free(timeline);
|
||||||
|
}
|
||||||
|
|
||||||
|
int wlr_drm_syncobj_timeline_export_sync_file(struct wlr_drm_syncobj_timeline *timeline,
|
||||||
|
uint64_t src_point) {
|
||||||
|
int sync_file_fd = -1;
|
||||||
|
|
||||||
|
uint32_t syncobj_handle;
|
||||||
|
if (drmSyncobjCreate(timeline->drm_fd, 0, &syncobj_handle) != 0) {
|
||||||
|
wlr_log_errno(WLR_ERROR, "drmSyncobjCreate failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (drmSyncobjTransfer(timeline->drm_fd, syncobj_handle, 0,
|
||||||
|
timeline->handle, src_point, 0) != 0) {
|
||||||
|
wlr_log_errno(WLR_ERROR, "drmSyncobjTransfer failed");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (drmSyncobjExportSyncFile(timeline->drm_fd,
|
||||||
|
syncobj_handle, &sync_file_fd) != 0) {
|
||||||
|
wlr_log_errno(WLR_ERROR, "drmSyncobjExportSyncFile failed");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
drmSyncobjDestroy(timeline->drm_fd, syncobj_handle);
|
||||||
|
return sync_file_fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wlr_drm_syncobj_timeline_import_sync_file(struct wlr_drm_syncobj_timeline *timeline,
|
||||||
|
uint64_t dst_point, int sync_file_fd) {
|
||||||
|
bool ok = false;
|
||||||
|
|
||||||
|
uint32_t syncobj_handle;
|
||||||
|
if (drmSyncobjCreate(timeline->drm_fd, 0, &syncobj_handle) != 0) {
|
||||||
|
wlr_log_errno(WLR_ERROR, "drmSyncobjCreate failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (drmSyncobjImportSyncFile(timeline->drm_fd, syncobj_handle,
|
||||||
|
sync_file_fd) != 0) {
|
||||||
|
wlr_log_errno(WLR_ERROR, "drmSyncobjImportSyncFile failed");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (drmSyncobjTransfer(timeline->drm_fd, timeline->handle, dst_point,
|
||||||
|
syncobj_handle, 0, 0) != 0) {
|
||||||
|
wlr_log_errno(WLR_ERROR, "drmSyncobjTransfer failed");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ok = true;
|
||||||
|
|
||||||
|
out:
|
||||||
|
drmSyncobjDestroy(timeline->drm_fd, syncobj_handle);
|
||||||
|
return ok;
|
||||||
|
}
|
Loading…
Reference in new issue