[clutter] master-clock: Clean up the frame processing



commit bdf9f4958825fa7a9adf0bea16d4d079becb896f
Author: Emmanuele Bassi <ebassi linux intel com>
Date:   Tue Mar 6 12:55:27 2012 +0000

    master-clock: Clean up the frame processing
    
    Split out every phase into its own function, to ensure that the sequence
    of operation is clear and easy to follow.

 clutter/clutter-master-clock.c |  237 +++++++++++++++++++++-------------------
 clutter/clutter-master-clock.h |    1 -
 2 files changed, 124 insertions(+), 114 deletions(-)
---
diff --git a/clutter/clutter-master-clock.c b/clutter/clutter-master-clock.c
index 78aefc7..de3dd7f 100644
--- a/clutter/clutter-master-clock.c
+++ b/clutter/clutter-master-clock.c
@@ -206,15 +206,7 @@ master_clock_next_frame_delay (ClutterMasterClock *master_clock)
   /* Otherwise, wait at least 1/frame_rate seconds since we last
    * started a frame
    */
-#if GLIB_CHECK_VERSION (2, 27, 3)
   now = g_source_get_time (master_clock->source);
-#else
-  {
-    GTimeVal source_time;
-    g_source_get_current_time (master_clock->source, &source_time);
-    now = source_time.tv_sec * 1000000L + source_time.tv_usec;
-  }
-#endif
 
   next = master_clock->prev_tick;
 
@@ -245,6 +237,119 @@ master_clock_next_frame_delay (ClutterMasterClock *master_clock)
     }
 }
 
+static void
+master_clock_process_events (ClutterMasterClock *master_clock,
+                             GSList             *stages)
+{
+  GSList *l;
+
+  CLUTTER_STATIC_TIMER (master_event_process,
+                        "Master Clock",
+                        "Event Processing",
+                        "The time spent processing events on all stages",
+                        0);
+
+  CLUTTER_TIMER_START (_clutter_uprof_context, master_event_process);
+
+  /* Process queued events */
+  for (l = stages; l != NULL; l = l->next)
+    {
+      /* NB: If a stage is busy waiting for a swap-buffers completion then
+       * we don't process its events so we can maximize the benefits of
+       * motion compression, and avoid multiple picks per frame.
+       */
+      if (_clutter_stage_get_pending_swaps (l->data) == 0)
+        _clutter_stage_process_queued_events (l->data);
+    }
+
+  CLUTTER_TIMER_STOP (_clutter_uprof_context, master_event_process);
+}
+
+/*
+ * master_clock_advance_timelines:
+ * @master_clock: a #ClutterMasterClock
+ *
+ * Advances all the timelines held by the master clock. This function
+ * should be called before calling _clutter_stage_do_update() to
+ * make sure that all the timelines are advanced and the scene is updated.
+ */
+static void
+master_clock_advance_timelines (ClutterMasterClock *master_clock)
+{
+  GSList *timelines, *l;
+
+  CLUTTER_STATIC_TIMER (master_timeline_advance,
+                        "Master Clock",
+                        "Timelines Advancement",
+                        "The time spent advancing all timelines",
+                        0);
+
+  /* we protect ourselves from timelines being removed during
+   * the advancement by other timelines by copying the list of
+   * timelines, taking a reference on them, iterating over the
+   * copied list and then releasing the reference.
+   *
+   * we cannot simply take a reference on the timelines and still
+   * use the list held by the master clock because the do_tick()
+   * might result in the creation of a new timeline, which gets
+   * added at the end of the list with no reference increase and
+   * thus gets disposed at the end of the iteration.
+   *
+   * this implies that a newly added timeline will not be advanced
+   * by this clock iteration, which is perfectly fine since we're
+   * in its first cycle.
+   *
+   * we also cannot steal the master clock timelines list because
+   * a timeline might be removed as the direct result of do_tick()
+   * and remove_timeline() would not find the timeline, failing
+   * and leaving a dangling pointer behind.
+   */
+  timelines = g_slist_copy (master_clock->timelines);
+  g_slist_foreach (timelines, (GFunc) g_object_ref, NULL);
+
+  CLUTTER_TIMER_START (_clutter_uprof_context, master_timeline_advance);
+
+  for (l = timelines; l != NULL; l = l->next)
+    _clutter_timeline_do_tick (l->data, master_clock->cur_tick / 1000);
+
+  CLUTTER_TIMER_STOP (_clutter_uprof_context, master_timeline_advance);
+
+  g_slist_foreach (timelines, (GFunc) g_object_unref, NULL);
+  g_slist_free (timelines);
+}
+
+static gboolean
+master_clock_update_stages (ClutterMasterClock *master_clock,
+                            GSList             *stages)
+{
+  gboolean stages_updated = FALSE;
+  GSList *l;
+
+  _clutter_run_repaint_functions (CLUTTER_REPAINT_FLAGS_PRE_PAINT);
+
+  /* Update any stage that needs redraw/relayout after the clock
+   * is advanced.
+   */
+  for (l = stages; l != NULL; l = l->next)
+    {
+      /* If a stage has a swap-buffers pending we don't want to draw to it
+       * in case the driver may block the CPU while it waits for the next
+       * backbuffer to become available.
+       *
+       * TODO: We should be able to identify if we are running triple or N
+       * buffered and in these cases we can still draw if there is 1 swap
+       * pending so we can hopefully always be ready to swap for the next
+       * vblank and really match the vsync frequency.
+       */
+      if (_clutter_stage_get_pending_swaps (l->data) == 0)
+        stages_updated |= _clutter_stage_do_update (l->data);
+    }
+
+  _clutter_run_repaint_functions (CLUTTER_REPAINT_FLAGS_POST_PAINT);
+
+  return stages_updated;
+}
+
 /*
  * clutter_clock_source_new:
  * @master_clock: a #ClutterMasterClock for the source
@@ -322,18 +427,13 @@ clutter_clock_dispatch (GSource     *source,
   ClutterMasterClock *master_clock = clock_source->master_clock;
   ClutterStageManager *stage_manager = clutter_stage_manager_get_default ();
   gboolean stages_updated = FALSE;
-  GSList *stages, *l;
+  GSList *stages;
 
   CLUTTER_STATIC_TIMER (master_dispatch_timer,
                         "Mainloop",
                         "Master Clock",
                         "Master clock dispatch",
                         0);
-  CLUTTER_STATIC_TIMER (master_event_process,
-                        "Master Clock",
-                        "Event Processing",
-                        "The time spent processing events on all stages",
-                        0);
 
   CLUTTER_TIMER_START (_clutter_uprof_context, master_dispatch_timer);
 
@@ -342,16 +442,7 @@ clutter_clock_dispatch (GSource     *source,
   clutter_threads_enter ();
 
   /* Get the time to use for this frame */
