mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2026-04-12 08:21:33 -04:00
ext_image_capture_source_v1/output: wait for render timeline
When capturing an output that uses timelines, delay the capture source 'frame' event until buffer content is readable
This commit is contained in:
parent
fd870f6d27
commit
bd8ed156aa
1 changed files with 57 additions and 15 deletions
|
|
@ -2,6 +2,7 @@
|
|||
#include <stdlib.h>
|
||||
#include <wlr/interfaces/wlr_ext_image_capture_source_v1.h>
|
||||
#include <wlr/interfaces/wlr_output.h>
|
||||
#include <wlr/render/drm_syncobj.h>
|
||||
#include <wlr/render/swapchain.h>
|
||||
#include <wlr/types/wlr_ext_image_capture_source_v1.h>
|
||||
#include <wlr/types/wlr_ext_image_copy_capture_v1.h>
|
||||
|
|
@ -30,6 +31,13 @@ struct wlr_ext_output_image_capture_source_v1 {
|
|||
struct wlr_output *output;
|
||||
|
||||
struct wl_listener output_commit;
|
||||
bool has_commit_waiter;
|
||||
struct wlr_drm_syncobj_timeline_waiter commit_waiter;
|
||||
struct {
|
||||
pixman_region32_t damage;
|
||||
struct wlr_buffer *buffer;
|
||||
struct timespec when;
|
||||
} next_event;
|
||||
|
||||
struct output_cursor_source cursor;
|
||||
|
||||
|
|
@ -122,6 +130,28 @@ static void source_update_buffer_constraints(struct wlr_ext_output_image_capture
|
|||
output->swapchain, output->renderer);
|
||||
}
|
||||
|
||||
static void source_send_frame_event(
|
||||
struct wlr_ext_output_image_capture_source_v1 *source) {
|
||||
struct wlr_ext_output_image_capture_source_v1_frame_event frame_event = {
|
||||
.base = {
|
||||
.damage = &source->next_event.damage,
|
||||
},
|
||||
.buffer = source->next_event.buffer,
|
||||
.when = source->next_event.when,
|
||||
};
|
||||
wl_signal_emit_mutable(&source->base.events.frame, &frame_event);
|
||||
wlr_buffer_unlock(source->next_event.buffer);
|
||||
source->next_event.buffer = NULL;
|
||||
}
|
||||
|
||||
static void source_handle_commit_ready(
|
||||
struct wlr_drm_syncobj_timeline_waiter *waiter) {
|
||||
struct wlr_ext_output_image_capture_source_v1 *source = wl_container_of(waiter, source, commit_waiter);
|
||||
source_send_frame_event(source);
|
||||
source->has_commit_waiter = false;
|
||||
wlr_drm_syncobj_timeline_waiter_finish(waiter);
|
||||
}
|
||||
|
||||
static void source_handle_output_commit(struct wl_listener *listener,
|
||||
void *data) {
|
||||
struct wlr_ext_output_image_capture_source_v1 *source = wl_container_of(listener, source, output_commit);
|
||||
|
|
@ -132,29 +162,35 @@ static void source_handle_output_commit(struct wl_listener *listener,
|
|||
source_update_buffer_constraints(source);
|
||||
}
|
||||
|
||||
if (source->num_started == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event->state->committed & WLR_OUTPUT_STATE_BUFFER) {
|
||||
struct wlr_buffer *buffer = event->state->buffer;
|
||||
|
||||
pixman_region32_t full_damage;
|
||||
pixman_region32_init_rect(&full_damage, 0, 0, buffer->width, buffer->height);
|
||||
wlr_buffer_unlock(source->next_event.buffer);
|
||||
source->next_event.buffer = wlr_buffer_lock(buffer);
|
||||
source->next_event.when = event->when; // TODO: predict next presentation time instead
|
||||
|
||||
const pixman_region32_t *damage;
|
||||
if (event->state->committed & WLR_OUTPUT_STATE_DAMAGE) {
|
||||
damage = &event->state->damage;
|
||||
pixman_region32_copy(&source->next_event.damage, &event->state->damage);
|
||||
} else {
|
||||
damage = &full_damage;
|
||||
pixman_region32_clear(&source->next_event.damage);
|
||||
pixman_region32_union_rect(&source->next_event.damage,
|
||||
&source->next_event.damage, 0, 0, buffer->width, buffer->height);
|
||||
}
|
||||
|
||||
struct wlr_ext_output_image_capture_source_v1_frame_event frame_event = {
|
||||
.base = {
|
||||
.damage = damage,
|
||||
},
|
||||
.buffer = buffer,
|
||||
.when = event->when, // TODO: predict next presentation time instead
|
||||
};
|
||||
wl_signal_emit_mutable(&source->base.events.frame, &frame_event);
|
||||
|
||||
pixman_region32_fini(&full_damage);
|
||||
if (event->state->committed & WLR_OUTPUT_STATE_WAIT_TIMELINE) {
|
||||
if (source->has_commit_waiter) {
|
||||
wlr_drm_syncobj_timeline_waiter_finish(&source->commit_waiter);
|
||||
}
|
||||
source->has_commit_waiter = wlr_drm_syncobj_timeline_waiter_init(
|
||||
&source->commit_waiter, event->state->wait_timeline, event->state->wait_point,
|
||||
0, event->output->event_loop, source_handle_commit_ready);
|
||||
} else {
|
||||
source_send_frame_event(source);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -168,6 +204,11 @@ static void output_addon_destroy(struct wlr_addon *addon) {
|
|||
output_cursor_source_finish(&source->cursor);
|
||||
wl_list_remove(&source->output_commit.link);
|
||||
wlr_addon_finish(&source->addon);
|
||||
if (source->has_commit_waiter) {
|
||||
wlr_drm_syncobj_timeline_waiter_finish(&source->commit_waiter);
|
||||
}
|
||||
pixman_region32_fini(&source->next_event.damage);
|
||||
wlr_buffer_unlock(source->next_event.buffer);
|
||||
free(source);
|
||||
}
|
||||
|
||||
|
|
@ -206,6 +247,7 @@ static void output_manager_handle_create_source(struct wl_client *client,
|
|||
source_update_buffer_constraints(source);
|
||||
|
||||
output_cursor_source_init(&source->cursor, output);
|
||||
pixman_region32_init(&source->next_event.damage);
|
||||
}
|
||||
|
||||
if (!wlr_ext_image_capture_source_v1_create_resource(&source->base, client, new_id)) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue