From 2f01ef69e31d5434d2f6f57453f548e208e90606 Mon Sep 17 00:00:00 2001 From: Georges Basile Stavracas Neto Date: Mon, 14 Dec 2020 14:28:42 -0300 Subject: [PATCH] clutter/paint-node: Add multi-rect operations Add a new pair of APIs corresponding to CoglFramebuffer's draw_rectangles() and draw_textured_rectangles(). They're generally more performance compared to adding multiple single-rect operations. These variants are heavily used by GNOME Shell's CSS implementation. The op array is built to match cogl_framebuffer_draw_textured_rectangles() always, which means it's a series of 8 floats composed (x1 y1 x2 y2) and (s1 t1 s2 t2). To avoid adding new struct fields to ClutterPaintOperation, which is a performance and memory sensitive structure, simply divide the array length by 8 (which is guaranteed to be correct). Part-of: --- clutter/clutter/clutter-paint-node-private.h | 1 + clutter/clutter/clutter-paint-node.c | 112 +++++++++++++++++++ clutter/clutter/clutter-paint-node.h | 9 ++ clutter/clutter/clutter-paint-nodes.c | 18 +++ 4 files changed, 140 insertions(+) diff --git a/clutter/clutter/clutter-paint-node-private.h b/clutter/clutter/clutter-paint-node-private.h index ee2b89439..b084e81d4 100644 --- a/clutter/clutter/clutter-paint-node-private.h +++ b/clutter/clutter/clutter-paint-node-private.h @@ -82,6 +82,7 @@ typedef enum { PAINT_OP_INVALID = 0, PAINT_OP_TEX_RECT, + PAINT_OP_TEX_RECTS, PAINT_OP_MULTITEX_RECT, PAINT_OP_PRIMITIVE } PaintOpCode; diff --git a/clutter/clutter/clutter-paint-node.c b/clutter/clutter/clutter-paint-node.c index 116cfa833..4df3dac34 100644 --- a/clutter/clutter/clutter-paint-node.c +++ b/clutter/clutter/clutter-paint-node.c @@ -777,6 +777,7 @@ clutter_paint_operation_clear (ClutterPaintOperation *op) case PAINT_OP_TEX_RECT: break; + case PAINT_OP_TEX_RECTS: case PAINT_OP_MULTITEX_RECT: g_clear_pointer (&op->coords, g_array_unref); break; @@ -809,6 +810,36 @@ clutter_paint_op_init_tex_rect (ClutterPaintOperation *op, op->op.texrect[7] = y_2; } +static inline void +clutter_paint_op_init_tex_rects (ClutterPaintOperation *op, + const float *coords, + unsigned int n_rects, + gboolean use_default_tex_coords) +{ + const unsigned int n_floats = n_rects * 8; + + clutter_paint_operation_clear (op); + + op->opcode = PAINT_OP_TEX_RECTS; + op->coords = g_array_sized_new (FALSE, FALSE, sizeof (float), n_floats); + + if (use_default_tex_coords) + { + const float default_tex_coords[4] = { 0.0, 0.0, 1.0, 1.0 }; + int i; + + for (i = 0; i < n_rects; i++) + { + g_array_append_vals (op->coords, &coords[i * 4], 4); + g_array_append_vals (op->coords, default_tex_coords, 4); + } + } + else + { + g_array_append_vals (op->coords, coords, n_floats); + } +} + static inline void clutter_paint_op_init_multitex_rect (ClutterPaintOperation *op, const ClutterActorBox *rect, @@ -934,6 +965,74 @@ clutter_paint_node_add_multitexture_rectangle (ClutterPaintNode *node, g_array_append_val (node->operations, operation); } +/** + * clutter_paint_node_add_rectangles: + * @node: a #ClutterPaintNode + * @coords: (in) (array length=n_rects) (transfer none): array of + * coordinates containing groups of 4 float values: [x_1, y_1, x_2, y_2] that + * are interpreted as two position coordinates; one for the top left of the + * rectangle (x1, y1), and one for the bottom right of the rectangle + * (x2, y2). + * @n_rects: number of rectangles defined in @coords. + * + * Adds a series of rectangles to @node. + * + * As a general rule for better performance its recommended to use this API + * instead of calling clutter_paint_node_add_rectangle() separately for + * multiple rectangles if all of the rectangles will be drawn together. + * + * See cogl_framebuffer_draw_rectangles(). + */ +void +clutter_paint_node_add_rectangles (ClutterPaintNode *node, + const float *coords, + unsigned int n_rects) +{ + ClutterPaintOperation operation = PAINT_OP_INIT; + + g_return_if_fail (CLUTTER_IS_PAINT_NODE (node)); + g_return_if_fail (coords != NULL); + + clutter_paint_node_maybe_init_operations (node); + + clutter_paint_op_init_tex_rects (&operation, coords, n_rects, TRUE); + g_array_append_val (node->operations, operation); +} + +/** + * clutter_paint_node_add_texture_rectangles: + * @node: a #ClutterPaintNode + * @coords: (in) (array length=n_rects) (transfer none): array containing + * groups of 8 float values: [x_1, y_1, x_2, y_2, s_1, t_1, s_2, t_2] + * that have the same meaning as the arguments for + * cogl_framebuffer_draw_textured_rectangle(). + * @n_rects: number of rectangles defined in @coords. + * + * Adds a series of rectangles to @node. + * + * The given texture coordinates should always be normalized such that + * (0, 0) corresponds to the top left and (1, 1) corresponds to the + * bottom right. To map an entire texture across the rectangle pass + * in s_1=0, t_1=0, s_2=1, t_2=1. + * + * See cogl_framebuffer_draw_textured_rectangles(). + */ +void +clutter_paint_node_add_texture_rectangles (ClutterPaintNode *node, + const float *coords, + unsigned int n_rects) +{ + ClutterPaintOperation operation = PAINT_OP_INIT; + + g_return_if_fail (CLUTTER_IS_PAINT_NODE (node)); + g_return_if_fail (coords != NULL); + + clutter_paint_node_maybe_init_operations (node); + + clutter_paint_op_init_tex_rects (&operation, coords, n_rects, FALSE); + g_array_append_val (node->operations, operation); +} + /** * clutter_paint_node_add_primitive: (skip) * @node: a #ClutterPaintNode @@ -1057,6 +1156,19 @@ clutter_paint_node_to_json (ClutterPaintNode *node) json_builder_end_array (builder); break; + case PAINT_OP_TEX_RECTS: + json_builder_set_member_name (builder, "texrects"); + json_builder_begin_array (builder); + + for (j = 0; i < op->coords->len; j++) + { + float coord = g_array_index (op->coords, float, j); + json_builder_add_double_value (builder, coord); + } + + json_builder_end_array (builder); + break; + case PAINT_OP_MULTITEX_RECT: json_builder_set_member_name (builder, "texrect"); json_builder_begin_array (builder); diff --git a/clutter/clutter/clutter-paint-node.h b/clutter/clutter/clutter-paint-node.h index 7afc60f66..b9f174962 100644 --- a/clutter/clutter/clutter-paint-node.h +++ b/clutter/clutter/clutter-paint-node.h @@ -83,6 +83,15 @@ void clutter_paint_node_add_multitexture_rectangle (ClutterP const float *text_coords, unsigned int text_coords_len); +CLUTTER_EXPORT +void clutter_paint_node_add_rectangles (ClutterPaintNode *node, + const float *coords, + unsigned int n_rects); +CLUTTER_EXPORT +void clutter_paint_node_add_texture_rectangles (ClutterPaintNode *node, + const float *coords, + unsigned int n_rects); + CLUTTER_EXPORT void clutter_paint_node_add_primitive (ClutterPaintNode *node, CoglPrimitive *primitive); diff --git a/clutter/clutter/clutter-paint-nodes.c b/clutter/clutter/clutter-paint-nodes.c index db42f2f3f..9da5b450f 100644 --- a/clutter/clutter/clutter-paint-nodes.c +++ b/clutter/clutter/clutter-paint-nodes.c @@ -467,6 +467,13 @@ clutter_pipeline_node_draw (ClutterPaintNode *node, op->op.texrect[7]); break; + case PAINT_OP_TEX_RECTS: + cogl_framebuffer_draw_textured_rectangles (fb, + pnode->pipeline, + (float *) op->coords->data, + op->coords->len / 8); + break; + case PAINT_OP_MULTITEX_RECT: cogl_framebuffer_draw_multitextured_rectangle (fb, pnode->pipeline, @@ -872,6 +879,7 @@ clutter_text_node_draw (ClutterPaintNode *node, cogl_framebuffer_pop_clip (fb); break; + case PAINT_OP_TEX_RECTS: case PAINT_OP_MULTITEX_RECT: case PAINT_OP_PRIMITIVE: case PAINT_OP_INVALID: @@ -1033,6 +1041,7 @@ clutter_clip_node_pre_draw (ClutterPaintNode *node, retval = TRUE; break; + case PAINT_OP_TEX_RECTS: case PAINT_OP_MULTITEX_RECT: case PAINT_OP_PRIMITIVE: case PAINT_OP_INVALID: @@ -1067,6 +1076,7 @@ clutter_clip_node_post_draw (ClutterPaintNode *node, cogl_framebuffer_pop_clip (fb); break; + case PAINT_OP_TEX_RECTS: case PAINT_OP_MULTITEX_RECT: case PAINT_OP_PRIMITIVE: case PAINT_OP_INVALID: @@ -1440,6 +1450,13 @@ clutter_layer_node_post_draw (ClutterPaintNode *node, op->op.texrect[7]); break; + case PAINT_OP_TEX_RECTS: + cogl_framebuffer_draw_textured_rectangles (fb, + lnode->pipeline, + (float *) op->coords->data, + op->coords->len / 8); + break; + case PAINT_OP_MULTITEX_RECT: cogl_framebuffer_draw_multitextured_rectangle (fb, lnode->pipeline, @@ -1695,6 +1712,7 @@ clutter_blit_node_draw (ClutterPaintNode *node, } break; + case PAINT_OP_TEX_RECTS: case PAINT_OP_MULTITEX_RECT: case PAINT_OP_PRIMITIVE: break;