BLF: Add Batching capabilities.

You can now use BLF_batching_start and BLF_batching_end to batch every
drawcall to BLF together minimizing the overhead introduced by BLF and the
opengl driver.

These calls cannot be nested (for now).

If the modelview matrix changes, previously batched calls are issued and a
the process resume with the new matrix.

However the projection matrix MUST not change and gl scissors as well.
This commit is contained in:
Clément Foucault 2018-03-30 20:59:45 +02:00
parent fb1463ff2b
commit 963e48e1df
5 changed files with 79 additions and 16 deletions

View File

@ -95,6 +95,11 @@ void BLF_color3fv_alpha(int fontid, const float rgb[3], float alpha);
*/
void BLF_matrix(int fontid, const float m[16]);
/* Batch drawcalls together as long as
* the modelview matrix and the font remain unchanged. */
void BLF_batching_start(void);
void BLF_batching_end(void);
/* Draw the string using the default font, size and dpi. */
void BLF_draw_default(float x, float y, float z, const char *str, size_t len) ATTR_NONNULL();
void BLF_draw_default_ascii(float x, float y, float z, const char *str, size_t len) ATTR_NONNULL();

View File

@ -540,6 +540,19 @@ void BLF_color3f(int fontid, float r, float g, float b)
BLF_color4fv(fontid, rgba);
}
void BLF_batching_start(void)
{
BLI_assert(g_batch.enabled == false);
g_batch.enabled = true;
}
void BLF_batching_end(void)
{
BLI_assert(g_batch.enabled == true);
blf_batching_draw(); /* Draw remaining glyphs */
g_batch.enabled = false;
}
void BLF_draw_default(float x, float y, float z, const char *str, size_t len)
{
ASSERT_DEFAULT_SET;

View File

@ -97,6 +97,11 @@ static void blf_batching_init(void)
g_batch.verts = GWN_vertbuf_create_with_format_ex(&format, GWN_USAGE_STREAM);
GWN_vertbuf_data_alloc(g_batch.verts, BLF_BATCHING_SIZE);
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.batch = GWN_batch_create_ex(GWN_PRIM_POINTS, g_batch.verts, NULL, GWN_BATCH_OWNS_VBO);
}
@ -118,17 +123,53 @@ void blf_batching_start(FontBLF *font)
blf_batching_init();
}
zero_v2(g_batch.ofs);
if ((font->flags & (BLF_ROTATION | BLF_MATRIX | BLF_ASPECT)) == 0) {
const bool font_changed = (g_batch.font != font);
g_batch.font = font;
const bool manual_ofs_active = ((font->flags & (BLF_ROTATION | BLF_MATRIX | BLF_ASPECT)) == 0);
g_batch.active = g_batch.enabled && manual_ofs_active;
if (manual_ofs_active) {
/* Offset is applied to each glyph. */
copy_v2_v2(g_batch.ofs, font->pos);
}
else {
/* Offset is baked in modelview mat. */
zero_v2(g_batch.ofs);
}
/* 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;
if (g_batch.active) {
float gpumat[4][4];
gpuGetModelViewMatrix(gpumat);
bool mat_changed = (memcmp(gpumat, g_batch.mat, sizeof(g_batch.mat)) != 0);
/* Save for next memcmp. */
memcpy(g_batch.mat, gpumat, sizeof(g_batch.mat));
if (mat_changed) {
/* Modelviewmat is no longer the same.
* Flush cache but with the previous mat. */
gpuPushMatrix();
gpuLoadMatrix(g_batch.mat);
}
/* flush cache if config is not the same. */
if (mat_changed || font_changed) {
blf_batching_draw();
}
else {
/* Nothing changed continue batching. */
return;
}
if (mat_changed) {
gpuPopMatrix();
}
}
else {
/* flush cache */
blf_batching_draw();
}
}
void blf_batching_draw(void)
@ -152,12 +193,16 @@ void blf_batching_draw(void)
glDisable(GL_BLEND);
/* 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;
}
static void blf_batching_end(void)
{
if (!g_batch.enabled) {
if (!g_batch.active) {
blf_batching_draw();
}
}

View File

@ -319,17 +319,17 @@ void blf_glyph_free(GlyphBLF *g)
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 */
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);
g_batch.glyph_ct++;
/* Flush cache if it's full. */
if (g_batch.glyph_ct == BLF_BATCHING_SIZE) {
blf_batching_draw();
}
}
static void blf_texture5_draw(const unsigned char color_in[4], float uv[2][2], float x1, float y1, float x2, float y2)

View File

@ -43,8 +43,8 @@ typedef struct BatchBLF{
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;
float mat[4][4]; /* previous call modelmatrix. */
bool enabled, active;
} BatchBLF;
extern BatchBLF g_batch;