diff --git a/types/wlr_output.c b/types/wlr_output.c index 325b0233..9089ea5c 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -736,8 +736,19 @@ bool wlr_output_commit(struct wlr_output *output) { }; wlr_signal_emit_safe(&output->events.precommit, &pre_event); - if (!output->impl->commit(output)) { + // output_clear_back_buffer detaches the buffer from the renderer. This is + // important to do before calling impl->commit(), because this marks an + // implicit rendering synchronization point. The backend needs it to avoid + // displaying a buffer when asynchronous GPU work isn't finished. + struct wlr_buffer *back_buffer = NULL; + if ((output->pending.committed & WLR_OUTPUT_STATE_BUFFER) && + output->back_buffer != NULL) { + back_buffer = wlr_buffer_lock(output->back_buffer); output_clear_back_buffer(output); + } + + if (!output->impl->commit(output)) { + wlr_buffer_unlock(back_buffer); output_state_clear(&output->pending); return false; } @@ -782,12 +793,11 @@ bool wlr_output_commit(struct wlr_output *output) { if (output->pending.committed & WLR_OUTPUT_STATE_BUFFER) { output->frame_pending = true; output->needs_frame = false; + } - if (output->back_buffer != NULL) { - wlr_swapchain_set_buffer_submitted(output->swapchain, - output->back_buffer); - output_clear_back_buffer(output); - } + if (back_buffer != NULL) { + wlr_swapchain_set_buffer_submitted(output->swapchain, back_buffer); + wlr_buffer_unlock(back_buffer); } uint32_t committed = output->pending.committed;