From d1d3ac6b2008b96e40ed559c0856cf817d820f11 Mon Sep 17 00:00:00 2001 From: Georges Basile Stavracas Neto Date: Sat, 10 Oct 2020 11:17:58 -0300 Subject: [PATCH] clutter/stage: Use multiple frusta depending on the redraw clip The redraw clip region may contain multiple clip rectangles. We currently only use the extents of this region, but having multiple frusta for each rectangle is a better alternative, and will allow us to remove the extra projection we currently do. Make the clip frustum an array, with multiple frusta. https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1489 --- clutter/clutter/clutter-actor.c | 32 +++++++++++---- .../clutter/clutter-paint-context-private.h | 12 +++--- clutter/clutter/clutter-paint-context.c | 20 ++++----- clutter/clutter/clutter-stage.c | 41 ++++++++++++++++--- 4 files changed, 77 insertions(+), 28 deletions(-) diff --git a/clutter/clutter/clutter-actor.c b/clutter/clutter/clutter-actor.c index 911f5dbe4..6ac478d7a 100644 --- a/clutter/clutter/clutter-actor.c +++ b/clutter/clutter/clutter-actor.c @@ -3449,7 +3449,9 @@ cull_actor (ClutterActor *self, ClutterCullResult *result_out) { ClutterActorPrivate *priv = self->priv; - const graphene_frustum_t *clip_frustum; + const GArray *clip_frusta; + ClutterCullResult result; + int i; if (!priv->last_paint_volume_valid) { @@ -3470,12 +3472,26 @@ cull_actor (ClutterActor *self, return FALSE; } - clip_frustum = clutter_paint_context_get_clip_frustum (paint_context); + clip_frusta = clutter_paint_context_get_clip_frusta (paint_context); + if (!clip_frusta) + { + *result_out = CLUTTER_CULL_RESULT_IN; + return TRUE; + } - *result_out = - _clutter_paint_volume_cull (&priv->last_paint_volume, clip_frustum); + for (i = 0; i < clip_frusta->len; i++) + { + const graphene_frustum_t *clip_frustum = + &g_array_index (clip_frusta, graphene_frustum_t, i); - if (*result_out != CLUTTER_CULL_RESULT_OUT) + result = _clutter_paint_volume_cull (&priv->last_paint_volume, + clip_frustum); + + if (result != CLUTTER_CULL_RESULT_OUT) + break; + } + + if (result != CLUTTER_CULL_RESULT_OUT) { const cairo_region_t *redraw_clip; @@ -3504,15 +3520,17 @@ cull_actor (ClutterActor *self, { case CAIRO_REGION_OVERLAP_IN: case CAIRO_REGION_OVERLAP_PART: - *result_out = CLUTTER_CULL_RESULT_IN; + result = CLUTTER_CULL_RESULT_IN; break; case CAIRO_REGION_OVERLAP_OUT: - *result_out = CLUTTER_CULL_RESULT_OUT; + result = CLUTTER_CULL_RESULT_OUT; break; } } } + *result_out = result; + return TRUE; } diff --git a/clutter/clutter/clutter-paint-context-private.h b/clutter/clutter/clutter-paint-context-private.h index ff26edf21..25592a6fe 100644 --- a/clutter/clutter/clutter-paint-context-private.h +++ b/clutter/clutter/clutter-paint-context-private.h @@ -21,16 +21,16 @@ #include "clutter-paint-context.h" ClutterPaintContext * -clutter_paint_context_new_for_view (ClutterStageView *view, - const cairo_region_t *redraw_clip, - const graphene_frustum_t *clip_frustum, - ClutterPaintFlag paint_flags); +clutter_paint_context_new_for_view (ClutterStageView *view, + const cairo_region_t *redraw_clip, + GArray *clip_frusta, + ClutterPaintFlag paint_flags); gboolean clutter_paint_context_is_drawing_off_stage (ClutterPaintContext *paint_context); CoglFramebuffer * clutter_paint_context_get_base_framebuffer (ClutterPaintContext *paint_context); -const graphene_frustum_t * -clutter_paint_context_get_clip_frustum (ClutterPaintContext *paint_context); +const GArray * +clutter_paint_context_get_clip_frusta (ClutterPaintContext *paint_context); #endif /* CLUTTER_PAINT_CONTEXT_PRIVATE_H */ diff --git a/clutter/clutter/clutter-paint-context.c b/clutter/clutter/clutter-paint-context.c index d83dec157..b56d92aa7 100644 --- a/clutter/clutter/clutter-paint-context.c +++ b/clutter/clutter/clutter-paint-context.c @@ -30,7 +30,7 @@ struct _ClutterPaintContext ClutterStageView *view; cairo_region_t *redraw_clip; - graphene_frustum_t clip_frustum; + GArray *clip_frusta; }; G_DEFINE_BOXED_TYPE (ClutterPaintContext, clutter_paint_context, @@ -38,10 +38,10 @@ G_DEFINE_BOXED_TYPE (ClutterPaintContext, clutter_paint_context, clutter_paint_context_unref) ClutterPaintContext * -clutter_paint_context_new_for_view (ClutterStageView *view, - const cairo_region_t *redraw_clip, - const graphene_frustum_t *clip_frustum, - ClutterPaintFlag paint_flags) +clutter_paint_context_new_for_view (ClutterStageView *view, + const cairo_region_t *redraw_clip, + GArray *clip_frusta, + ClutterPaintFlag paint_flags) { ClutterPaintContext *paint_context; CoglFramebuffer *framebuffer; @@ -50,9 +50,8 @@ clutter_paint_context_new_for_view (ClutterStageView *view, g_ref_count_init (&paint_context->ref_count); paint_context->view = view; paint_context->redraw_clip = cairo_region_copy (redraw_clip); + paint_context->clip_frusta = g_array_ref (clip_frusta); paint_context->paint_flags = paint_flags; - graphene_frustum_init_from_frustum (&paint_context->clip_frustum, - clip_frustum); framebuffer = clutter_stage_view_get_framebuffer (view); clutter_paint_context_push_framebuffer (paint_context, framebuffer); @@ -93,6 +92,7 @@ clutter_paint_context_dispose (ClutterPaintContext *paint_context) g_list_free_full (paint_context->framebuffers, g_object_unref); paint_context->framebuffers = NULL; g_clear_pointer (&paint_context->redraw_clip, cairo_region_destroy); + g_clear_pointer (&paint_context->clip_frusta, g_array_unref); } void @@ -137,10 +137,10 @@ clutter_paint_context_get_redraw_clip (ClutterPaintContext *paint_context) return paint_context->redraw_clip; } -const graphene_frustum_t * -clutter_paint_context_get_clip_frustum (ClutterPaintContext *paint_context) +const GArray * +clutter_paint_context_get_clip_frusta (ClutterPaintContext *paint_context) { - return &paint_context->clip_frustum; + return paint_context->clip_frusta; } /** diff --git a/clutter/clutter/clutter-stage.c b/clutter/clutter/clutter-stage.c index ab1877f1d..9726ba0ba 100644 --- a/clutter/clutter/clutter-stage.c +++ b/clutter/clutter/clutter-stage.c @@ -77,6 +77,8 @@ #include "cogl/cogl.h" +#define MAX_FRUSTA 64 + struct _ClutterStageQueueRedrawEntry { ClutterActor *actor; @@ -814,8 +816,6 @@ setup_view_for_paint (ClutterStage *stage, &priv->inverse_projection, &priv->perspective, out_frustum); - - _clutter_stage_paint_volume_stack_free_all (stage); } static void @@ -826,7 +826,9 @@ clutter_stage_do_paint_view (ClutterStage *stage, ClutterStagePrivate *priv = stage->priv; ClutterPaintContext *paint_context; cairo_rectangle_int_t clip_rect; + g_autoptr (GArray) clip_frusta = NULL; graphene_frustum_t clip_frustum; + int n_rectangles; /* Any mode of painting/picking invalidates the pick cache, unless we're * in the middle of building it. So we reset the cached flag but don't @@ -834,12 +836,41 @@ clutter_stage_do_paint_view (ClutterStage *stage, */ priv->cached_pick_mode = CLUTTER_PICK_NONE; - cairo_region_get_extents (redraw_clip, &clip_rect); - setup_view_for_paint (stage, view, &clip_rect, &clip_frustum); + n_rectangles = redraw_clip ? cairo_region_num_rectangles (redraw_clip) : 0; + if (redraw_clip && n_rectangles < MAX_FRUSTA) + { + int i; + + clip_frusta = g_array_sized_new (FALSE, FALSE, + sizeof (graphene_frustum_t), + n_rectangles); + + for (i = 0; i < n_rectangles; i++) + { + cairo_region_get_rectangle (redraw_clip, i, &clip_rect); + setup_view_for_paint (stage, view, &clip_rect, &clip_frustum); + g_array_append_val (clip_frusta, clip_frustum); + } + } + else + { + clip_frusta = g_array_sized_new (FALSE, FALSE, + sizeof (graphene_frustum_t), + 1); + if (redraw_clip) + cairo_region_get_extents (redraw_clip, &clip_rect); + else + clutter_stage_view_get_layout (view, &clip_rect); + + setup_view_for_paint (stage, view, &clip_rect, &clip_frustum); + g_array_append_val (clip_frusta, clip_frustum); + } + + _clutter_stage_paint_volume_stack_free_all (stage); paint_context = clutter_paint_context_new_for_view (view, redraw_clip, - &clip_frustum, + clip_frusta, CLUTTER_PAINT_FLAG_NONE); clutter_actor_paint (CLUTTER_ACTOR (stage), paint_context);