Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGermano Cavalcante <germano.costa@ig.com.br>2020-02-23 23:30:27 +0300
committerGermano Cavalcante <germano.costa@ig.com.br>2020-02-24 14:01:22 +0300
commit001f7c92d1452e01622f066d37bd42545b650a27 (patch)
treec31f0067b2b6399b7c2b2f55ded1af244e67e248 /source/blender/blenfont/intern/blf_glyph.c
parenta31bd3f7b5cf27166ccdf3b33890533c5366eb4f (diff)
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
Diffstat (limited to 'source/blender/blenfont/intern/blf_glyph.c')
-rw-r--r--source/blender/blenfont/intern/blf_glyph.c230
1 files changed, 78 insertions, 152 deletions
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 + 2, x2 + 2, y2 - 2);
+ blf_texture_draw(color_in, glyph_size_flag, offset, x1, y1, x2, y2);
}
static void blf_texture3_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] = {1 / (float)tex_w, 1 / (float)tex_h};
- float uv_flag[2][2];
- copy_v4_v4((float *)uv_flag, (float *)uv);
+ int glyph_size_flag[2];
/* flag the x component sign for 3x3 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 - 1, y1 + 1, x2 + 1, y2 - 1);
+ blf_texture_draw(color_in, glyph_size_flag, offset, x1, y1, x2, y2);
}
static void blf_glyph_calc_rect(rctf *rect, GlyphBLF *g, float x, float y)
@@ -518,63 +461,38 @@ void blf_glyph_render(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, float x, fl
return;
}
- if (g->build_tex == 0) {
+ if (!g->cached) {
if (font->tex_size_max == -1) {
font->tex_size_max = GPU_max_texture_size();
}
- if (gc->texture_current == BLF_TEXTURE_UNSET) {
- blf_glyph_cache_texture(font, gc);
- gc->offset_x = gc->pad;
- gc->offset_y = 3; /* enough padding for blur */
- }
+ g->offset = gc->bitmap_len;
- if (gc->offset_x > (gc->p2_width - gc->glyph_width_max)) {
- gc->offset_x = gc->pad;
- gc->offset_y += gc->glyph_height_max;
+ int buff_size = g->width * g->height;
+ int bitmap_len = gc->bitmap_len + buff_size;
- if (gc->offset_y > (gc->p2_height - gc->glyph_height_max)) {
- gc->offset_y = 3; /* enough padding for blur */
- blf_glyph_cache_texture(font, gc);
- }
- }
+ if (bitmap_len > gc->bitmap_len_alloc) {
+ int w = font->tex_size_max;
+ int h = bitmap_len / w + 1;
- g->tex = gc->textures[gc->texture_current];
- g->offset_x = gc->offset_x;
- g->offset_y = gc->offset_y;
+ gc->bitmap_len_alloc = w * h;
+ gc->bitmap_result = MEM_reallocN(gc->bitmap_result, (size_t)gc->bitmap_len_alloc);
- /* prevent glTexSubImage2D from failing if the character
- * asks for pixels out of bounds, this tends only to happen
- * with very small sizes (5px high or less) */
- if (UNLIKELY((g->offset_x + g->width) > gc->p2_width)) {
- g->width -= (g->offset_x + g->width) - gc->p2_width;
- BLI_assert(g->width > 0);
- }
- if (UNLIKELY((g->offset_y + g->height) > gc->p2_height)) {
- g->height -= (g->offset_y + g->height) - gc->p2_height;
- BLI_assert(g->height > 0);
- }
-
- GPU_texture_update_sub(g->tex,
- GPU_DATA_UNSIGNED_BYTE,
- g->bitmap,
- g->offset_x,
- g->offset_y,
- 0,
- g->width,
- g->height,
- 0);
+ /* Keep in sync with the texture. */
+ if (gc->texture) {
+ GPU_texture_free(gc->texture);
+ }
+ gc->texture = GPU_texture_create_nD(
+ w, h, 0, 1, NULL, GPU_R8, GPU_DATA_UNSIGNED_BYTE, 0, false, NULL);
- g->uv[0][0] = ((float)g->offset_x) / ((float)gc->p2_width);
- g->uv[0][1] = ((float)g->offset_y) / ((float)gc->p2_height);
- g->uv[1][0] = ((float)(g->offset_x + g->width)) / ((float)gc->p2_width);
- g->uv[1][1] = ((float)(g->offset_y + g->height)) / ((float)gc->p2_height);
+ gc->bitmap_len_landed = 0;
+ }
- /* update the x offset for the next glyph. */
- gc->offset_x += (int)BLI_rctf_size_x(&g->box) + gc->pad;
+ memcpy(&gc->bitmap_result[gc->bitmap_len], g->bitmap, (size_t)buff_size);
+ gc->bitmap_len = bitmap_len;
gc->glyphs_len_free--;
- g->build_tex = 1;
+ g->cached = true;
}
if (font->flags & BLF_CLIPPING) {
@@ -587,27 +505,26 @@ void blf_glyph_render(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, float x, fl
}
}
- if (font->tex_bind_state != g->tex) {
- blf_batch_draw();
- font->tex_bind_state = g->tex;
- GPU_texture_bind(font->tex_bind_state, 0);
- }
-
- g_batch.tex_bind_state = g->tex;
+ g_batch.glyph_cache = gc;
+ BLI_assert(g->offset < gc->bitmap_len);
if (font->flags & BLF_SHADOW) {
rctf rect_ofs;
blf_glyph_calc_rect_shadow(&rect_ofs, g, x, y, font);
if (font->shadow == 0) {
- blf_texture_draw(
- font->shadow_color, g->uv, rect_ofs.xmin, rect_ofs.ymin, rect_ofs.xmax, rect_ofs.ymax);
+ blf_texture_draw(font->shadow_color,
+ (int[2]){g->width, g->height},
+ g->offset,
+ rect_ofs.xmin,
+ rect_ofs.ymin,
+ rect_ofs.xmax,
+ rect_ofs.ymax);
}
else if (font->shadow <= 4) {
blf_texture3_draw(font->shadow_color,
- gc->p2_width,
- gc->p2_height,
- g->uv,
+ (int[2]){g->width, g->height},
+ g->offset,
rect_ofs.xmin,
rect_ofs.ymin,
rect_ofs.xmax,
@@ -615,9 +532,8 @@ void blf_glyph_render(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, float x, fl
}
else {
blf_texture5_draw(font->shadow_color,
- gc->p2_width,
- gc->p2_height,
- g->uv,
+ (int[2]){g->width, g->height},
+ g->offset,
rect_ofs.xmin,
rect_ofs.ymin,
rect_ofs.xmax,
@@ -632,9 +548,8 @@ void blf_glyph_render(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, float x, fl
switch (font->blur) {
case 3:
blf_texture3_draw(font->color,
- gc->p2_width,
- gc->p2_height,
- g->uv,
+ (int[2]){g->width, g->height},
+ g->offset,
rect.xmin,
rect.ymin,
rect.xmax,
@@ -642,18 +557,29 @@ void blf_glyph_render(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, float x, fl
break;
case 5:
blf_texture5_draw(font->color,
- gc->p2_width,
- gc->p2_height,
- g->uv,
+ (int[2]){g->width, g->height},
+ g->offset,
rect.xmin,
rect.ymin,
rect.xmax,
rect.ymax);
break;
default:
- blf_texture_draw(font->color, g->uv, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
+ blf_texture_draw(font->color,
+ (int[2]){g->width, g->height},
+ g->offset,
+ rect.xmin,
+ rect.ymin,
+ rect.xmax,
+ rect.ymax);
}
#else
- blf_texture_draw(font->color, g->uv, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
+ blf_texture_draw(font->color,
+ (int[2]){g->width, g->height},
+ g->offset,
+ rect.xmin,
+ rect.ymin,
+ rect.xmax,
+ rect.ymax);
#endif
}