Skip to content
This repository has been archived by the owner on Nov 1, 2021. It is now read-only.

Rapid window updates result in incorrect frame order in nested Sway sessions #3020

Closed
vyivel opened this issue Jul 4, 2021 · 7 comments · Fixed by #3027
Closed

Rapid window updates result in incorrect frame order in nested Sway sessions #3020

vyivel opened this issue Jul 4, 2021 · 7 comments · Fixed by #3027

Comments

@vyivel
Copy link

vyivel commented Jul 4, 2021

  • Sway version: 1.6.1
  • Configuration: none/irrelevant (tested with sway -c /dev/null)

Description

Sometimes Sway renders frames out of order when run with a Wayland/X11 backend, resulting in older frames being seen after newer ones. At least, that's what it looks like.

Reproduction

  1. Start Sway
  2. Start weston-terminal (or any other program capable of updating its window contents rapidly)
  3. Hold a key
  4. Observe the incorrect rendering order, something like this:
    Frame 1: $ aaaaaaaaaa
    Frame 2: $ aaaaaa
    Frame 3: $ aaaaaaaaaaaaaaaa

This isn't reproducible with Sway 1.6 or when the DRM backend is used.

Notes

  • This might be a wlroots issue; 543f5b3 is the commit that causes this behavior (under Wayland), compiling Sway with a commit before that fixes the problem.
  • -D damage=highlight has no effect for nested Sway sessions, which may or may not be related to this. Also introduced with the wlroots commit mentioned above.
  • It's easier to reproduce this under a high CPU load (can be simulated with cpulimit -l 1 sway -c /dev/null).
@emersion emersion transferred this issue from swaywm/sway Jul 5, 2021
@emersion emersion added this to the 0.14.1 milestone Jul 5, 2021
@emersion
Copy link
Member

emersion commented Jul 5, 2021

Just to understand the bug better, does this wlroots patch help? https://l.sr.ht/qsvv.txt

@vyivel
Copy link
Author

vyivel commented Jul 5, 2021

Nope, the issue persists.

@emersion
Copy link
Member

emersion commented Jul 6, 2021

Okay, new attempt: https://l.sr.ht/BSq5.txt

If this doesn't work, can you try -Ddamage=rerender and see if it helps? The flag disables damage tracking and forces the whole output to be re-rendered each frame.

@vyivel
Copy link
Author

vyivel commented Jul 7, 2021

This patch fixes -Ddamage=highlight (seems like nested sessions using WLR_OUTPUT_STATE_BUFFER_SCANOUT damage the whole output each frame anyway), but doesn't fix the flickering issue. -Ddamage=rerender has no effect.

@vyivel
Copy link
Author

vyivel commented Jul 7, 2021

wlr_output_damage doesn't seem to be relevant at all, as the issue is reproducible with tinywl.

@emersion
Copy link
Member

emersion commented Jul 7, 2021

Thanks for confirming this isn't a damage tracking issue.

Here's yet another attempt: https://l.sr.ht/xcCP.txt. Can you try it? (Sorry, I'm having trouble reproducing reliably.)

@vyivel
Copy link
Author

vyivel commented Jul 7, 2021

This patch does fix the issue.

emersion added a commit to emersion/wlroots that referenced this issue Jul 7, 2021
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: swaywm#3020
emersion added a commit to emersion/wlroots that referenced this issue Jul 7, 2021
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: swaywm#3020
bl4ckb0ne pushed a commit that referenced this issue Jul 7, 2021
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: #3020
emersion added a commit to emersion/wlroots that referenced this issue Jul 7, 2021
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: swaywm#3020
(cherry picked from commit c2bd63c)
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Development

Successfully merging a pull request may close this issue.

2 participants