From 294642363f1717927b9ecc13d21900b7bf77e871 Mon Sep 17 00:00:00 2001 From: Mars-Wave <57585293+Mars-Wave@users.noreply.github.com> Date: Sun, 23 Nov 2025 22:05:32 +0100 Subject: [PATCH] Recycle failed capture buffers, release when off --- src/main.c | 1 + src/outputs.c | 39 +++++++++++++++++++++++++++++++-------- src/wdisplays.h | 5 +++++ 3 files changed, 37 insertions(+), 8 deletions(-) diff --git a/src/main.c b/src/main.c index 6174902..b01895d 100644 --- a/src/main.c +++ b/src/main.c @@ -183,6 +183,7 @@ static void update_tick_callback(struct wd_state *state) { if (state->capture_timeout != -1) { g_source_remove(state->capture_timeout); state->capture_timeout = -1; + wd_capture_release(state); } } else if (state->capture_timeout == -1) { state->capture_due = true; diff --git a/src/outputs.c b/src/outputs.c index 4a61837..94a19db 100644 --- a/src/outputs.c +++ b/src/outputs.c @@ -252,6 +252,21 @@ static void capture_flags(void *data, frame->y_invert = !!(flags & ZWLR_SCREENCOPY_FRAME_V1_FLAGS_Y_INVERT); } +static void keep_as_spare(struct wd_frame *frame) { + struct wd_output *output = frame->output; + if (output->spare != NULL) { + wd_frame_destroy(frame); + return; + } + if (frame->wlr_frame != NULL) { + zwlr_screencopy_frame_v1_destroy(frame->wlr_frame); + frame->wlr_frame = NULL; + } + wl_list_remove(&frame->link); + wl_list_init(&frame->link); + output->spare = frame; +} + static void capture_ready(void *data, struct zwlr_screencopy_frame_v1 *wlr_frame, uint32_t tv_sec_hi, uint32_t tv_sec_lo, uint32_t tv_nsec) { @@ -268,13 +283,7 @@ static void capture_ready(void *data, struct wd_frame *frame_iter, *frame_tmp; wl_list_for_each_safe(frame_iter, frame_tmp, &output->frames, link) { if (frame != frame_iter) { - if (output->spare == NULL) { - wl_list_remove(&frame_iter->link); - wl_list_init(&frame_iter->link); - output->spare = frame_iter; - } else { - wd_frame_destroy(frame_iter); - } + keep_as_spare(frame_iter); } } } @@ -282,7 +291,7 @@ static void capture_ready(void *data, static void capture_failed(void *data, struct zwlr_screencopy_frame_v1 *wlr_frame) { struct wd_frame *frame = data; - wd_frame_destroy(frame); + keep_as_spare(frame); } struct zwlr_screencopy_frame_v1_listener capture_listener = { @@ -330,6 +339,20 @@ void wd_capture_frame(struct wd_state *state) { } } +void wd_capture_release(struct wd_state *state) { + struct wd_output *output; + wl_list_for_each(output, &state->outputs, link) { + struct wd_frame *frame, *frame_tmp; + wl_list_for_each_safe(frame, frame_tmp, &output->frames, link) { + wd_frame_destroy(frame); + } + if (output->spare != NULL) { + wd_frame_destroy(output->spare); + output->spare = NULL; + } + } +} + static void wd_output_destroy(struct wd_output *output) { struct wd_frame *frame, *frame_tmp; wl_list_for_each_safe(frame, frame_tmp, &output->frames, link) { diff --git a/src/wdisplays.h b/src/wdisplays.h index 2159d93..e5cbd0d 100644 --- a/src/wdisplays.h +++ b/src/wdisplays.h @@ -285,6 +285,11 @@ void wd_capture_frame(struct wd_state *state); */ void wd_capture_wait(struct wd_state *state, struct wl_display *display); +/* + * Frees all captured frames and their buffers. + */ +void wd_capture_release(struct wd_state *state); + /* * Updates the UI stack of all heads. Does not update individual head forms. * Useful for when a display is plugged/unplugged and we want to add/remove