mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2026-03-12 15:50:36 +01:00
drm/syncobj: add timeline point merger utility
This commit is contained in:
parent
5752434367
commit
7c1df6398a
3 changed files with 176 additions and 0 deletions
44
include/render/drm_syncobj_merger.h
Normal file
44
include/render/drm_syncobj_merger.h
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
#ifndef WLR_RENDER_DRM_SYNCOBJ_MERGER_H
|
||||
#define WLR_RENDER_DRM_SYNCOBJ_MERGER_H
|
||||
|
||||
#include <wayland-server-core.h>
|
||||
|
||||
/**
|
||||
* Accumulate timeline points, to have a destination timeline point be
|
||||
* signalled when all inputs are
|
||||
*/
|
||||
struct wlr_drm_syncobj_merger {
|
||||
int n_ref;
|
||||
struct wlr_drm_syncobj_timeline *dst_timeline;
|
||||
uint64_t dst_point;
|
||||
int sync_fd;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new merger.
|
||||
*
|
||||
* The given timeline point will be signalled when all input points are
|
||||
* signalled and the merger is destroyed.
|
||||
*/
|
||||
struct wlr_drm_syncobj_merger *wlr_drm_syncobj_merger_create(
|
||||
struct wlr_drm_syncobj_timeline *dst_timeline, uint64_t dst_point);
|
||||
|
||||
struct wlr_drm_syncobj_merger *wlr_drm_syncobj_merger_ref(
|
||||
struct wlr_drm_syncobj_merger *merger);
|
||||
|
||||
/**
|
||||
* Target timeline point is materialized when all inputs are, and the merger is
|
||||
* destroyed.
|
||||
*/
|
||||
void wlr_drm_syncobj_merger_unref(struct wlr_drm_syncobj_merger *merger);
|
||||
/**
|
||||
* Add a new timeline point to wait for.
|
||||
*
|
||||
* If the point is not materialized, the supplied event loop is used to schedule
|
||||
* a wait.
|
||||
*/
|
||||
bool wlr_drm_syncobj_merger_add(struct wlr_drm_syncobj_merger *merger,
|
||||
struct wlr_drm_syncobj_timeline *dst_timeline, uint64_t dst_point,
|
||||
struct wl_event_loop *loop);
|
||||
|
||||
#endif
|
||||
130
render/drm_syncobj_merger.c
Normal file
130
render/drm_syncobj_merger.c
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <wayland-util.h>
|
||||
#include <wlr/render/drm_syncobj.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include <xf86drm.h>
|
||||
#include "render/drm_syncobj_merger.h"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#if HAVE_LINUX_SYNC_FILE
|
||||
|
||||
#include <linux/sync_file.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
static int sync_file_merge(int fd1, int fd2) {
|
||||
// The kernel will automatically prune signalled fences
|
||||
struct sync_merge_data merge_data = { .fd2 = fd2 };
|
||||
if (ioctl(fd1, SYNC_IOC_MERGE, &merge_data) < 0) {
|
||||
wlr_log_errno(WLR_ERROR, "ioctl(SYNC_IOC_MERGE) failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return merge_data.fence;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static int sync_file_merge(int fd1, int fd2) {
|
||||
wlr_log(WLR_ERROR, "sync_file support is unavailable");
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
struct wlr_drm_syncobj_merger *wlr_drm_syncobj_merger_create(
|
||||
struct wlr_drm_syncobj_timeline *dst_timeline, uint64_t dst_point) {
|
||||
struct wlr_drm_syncobj_merger *merger = calloc(1, sizeof(*merger));
|
||||
if (merger == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
merger->n_ref = 1;
|
||||
merger->dst_timeline = wlr_drm_syncobj_timeline_ref(dst_timeline);
|
||||
merger->dst_point = dst_point;
|
||||
merger->sync_fd = -1;
|
||||
return merger;
|
||||
}
|
||||
|
||||
struct wlr_drm_syncobj_merger *wlr_drm_syncobj_merger_ref(
|
||||
struct wlr_drm_syncobj_merger *merger) {
|
||||
assert(merger->n_ref > 0);
|
||||
merger->n_ref++;
|
||||
return merger;
|
||||
}
|
||||
|
||||
void wlr_drm_syncobj_merger_unref(struct wlr_drm_syncobj_merger *merger) {
|
||||
assert(merger->n_ref > 0);
|
||||
merger->n_ref--;
|
||||
if (merger->n_ref > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (merger->sync_fd != -1) {
|
||||
wlr_drm_syncobj_timeline_import_sync_file(merger->dst_timeline,
|
||||
merger->dst_point, merger->sync_fd);
|
||||
close(merger->sync_fd);
|
||||
} else {
|
||||
wlr_drm_syncobj_timeline_signal(merger->dst_timeline, merger->dst_point);
|
||||
}
|
||||
wlr_drm_syncobj_timeline_unref(merger->dst_timeline);
|
||||
free(merger);
|
||||
}
|
||||
|
||||
static bool merger_add_exportable(struct wlr_drm_syncobj_merger *merger,
|
||||
struct wlr_drm_syncobj_timeline *src_timeline, uint64_t src_point) {
|
||||
int new_sync = wlr_drm_syncobj_timeline_export_sync_file(src_timeline, src_point);
|
||||
if (merger->sync_fd != -1) {
|
||||
int fd2 = new_sync;
|
||||
new_sync = sync_file_merge(merger->sync_fd, fd2);
|
||||
close(fd2);
|
||||
close(merger->sync_fd);
|
||||
}
|
||||
merger->sync_fd = new_sync;
|
||||
return true;
|
||||
}
|
||||
|
||||
struct export_waiter {
|
||||
struct wlr_drm_syncobj_timeline_waiter waiter;
|
||||
struct wlr_drm_syncobj_merger *merger;
|
||||
struct wlr_drm_syncobj_timeline *src_timeline;
|
||||
uint64_t src_point;
|
||||
};
|
||||
|
||||
static void export_waiter_handle_ready(struct wlr_drm_syncobj_timeline_waiter *waiter) {
|
||||
struct export_waiter *add = wl_container_of(waiter, add, waiter);
|
||||
merger_add_exportable(add->merger, add->src_timeline, add->src_point);
|
||||
wlr_drm_syncobj_merger_unref(add->merger);
|
||||
wlr_drm_syncobj_timeline_unref(add->src_timeline);
|
||||
wlr_drm_syncobj_timeline_waiter_finish(&add->waiter);
|
||||
free(add);
|
||||
}
|
||||
|
||||
bool wlr_drm_syncobj_merger_add(struct wlr_drm_syncobj_merger *merger,
|
||||
struct wlr_drm_syncobj_timeline *src_timeline, uint64_t src_point,
|
||||
struct wl_event_loop *loop) {
|
||||
assert(loop != NULL);
|
||||
bool exportable = false;
|
||||
int flags = DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE;
|
||||
if (!wlr_drm_syncobj_timeline_check(src_timeline, src_point, flags, &exportable)) {
|
||||
return false;
|
||||
}
|
||||
if (exportable) {
|
||||
return merger_add_exportable(merger, src_timeline, src_point);
|
||||
}
|
||||
struct export_waiter *add = calloc(1, sizeof(*add));
|
||||
if (add == NULL) {
|
||||
return false;
|
||||
}
|
||||
if (!wlr_drm_syncobj_timeline_waiter_init(&add->waiter, src_timeline, src_point,
|
||||
flags, loop, export_waiter_handle_ready)) {
|
||||
return false;
|
||||
}
|
||||
add->merger = merger;
|
||||
add->src_timeline = wlr_drm_syncobj_timeline_ref(src_timeline);
|
||||
add->src_point = src_point;
|
||||
merger->n_ref++;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -9,6 +9,7 @@ wlr_files += files(
|
|||
'color.c',
|
||||
'dmabuf.c',
|
||||
'drm_format_set.c',
|
||||
'drm_syncobj_merger.c',
|
||||
'drm_syncobj.c',
|
||||
'pass.c',
|
||||
'pixel_format.c',
|
||||
|
|
@ -28,6 +29,7 @@ else
|
|||
endif
|
||||
|
||||
internal_config.set10('HAVE_EVENTFD', cc.has_header('sys/eventfd.h'))
|
||||
internal_config.set10('HAVE_LINUX_SYNC_FILE', cc.has_header('linux/sync_file.h'))
|
||||
|
||||
if 'gles2' in renderers or 'auto' in renderers
|
||||
egl = dependency('egl', required: 'gles2' in renderers)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue