[Cogl] [PATCH v3] Rework sdl integration api

Robert Bragg robert at sixbynine.org
Wed Apr 11 15:48:06 PDT 2012


From: Robert Bragg <robert at linux.intel.com>

Oops, although in my last patch I updated cogl-sdl-hello.c to use the event
loop I described in my earlier email I forgot to update the example in
cogl-sdl.h.
-- >8 --

This re-works the SDL integration api to simplify the integration for
application developers and also allow Cogl to know when the application
is about to go idle waiting for events so it can perform idle
book-keeping work.
---
 cogl/Makefile.am                                   |    4 +-
 cogl/cogl-renderer-private.h                       |    6 +
 cogl/cogl-sdl.c                                    |   85 +++++++++
 cogl/cogl-sdl.h                                    |  198 ++++++++++++++++++++
 cogl/cogl.h                                        |    3 +
 cogl/winsys/cogl-winsys-sdl.c                      |    6 +
 .../cogl-2.0-experimental-docs.xml.in              |    2 +
 .../cogl-2.0-experimental-sections.txt             |   10 +
 examples/cogl-sdl-hello.c                          |  105 +++--------
 9 files changed, 339 insertions(+), 80 deletions(-)
 create mode 100644 cogl/cogl-sdl.c
 create mode 100644 cogl/cogl-sdl.h

diff --git a/cogl/Makefile.am b/cogl/Makefile.am
index 1e39005..51e578c 100644
--- a/cogl/Makefile.am
+++ b/cogl/Makefile.am
@@ -448,9 +448,11 @@ cogl_sources_c += \
        $(srcdir)/winsys/cogl-winsys-egl-private.h
 endif
 if SUPPORT_SDL
+cogl_experimental_h += $(srcdir)/cogl-sdl.h
 cogl_sources_c += \
        $(srcdir)/winsys/cogl-winsys-sdl-private.h \
-       $(srcdir)/winsys/cogl-winsys-sdl.c
+       $(srcdir)/winsys/cogl-winsys-sdl.c \
+       $(srcdir)/cogl-sdl.c
 endif
 
 EXTRA_DIST += stb_image.c
diff --git a/cogl/cogl-renderer-private.h b/cogl/cogl-renderer-private.h
index 11dc0bb..0d119cb 100644
--- a/cogl/cogl-renderer-private.h
+++ b/cogl/cogl-renderer-private.h
@@ -62,6 +62,12 @@ struct _CoglRenderer
   struct wl_compositor *foreign_wayland_compositor;
   struct wl_shell *foreign_wayland_shell;
 #endif
+
+#ifdef COGL_HAS_SDL_SUPPORT
+  gboolean sdl_event_type_set;
+  guint8 sdl_event_type;
+#endif
+
   /* List of callback functions that will be given every native event */
   GSList *event_filters;
   void *winsys;
