[cogl/fosdem-2012: 16/17] kms: Implement the swap buffers notify feature



commit 926db53775710f672e877a2989dd5c188485c483
Author: Neil Roberts <neil linux intel com>
Date:   Mon Dec 19 19:28:30 2011 +0000

    kms: Implement the swap buffers notify feature
    
    The KMS EGL platform now notifies when a swap is complete. The
    notification is delayed until the application calls
    cogl_context_dispatch. The GLX backend doesn't currently do this but I
    think that is how it should behave to make it easier for the
    application to handle locks and such.

 cogl/winsys/cogl-winsys-egl-kms.c |   99 +++++++++++++++++++++++++++++++++----
 1 files changed, 89 insertions(+), 10 deletions(-)
---
diff --git a/cogl/winsys/cogl-winsys-egl-kms.c b/cogl/winsys/cogl-winsys-egl-kms.c
index 84d96bf..b48faa3 100644
--- a/cogl/winsys/cogl-winsys-egl-kms.c
+++ b/cogl/winsys/cogl-winsys-egl-kms.c
@@ -67,6 +67,7 @@ typedef struct _CoglDisplayKMS
   drmModeModeInfo mode;
   drmModeCrtcPtr saved_crtc;
   int width, height;
+  gboolean pending_swap_notify;
 } CoglDisplayKMS;
 
 typedef struct _CoglOnscreenKMS
@@ -76,6 +77,7 @@ typedef struct _CoglOnscreenKMS
   uint32_t next_fb_id;
   struct gbm_bo *current_bo;
   struct gbm_bo *next_bo;
+  gboolean pending_swap_notify;
 } CoglOnscreenKMS;
 
 static const char device_name[] = "/dev/dri/card0";
@@ -307,13 +309,8 @@ _cogl_winsys_egl_cleanup_context (CoglDisplay *display)
 }
 
 static void
-page_flip_handler (int fd,
-                   unsigned int frame,
-                   unsigned int sec,
-                   unsigned int usec,
-                   void *data)
+free_current_bo (CoglOnscreen *onscreen)
 {
-  CoglOnscreen *onscreen = data;
   CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
   CoglOnscreenKMS *kms_onscreen = egl_onscreen->platform;
   CoglContext *context = COGL_FRAMEBUFFER (onscreen)->context;
@@ -333,12 +330,36 @@ page_flip_handler (int fd,
                               kms_onscreen->current_bo);
       kms_onscreen->current_bo = NULL;
     }
+}
+
+static void
+page_flip_handler (int fd,
+                   unsigned int frame,
+                   unsigned int sec,
+                   unsigned int usec,
+                   void *data)
+{
+  CoglOnscreen *onscreen = data;
+  CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
+  CoglOnscreenKMS *kms_onscreen = egl_onscreen->platform;
+  CoglContext *context = COGL_FRAMEBUFFER (onscreen)->context;
+  CoglDisplay *display = context->display;
+  CoglDisplayEGL *egl_display = display->winsys;
+  CoglDisplayKMS *kms_display = egl_display->platform;
+
+  free_current_bo (onscreen);
 
   kms_onscreen->current_fb_id = kms_onscreen->next_fb_id;
   kms_onscreen->next_fb_id = 0;
 
   kms_onscreen->current_bo = kms_onscreen->next_bo;
   kms_onscreen->next_bo = NULL;
+
+  /* We only want to notify that the swap is complete when the
+     application calls cogl_context_dispatch so instead of immediately
+     notifying we'll set a flag to remember to notify later */
+  kms_display->pending_swap_notify = TRUE;
+  kms_onscreen->pending_swap_notify = TRUE;
 }
 
 static void
@@ -403,6 +424,19 @@ _cogl_winsys_onscreen_swap_buffers (CoglOnscreen *onscreen)
 }
 
 static gboolean
