[clutter/wip/cogl-winsys-egl: 2/37] stage: Move _clutter_do_pick to clutter-stage.c



commit 7b5eb2ec80ffdcabd2f80330b5751748353fd94c
Author: Robert Bragg <robert linux intel com>
Date:   Tue Mar 15 13:17:04 2011 +0000

    stage: Move _clutter_do_pick to clutter-stage.c
    
    This moves the implementation of _clutter_do_pick to clutter-stage.c and
    renames it _clutter_stage_do_pick. This function can be compared to
    _clutter_stage_do_update/redraw in that it prepares for and starts a
    traversal of a scenegraph descending from a given stage. Since it is
    desirable that this function should have access to the private state of
    the stage it is awkward to maintain outside of clutter-stage.c.
    
    Besides moving _clutter_do_pick this patch is also able to remove the
    following private state accessors from clutter-stage-private.h:
    _clutter_stage_set_pick_buffer_valid,
    _clutter_stage_get_pick_buffer_valid,
    _clutter_stage_increment_picks_per_frame_counter,
    _clutter_stage_reset_picks_per_frame_counter and
    _clutter_stage_get_picks_per_frame_counter.

 clutter/clutter-input-device.c  |    3 +-
 clutter/clutter-main.c          |  270 +------------------------------
 clutter/clutter-private.h       |    7 +-
 clutter/clutter-stage-private.h |   13 +-
 clutter/clutter-stage.c         |  343 +++++++++++++++++++++++++++++++++------
 5 files changed, 307 insertions(+), 329 deletions(-)
