examples: use dedicated thread for rendering the scene
authorJosep Torra <n770galaxy@gmail.com>
Fri, 20 Sep 2013 07:34:37 +0000 (09:34 +0200)
committerJosep Torra <n770galaxy@gmail.com>
Fri, 20 Sep 2013 16:17:34 +0000 (18:17 +0200)
Produces smother animation and prevents dropping frames due busy
mainloop.

examples/egl/testegl.c

index 617b547..b9833dd 100644 (file)
@@ -139,7 +139,6 @@ typedef struct
   uint32_t screen_width;
   uint32_t screen_height;
   gboolean animate;
-  gboolean sync_animation_with_video;
 
   /* OpenGL|ES objects */
   EGLDisplay display;
@@ -179,6 +178,9 @@ typedef struct
   GstBuffer *last_buffer;
 
   GstCaps *current_caps;
+
+  /* Rendering thread state */
+  gboolean running;
 } APP_STATE_T;
 
 typedef struct
@@ -933,14 +935,14 @@ init_textures (APP_STATE_T * state)
   glBindTexture (GL_TEXTURE_2D, state->tex);
 }
 
-static gboolean
+static void
 render_scene (APP_STATE_T * state)
 {
   update_model (state);
   redraw_scene (state);
   TRACE_VC_MEMORY_ONCE_FOR_ID ("after render_scene", gid2);
 
-  return !state->sync_animation_with_video;
+  return;
 }
 
 static void
@@ -964,9 +966,7 @@ update_image (APP_STATE_T * state, GstBuffer * buffer)
 
   TRACE_VC_MEMORY_ONCE_FOR_ID ("after glEGLImageTargetTexture2DOES", gid1);
 
-  if (state->sync_animation_with_video) {
-    render_scene (state);
-  }
+  render_scene (state);
 }
 
 static void
@@ -979,6 +979,23 @@ init_intercom (APP_STATE_T * state)
 }
 
 static void