+_cogl_winsys_egl_context_init (CoglContext *context,
+                               GError **error)
+{
+  COGL_FLAGS_SET (context->features,
+                  COGL_FEATURE_ID_SWAP_BUFFERS_EVENT, TRUE);
+  COGL_FLAGS_SET (context->winsys_features,
+                  COGL_WINSYS_FEATURE_SWAP_BUFFERS_EVENT,
+                  TRUE);
+
+  return TRUE;
+}
+
+static gboolean
 _cogl_winsys_onscreen_init (CoglOnscreen *onscreen,
                             GError **error)
 {
@@ -465,6 +499,7 @@ _cogl_winsys_onscreen_deinit (CoglOnscreen *onscreen)
   CoglContext *context = framebuffer->context;
   CoglRenderer *renderer = context->display->renderer;
   CoglRendererEGL *egl_renderer = renderer->winsys;
+  CoglRendererKMS *kms_renderer = egl_renderer->platform;
   CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
   CoglOnscreenKMS *kms_onscreen;
 
@@ -474,6 +509,12 @@ _cogl_winsys_onscreen_deinit (CoglOnscreen *onscreen)
 
   kms_onscreen = egl_onscreen->platform;
 
+  /* If have a pending swap then block until it completes */
+  while (kms_onscreen->next_fb_id != 0)
+    handle_drm_event (kms_renderer);
+
+  free_current_bo (onscreen);
+
   if (egl_onscreen->egl_surface != EGL_NO_SURFACE)
     {
       eglDestroySurface (egl_renderer->edpy, egl_onscreen->egl_surface);
@@ -497,13 +538,39 @@ _cogl_winsys_poll_get_info (CoglContext *context,
                             int *n_poll_fds,
                             gint64 *timeout)
 {
-  CoglRenderer *renderer = context->display->renderer;
+  CoglDisplay *display = context->display;
+  CoglDisplayEGL *egl_display = display->winsys;
+  CoglDisplayKMS *kms_display = egl_display->platform;
+  CoglRenderer *renderer = display->renderer;
   CoglRendererEGL *egl_renderer = renderer->winsys;
   CoglRendererKMS *kms_renderer = egl_renderer->platform;
 
   *poll_fds = &kms_renderer->poll_fd;
   *n_poll_fds = 1;
-  *timeout = -1;
+
+  /* If we've already got a pending swap notify then we'll dispatch
+     immediately */
+  *timeout = kms_display->pending_swap_notify ? 0 : -1;
+}
+
+static void
+flush_pending_swap_notify_cb (void *data,
+                              void *user_data)
+{
+  CoglFramebuffer *framebuffer = data;
+
+  if (framebuffer->type == COGL_FRAMEBUFFER_TYPE_ONSCREEN)
+    {
+      CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
+      CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
+      CoglOnscreenKMS *kms_onscreen = egl_onscreen->platform;
+
+      if (kms_onscreen->pending_swap_notify)
+        {
+          _cogl_onscreen_notify_swap_buffers (onscreen);
+          kms_onscreen->pending_swap_notify = FALSE;
+        }
+    }
 }
 
 static void
@@ -511,7 +578,10 @@ _cogl_winsys_poll_dispatch (CoglContext *context,
                             const CoglPollFD *poll_fds,
                             int n_poll_fds)
 {
-  CoglRenderer *renderer = context->display->renderer;
+  CoglDisplay *display = context->display;
+  CoglDisplayEGL *egl_display = display->winsys;
+  CoglDisplayKMS *kms_display = egl_display->platform;
+  CoglRenderer *renderer = display->renderer;
   CoglRendererEGL *egl_renderer = renderer->winsys;
   CoglRendererKMS *kms_renderer = egl_renderer->platform;
   int i;
@@ -524,6 +594,14 @@ _cogl_winsys_poll_dispatch (CoglContext *context,
 
         break;
       }
+
+  if (kms_display->pending_swap_notify)
+    {
+      g_list_foreach (context->framebuffers,
+                      flush_pending_swap_notify_cb,
+                      NULL);
+      kms_display->pending_swap_notify = FALSE;
+    }
 }
 
 static const CoglWinsysEGLVtable
@@ -532,7 +610,8 @@ _cogl_winsys_egl_vtable =
     .display_setup = _cogl_winsys_egl_display_setup,
     .display_destroy = _cogl_winsys_egl_display_destroy,
     .context_created = _cogl_winsys_egl_context_created,
-    .cleanup_context = _cogl_winsys_egl_cleanup_context
+    .cleanup_context = _cogl_winsys_egl_cleanup_context,
+    .context_init = _cogl_winsys_egl_context_init
   };
 
 const CoglWinsysVtable *



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