picking: Fix tracking of pick buffer validity

We have an optimization to track when there are multiple picks per
frames so we can do a full render of the pick buffer to reduce the
number of pick renders for a static scene.

There were two problems with how we were tracking this state though.
Firstly we were tracking this information in the ClutterMainContext, but
conceptually this doesn't really make sense because the pick buffer is
associated with a stage framebuffer and there can be multiple stages for
one context.  Secondly - since the change to how redraws are queued - we
weren't marking the pick buffer as invalid when a queuing a redraw, we
were only marking the buffer invalid when signaling/finishing the
queue-redraw process, which is now deferred until just before a paint.
This meant using clutter_stage_get_actor_at_pos after a scenegraph
change could give a wrong result if it just read from an existing (but
technically invalid) pick buffer.

This patch moves the state tracking to ClutterStage, and ensures the
buffer is invalidated in _clutter_stage_queue_actor_redraw.

http://bugzilla.clutter-project.org/show_bug.cgi?id=2283

Signed-off-by: Emmanuele Bassi <ebassi@linux.intel.com>
This commit is contained in:
Robert Bragg 2010-09-11 00:29:05 +01:00 committed by Emmanuele Bassi
parent 60c9dc25df
commit d7e86e2696
4 changed files with 59 additions and 25 deletions

View File

@ -1780,7 +1780,6 @@ clutter_actor_real_queue_redraw (ClutterActor *self,
ClutterActor *origin)
{
ClutterActor *parent;
ClutterMainContext *context;
CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
get_actor_debug_name (self),
@ -1798,17 +1797,6 @@ clutter_actor_real_queue_redraw (ClutterActor *self,
if (!CLUTTER_ACTOR_IS_VISIBLE (self))
return;
/* 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.
*
* 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.
*/
context = _clutter_context_get_default ();
context->have_complete_pick_buffer = FALSE;
/* Although we could determine here that a full stage redraw
* has already been queued and immediately bail out, we actually
* guarantee that we will propagate a queue-redraw signal to our

View File

@ -274,12 +274,8 @@ _clutter_do_redraw (ClutterStage *stage)
ctx = _clutter_context_get_default ();
/* We have an optimization to avoid pick renders while scene is static.
* This is implied by seeing multiple picks per frame so we have to
* reset a pick counter each frame and also invalidate any current pick
* buffer. */
ctx->picks_per_frame = 0;
ctx->have_complete_pick_buffer = FALSE;
_clutter_stage_set_pick_buffer_valid (stage, FALSE);
_clutter_stage_unset_pick_counter (stage);
/* Before we can paint, we have to be sure we have the latest layout */
_clutter_stage_maybe_relayout (CLUTTER_ACTOR (stage));
@ -601,7 +597,7 @@ _clutter_do_pick (ClutterStage *stage,
/* 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 (context->have_complete_pick_buffer)
if (_clutter_stage_get_pick_buffer_valid (stage))
{
CLUTTER_TIMER_START (_clutter_uprof_context, pick_read);
cogl_read_pixels (x, y, 1, 1,
@ -628,7 +624,7 @@ _clutter_do_pick (ClutterStage *stage,
goto result;
}
context->picks_per_frame++;
_clutter_stage_increment_pick_counter (stage);
_clutter_backend_ensure_context (context->backend, stage);
@ -638,7 +634,7 @@ _clutter_do_pick (ClutterStage *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 (context->picks_per_frame < 2)
if (_clutter_stage_get_pick_counter (stage) < 2)
{
if (G_LIKELY (!(clutter_pick_debug_flags &
CLUTTER_DEBUG_DUMP_PICK_BUFFERS)))
@ -680,7 +676,7 @@ _clutter_do_pick (ClutterStage *stage,
cogl_clip_pop ();
}
else
context->have_complete_pick_buffer = TRUE;
_clutter_stage_set_pick_buffer_valid (stage, TRUE);
/* Make sure Cogl flushes any batched geometry to the GPU driver */
cogl_flush ();

View File

@ -183,9 +183,6 @@ struct _ClutterMainContext
GList *repaint_funcs;
ClutterSettings *settings;
gint picks_per_frame;
gboolean have_complete_pick_buffer;
};
#define CLUTTER_CONTEXT() (_clutter_context_get_default ())
@ -279,6 +276,13 @@ 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);
gboolean _clutter_stage_get_pick_buffer_valid (ClutterStage *stage);
void _clutter_stage_increment_pick_counter (ClutterStage *stage);
void _clutter_stage_unset_pick_counter (ClutterStage *stage);
guint _clutter_stage_get_pick_counter (ClutterStage *stage);
/* vfuncs implemented by backend */
GType _clutter_backend_impl_get_type (void);

View File

@ -116,6 +116,8 @@ struct _ClutterStagePrivate
ClutterStageHint stage_hints;
gint picks_per_frame;
guint redraw_pending : 1;
guint is_fullscreen : 1;
guint is_cursor_visible : 1;
@ -126,6 +128,7 @@ struct _ClutterStagePrivate
guint min_size_changed : 1;
guint dirty_viewport : 1;
guint dirty_projection : 1;
guint have_valid_pick_buffer : 1;
};
enum
@ -734,6 +737,16 @@ clutter_stage_real_queue_redraw (ClutterActor *actor,
else
CLUTTER_CONTEXT ()->redraw_count += 1;
/* 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.
*
* 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);
/* If the backend can't do anything with redraw clips (e.g. it already knows
* it needs to redraw everything anyway) then don't spend time transforming
* any clip regions into stage coordinates... */
@ -2929,3 +2942,36 @@ 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)
{
return stage->priv->have_valid_pick_buffer;
}
void
_clutter_stage_set_pick_buffer_valid (ClutterStage *stage,
gboolean valid)
{
valid = !!valid;
stage->priv->have_valid_pick_buffer = valid;
}
void
_clutter_stage_increment_pick_counter (ClutterStage *stage)
{
stage->priv->picks_per_frame += 1;
}
void
_clutter_stage_unset_pick_counter (ClutterStage *stage)
{
stage->priv->picks_per_frame = 0;
}
guint
_clutter_stage_get_pick_counter (ClutterStage *stage)
{
return stage->priv->picks_per_frame;
}