From 83af3202f94fa49822039f051070be1491854c24 Mon Sep 17 00:00:00 2001 From: Rose Hudson Date: Sat, 26 Aug 2023 16:01:46 +0100 Subject: [PATCH] output: defer fake present events until after commit Since headless and wayland-without-presentation-feedback were firing present inside their commit impls, present was getting fired before commit, which is cursed. Defer this with an idle timer so that commit handlers can run before present handlers. --- backend/headless/output.c | 2 +- backend/wayland/output.c | 2 +- include/types/wlr_output.h | 2 ++ types/output/output.c | 40 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 44 insertions(+), 2 deletions(-) diff --git a/backend/headless/output.c b/backend/headless/output.c index f4719a3c6..a6c97dec6 100644 --- a/backend/headless/output.c +++ b/backend/headless/output.c @@ -71,7 +71,7 @@ static bool output_commit(struct wlr_output *wlr_output, .commit_seq = wlr_output->commit_seq + 1, .presented = true, }; - wlr_output_send_present(wlr_output, &present_event); + output_defer_present(wlr_output, present_event); wl_event_source_timer_update(output->frame_timer, output->frame_delay); } diff --git a/backend/wayland/output.c b/backend/wayland/output.c index e51be4c55..2e5c39f51 100644 --- a/backend/wayland/output.c +++ b/backend/wayland/output.c @@ -590,7 +590,7 @@ static bool output_commit(struct wlr_output *wlr_output, .commit_seq = wlr_output->commit_seq + 1, .presented = true, }; - wlr_output_send_present(wlr_output, &present_event); + output_defer_present(wlr_output, present_event); } } diff --git a/include/types/wlr_output.h b/include/types/wlr_output.h index b885fd084..e1aea1be1 100644 --- a/include/types/wlr_output.h +++ b/include/types/wlr_output.h @@ -21,4 +21,6 @@ bool output_cursor_set_texture(struct wlr_output_cursor *cursor, int dst_width, int dst_height, enum wl_output_transform transform, int32_t hotspot_x, int32_t hotspot_y); +void output_defer_present(struct wlr_output *output, struct wlr_output_event_present event); + #endif diff --git a/types/output/output.c b/types/output/output.c index 278ecb9ed..a9a0ccb2d 100644 --- a/types/output/output.c +++ b/types/output/output.c @@ -927,6 +927,46 @@ void wlr_output_send_present(struct wlr_output *output, wl_signal_emit_mutable(&output->events.present, event); } +struct deferred_present_event { + struct wlr_output *output; + struct wl_event_source *idle_source; + struct wlr_output_event_present event; + struct wl_listener output_destroy; +}; + +static void deferred_present_event_destroy(struct deferred_present_event *deferred) { + wl_list_remove(&deferred->output_destroy.link); + free(deferred); +} + +static void deferred_present_event_handle_idle(void *data) { + struct deferred_present_event *deferred = data; + wlr_output_send_present(deferred->output, &deferred->event); + deferred_present_event_destroy(deferred); +} + +static void deferred_present_event_handle_output_destroy(struct wl_listener *listener, void *data) { + struct deferred_present_event *deferred = wl_container_of(listener, deferred, output_destroy); + wl_event_source_remove(deferred->idle_source); + deferred_present_event_destroy(deferred); +} + +void output_defer_present(struct wlr_output *output, struct wlr_output_event_present event) { + struct deferred_present_event *deferred = calloc(1, sizeof(struct wlr_output_event_present)); + if (!deferred) { + return; + } + *deferred = (struct deferred_present_event){ + .output = output, + .event = event, + }; + deferred->output_destroy.notify = deferred_present_event_handle_output_destroy; + wl_signal_add(&output->events.destroy, &deferred->output_destroy); + + struct wl_event_loop *ev = wl_display_get_event_loop(output->display); + deferred->idle_source = wl_event_loop_add_idle(ev, deferred_present_event_handle_idle, deferred); +} + void wlr_output_send_request_state(struct wlr_output *output, const struct wlr_output_state *state) { uint32_t unchanged = output_compare_state(output, state);