[gtk+/wip/baedert/gl: 39/85] gl renderer: Optimize text drawing



commit 2b38f9b5d558ac3a42c81c37c07221eb1dfb7d2f
Author: Timm Bäder <mail baedert org>
Date:   Thu Nov 23 19:49:41 2017 +0100

    gl renderer: Optimize text drawing
    
    Text nodes will almost always end up using the exact same texture and
    the same program. So, in that case we can simply add vertex data for all
    the characters we need to draw and use just one draw call.

 gsk/gl/gskglrenderer.c         |   40 +++++++++++++++++++---------------
 gsk/gl/gskglrenderops.c        |   46 ++++++++++++++++++++++++++++++++-------
 gsk/gl/gskglrenderopsprivate.h |    5 +++-
 3 files changed, 63 insertions(+), 28 deletions(-)
---
diff --git a/gsk/gl/gskglrenderer.c b/gsk/gl/gskglrenderer.c
index 880c108..c153219 100644
--- a/gsk/gl/gskglrenderer.c
+++ b/gsk/gl/gskglrenderer.c
@@ -328,6 +328,7 @@ gsk_gl_renderer_create_programs (GskGLRenderer  *self,
       goto out;
     }
   self->coloring_program.index = 3;
+  self->coloring_program.name = "coloring";
   init_common_locations (self, builder, &self->coloring_program);
   INIT_PROGRAM_UNIFORM_LOCATION (coloring_program, color_location, "uColor");
 
@@ -342,6 +343,7 @@ gsk_gl_renderer_create_programs (GskGLRenderer  *self,
       goto out;
     }
   self->color_matrix_program.index = 4;
+  self->color_matrix_program.name = "color matrix";
   init_common_locations (self, builder, &self->color_matrix_program);
   INIT_PROGRAM_UNIFORM_LOCATION (color_matrix_program, color_matrix_location, "uColorMatrix");
   INIT_PROGRAM_UNIFORM_LOCATION (color_matrix_program, color_offset_location, "uColorOffset");
@@ -357,6 +359,7 @@ gsk_gl_renderer_create_programs (GskGLRenderer  *self,
       goto out;
     }
   self->linear_gradient_program.index = 5;
+  self->linear_gradient_program.name = "linear gradient";
   init_common_locations (self, builder, &self->linear_gradient_program);
   INIT_PROGRAM_UNIFORM_LOCATION (linear_gradient_program, color_stops_location, "uColorStops");
   INIT_PROGRAM_UNIFORM_LOCATION (linear_gradient_program, color_offsets_location, "uColorOffsets");
@@ -858,6 +861,22 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer   *self,
         int x = gsk_text_node_get_x (node);
         int y = gsk_text_node_get_y (node);
 
+        /* If the font has color glyphs, we don't need to recolor anything */
+        if (has_color_glyphs)
+          {
+            ops_set_program (builder, &self->blit_program);
+          }
+        else
+          {
+            RenderOp op;
+
+            ops_set_program (builder, &self->coloring_program);
+
+            op.op = OP_CHANGE_COLOR;
+            op.color = *gsk_text_node_peek_color (node);
+            ops_add (builder, &op);
+          }
+
         /* We use one quad per character, unlike the other nodes which
          * use at most one quad altogether */
         for (i = 0; i < num_glyphs; i++)
@@ -888,22 +907,6 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer   *self,
             cx = (double)(x_position + gi->geometry.x_offset) / PANGO_SCALE;
             cy = (double)(gi->geometry.y_offset) / PANGO_SCALE;
 
-            /* If the font has color glyphs, we don't need to recolor anything */
-            if (has_color_glyphs)
-              {
-                ops_set_program (builder, &self->blit_program);
-              }
-            else
-              {
-                RenderOp op;
-
-                ops_set_program (builder, &self->coloring_program);
-
-                op.op = OP_CHANGE_COLOR;
-                op.color = *gsk_text_node_peek_color (node);
-                ops_add (builder, &op);
-              }
-
             ops_set_texture (builder, gsk_gl_glyph_cache_get_glyph_image (&self->glyph_cache,
                                                                          glyph)->texture_id);
 