---
diff --git a/clutter/clutter-input-device.c b/clutter/clutter-input-device.c
index dd277d1..24f0b94 100644
--- a/clutter/clutter-input-device.c
+++ b/clutter/clutter-input-device.c
@@ -708,7 +708,8 @@ _clutter_input_device_update (ClutterInputDevice *device,
   clutter_input_device_get_device_coords (device, &x, &y);
 
   old_cursor_actor = device->cursor_actor;
-  new_cursor_actor = _clutter_do_pick (stage, x, y, CLUTTER_PICK_REACTIVE);
+  new_cursor_actor =
+    _clutter_stage_do_pick (stage, x, y, CLUTTER_PICK_REACTIVE);
 
   /* if the pick could not find an actor then we do not update the
    * input device, to avoid ghost enter/leave events; the pick should
diff --git a/clutter/clutter-main.c b/clutter/clutter-main.c
index 533839e..c1e6884 100644
--- a/clutter/clutter-main.c
+++ b/clutter/clutter-main.c
@@ -94,10 +94,6 @@
 #include <glib/gi18n-lib.h>
 #include <locale.h>
 
-#ifdef USE_GDKPIXBUF
-#include <gdk-pixbuf/gdk-pixbuf.h>
-#endif
-
 #include "clutter-actor.h"
 #include "clutter-backend-private.h"
 #include "clutter-debug.h"
@@ -307,8 +303,8 @@ clutter_get_motion_events_enabled (void)
   return context->motion_events_per_actor;
 }
 
-static inline ClutterActor *
-_clutter_actor_get_by_id (guint32 actor_id)
+ClutterActor *
+_clutter_get_actor_by_id (guint32 actor_id)
 {
   ClutterMainContext *context = _clutter_context_get_default ();
 
@@ -388,7 +384,7 @@ _clutter_id_to_color (guint         id_,
     }
 }
 
-static inline guint
+guint
 _clutter_pixel_to_id (guchar pixel[4])
 {
   ClutterMainContext *ctx;
@@ -436,258 +432,6 @@ _clutter_pixel_to_id (guchar pixel[4])
   return retval;
 }
 
-#ifdef USE_GDKPIXBUF
-static void
-pixbuf_free (guchar   *pixels,
-             gpointer  data)
-{
-  g_free (pixels);
-}
-#endif
-
-static void
-read_pixels_to_file (char *filename_stem,
-                     int   x,
-                     int   y,
-                     int   width,
-                     int   height)
-{
-#ifdef USE_GDKPIXBUF
-  GLubyte *data;
-  GdkPixbuf *pixbuf;
-  static int read_count = 0;
-
-  data = g_malloc (4 * width * height);
-  cogl_read_pixels (x, y, width, height,
-                    COGL_READ_PIXELS_COLOR_BUFFER,
-                    COGL_PIXEL_FORMAT_RGB_888,
-                    data);
-  pixbuf = gdk_pixbuf_new_from_data (data,
-                                     GDK_COLORSPACE_RGB,
-                                     FALSE, /* has alpha */
-                                     8, /* bits per sample */
-                                     width, /* width */
-                                     height, /* height */
-                                     width * 3, /* rowstride */
-                                     pixbuf_free, /* callback to free data */
-                                     NULL); /* callback data */
-  if (pixbuf)
-    {
-      char *filename = g_strdup_printf ("%s-%05d.png",
-                                        filename_stem,
-                                        read_count);
-      GError *error = NULL;
-
-      if (!gdk_pixbuf_save (pixbuf, filename, "png", &error, NULL))
-        {
-          g_warning ("Failed to save pick buffer to file %s: %s",
-                     filename, error->message);
-          g_error_free (error);
-        }
-
-      g_free (filename);
-      g_object_unref (pixbuf);
-      read_count++;
-    }
-#else /* !USE_GDKPIXBUF */
-  {
-    static gboolean seen = FALSE;
-
-    if (!seen)
-      {
-        g_warning ("dumping buffers to an image isn't supported on platforms "
-                   "without gdk pixbuf support\n");
-        seen = TRUE;
-      }
-  }
-#endif /* USE_GDKPIXBUF */
-}
-
-ClutterActor *
-_clutter_do_pick (ClutterStage   *stage,
-		  gint            x,
-		  gint            y,
-		  ClutterPickMode mode)
-{
-  ClutterMainContext *context;
-  guchar pixel[4] = { 0xff, 0xff, 0xff, 0xff };
-  CoglColor stage_pick_id;
-  guint32 id_;
-  GLboolean dither_was_on;
-  ClutterActor *actor;
-  gboolean is_clipped;
-  CLUTTER_STATIC_COUNTER (do_pick_counter,
-                          "_clutter_do_pick counter",
-                          "Increments for each full pick run",
-                          0 /* no application private data */);
-  CLUTTER_STATIC_TIMER (pick_timer,
-                        "Mainloop", /* parent */
-                        "Picking",
-                        "The time spent picking",
-                        0 /* no application private data */);
-  CLUTTER_STATIC_TIMER (pick_clear,
-                        "Picking", /* parent */
-                        "Stage clear (pick)",
-                        "The time spent clearing stage for picking",
-                        0 /* no application private data */);
-  CLUTTER_STATIC_TIMER (pick_paint,
-                        "Picking", /* parent */
-                        "Painting actors (pick mode)",
-                        "The time spent painting actors in pick mode",
-                        0 /* no application private data */);
-  CLUTTER_STATIC_TIMER (pick_read,
-                        "Picking", /* parent */
-                        "Read Pixels",
-                        "The time spent issuing a read pixels",
-                        0 /* no application private data */);
-
-  g_return_val_if_fail (CLUTTER_IS_STAGE (stage), NULL);
-
-  if (G_UNLIKELY (clutter_pick_debug_flags & CLUTTER_DEBUG_NOP_PICKING))
-    return CLUTTER_ACTOR (stage);
-
-#ifdef CLUTTER_ENABLE_PROFILE
-  if (clutter_profile_flags & CLUTTER_PROFILE_PICKING_ONLY)
-    _clutter_profile_resume ();
-#endif /* CLUTTER_ENABLE_PROFILE */
-
-  CLUTTER_COUNTER_INC (_clutter_uprof_context, do_pick_counter);
-  CLUTTER_TIMER_START (_clutter_uprof_context, pick_timer);
-
-  context = _clutter_context_get_default ();
-
-  /* It's possible that we currently have a static scene and have renderered a
-   * full, unclipped pick buffer. If so we can simply continue to read from
-   * this cached buffer until the scene next changes. */
-  if (_clutter_stage_get_pick_buffer_valid (stage, mode))
-    {
-      CLUTTER_TIMER_START (_clutter_uprof_context, pick_read);
-      cogl_read_pixels (x, y, 1, 1,
-                        COGL_READ_PIXELS_COLOR_BUFFER,
-                        COGL_PIXEL_FORMAT_RGBA_8888_PRE,
-                        pixel);
-      CLUTTER_TIMER_STOP (_clutter_uprof_context, pick_read);
-
-      CLUTTER_NOTE (PICK, "Reusing pick buffer from previous render to fetch "
-                    "actor at %i,%i", x, y);
-
-      /* FIXME: This is a lazy copy and paste of the logic at the end of this
-       * function used when we actually do a pick render. It should be
-       * consolidated somehow.
-       */
-      if (pixel[0] == 0xff && pixel[1] == 0xff && pixel[2] == 0xff)
-        {
-          actor = CLUTTER_ACTOR (stage);
-          goto result;
-        }
-
-      id_ = _clutter_pixel_to_id (pixel);
-      actor = _clutter_actor_get_by_id (id_);
-      goto result;
-    }
-
-  _clutter_stage_increment_picks_per_frame_counter (stage);
-
-  _clutter_backend_ensure_context (context->backend, stage);
-
-  /* needed for when a context switch happens */
-  _clutter_stage_maybe_setup_viewport (stage);
-
-  /* If we are seeing multiple picks per frame that means the scene is static
-   * so we promote to doing a non-scissored pick render so that all subsequent
-   * picks for the same static scene won't require additional renders */
-  if (_clutter_stage_get_picks_per_frame_counter (stage) < 2)
-    {
-      if (G_LIKELY (!(clutter_pick_debug_flags &
-                      CLUTTER_DEBUG_DUMP_PICK_BUFFERS)))
-        cogl_clip_push_window_rectangle (x, y, 1, 1);
-      is_clipped = TRUE;
-    }
-  else
-    is_clipped = FALSE;
-
-  CLUTTER_NOTE (PICK, "Performing %s pick at %i,%i",
-                is_clipped ? "clippped" : "full", x, y);
-
-  cogl_disable_fog ();
-  cogl_color_init_from_4ub (&stage_pick_id, 255, 255, 255, 255);
-  CLUTTER_TIMER_START (_clutter_uprof_context, pick_clear);
-  cogl_clear (&stage_pick_id,
-	      COGL_BUFFER_BIT_COLOR |
-	      COGL_BUFFER_BIT_DEPTH);
-  CLUTTER_TIMER_STOP (_clutter_uprof_context, pick_clear);
-
-  /* Disable dithering (if any) when doing the painting in pick mode */
-  dither_was_on = glIsEnabled (GL_DITHER);
-  if (dither_was_on)
-    glDisable (GL_DITHER);
-
-  /* Render the entire scence in pick mode - just single colored silhouette's
-   * are drawn offscreen (as we never swap buffers)
-  */
-  CLUTTER_TIMER_START (_clutter_uprof_context, pick_paint);
-  context->pick_mode = mode;
-  _clutter_stage_do_paint (stage, NULL);
-  context->pick_mode = CLUTTER_PICK_NONE;
-  CLUTTER_TIMER_STOP (_clutter_uprof_context, pick_paint);
-
-  if (is_clipped)
-    {
-      if (G_LIKELY (!(clutter_pick_debug_flags &
-                      CLUTTER_DEBUG_DUMP_PICK_BUFFERS)))
-        cogl_clip_pop ();
-
-      _clutter_stage_set_pick_buffer_valid (stage, FALSE, -1);
-    }
-  else
-    _clutter_stage_set_pick_buffer_valid (stage, TRUE, mode);
-
-  /* Read the color of the screen co-ords pixel. RGBA_8888_PRE is used
-     even though we don't care about the alpha component because under
-     GLES this is the only format that is guaranteed to work so Cogl
-     will end up having to do a conversion if any other format is
-     used. The format is requested as pre-multiplied because Cogl
-     assumes that all pixels in the framebuffer are premultiplied so
-     it avoids a conversion. */
-  CLUTTER_TIMER_START (_clutter_uprof_context, pick_read);
-  cogl_read_pixels (x, y, 1, 1,
-                    COGL_READ_PIXELS_COLOR_BUFFER,
-                    COGL_PIXEL_FORMAT_RGBA_8888_PRE,
-                    pixel);
-  CLUTTER_TIMER_STOP (_clutter_uprof_context, pick_read);
-
-  if (G_UNLIKELY (clutter_pick_debug_flags & CLUTTER_DEBUG_DUMP_PICK_BUFFERS))
-    {
-      read_pixels_to_file ("pick-buffer", 0, 0,
-                           clutter_actor_get_width (CLUTTER_ACTOR (stage)),
-                           clutter_actor_get_height (CLUTTER_ACTOR (stage)));
-    }
-
-  /* Restore whether GL_DITHER was enabled */
-  if (dither_was_on)
-    glEnable (GL_DITHER);
-
-  if (pixel[0] == 0xff && pixel[1] == 0xff && pixel[2] == 0xff)
-    {
-      actor = CLUTTER_ACTOR (stage);
-      goto result;
-    }
-
-  id_ = _clutter_pixel_to_id (pixel);
-  actor = _clutter_actor_get_by_id (id_);
-
-result:
-
-  CLUTTER_TIMER_STOP (_clutter_uprof_context, pick_timer);
-
-#ifdef CLUTTER_ENABLE_PROFILE
-  if (clutter_profile_flags & CLUTTER_PROFILE_PICKING_ONLY)
-    _clutter_profile_suspend ();
-#endif
-
-  return actor;
-}
-
 static CoglPangoFontMap *
 clutter_context_get_pango_fontmap (void)
 {
@@ -2482,9 +2226,9 @@ _clutter_process_event_details (ClutterActor        *stage,
                 {
                   CLUTTER_NOTE (EVENT, "No device found: picking");
 
-                  actor = _clutter_do_pick (CLUTTER_STAGE (stage),
-                                            x, y,
-                                            CLUTTER_PICK_REACTIVE);
+                  actor = _clutter_stage_do_pick (CLUTTER_STAGE (stage),
+                                                  x, y,
+                                                  CLUTTER_PICK_REACTIVE);
                 }
 
               if (actor == NULL)
@@ -2568,7 +2312,7 @@ _clutter_process_event (ClutterEvent *event)
 ClutterActor *
 clutter_get_actor_by_gid (guint32 id_)
 {
-  return _clutter_actor_get_by_id (id_);
+  return _clutter_get_actor_by_id (id_);
 }
 
 void
diff --git a/clutter/clutter-private.h b/clutter/clutter-private.h
index c88f718..4a27343 100644
--- a/clutter/clutter-private.h
+++ b/clutter/clutter-private.h
@@ -194,13 +194,10 @@ G_CONST_RETURN gchar *_clutter_gettext (const gchar *str);
 gboolean      _clutter_feature_init (GError **error);
 
 /* Picking code */
-ClutterActor *_clutter_do_pick (ClutterStage    *stage,
-				gint             x,
-				gint             y,
-				ClutterPickMode  mode);
-
+guint         _clutter_pixel_to_id (guchar pixel[4]);
 void          _clutter_id_to_color (guint id,
                                     ClutterColor *col);
+ClutterActor *_clutter_get_actor_by_id (guint32 actor_id);
 
 /* use this function as the accumulator if you have a signal with
  * a G_TYPE_BOOLEAN return value; this will stop the emission as
diff --git a/clutter/clutter-stage-private.h b/clutter/clutter-stage-private.h
index 7dad14f..79a22f3 100644
--- a/clutter/clutter-stage-private.h
+++ b/clutter/clutter-stage-private.h
@@ -64,14 +64,11 @@ void     _clutter_stage_process_queued_events             (ClutterStage *stage);
 void     _clutter_stage_update_input_devices              (ClutterStage *stage);
 int      _clutter_stage_get_pending_swaps                 (ClutterStage *stage);
 gboolean _clutter_stage_has_full_redraw_queued            (ClutterStage *stage);
-void     _clutter_stage_set_pick_buffer_valid             (ClutterStage   *stage,
-                                                           gboolean        valid,
-                                                           ClutterPickMode mode);
-gboolean _clutter_stage_get_pick_buffer_valid             (ClutterStage *stage,
-                                                           ClutterPickMode mode);
-void     _clutter_stage_increment_picks_per_frame_counter (ClutterStage *stage);
-void     _clutter_stage_reset_picks_per_frame_counter     (ClutterStage *stage);
-guint    _clutter_stage_get_picks_per_frame_counter       (ClutterStage *stage);
+
+ClutterActor *_clutter_stage_do_pick (ClutterStage    *stage,
+                                      gint             x,
+                                      gint             y,
+                                      ClutterPickMode  mode);
 
 ClutterPaintVolume *_clutter_stage_paint_volume_stack_allocate (ClutterStage *stage);
 void                _clutter_stage_paint_volume_stack_free_all (ClutterStage *stage);
diff --git a/clutter/clutter-stage.c b/clutter/clutter-stage.c
index 689b782..bb2b345 100644
--- a/clutter/clutter-stage.c
+++ b/clutter/clutter-stage.c
@@ -73,11 +73,17 @@
 #include "clutter-stage-private.h"
 #include "clutter-util.h"
 #include "clutter-version.h" 	/* For flavour */
+#include "clutter-private.h"
 
 #include "cogl/cogl.h"
 
 #include <math.h>
 
+#ifdef USE_GDKPIXBUF
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#endif
+
+
 G_DEFINE_TYPE (ClutterStage, clutter_stage, CLUTTER_TYPE_GROUP);
 
 #define CLUTTER_STAGE_GET_PRIVATE(obj) \
@@ -954,6 +960,28 @@ _clutter_stage_maybe_relayout (ClutterActor *actor)
     }
 }
 
