Merge branch 'nonoverlapping-containers' into 'main'

gsk/gl: Avoid offscreening in more cases

See merge request GNOME/gtk!4619
This commit is contained in:
Matthias Clasen 2022-04-07 14:32:53 +00:00
commit 8c548d5579
4 changed files with 69 additions and 60 deletions

View File

@ -2860,58 +2860,6 @@ gsk_gl_render_job_visit_cross_fade_node (GskGLRenderJob *job,
gsk_gl_render_job_end_draw (job);
}
static gboolean
is_non_branching (const GskRenderNode *node)
{
switch ((int)gsk_render_node_get_node_type (node))
{
case GSK_COLOR_NODE:
case GSK_LINEAR_GRADIENT_NODE:
case GSK_REPEATING_LINEAR_GRADIENT_NODE:
case GSK_RADIAL_GRADIENT_NODE:
case GSK_REPEATING_RADIAL_GRADIENT_NODE:
case GSK_CONIC_GRADIENT_NODE:
case GSK_BORDER_NODE:
case GSK_TEXTURE_NODE:
case GSK_INSET_SHADOW_NODE:
case GSK_OUTSET_SHADOW_NODE:
case GSK_TEXT_NODE:
case GSK_CAIRO_NODE:
return TRUE;
case GSK_TRANSFORM_NODE:
return is_non_branching (gsk_transform_node_get_child (node));
case GSK_OPACITY_NODE:
return is_non_branching (gsk_opacity_node_get_child (node));
case GSK_COLOR_MATRIX_NODE:
return is_non_branching (gsk_color_matrix_node_get_child (node));
case GSK_CLIP_NODE:
return is_non_branching (gsk_clip_node_get_child (node));
case GSK_ROUNDED_CLIP_NODE:
return is_non_branching (gsk_rounded_clip_node_get_child (node));
case GSK_SHADOW_NODE:
return is_non_branching (gsk_shadow_node_get_child (node));
case GSK_BLUR_NODE:
return is_non_branching (gsk_shadow_node_get_child (node));
case GSK_DEBUG_NODE:
return is_non_branching (gsk_debug_node_get_child (node));
case GSK_CONTAINER_NODE:
return gsk_container_node_get_n_children (node) == 1 &&
is_non_branching (gsk_container_node_get_child (node, 0));
default:
return FALSE;
}
}
static inline void
gsk_gl_render_job_visit_opacity_node (GskGLRenderJob *job,
const GskRenderNode *node)
@ -2924,11 +2872,7 @@ gsk_gl_render_job_visit_opacity_node (GskGLRenderJob *job,
{
float prev_alpha = gsk_gl_render_job_set_alpha (job, new_alpha);
/* Handle a few easy cases without offscreen. We bail out
* as soon as we see nodes with multiple children - in theory,
* we would only need offscreens for overlapping children.
*/
if (is_non_branching (child))
if (!gsk_render_node_use_offscreen_for_opacity (child))
{
gsk_gl_render_job_visit_node (job, child);
gsk_gl_render_job_set_alpha (job, prev_alpha);

View File

@ -58,14 +58,14 @@ value_render_node_init (GValue *value)
{
value->data[0].v_pointer = NULL;
}
static void
value_render_node_free_value (GValue *value)
{
if (value->data[0].v_pointer != NULL)
gsk_render_node_unref (value->data[0].v_pointer);
}
static void
value_render_node_copy_value (const GValue *src,
GValue *dst)
@ -75,7 +75,7 @@ value_render_node_copy_value (const GValue *src,
else
dst->data[0].v_pointer = NULL;
}
static gpointer
value_render_node_peek_pointer (const GValue *value)
{
@ -738,3 +738,16 @@ gsk_render_node_prefers_high_depth (const GskRenderNode *node)
{
return node->prefers_high_depth;
}
/* Whether we need an offscreen to handle opacity correctly for this node.
* We don't if there is only one drawing node inside (could be child
* node, or grandchild, or...).
*
* For containers with multiple children, we can avoid the offscreen if
* the children are known not to overlap.
*/
gboolean
gsk_render_node_use_offscreen_for_opacity (const GskRenderNode *node)
{
return node->offscreen_for_opacity;
}

View File

@ -139,6 +139,7 @@ gsk_color_node_new (const GdkRGBA *rgba,
self = gsk_render_node_alloc (GSK_COLOR_NODE);
node = (GskRenderNode *) self;
node->offscreen_for_opacity = FALSE;
self->color = *rgba;
graphene_rect_init_from_rect (&node->bounds, bounds);
@ -284,6 +285,7 @@ gsk_linear_gradient_node_new (const graphene_rect_t *bounds,
self = gsk_render_node_alloc (GSK_LINEAR_GRADIENT_NODE);
node = (GskRenderNode *) self;
node->offscreen_for_opacity = FALSE;
graphene_rect_init_from_rect (&node->bounds, bounds);
graphene_point_init_from_point (&self->start, start);
@ -336,6 +338,7 @@ gsk_repeating_linear_gradient_node_new (const graphene_rect_t *bounds,
self = gsk_render_node_alloc (GSK_REPEATING_LINEAR_GRADIENT_NODE);
node = (GskRenderNode *) self;
node->offscreen_for_opacity = FALSE;
graphene_rect_init_from_rect (&node->bounds, bounds);
graphene_point_init_from_point (&self->start, start);
@ -584,6 +587,7 @@ gsk_radial_gradient_node_new (const graphene_rect_t *bounds,
self = gsk_render_node_alloc (GSK_RADIAL_GRADIENT_NODE);
node = (GskRenderNode *) self;
node->offscreen_for_opacity = FALSE;
graphene_rect_init_from_rect (&node->bounds, bounds);
graphene_point_init_from_point (&self->center, center);
@ -652,6 +656,7 @@ gsk_repeating_radial_gradient_node_new (const graphene_rect_t *bounds,
self = gsk_render_node_alloc (GSK_REPEATING_RADIAL_GRADIENT_NODE);
node = (GskRenderNode *) self;
node->offscreen_for_opacity = FALSE;
graphene_rect_init_from_rect (&node->bounds, bounds);
graphene_point_init_from_point (&self->center, center);
@ -1030,6 +1035,7 @@ gsk_conic_gradient_node_new (const graphene_rect_t *bounds,
self = gsk_render_node_alloc (GSK_CONIC_GRADIENT_NODE);
node = (GskRenderNode *) self;
node->offscreen_for_opacity = FALSE;
graphene_rect_init_from_rect (&node->bounds, bounds);
graphene_point_init_from_point (&self->center, center);
@ -1413,6 +1419,7 @@ gsk_border_node_new (const GskRoundedRect *outline,
self = gsk_render_node_alloc (GSK_BORDER_NODE);
node = (GskRenderNode *) self;
node->offscreen_for_opacity = FALSE;
gsk_rounded_rect_init_copy (&self->outline, outline);
memcpy (self->border_width, border_width, sizeof (self->border_width));
@ -1559,6 +1566,7 @@ gsk_texture_node_new (GdkTexture *texture,
self = gsk_render_node_alloc (GSK_TEXTURE_NODE);
node = (GskRenderNode *) self;
node->offscreen_for_opacity = FALSE;
self->texture = g_object_ref (texture);
graphene_rect_init_from_rect (&node->bounds, bounds);
@ -2014,6 +2022,7 @@ gsk_inset_shadow_node_new (const GskRoundedRect *outline,
self = gsk_render_node_alloc (GSK_INSET_SHADOW_NODE);
node = (GskRenderNode *) self;
node->offscreen_for_opacity = FALSE;
gsk_rounded_rect_init_copy (&self->outline, outline);
self->color = *color;
@ -2313,6 +2322,7 @@ gsk_outset_shadow_node_new (const GskRoundedRect *outline,
self = gsk_render_node_alloc (GSK_OUTSET_SHADOW_NODE);
node = (GskRenderNode *) self;
node->offscreen_for_opacity = FALSE;
gsk_rounded_rect_init_copy (&self->outline, outline);
self->color = *color;
@ -2506,6 +2516,7 @@ gsk_cairo_node_new (const graphene_rect_t *bounds)
self = gsk_render_node_alloc (GSK_CAIRO_NODE);
node = (GskRenderNode *) self;
node->offscreen_for_opacity = FALSE;
graphene_rect_init_from_rect (&node->bounds, bounds);
@ -2576,6 +2587,7 @@ struct _GskContainerNode
{
GskRenderNode render_node;
gboolean disjoint;
guint n_children;
GskRenderNode **children;
};
@ -2724,6 +2736,7 @@ gsk_container_node_new (GskRenderNode **children,
self = gsk_render_node_alloc (GSK_CONTAINER_NODE);
node = (GskRenderNode *) self;
self->disjoint = TRUE;
self->n_children = n_children;
if (n_children == 0)
@ -2743,11 +2756,14 @@ gsk_container_node_new (GskRenderNode **children,
for (guint i = 1; i < n_children; i++)
{
self->children[i] = gsk_render_node_ref (children[i]);
self->disjoint &= !graphene_rect_intersection (&bounds, &(children[i]->bounds), NULL);
graphene_rect_union (&bounds, &(children[i]->bounds), &bounds);
node->prefers_high_depth |= gsk_render_node_prefers_high_depth (children[i]);
node->offscreen_for_opacity |= children[i]->offscreen_for_opacity;
}
graphene_rect_init_from_rect (&node->bounds, &bounds);
node->offscreen_for_opacity |= !self->disjoint;
}
return node;
@ -2801,6 +2817,24 @@ gsk_container_node_get_children (const GskRenderNode *node,
return self->children;
}
/*< private>
* gsk_container_node_is_disjoint:
* @node: a container `GskRenderNode`
*
* Returns `TRUE` if it is known that the child nodes are not
* overlapping. There is no guarantee that they do overlap
* if this function return FALSE.
*
* Returns: `TRUE` if children don't overlap
*/
gboolean
gsk_container_node_is_disjoint (const GskRenderNode *node)
{
const GskContainerNode *self = (const GskContainerNode *) node;
return self->disjoint;
}
/*** GSK_TRANSFORM_NODE ***/
/**
@ -2962,6 +2996,7 @@ gsk_transform_node_new (GskRenderNode *child,
self = gsk_render_node_alloc (GSK_TRANSFORM_NODE);
node = (GskRenderNode *) self;
node->offscreen_for_opacity = child->offscreen_for_opacity;
self->child = gsk_render_node_ref (child);
self->transform = gsk_transform_ref (transform);
@ -3106,6 +3141,7 @@ gsk_opacity_node_new (GskRenderNode *child,
self = gsk_render_node_alloc (GSK_OPACITY_NODE);
node = (GskRenderNode *) self;
node->offscreen_for_opacity = child->offscreen_for_opacity;
self->child = gsk_render_node_ref (child);
self->opacity = CLAMP (opacity, 0.0, 1.0);
@ -3309,6 +3345,7 @@ gsk_color_matrix_node_new (GskRenderNode *child,
self = gsk_render_node_alloc (GSK_COLOR_MATRIX_NODE);
node = (GskRenderNode *) self;
node->offscreen_for_opacity = child->offscreen_for_opacity;
self->child = gsk_render_node_ref (child);
graphene_matrix_init_from_matrix (&self->color_matrix, color_matrix);
@ -3457,6 +3494,7 @@ gsk_repeat_node_new (const graphene_rect_t *bounds,
self = gsk_render_node_alloc (GSK_REPEAT_NODE);
node = (GskRenderNode *) self;
node->offscreen_for_opacity = TRUE;
graphene_rect_init_from_rect (&node->bounds, bounds);
@ -3594,6 +3632,7 @@ gsk_clip_node_new (GskRenderNode *child,
self = gsk_render_node_alloc (GSK_CLIP_NODE);
node = (GskRenderNode *) self;
node->offscreen_for_opacity = child->offscreen_for_opacity;
self->child = gsk_render_node_ref (child);
graphene_rect_normalize_r (clip, &self->clip);
@ -3727,6 +3766,7 @@ gsk_rounded_clip_node_new (GskRenderNode *child,
self = gsk_render_node_alloc (GSK_ROUNDED_CLIP_NODE);
node = (GskRenderNode *) self;
node->offscreen_for_opacity = child->offscreen_for_opacity;
self->child = gsk_render_node_ref (child);
gsk_rounded_rect_init_copy (&self->clip, clip);
@ -3946,6 +3986,7 @@ gsk_shadow_node_new (GskRenderNode *child,
self = gsk_render_node_alloc (GSK_SHADOW_NODE);
node = (GskRenderNode *) self;
node->offscreen_for_opacity = child->offscreen_for_opacity;
self->child = gsk_render_node_ref (child);
self->n_shadows = n_shadows;
@ -4142,6 +4183,7 @@ gsk_blend_node_new (GskRenderNode *bottom,
self = gsk_render_node_alloc (GSK_BLEND_NODE);
node = (GskRenderNode *) self;
node->offscreen_for_opacity = TRUE;
self->bottom = gsk_render_node_ref (bottom);
self->top = gsk_render_node_ref (top);
@ -4292,6 +4334,7 @@ gsk_cross_fade_node_new (GskRenderNode *start,
self = gsk_render_node_alloc (GSK_CROSS_FADE_NODE);
node = (GskRenderNode *) self;
node->offscreen_for_opacity = TRUE;
self->start = gsk_render_node_ref (start);
self->end = gsk_render_node_ref (end);
@ -4478,6 +4521,7 @@ gsk_text_node_new (PangoFont *font,
self = gsk_render_node_alloc (GSK_TEXT_NODE);
node = (GskRenderNode *) self;
node->offscreen_for_opacity = FALSE;
self->font = g_object_ref (font);
self->color = *color;
@ -4884,6 +4928,7 @@ gsk_blur_node_new (GskRenderNode *child,
self = gsk_render_node_alloc (GSK_BLUR_NODE);
node = (GskRenderNode *) self;
node->offscreen_for_opacity = child->offscreen_for_opacity;
self->child = gsk_render_node_ref (child);
self->radius = radius;
@ -5013,6 +5058,7 @@ gsk_debug_node_new (GskRenderNode *child,
self = gsk_render_node_alloc (GSK_DEBUG_NODE);
node = (GskRenderNode *) self;
node->offscreen_for_opacity = child->offscreen_for_opacity;
self->child = gsk_render_node_ref (child);
self->message = message;
@ -5174,6 +5220,7 @@ gsk_gl_shader_node_new (GskGLShader *shader,
self = gsk_render_node_alloc (GSK_GL_SHADER_NODE);
node = (GskRenderNode *) self;
node->offscreen_for_opacity = TRUE;
graphene_rect_init_from_rect (&node->bounds, bounds);
self->shader = g_object_ref (shader);

View File

@ -29,6 +29,7 @@ struct _GskRenderNode
graphene_rect_t bounds;
guint prefers_high_depth : 1;
guint offscreen_for_opacity : 1;
};
struct _GskRenderNodeClass
@ -113,6 +114,10 @@ void gsk_transform_node_get_translate (const GskRenderNode *no
float *dy);
gboolean gsk_render_node_prefers_high_depth (const GskRenderNode *node);
gboolean gsk_container_node_is_disjoint (const GskRenderNode *node);
gboolean gsk_render_node_use_offscreen_for_opacity (const GskRenderNode *node);
G_END_DECLS