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
This commit is contained in:
Georges Basile Stavracas Neto 2020-10-10 11:17:58 -03:00
parent 63d05565f6
commit d1d3ac6b20
4 changed files with 77 additions and 28 deletions

View File

@ -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;
}

View File

@ -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 */

View File

@ -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;
}
/**

View File

@ -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);