ext_image_capture_source_v1/output: wait for explicit sync

Synchronize from the scene render to the copy to capture client.
Buffer return is still covered by implicit sync.
We know this is the scene's render buffer, direct scanout is disallowed
for the output capture source.
This commit is contained in:
Félix Poisot 2026-03-27 20:06:57 +00:00
parent 4a9692013d
commit 1433c1ee9e
4 changed files with 29 additions and 11 deletions

View file

@ -15,6 +15,7 @@
#include <time.h>
struct wlr_renderer;
struct wlr_drm_syncobj_timeline;
struct wlr_ext_image_copy_capture_manager_v1 {
struct wl_global *global;
@ -82,6 +83,7 @@ void wlr_ext_image_copy_capture_frame_v1_fail(struct wlr_ext_image_copy_capture_
* Copy a struct wlr_buffer into the client-provided buffer for the frame.
*/
bool wlr_ext_image_copy_capture_frame_v1_copy_buffer(struct wlr_ext_image_copy_capture_frame_v1 *frame,
struct wlr_buffer *src, struct wlr_renderer *renderer);
struct wlr_buffer *src, struct wlr_renderer *renderer,
struct wlr_drm_syncobj_timeline *wait_timeline, uint64_t wait_point);
#endif

View file

@ -41,6 +41,8 @@ struct wlr_ext_output_image_capture_source_v1_frame_event {
struct wlr_ext_image_capture_source_v1_frame_event base;
struct wlr_buffer *buffer;
struct timespec when;
struct wlr_drm_syncobj_timeline *wait_timeline;
uint64_t wait_point;
};
static void output_source_start(struct wlr_ext_image_capture_source_v1 *base,
@ -86,7 +88,8 @@ static void output_source_copy_frame(struct wlr_ext_image_capture_source_v1 *bas
wl_container_of(base_event, event, base);
if (wlr_ext_image_copy_capture_frame_v1_copy_buffer(frame,
event->buffer, source->output->renderer)) {
event->buffer, source->output->renderer,
event->wait_timeline, event->wait_point)) {
wlr_ext_image_copy_capture_frame_v1_ready(frame,
source->output->transform, &event->when);
}
@ -152,6 +155,10 @@ static void source_handle_output_commit(struct wl_listener *listener,
.buffer = buffer,
.when = event->when, // TODO: predict next presentation time instead
};
if (event->state->committed & WLR_OUTPUT_STATE_WAIT_TIMELINE) {
frame_event.wait_timeline = event->state->wait_timeline;
frame_event.wait_point = event->state->wait_point;
}
wl_signal_emit_mutable(&source->base.events.frame, &frame_event);
pixman_region32_fini(&full_damage);
@ -279,6 +286,8 @@ static void output_cursor_source_copy_frame(struct wlr_ext_image_capture_source_
struct wlr_ext_image_copy_capture_frame_v1 *frame,
struct wlr_ext_image_capture_source_v1_frame_event *base_event) {
struct output_cursor_source *cursor_source = wl_container_of(base, cursor_source, base);
struct wlr_ext_output_image_capture_source_v1_frame_event *event =
wl_container_of(base_event, event, base);
struct wlr_buffer *src_buffer = cursor_source->output->cursor_front_buffer;
if (src_buffer == NULL) {
@ -287,7 +296,8 @@ static void output_cursor_source_copy_frame(struct wlr_ext_image_capture_source_
}
if (!wlr_ext_image_copy_capture_frame_v1_copy_buffer(frame,
src_buffer, cursor_source->output->renderer)) {
src_buffer, cursor_source->output->renderer,
event->wait_timeline, event->wait_point)) {
return;
}

View file

@ -149,7 +149,7 @@ static void source_copy_frame(struct wlr_ext_image_capture_source_v1 *base,
struct scene_node_source_frame_event *event = wl_container_of(base_event, event, base);
if (wlr_ext_image_copy_capture_frame_v1_copy_buffer(frame,
event->buffer, source->output.renderer)) {
event->buffer, source->output.renderer, NULL, 0)) {
wlr_ext_image_copy_capture_frame_v1_ready(frame,
source->output.transform, &event->when);
}

View file

@ -105,9 +105,9 @@ void wlr_ext_image_copy_capture_frame_v1_ready(struct wlr_ext_image_copy_capture
frame_destroy(frame);
}
static bool copy_dmabuf(struct wlr_buffer *dst,
struct wlr_buffer *src, struct wlr_renderer *renderer,
const pixman_region32_t *clip) {
static bool copy_dmabuf(struct wlr_buffer *dst, struct wlr_buffer *src,
struct wlr_renderer *renderer, const pixman_region32_t *clip,
struct wlr_drm_syncobj_timeline *wait_timeline, uint64_t wait_point) {
struct wlr_texture *texture = wlr_texture_from_buffer(renderer, src);
if (texture == NULL) {
return false;
@ -123,6 +123,8 @@ static bool copy_dmabuf(struct wlr_buffer *dst,
.texture = texture,
.clip = clip,
.blend_mode = WLR_RENDER_BLEND_MODE_NONE,
.wait_timeline = wait_timeline,
.wait_point = wait_point,
});
ok = wlr_render_pass_submit(pass);
@ -133,7 +135,8 @@ out:
}
static bool copy_shm(void *data, uint32_t format, size_t stride,
struct wlr_buffer *src, struct wlr_renderer *renderer) {
struct wlr_buffer *src, struct wlr_renderer *renderer,
struct wlr_drm_syncobj_timeline *wait_timeline, uint64_t wait_point) {
// TODO: bypass renderer if source buffer supports data ptr access
struct wlr_texture *texture = wlr_texture_from_buffer(renderer, src);
if (!texture) {
@ -145,6 +148,8 @@ static bool copy_shm(void *data, uint32_t format, size_t stride,
.data = data,
.format = format,
.stride = stride,
.wait_timeline = wait_timeline,
.wait_point = wait_point,
});
wlr_texture_destroy(texture);
@ -153,7 +158,8 @@ static bool copy_shm(void *data, uint32_t format, size_t stride,
}
bool wlr_ext_image_copy_capture_frame_v1_copy_buffer(struct wlr_ext_image_copy_capture_frame_v1 *frame,
struct wlr_buffer *src, struct wlr_renderer *renderer) {
struct wlr_buffer *src, struct wlr_renderer *renderer,
struct wlr_drm_syncobj_timeline *wait_timeline, uint64_t wait_point) {
struct wlr_buffer *dst = frame->buffer;
if (src->width != dst->width || src->height != dst->height) {
@ -174,7 +180,7 @@ bool wlr_ext_image_copy_capture_frame_v1_copy_buffer(struct wlr_ext_image_copy_c
ok = false;
failure_reason = EXT_IMAGE_COPY_CAPTURE_FRAME_V1_FAILURE_REASON_BUFFER_CONSTRAINTS;
} else {
ok = copy_dmabuf(dst, src, renderer, &frame->buffer_damage);
ok = copy_dmabuf(dst, src, renderer, &frame->buffer_damage, wait_timeline, wait_point);
}
} else if (wlr_buffer_begin_data_ptr_access(dst,
WLR_BUFFER_DATA_PTR_ACCESS_WRITE, &data, &format, &stride)) {
@ -182,7 +188,7 @@ bool wlr_ext_image_copy_capture_frame_v1_copy_buffer(struct wlr_ext_image_copy_c
ok = false;
failure_reason = EXT_IMAGE_COPY_CAPTURE_FRAME_V1_FAILURE_REASON_BUFFER_CONSTRAINTS;
} else {
ok = copy_shm(data, format, stride, src, renderer);
ok = copy_shm(data, format, stride, src, renderer, wait_timeline, wait_point);
}
wlr_buffer_end_data_ptr_access(dst);
}