diff --git a/cogl/cogl-sdl.c b/cogl/cogl-sdl.c
new file mode 100644
index 0000000..9779593
--- /dev/null
+++ b/cogl/cogl-sdl.c
@@ -0,0 +1,85 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2012 Intel Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "cogl-sdl.h"
+#include "cogl-context-private.h"
+#include "cogl-renderer-private.h"
+
+void
+cogl_sdl_renderer_set_event_type (CoglRenderer *renderer, guint8 type)
+{
+  renderer->sdl_event_type_set = TRUE;
+  renderer->sdl_event_type = type;
+}
+
+guint8
+cogl_sdl_renderer_get_event_type (CoglRenderer *renderer)
+{
+  _COGL_RETURN_VAL_IF_FAIL (renderer->sdl_event_type_set, SDL_USEREVENT);
+
+  return renderer->sdl_event_type;
+}
+
+CoglContext *
+cogl_sdl_context_new (guint8 type, GError **error)
+{
+  CoglRenderer *renderer = cogl_renderer_new ();
+  CoglDisplay *display;
+
+  cogl_renderer_set_winsys_id (renderer, COGL_WINSYS_ID_SDL);
+
+  cogl_sdl_renderer_set_event_type (renderer, type);
+
+  if (!cogl_renderer_connect (renderer, error))
+    return NULL;
+
+  display = cogl_display_new (renderer, NULL);
+  if (!cogl_display_setup (display, error))
+    return NULL;
+
+  return cogl_context_new (display, error);
+}
+
+void
+cogl_sdl_handle_event (CoglContext *context, SDL_Event *event)
+{
+  const CoglWinsysVtable *winsys;
+
+  _COGL_RETURN_IF_FAIL (cogl_is_context (context));
+
+  winsys = _cogl_context_get_winsys (context);
+
+  if (winsys->poll_dispatch)
+    winsys->poll_dispatch (context, NULL, 0);
+}
+
+void
+cogl_sdl_idle (CoglContext *context)
+{
+  /* NOP since Cogl doesn't currently need to do anything when idle */
+}
diff --git a/cogl/cogl-sdl.h b/cogl/cogl-sdl.h
new file mode 100644
index 0000000..27e3372
--- /dev/null
+++ b/cogl/cogl-sdl.h
@@ -0,0 +1,198 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2012 Intel Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ */
+
+#if !defined(__COGL_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
+#error "Only <cogl/cogl.h> can be included directly."
+#endif
+
+#ifndef __COGL_SDL_H__
+#define __COGL_SDL_H__
+
+#include <cogl/cogl-context.h>
+#include <SDL.h>
+
+G_BEGIN_DECLS
+
+/**
+ * SECTION:cogl-sdl
+ * @short_description: Integration api for the Simple DirectMedia
+ *                     Layer library.
+ *
+ * Cogl is a portable graphics api that can either be used standalone
+ * or alternatively integrated with certain existing frameworks. This
+ * api enables Cogl to be used in conjunction with the Simple
+ * DirectMedia Layer library.
+ *
+ * Using this API a typical SDL application would look something like
+ * this:
+ * |[
+ * MyAppData data;
+ * GError *error = NULL;
+ *
+ * data.ctx = cogl_sdl_context_new (NULL, SDL_USEREVENT, &error);
+ * if (!data.ctx)
+ *   {
+ *     fprintf (stderr, "Failed to create context: %s\n",
+ *              error->message);
+ *     return 1;
+ *   }
+ *
+ * my_application_setup (&data);
+ *
+ * data.redraw_queued = TRUE;
+ * while (!data.quit)
+ *   {
+ *     while (!data.quit)
+ *       {
+ *         int status = SDL_PollEvent (&event);
+ *         if (!status && data.redraw_queued)
+ *           break;
+ *         else if (!status)
+ *           {
+ *             cogl_sdl_idle (ctx);
+ *             if (!SDL_WaitEvent (&event))
+ *               {
+ *                 fprintf (stderr, "Error waiting for SDL events");
+ *                 return 1;
+ *               }
+ *           }
+ *
+ *          handle_event (&data, &event);
+ *          cogl_sdl_handle_event (ctx, &event);
+ *        }
+ *
+ *     data.redraw_queued = redraw (&data);
+ *   }
+ * ]|
+ */
+
+/**
+ * cogl_sdl_context_new:
+ * @type: An SDL user event type between %SDL_USEREVENT and
+ *        %SDL_NUMEVENTS - %1
+ * @error: A GError return location.
+ *
+ * This is a convenience function for creating a new #CoglContext for
+ * use with SDL and specifying what SDL user event type Cogl can use
+ * as a way to interrupt SDL_WaitEvent().
+ *
+ * This function is equivalent to the following code:
+ * |[
+ * CoglRenderer *renderer = cogl_renderer_new ();
+ * CoglDisplay *display;
+ *
+ * cogl_renderer_set_winsys_id (renderer, COGL_WINSYS_ID_SDL);
+ *
+ * cogl_sdl_renderer_set_event_type (renderer, type);
+ *
+ * if (!cogl_renderer_connect (renderer, error))
+ *   return NULL;
+ *
+ * display = cogl_display_new (renderer, NULL);
+ * if (!cogl_display_setup (display, error))
+ *   return NULL;
+ *
+ * return cogl_context_new (display, error);
+ * ]|
+ *
+ * <note>SDL applications are required to either use this API or
+ * to manually create a #CoglRenderer and call
+ * cogl_sdl_renderer_set_event_type().</note>
+ *
+ * Since: 2.0
+ * Stability: unstable
+ */
+CoglContext *
+cogl_sdl_context_new (guint8 type, GError **error);
+
+/**
+ * cogl_sdl_renderer_set_event_type:
+ * @renderer: A #CoglRenderer
+ * @type: An SDL user event type between %SDL_USEREVENT and
+ *        %SDL_NUMEVENTS - %1
+ *
+ * Tells Cogl what SDL user event type it can use as a way to
+ * interrupt SDL_WaitEvent() to ensure that cogl_sdl_handle_event()
+ * will be called in a finite amount of time.
+ *
+ * <note>This should only be called on an un-connected
+ * @renderer.</note>
+ *
+ * <note>For convenience most simple applications can use
+ * cogl_sdl_context_new() if they don't want to manually create
+ * #CoglRenderer and #CoglDisplay objects during
+ * initialization.</note>
+ *
+ * Since: 2.0
+ * Stability: unstable
+ */
+void
+cogl_sdl_renderer_set_event_type (CoglRenderer *renderer, guint8 type);
+
+/**
+ * cogl_sdl_renderer_get_event_type:
+ * @renderer: A #CoglRenderer
+ *
+ * Queries what SDL user event type Cogl is using as a way to
+ * interrupt SDL_WaitEvent(). This is set either using
+ * cogl_sdl_context_new or by using
+ * cogl_sdl_renderer_set_event_type().
+ *
+ * Since: 2.0
+ * Stability: unstable
+ */
+guint8
+cogl_sdl_renderer_get_event_type (CoglRenderer *renderer);
+
+/**
+ * cogl_sdl_handle_event:
+ * @context: A #CoglContext
+ * @event: An SDL event
+ *
+ * Passes control to Cogl so that it may dispatch any internal event
+ * callbacks in response to the given SDL @event. This function must
+ * be called for every SDL event.
+ *
+ * Since: 2.0
+ * Stability: unstable
+ */
+void
+cogl_sdl_handle_event (CoglContext *context, SDL_Event *event);
+
+/**
+ * cogl_sdl_idle:
+ * @context: A #CoglContext
+ *
+ * Notifies Cogl that the application is idle and about to call
+ * SDL_WaitEvent(). Cogl may use this to run low priority book keeping
+ * tasks.
+ *
+ * Since: 2.0
+ * Stability: unstable
+ */
+void
+cogl_sdl_idle (CoglContext *context);
+
+G_END_DECLS
+
+#endif /* __COGL_SDL_H__ */
diff --git a/cogl/cogl.h b/cogl/cogl.h
index 8663f95..108ac9e 100644
--- a/cogl/cogl.h
+++ b/cogl/cogl.h
@@ -116,6 +116,9 @@
  * code has been migrated down into Cogl! */
 #include <cogl/cogl-clutter.h>
 #endif
