[Bf-blender-cvs] [001f7c92d14] master: BLF: Optimize text rendering and caching

Germano Cavalcante noreply at git.blender.org
Mon Feb 24 12:01:45 CET 2020


Commit: 001f7c92d1452e01622f066d37bd42545b650a27
Author: Germano Cavalcante
Date:   Sun Feb 23 17:30:27 2020 -0300
Branches: master
https://developer.blender.org/rB001f7c92d1452e01622f066d37bd42545b650a27

BLF: Optimize text rendering and caching

The current code allocates and transfers a lot of memory to the GPU,
but only a small portion of this memory is actually used.
In addition, the code calls many costly gl operations during the
caching process.

This commit significantly reduce the amount of memory by allocating
and transferring a flat array without pads to the GPU.
It also calls as little as possible the gl operations during the cache.

This code also simulate a billinear filter `GL_LINEAR` using a 1D texture.

**Average drawing time:**
|before:|0.00003184 sec
|now:|0.00001943 sec
|fac:|1.6385156675048407

**5 worst times:**
|before:|[0.001075, 0.001433, 0.002143, 0.002915, 0.003242]
|now:|[0.00094, 0.000993, 0.001502, 0.002284, 0.002328]

Differential Revision: https://developer.blender.org/D6886

===================================================================

M	source/blender/blenfont/intern/blf.c
M	source/blender/blenfont/intern/blf_font.c
M	source/blender/blenfont/intern/blf_glyph.c
M	source/blender/blenfont/intern/blf_internal_types.h
M	source/blender/gpu/shaders/gpu_shader_text_frag.glsl
M	source/blender/gpu/shaders/gpu_shader_text_vert.glsl

===================================================================

diff --git a/source/blender/blenfont/intern/blf.c b/source/blender/blenfont/intern/blf.c
index 2b592c9e550..725c4c0712d 100644
--- a/source/blender/blenfont/intern/blf.c
+++ b/source/blender/blenfont/intern/blf.c
@@ -584,9 +584,6 @@ static void blf_draw_gl__start(FontBLF *font)
    * in BLF_position (old ui_rasterpos_safe).
    */
 
-  /* always bind the texture for the first glyph */
-  font->tex_bind_state = 0;
-
   if ((font->flags & (BLF_ROTATION | BLF_MATRIX | BLF_ASPECT)) == 0) {
     return; /* glyphs will be translated individually and batched. */
   }
diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c
index 25ea0770f8b..f0afe184233 100644
--- a/source/blender/blenfont/intern/blf_font.c
+++ b/source/blender/blenfont/intern/blf_font.c
@@ -84,16 +84,19 @@ static void blf_batch_draw_init(void)
 {
   GPUVertFormat format = {0};
   g_batch.pos_loc = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
-  g_batch.tex_loc = GPU_vertformat_attr_add(&format, "tex", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
   g_batch.col_loc = GPU_vertformat_attr_add(
       &format, "col", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
+  g_batch.offset_loc = GPU_vertformat_attr_add(&format, "offset", GPU_COMP_I32, 1, GPU_FETCH_INT);
+  g_batch.glyph_size_loc = GPU_vertformat_attr_add(
+      &format, "glyph_size", GPU_COMP_I32, 2, GPU_FETCH_INT);
 
   g_batch.verts = GPU_vertbuf_create_with_format_ex(&format, GPU_USAGE_STREAM);
   GPU_vertbuf_data_alloc(g_batch.verts, BLF_BATCH_DRAW_LEN_MAX);
 
   GPU_vertbuf_attr_get_raw_data(g_batch.verts, g_batch.pos_loc, &g_batch.pos_step);
-  GPU_vertbuf_attr_get_raw_data(g_batch.verts, g_batch.tex_loc, &g_batch.tex_step);
   GPU_vertbuf_attr_get_raw_data(g_batch.verts, g_batch.col_loc, &g_batch.col_step);
+  GPU_vertbuf_attr_get_raw_data(g_batch.verts, g_batch.offset_loc, &g_batch.offset_step);
+  GPU_vertbuf_attr_get_raw_data(g_batch.verts, g_batch.glyph_size_loc, &g_batch.glyph_size_step);
   g_batch.glyph_len = 0;
 
   /* A dummy vbo containing 4 points, attribs are not used.  */
@@ -177,6 +180,46 @@ void blf_batch_draw_begin(FontBLF *font)
   }
 }
 
+static GPUTexture *blf_batch_cache_texture_load(void)
+{
+  GlyphCacheBLF *gc = g_batch.glyph_cache;
+  BLI_assert(gc);
+  BLI_assert(gc->bitmap_len > 0);
+
+  if (gc->bitmap_len > gc->bitmap_len_landed) {
+    const int tex_width = GPU_texture_width(gc->texture);
+
+    int bitmap_len_landed = gc->bitmap_len_landed;
+    int remain = gc->bitmap_len - bitmap_len_landed;
+    int offset_x = bitmap_len_landed % tex_width;
+    int offset_y = bitmap_len_landed / tex_width;
+
+    /* TODO(germano): Update more than one row in a single call. */
+    while (remain) {
+      int remain_row = tex_width - offset_x;
+      int width = remain > remain_row ? remain_row : remain;
+      GPU_texture_update_sub(gc->texture,
+                             GPU_DATA_UNSIGNED_BYTE,
+                             &gc->bitmap_result[bitmap_len_landed],
+                             offset_x,
+                             offset_y,
+                             0,
+                             width,
+                             1,
+                             0);
+
+      bitmap_len_landed += width;
+      remain -= width;
+      offset_x = 0;
+      offset_y += 1;
+    }
+
+    gc->bitmap_len_landed = bitmap_len_landed;
+  }
+
+  return gc->texture;
+}
+
 void blf_batch_draw(void)
 {
   if (g_batch.glyph_len == 0) {
@@ -190,7 +233,8 @@ void blf_batch_draw(void)
   /* We need to flush widget base first to ensure correct ordering. */
   UI_widgetbase_draw_cache_flush();
 
-  GPU_texture_bind(g_batch.tex_bind_state, 0);
+  GPUTexture *texture = blf_batch_cache_texture_load();
+  GPU_texture_bind(texture, 0);
   GPU_vertbuf_data_len_set(g_batch.verts, g_batch.glyph_len);
   GPU_vertbuf_use(g_batch.verts); /* send data */
 
@@ -202,8 +246,9 @@ void blf_batch_draw(void)
 
   /* restart to 1st vertex data pointers */
   GPU_vertbuf_attr_get_raw_data(g_batch.verts, g_batch.pos_loc, &g_batch.pos_step);
-  GPU_vertbuf_attr_get_raw_data(g_batch.verts, g_batch.tex_loc, &g_batch.tex_step);
   GPU_vertbuf_attr_get_raw_data(g_batch.verts, g_batch.col_loc, &g_batch.col_step);
+  GPU_vertbuf_attr_get_raw_data(g_batch.verts, g_batch.offset_loc, &g_batch.offset_step);
+  GPU_vertbuf_attr_get_raw_data(g_batch.verts, g_batch.glyph_size_loc, &g_batch.glyph_size_step);
   g_batch.glyph_len = 0;
 }
 
diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c
index 80d43a49e77..8e88bda37a5 100644
--- a/source/blender/blenfont/intern/blf_glyph.c
+++ b/source/blender/blenfont/intern/blf_glyph.c
@@ -143,13 +143,6 @@ GlyphCacheBLF *blf_glyph_cache_new(FontBLF *font)
   memset(gc->glyph_ascii_table, 0, sizeof(gc->glyph_ascii_table));
   memset(gc->bucket, 0, sizeof(gc->bucket));
 
-  gc->textures = (GPUTexture **)MEM_callocN(sizeof(GPUTexture *) * 256, __func__);
-  gc->textures_len = 256;
-  gc->texture_current = BLF_TEXTURE_UNSET;
-  gc->offset_x = 3; /* enough padding for blur */
-  gc->offset_y = 3; /* enough padding for blur */
-  gc->pad = 6;
-
   gc->glyphs_len_max = (int)font->face->num_glyphs;
   gc->glyphs_len_free = (int)font->face->num_glyphs;
   gc->ascender = ((float)font->face->size->metrics.ascender) / 64.0f;
@@ -173,9 +166,6 @@ GlyphCacheBLF *blf_glyph_cache_new(FontBLF *font)
   CLAMP_MIN(gc->glyph_width_max, 1);
   CLAMP_MIN(gc->glyph_height_max, 1);
 
-  gc->p2_width = 0;
-  gc->p2_height = 0;
-
   BLI_addhead(&font->cache, gc);
   return gc;
 }
@@ -229,52 +219,13 @@ void blf_glyph_cache_free(GlyphCacheBLF *gc)
       blf_glyph_free(g);
     }
   }