+terminate_intercom (APP_STATE_T * state)
+{
+  /* Release intercom */
+  if (state->queue) {
+    g_async_queue_unref (state->queue);
+  }
+
+  if (state->lock) {
+    g_mutex_free (state->lock);
+  }
+
+  if (state->cond) {
+    g_cond_free (state->cond);
+  }
+}
+
+static void
 flush_internal (APP_STATE_T * state)
 {
   if (state->current_mem) {
@@ -1159,12 +1176,6 @@ queue_object (APP_STATE_T * state, GstMiniObject * obj, gboolean synchronous)
 
   g_async_queue_push (state->queue, obj);
 
-
-  if (state->sync_animation_with_video) {
-    g_idle_add_full (G_PRIORITY_HIGH_IDLE, (GSourceFunc) handle_queued_objects,
-        state, NULL);
-  }
-
   if (synchronous) {
     /* Waiting for object to be handled */
     do {
@@ -1176,13 +1187,6 @@ queue_object (APP_STATE_T * state, GstMiniObject * obj, gboolean synchronous)
   return TRUE;
 }
 
-static gboolean
-handle_msgs_and_render_scene (APP_STATE_T * state)
-{
-  handle_queued_objects (state);
-  return render_scene (state);
-}
-
 static void
 preroll_cb (GstElement * fakesink, GstBuffer * buffer, GstPad * pad,
     gpointer user_data)
@@ -1509,18 +1513,6 @@ handle_keyboard (GIOChannel * source, GIOCondition cond, APP_STATE_T * state)
         flush_start (state);
         gst_element_set_state (state->pipeline, GST_STATE_READY);
         break;
-      case 'S':
-        if (state->sync_animation_with_video) {
-          state->sync_animation_with_video = FALSE;
-          /* Add the rendering task */
-          g_idle_add_full (G_PRIORITY_HIGH_IDLE,
-              (GSourceFunc) handle_msgs_and_render_scene, state, NULL);
-          g_print ("\nanimation is not synchoronized with video\n");
-        } else {
-          state->sync_animation_with_video = TRUE;
-          g_print ("\nanimation is synchoronized with video\n");
-        }
-        break;
     }
   }
   g_free (str);
@@ -1617,6 +1609,47 @@ close_ogl (void)
 
 //==============================================================================
 
+static void
+open_ogl (void)
+{
+  TRACE_VC_MEMORY ("state 0");
+
+#if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_EGL)
+  bcm_host_init ();
+  TRACE_VC_MEMORY ("after bcm_host_init");
+#endif
+
+  /* Start OpenGLES */
+  init_ogl (state);
+  TRACE_VC_MEMORY ("after init_ogl");
+
+  /* Wrap the EGL display */
+  state->gst_display = gst_egl_display_new (state->display, NULL);
+
+  /* Setup the model world */
+  init_model_proj (state);
+  TRACE_VC_MEMORY ("after init_model_proj");
+
+  /* initialize the OGLES texture(s) */
+  init_textures (state);
+  TRACE_VC_MEMORY ("after init_textures");
+}
+
+static gpointer
+render_func (gpointer data)
+{
+  open_ogl ();
+  state->running = TRUE;
+
+  do {
+    handle_queued_objects (state);
+    g_usleep (0);
+  } while (state->running == TRUE);
+
+  close_ogl ();
+  return NULL;
+}
+
 int
 main (int argc, char **argv)
 {
@@ -1628,11 +1661,11 @@ main (int argc, char **argv)
   GOptionEntry options[] = {
     {NULL}
   };
+  GThread *rthread;
 
   /* Clear application state */
   memset (state, 0, sizeof (*state));
   state->animate = TRUE;
-  state->sync_animation_with_video = TRUE;
 
   /* must initialise the threading system before using any other GLib funtion */
   if (!g_thread_supported ())
@@ -1655,31 +1688,16 @@ main (int argc, char **argv)
   /* Initialize GStreamer */
   gst_init (&argc, &argv);
 
-  TRACE_VC_MEMORY ("state 0");
-
-#if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_EGL)
-  bcm_host_init ();
-  TRACE_VC_MEMORY ("after bcm_host_init");
-#endif
-
-  /* Start OpenGLES */
-  init_ogl (state);
-  TRACE_VC_MEMORY ("after init_ogl");
-
-  /* Wrap the EGL display */
-  state->gst_display = gst_egl_display_new (state->display, NULL);
-
-  /* Setup the model world */
-  init_model_proj (state);
-  TRACE_VC_MEMORY ("after init_model_proj");
-
-  /* initialize the OGLES texture(s) */
-  init_textures (state);
-  TRACE_VC_MEMORY ("after init_textures");
-
   /* initialize inter thread comunnication */
   init_intercom (state);
 
+  TRACE_VC_MEMORY ("state 0");
+
+  if (!(rthread = g_thread_new ("render", (GThreadFunc) render_func, NULL))) {
+    g_print ("Render thread create failed\n");
+    exit (1);
+  }
+
   /* Initialize player */
   if (gst_uri_is_valid (argv[1])) {
     res = init_playbin_player (state, argv[1]);
@@ -1706,16 +1724,9 @@ main (int argc, char **argv)
       "  l - Query position/duration\n"
       "  f - Seek 30 seconds forward \n"
       "  b - Seek 30 seconds backward \n"
-      "  S - Toggle synchronization of video and animation \n"
       "  q - Quit \n");
   /* *INDENT-ON* */
 
-  if (!state->sync_animation_with_video) {
-    /* Add the rendering task */
-    g_idle_add_full (G_PRIORITY_HIGH_IDLE,
-        (GSourceFunc) handle_msgs_and_render_scene, state, NULL);
-  }
-
   /* Connect the bus handlers */
   bus = gst_element_get_bus (state->pipeline);
 
@@ -1748,25 +1759,16 @@ done:
     gst_object_unref (state->pipeline);
   }
 
-  /* Release intercom */
-  if (state->queue) {
-    g_async_queue_unref (state->queue);
-  }
-
-  if (state->lock) {
-    g_mutex_free (state->lock);
-  }
-
-  if (state->cond) {
-    g_cond_free (state->cond);
-  }
-
   /* Unref the mainloop */
   if (state->main_loop) {
     g_main_loop_unref (state->main_loop);
   }
 
-  close_ogl ();
+  /* Stop rendering thread */
+  state->running = FALSE;
+  g_thread_join (rthread);
+
+  terminate_intercom (state);
 
   TRACE_VC_MEMORY ("at exit");
   return 0;