+static gboolean
+_clutter_stage_get_pick_buffer_valid (ClutterStage *stage, ClutterPickMode mode)
+{
+  g_return_val_if_fail (CLUTTER_IS_STAGE (stage), FALSE);
+
+  if (stage->priv->pick_buffer_mode != mode)
+    return FALSE;
+
+  return stage->priv->have_valid_pick_buffer;
+}
+
+static void
+_clutter_stage_set_pick_buffer_valid (ClutterStage   *stage,
+                                      gboolean        valid,
+                                      ClutterPickMode mode)
+{
+  g_return_if_fail (CLUTTER_IS_STAGE (stage));
+
+  stage->priv->have_valid_pick_buffer = !!valid;
+  stage->priv->pick_buffer_mode = mode;
+}
+
 static void
 clutter_stage_do_redraw (ClutterStage *stage)
 {
@@ -966,7 +994,7 @@ clutter_stage_do_redraw (ClutterStage *stage)
                      stage);
 
   _clutter_stage_set_pick_buffer_valid (stage, FALSE, -1);
-  _clutter_stage_reset_picks_per_frame_counter (stage);
+  priv->picks_per_frame = 0;
 
   _clutter_backend_ensure_context (backend, stage);
 
@@ -1130,6 +1158,263 @@ _clutter_stage_has_full_redraw_queued (ClutterStage *stage)
     return FALSE;
 }
 
