mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2026-03-07 16:50:32 +01:00
Merge branch 'syncobj_merge_2' into 'master'
scene: fine-grained explicit sync release points See merge request wlroots/wlroots!4979
This commit is contained in:
commit
76e5eaf808
14 changed files with 337 additions and 67 deletions
|
|
@ -423,12 +423,6 @@ void drm_atomic_connector_apply_commit(struct wlr_drm_connector_state *state) {
|
|||
if (state->primary_in_fence_fd >= 0) {
|
||||
close(state->primary_in_fence_fd);
|
||||
}
|
||||
if (state->out_fence_fd >= 0) {
|
||||
// TODO: error handling
|
||||
wlr_drm_syncobj_timeline_import_sync_file(state->base->signal_timeline,
|
||||
state->base->signal_point, state->out_fence_fd);
|
||||
close(state->out_fence_fd);
|
||||
}
|
||||
|
||||
conn->colorspace = state->colorspace;
|
||||
}
|
||||
|
|
@ -446,9 +440,6 @@ void drm_atomic_connector_rollback_commit(struct wlr_drm_connector_state *state)
|
|||
if (state->primary_in_fence_fd >= 0) {
|
||||
close(state->primary_in_fence_fd);
|
||||
}
|
||||
if (state->out_fence_fd >= 0) {
|
||||
close(state->out_fence_fd);
|
||||
}
|
||||
}
|
||||
|
||||
static void plane_disable(struct atomic *atom, struct wlr_drm_plane *plane) {
|
||||
|
|
@ -500,19 +491,6 @@ static void set_plane_in_fence_fd(struct atomic *atom,
|
|||
atomic_add(atom, plane->id, plane->props.in_fence_fd, sync_file_fd);
|
||||
}
|
||||
|
||||
static void set_crtc_out_fence_ptr(struct atomic *atom, struct wlr_drm_crtc *crtc,
|
||||
int *fd_ptr) {
|
||||
if (!crtc->props.out_fence_ptr) {
|
||||
wlr_log(WLR_ERROR,
|
||||
"CRTC %"PRIu32" is missing the OUT_FENCE_PTR property",
|
||||
crtc->id);
|
||||
atom->failed = true;
|
||||
return;
|
||||
}
|
||||
|
||||
atomic_add(atom, crtc->id, crtc->props.out_fence_ptr, (uintptr_t)fd_ptr);
|
||||
}
|
||||
|
||||
static void atomic_connector_add(struct atomic *atom,
|
||||
struct wlr_drm_connector_state *state, bool modeset) {
|
||||
struct wlr_drm_connector *conn = state->connector;
|
||||
|
|
@ -557,9 +535,6 @@ static void atomic_connector_add(struct atomic *atom,
|
|||
if (state->primary_in_fence_fd >= 0) {
|
||||
set_plane_in_fence_fd(atom, crtc->primary, state->primary_in_fence_fd);
|
||||
}
|
||||
if (state->base->committed & WLR_OUTPUT_STATE_SIGNAL_TIMELINE) {
|
||||
set_crtc_out_fence_ptr(atom, crtc, &state->out_fence_fd);
|
||||
}
|
||||
if (crtc->cursor) {
|
||||
if (drm_connector_is_cursor_visible(conn)) {
|
||||
struct wlr_fbox cursor_src = {
|
||||
|
|
|
|||
|
|
@ -367,7 +367,17 @@ static void drm_plane_finish_surface(struct wlr_drm_plane *plane) {
|
|||
}
|
||||
|
||||
drm_fb_clear(&plane->queued_fb);
|
||||
if (plane->queued_release_timeline != NULL) {
|
||||
wlr_drm_syncobj_timeline_signal(plane->queued_release_timeline, plane->queued_release_point);
|
||||
wlr_drm_syncobj_timeline_unref(plane->queued_release_timeline);
|
||||
plane->queued_release_timeline = NULL;
|
||||
}
|
||||
drm_fb_clear(&plane->current_fb);
|
||||
if (plane->current_release_timeline != NULL) {
|
||||
wlr_drm_syncobj_timeline_signal(plane->current_release_timeline, plane->current_release_point);
|
||||
wlr_drm_syncobj_timeline_unref(plane->current_release_timeline);
|
||||
plane->current_release_timeline = NULL;
|
||||
}
|
||||
|
||||
finish_drm_surface(&plane->mgpu_surf);
|
||||
}
|
||||
|
|
@ -556,6 +566,18 @@ static void drm_connector_apply_commit(const struct wlr_drm_connector_state *sta
|
|||
struct wlr_drm_crtc *crtc = conn->crtc;
|
||||
|
||||
drm_fb_copy(&crtc->primary->queued_fb, state->primary_fb);
|
||||
if (crtc->primary->queued_release_timeline != NULL) {
|
||||
wlr_drm_syncobj_timeline_signal(crtc->primary->queued_release_timeline, crtc->primary->queued_release_point);
|
||||
wlr_drm_syncobj_timeline_unref(crtc->primary->queued_release_timeline);
|
||||
}
|
||||
if (state->base->signal_timeline != NULL) {
|
||||
crtc->primary->queued_release_timeline = wlr_drm_syncobj_timeline_ref(state->base->signal_timeline);
|
||||
crtc->primary->queued_release_point = state->base->signal_point;
|
||||
} else {
|
||||
crtc->primary->queued_release_timeline = NULL;
|
||||
crtc->primary->queued_release_point = 0;
|
||||
}
|
||||
|
||||
crtc->primary->viewport = state->primary_viewport;
|
||||
if (crtc->cursor != NULL) {
|
||||
drm_fb_copy(&crtc->cursor->queued_fb, state->cursor_fb);
|
||||
|
|
@ -646,7 +668,6 @@ static void drm_connector_state_init(struct wlr_drm_connector_state *state,
|
|||
.base = base,
|
||||
.active = output_pending_enabled(&conn->output, base),
|
||||
.primary_in_fence_fd = -1,
|
||||
.out_fence_fd = -1,
|
||||
};
|
||||
|
||||
struct wlr_output_mode *mode = conn->output.current_mode;
|
||||
|
|
@ -2018,6 +2039,14 @@ static void handle_page_flip(int fd, unsigned seq,
|
|||
struct wlr_drm_plane *plane = conn->crtc->primary;
|
||||
if (plane->queued_fb) {
|
||||
drm_fb_move(&plane->current_fb, &plane->queued_fb);
|
||||
if (plane->current_release_timeline != NULL) {
|
||||
wlr_drm_syncobj_timeline_signal(plane->current_release_timeline, plane->current_release_point);
|
||||
wlr_drm_syncobj_timeline_unref(plane->current_release_timeline);
|
||||
}
|
||||
plane->current_release_timeline = plane->queued_release_timeline;
|
||||
plane->current_release_point = plane->queued_release_point;
|
||||
plane->queued_release_timeline = NULL;
|
||||
plane->queued_release_point = 0;
|
||||
}
|
||||
if (conn->crtc->cursor && conn->crtc->cursor->queued_fb) {
|
||||
drm_fb_move(&conn->crtc->cursor->current_fb,
|
||||
|
|
|
|||
|
|
@ -352,10 +352,6 @@ static bool add_connector(drmModeAtomicReq *req,
|
|||
liftoff_layer_set_property(crtc->liftoff_composition_layer,
|
||||
"IN_FENCE_FD", state->primary_in_fence_fd);
|
||||
}
|
||||
if (state->base->committed & WLR_OUTPUT_STATE_SIGNAL_TIMELINE) {
|
||||
ok = ok && add_prop(req, crtc->id, crtc->props.out_fence_ptr,
|
||||
(uintptr_t)&state->out_fence_fd);
|
||||
}
|
||||
|
||||
if (state->base->committed & WLR_OUTPUT_STATE_LAYERS) {
|
||||
for (size_t i = 0; i < state->base->layers_len; i++) {
|
||||
|
|
|
|||
|
|
@ -29,8 +29,12 @@ struct wlr_drm_plane {
|
|||
|
||||
/* Buffer submitted to the kernel, will be presented on next vblank */
|
||||
struct wlr_drm_fb *queued_fb;
|
||||
struct wlr_drm_syncobj_timeline *queued_release_timeline;
|
||||
uint64_t queued_release_point;
|
||||
/* Buffer currently displayed on screen */
|
||||
struct wlr_drm_fb *current_fb;
|
||||
struct wlr_drm_syncobj_timeline *current_release_timeline;
|
||||
uint64_t current_release_point;
|
||||
/* Viewport belonging to the last committed fb */
|
||||
struct wlr_drm_viewport viewport;
|
||||
|
||||
|
|
@ -156,7 +160,7 @@ struct wlr_drm_connector_state {
|
|||
uint32_t mode_id;
|
||||
uint32_t gamma_lut;
|
||||
uint32_t fb_damage_clips;
|
||||
int primary_in_fence_fd, out_fence_fd;
|
||||
int primary_in_fence_fd;
|
||||
bool vrr_enabled;
|
||||
uint32_t colorspace;
|
||||
uint32_t hdr_output_metadata;
|
||||
|
|
|
|||
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
|
||||
|
|
@ -90,6 +90,10 @@ bool wlr_drm_syncobj_timeline_transfer(struct wlr_drm_syncobj_timeline *dst,
|
|||
*/
|
||||
bool wlr_drm_syncobj_timeline_check(struct wlr_drm_syncobj_timeline *timeline,
|
||||
uint64_t point, uint32_t flags, bool *result);
|
||||
/**
|
||||
* Signals a timeline point.
|
||||
*/
|
||||
bool wlr_drm_syncobj_timeline_signal(struct wlr_drm_syncobj_timeline *timeline, uint64_t point);
|
||||
/**
|
||||
* Asynchronously wait for a timeline point.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@ struct wlr_linux_drm_syncobj_surface_v1_state {
|
|||
|
||||
struct wlr_drm_syncobj_timeline *release_timeline;
|
||||
uint64_t release_point;
|
||||
|
||||
struct wlr_drm_syncobj_merger *release_merger;
|
||||
};
|
||||
|
||||
struct wlr_linux_drm_syncobj_manager_v1 {
|
||||
|
|
|
|||
|
|
@ -155,6 +155,8 @@ struct wlr_scene_outputs_update_event {
|
|||
struct wlr_scene_output_sample_event {
|
||||
struct wlr_scene_output *output;
|
||||
bool direct_scanout;
|
||||
struct wlr_drm_syncobj_timeline *release_timeline;
|
||||
uint64_t release_point;
|
||||
};
|
||||
|
||||
struct wlr_scene_frame_done_event {
|
||||
|
|
@ -209,6 +211,7 @@ struct wlr_scene_buffer {
|
|||
|
||||
struct wlr_drm_syncobj_timeline *wait_timeline;
|
||||
uint64_t wait_point;
|
||||
struct wlr_drm_syncobj_merger *release_merger;
|
||||
|
||||
struct wl_listener buffer_release;
|
||||
struct wl_listener renderer_destroy;
|
||||
|
|
@ -268,6 +271,8 @@ struct wlr_scene_output {
|
|||
|
||||
struct wlr_drm_syncobj_timeline *in_timeline;
|
||||
uint64_t in_point;
|
||||
struct wlr_drm_syncobj_timeline *out_timeline;
|
||||
uint64_t out_point;
|
||||
} WLR_PRIVATE;
|
||||
};
|
||||
|
||||
|
|
@ -503,6 +508,9 @@ struct wlr_scene_buffer_set_buffer_options {
|
|||
// Wait for a timeline synchronization point before reading from the buffer.
|
||||
struct wlr_drm_syncobj_timeline *wait_timeline;
|
||||
uint64_t wait_point;
|
||||
|
||||
// Synchronize with last read from the buffer.
|
||||
struct wlr_drm_syncobj_merger *release_merger;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -177,6 +177,14 @@ bool wlr_drm_syncobj_timeline_check(struct wlr_drm_syncobj_timeline *timeline,
|
|||
return true;
|
||||
}
|
||||
|
||||
bool wlr_drm_syncobj_timeline_signal(struct wlr_drm_syncobj_timeline *timeline, uint64_t point) {
|
||||
if (drmSyncobjTimelineSignal(timeline->drm_fd, &timeline->handle, &point, 1) != 0) {
|
||||
wlr_log(WLR_ERROR, "drmSyncobjTimelineSignal() failed");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static int handle_eventfd_ready(int ev_fd, uint32_t mask, void *data) {
|
||||
struct wlr_drm_syncobj_timeline_waiter *waiter = data;
|
||||
|
||||
|
|
|
|||
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)
|
||||
|
|
|
|||
|
|
@ -311,27 +311,25 @@ static void surface_reconfigure(struct wlr_scene_surface *scene_surface) {
|
|||
struct wlr_linux_drm_syncobj_surface_v1_state *syncobj_surface_state =
|
||||
wlr_linux_drm_syncobj_v1_get_surface_state(surface);
|
||||
|
||||
struct wlr_drm_syncobj_timeline *wait_timeline = NULL;
|
||||
uint64_t wait_point = 0;
|
||||
if (syncobj_surface_state != NULL) {
|
||||
wait_timeline = syncobj_surface_state->acquire_timeline;
|
||||
wait_point = syncobj_surface_state->acquire_point;
|
||||
}
|
||||
|
||||
struct wlr_scene_buffer_set_buffer_options options = {
|
||||
.damage = &surface->buffer_damage,
|
||||
.wait_timeline = wait_timeline,
|
||||
.wait_point = wait_point,
|
||||
.wait_timeline = scene_buffer->wait_timeline,
|
||||
.wait_point = scene_buffer->wait_point,
|
||||
.release_merger = scene_buffer->release_merger,
|
||||
};
|
||||
if (surface->current.committed & WLR_SURFACE_STATE_BUFFER) {
|
||||
if (syncobj_surface_state != NULL) {
|
||||
options.wait_timeline = syncobj_surface_state->acquire_timeline;
|
||||
options.wait_point = syncobj_surface_state->acquire_point;
|
||||
options.release_merger = syncobj_surface_state->release_merger;
|
||||
} else if (syncobj_surface_state == NULL) {
|
||||
options.wait_timeline = NULL;
|
||||
options.wait_point = 0;
|
||||
options.release_merger = NULL;
|
||||
}
|
||||
}
|
||||
wlr_scene_buffer_set_buffer_with_options(scene_buffer,
|
||||
&surface->buffer->base, &options);
|
||||
|
||||
if (syncobj_surface_state != NULL &&
|
||||
(surface->current.committed & WLR_SURFACE_STATE_BUFFER) &&
|
||||
surface->buffer->source != NULL) {
|
||||
wlr_linux_drm_syncobj_v1_state_signal_release_with_buffer(syncobj_surface_state,
|
||||
surface->buffer->source);
|
||||
}
|
||||
} else {
|
||||
wlr_scene_buffer_set_buffer(scene_buffer, NULL);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
#include <wlr/util/region.h>
|
||||
#include <wlr/util/transform.h>
|
||||
#include "render/color.h"
|
||||
#include "render/drm_syncobj_merger.h"
|
||||
#include "types/wlr_output.h"
|
||||
#include "types/wlr_scene.h"
|
||||
#include "util/array.h"
|
||||
|
|
@ -128,6 +129,9 @@ void wlr_scene_node_destroy(struct wlr_scene_node *node) {
|
|||
scene_buffer_set_texture(scene_buffer, NULL);
|
||||
pixman_region32_fini(&scene_buffer->opaque_region);
|
||||
wlr_drm_syncobj_timeline_unref(scene_buffer->wait_timeline);
|
||||
if (scene_buffer->release_merger) {
|
||||
wlr_drm_syncobj_merger_unref(scene_buffer->release_merger);
|
||||
}
|
||||
|
||||
assert(wl_list_empty(&scene_buffer->events.output_leave.listener_list));
|
||||
assert(wl_list_empty(&scene_buffer->events.output_enter.listener_list));
|
||||
|
|
@ -847,16 +851,23 @@ static void scene_buffer_set_texture(struct wlr_scene_buffer *scene_buffer,
|
|||
}
|
||||
}
|
||||
|
||||
static void scene_buffer_set_wait_timeline(struct wlr_scene_buffer *scene_buffer,
|
||||
struct wlr_drm_syncobj_timeline *timeline, uint64_t point) {
|
||||
wlr_drm_syncobj_timeline_unref(scene_buffer->wait_timeline);
|
||||
if (timeline != NULL) {
|
||||
scene_buffer->wait_timeline = wlr_drm_syncobj_timeline_ref(timeline);
|
||||
scene_buffer->wait_point = point;
|
||||
} else {
|
||||
scene_buffer->wait_timeline = NULL;
|
||||
scene_buffer->wait_point = 0;
|
||||
static void scene_buffer_set_timelines(struct wlr_scene_buffer *scene_buffer,
|
||||
struct wlr_drm_syncobj_timeline *wait_timeline, uint64_t wait_point,
|
||||
struct wlr_drm_syncobj_merger *release_merger) {
|
||||
if (wait_timeline != NULL) {
|
||||
wait_timeline = wlr_drm_syncobj_timeline_ref(wait_timeline);
|
||||
}
|
||||
wlr_drm_syncobj_timeline_unref(scene_buffer->wait_timeline);
|
||||
scene_buffer->wait_timeline = wait_timeline;
|
||||
scene_buffer->wait_point = wait_point;
|
||||
|
||||
if (release_merger != NULL) {
|
||||
release_merger = wlr_drm_syncobj_merger_ref(release_merger);
|
||||
}
|
||||
if (scene_buffer->release_merger != NULL) {
|
||||
wlr_drm_syncobj_merger_unref(scene_buffer->release_merger);
|
||||
}
|
||||
scene_buffer->release_merger = release_merger;
|
||||
}
|
||||
|
||||
struct wlr_scene_buffer *wlr_scene_buffer_create(struct wlr_scene_tree *parent,
|
||||
|
|
@ -938,8 +949,8 @@ void wlr_scene_buffer_set_buffer_with_options(struct wlr_scene_buffer *scene_buf
|
|||
|
||||
scene_buffer_set_buffer(scene_buffer, buffer);
|
||||
scene_buffer_set_texture(scene_buffer, NULL);
|
||||
scene_buffer_set_wait_timeline(scene_buffer,
|
||||
options->wait_timeline, options->wait_point);
|
||||
scene_buffer_set_timelines(scene_buffer, options->wait_timeline, options->wait_point,
|
||||
options->release_merger);
|
||||
|
||||
if (update) {
|
||||
scene_node_update(&scene_buffer->node, NULL);
|
||||
|
|
@ -1199,6 +1210,16 @@ static struct wlr_texture *scene_buffer_get_texture(
|
|||
return texture;
|
||||
}
|
||||
|
||||
static void scene_buffer_sample(struct wlr_scene_buffer *buffer,
|
||||
struct wlr_scene_output_sample_event *event, struct wl_event_loop *loop) {
|
||||
if (event->release_timeline && buffer->release_merger) {
|
||||
wlr_drm_syncobj_merger_add(buffer->release_merger,
|
||||
event->release_timeline, event->release_point, loop);
|
||||
}
|
||||
|
||||
wl_signal_emit_mutable(&buffer->events.output_sample, event);
|
||||
}
|
||||
|
||||
void scene_node_get_size(struct wlr_scene_node *node, int *width, int *height) {
|
||||
*width = 0;
|
||||
*height = 0;
|
||||
|
|
@ -1553,8 +1574,10 @@ static void scene_entry_render(struct render_list_entry *entry, const struct ren
|
|||
struct wlr_scene_output_sample_event sample_event = {
|
||||
.output = data->output,
|
||||
.direct_scanout = false,
|
||||
.release_timeline = data->output->in_timeline,
|
||||
.release_point = data->output->in_point,
|
||||
};
|
||||
wl_signal_emit_mutable(&scene_buffer->events.output_sample, &sample_event);
|
||||
scene_buffer_sample(scene_buffer, &sample_event, data->output->output->event_loop);
|
||||
|
||||
if (entry->highlight_transparent_region) {
|
||||
wlr_render_pass_add_rect(data->render_pass, &(struct wlr_render_rect_options){
|
||||
|
|
@ -1785,7 +1808,10 @@ struct wlr_scene_output *wlr_scene_output_create(struct wlr_scene *scene,
|
|||
if (drm_fd >= 0 && output->backend->features.timeline &&
|
||||
output->renderer != NULL && output->renderer->features.timeline) {
|
||||
scene_output->in_timeline = wlr_drm_syncobj_timeline_create(drm_fd);
|
||||
if (scene_output->in_timeline == NULL) {
|
||||
scene_output->out_timeline = wlr_drm_syncobj_timeline_create(drm_fd);
|
||||
if (scene_output->in_timeline == NULL || scene_output->out_timeline == NULL) {
|
||||
wlr_drm_syncobj_timeline_unref(scene_output->in_timeline);
|
||||
wlr_drm_syncobj_timeline_unref(scene_output->out_timeline);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
|
@ -1840,7 +1866,14 @@ void wlr_scene_output_destroy(struct wlr_scene_output *scene_output) {
|
|||
wl_list_remove(&scene_output->output_commit.link);
|
||||
wl_list_remove(&scene_output->output_damage.link);
|
||||
wl_list_remove(&scene_output->output_needs_frame.link);
|
||||
wlr_drm_syncobj_timeline_unref(scene_output->in_timeline);
|
||||
if (scene_output->in_timeline != NULL) {
|
||||
wlr_drm_syncobj_timeline_signal(scene_output->in_timeline, UINT64_MAX);
|
||||
wlr_drm_syncobj_timeline_unref(scene_output->in_timeline);
|
||||
}
|
||||
if (scene_output->out_timeline != NULL) {
|
||||
wlr_drm_syncobj_timeline_signal(scene_output->out_timeline, UINT64_MAX);
|
||||
wlr_drm_syncobj_timeline_unref(scene_output->out_timeline);
|
||||
}
|
||||
wlr_color_transform_unref(scene_output->gamma_lut_color_transform);
|
||||
wlr_color_transform_unref(scene_output->prev_gamma_lut_color_transform);
|
||||
wlr_color_transform_unref(scene_output->prev_supplied_color_transform);
|
||||
|
|
@ -2136,6 +2169,12 @@ static enum scene_direct_scanout_result scene_entry_try_direct_scanout(
|
|||
if (buffer->wait_timeline != NULL) {
|
||||
wlr_output_state_set_wait_timeline(&pending, buffer->wait_timeline, buffer->wait_point);
|
||||
}
|
||||
|
||||
if (scene_output->out_timeline) {
|
||||
scene_output->out_point++;
|
||||
wlr_output_state_set_signal_timeline(&pending, scene_output->out_timeline, scene_output->out_point);
|
||||
}
|
||||
|
||||
if (!wlr_output_test_state(scene_output->output, &pending)) {
|
||||
wlr_output_state_finish(&pending);
|
||||
return SCANOUT_CANDIDATE;
|
||||
|
|
@ -2147,8 +2186,10 @@ static enum scene_direct_scanout_result scene_entry_try_direct_scanout(
|
|||
struct wlr_scene_output_sample_event sample_event = {
|
||||
.output = scene_output,
|
||||
.direct_scanout = true,
|
||||
.release_timeline = data->output->out_timeline,
|
||||
.release_point = data->output->out_point,
|
||||
};
|
||||
wl_signal_emit_mutable(&buffer->events.output_sample, &sample_event);
|
||||
scene_buffer_sample(buffer, &sample_event, scene_output->output->event_loop);
|
||||
return SCANOUT_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
@ -2606,6 +2647,9 @@ bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output,
|
|||
if (scene_output->in_timeline != NULL) {
|
||||
wlr_output_state_set_wait_timeline(state, scene_output->in_timeline,
|
||||
scene_output->in_point);
|
||||
scene_output->out_point++;
|
||||
wlr_output_state_set_signal_timeline(state, scene_output->out_timeline,
|
||||
scene_output->out_point);
|
||||
}
|
||||
|
||||
if (!render_gamma_lut) {
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include <xf86drm.h>
|
||||
#include "config.h"
|
||||
#include "linux-drm-syncobj-v1-protocol.h"
|
||||
#include "render/drm_syncobj_merger.h"
|
||||
|
||||
#define LINUX_DRM_SYNCOBJ_V1_VERSION 1
|
||||
|
||||
|
|
@ -158,6 +159,9 @@ static void surface_synced_finish_state(void *_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->release_timeline);
|
||||
if (state->release_merger != NULL) {
|
||||
wlr_drm_syncobj_merger_unref(state->release_merger);
|
||||
}
|
||||
}
|
||||
|
||||
static void surface_synced_move_state(void *_dst, void *_src) {
|
||||
|
|
@ -168,10 +172,31 @@ static void surface_synced_move_state(void *_dst, void *_src) {
|
|||
*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);
|
||||
struct wlr_linux_drm_syncobj_surface_v1_state *state = &surface->current;
|
||||
|
||||
if (state->release_merger != NULL || state->release_timeline == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
state->release_merger = wlr_drm_syncobj_merger_create(
|
||||
state->release_timeline, state->release_point);
|
||||
if (state->release_merger == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct wl_display *display = wl_client_get_display(surface->resource->client);
|
||||
wlr_drm_syncobj_merger_add(state->release_merger,
|
||||
state->acquire_timeline, state->acquire_point, wl_display_get_event_loop(display));
|
||||
}
|
||||
|
||||
static const struct wlr_surface_synced_impl surface_synced_impl = {
|
||||
.state_size = sizeof(struct wlr_linux_drm_syncobj_surface_v1_state),
|
||||
.finish_state = surface_synced_finish_state,
|
||||
.move_state = surface_synced_move_state,
|
||||
.commit = surface_synced_commit,
|
||||
};
|
||||
|
||||
static void manager_handle_destroy(struct wl_client *client,
|
||||
|
|
@ -422,6 +447,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) {
|
||||
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)) {
|
||||
wlr_log(WLR_INFO, "DRM syncobj eventfd unavailable, disabling linux-drm-syncobj-v1");
|
||||
return NULL;
|
||||
|
|
@ -475,11 +505,7 @@ struct release_signaller {
|
|||
static void release_signaller_handle_buffer_release(struct wl_listener *listener, void *data) {
|
||||
struct release_signaller *signaller = wl_container_of(listener, signaller, buffer_release);
|
||||
|
||||
if (drmSyncobjTimelineSignal(signaller->timeline->drm_fd, &signaller->timeline->handle,
|
||||
&signaller->point, 1) != 0) {
|
||||
wlr_log(WLR_ERROR, "drmSyncobjTimelineSignal() failed");
|
||||
}
|
||||
|
||||
wlr_drm_syncobj_timeline_signal(signaller->timeline, signaller->point);
|
||||
wlr_drm_syncobj_timeline_unref(signaller->timeline);
|
||||
wl_list_remove(&signaller->buffer_release.link);
|
||||
free(signaller);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue