c++ - FreeType OpenGL dynamic Text = abysmal performance -
i'm searching bottlenecks in code , turns out gui 1 of them. well, not gui rather dynamic text drawn there.
initialization
if (ft_init_freetype(&m_freetype)) throw helpers::exceptionwithmsg("could not init freetype lib"); if (ft_new_face(m_freetype, "res\\fonts\\freesans.ttf", 0, &m_fontface)) throw helpers::exceptionwithmsg("could not open font"); m_shaderid = ... // loads corresponding shader m_textcolorlocation = glgetuniformlocation(m_shaderid, "color"); m_coordinateslocation = glgetattriblocation(m_shaderid, "coord"); glgenbuffers(1, &m_vbo); ft_set_pixel_sizes(m_fontface, 0, m_fontsize); glyph = m_fontface->glyph; glgentextures(1, &m_texture); glactivetexture(gl_texture0); glbindtexture(gl_texture_2d, m_texture); // require 1 byte alignment when uploading texture data glpixelstorei(gl_unpack_alignment, 1); // linear filtering looks best text gltexparameteri(gl_texture_2d, gl_texture_min_filter, gl_linear); gltexparameteri(gl_texture_2d, gl_texture_mag_filter, gl_linear); // clamping edges important prevent artifacts when scaling gltexparameteri(gl_texture_2d, gl_texture_wrap_s, gl_clamp_to_edge); gltexparameteri(gl_texture_2d, gl_texture_wrap_t, gl_clamp_to_edge); gluseprogram(m_shaderid); gluniform4f(m_textcolorlocation, m_textcolor.x, m_textcolor.y, m_textcolor.z, m_textcolor.w); gluseprogram(0);
what do: initialize freetype, font, initialize shader , uniforms.
then create vbo texturecoordinates, set pixels font, glyph.
now generate texture, activate it, bind it... want set parameters , uniform never changes.
rendering:
gluseprogram(m_shaderid); glenable(gl_blend); glblendfunc(gl_src_alpha, gl_one_minus_src_alpha); glactivetexture(gl_texture0); glbindtexture(gl_texture_2d, m_texture); // linear filtering looks best text gltexparameteri(gl_texture_2d, gl_texture_min_filter, gl_linear); gltexparameteri(gl_texture_2d, gl_texture_mag_filter, gl_linear); // set vbo our vertex data glenablevertexattribarray(m_coordinateslocation); glbindbuffer(gl_array_buffer, m_vbo); glvertexattribpointer(m_coordinateslocation, 4, gl_float, gl_false, 0, 0); glfloat cursorposx = m_x; glfloat cursorposy = m_y; (size_t = 0; < m_text.size(); ++i) { // if loading char fails, continue if (ft_load_char(m_fontface, m_text[i], ft_load_render)) continue; glteximage2d(gl_texture_2d, 0, gl_alpha, glyph->bitmap.width, glyph->bitmap.rows, 0, gl_alpha, gl_unsigned_byte, glyph->bitmap.buffer); // calculate vertex , texture coordinates glfloat x2 = cursorposx + glyph->bitmap_left * m_sx; glfloat y2 = -cursorposy - glyph->bitmap_top * m_sy; glfloat w = glyph->bitmap.width * m_sx; glfloat h = glyph->bitmap.rows * m_sy; pointstruct box[4] = { { x2, -y2, 0, 0 }, { x2 + w, -y2, 1, 0 }, { x2, -y2 - h, 0, 1 }, { x2 + w, -y2 - h, 1, 1 } }; // draw character on screen glbufferdata(gl_array_buffer, sizeof box, box, gl_dynamic_draw); gldrawarrays(gl_triangle_strip, 0, 4); // advance cursor start of next character cursorposx += glyph->advance.x / 64 * m_sx; cursorposy += glyph->advance.y / 64 * m_sy; } gldisablevertexattribarray(m_coordinateslocation); gldeletetextures(1, &m_texture); gldisable(gl_blend); gluseprogram(0);
setting shader , stuff obvious.
for each render call activate texture, bind it, enable vbo store texturecoordinates in. iterate on every character in text load ft_load_char. specify texture glteximage2d, calculate vertex , texture coordinates , draw everything.
that seems highly inefficient, find no way improve performance , yet have readable text.
i wanted set text parameters once in init -> chars boxes.
i wanted set gl_dynamic_draw gl_static_draw... not difference. else can do?
the text render dynamic, changes (or may change) each frame, i'm kind of stuck.
i query performance of stuff query. if not render dynamic text it's low, if render dynamic text gets high... there not else going on in pass, it's drawing gui.
what bothers me
one thing don't understand (may sunny day...)
if not set linear filtering in render-method() strange cube-glyphs, why that? opengl state machine, texture-parameters set 1 bound. if set min , mag filter gl_linear in initialization why isn't enough?
if remove 2 lines in render way better performance query (much lower numbers), doesn't drawn readable.
this absolutely going slow.
for each render call activate texture, bind it, enable vbo store texturecoordinates in. iterate on every character in text load ft_load_char. specify texture glteximage2d, calculate vertex , texture coordinates , draw everything.
the problem, unfortunately, hard. here method use:
there 1 texture,
gl_red8
format, stores glyphs.whenever new glyph needed, added texture. done calling
ft_render_glyph()
, copying result texture buffer. if new glyph doesn't fit, whole glyph texture resized , repacked. (i use skyline algorithm packing glyphs since it's simple.)if new glyphs have been added, call
gltexsubimage2d()
. code should structured called once per frame.to render text, create vbo contains vertex , texture coordinates quads necessary render piece of text. (please understand "quad" means 2 triangles, not
gl_quad
).
so, when change text want render,
you have update vbo, once per frame
you might have update texture, once per frame, , happen less glyph texture fills glyphs use.
a way prototype kind of system render all of glyphs in font texture @ first, doesn't work if end using multiple fonts , styles, or if want render chinese, korean, or japanese text.
additional considerations line breaking, glyph substitution, kerning, bidi, general problems international text, how specify styling, et cetera. recommend using harfbuzz in combination freetype. harfbuzz handles difficult glyph substitution , positioning issues. none of strictly necessary if program has english text only.
there libraries of this, have not used them.
an alternative method, if want cut gordian knot, embed web browser chromium (awesomium, webkit, gecko—many choices) in application, , farm out text rendering that.
Comments
Post a Comment