Expected behaviour of eglSwapBuffers and the event queue

Pekka Paalanen ppaalanen at gmail.com
Fri Mar 1 03:49:15 PST 2013


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

[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


More information about the wayland-devel mailing list