+#ifdef USE_GDKPIXBUF
+static void
+pixbuf_free (guchar   *pixels,
+             gpointer  data)
+{
+  g_free (pixels);
+}
+#endif
+
+static void
+read_pixels_to_file (char *filename_stem,
+                     int   x,
+                     int   y,
+                     int   width,
+                     int   height)
+{
+#ifdef USE_GDKPIXBUF
+  GLubyte *data;
+  GdkPixbuf *pixbuf;
+  static int read_count = 0;
+
+  data = g_malloc (4 * width * height);
+  cogl_read_pixels (x, y, width, height,
+                    COGL_READ_PIXELS_COLOR_BUFFER,
+                    COGL_PIXEL_FORMAT_RGB_888,
+                    data);
+  pixbuf = gdk_pixbuf_new_from_data (data,
+                                     GDK_COLORSPACE_RGB,
+                                     FALSE, /* has alpha */
+                                     8, /* bits per sample */
+                                     width, /* width */
+                                     height, /* height */
+                                     width * 3, /* rowstride */
+                                     pixbuf_free, /* callback to free data */
+                                     NULL); /* callback data */
+  if (pixbuf)
+    {
+      char *filename = g_strdup_printf ("%s-%05d.png",
+                                        filename_stem,
+                                        read_count);
+      GError *error = NULL;
+
+      if (!gdk_pixbuf_save (pixbuf, filename, "png", &error, NULL))
+        {
+          g_warning ("Failed to save pick buffer to file %s: %s",
+                     filename, error->message);
+          g_error_free (error);
+        }
+
+      g_free (filename);
+      g_object_unref (pixbuf);
+      read_count++;
+    }
+#else /* !USE_GDKPIXBUF */
+  {
+    static gboolean seen = FALSE;
+
+    if (!seen)
+      {
+        g_warning ("dumping buffers to an image isn't supported on platforms "
+                   "without gdk pixbuf support\n");
+        seen = TRUE;
+      }
+  }
+#endif /* USE_GDKPIXBUF */
+}
+
+ClutterActor *
+_clutter_stage_do_pick (ClutterStage   *stage,
+                        gint            x,
+                        gint            y,
+                        ClutterPickMode mode)
+{
+  ClutterStagePrivate *priv;
+  ClutterMainContext *context;
+  guchar pixel[4] = { 0xff, 0xff, 0xff, 0xff };
+  CoglColor stage_pick_id;
+  guint32 id_;
+  GLboolean dither_was_on;
+  ClutterActor *actor;
+  gboolean is_clipped;
+  CLUTTER_STATIC_COUNTER (do_pick_counter,
+                          "_clutter_stage_do_pick counter",
+                          "Increments for each full pick run",
+                          0 /* no application private data */);
+  CLUTTER_STATIC_TIMER (pick_timer,
+                        "Mainloop", /* parent */
+                        "Picking",
+                        "The time spent picking",
+                        0 /* no application private data */);
+  CLUTTER_STATIC_TIMER (pick_clear,
+                        "Picking", /* parent */
+                        "Stage clear (pick)",
+                        "The time spent clearing stage for picking",
+                        0 /* no application private data */);
+  CLUTTER_STATIC_TIMER (pick_paint,
+                        "Picking", /* parent */
+                        "Painting actors (pick mode)",
+                        "The time spent painting actors in pick mode",
+                        0 /* no application private data */);
+  CLUTTER_STATIC_TIMER (pick_read,
+                        "Picking", /* parent */
+                        "Read Pixels",
+                        "The time spent issuing a read pixels",
+                        0 /* no application private data */);
+
+  g_return_val_if_fail (CLUTTER_IS_STAGE (stage), NULL);
+
+  priv = stage->priv;
+
+  if (G_UNLIKELY (clutter_pick_debug_flags & CLUTTER_DEBUG_NOP_PICKING))
+    return CLUTTER_ACTOR (stage);
+
+#ifdef CLUTTER_ENABLE_PROFILE
+  if (clutter_profile_flags & CLUTTER_PROFILE_PICKING_ONLY)
+    _clutter_profile_resume ();
+#endif /* CLUTTER_ENABLE_PROFILE */
+
+  CLUTTER_COUNTER_INC (_clutter_uprof_context, do_pick_counter);
+  CLUTTER_TIMER_START (_clutter_uprof_context, pick_timer);
+
+  context = _clutter_context_get_default ();
+
+  /* It's possible that we currently have a static scene and have renderered a
+   * full, unclipped pick buffer. If so we can simply continue to read from
+   * this cached buffer until the scene next changes. */
+  if (_clutter_stage_get_pick_buffer_valid (stage, mode))
+    {
+      CLUTTER_TIMER_START (_clutter_uprof_context, pick_read);
+      cogl_read_pixels (x, y, 1, 1,
+                        COGL_READ_PIXELS_COLOR_BUFFER,
+                        COGL_PIXEL_FORMAT_RGBA_8888_PRE,
+                        pixel);
+      CLUTTER_TIMER_STOP (_clutter_uprof_context, pick_read);
+
+      CLUTTER_NOTE (PICK, "Reusing pick buffer from previous render to fetch "
+                    "actor at %i,%i", x, y);
+
+      /* FIXME: This is a lazy copy and paste of the logic at the end of this
+       * function used when we actually do a pick render. It should be
+       * consolidated somehow.
+       */
+      if (pixel[0] == 0xff && pixel[1] == 0xff && pixel[2] == 0xff)
+        {
+          actor = CLUTTER_ACTOR (stage);
+          goto result;
+        }
+
+      id_ = _clutter_pixel_to_id (pixel);
+      actor = _clutter_get_actor_by_id (id_);
+      goto result;
+    }
+
+  priv->picks_per_frame++;
+
+  _clutter_backend_ensure_context (context->backend, stage);
+
+  /* needed for when a context switch happens */
+  _clutter_stage_maybe_setup_viewport (stage);
+
+  /* If we are seeing multiple picks per frame that means the scene is static
+   * so we promote to doing a non-scissored pick render so that all subsequent
+   * picks for the same static scene won't require additional renders */
+  if (priv->picks_per_frame < 2)
+    {
+      if (G_LIKELY (!(clutter_pick_debug_flags &
+                      CLUTTER_DEBUG_DUMP_PICK_BUFFERS)))
+        cogl_clip_push_window_rectangle (x, y, 1, 1);
+      is_clipped = TRUE;
+    }
+  else
+    is_clipped = FALSE;
+
+  CLUTTER_NOTE (PICK, "Performing %s pick at %i,%i",
+                is_clipped ? "clippped" : "full", x, y);
+
+  cogl_disable_fog ();
+  cogl_color_init_from_4ub (&stage_pick_id, 255, 255, 255, 255);
+  CLUTTER_TIMER_START (_clutter_uprof_context, pick_clear);
+  cogl_clear (&stage_pick_id,
+	      COGL_BUFFER_BIT_COLOR |
+	      COGL_BUFFER_BIT_DEPTH);
+  CLUTTER_TIMER_STOP (_clutter_uprof_context, pick_clear);
+
+  /* Disable dithering (if any) when doing the painting in pick mode */
+  dither_was_on = glIsEnabled (GL_DITHER);
+  if (dither_was_on)
+    glDisable (GL_DITHER);
+
+  /* Render the entire scence in pick mode - just single colored silhouette's
+   * are drawn offscreen (as we never swap buffers)
+  */
+  CLUTTER_TIMER_START (_clutter_uprof_context, pick_paint);
+  context->pick_mode = mode;
+  _clutter_stage_do_paint (stage, NULL);
+  context->pick_mode = CLUTTER_PICK_NONE;
+  CLUTTER_TIMER_STOP (_clutter_uprof_context, pick_paint);
+
+  if (is_clipped)
+    {
+      if (G_LIKELY (!(clutter_pick_debug_flags &
+                      CLUTTER_DEBUG_DUMP_PICK_BUFFERS)))
+        cogl_clip_pop ();
+
+      _clutter_stage_set_pick_buffer_valid (stage, FALSE, -1);
+    }
+  else
+    _clutter_stage_set_pick_buffer_valid (stage, TRUE, mode);
+
+  /* Read the color of the screen co-ords pixel. RGBA_8888_PRE is used
+     even though we don't care about the alpha component because under
+     GLES this is the only format that is guaranteed to work so Cogl
+     will end up having to do a conversion if any other format is
+     used. The format is requested as pre-multiplied because Cogl
+     assumes that all pixels in the framebuffer are premultiplied so
+     it avoids a conversion. */
+  CLUTTER_TIMER_START (_clutter_uprof_context, pick_read);
+  cogl_read_pixels (x, y, 1, 1,
+                    COGL_READ_PIXELS_COLOR_BUFFER,
+                    COGL_PIXEL_FORMAT_RGBA_8888_PRE,
+                    pixel);
+  CLUTTER_TIMER_STOP (_clutter_uprof_context, pick_read);
+
+  if (G_UNLIKELY (clutter_pick_debug_flags & CLUTTER_DEBUG_DUMP_PICK_BUFFERS))
+    {
+      read_pixels_to_file ("pick-buffer", 0, 0,
+                           clutter_actor_get_width (CLUTTER_ACTOR (stage)),
+                           clutter_actor_get_height (CLUTTER_ACTOR (stage)));
+    }
+
+  /* Restore whether GL_DITHER was enabled */
+  if (dither_was_on)
+    glEnable (GL_DITHER);
+
+  if (pixel[0] == 0xff && pixel[1] == 0xff && pixel[2] == 0xff)
+    {
+      actor = CLUTTER_ACTOR (stage);
+      goto result;
+    }
+
+  id_ = _clutter_pixel_to_id (pixel);
+  actor = _clutter_get_actor_by_id (id_);
+
+result:
+
+  CLUTTER_TIMER_STOP (_clutter_uprof_context, pick_timer);
+
+#ifdef CLUTTER_ENABLE_PROFILE
+  if (clutter_profile_flags & CLUTTER_PROFILE_PICKING_ONLY)
+    _clutter_profile_suspend ();
+#endif
+
+  return actor;
+}
+
+
+
 static gboolean
 clutter_stage_real_delete_event (ClutterStage *stage,
                                  ClutterEvent *event)
