[clutter] Improve repaint functions



commit 229607464b287d6ea1ed1633d4e982768ccb18cc
Author: Emmanuele Bassi <ebassi linux intel com>
Date:   Tue Mar 6 12:09:00 2012 +0000

    Improve repaint functions
    
    It is sometimes useful to be able to have better control on when a
    repaint function is called. Currently, all repaint functions are called
    prior to the stages update phase of the frame processing.
    
    We can introduce flags to represent the point in the frame update
    process in which we wish Clutter called the repaint function.
    
    As a bonus, we can also add a flag that causes adding a repaint function
    to spin the master clock.

 clutter/clutter-enums.h                    |   19 ++++++
 clutter/clutter-main.c                     |   91 +++++++++++++++++++++++++---
 clutter/clutter-main.h                     |    4 +
 clutter/clutter-master-clock.c             |    8 ++-
 clutter/clutter-private.h                  |    2 +-
 clutter/clutter.symbols                    |    1 +
 doc/reference/clutter/clutter-sections.txt |    1 +
 7 files changed, 113 insertions(+), 13 deletions(-)
---
diff --git a/clutter/clutter-enums.h b/clutter/clutter-enums.h
index 40bdb6a..0588780 100644
--- a/clutter/clutter-enums.h
+++ b/clutter/clutter-enums.h
@@ -1094,6 +1094,25 @@ typedef enum {
   CLUTTER_ACTOR_ALIGN_END
 } ClutterActorAlign;
 
+/**
+ * ClutterRepaintFlags:
+ * @CLUTTER_REPAINT_FLAGS_PRE_PAINT: Run the repaint function prior to
+ *   painting the stages
+ * @CLUTTER_REPAINT_FLAGS_POST_PAINT: Run the repaint function after
+ *   painting the stages
+ * @CLUTTER_REPAINT_FLAGS_QUEUE_REDRAW_ON_ADD: Ensure that a new frame
+ *   is queued after adding the repaint function
+ *
+ * Flags to pass to clutter_threads_add_repaint_func_full().
+ *
+ * Since: 1.10
+ */
+typedef enum {
+  CLUTTER_REPAINT_FLAGS_PRE_PAINT = 1 << 0,
+  CLUTTER_REPAINT_FLAGS_POST_PAINT = 1 << 1,
+  CLUTTER_REPAINT_FLAGS_QUEUE_REDRAW_ON_ADD = 1 << 2
+} ClutterRepaintFlags;
+
 G_END_DECLS
 
 #endif /* __CLUTTER_ENUMS_H__ */
diff --git a/clutter/clutter-main.c b/clutter/clutter-main.c
index 860fa6f..4ffbab1 100644
--- a/clutter/clutter-main.c
+++ b/clutter/clutter-main.c
@@ -19,9 +19,8 @@
  *
  * 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/>.
- *
- *
  */
