diff --git a/source/blender/blenfont/BLF_api.h b/source/blender/blenfont/BLF_api.h index cd3a15f1c88..fd0c0362300 100644 --- a/source/blender/blenfont/BLF_api.h +++ b/source/blender/blenfont/BLF_api.h @@ -47,6 +47,7 @@ void BLF_exit(void); void BLF_default_dpi(int dpi); void BLF_default_set(int fontid); int BLF_default(void); /* get default font ID so we can pass it to other functions */ +void BLF_batch_reset(void); /* call when changing opengl context. */ void BLF_antialias_set(bool enabled); bool BLF_antialias_get(void); diff --git a/source/blender/blenfont/intern/blf.c b/source/blender/blenfont/intern/blf.c index 30919f1acda..5b51ecbc047 100644 --- a/source/blender/blenfont/intern/blf.c +++ b/source/blender/blenfont/intern/blf.c @@ -132,6 +132,11 @@ void BLF_exit(void) blf_font_exit(); } +void BLF_batch_reset(void) +{ + blf_batching_vao_clear(); +} + void BLF_cache_clear(void) { FontBLF *font; @@ -561,8 +566,11 @@ static void blf_draw_gl__start(FontBLF *font) * in BLF_position (old ui_rasterpos_safe). */ - glEnable(GL_BLEND); - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + /* 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. */ gpuPushMatrix(); @@ -576,35 +584,12 @@ static void blf_draw_gl__start(FontBLF *font) if (font->flags & BLF_ROTATION) gpuRotate2D(RAD2DEG(font->angle)); - -#ifndef BLF_STANDALONE - Gwn_VertFormat *format = immVertexFormat(); - unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 4, GWN_FETCH_FLOAT); - unsigned int texCoord = GWN_vertformat_attr_add(format, "tex", GWN_COMP_F32, 4, GWN_FETCH_FLOAT); - unsigned int color = GWN_vertformat_attr_add(format, "col", GWN_COMP_U8, 4, GWN_FETCH_INT_TO_FLOAT_UNIT); - - BLI_assert(pos == BLF_POS_ID); - BLI_assert(texCoord == BLF_COORD_ID); - BLI_assert(color == BLF_COLOR_ID); - - UNUSED_VARS_NDEBUG(pos, texCoord, color); - - immBindBuiltinProgram(GPU_SHADER_TEXT); -#endif - - /* always bind the texture for the first glyph */ - font->tex_bind_state = -1; } -static void blf_draw_gl__end(void) +static void blf_draw_gl__end(FontBLF *font) { - gpuPopMatrix(); - -#ifndef BLF_STANDALONE - immUnbindProgram(); -#endif - - glDisable(GL_BLEND); + if ((font->flags & (BLF_ROTATION | BLF_MATRIX | BLF_ASPECT)) != 0) + gpuPopMatrix(); } void BLF_draw_ex( @@ -623,7 +608,7 @@ void BLF_draw_ex( else { blf_font_draw(font, str, len, r_info); } - blf_draw_gl__end(); + blf_draw_gl__end(font); } } void BLF_draw(int fontid, const char *str, size_t len) @@ -652,7 +637,7 @@ void BLF_draw_ascii_ex( else { blf_font_draw_ascii(font, str, len, r_info); } - blf_draw_gl__end(); + blf_draw_gl__end(font); } } void BLF_draw_ascii(int fontid, const char *str, size_t len) @@ -676,7 +661,7 @@ int BLF_draw_mono(int fontid, const char *str, size_t len, int cwidth) if (font && font->glyph_cache) { blf_draw_gl__start(font); columns = blf_font_draw_mono(font, str, len, cwidth); - blf_draw_gl__end(); + blf_draw_gl__end(font); } return columns; diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c index 1f304d208e6..868d8eb775e 100644 --- a/source/blender/blenfont/intern/blf_font.c +++ b/source/blender/blenfont/intern/blf_font.c @@ -59,6 +59,8 @@ #include "BLF_api.h" #include "GPU_immediate.h" +#include "GPU_matrix.h" +#include "GPU_batch.h" #include "blf_internal_types.h" #include "blf_internal.h" @@ -69,12 +71,104 @@ # define FT_New_Face FT_New_Face__win32_compat #endif +/* Batching buffer for drawing. */ +BatchBLF g_batch; + /* freetype2 handle ONLY for this file!. */ static FT_Library ft_lib; static SpinLock ft_lib_mutex; +/* -------------------------------------------------------------------- */ +/** \name Glyph Batching + * \{ */ +/** + * Drawcalls are precious! make them count! + * Since most of the Text elems are not covered by other UI elements, we can + * group some strings together and render them in one drawcall. This behaviour + * is on demand only, between BLF_batch_start() and BLF_batch_end(). + **/ +static void blf_batching_init(void) +{ + Gwn_VertFormat format = {0}; + g_batch.pos_loc = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 4, GWN_FETCH_FLOAT); + g_batch.tex_loc = GWN_vertformat_attr_add(&format, "tex", GWN_COMP_F32, 4, GWN_FETCH_FLOAT); + g_batch.col_loc = GWN_vertformat_attr_add(&format, "col", GWN_COMP_U8, 4, GWN_FETCH_INT_TO_FLOAT_UNIT); + + g_batch.verts = GWN_vertbuf_create_with_format_ex(&format, GWN_USAGE_STREAM); + GWN_vertbuf_data_alloc(g_batch.verts, BLF_BATCHING_SIZE); + + g_batch.batch = GWN_batch_create_ex(GWN_PRIM_POINTS, g_batch.verts, NULL, GWN_BATCH_OWNS_VBO); +} + +static void blf_batching_exit(void) +{ + GWN_BATCH_DISCARD_SAFE(g_batch.batch); +} + +void blf_batching_vao_clear(void) +{ + if (g_batch.batch) { + gwn_batch_vao_cache_clear(g_batch.batch); + } +} + +void blf_batching_start(FontBLF *font) +{ + if (g_batch.batch == NULL) { + blf_batching_init(); + } + + zero_v2(g_batch.ofs); + if ((font->flags & (BLF_ROTATION | BLF_MATRIX | BLF_ASPECT)) == 0) { + copy_v2_v2(g_batch.ofs, font->pos); + } + + /* restart to 1st vertex data pointers */ + GWN_vertbuf_attr_get_raw_data(g_batch.verts, g_batch.pos_loc, &g_batch.pos_step); + GWN_vertbuf_attr_get_raw_data(g_batch.verts, g_batch.tex_loc, &g_batch.tex_step); + GWN_vertbuf_attr_get_raw_data(g_batch.verts, g_batch.col_loc, &g_batch.col_step); + g_batch.glyph_ct = 0; + g_batch.font = font; +} + +void blf_batching_draw(void) +{ + if (g_batch.glyph_ct == 0) + return; + + glEnable(GL_BLEND); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + + BLI_assert(g_batch.font->tex_bind_state != 0); /* must still be valid */ + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, g_batch.font->tex_bind_state); + + GWN_vertbuf_vertex_count_set(g_batch.verts, g_batch.glyph_ct); + GWN_vertbuf_use(g_batch.verts); /* send data */ + + GWN_batch_program_set_builtin(g_batch.batch, GPU_SHADER_TEXT); + GWN_batch_uniform_1i(g_batch.batch, "glyph", 0); + GWN_batch_draw(g_batch.batch); + + glDisable(GL_BLEND); + + g_batch.glyph_ct = 0; +} + +static void blf_batching_end(void) +{ + if (!g_batch.enabled) { + blf_batching_draw(); + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ + int blf_font_init(void) { + memset(&g_batch, 0, sizeof(g_batch)); BLI_spin_init(&ft_lib_mutex); return FT_Init_FreeType(&ft_lib); } @@ -83,6 +177,7 @@ void blf_font_exit(void) { FT_Done_FreeType(ft_lib); BLI_spin_end(&ft_lib_mutex); + blf_batching_exit(); } void blf_font_size(FontBLF *font, unsigned int size, unsigned int dpi) @@ -174,24 +269,6 @@ static void blf_font_ensure_ascii_table(FontBLF *font) } \ } (void)0 -static unsigned int verts_needed(const FontBLF *font, const char *str, size_t len) -{ - size_t str_len = (len > 50) ? strlen(str) : INT_MAX; /* Arbitrary. */ - unsigned int length = (unsigned int)MIN2(str_len, len); - unsigned int quad_ct = 1; - - if (font->flags & BLF_SHADOW) { - if (font->shadow == 0) - quad_ct += 1; - if (font->shadow <= 4) - quad_ct += 9; /* 3x3 kernel */ - else - quad_ct += 25; /* 5x5 kernel */ - } - - return length * quad_ct; /* Only one vert per quad */ -} - static void blf_font_draw_ex( FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info, int pen_y) @@ -212,8 +289,7 @@ static void blf_font_draw_ex( blf_font_ensure_ascii_table(font); - immBeginAtMost(GWN_PRIM_POINTS, verts_needed(font, str, len)); - /* at most because some glyphs might be clipped & not drawn */ + blf_batching_start(font); while ((i < len) && str[i]) { BLF_UTF8_NEXT_FAST(font, g, str, i, c, glyph_ascii_table); @@ -232,7 +308,7 @@ static void blf_font_draw_ex( g_prev = g; } - immEnd(); + blf_batching_end(); if (r_info) { r_info->lines = 1; @@ -259,7 +335,7 @@ static void blf_font_draw_ascii_ex( blf_font_ensure_ascii_table(font); - immBeginAtMost(GWN_PRIM_POINTS, verts_needed(font, str, len)); + blf_batching_start(font); while ((c = *(str++)) && len--) { BLI_assert(c < 128); @@ -275,7 +351,7 @@ static void blf_font_draw_ascii_ex( g_prev = g; } - immEnd(); + blf_batching_end(); if (r_info) { r_info->lines = 1; @@ -299,7 +375,7 @@ int blf_font_draw_mono(FontBLF *font, const char *str, size_t len, int cwidth) blf_font_ensure_ascii_table(font); - immBeginAtMost(GWN_PRIM_POINTS, verts_needed(font, str, len)); + blf_batching_start(font); while ((i < len) && str[i]) { BLF_UTF8_NEXT_FAST(font, g, str, i, c, glyph_ascii_table); @@ -320,7 +396,7 @@ int blf_font_draw_mono(FontBLF *font, const char *str, size_t len, int cwidth) pen_x += cwidth * col; } - immEnd(); + blf_batching_end(); return columns; } diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c index 5e1debf1501..b91eceac817 100644 --- a/source/blender/blenfont/intern/blf_glyph.c +++ b/source/blender/blenfont/intern/blf_glyph.c @@ -63,6 +63,7 @@ #include "blf_internal.h" #include "BLI_strict_flags.h" +#include "BLI_math_vector.h" GlyphCacheBLF *blf_glyph_cache_find(FontBLF *font, unsigned int size, unsigned int dpi) { @@ -316,13 +317,19 @@ void blf_glyph_free(GlyphBLF *g) MEM_freeN(g); } -static void blf_texture_draw(const unsigned char color[4], float uv[2][2], float dx, float y1, float dx1, float y2) +static void blf_texture_draw(const unsigned char color[4], float uv[2][2], float x1, float y1, float x2, float y2) { + if (g_batch.glyph_ct == BLF_BATCHING_SIZE) { + blf_batching_draw(); + blf_batching_start(g_batch.font); + } + g_batch.glyph_ct++; /* 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 */ - immAttrib4ubv(BLF_COLOR_ID, color); - immAttrib4fv(BLF_COORD_ID, (float *)uv); - immVertex4f(BLF_POS_ID, dx, y1, dx1, y2); + copy_v4_fl4(GWN_vertbuf_raw_step(&g_batch.pos_step), x1 + g_batch.ofs[0], y1 + g_batch.ofs[1], + x2 + g_batch.ofs[0], y2 + g_batch.ofs[1]); + copy_v4_v4(GWN_vertbuf_raw_step(&g_batch.tex_step), (float *)uv); + copy_v4_v4_uchar(GWN_vertbuf_raw_step(&g_batch.col_step), color); } static void blf_texture5_draw(const unsigned char color_in[4], float uv[2][2], float x1, float y1, float x2, float y2) diff --git a/source/blender/blenfont/intern/blf_internal.h b/source/blender/blenfont/intern/blf_internal.h index ba17e050399..c9ea8c3323b 100644 --- a/source/blender/blenfont/intern/blf_internal.h +++ b/source/blender/blenfont/intern/blf_internal.h @@ -37,10 +37,9 @@ struct GlyphBLF; struct GlyphCacheBLF; struct rctf; -/* vertex attribute IDs (fixed IDs so we don't have to pass them around) */ -#define BLF_POS_ID 0 -#define BLF_COORD_ID 1 -#define BLF_COLOR_ID 2 +void blf_batching_vao_clear(void); +void blf_batching_start(struct FontBLF *font); +void blf_batching_draw(void); unsigned int blf_next_p2(unsigned int x); unsigned int blf_hash(unsigned int val); diff --git a/source/blender/blenfont/intern/blf_internal_types.h b/source/blender/blenfont/intern/blf_internal_types.h index 9164a02b2cc..360aae47dd0 100644 --- a/source/blender/blenfont/intern/blf_internal_types.h +++ b/source/blender/blenfont/intern/blf_internal_types.h @@ -31,6 +31,24 @@ #ifndef __BLF_INTERNAL_TYPES_H__ #define __BLF_INTERNAL_TYPES_H__ +#include "../../../intern/gawain/gawain/gwn_vertex_buffer.h" + +#define BLF_BATCHING_SIZE 2048 /* in glyph */ + +typedef struct BatchBLF{ + struct FontBLF *font; /* can only batch glyph from the same font */ + struct Gwn_Batch *batch; + struct Gwn_VertBuf *verts; + struct Gwn_VertBufRaw pos_step, tex_step, col_step; + unsigned int pos_loc, tex_loc, col_loc; + unsigned int glyph_ct; + float ofs[2]; /* copy of font->pos */ + float mat[4][4]; /* to catch bad usage */ + bool enabled; +} BatchBLF; + +extern BatchBLF g_batch; + typedef struct GlyphCacheBLF { struct GlyphCacheBLF *next; struct GlyphCacheBLF *prev; diff --git a/source/blender/gpu/GPU_batch.h b/source/blender/gpu/GPU_batch.h index fda24018150..52cf37a7457 100644 --- a/source/blender/gpu/GPU_batch.h +++ b/source/blender/gpu/GPU_batch.h @@ -40,6 +40,7 @@ struct rctf; // #include "gawain/batch.h" #include "BLI_compiler_attrs.h" +#include "BLI_sys_types.h" #include "GPU_shader.h" diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index 2ed16dd20db..14376b1bbb1 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -519,6 +519,7 @@ void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win) } if (tmpwin) { + BLF_batch_reset(); gpu_batch_presets_reset(); immDeactivate(); } @@ -1168,6 +1169,7 @@ void wm_window_make_drawable(wmWindowManager *wm, wmWindow *win) printf("%s: set drawable %d\n", __func__, win->winid); } + BLF_batch_reset(); gpu_batch_presets_reset(); immDeactivate(); GHOST_ActivateWindowDrawingContext(win->ghostwin); @@ -1192,6 +1194,7 @@ void wm_window_reset_drawable(void) wmWindow *win = wm->windrawable; if (win && win->ghostwin) { + BLF_batch_reset(); gpu_batch_presets_reset(); immDeactivate(); GHOST_ActivateWindowDrawingContext(win->ghostwin);