[clutter/wip/clip-with-swap-buffers: 3/4] stage: add dedicated pixel pick buffer



commit 5c548ad9bd95bcec0c43bfe6c313b8f391ab2abd
Author: Robert Bragg <robert linux intel com>
Date:   Fri Apr 1 13:33:41 2011 +0100

    stage: add dedicated pixel pick buffer
    
    This gives each stage a dedicated 1 pixel framebuffer for handling
    picking when we are only reading back a single point under the cursor.
    
    Having a dedicated pick buffer means we can avoid damaging the contents
    of the back buffer used for painting so we can re-use the contents of
    old back buffers to reduce how much is drawn each frame.
    
    Note that we don't create a full stage size pick buffer because we want
    to avoid the large allocations of memory that would imply.
    
    Note when a clutter scene is static then we will still use the back
    buffer for picking so that we can do a full stage size pick render
    without requiring the allocation of a dedicated buffer.

 clutter/clutter-stage.c |   66 ++++++++++++++++++++++++++++++++--------------
 1 files changed, 46 insertions(+), 20 deletions(-)
---
diff --git a/clutter/clutter-stage.c b/clutter/clutter-stage.c
index bf55647..dd416e6 100644
--- a/clutter/clutter-stage.c
+++ b/clutter/clutter-stage.c
@@ -144,6 +144,7 @@ struct _ClutterStagePrivate
   GList              *pending_queue_redraws;
 
   ClutterPickMode     pick_buffer_mode;
+  CoglHandle          pixel_pick_buffer;
 
   GHashTable *devices;
 
@@ -1239,6 +1240,8 @@ _clutter_stage_do_pick (ClutterStage   *stage,
   GLboolean dither_was_on;
   ClutterActor *actor;
   gboolean is_clipped;
+  gint read_x;
+  gint read_y;
   CLUTTER_STATIC_COUNTER (do_pick_counter,
                           "_clutter_stage_do_pick counter",
                           "Increments for each full pick run",
@@ -1323,13 +1326,21 @@ _clutter_stage_do_pick (ClutterStage   *stage,
    * 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);
+      cogl_push_framebuffer (priv->pixel_pick_buffer);
+      cogl_set_viewport (priv->viewport[0] - x,
+                         priv->viewport[1] - y,
+                         priv->viewport[2],
+                         priv->viewport[3]);
+      read_x = 0;
+      read_y = 0;
       is_clipped = TRUE;
     }
   else
-    is_clipped = FALSE;
+    {
+      read_x = x;
+      read_y = y;
+      is_clipped = FALSE;
+    }
 
   CLUTTER_NOTE (PICK, "Performing %s pick at %i,%i",
                 is_clipped ? "clippped" : "full", x, y);
@@ -1356,21 +1367,6 @@ _clutter_stage_do_pick (ClutterStage   *stage,
   context->pick_mode = CLUTTER_PICK_NONE;
   CLUTTER_TIMER_STOP (_clutter_uprof_context, pick_paint);
 
-  /* Notify the backend that we have trashed the contents of
-   * the back buffer... */
-  _clutter_stage_window_dirty_back_buffer (priv->impl);
-
-  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
@@ -1379,7 +1375,7 @@ _clutter_stage_do_pick (ClutterStage   *stage,
      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 (read_x, read_y, 1, 1,
                     COGL_READ_PIXELS_COLOR_BUFFER,
                     COGL_PIXEL_FORMAT_RGBA_8888_PRE,
                     pixel);
@@ -1396,6 +1392,21 @@ _clutter_stage_do_pick (ClutterStage   *stage,
   if (dither_was_on)
     glEnable (GL_DITHER);
 
+  if (is_clipped)
+    {
+      cogl_pop_framebuffer ();
+
+      _clutter_stage_set_pick_buffer_valid (stage, FALSE, -1);
+    }
+  else
+    {
+      /* Notify the backend that we have trashed the contents of
+       * the back buffer... */
+      _clutter_stage_window_dirty_back_buffer (priv->impl);
+
+      _clutter_stage_set_pick_buffer_valid (stage, TRUE, mode);
+    }
+
   if (pixel[0] == 0xff && pixel[1] == 0xff && pixel[2] == 0xff)
     {
       actor = CLUTTER_ACTOR (stage);
@@ -1981,6 +1992,7 @@ clutter_stage_init (ClutterStage *self)
   ClutterStagePrivate *priv;
   ClutterBackend *backend;
   ClutterGeometry geom;
+  CoglHandle color_buffer;
 
   /* a stage is a top-level object */
   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IS_TOPLEVEL);
@@ -2061,6 +2073,16 @@ clutter_stage_init (ClutterStage *self)
     g_array_new (FALSE, FALSE, sizeof (ClutterPaintVolume));
 
   priv->devices = g_hash_table_new (NULL, NULL);
+
+  color_buffer = cogl_texture_new_with_size (1, 1,
+                                             COGL_TEXTURE_NONE,
+                                             COGL_PIXEL_FORMAT_RGB_888);
+
+  /* XXX: We are only using cogl_offscreen_new_to_texture for convenience
+   * and wont need to reference the underlying texture handle once we
+   * have the buffer. */
+  priv->pixel_pick_buffer = cogl_offscreen_new_to_texture (color_buffer);
+  cogl_handle_unref (color_buffer);
 }
 
 /**
@@ -3162,6 +3184,10 @@ _clutter_stage_maybe_setup_viewport (ClutterStage *stage)
     {
       cogl_set_projection_matrix (&priv->projection);
 
+      cogl_push_framebuffer (priv->pixel_pick_buffer);
+      cogl_set_projection_matrix (&priv->projection);
+      cogl_pop_framebuffer ();
+
       priv->dirty_projection = FALSE;
     }
 }



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