mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2026-03-20 05:35:12 -04:00
linux_drm_syncobj_v1: add release point accumulation
This changes the behavior of wlr_linux_drm_syncobj_surface_v1 to automatically signal release of previous commits as they are replaced. Users must call wlr_linux_drm_syncobj_v1_state_add_release_point or wlr_linux_drm_syncobj_v1_state_signal_release_with_buffer to delay the signal as appropriate.
This commit is contained in:
parent
e83a679e23
commit
bfd6e619fc
2 changed files with 57 additions and 10 deletions
|
|
@ -19,8 +19,11 @@ struct wlr_linux_drm_syncobj_surface_v1_state {
|
||||||
struct wlr_drm_syncobj_timeline *acquire_timeline;
|
struct wlr_drm_syncobj_timeline *acquire_timeline;
|
||||||
uint64_t acquire_point;
|
uint64_t acquire_point;
|
||||||
|
|
||||||
struct wlr_drm_syncobj_timeline *release_timeline;
|
struct {
|
||||||
uint64_t release_point;
|
struct wlr_drm_syncobj_timeline *release_timeline;
|
||||||
|
uint64_t release_point;
|
||||||
|
struct wlr_drm_syncobj_merger *release_merger;
|
||||||
|
} WLR_PRIVATE;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct wlr_linux_drm_syncobj_manager_v1 {
|
struct wlr_linux_drm_syncobj_manager_v1 {
|
||||||
|
|
@ -55,4 +58,19 @@ struct wlr_linux_drm_syncobj_surface_v1_state *wlr_linux_drm_syncobj_v1_get_surf
|
||||||
bool wlr_linux_drm_syncobj_v1_state_signal_release_with_buffer(
|
bool wlr_linux_drm_syncobj_v1_state_signal_release_with_buffer(
|
||||||
struct wlr_linux_drm_syncobj_surface_v1_state *state, struct wlr_buffer *buffer);
|
struct wlr_linux_drm_syncobj_surface_v1_state *state, struct wlr_buffer *buffer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a release point for buffer usage.
|
||||||
|
*
|
||||||
|
* This function may be called multiple times for the same commit. The client's
|
||||||
|
* release point will be signalled when all registered points are signalled, and
|
||||||
|
* a new buffer has been committed.
|
||||||
|
*
|
||||||
|
* Because the given release point may not be materialized, a wl_event_loop must
|
||||||
|
* be supplied to schedule a wait internally, if needed
|
||||||
|
*/
|
||||||
|
bool wlr_linux_drm_syncobj_v1_state_add_release_point(
|
||||||
|
struct wlr_linux_drm_syncobj_surface_v1_state *state,
|
||||||
|
struct wlr_drm_syncobj_timeline *release_timeline, uint64_t release_point,
|
||||||
|
struct wl_event_loop *event_loop);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <wayland-server-core.h>
|
||||||
#include <wlr/render/drm_syncobj.h>
|
#include <wlr/render/drm_syncobj.h>
|
||||||
#include <wlr/types/wlr_buffer.h>
|
#include <wlr/types/wlr_buffer.h>
|
||||||
#include <wlr/types/wlr_compositor.h>
|
#include <wlr/types/wlr_compositor.h>
|
||||||
|
|
@ -11,6 +12,7 @@
|
||||||
#include <xf86drm.h>
|
#include <xf86drm.h>
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "linux-drm-syncobj-v1-protocol.h"
|
#include "linux-drm-syncobj-v1-protocol.h"
|
||||||
|
#include "render/drm_syncobj_merger.h"
|
||||||
|
|
||||||
#define LINUX_DRM_SYNCOBJ_V1_VERSION 1
|
#define LINUX_DRM_SYNCOBJ_V1_VERSION 1
|
||||||
|
|
||||||
|
|
@ -158,20 +160,38 @@ static void surface_synced_finish_state(void *_state) {
|
||||||
struct wlr_linux_drm_syncobj_surface_v1_state *state = _state;
|
struct wlr_linux_drm_syncobj_surface_v1_state *state = _state;
|
||||||
wlr_drm_syncobj_timeline_unref(state->acquire_timeline);
|
wlr_drm_syncobj_timeline_unref(state->acquire_timeline);
|
||||||
wlr_drm_syncobj_timeline_unref(state->release_timeline);
|
wlr_drm_syncobj_timeline_unref(state->release_timeline);
|
||||||
|
wlr_drm_syncobj_merger_unref(state->release_merger);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void surface_synced_move_state(void *_dst, void *_src) {
|
static void surface_synced_move_state(void *_dst, void *_src) {
|
||||||
struct wlr_linux_drm_syncobj_surface_v1_state *dst = _dst, *src = _src;
|
struct wlr_linux_drm_syncobj_surface_v1_state *dst = _dst, *src = _src;
|
||||||
// TODO: immediately signal dst.release_timeline if necessary
|
if (src->acquire_timeline == NULL) {
|
||||||
|
// ignore commits that did not attach a buffer
|
||||||
|
return;
|
||||||
|
}
|
||||||
surface_synced_finish_state(dst);
|
surface_synced_finish_state(dst);
|
||||||
*dst = *src;
|
*dst = *src;
|
||||||
*src = (struct wlr_linux_drm_syncobj_surface_v1_state){0};
|
*src = (struct wlr_linux_drm_syncobj_surface_v1_state){0};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void surface_synced_commit(struct wlr_surface_synced *synced) {
|
||||||
|
struct wlr_linux_drm_syncobj_surface_v1 *surface = wl_container_of(synced, surface, synced);
|
||||||
|
|
||||||
|
if (surface->current.release_merger != NULL) {
|
||||||
|
// ignore commits that did not attach a buffer
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
surface->current.release_merger = wlr_drm_syncobj_merger_create(
|
||||||
|
surface->current.release_timeline, surface->current.release_point);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static const struct wlr_surface_synced_impl surface_synced_impl = {
|
static const struct wlr_surface_synced_impl surface_synced_impl = {
|
||||||
.state_size = sizeof(struct wlr_linux_drm_syncobj_surface_v1_state),
|
.state_size = sizeof(struct wlr_linux_drm_syncobj_surface_v1_state),
|
||||||
.finish_state = surface_synced_finish_state,
|
.finish_state = surface_synced_finish_state,
|
||||||
.move_state = surface_synced_move_state,
|
.move_state = surface_synced_move_state,
|
||||||
|
.commit = surface_synced_commit,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void manager_handle_destroy(struct wl_client *client,
|
static void manager_handle_destroy(struct wl_client *client,
|
||||||
|
|
@ -422,6 +442,11 @@ struct wlr_linux_drm_syncobj_manager_v1 *wlr_linux_drm_syncobj_manager_v1_create
|
||||||
struct wl_display *display, uint32_t version, int drm_fd) {
|
struct wl_display *display, uint32_t version, int drm_fd) {
|
||||||
assert(version <= LINUX_DRM_SYNCOBJ_V1_VERSION);
|
assert(version <= LINUX_DRM_SYNCOBJ_V1_VERSION);
|
||||||
|
|
||||||
|
if (!HAVE_LINUX_SYNC_FILE) {
|
||||||
|
wlr_log(WLR_INFO, "Linux sync_file unavailable, disabling linux-drm-syncobj-v1");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (!check_syncobj_eventfd(drm_fd)) {
|
if (!check_syncobj_eventfd(drm_fd)) {
|
||||||
wlr_log(WLR_INFO, "DRM syncobj eventfd unavailable, disabling linux-drm-syncobj-v1");
|
wlr_log(WLR_INFO, "DRM syncobj eventfd unavailable, disabling linux-drm-syncobj-v1");
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
@ -467,16 +492,14 @@ wlr_linux_drm_syncobj_v1_get_surface_state(struct wlr_surface *wlr_surface) {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct release_signaller {
|
struct release_signaller {
|
||||||
struct wlr_drm_syncobj_timeline *timeline;
|
struct wlr_drm_syncobj_merger *merger;
|
||||||
uint64_t point;
|
|
||||||
struct wl_listener buffer_release;
|
struct wl_listener buffer_release;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void release_signaller_handle_buffer_release(struct wl_listener *listener, void *data) {
|
static void release_signaller_handle_buffer_release(struct wl_listener *listener, void *data) {
|
||||||
struct release_signaller *signaller = wl_container_of(listener, signaller, buffer_release);
|
struct release_signaller *signaller = wl_container_of(listener, signaller, buffer_release);
|
||||||
|
|
||||||
wlr_drm_syncobj_timeline_signal(signaller->timeline, signaller->point);
|
wlr_drm_syncobj_merger_unref(signaller->merger);
|
||||||
wlr_drm_syncobj_timeline_unref(signaller->timeline);
|
|
||||||
wl_list_remove(&signaller->buffer_release.link);
|
wl_list_remove(&signaller->buffer_release.link);
|
||||||
free(signaller);
|
free(signaller);
|
||||||
}
|
}
|
||||||
|
|
@ -496,11 +519,17 @@ bool wlr_linux_drm_syncobj_v1_state_signal_release_with_buffer(
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
signaller->timeline = wlr_drm_syncobj_timeline_ref(state->release_timeline);
|
signaller->merger = wlr_drm_syncobj_merger_ref(state->release_merger);
|
||||||
signaller->point = state->release_point;
|
|
||||||
|
|
||||||
signaller->buffer_release.notify = release_signaller_handle_buffer_release;
|
signaller->buffer_release.notify = release_signaller_handle_buffer_release;
|
||||||
wl_signal_add(&buffer->events.release, &signaller->buffer_release);
|
wl_signal_add(&buffer->events.release, &signaller->buffer_release);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool wlr_linux_drm_syncobj_v1_state_add_release_point(
|
||||||
|
struct wlr_linux_drm_syncobj_surface_v1_state *state,
|
||||||
|
struct wlr_drm_syncobj_timeline *release_timeline, uint64_t release_point,
|
||||||
|
struct wl_event_loop *event_loop) {
|
||||||
|
return wlr_drm_syncobj_merger_add(state->release_merger,
|
||||||
|
release_timeline, release_point, event_loop);
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue