Process for implementing a double buffer on Wayland

Fabien DESSENNE fabien.dessenne at st.com
Thu Nov 26 08:56:05 PST 2015


>  > Date: Thu, 26 Nov 2015 10:40:20 +0200
>  > From: ppaalanen at gmail.com
>  > To: rdp.effort at gmail.com; mikeyj001 at hotmail.com
>  > CC: wayland-devel at lists.freedesktop.org; daniel at fooishbar.org
>  > Subject: Re: Process for implementing a double buffer on Wayland
>  >
>  > On Wed, 25 Nov 2015 21:43:49 +0100
>  > Hardening <rdp.effort at gmail.com> wrote:
>  >
>  > > Le 25/11/2015 17:18, Daniel Stone a écrit :
>  > > > Hi Mike,
>  > > >
>  > > > On 25 November 2015 at 16:06, Mike Johnson
> <mikeyj001 at hotmail.com> wrote:
>  > > >> I've created 2 buffers of the same size (800x600 pixels). So I
> want the
>  > > >> input buffer to get filled off-screen, while the output buffer
> will show the
>  > > >> content on-screen.
>  > > >>
>  > > >> First of all what sort of content could be used to illustrate this
>  > > >> technique, and secondly, what mechanisms are available to:
>  > > >>
>  > > >> a) Notify that the input buffer is full
>  > > >> b) Copy the content to the output buffer so that it shows on-screen
>  > > >
>  > > > It's quite simple. wl_surface_attach(surf, buf) +
>  > > > wl_surface_commit(surf) will display 'buf' for that surface. At that
>  > > > point, the compositor owns that buffer, so you should stop drawing on
>  > > > it. When the compositor has finished with a buffer, it will send
> you a
>  > > > wl_buffer.release event. You can sync your paint clock to the
>  > > > compositor's repaint loop with wl_surface_frame.
>  > > >
>  > > > So, the normal workflow is:
>  > > > - create surface S, buffer A, buffer B
>  > > > - draw first frame into buffer A
>  > > > - call wl_surface_frame(S) + wl_surface_attach(S, A) +
>  > > > wl_surface_commit(S) + wl_display_flush()
>  > > > - go to sleep
>  > > > - receive completion for wl_surface_frame callback
>  > > > - draw second frame into buffer B
>  > > > - call wl_surface_frame(S) + wl_surface_attach(S, B) +
>  > > > wl_surface_commit(S) + wl_display_flush()
>  > > > - compositor now owns both buffers, so don't touch any
>  > > > - receive wl_buffer.release event for buffer A - now unused
>  > > > - receive completion for wl_surface_frame callback
>  > > > - draw third frame into buffer A
>  > > > - ...
>  > > >
>  > >
>  > > I may be wrong, but there's no guaranty that the compositor sends
>  > > wl_buffer.release event on buffer A. I think I have experimented this
>  > > when the renderer in weston is the pixman renderer.
>  > > IIRC I have been told on IRC that the compositor decides when the
> buffer
>  > > is not used, so you may not receive the release message immediately. I
>  > > have hit that kind of bug when coding libUWAC.
>  >
>  > You are definitely right if you don't commit buffer B.
>  >
>  > When you have committed buffer B, the compositor eventually will
>  > release buffer A if it had not already, but there are some exceptions
>  > too. One is on certain circumstances when using a sub-surface.
>  >
>  >
>  > Mike,
>  >
>  > essentially one should decouple the buffer management from the repaint
>  > cycle, like simple-shm.c does.
>  >
>  > The reply to wl_surface.frame tells you when it is appropriate to draw
>  > a new frame after the previous one. Whenever you decide to draw a new
>  > frame, check your buffer pool for available buffers (I mean a collection
>  > of wl_buffers, not wl_shm_pool). If none are available, create a new
>  > buffer to draw into, or in some cases you can wait for a buffer become
>  > available again.
>  >
>  > When a buffer is created, it is naturally available to be drawn into.
>  > Using wl_surface.attach and wl_surface.commit with the buffer makes it
>  > reserved by the server, unavailable, until you receive a
>  > wl_buffer.release event making it available again.
>  >
>  > When you follow these rules, you get adaptive buffering. You'll only
>  > ever use just one buffer if possible, and use more if necessary to
>  > achieve glitch-free output. Double-buffering in the client is not
>  > always mandatory to achieve the effect of double-buffering, because the
>  > server might be buffering too.
>  >
>  >
>  > Thanks,
>  > pq
>
> Hi Pekka,
>
> Thanks for your input.  If I understand you correctly, you recommend
> creating buffers dynamically in the event there aren't any available to
> use in the shm pool.  I can see how that would help the frame rate.
>
> Thanks again for your comments guys.  I have the info I need.
> Best regards
> Mike

Hi all,

I have also experienced this : the replaced buffer (A) is not 
immediately released after the new buffer (B) is on display.
I guess that the behavior depends on both the backend (eg DRM) and the 
renderer (GL, pixman)
In compositor-drm.c you can read this comment
  * Also, keep a reference when using the pixman renderer.
  * That makes it possible to do a seamless switch to the GL
  * renderer and since the pixman renderer keeps a reference
  * to the buffer anyway, there is no side effects.
I am not sure, but this may be be a reason why a buffer is kept longer 
than expected.

I had deadlock issues when using a 2 buffer pool (A, B).
Moving to 3 (A, B C) solved the issue : after having pushed C, A is 
released.
Running with 3 buffers is quite usual, I used it within an 'Android 
HWComposer' project. The drawback is that you need some extra memory.

BR
Fabien




More information about the wayland-devel mailing list