[PATCH weston v3 07/13] window: implement shm triple-buffering

Pekka Paalanen ppaalanen at gmail.com
Sat Apr 27 05:21:15 PDT 2013


On Fri, 26 Apr 2013 11:40:23 -0700
Bill Spitzak <spitzak at gmail.com> wrote:

> Pekka Paalanen wrote:
> 
> > This is all *inside* the client. This is a toolkit patch.
> 
> You are right, the patch is in clients/window.c, I confused it with an 
> adjacent patch.
> 
> I agree the client has to throttle resizes but I think this can avoid 
> the triple buffer and removes the difference between main and subwindows.
> 
> For a single-surface client, it does not need a third, fourth, etc 
> buffer because it does not draw until it receives the buffer-release for 
> the old buffer. The same rule can be applied to subsurfaces. They should 
> not draw until they get their buffer-release. I don't see this as being 
> any more difficult than any kind of throttling, and removes the 
> difference between main and subsurfaces.

But in resize scenario, a sub-surface will never get the buffer
release it would need to update its size, because that would need a
commit on the parent surface. Parent surface cannot commit,
until the sub-surface has committed its newly sized rendering,
otherwise there can be a glitch.

1. There is a window with a main surface and a sub-surface is in
desync mode. Sub-surface is running independently. Sub-surface has
buffer B1 reserved by the server on display.
2. Application decides the window must resize.
3. The sub-surface is set sync.
4. Meanwhile the sub-surface component keeps on running: it draws
and commits buffer B2.
5. Due to sync mode, B2 goes into cache instead. B1 is still on
display. Both B1 and B2 stay reserved indefinitely.
6. Application tells sub-surface component to resize, and waits for
it to do so.
7. Sub-surface component obviously does not get a frame callback
for B2, so it is still waiting on that.
8. Sub-surface component gets the command to resize, and needs to
redraw.
9. Sub-surface component draws and commits buffer B3, and acks the
resize.
10. The application gets the ack.
11. The application draws and commits the main surface in the new
size.
12. The application reverts the sub-surface mode to desync.
13. Due to step 9, the server releases buffer B2.
14. The main surface commit causes a server repaint cycle to start.
15. The main surface, and the sub-surface with buffer B3 are
updated atomically on display.
16. The server releases buffer B1.

It is a bit difficult to describe, since there are three
asyncronous lines of execution: the server, the application
controlling the main surface, and the component using the
sub-surface. Also, the Wayland connection acts as a serialising
mechanism for all requests coming from the two client threads. The
requests are processed in order by the server, but the client side
must take some care in ordering them.

Therefore the only way for glitch- and deadlock free resizing is to
use a third buffer, sans explicit synchronization of the
sub-surface thread or component.

Note, that a sub-surface is assumed to run independently. This
algorithm avoids the need to explicitly pause the sub-surface
thread for resizing. Of course, one is free to explicitly pause it,
and then resize in a completely synchronous way, but my example
does not do that. In my scenario, resizing does not need a full
stop of the sub-surface thread, just one roundtrip from the app to
the component, with the cost of temporarily using an extra buffer.

> For the toytoolkit this means that draw is not called until all the old 
> buffers for all subsurfaces are released. Rather than the toytoolkit 
> having to manage this, it may be easier for the server to send the 
> release events for subsurfaces first, and the main surface last. Thus 
> the toolkit only has to wait for the main surface.
> 
> I cannot think of any plausible compositor that will not release all the 
> old buffers for an entire tree of subsurfaces at once so reordering the 
> events like this should not be a problem.
> 
> If some subsurface buffers were not released, I also do not see any way 
> that triple buffering is going to fix this, an infinite number of 
> buffers are going to be needed. Throttling will have to block until the 
> third buffer is released, so I see no reason not to have it block until 
> the second buffer is released instead.

There is only a finite number of slots where buffers can be held
reserved in the server for a sub-surface: three at most, which is a
transient state; otherwise two. For normal surfaces it is one less
in both cases, because normal surfaces do not have the cache slot.

Oh, and all this really assumes, that the server actually needs to
keep hold of the buffer, whose contents are on display. If instead
the server makes a copy, like for all wl_shm buffers in the
GL-renderer case, you get to subtract another one from both cases.


Thanks,
pq


More information about the wayland-devel mailing list