aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Ser <contact@emersion.fr>2021-07-07 17:09:17 +0200
committerSimon Zeni <simon@bl4ckb0ne.ca>2021-07-07 12:00:43 -0400
commitc2bd63c1865358ec22e467dad70159dac0afbed9 (patch)
treeea4b737342b6254306818c665ab7d7420b8bfb5a
parent4c7657ee629874df1d33f850bfc33fd9af556888 (diff)
output: detach buffer from renderer before commit
Right now we rely entirely on implicit sync for synchronizing access to GPU buffers. Implicit sync works by setting synchronization points on the buffer in writers, and letting readers wait on these sync points before accessing the buffer. With OpenGL, sync points are created using functions such as eglSwapBuffers or glFlush. If none of these special functions are called, no sync point will be created and readers will potentially access a buffer that hasn't finished rendering yet. In the context of wlroots, OpenGL is the writer and the backend (KMS or parent Wayland/X11 session) is the reader. After we're done rendering a frame, and before passing that frame to the backend, we need to call glFlush. glFlush is called when the buffer is detached from the renderer. This is a task done by output_clear_back_buffer. So let's call this function before invoking the impl->commit hook, instead of calling it after. All of this is maybe a little tricky to get right with the current renderer_bind_buffer API. The new wlr_renderer_begin_with_buffer API is much better, because glFlush is called on wlr_renderer_end, so it's more intuitive. Closes: https://github.com/swaywm/wlroots/issues/3020
-rw-r--r--types/wlr_output.c22
1 files changed, 16 insertions, 6 deletions
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;