Expected behaviour of eglSwapBuffers and the event queue

Kristian Høgsberg krh at bitplanet.net
Fri Mar 1 07:33:32 PST 2013


On Fri, Mar 1, 2013 at 6:49 AM, Pekka Paalanen <ppaalanen at gmail.com> wrote:
> On Fri, 1 Mar 2013 12:02:38 +0800
> Sam Spilsbury <smspillaz at gmail.com> wrote:
>
>> Hi,
>>
>> I'm a little confused on the behaviour of eglSwapBuffers operating on
>> the event queue. At the moment, it calls wl_connection_read () on the
>> display fd, which will read events into the local event buffer. I
>> imagine it needs to do this in order to fetch some information about
>> the next backbuffer from the compositor. However, it reads all of the
>> events out of the queue, and this has pretty bad consequences for
>> event loops which are trying to integrate the wayland fd into their
>> poll () / select () loop.
>>
>> Because all of the data has been read from the fd, there is a
>> condition where we have read every single event that needed to be
>> delivered to us. Then when we return to poll (), it will block
>> indefinitely because there is nothing left in the fd for us to read,
>> and the compositor isn't going to send us any more events. It might be
>> possible to work around this by checking if events are available in
>> the queue and calling poll () if there aren't any, but it seems like
>> there is no API available to do so.
>>
>> I wanted to know what the expected behaviour around this was meant to
>> be. If eglSwapBuffers is meant to read () the fd, then that means that
>> we need to rely on it being called in order to populate the event
>> queue (since it can only be done in one place). That, in my opinion,
>> feels like broken behaviour, because we might want to use the protocol
>> to send data to clients which wouldn't necessarily result in a
>> SwapBuffers,  then those clients can't reliably call either
>> wl_display_dispatch_pending () or wl_display_dispatch () with poll ()
>> because there's no way of knowing whether or not that fd is going to
>> block indefinitely or not.
>
> Hi Sam,
>
> I'm re-iterating the things I said in irc, since I think you went away
> already. The basic scheme was explained in [1].
>
> What I call a main thread is the main thread in the libwayland sense,
> i.e. the thread where the wl_display belongs to.
>
> The loop cycle for main thread should look like this, AFAIU:
>
> 1. the (Wayland) fd polls for readable
> 2. call wl_display_dispatch()
> 3. do whatever other processing you want
> 4. call wl_display_dispatch_pending() until it returns 0 or error
> 5. call wl_display_flush()
> 6. go back to poll

Yeah, this looks right.  I would just point out that the fd starvation
doesn't happen because either you're calling eglSwapBuffers in the
main thread, in which case you'll go back to the main loop eventually.
 There you'll call wl_display_dispatch_pending(), then
wl_display_flush() and then poll on the fd.  The
wl_display_dispatch_queue() in eglSwapBuffers will queue up any main
event queue events in the wl_display queue, and
wl_display_dispatch_pending() in the main loop will then dispatch them
before blocking.

If you're calling eglSwapBuffers from a different thread, it will
never read from the fd.  It will only dispatch events already in its
event queue, and if no events are in the queue, it will block on a
pthread condition, that the main thread will signal when it puts
events in the queue.

Kristian

> [1] also tells when to poll the fd for writable.
>
> The nasty thing about eglSwapBuffers() is that it may block, and it may
> read the fd if it is called in the main thread, but you cannot rely on
> it doing either. However, eglSwapBuffers does guarantee, that it will
> not read the fd, if it is being called in a different thread than the
> main thread. EGL Wayland platform (i.e. Wayland client side) has its own
> Wayland dispatch queue. eglSwapBuffers() may wait for its previous
> frame callback to arrive, in which case it blocks by design.
>
> That is why you must not call eglSwapBuffers() between steps 1 and 2.
>
> You can call eglSwapBuffers from within steps 2 and 4, i.e. directly
> from your wayland event callback functions, I believe. And of course you
> can call eglSwapBuffers() in step 3. Or not call it at all anywhere.
>
> You should never get blocked in a read from the fd, unless you failed
> to map the window (client code bug), which means frame callback will
> never come, and so one of the next eglSwapBuffers may end up waiting
> indefinitely for the frame callback event.
>
> It is also possible for the frame callback event to not arrive soon. If
> the compositor does not have the window visible (e.g. it is on an
> inactive workspace), the frame events generally don't run for that
> window, and you can get stuck in eglSwapBuffers, by design. This is
> avoidable by setting up your own frame callbacks, and issuing a new
> eglSwapBuffers only, when the last frame callback has arrived. In other
> words, throttle the redrawing manually, instead of relying on
> eglSwapBuffers. This way you can at least keep the rest of the program
> main loop running.
>
> Once eglSwapInterval() gets implemented for the EGL Wayland platform,
> you can change the waiting behaviour of eglSwapBuffers with it. That
> will be another story, though.
>
> Does this help?
>
>
> Thanks,
> pq
>
> [1] http://lists.freedesktop.org/archives/wayland-devel/2012-October/005967.html
> _______________________________________________
> wayland-devel mailing list
> wayland-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/wayland-devel


More information about the wayland-devel mailing list