From d7e86e26960f4cb2f5f0600357f5df89bd1c46c1 Mon Sep 17 00:00:00 2001 From: Robert Bragg Date: Sat, 11 Sep 2010 00:29:05 +0100 Subject: [PATCH] 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 --- clutter/clutter-actor.c | 12 ---------- clutter/clutter-main.c | 16 +++++--------- clutter/clutter-private.h | 10 ++++++--- clutter/clutter-stage.c | 46 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 59 insertions(+), 25 deletions(-) diff --git a/clutter/clutter-actor.c b/clutter/clutter-actor.c index 944c0a465..e994af860 100644 --- a/clutter/clutter-actor.c +++ b/clutter/clutter-actor.c @@ -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 diff --git a/clutter/clutter-main.c b/clutter/clutter-main.c index 0768833d6..7795f75b3 100644 --- a/clutter/clutter-main.c +++ b/clutter/clutter-main.c @@ -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 (); diff --git a/clutter/clutter-private.h b/clutter/clutter-private.h index 7c460d393..30e4f75a9 100644 --- a/clutter/clutter-private.h +++ b/clutter/clutter-private.h @@ -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); diff --git a/clutter/clutter-stage.c b/clutter/clutter-stage.c index 7b7c8c867..6c3dd2928 100644 --- a/clutter/clutter-stage.c +++ b/clutter/clutter-stage.c @@ -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; +}