stage: Remove the pick buffer caching

Since the journal is flushed on context switches, trying to use a cached
buffer means that we will use glReadPixels when picking, which isn't what
we want. Instead, always use a clipped draw, and remove the logic for
caching the pick buffer.

https://bugzilla.gnome.org/show_bug.cgi?id=712563
This commit is contained in:
Jasper St. Pierre 2013-11-18 00:18:32 -05:00
parent 9082ccc30b
commit a427c120c2

View File

@ -125,16 +125,12 @@ struct _ClutterStagePrivate
ClutterStageHint stage_hints; ClutterStageHint stage_hints;
gint picks_per_frame;
GArray *paint_volume_stack; GArray *paint_volume_stack;
ClutterPlane current_clip_planes[4]; ClutterPlane current_clip_planes[4];
GList *pending_queue_redraws; GList *pending_queue_redraws;
ClutterPickMode pick_buffer_mode;
CoglFramebuffer *active_framebuffer; CoglFramebuffer *active_framebuffer;
gint sync_delay; gint sync_delay;
@ -165,7 +161,6 @@ struct _ClutterStagePrivate
guint min_size_changed : 1; guint min_size_changed : 1;
guint dirty_viewport : 1; guint dirty_viewport : 1;
guint dirty_projection : 1; guint dirty_projection : 1;
guint have_valid_pick_buffer : 1;
guint accept_focus : 1; guint accept_focus : 1;
guint motion_events_enabled : 1; guint motion_events_enabled : 1;
guint has_custom_perspective : 1; guint has_custom_perspective : 1;
@ -1146,28 +1141,6 @@ _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 static void
clutter_stage_do_redraw (ClutterStage *stage) clutter_stage_do_redraw (ClutterStage *stage)
{ {
@ -1195,9 +1168,6 @@ clutter_stage_do_redraw (ClutterStage *stage)
_clutter_actor_get_debug_name (actor), _clutter_actor_get_debug_name (actor),
stage); stage);
_clutter_stage_set_pick_buffer_valid (stage, FALSE, -1);
priv->picks_per_frame = 0;
_clutter_backend_ensure_context (backend, stage); _clutter_backend_ensure_context (backend, stage);
if (_clutter_context_get_show_fps ()) if (_clutter_context_get_show_fps ())
@ -1464,7 +1434,8 @@ _clutter_stage_do_pick (ClutterStage *stage,
gboolean dither_enabled_save; gboolean dither_enabled_save;
CoglFramebuffer *fb; CoglFramebuffer *fb;
ClutterActor *actor; ClutterActor *actor;
gboolean is_clipped; gint dirty_x;
gint dirty_y;
gint read_x; gint read_x;
gint read_y; gint read_y;
int window_scale; int window_scale;
@ -1519,64 +1490,25 @@ _clutter_stage_do_pick (ClutterStage *stage,
clutter_stage_ensure_current (stage); clutter_stage_ensure_current (stage);
window_scale = _clutter_stage_window_get_scale_factor (priv->impl); window_scale = _clutter_stage_window_get_scale_factor (priv->impl);
/* 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 * window_scale,
y * window_scale,
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);
goto check_pixel;
}
priv->picks_per_frame++;
_clutter_backend_ensure_context (context->backend, stage); _clutter_backend_ensure_context (context->backend, stage);
/* needed for when a context switch happens */ /* needed for when a context switch happens */
_clutter_stage_maybe_setup_viewport (stage); _clutter_stage_maybe_setup_viewport (stage);
/* If we are seeing multiple picks per frame that means the scene is static _clutter_stage_window_get_dirty_pixel (priv->impl, &dirty_x, &dirty_y);
* 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)
{
gint dirty_x;
gint dirty_y;
_clutter_stage_window_get_dirty_pixel (priv->impl, &dirty_x, &dirty_y); if (G_LIKELY (!(clutter_pick_debug_flags & CLUTTER_DEBUG_DUMP_PICK_BUFFERS)))
cogl_clip_push_window_rectangle (dirty_x * window_scale, dirty_y * window_scale, 1, 1);
if (G_LIKELY (!(clutter_pick_debug_flags & CLUTTER_DEBUG_DUMP_PICK_BUFFERS))) cogl_set_viewport (priv->viewport[0] * window_scale - x * window_scale + dirty_x * window_scale,
cogl_clip_push_window_rectangle (dirty_x * window_scale, dirty_y * window_scale, 1, 1); priv->viewport[1] * window_scale - y * window_scale + dirty_y * window_scale,
priv->viewport[2] * window_scale,
priv->viewport[3] * window_scale);
cogl_set_viewport (priv->viewport[0] * window_scale - x * window_scale + dirty_x * window_scale, read_x = dirty_x * window_scale;
priv->viewport[1] * window_scale - y * window_scale + dirty_y * window_scale, read_y = dirty_y * window_scale;
priv->viewport[2] * window_scale,
priv->viewport[3] * window_scale);
read_x = dirty_x * window_scale; CLUTTER_NOTE (PICK, "Performing pick at %i,%i", x, y);
read_y = dirty_y * window_scale;
is_clipped = TRUE;
}
else
{
read_x = x * window_scale;
read_y = y * window_scale;
is_clipped = FALSE;
}
CLUTTER_NOTE (PICK, "Performing %s pick at %i,%i",
is_clipped ? "clipped" : "full", x, y);
cogl_color_init_from_4ub (&stage_pick_id, 255, 255, 255, 255); cogl_color_init_from_4ub (&stage_pick_id, 255, 255, 255, 255);
CLUTTER_TIMER_START (_clutter_uprof_context, pick_clear); CLUTTER_TIMER_START (_clutter_uprof_context, pick_clear);
@ -1630,25 +1562,11 @@ _clutter_stage_do_pick (ClutterStage *stage,
/* Restore whether GL_DITHER was enabled */ /* Restore whether GL_DITHER was enabled */
cogl_framebuffer_set_dither_enabled (fb, dither_enabled_save); cogl_framebuffer_set_dither_enabled (fb, dither_enabled_save);
if (is_clipped) if (G_LIKELY (!(clutter_pick_debug_flags & CLUTTER_DEBUG_DUMP_PICK_BUFFERS)))
{ cogl_clip_pop ();
if (G_LIKELY (!(clutter_pick_debug_flags & CLUTTER_DEBUG_DUMP_PICK_BUFFERS)))
cogl_clip_pop ();
_clutter_stage_dirty_viewport (stage); _clutter_stage_dirty_viewport (stage);
_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);
}
check_pixel:
if (pixel[0] == 0xff && pixel[1] == 0xff && pixel[2] == 0xff) if (pixel[0] == 0xff && pixel[1] == 0xff && pixel[2] == 0xff)
{ {
actor = CLUTTER_ACTOR (stage); actor = CLUTTER_ACTOR (stage);
@ -2389,9 +2307,6 @@ clutter_stage_init (ClutterStage *self)
geom.width, geom.width,
geom.height); geom.height);
_clutter_stage_set_pick_buffer_valid (self, FALSE, CLUTTER_PICK_ALL);
priv->picks_per_frame = 0;
priv->paint_volume_stack = priv->paint_volume_stack =
g_array_new (FALSE, FALSE, sizeof (ClutterPaintVolume)); g_array_new (FALSE, FALSE, sizeof (ClutterPaintVolume));
@ -4139,16 +4054,6 @@ _clutter_stage_queue_actor_redraw (ClutterStage *stage,
} }
#endif /* CLUTTER_ENABLE_DEBUG */ #endif /* CLUTTER_ENABLE_DEBUG */
/* 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
* this point to invalidate any currently cached pick buffer.
*/
_clutter_stage_set_pick_buffer_valid (stage, FALSE, -1);
if (entry) if (entry)
{ {
/* Ignore all requests to queue a redraw for an actor if a full /* Ignore all requests to queue a redraw for an actor if a full