[cogl] wayland: Always call wl_display_flush before going idle



commit 962d1825105a87dd8358a765353b77f6af8fe760
Author: Neil Roberts <neil linux intel com>
Date:   Fri Jun 28 12:19:20 2013 +0100

    wayland: Always call wl_display_flush before going idle
    
    Previously Cogl would only call wl_display_flush after doing a swap
    buffers on the onscreen because that is the only place where Cogl
    itself would end up queueing requests. However since commit
    323fe188748 Cogl takes control of calling wl_display_dispatch as well
    which effectively makes it very difficult for the application to
    handle the Wayland event queue itself. Therefore it needs to rely on
    Cogl to do it which means that other parts of the application may also
    queue requests that need to be flushed.
    
    This patch tries to copy the display fd handling of window.c in the
    Weston example clients. wl_display_flush will always be called in
    prepare function for the fd which means it will always be called
    before going idle. If flushing the display causes the socket buffer to
    become full, it will additionally poll for write on the FD to try
    flushing again when it becomes empty.
    
    We also need to call wl_display_dispatch_pending in the prepare
    because apparently calling eglSwapBuffers can cause it to read data
    from the FD to receive events for a different queue. In that case
    there will be events that need to be handled but the FD will no longer
    be ready for reading so we won't wake up the main loop any other way.
    
    Reviewed-by: Robert Bragg <robert linux intel com>

 cogl/winsys/cogl-winsys-egl-wayland.c |   62 +++++++++++++++++++++++---------
 1 files changed, 44 insertions(+), 18 deletions(-)
---
diff --git a/cogl/winsys/cogl-winsys-egl-wayland.c b/cogl/winsys/cogl-winsys-egl-wayland.c
index c4c11b5..461ed18 100644
--- a/cogl/winsys/cogl-winsys-egl-wayland.c
+++ b/cogl/winsys/cogl-winsys-egl-wayland.c
@@ -32,6 +32,7 @@
 #include <wayland-client.h>
 #include <wayland-egl.h>
 #include <string.h>
+#include <errno.h>
 
 #include "cogl-winsys-egl-wayland-private.h"
 #include "cogl-winsys-egl-private.h"
@@ -121,6 +122,35 @@ static const struct wl_registry_listener registry_listener = {
   registry_handle_global_cb,
 };
 
+static int64_t
+prepare_wayland_display_events (void *user_data)
+{
+  CoglRenderer *renderer = user_data;
+  CoglRendererEGL *egl_renderer = renderer->winsys;
+  CoglRendererWayland *wayland_renderer = egl_renderer->platform;
+  int flush_ret;
+
+  flush_ret = wl_display_flush (wayland_renderer->wayland_display);
+
+  /* If the socket buffer became full then we need to wake up the main
+   * loop once it is writable again */
+  if (flush_ret == -1 && errno == EAGAIN)
+    _cogl_poll_renderer_modify_fd (renderer,
+                                   wayland_renderer->fd,
+                                   COGL_POLL_FD_EVENT_IN |
+                                   COGL_POLL_FD_EVENT_OUT);
+
+  /* Calling this here is a bit dodgy because Cogl usually tries to
+   * say that it won't do any event processing until
+   * cogl_poll_renderer_dispatch is called. However Wayland doesn't
+   * seem to provide any way to query whether the event queue is empty
+   * and we would need to do that in order to force the main loop to
+   * wake up to call it from dispatch. */
+  wl_display_dispatch_pending (wayland_renderer->wayland_display);
+
+  return -1;
+}
+
 static void
 dispatch_wayland_display_events (void *user_data, int revents)
 {
@@ -128,10 +158,20 @@ dispatch_wayland_display_events (void *user_data, int revents)
   CoglRendererEGL *egl_renderer = renderer->winsys;
   CoglRendererWayland *wayland_renderer = egl_renderer->platform;
 
-  if (!revents)
-    return;
+  if ((revents & COGL_POLL_FD_EVENT_IN))
+    wl_display_dispatch (wayland_renderer->wayland_display);
 
-  wl_display_dispatch (wayland_renderer->wayland_display);
+  if ((revents & COGL_POLL_FD_EVENT_OUT))
+    {
+      int ret = wl_display_flush (wayland_renderer->wayland_display);
+
+      if (ret != -1 || errno != EAGAIN)
+        /* There is no more data to write so we don't need to wake up
+         * when the write buffer is emptied anymore */
+        _cogl_poll_renderer_modify_fd (renderer,
+                                       wayland_renderer->fd,
+                                       COGL_POLL_FD_EVENT_IN);
+    }
 }
 
 static CoglBool
@@ -206,7 +246,7 @@ _cogl_winsys_renderer_connect (CoglRenderer *renderer,
   _cogl_poll_renderer_add_fd (renderer,
                               wayland_renderer->fd,
                               COGL_POLL_FD_EVENT_IN,
-                              NULL, /* no prepare callback */
+                              prepare_wayland_display_events,
                               dispatch_wayland_display_events,
                               renderer);
 
@@ -469,25 +509,11 @@ _cogl_winsys_onscreen_swap_buffers_with_damage (CoglOnscreen *onscreen,
                                                 const int *rectangles,
                                                 int n_rectangles)
 {
-  CoglFramebuffer *fb = COGL_FRAMEBUFFER (onscreen);
-  CoglContext *context = fb->context;
-  CoglRenderer *renderer = context->display->renderer;
-  CoglRendererEGL *egl_renderer = renderer->winsys;
-  CoglRendererWayland *wayland_renderer = egl_renderer->platform;
-
   flush_pending_resize (onscreen);
 
   parent_vtable->onscreen_swap_buffers_with_damage (onscreen,
                                                     rectangles,
                                                     n_rectangles);
-
-  /*
-   * The implementation of eglSwapBuffers may do a flush however the semantics
-   * of eglSwapBuffers on Wayland has changed in the past. So to be safe to
-   * the implementation changing we should explicitly ensure all messages are
-   * sent.
-   */
-  wl_display_flush (wayland_renderer->wayland_display);
 }
 
 static void


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]