@@ -1156,8 +1159,9 @@ gsk_gl_renderer_render_ops (GskGLRenderer *self,
           break;
 
         case OP_DRAW:
-          OP_PRINT (" -> draw %ld and program %s\n", op->vao_offset, program->name);
-          glDrawArrays (GL_TRIANGLES, op->vao_offset, GL_N_VERTICES);
+          OP_PRINT (" -> draw %ld, size %ld and program %s\n",
+                    op->draw.vao_offset, op->draw.draw_size, program->name);
+          glDrawArrays (GL_TRIANGLES, op->draw.vao_offset, op->draw.draw_size);//GL_N_VERTICES);
           break;
 
         default:
diff --git a/gsk/gl/gskglrenderops.c b/gsk/gl/gskglrenderops.c
index a1621c6..6bc9e82 100644
--- a/gsk/gl/gskglrenderops.c
+++ b/gsk/gl/gskglrenderops.c
@@ -223,17 +223,45 @@ void
 ops_draw (RenderOpBuilder     *builder,
           const GskQuadVertex  vertex_data[GL_N_VERTICES])
 {
-  RenderOp op;
-  gsize offset = builder->buffer_size / sizeof (GskQuadVertex);
+  RenderOp *last_op;
 
-  op.op = OP_CHANGE_VAO;
-  memcpy (&op.vertex_data, vertex_data, sizeof(GskQuadVertex) * GL_N_VERTICES);
-  g_array_append_val (builder->render_ops, op);
-  builder->buffer_size += sizeof (GskQuadVertex) * GL_N_VERTICES;
+  last_op = &g_array_index (builder->render_ops, RenderOp, builder->render_ops->len - 1);
+  /* If the previous op was a DRAW as well, we didn't change anything between the two calls,
+   * so these are just 2 subsequent draw calls. Same VAO, same program etc.
+   * And the offsets into the vao are in order as well, so make it one draw call. */
+  if (last_op->op == OP_DRAW)
+    {
+      /* We allow ourselves a little trick here. We still have to add a CHANGE_VAO op for
+       * this draw call so we can add our vertex data there, but we want it to be placed before
+       * the last draw call, so we reorder those. */
+      RenderOp new_draw;
+      new_draw.op = OP_DRAW;
+      new_draw.draw.vao_offset = last_op->draw.vao_offset;
+      new_draw.draw.draw_size = last_op->draw.draw_size + GL_N_VERTICES;
+
+      last_op->op = OP_CHANGE_VAO;
+      memcpy (&last_op->vertex_data, vertex_data, sizeof(GskQuadVertex) * GL_N_VERTICES);
+
+      /* Now add the DRAW */
+      g_array_append_val (builder->render_ops, new_draw);
+    }
+  else
+    {
+      RenderOp op;
+      gsize offset = builder->buffer_size / sizeof (GskQuadVertex);
 
-  op.op = OP_DRAW;
-  op.vao_offset = offset;
-  g_array_append_val (builder->render_ops, op);
+      op.op = OP_CHANGE_VAO;
+      memcpy (&op.vertex_data, vertex_data, sizeof(GskQuadVertex) * GL_N_VERTICES);
+      g_array_append_val (builder->render_ops, op);
+
+      op.op = OP_DRAW;
+      op.draw.vao_offset = offset;
+      op.draw.draw_size = GL_N_VERTICES;
+      g_array_append_val (builder->render_ops, op);
+    }
+
+  /* We added new vertex data in both cases so increase the buffer size */
+  builder->buffer_size += sizeof (GskQuadVertex) * GL_N_VERTICES;
 }
 
 void
diff --git a/gsk/gl/gskglrenderopsprivate.h b/gsk/gl/gskglrenderopsprivate.h
index 11d69df..fee25af 100644
--- a/gsk/gl/gskglrenderopsprivate.h
+++ b/gsk/gl/gskglrenderopsprivate.h
@@ -85,7 +85,6 @@ typedef struct
     int texture_id;
     int render_target_id;
     GdkRGBA color;
-    gsize vao_offset;
     GskQuadVertex vertex_data[6];
     GskRoundedRect clip;
     graphene_rect_t viewport;
@@ -96,6 +95,10 @@ typedef struct
       graphene_point_t start_point;
       graphene_point_t end_point;
     } linear_gradient;
+    struct {
+      gsize vao_offset;
+      gsize draw_size;
+    } draw;
   };
 } RenderOp;
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]