-#if GLIB_CHECK_VERSION (2, 27, 3)
   master_clock->cur_tick = g_source_get_time (source);
-#else
-  {
-    GTimeVal source_time;
-    g_source_get_current_time (source, &source_time);
-    master_clock->cur_tick = source_time.tv_sec * 1000000L
-                           + source_time.tv_usec;
-  }
-#endif
 
   /* We need to protect ourselves against stages being destroyed during
    * event handling
@@ -361,44 +452,19 @@ clutter_clock_dispatch (GSource     *source,
 
   master_clock->idle = FALSE;
 
-  CLUTTER_TIMER_START (_clutter_uprof_context, master_event_process);
-
-  /* Process queued events */
-  for (l = stages; l != NULL; l = l->next)
-    {
-      /* NB: If a stage is busy waiting for a swap-buffers completion then
-       * we don't process its events so we can maximize the benefits of
-       * motion compression, and avoid multiple picks per frame.
-       */
-      if (_clutter_stage_get_pending_swaps (l->data) == 0)
-        _clutter_stage_process_queued_events (l->data);
-    }
-
-  CLUTTER_TIMER_STOP (_clutter_uprof_context, master_event_process);
-
-  _clutter_master_clock_advance (master_clock);
-
-  _clutter_run_repaint_functions (CLUTTER_REPAINT_FLAGS_PRE_PAINT);
+  /* Each frame is split into three separate phases: */
 
-  /* Update any stage that needs redraw/relayout after the clock
-   * is advanced.
+  /* 1. process all the events; each stage goes through its events queue
+   *    and processes each event according to its type, then emits the
+   *    various signals that are associated with the event
    */