@@ -1766,7 +2051,7 @@ clutter_stage_init (ClutterStage *self)
   _clutter_stage_set_viewport (self, 0, 0, geom.width, geom.height);
 
   _clutter_stage_set_pick_buffer_valid (self, FALSE, CLUTTER_PICK_ALL);
-  _clutter_stage_reset_picks_per_frame_counter (self);
+  priv->picks_per_frame = 0;
 
   priv->paint_volume_stack =
     g_array_new (FALSE, FALSE, sizeof (ClutterPaintVolume));
@@ -2331,7 +2616,7 @@ clutter_stage_get_actor_at_pos (ClutterStage    *stage,
                                 gint             x,
                                 gint             y)
 {
-  return _clutter_do_pick (stage, x, y, pick_mode);
+  return _clutter_stage_do_pick (stage, x, y, pick_mode);
 }
 
 /**
@@ -3250,52 +3535,6 @@ clutter_stage_get_no_clear_hint (ClutterStage *stage)
   return (stage->priv->stage_hints & CLUTTER_STAGE_NO_CLEAR_ON_PAINT) != 0;
 }
 
-gboolean
-_clutter_stage_get_pick_buffer_valid (ClutterStage *stage, ClutterPickMode mode)
-{
-  g_return_val_if_fail (CLUTTER_IS_STAGE (stage), FALSE);
-
-  if (stage->priv->pick_buffer_mode != mode)
-    return FALSE;
-
-  return stage->priv->have_valid_pick_buffer;
-}
-
-void
-_clutter_stage_set_pick_buffer_valid (ClutterStage   *stage,
-                                      gboolean        valid,
-                                      ClutterPickMode mode)
-{
-  g_return_if_fail (CLUTTER_IS_STAGE (stage));
-
-  stage->priv->have_valid_pick_buffer = !!valid;
-  stage->priv->pick_buffer_mode = mode;
-}
-
-void
-_clutter_stage_increment_picks_per_frame_counter (ClutterStage *stage)
-{
-  g_return_if_fail (CLUTTER_IS_STAGE (stage));
-
-  stage->priv->picks_per_frame++;
-}
-
-void
-_clutter_stage_reset_picks_per_frame_counter (ClutterStage *stage)
-{
-  g_return_if_fail (CLUTTER_IS_STAGE (stage));
-
-  stage->priv->picks_per_frame = 0;
-}
-
-guint
-_clutter_stage_get_picks_per_frame_counter (ClutterStage *stage)
-{
-  g_return_val_if_fail (CLUTTER_IS_STAGE (stage), 0);
-
-  return stage->priv->picks_per_frame;
-}
-
 ClutterPaintVolume *
 _clutter_stage_paint_volume_stack_allocate (ClutterStage *stage)
 {
@@ -3376,9 +3615,9 @@ _clutter_stage_queue_actor_redraw (ClutterStage *stage,
     }
 #endif /* CLUTTER_ENABLE_DEBUG */
 
-  /* We have an optimization in _clutter_do_pick to detect when the
-   * scene is static so we can cache a full, un-clipped pick buffer to
-   * avoid continuous pick renders.
+  /* We have an optimization in _clutter_stage_do_pick to detect when
+   * the scene is static so we can cache a full, un-clipped pick
+   * buffer to avoid continuous pick renders.
    *
    * Currently the assumption is that actors queue a redraw when some
    * state changes that affects painting *or* picking so we can use



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