[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