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 f4719a3c..a6c97dec 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 e51be4c5..2e5c39f5 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 b885fd08..e1aea1be 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 278ecb9e..a9a0ccb2 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);