mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-12-26 13:41:07 +00:00
broadway: Prune fully clipped render nodes
If some node is fully outside the clip region we don't send it to the daemon. This helps a lot in how much data we send for scrolling viewports. However, sending partial trees makes node reuse a bit more tricky. We can't save for reuse any node that could possibly clip different depending on the clip region, as that could be different next frame. So, unless the node is fully contained in the current clip (and we thus know it is not parial) we don't allow reusing that next frame. This fixes #3086
This commit is contained in:
parent
4b1ea7c4a1
commit
d57e6b754f
@ -8,7 +8,7 @@ typedef struct {
|
||||
gint32 width, height;
|
||||
} BroadwayRect;
|
||||
|
||||
typedef enum { /* Sync changes with broadway.js */
|
||||
typedef enum { /* Sync changes with broadway.js and node_type_is_container() */
|
||||
BROADWAY_NODE_TEXTURE = 0,
|
||||
BROADWAY_NODE_CONTAINER = 1,
|
||||
BROADWAY_NODE_COLOR = 2,
|
||||
|
@ -90,6 +90,23 @@ add_uint32 (GArray *nodes, guint32 v)
|
||||
g_array_append_val (nodes, v);
|
||||
}
|
||||
|
||||
static guint
|
||||
add_uint32_placeholder (GArray *nodes)
|
||||
{
|
||||
guint pos = nodes->len;
|
||||
guint32 v = 0;
|
||||
|
||||
g_array_append_val (nodes, v);
|
||||
return pos;
|
||||
}
|
||||
|
||||
static void
|
||||
set_uint32_at (GArray *nodes, guint index, guint32 v)
|
||||
{
|
||||
g_array_index (nodes, guint32, index) = v;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
add_float (GArray *nodes, float f)
|
||||
{
|
||||
@ -212,11 +229,10 @@ collect_reused_node (GskRenderer *renderer,
|
||||
|
||||
if (self->last_node_lookup &&
|
||||
(old_id = GPOINTER_TO_INT(g_hash_table_lookup (self->last_node_lookup, node))) != 0)
|
||||
{
|
||||
g_hash_table_insert (self->node_lookup, node, GINT_TO_POINTER (old_id));
|
||||
|
||||
collect_reused_child_nodes (renderer, node);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
@ -298,10 +314,46 @@ collect_reused_child_nodes (GskRenderer *renderer,
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
node_is_visible (GskRenderNode *node,
|
||||
graphene_rect_t *clip_bounds)
|
||||
{
|
||||
if (clip_bounds == NULL ||
|
||||
graphene_rect_intersection (clip_bounds, &node->bounds, NULL))
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
node_is_fully_visible (GskRenderNode *node,
|
||||
graphene_rect_t *clip_bounds)
|
||||
{
|
||||
if (clip_bounds == NULL ||
|
||||
graphene_rect_contains_rect (clip_bounds, &node->bounds))
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
node_type_is_container (BroadwayNodeType type)
|
||||
{
|
||||
return
|
||||
type == BROADWAY_NODE_SHADOW ||
|
||||
type == BROADWAY_NODE_OPACITY ||
|
||||
type == BROADWAY_NODE_ROUNDED_CLIP ||
|
||||
type == BROADWAY_NODE_CLIP ||
|
||||
type == BROADWAY_NODE_TRANSFORM ||
|
||||
type == BROADWAY_NODE_DEBUG ||
|
||||
type == BROADWAY_NODE_CONTAINER;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
add_new_node (GskRenderer *renderer,
|
||||
GskRenderNode *node,
|
||||
BroadwayNodeType type)
|
||||
BroadwayNodeType type,
|
||||
graphene_rect_t *clip_bounds)
|
||||
{
|
||||
GskBroadwayRenderer *self = GSK_BROADWAY_RENDERER (renderer);
|
||||
guint32 id, old_id;
|
||||
@ -319,6 +371,20 @@ add_new_node (GskRenderer *renderer,
|
||||
}
|
||||
|
||||
id = ++self->next_node_id;
|
||||
|
||||
/* Never try to reuse partially visible container types the next
|
||||
* frame, as they could be be partial due to pruning against clip_bounds,
|
||||
* and the clip_bounds may be different the next frame. However, anything
|
||||
* that is fully visible will not be pruned, so is ok to reuse.
|
||||
*
|
||||
* Note: its quite possible that the node is fully visible, but contains
|
||||
* a clip node which means the tree under that partial. That is fine and we can
|
||||
* still reuse *this* node next frame, but we can't use the child that is
|
||||
* partial, for example in a different place, because then it might see
|
||||
* the partial region of the tree.
|
||||
*/
|
||||
if (!node_type_is_container (type) ||
|
||||
node_is_fully_visible (node, clip_bounds))
|
||||
g_hash_table_insert (self->node_lookup, node, GINT_TO_POINTER(id));
|
||||
|
||||
add_uint32 (self->nodes, type);
|
||||
@ -497,7 +563,7 @@ gsk_broadway_renderer_add_node (GskRenderer *renderer,
|
||||
/* Leaf nodes */
|
||||
|
||||
case GSK_TEXTURE_NODE:
|
||||
if (add_new_node (renderer, node, BROADWAY_NODE_TEXTURE))
|
||||
if (add_new_node (renderer, node, BROADWAY_NODE_TEXTURE, clip_bounds))
|
||||
{
|
||||
GdkTexture *texture = gsk_texture_node_get_texture (node);
|
||||
guint32 texture_id;
|
||||
@ -512,7 +578,7 @@ gsk_broadway_renderer_add_node (GskRenderer *renderer,
|
||||
return;
|
||||
|
||||
case GSK_CAIRO_NODE:
|
||||
if (add_new_node (renderer, node, BROADWAY_NODE_TEXTURE))
|
||||
if (add_new_node (renderer, node, BROADWAY_NODE_TEXTURE, clip_bounds))
|
||||
{
|
||||
cairo_surface_t *surface = gsk_cairo_node_peek_surface (node);
|
||||
cairo_surface_t *image_surface = NULL;
|
||||
@ -548,7 +614,7 @@ gsk_broadway_renderer_add_node (GskRenderer *renderer,
|
||||
return;
|
||||
|
||||
case GSK_COLOR_NODE:
|
||||
if (add_new_node (renderer, node, BROADWAY_NODE_COLOR))
|
||||
if (add_new_node (renderer, node, BROADWAY_NODE_COLOR, clip_bounds))
|
||||
{
|
||||
add_rect (nodes, &node->bounds, offset_x, offset_y);
|
||||
add_rgba (nodes, gsk_color_node_peek_color (node));
|
||||
@ -556,7 +622,7 @@ gsk_broadway_renderer_add_node (GskRenderer *renderer,
|
||||
return;
|
||||
|
||||
case GSK_BORDER_NODE:
|
||||
if (add_new_node (renderer, node, BROADWAY_NODE_BORDER))
|
||||
if (add_new_node (renderer, node, BROADWAY_NODE_BORDER, clip_bounds))
|
||||
{
|
||||
int i;
|
||||
add_rounded_rect (nodes, gsk_border_node_peek_outline (node), offset_x, offset_y);
|
||||
@ -568,7 +634,7 @@ gsk_broadway_renderer_add_node (GskRenderer *renderer,
|
||||
return;
|
||||
|
||||
case GSK_OUTSET_SHADOW_NODE:
|
||||
if (add_new_node (renderer, node, BROADWAY_NODE_OUTSET_SHADOW))
|
||||
if (add_new_node (renderer, node, BROADWAY_NODE_OUTSET_SHADOW, clip_bounds))
|
||||
{
|
||||
add_rounded_rect (nodes, gsk_outset_shadow_node_peek_outline (node), offset_x, offset_y);
|
||||
add_rgba (nodes, gsk_outset_shadow_node_peek_color (node));
|
||||
@ -580,7 +646,7 @@ gsk_broadway_renderer_add_node (GskRenderer *renderer,
|
||||
return;
|
||||
|
||||
case GSK_INSET_SHADOW_NODE:
|
||||
if (add_new_node (renderer, node, BROADWAY_NODE_INSET_SHADOW))
|
||||
if (add_new_node (renderer, node, BROADWAY_NODE_INSET_SHADOW, clip_bounds))
|
||||
{
|
||||
add_rounded_rect (nodes, gsk_inset_shadow_node_peek_outline (node), offset_x, offset_y);
|
||||
add_rgba (nodes, gsk_inset_shadow_node_peek_color (node));
|
||||
@ -592,7 +658,7 @@ gsk_broadway_renderer_add_node (GskRenderer *renderer,
|
||||
return;
|
||||
|
||||
case GSK_LINEAR_GRADIENT_NODE:
|
||||
if (add_new_node (renderer, node, BROADWAY_NODE_LINEAR_GRADIENT))
|
||||
if (add_new_node (renderer, node, BROADWAY_NODE_LINEAR_GRADIENT, clip_bounds))
|
||||
{
|
||||
guint i, n;
|
||||
|
||||
@ -609,7 +675,7 @@ gsk_broadway_renderer_add_node (GskRenderer *renderer,
|
||||
/* Bin nodes */
|
||||
|
||||
case GSK_SHADOW_NODE:
|
||||
if (add_new_node (renderer, node, BROADWAY_NODE_SHADOW))
|
||||
if (add_new_node (renderer, node, BROADWAY_NODE_SHADOW, clip_bounds))
|
||||
{
|
||||
gsize i, n_shadows = gsk_shadow_node_get_n_shadows (node);
|
||||
|
||||
@ -629,7 +695,7 @@ gsk_broadway_renderer_add_node (GskRenderer *renderer,
|
||||
return;
|
||||
|
||||
case GSK_OPACITY_NODE:
|
||||
if (add_new_node (renderer, node, BROADWAY_NODE_OPACITY))
|
||||
if (add_new_node (renderer, node, BROADWAY_NODE_OPACITY, clip_bounds))
|
||||
{
|
||||
add_float (nodes, gsk_opacity_node_get_opacity (node));
|
||||
gsk_broadway_renderer_add_node (renderer,
|
||||
@ -639,7 +705,7 @@ gsk_broadway_renderer_add_node (GskRenderer *renderer,
|
||||
return;
|
||||
|
||||
case GSK_ROUNDED_CLIP_NODE:
|
||||
if (add_new_node (renderer, node, BROADWAY_NODE_ROUNDED_CLIP))
|
||||
if (add_new_node (renderer, node, BROADWAY_NODE_ROUNDED_CLIP, clip_bounds))
|
||||
{
|
||||
const GskRoundedRect *rclip = gsk_rounded_clip_node_peek_clip (node);
|
||||
graphene_rect_t child_bounds = rclip->bounds;
|
||||
@ -657,7 +723,7 @@ gsk_broadway_renderer_add_node (GskRenderer *renderer,
|
||||
return;
|
||||
|
||||
case GSK_CLIP_NODE:
|
||||
if (add_new_node (renderer, node, BROADWAY_NODE_CLIP))
|
||||
if (add_new_node (renderer, node, BROADWAY_NODE_CLIP, clip_bounds))
|
||||
{
|
||||
const graphene_rect_t *clip = gsk_clip_node_peek_clip (node);
|
||||
graphene_rect_t child_bounds = *clip;
|
||||
@ -679,7 +745,7 @@ gsk_broadway_renderer_add_node (GskRenderer *renderer,
|
||||
GskTransform *transform = gsk_transform_node_get_transform (node);
|
||||
GskTransformCategory category = gsk_transform_get_category (transform);
|
||||
|
||||
if (add_new_node (renderer, node, BROADWAY_NODE_TRANSFORM)) {
|
||||
if (add_new_node (renderer, node, BROADWAY_NODE_TRANSFORM, clip_bounds)) {
|
||||
if (category >= GSK_TRANSFORM_CATEGORY_2D_TRANSLATE)
|
||||
{
|
||||
float dx, dy;
|
||||
@ -717,7 +783,7 @@ gsk_broadway_renderer_add_node (GskRenderer *renderer,
|
||||
return;
|
||||
|
||||
case GSK_DEBUG_NODE:
|
||||
if (add_new_node (renderer, node, BROADWAY_NODE_DEBUG))
|
||||
if (add_new_node (renderer, node, BROADWAY_NODE_DEBUG, clip_bounds))
|
||||
{
|
||||
const char *message = gsk_debug_node_get_message (node);
|
||||
add_string (nodes, message);
|
||||
@ -729,14 +795,28 @@ gsk_broadway_renderer_add_node (GskRenderer *renderer,
|
||||
/* Generic nodes */
|
||||
|
||||
case GSK_CONTAINER_NODE:
|
||||
if (add_new_node (renderer, node, BROADWAY_NODE_CONTAINER))
|
||||
if (add_new_node (renderer, node, BROADWAY_NODE_CONTAINER, clip_bounds))
|
||||
{
|
||||
guint i;
|
||||
guint i, placeholder;
|
||||
guint32 n_children = 0;
|
||||
|
||||
add_uint32 (nodes, gsk_container_node_get_n_children (node));
|
||||
placeholder = add_uint32_placeholder (nodes);
|
||||
for (i = 0; i < gsk_container_node_get_n_children (node); i++)
|
||||
{
|
||||
/* We prune fully clipped children, but we only do this for container_node, as
|
||||
* we don't have a way for any other nodes to say there are children missing (i.e.
|
||||
* bins always assume there is a child).
|
||||
* Pruning is really only useful for large sets of children anyway, so thats
|
||||
* probably fine. */
|
||||
GskRenderNode *child = gsk_container_node_get_child (node, i);
|
||||
if (node_is_visible (child, clip_bounds))
|
||||
{
|
||||
n_children++;
|
||||
gsk_broadway_renderer_add_node (renderer,
|
||||
gsk_container_node_get_child (node, i), offset_x, offset_y, clip_bounds);
|
||||
child, offset_x, offset_y, clip_bounds);
|
||||
}
|
||||
}
|
||||
set_uint32_at (nodes, placeholder, n_children);
|
||||
}
|
||||
return;
|
||||
|
||||
@ -749,7 +829,7 @@ gsk_broadway_renderer_add_node (GskRenderer *renderer,
|
||||
const graphene_vec4_t *color_offset = gsk_color_matrix_node_peek_color_offset (node);
|
||||
GdkTexture *texture = gsk_texture_node_get_texture (child);
|
||||
GdkTexture *colorized_texture = get_colorized_texture (texture, color_matrix, color_offset);
|
||||
if (add_new_node (renderer, node, BROADWAY_NODE_TEXTURE))
|
||||
if (add_new_node (renderer, node, BROADWAY_NODE_TEXTURE, clip_bounds))
|
||||
{
|
||||
guint32 texture_id = gdk_broadway_display_ensure_texture (display, colorized_texture);
|
||||
add_rect (nodes, &child->bounds, offset_x, offset_y);
|
||||
@ -771,7 +851,7 @@ gsk_broadway_renderer_add_node (GskRenderer *renderer,
|
||||
break; /* Fallback */
|
||||
}
|
||||
|
||||
if (add_new_node (renderer, node, BROADWAY_NODE_TEXTURE))
|
||||
if (add_new_node (renderer, node, BROADWAY_NODE_TEXTURE, clip_bounds))
|
||||
{
|
||||
GdkTexture *texture;
|
||||
cairo_surface_t *surface;
|
||||
|
Loading…
Reference in New Issue
Block a user