-  for (l = stages; l != NULL; l = l->next)
-    {
-      /* If a stage has a swap-buffers pending we don't want to draw to it
-       * in case the driver may block the CPU while it waits for the next
-       * backbuffer to become available.
-       *
-       * TODO: We should be able to identify if we are running triple or N
-       * buffered and in these cases we can still draw if there is 1 swap
-       * pending so we can hopefully always be ready to swap for the next
-       * vblank and really match the vsync frequency.
-       */
-      if (_clutter_stage_get_pending_swaps (l->data) == 0)
-        stages_updated |= _clutter_stage_do_update (l->data);
-    }
+  master_clock_process_events (master_clock, stages);
 
-  _clutter_run_repaint_functions (CLUTTER_REPAINT_FLAGS_POST_PAINT);
+  /* 2. advance the timelines */
+  master_clock_advance_timelines (master_clock);
+
+  /* 3. relayout and redraw the stages */
+  stages_updated = master_clock_update_stages (master_clock, stages);
 
   /* The master clock goes idle if no stages were updated and falls back
    * to polling for timeline progressions... */
@@ -529,61 +595,6 @@ _clutter_master_clock_start_running (ClutterMasterClock *master_clock)
   g_main_context_wakeup (NULL);
 }
 
-/*
- * _clutter_master_clock_advance:
- * @master_clock: a #ClutterMasterClock
- *
- * Advances all the timelines held by the master clock. This function
- * should be called before calling _clutter_stage_do_update() to
- * make sure that all the timelines are advanced and the scene is updated.
- */
-void
-_clutter_master_clock_advance (ClutterMasterClock *master_clock)
-{
-  GSList *timelines, *l;
-
-  CLUTTER_STATIC_TIMER (master_timeline_advance,
-                        "Master Clock",
-                        "Timelines Advancement",
-                        "The time spent advancing all timelines",
-                        0);
-
-  g_return_if_fail (CLUTTER_IS_MASTER_CLOCK (master_clock));
-
-  CLUTTER_TIMER_START (_clutter_uprof_context, master_timeline_advance);
-
-  /* we protect ourselves from timelines being removed during
-   * the advancement by other timelines by copying the list of
-   * timelines, taking a reference on them, iterating over the
-   * copied list and then releasing the reference.
-   *
-   * we cannot simply take a reference on the timelines and still
-   * use the list held by the master clock because the do_tick()
-   * might result in the creation of a new timeline, which gets
-   * added at the end of the list with no reference increase and
-   * thus gets disposed at the end of the iteration.
-   *
-   * this implies that a newly added timeline will not be advanced
-   * by this clock iteration, which is perfectly fine since we're
-   * in its first cycle.
-   *
-   * we also cannot steal the master clock timelines list because
-   * a timeline might be removed as the direct result of do_tick()
-   * and remove_timeline() would not find the timeline, failing
-   * and leaving a dangling pointer behind.
-   */
-  timelines = g_slist_copy (master_clock->timelines);
-  g_slist_foreach (timelines, (GFunc) g_object_ref, NULL);
-
-  for (l = timelines; l != NULL; l = l->next)
-    _clutter_timeline_do_tick (l->data, master_clock->cur_tick / 1000);
-
-  g_slist_foreach (timelines, (GFunc) g_object_unref, NULL);
-  g_slist_free (timelines);
-
-  CLUTTER_TIMER_STOP (_clutter_uprof_context, master_timeline_advance);
-}
-
 /**
  * _clutter_master_clock_ensure_next_iteration:
  * @master_clock: a #ClutterMasterClock
diff --git a/clutter/clutter-master-clock.h b/clutter/clutter-master-clock.h
index 75213af..17162d1 100644
--- a/clutter/clutter-master-clock.h
+++ b/clutter/clutter-master-clock.h
@@ -41,7 +41,6 @@ void                    _clutter_master_clock_add_timeline              (Clutter
                                                                          ClutterTimeline    *timeline);
 void                    _clutter_master_clock_remove_timeline           (ClutterMasterClock *master_clock,
                                                                          ClutterTimeline    *timeline);
-void                    _clutter_master_clock_advance                   (ClutterMasterClock *master_clock);
 void                    _clutter_master_clock_start_running             (ClutterMasterClock *master_clock);
 void                    _clutter_master_clock_ensure_next_iteration     (ClutterMasterClock *master_clock);
 



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