mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2024-11-25 08:32:30 +00:00
render/drm_syncobj: add helpers to wait for timeline points
References: https://patchwork.freedesktop.org/patch/506761/
This commit is contained in:
parent
ea75aa3065
commit
d9bfb47648
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <wayland-server-core.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A synchronization timeline.
|
* A synchronization timeline.
|
||||||
@ -33,6 +34,17 @@ struct wlr_drm_syncobj_timeline {
|
|||||||
size_t n_refs;
|
size_t n_refs;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct wlr_drm_syncobj_timeline_waiter {
|
||||||
|
struct {
|
||||||
|
struct wl_signal ready;
|
||||||
|
} events;
|
||||||
|
|
||||||
|
// private state
|
||||||
|
|
||||||
|
int ev_fd;
|
||||||
|
struct wl_event_source *event_source;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new synchronization timeline.
|
* Create a new synchronization timeline.
|
||||||
*/
|
*/
|
||||||
@ -50,6 +62,30 @@ struct wlr_drm_syncobj_timeline *wlr_drm_syncobj_timeline_ref(struct wlr_drm_syn
|
|||||||
* Unreference a synchronization timeline.
|
* Unreference a synchronization timeline.
|
||||||
*/
|
*/
|
||||||
void wlr_drm_syncobj_timeline_unref(struct wlr_drm_syncobj_timeline *timeline);
|
void wlr_drm_syncobj_timeline_unref(struct wlr_drm_syncobj_timeline *timeline);
|
||||||
|
/**
|
||||||
|
* Check if a timeline point has been signalled or has materialized.
|
||||||
|
*
|
||||||
|
* Flags can be:
|
||||||
|
*
|
||||||
|
* - DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT to wait for the point to be
|
||||||
|
* signalled
|
||||||
|
* - DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE to only wait for a fence to
|
||||||
|
* materialize
|
||||||
|
*/
|
||||||
|
bool wlr_drm_syncobj_timeline_check(struct wlr_drm_syncobj_timeline *timeline,
|
||||||
|
uint64_t point, uint32_t flags, bool *result);
|
||||||
|
/**
|
||||||
|
* Asynchronously wait for a timeline point.
|
||||||
|
*
|
||||||
|
* See wlr_drm_syncobj_timeline_check() for a definition of flags.
|
||||||
|
*/
|
||||||
|
bool wlr_drm_syncobj_timeline_waiter_init(struct wlr_drm_syncobj_timeline_waiter *waiter,
|
||||||
|
struct wlr_drm_syncobj_timeline *timeline, uint64_t point, uint32_t flags,
|
||||||
|
struct wl_event_loop *loop);
|
||||||
|
/**
|
||||||
|
* Cancel a timeline waiter.
|
||||||
|
*/
|
||||||
|
void wlr_drm_syncobj_timeline_waiter_finish(struct wlr_drm_syncobj_timeline_waiter *waiter);
|
||||||
/**
|
/**
|
||||||
* Export a timeline point as a sync_file FD.
|
* Export a timeline point as a sync_file FD.
|
||||||
*
|
*
|
||||||
|
@ -1,9 +1,17 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <xf86drm.h>
|
#include <xf86drm.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <wayland-server-core.h>
|
||||||
#include <wlr/render/drm_syncobj.h>
|
#include <wlr/render/drm_syncobj.h>
|
||||||
#include <wlr/util/log.h>
|
#include <wlr/util/log.h>
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#if HAVE_EVENTFD
|
||||||
|
#include <sys/eventfd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
struct wlr_drm_syncobj_timeline *wlr_drm_syncobj_timeline_create(int drm_fd) {
|
struct wlr_drm_syncobj_timeline *wlr_drm_syncobj_timeline_create(int drm_fd) {
|
||||||
struct wlr_drm_syncobj_timeline *timeline = calloc(1, sizeof(*timeline));
|
struct wlr_drm_syncobj_timeline *timeline = calloc(1, sizeof(*timeline));
|
||||||
if (timeline == NULL) {
|
if (timeline == NULL) {
|
||||||
@ -114,3 +122,91 @@ out:
|
|||||||
drmSyncobjDestroy(timeline->drm_fd, syncobj_handle);
|
drmSyncobjDestroy(timeline->drm_fd, syncobj_handle);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool wlr_drm_syncobj_timeline_check(struct wlr_drm_syncobj_timeline *timeline,
|
||||||
|
uint64_t point, uint32_t flags, bool *result) {
|
||||||
|
int etime;
|
||||||
|
#if defined(__FreeBSD__)
|
||||||
|
etime = ETIMEDOUT;
|
||||||
|
#else
|
||||||
|
etime = ETIME;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint32_t signaled_point;
|
||||||
|
int ret = drmSyncobjTimelineWait(timeline->drm_fd, &timeline->handle, &point, 1, 0, flags, &signaled_point);
|
||||||
|
if (ret != 0 && ret != -etime) {
|
||||||
|
wlr_log_errno(WLR_ERROR, "drmSyncobjWait() failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
*result = ret == 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int handle_eventfd_ready(int ev_fd, uint32_t mask, void *data) {
|
||||||
|
struct wlr_drm_syncobj_timeline_waiter *waiter = data;
|
||||||
|
|
||||||
|
if (mask & (WL_EVENT_HANGUP | WL_EVENT_ERROR)) {
|
||||||
|
wlr_log(WLR_ERROR, "Failed to wait for render timeline: eventfd error");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mask & WL_EVENT_READABLE) {
|
||||||
|
uint64_t ev_fd_value;
|
||||||
|
if (read(ev_fd, &ev_fd_value, sizeof(ev_fd_value)) <= 0) {
|
||||||
|
wlr_log(WLR_ERROR, "Failed to wait for render timeline: read() failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wl_signal_emit_mutable(&waiter->events.ready, NULL);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wlr_drm_syncobj_timeline_waiter_init(struct wlr_drm_syncobj_timeline_waiter *waiter,
|
||||||
|
struct wlr_drm_syncobj_timeline *timeline, uint64_t point, uint32_t flags,
|
||||||
|
struct wl_event_loop *loop) {
|
||||||
|
int ev_fd;
|
||||||
|
#if HAVE_EVENTFD
|
||||||
|
ev_fd = eventfd(0, EFD_CLOEXEC);
|
||||||
|
if (ev_fd < 0) {
|
||||||
|
wlr_log_errno(WLR_ERROR, "eventfd() failed");
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
ev_fd = -1;
|
||||||
|
wlr_log(WLR_ERROR, "eventfd() is unavailable");
|
||||||
|
#endif
|
||||||
|
if (ev_fd < 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct drm_syncobj_eventfd syncobj_eventfd = {
|
||||||
|
.handle = timeline->handle,
|
||||||
|
.flags = flags,
|
||||||
|
.point = point,
|
||||||
|
.fd = ev_fd,
|
||||||
|
};
|
||||||
|
if (drmIoctl(timeline->drm_fd, DRM_IOCTL_SYNCOBJ_EVENTFD, &syncobj_eventfd) != 0) {
|
||||||
|
wlr_log_errno(WLR_ERROR, "DRM_IOCTL_SYNCOBJ_EVENTFD failed");
|
||||||
|
close(ev_fd);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wl_event_source *source = wl_event_loop_add_fd(loop, ev_fd, WL_EVENT_READABLE, handle_eventfd_ready, waiter);
|
||||||
|
if (source == NULL) {
|
||||||
|
wlr_log(WLR_ERROR, "Failed to add FD to event loop");
|
||||||
|
close(ev_fd);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
*waiter = (struct wlr_drm_syncobj_timeline_waiter){
|
||||||
|
.ev_fd = ev_fd,
|
||||||
|
.event_source = source,
|
||||||
|
};
|
||||||
|
wl_signal_init(&waiter->events.ready);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wlr_drm_syncobj_timeline_waiter_finish(struct wlr_drm_syncobj_timeline_waiter *waiter) {
|
||||||
|
wl_list_remove(&waiter->events.ready.listener_list);
|
||||||
|
wl_event_source_remove(waiter->event_source);
|
||||||
|
close(waiter->ev_fd);
|
||||||
|
}
|
||||||
|
@ -23,6 +23,8 @@ else
|
|||||||
wlr_files += files('dmabuf_fallback.c')
|
wlr_files += files('dmabuf_fallback.c')
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
internal_config.set10('HAVE_EVENTFD', cc.has_header('sys/eventfd.h'))
|
||||||
|
|
||||||
if 'gles2' in renderers or 'auto' in renderers
|
if 'gles2' in renderers or 'auto' in renderers
|
||||||
egl = dependency('egl', required: 'gles2' in renderers)
|
egl = dependency('egl', required: 'gles2' in renderers)
|
||||||
gbm = dependency('gbm', required: 'gles2' in renderers)
|
gbm = dependency('gbm', required: 'gles2' in renderers)
|
||||||
|
Loading…
Reference in New Issue
Block a user