+
 /**
  * SECTION:clutter-main
  * @short_description: Various 'global' clutter functions.
@@ -3310,6 +3309,7 @@ clutter_get_font_map (void)
 typedef struct _ClutterRepaintFunction
 {
   guint id;
+  ClutterRepaintFlags flags;
   GSourceFunc func;
   gpointer data;
   GDestroyNotify notify;
@@ -3368,21 +3368,32 @@ clutter_threads_remove_repaint_func (guint handle_id)
  * @notify: function to be called when removing the repaint
  *    function, or %NULL
  *
- * Adds a function to be called whenever Clutter is repainting a Stage.
+ * Adds a function to be called whenever Clutter is processing a new
+ * frame.
+ *
  * If the function returns %FALSE it is automatically removed from the
  * list of repaint functions and will not be called again.
  *
  * This function is guaranteed to be called from within the same thread
- * that called clutter_main(), and while the Clutter lock is being held.
+ * that called clutter_main(), and while the Clutter lock is being held;
+ * the function will be called within the main loop, so it is imperative
+ * that it does not block, otherwise the frame time budget may be lost.
  *
  * A repaint function is useful to ensure that an update of the scenegraph
  * is performed before the scenegraph is repainted; for instance, uploading
- * a frame from a video into a #ClutterTexture.
+ * a frame from a video into a #ClutterTexture. By default, a repaint
+ * function added using this function will be invoked prior to the frame
+ * being processed.
+ *
+ * Adding a repaint function does not automatically ensure that a new
+ * frame will be queued.
  *
  * When the repaint function is removed (either because it returned %FALSE
  * or because clutter_threads_remove_repaint_func() has been called) the
  * @notify function will be called, if any is set.
  *
+ * See also: clutter_threads_add_repaint_func_full()
+ *
  * Return value: the ID (greater than 0) of the repaint function. You
  *   can use the returned integer to remove the repaint function by
  *   calling clutter_threads_remove_repaint_func().
@@ -3394,6 +3405,55 @@ clutter_threads_add_repaint_func (GSourceFunc    func,
                                   gpointer       data,
                                   GDestroyNotify notify)
 {
+  return clutter_threads_add_repaint_func_full (CLUTTER_REPAINT_FLAGS_PRE_PAINT,
+                                                func,
+                                                data, notify);
+}
+
+/**
+ * clutter_threads_add_repaint_func_full:
+ * @flags: flags for the repaint function
+ * @func: the function to be called within the paint cycle
+ * @data: data to be passed to the function, or %NULL
+ * @notify: function to be called when removing the repaint
+ *    function, or %NULL
+ *
+ * Adds a function to be called whenever Clutter is processing a new
+ * frame.
+ *
+ * If the function returns %FALSE it is automatically removed from the
+ * list of repaint functions and will not be called again.
+ *
+ * This function is guaranteed to be called from within the same thread
+ * that called clutter_main(), and while the Clutter lock is being held;
+ * the function will be called within the main loop, so it is imperative
+ * that it does not block, otherwise the frame time budget may be lost.
+ *
+ * A repaint function is useful to ensure that an update of the scenegraph
+ * is performed before the scenegraph is repainted; for instance, uploading
+ * a frame from a video into a #ClutterTexture. The @flags passed to this
+ * function will determine the section of the frame processing that will
+ * result in @func being called.
+ *
+ * Adding a repaint function does not automatically ensure that a new
+ * frame will be queued.
+ *
+ * When the repaint function is removed (either because it returned %FALSE
+ * or because clutter_threads_remove_repaint_func() has been called) the
+ * @notify function will be called, if any is set.
+ *
+ * Return value: the ID (greater than 0) of the repaint function. You
+ *   can use the returned integer to remove the repaint function by
+ *   calling clutter_threads_remove_repaint_func().
+ *
+ * Since: 1.10
+ */
+guint
+clutter_threads_add_repaint_func_full (ClutterRepaintFlags flags,
+                                       GSourceFunc         func,
+                                       gpointer            data,
+                                       GDestroyNotify      notify)
+{
   ClutterMainContext *context;
   ClutterRepaintFunction *repaint_func;
 
@@ -3406,6 +3466,9 @@ clutter_threads_add_repaint_func (GSourceFunc    func,
   repaint_func = g_slice_new (ClutterRepaintFunction);
 
   repaint_func->id = context->last_repaint_id++;
+
+  /* mask out QUEUE_REDRAW_ON_ADD, since we're going to consume it */
+  repaint_func->flags = flags & ~CLUTTER_REPAINT_FLAGS_QUEUE_REDRAW_ON_ADD;
   repaint_func->func = func;
   repaint_func->data = data;
   repaint_func->notify = notify;
@@ -3415,20 +3478,27 @@ clutter_threads_add_repaint_func (GSourceFunc    func,
 
   _clutter_context_unlock ();
 
+  if ((flags & CLUTTER_REPAINT_FLAGS_QUEUE_REDRAW_ON_ADD) != 0)
+    {
+      ClutterMasterClock *master_clock = _clutter_master_clock_get_default ();
+
+      _clutter_master_clock_ensure_next_iteration (master_clock);
+    }
+
   return repaint_func->id;
 }
 
 /*
  * _clutter_run_repaint_functions:
+ * @flags: only run the repaint functions matching the passed flags
  *
  * Executes the repaint functions added using the
  * clutter_threads_add_repaint_func() function.
  *
- * Must be called before calling _clutter_stage_do_paint() and
- * with the Clutter thread lock held.
+ * Must be called with the Clutter thread lock held.
  */
 void
-_clutter_run_repaint_functions (void)
+_clutter_run_repaint_functions (ClutterRepaintFlags flags)
 {
   ClutterMainContext *context = _clutter_context_get_default ();
   ClutterRepaintFunction *repaint_func;
@@ -3455,7 +3525,10 @@ _clutter_run_repaint_functions (void)
 
       g_list_free (l);
 
-      res = repaint_func->func (repaint_func->data);
+      if ((repaint_func->flags & flags) != 0)
+        res = repaint_func->func (repaint_func->data);
+      else
+        res = TRUE;
 
       if (res)
         reinvoke_list = g_list_prepend (reinvoke_list, repaint_func);
diff --git a/clutter/clutter-main.h b/clutter/clutter-main.h
index b59b572..1b4a6bb 100644
--- a/clutter/clutter-main.h
+++ b/clutter/clutter-main.h
@@ -122,6 +122,10 @@ guint                   clutter_threads_add_timeout_full        (gint
 guint                   clutter_threads_add_repaint_func        (GSourceFunc    func,
                                                                  gpointer       data,
                                                                  GDestroyNotify notify);
+guint                   clutter_threads_add_repaint_func_full   (ClutterRepaintFlags flags,
+                                                                 GSourceFunc    func,
+                                                                 gpointer       data,
+                                                                 GDestroyNotify notify);
 void                    clutter_threads_remove_repaint_func     (guint          handle_id);
 
 void                    clutter_grab_pointer                    (ClutterActor  *actor);
diff --git a/clutter/clutter-master-clock.c b/clutter/clutter-master-clock.c
index a48a66e..78aefc7 100644
--- a/clutter/clutter-master-clock.c
+++ b/clutter/clutter-master-clock.c
@@ -359,10 +359,10 @@ clutter_clock_dispatch (GSource     *source,
   stages = clutter_stage_manager_list_stages (stage_manager);
   g_slist_foreach (stages, (GFunc) g_object_ref, NULL);
 
-  CLUTTER_TIMER_START (_clutter_uprof_context, master_event_process);
-
   master_clock->idle = FALSE;
 
+  CLUTTER_TIMER_START (_clutter_uprof_context, master_event_process);
+
   /* Process queued events */
   for (l = stages; l != NULL; l = l->next)
     {
@@ -378,7 +378,7 @@ clutter_clock_dispatch (GSource     *source,
 
   _clutter_master_clock_advance (master_clock);
 
-  _clutter_run_repaint_functions ();
+  _clutter_run_repaint_functions (CLUTTER_REPAINT_FLAGS_PRE_PAINT);
 
   /* Update any stage that needs redraw/relayout after the clock
    * is advanced.
@@ -398,6 +398,8 @@ clutter_clock_dispatch (GSource     *source,
         stages_updated |= _clutter_stage_do_update (l->data);
     }
 
+  _clutter_run_repaint_functions (CLUTTER_REPAINT_FLAGS_POST_PAINT);
+
   /* The master clock goes idle if no stages were updated and falls back
    * to polling for timeline progressions... */
   if (!stages_updated)
diff --git a/clutter/clutter-private.h b/clutter/clutter-private.h
index df17d6a..916ee73 100644
--- a/clutter/clutter-private.h
+++ b/clutter/clutter-private.h
@@ -232,7 +232,7 @@ gboolean _clutter_boolean_handled_accumulator (GSignalInvocationHint *ihint,
                                                const GValue          *handler_return,
                                                gpointer               dummy);
 
-void _clutter_run_repaint_functions (void);
+void _clutter_run_repaint_functions (ClutterRepaintFlags flags);
 
 void _clutter_constraint_update_allocation (ClutterConstraint *constraint,
                                             ClutterActor      *actor,
diff --git a/clutter/clutter.symbols b/clutter/clutter.symbols
index df9fa69..9cd12fa 100644
--- a/clutter/clutter.symbols
+++ b/clutter/clutter.symbols
@@ -1247,6 +1247,7 @@ clutter_threads_add_frame_source_full
 clutter_threads_add_idle
 clutter_threads_add_idle_full
 clutter_threads_add_repaint_func
+clutter_threads_add_repaint_func_full
 clutter_threads_add_timeout
 clutter_threads_add_timeout_full
 clutter_threads_enter
diff --git a/doc/reference/clutter/clutter-sections.txt b/doc/reference/clutter/clutter-sections.txt
index 38fc7a8..1311b87 100644
--- a/doc/reference/clutter/clutter-sections.txt
+++ b/doc/reference/clutter/clutter-sections.txt
@@ -1296,6 +1296,7 @@ clutter_threads_add_timeout_full
 clutter_threads_add_frame_source
 clutter_threads_add_frame_source_full
 clutter_threads_add_repaint_func
+clutter_threads_add_repaint_func_full
 clutter_threads_remove_repaint_func
 
 <SUBSECTION>



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