[Mesa-dev] [PATCH 1/2] eglut_wayland: Drive event loop by frame events
Daniel Stone
daniel at fooishbar.org
Mon Jul 17 11:01:34 UTC 2017
Hi,
Sorry, I have no idea why --subject-prefix didn't actually work. These
two patches are for the demos repo.
Cheers,
Daniel
On 17 July 2017 at 12:00, Daniel Stone <daniels at collabora.com> wrote:
> The eglut_wayland event loop attempted to use frame events to drive the
> redraw loop. However, the frame events were being requested after
> eglSwapBuffers (i.e. wl_surface_commit()), which means they would not
> actually activate until the next eglSwapBuffers.
>
> This was being balanced out by 'redisplay' being set immediately by
> es2gears, which would do an instant-return poll before calling
> eglSwapBuffers, which would internally wait on its own frame event, and
> as a side effect trigger the frame event that eglut_wayland had just
> placed, causing redraw to be called again. The result would be a
> stuttering 40fps.
>
> Rewrite the event loop, so that:
> - frame events are placed before eglSwapBuffers is called
> - 'redisplay' no longer triggers an immediate return from poll
> - the frame event handler redraws if redisplay is requested, and
> exits if not
> - if redisplay is requested whilst we do not have a pending frame
> event, redraw instantly
>
> Reported-by: Daniel van Vugt <daniel.van.vugt at canonical.com>
> Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=101814
> Signed-off-by: Daniel Stone <daniels at collabora.com>
> ---
> src/egl/eglut/eglut_wayland.c | 83 +++++++++++++++++++++++++------------------
> 1 file changed, 48 insertions(+), 35 deletions(-)
>
> diff --git a/src/egl/eglut/eglut_wayland.c b/src/egl/eglut/eglut_wayland.c
> index 968b33fe..6376acc0 100644
> --- a/src/egl/eglut/eglut_wayland.c
> +++ b/src/egl/eglut/eglut_wayland.c
> @@ -94,6 +94,7 @@ _eglutNativeInitDisplay(void)
> wl_registry_destroy(registry);
>
> _eglut->surface_type = EGL_WINDOW_BIT;
> + _eglut->redisplay = 1;
> }
>
> void
> @@ -149,19 +150,27 @@ static const struct wl_callback_listener frame_listener = {
>
> static void
> draw(void *data, struct wl_callback *callback, uint32_t time)
> -{
> +{
> struct window *window = (struct window *)data;
> struct eglut_window *win = _eglut->current;
>
> + if (callback) {
> + wl_callback_destroy(callback);
> + window->callback = NULL;
> + }
> +
> + /* Our client doesn't want to push another frame; go back to sleep. */
> + if (!_eglut->redisplay)
> + return;
> + _eglut->redisplay = 0;
> +
> if (win->display_cb)
> win->display_cb();
> - eglSwapBuffers(_eglut->dpy, win->surface);
> -
> - if (callback)
> - wl_callback_destroy(callback);
>
> window->callback = wl_surface_frame(window->surface);
> wl_callback_add_listener(window->callback, &frame_listener, window);
> +
> + eglSwapBuffers(_eglut->dpy, win->surface);
> }
>
> void
> @@ -170,53 +179,57 @@ _eglutNativeEventLoop(void)
> struct pollfd pollfd;
> int ret;
>
> - draw(&window, NULL, 0);
> -
> pollfd.fd = wl_display_get_fd(display.display);
> pollfd.events = POLLIN;
> pollfd.revents = 0;
>
> while (1) {
> - wl_display_dispatch_pending(display.display);
> -
> - if (_eglut->idle_cb)
> - _eglut->idle_cb();
> + /* If we need to flush but can't, don't do anything at all which could
> + * push further events into the socket. */
> + if (!(pollfd.events & POLLOUT)) {
> + wl_display_dispatch_pending(display.display);
> +
> + if (_eglut->idle_cb)
> + _eglut->idle_cb();
> +
> + /* Client wants to redraw, but we have no frame event to trigger the
> + * redraw; kickstart it by redrawing immediately. */
> + if (_eglut->redisplay && !window.callback)
> + draw(&window, NULL, 0);
> + }
>
> ret = wl_display_flush(display.display);
> - if (ret < 0 && errno == EAGAIN)
> - pollfd.events |= POLLOUT;
> - else if (ret < 0)
> - break;
> -
> - if (poll(&pollfd, 1, _eglut->redisplay ? 0 : -1) == -1)
> + if (ret < 0 && errno != EAGAIN)
> + break; /* fatal error; socket is broken */
> + else if (ret < 0 && errno == EAGAIN)
> + pollfd.events |= POLLOUT; /* need to wait until we can flush */
> + else
> + pollfd.events &= ~POLLOUT; /* successfully flushed */
> +
> + if (poll(&pollfd, 1, -1) == -1)
> break;
>
> if (pollfd.revents & (POLLERR | POLLHUP))
> break;
>
> + if (pollfd.events & POLLOUT) {
> + if (!(pollfd.revents & POLLOUT))
> + continue; /* block until we can flush */
> + pollfd.events &= ~POLLOUT;
> + }
> +
> if (pollfd.revents & POLLIN) {
> ret = wl_display_dispatch(display.display);
> if (ret == -1)
> break;
> }
>
> - if (pollfd.revents & POLLOUT) {
> - ret = wl_display_flush(display.display);
> - if (ret == 0)
> - pollfd.events &= ~POLLOUT;
> - else if (ret == -1 && errno != EAGAIN)
> - break;
> - }
> -
> - if (_eglut->redisplay) {
> - struct eglut_window *win = _eglut->current;
> -
> - _eglut->redisplay = 0;
> -
> - if (win->display_cb)
> - win->display_cb();
> -
> - eglSwapBuffers(_eglut->dpy, win->surface);
> - }
> + ret = wl_display_flush(display.display);
> + if (ret < 0 && errno != EAGAIN)
> + break; /* fatal error; socket is broken */
> + else if (ret < 0 && errno == EAGAIN)
> + pollfd.events |= POLLOUT; /* need to wait until we can flush */
> + else
> + pollfd.events &= ~POLLOUT; /* successfully flushed */
> }
> }
> --
> 2.13.3
>
> _______________________________________________
> mesa-dev mailing list
> mesa-dev at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/mesa-dev
More information about the mesa-dev
mailing list