<html>
<head>
<base href="https://bugs.freedesktop.org/" />
</head>
<body>
<p>
<div>
<b><a class="bz_bug_link
bz_status_NEW "
title="NEW --- - Weston-simple-egl fullscreening causes client application flicker"
href="https://bugs.freedesktop.org/show_bug.cgi?id=72863#c5">Comment # 5</a>
on <a class="bz_bug_link
bz_status_NEW "
title="NEW --- - Weston-simple-egl fullscreening causes client application flicker"
href="https://bugs.freedesktop.org/show_bug.cgi?id=72863">bug 72863</a>
from <span class="vcard"><a class="email" href="mailto:neil@linux.intel.com" title="Neil Roberts <neil@linux.intel.com>"> <span class="fn">Neil Roberts</span></a>
</span></b>
<pre>I think I understand why this is happening. The client is sitting in a loop
doing two things: rendering and then swapping the buffers. For the sake of this
explanation the only thing we care about in the rendering part is that it calls
get_back_bo to get a new back buffer. While swapping it does two important
things: it waits for a frame callback and attaches a buffer. After the client
attaches a buffer the compositor will go off and asynchronously do a render.
The render doesn't have any effect on the client until it waits for the frame
callback where it might receive a buffer release event so for the sake of
argument we can imagine the rendering only happens during the wait.
Mesa 10.0 has slots for three buffers which we will call 1, 2 and 3. These are
created on demand but for the example we can imagine they always exist. The
lifecycle of the buffers is like this:
At first all of the buffers are available to the client.
*Client side* *Compositor side*
Free: 1 2 3 Attached to surface:
Rendering: Next scanout:
current scanout:
== get_back_bo:
The client will start rendering its first frame and call get_back_bo to grab
the first free buffer.
*Client side* *Compositor side*
Free: 2 3 Attached to surface:
Rendering: 1 Next scanout:
current scanout:
== wait:
Before swapping, the client will wait for a frame callback. There hasn't been a
frame yet so this does nothing.
*Client side* *Compositor side*
Free: 2 3 Attached to surface:
Rendering: 1 Next scanout:
current scanout:
== attach:
The client will then attach the buffer it rendered to and the compositor will
go off and do a render itself. The compositor was previously sitting idle so it
will do this render immediately without waiting for a page flip.
*Client side* *Compositor side*
Free: 2 3 Attached to surface: 1
Rendering: Next scanout:
current scanout:
== get_back_bo:
The client will now grab another buffer to start rendering the second frame.
*Client side* *Compositor side*
Free: 3 Attached to surface: 1
Rendering: 2 Next scanout:
current scanout:
== wait:
Before swapping it will wait for the frame callback from the first frame. At
this point we can assume the compositor has finished the render which means it
will have queued a page flip with the first buffer.
*Client side* *Compositor side*
Free: 3 Attached to surface: 1
Rendering: 2 Next scanout: 1
current scanout:
== attach:
Now the client attaches the second frame...
*Client side* *Compositor side*
Free: 3 Attached to surface: 2
Rendering: Next scanout: 1
current scanout:
== get_back_bo:
and grabs a buffer for its third frame.
*Client side* *Compositor side*
Free: Attached to surface: 2
Rendering: 3 Next scanout: 1
current scanout:
== wait:
The client now waits for the frame callback. The compositor will only send this
once it has finished rendering and it will only do that after the page flip for
the previous frame has completed. The compositor is still holding onto both
buffers so no release event is sent.
*Client side* *Compositor side*
Free: Attached to surface: 2
Rendering: 3 Next scanout: 2
current scanout: 1
== attach:
Now the client attaches its third frame and the compositor is still holding on
to all three buffers.
*Client side* *Compositor side*
Free: Attached to surface: 3
Rendering: Next scanout: 2
current scanout: 1
== get_back_bo:
The compositor will now try to grab a buffer for the fourth frame but this is
not possible because they are all locked. get_back_bo will return -1 and all of
the rendering will be discarded.
*Client side* *Compositor side*
Free: Attached to surface: 3
Rendering: -1 Next scanout: 2
current scanout: 1
== wait:
Again will we wait until the compositor was finished painting frame three
before attaching frame four. This entails waiting for the page flip from frame
2 which will cause a release event to be sent for the first frame. The client
will catch this before attaching its buffer.
*Client side* *Compositor side*
Free: 1 Attached to surface: 3
Rendering: -1 Next scanout: 3
current scanout: 2
== attach:
eglSwapBuffers calls get_back_bo a final time just before attaching a buffer.
At this point there is a free buffer available so we immediately attach it. The
buffer hasn't been rendered to so it still contains the image for frame 1.
*Client side* *Compositor side*
Free: Attached to surface: 1
Rendering: Next scanout: 3
current scanout: 2
== get_back_bo:
The client no longer has any buffers again so get_back_bo will fail again and
it is back at the same state it was before so the loop should just continue
like that.
*Client side* *Compositor side*
Free: Attached to surface: 1
Rendering: -1 Next scanout: 3
current scanout: 2
So basically I think this is just a symptom of the problem described in this
message on the mailing list:
<a href="http://lists.freedesktop.org/archives/wayland-devel/2013-December/012456.html">http://lists.freedesktop.org/archives/wayland-devel/2013-December/012456.html</a>
The core problem is that if a client doesn't wait for a frame callback before
starting to render then it will end up using one more buffer than it should
need. In that email the client isn't fullscreen so the client should only need
two buffers and ends up using three. In this case the client is fullscreen so
it should need three buffers but actually needs four.
The solution on master is to also wait for the frame callback in get_back_bo
which effectively forces the client to wait for a frame callback before
rendering. We could backport this patch to the Mesa 10.0 branch to fix the
problem but it might not be worth it as it's not totally risk-free. On the
other hand I think this bug isn't really a new bug but it's just exemplified by
the recent change to weston-simple-egl to stop it from waiting for a frame
callback before rendering. In that case you could argue we can just leave the
bug broken in Mesa 10.0.
The story I decribed above has one plot hole in that it looks like
weston-simple-egl does manage to get some of the frames to render and
approximately every third frame looks correct. I'm not quite sure why this is
happening so perhaps my explanation isn't the full picture.</pre>
</div>
</p>
<hr>
<span>You are receiving this mail because:</span>
<ul>
<li>You are the assignee for the bug.</li>
</ul>
</body>
</html>