+#ifdef COGL_HAS_SDL_SUPPORT
+#include <cogl/cogl-sdl.h>
+#endif
 
 /*
  * 2.0 only api...
diff --git a/cogl/winsys/cogl-winsys-sdl.c b/cogl/winsys/cogl-winsys-sdl.c
index deda045..04fa636 100644
--- a/cogl/winsys/cogl-winsys-sdl.c
+++ b/cogl/winsys/cogl-winsys-sdl.c
@@ -159,6 +159,12 @@ error:
 static gboolean
 _cogl_winsys_context_init (CoglContext *context, GError **error)
 {
+  CoglRenderer *renderer = context->display->renderer;
+
+  if (G_UNLIKELY (renderer->sdl_event_type_set == FALSE))
+    g_error ("cogl_sdl_renderer_set_event_type() or cogl_sdl_context_new() "
+             "must be called during initialization");
+
   return _cogl_context_update_features (context, error);
 }
 
diff --git a/doc/reference/cogl-2.0-experimental/cogl-2.0-experimental-docs.xml.in b/doc/reference/cogl-2.0-experimental/cogl-2.0-experimental-docs.xml.in
index 92a47b6..6c9b91c 100644
--- a/doc/reference/cogl-2.0-experimental/cogl-2.0-experimental-docs.xml.in
+++ b/doc/reference/cogl-2.0-experimental/cogl-2.0-experimental-docs.xml.in
@@ -18,6 +18,7 @@
       <year>2009</year>
       <year>2010</year>
       <year>2011</year>
+      <year>2012</year>
       <holder>Intel Corporation</holder>
     </copyright>
 
@@ -130,6 +131,7 @@
 
     <section id="cogl-integration">
       <title>Binding and Integrating</title>
+      <xi:include href="xml/cogl-sdl.xml"/>
       <xi:include href="xml/cogl-gtype.xml"/>
     </section>
 
diff --git a/doc/reference/cogl-2.0-experimental/cogl-2.0-experimental-sections.txt b/doc/reference/cogl-2.0-experimental/cogl-2.0-experimental-sections.txt
index a3852bc..ade861d 100644
--- a/doc/reference/cogl-2.0-experimental/cogl-2.0-experimental-sections.txt
+++ b/doc/reference/cogl-2.0-experimental/cogl-2.0-experimental-sections.txt
@@ -777,3 +777,13 @@ CoglColorMask
 <TITLE>GType Integration API</TITLE>
 cogl_gtype_matrix_get_type
 </SECTION>
+
+<SECTION>
+<FILE>SDL</FILE>
+<TITLE>SDL Integration</TITLE>
+cogl_sdl_context_new
+cogl_sdl_renderer_set_event_type
+cogl_sdl_renderer_get_event_type
+cogl_sdl_handle_event
+cogl_sdl_idle
+</SECTION>
diff --git a/examples/cogl-sdl-hello.c b/examples/cogl-sdl-hello.c
index 8643c38..bffa044 100644
--- a/examples/cogl-sdl-hello.c
+++ b/examples/cogl-sdl-hello.c
@@ -13,9 +13,10 @@ typedef struct Data
   float center_x, center_y;
   CoglFramebuffer *fb;
   gboolean quit;
+  gboolean redraw_queued;
 } Data;
 
-static void
+static gboolean
 redraw (Data *data)
 {
   CoglFramebuffer *fb = data->fb;
@@ -29,6 +30,8 @@ redraw (Data *data)
   cogl_framebuffer_pop_matrix (fb);
 
   cogl_onscreen_swap_buffers (COGL_ONSCREEN (fb));
+
+  return FALSE;
 }
 
 static void
@@ -37,7 +40,7 @@ handle_event (Data *data, SDL_Event *event)
   switch (event->type)
     {
     case SDL_VIDEOEXPOSE:
-      redraw (data);
+      data->redraw_queued = TRUE;
       break;
 
     case SDL_MOUSEMOTION:
@@ -50,7 +53,7 @@ handle_event (Data *data, SDL_Event *event)
         data->center_x = event->motion.x * 2.0f / width - 1.0f;
         data->center_y = event->motion.y * 2.0f / height - 1.0f;
 
-        redraw (data);
+        data->redraw_queued = TRUE;
       }
       break;
 
@@ -60,61 +63,9 @@ handle_event (Data *data, SDL_Event *event)
     }
 }
 
-static Uint32
-timer_handler (Uint32 interval, void *user_data)
-{
-  static const SDL_UserEvent dummy_event =
-    {
-      SDL_USEREVENT
-    };
-
-  /* Post an event to wake up from SDL_WaitEvent */
-  SDL_PushEvent ((SDL_Event *) &dummy_event);
-
-  return 0;
-}
-
-static gboolean
-wait_event_with_timeout (Data *data, SDL_Event *event, gint64 timeout)
-{
-  if (timeout == -1)
-    {
-      if (SDL_WaitEvent (event))
-        return TRUE;
-      else
-        {
-          data->quit = TRUE;
-          return FALSE;
-        }
-    }
-  else if (timeout == 0)
-    return SDL_PollEvent (event);
-  else
-    {
-      gboolean ret;
-      /* Add a timer so that we can wake up the event loop */
-      SDL_TimerID timer_id =
-        SDL_AddTimer (timeout / 1000, timer_handler, data);
-
-      if (SDL_WaitEvent (event))
-        ret = TRUE;
-      else
-        {
-          data->quit = TRUE;
-          ret = FALSE;
-        }
-
-      SDL_RemoveTimer (timer_id);
-
-      return ret;
-    }
-}
-
 int
 main (int argc, char **argv)
 {
-  CoglRenderer *renderer;
-  CoglDisplay *display;
   CoglContext *ctx;
   CoglOnscreen *onscreen;
   GError *error = NULL;
@@ -126,19 +77,13 @@ main (int argc, char **argv)
   Data data;
   SDL_Event event;
 
-  /* Force the SDL winsys */
-  renderer = cogl_renderer_new ();
-  cogl_renderer_set_winsys_id (renderer, COGL_WINSYS_ID_SDL);
-  display = cogl_display_new (renderer, NULL);
-  ctx = cogl_context_new (display, &error);
+  ctx = cogl_sdl_context_new (SDL_USEREVENT, &error);
   if (!ctx)
     {
       fprintf (stderr, "Failed to create context: %s\n", error->message);
       return 1;
     }
 
-  SDL_InitSubSystem (SDL_INIT_TIMER);
-
   onscreen = cogl_onscreen_new (ctx, 800, 600);
   data.fb = COGL_FRAMEBUFFER (onscreen);
 
@@ -151,31 +96,33 @@ main (int argc, char **argv)
   data.triangle = cogl_primitive_new_p2c4 (ctx, COGL_VERTICES_MODE_TRIANGLES,
                                            3, triangle_vertices);
   data.pipeline = cogl_pipeline_new (ctx);
+
+  data.redraw_queued = TRUE;
   while (!data.quit)
     {
-      CoglPollFD *poll_fds;
-      int n_poll_fds;
-      gint64 timeout;
-
-      cogl_poll_get_info (ctx, &poll_fds, &n_poll_fds, &timeout);
-
-      /* It's difficult to wait for file descriptors using the SDL
-         event mechanism, but it the SDL winsys is documented that it
-         will never require this so we can assert that there are no
-         fds */
-      g_assert (n_poll_fds == 0);
+      while (!data.quit)
+        {
+          int status = SDL_PollEvent (&event);
+          if (!status && data.redraw_queued)
+            break;
+          else if (!status)
+            {
+              cogl_sdl_idle (ctx);
+              if (!SDL_WaitEvent (&event))
+                {
+                  fprintf (stderr, "Error waiting for SDL events");
+                  return 1;
+                }
+            }
 
-      if (wait_event_with_timeout (&data, &event, timeout))
-        do
           handle_event (&data, &event);
-        while (SDL_PollEvent (&event));
+          cogl_sdl_handle_event (ctx, &event);
+        }
 
-      cogl_poll_dispatch (ctx, poll_fds, n_poll_fds);
+      data.redraw_queued = redraw (&data);
     }
 
   cogl_object_unref (ctx);
-  cogl_object_unref (display);
-  cogl_object_unref (renderer);
 
   return 0;
 }
-- 
1.7.7.6



More information about the Cogl mailing list