-  for (i = 0; i < gc->textures_len; i++) {
-    if (gc->textures[i]) {
-      GPU_texture_free(gc->textures[i]);
-    }
+  if (gc->texture) {
+    GPU_texture_free(gc->texture);
   }
-  MEM_freeN(gc->textures);
-  MEM_freeN(gc);
-}
-
-static void blf_glyph_cache_texture(FontBLF *font, GlyphCacheBLF *gc)
-{
-  int i;
-  char error[256];
-
-  /* move the index. */
-  gc->texture_current++;
-
-  if (UNLIKELY(gc->texture_current >= gc->textures_len)) {
-    gc->textures_len *= 2;
-    gc->textures = MEM_recallocN((void *)gc->textures, sizeof(GPUTexture *) * gc->textures_len);
-  }
-
-  gc->p2_width = (int)blf_next_p2(
-      (unsigned int)((gc->glyphs_len_free * gc->glyph_width_max) + (gc->pad * 2)));
-  if (gc->p2_width > font->tex_size_max) {
-    gc->p2_width = font->tex_size_max;
+  if (gc->bitmap_result) {
+    MEM_freeN(gc->bitmap_result);
   }
-
-  i = (int)((gc->p2_width - (gc->pad * 2)) / gc->glyph_width_max);
-  gc->p2_height = (int)blf_next_p2(
-      (unsigned int)(((gc->glyphs_len_max / i) + 1) * gc->glyph_height_max + (gc->pad * 2)));
-
-  if (gc->p2_height > font->tex_size_max) {
-    gc->p2_height = font->tex_size_max;
-  }
-
-  GPUTexture *tex = GPU_texture_create_nD(
-      gc->p2_width, gc->p2_height, 0, 2, NULL, GPU_R8, GPU_DATA_UNSIGNED_BYTE, 0, false, error);
-
-  GPU_texture_bind(tex, 0);
-  GPU_texture_wrap_mode(tex, false);
-  GPU_texture_filters(tex, GPU_NEAREST, GPU_LINEAR);
-  GPU_texture_clear(tex, GPU_DATA_UNSIGNED_BYTE, NULL);
-  GPU_texture_unbind(tex);
-
-  gc->textures[gc->texture_current] = tex;
+  MEM_freeN(gc);
 }
 
 GlyphBLF *blf_glyph_search(GlyphCacheBLF *gc, unsigned int c)
@@ -377,8 +328,6 @@ GlyphBLF *blf_glyph_add(FontBLF *font, GlyphCacheBLF *gc, unsigned int index, un
   g = (GlyphBLF *)MEM_callocN(sizeof(GlyphBLF), "blf_glyph_add");
   g->c = c;
   g->idx = (FT_UInt)index;
-  g->offset_x = -1;
-  g->offset_y = -1;
   bitmap = slot->bitmap;
   g->width = (int)bitmap.width;
   g->height = (int)bitmap.rows;
@@ -418,17 +367,19 @@ GlyphBLF *blf_glyph_add(FontBLF *font, GlyphCacheBLF *gc, unsigned int index, un
 
 void blf_glyph_free(GlyphBLF *g)
 {
-  /* don't need free the texture, the GlyphCache already
-   * have a list of all the texture and free it.
-   */
   if (g->bitmap) {
     MEM_freeN(g->bitmap);
   }
   MEM_freeN(g);
 }
 
-static void blf_texture_draw(
-    const unsigned char color[4], const float uv[2][2], float x1, float y1, float x2, float y2)
+static void blf_texture_draw(const unsigned char color[4],
+                             const int glyph_size[2],
+                             const int offset,
+                             float x1,
+                             float y1,
+                             float x2,
+                             float y2)
 {
   /* Only one vertex per glyph, geometry shader expand it into a quad. */
   /* TODO Get rid of Geom Shader because it's not optimal AT ALL for the GPU */
@@ -437,8 +388,10 @@ static void blf_texture_draw(
               y1 + g_batch.ofs[1],
               x2 + g_batch.ofs[0],
               y2 + g_batch.ofs[1]);
-  copy_v4_v4(GPU_vertbuf_raw_step(&g_batch.tex_step), (float *)uv);
   copy_v4_v4_uchar(GPU_vertbuf_raw_step(&g_batch.col_step), color);
+  copy_v2_v2_int(GPU_vertbuf_raw_step(&g_batch.glyph_size_step), glyph_size);
+  *((int *)GPU_vertbuf_raw_step(&g_batch.offset_step)) = offset;
+
   g_batch.glyph_len++;
   /* Flush cache if it's full. */
   if (g_batch.glyph_len == BLF_BATCH_DRAW_LEN_MAX) {
@@ -447,45 +400,35 @@ static void blf_texture_draw(
 }
 
 static void blf_texture5_draw(const unsigned char color_in[4],
-                              int tex_w,
-                              int tex_h,
-                              const float uv[2][2],
+                              const int glyph_size[2],
+                              const int offset,
                               float x1,
                               float y1,
                               float x2,
                               float y2)
 {
-  float ofs[2] = {2 / (float)tex_w, 2 / (float)tex_h};
-  float uv_flag[2][2];
-  copy_v4_v4((float *)uv_flag, (float *)uv);
+  int glyph_size_flag[2];
   /* flag the x and y component signs for 5x5 blurring */
-  uv_flag[0][0] = -(uv_flag[0][0] - ofs[0]);
-  uv_flag[0][1] = -(uv_flag[0][1] - ofs[1]);
-  uv_flag[1][0] = -(uv_flag[1][0] + ofs[0]);
-  uv_flag[1][1] = -(uv_flag[1][1] + ofs[1]);
+  glyph_size_flag[0] = -glyph_size[0];
+  glyph_size_flag[1] = -glyph_size[1];
 
-  blf_texture_draw(color_in, uv_flag, x1 - 2, y1

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list