• Advertisement
Sign in to follow this  

OpenGL [Solved] Rendering text hits fps - hard.

This topic is 2880 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

So I'm using opengl, wgl and c++ to render text. The code makes a call to glCallLists to render the text - so it shouldn't be too slow, right? Wrong. Has a rotating skybox (6 quads, 6 textures, texture size 1024x1024, linear filter), and 1/2/3 characters of text drawn in colour at the top right (represents fps). At this point, fps is between 70 and 90. Uh oh. Draw some untextured quads and lines (I tried just the console without text, it has no fps hit) and a whole bunch more text, fps down to a persistent 2. Not good. Here is the relevant code: The calls are made from Lua into c++, but I don't think the problem lies there as I'm also making tonnes of other calls (like drawing each line, each quad) that are still being made back when fps is up at 80. Just to put this in perspective, when I render 3x3 segments of terrain at the same time (each segment is 64x64 quads, textured, with lighting), fps is about 20. Surely rendering some simple text can't be more intensive than rendering a full 3D terrain with lighting? Here is the text code:
// Include header
#include "text.h"

// Define functions
int font_create( char* family, int size, int weight ) {
	HFONT font;
	HFONT oldfont;

	HDC hDC = GetHDC();

	int base = glGenLists( 96 );
	font = CreateFont( -size, 0, 0, 0, weight, false, false, false, 
		ANSI_CHARSET, OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY,
		FF_DONTCARE | DEFAULT_PITCH, family );
	oldfont = (HFONT)SelectObject( hDC, font );
	wglUseFontBitmaps( hDC, 32, 96, base );
	SelectObject( hDC, oldfont );
	DeleteObject( font );

	return base;
}

void font_destroy( int id ) {
	glDeleteLists( id, 96 );
}

void font_render_noraster( char* text, int id ) {
	glPushAttrib( GL_LIST_BIT );
	glListBase( id-32 );
	glCallLists( strlen( text ), GL_UNSIGNED_BYTE, text );
	glPopAttrib();
}

void font_render( char* text, int id, int x, int y ) {
	glRasterPos2f( float( x ), float( y ) );
	font_render_noraster( text, id );
}

int font_getwidth( char* text, int id ) {

	GLint oldbuffer;
	glGetIntegerv( GL_DRAW_BUFFER, &oldbuffer );
	glDrawBuffer( GL_NONE );

	GLfloat o_rpos[4];
	glGetFloatv( GL_CURRENT_RASTER_POSITION, o_rpos );

	font_render_noraster( text, id );

	GLfloat n_rpos[4];
	glGetFloatv( GL_CURRENT_RASTER_POSITION, n_rpos );

	glDrawBuffer( oldbuffer );

	return int( n_rpos[0] - o_rpos[0] );
}

Here is the lua binding:
static int lbind_r_rendertext( lua_State* L ) {
	char* text = const_cast<char*>( luaL_checkstring( L, 1 ) );
	int base = luaL_checkint( L, 2 );
	int x = luaL_checkint( L, 3 );
	int y = luaL_checkint( L, 4 );
	font_render( text, base, x, y );
	return 0;
}

Perhaps it doesn't like the const_cast much? Any ideas? [Edited by - thomasfn1 on April 1, 2010 2:03:54 PM]

Share this post


Link to post
Share on other sites
Advertisement
Can you try a profiler or something to see if there is something obvious causing that perf hit? I use a similar method to render text and I've never seen any kind of performance hit from it.

I think something else has to be going on, because that shouldn't be that slow, unless you're calling font_create every frame or something.

Share this post


Link to post
Share on other sites
I'll do some more debugging to see if something silly like font_create being called every frame is happening. I'm not sure on the best way of implementing a profiler, I guess I could make something that records time differences between operations and writes it to the log but it isn't practical (especially since what gets written to the log gets written to that console too :P)

I also tried not casting into char* at the lua binding and keeping it as const char* and passing that into glCallLists instead, had no effect.

Edit:
font_create is getting called once, at the beginning of the program, as expected.

And who uses html in forum code anyways -_-

Share this post


Link to post
Share on other sites
Thanks - suitable name methinks. I'll have a go now - but I'll have to go soon, so I might not get back to you until tommorow.

Edit:

I ran it over a 10 second period, with the console rendering all the text.

Profiler Result

I'm not sure what it all means :/

Share this post


Link to post
Share on other sites
You could use GetTextExtentExPoint for getting the text width....
Just make sure to set the active font.

Share this post


Link to post
Share on other sites
Anyone got any more ideas? I replaced the text size calculation code with GetTextExtentPoint, it apparently works, nothing's moved off to weird places. But I'm still having problems with the fps levels.

Share this post


Link to post
Share on other sites
Where is your code to actually create the display list(glNewList)? I'd guess something odd maybe happening in there...

Share this post


Link to post
Share on other sites
As soon as I saw "glRasterPos2f" alarm bells started ringing and so I have an idea; don't use wglUseFontBitmaps to generate your text.

A quick look at the MSDN page on it hightlights the problem;
Quote:

Each display list consists of a single call to glBitmap


That is going to be a killer. The function is old and is going to hurt as its probably poorly optimised/implimented in modern systems, not to mention it probably sends a bitmap over the bus to the card for every call, even in a display list its not going to be fast.

The fastest way to render text is to create a texture with each character on (or more than one texture in the case of larger fonts), then build the list of tris or quads which access this texture at the right point to grab the letters and render them to the screen; it will be faster.

  • Instead of wglUseFontBitmaps maybe try wglUseFontOutlines? I use that currently and I've never noticed any slowdown from it. I've tried building my own text from a character map texture, but I always thought that looked like crap unless I used a huge texture to store the text (either too jagged or too blurred with AA)

    Heres a setup test you can quickly drop in to test to see if its any faster for you.


    void GfxOpenGL::BuildOutlineFont(){

    HFONT font;
    base_ = glGenLists(256);
    font = CreateFont( -24, // Height Of Font
    0, // Width Of Font
    0, // Angle Of Escapement
    0, // Orientation Angle
    400, // Font Weight
    FALSE, // Italic
    FALSE, // Underline
    FALSE, // Strikeout
    ANSI_CHARSET, // Character Set Identifier
    OUT_TT_PRECIS, // Output Precision
    CLIP_DEFAULT_PRECIS, // Clipping Precision
    0, // Output Quality
    FF_DONTCARE|DEFAULT_PITCH, // Family And Pitch
    "Arial"); // Font Name


    SelectObject(hDC,font);
    wglUseFontOutlines( hDC, // Select The Current DC
    0, // Starting Character
    255, // Number Of Display Lists To Build
    base_, // Starting Display Lists
    0.8f, // Deviation From The True Outlines
    0.2f, // Font Thickness In The Z Direction
    WGL_FONT_POLYGONS, // Use Polygons, Not Lines
    gmf); // Address Of Buffer To Recieve Data


    }

    Share this post


    Link to post
    Share on other sites
    I use the wglUseFontBitmaps method on a pretty recent card.

    About 1000 glyphs displayed: 100 fps to 80 fps drop.

    Nowhere near the 70-2 stuff. That old and nasty ugly bitmap/displaylist stuff should work much faster.

    Share this post


    Link to post
    Share on other sites
    I'm working on a pretty old laptop: 768mb ram, 2.8ghz single core, ati radeon mobility 7000. But still, the drop is ridiculous. I've been messing with using texture mapped fonts, once I get the damn thing to compile, I'll see how that works out. I'll try the outlined fonts in a sec.

    Edit:
    Probably something todo with that glyph metrics float structure thing.

    Share this post


    Link to post
    Share on other sites
    Ok so nevermind that error - I just allocated the structure to the heap and stopped that error. But then, as soon as the code returns out of that function, it gives me debug assertion failure (with no information). I'm also giving up on the bitmapped fonts, as that's giving me random debug assertion failures all over the place - when returning stuff from functions mostly.

    I'm really at a loss here :(

    Edit:
    I am an idiot. You pass an array to that function.

    Ok now it compiles and runs with the Outlines. But rendering text now glitches up everything; the only thing that renders is my console window and a few random lines, and there are some inexplicable dots at the top of the screen. I suspect the lists generated contains some translation call that's messing stuff up; I'll investigate. Thanks for your help guys.

    Edit2:
    Wrapping the list call in PushMatrix and PopMatrix doesn't work.

    Share this post


    Link to post
    Share on other sites
    Just a quick observation..

    glListBase( id-32 );
    glCallLists( strlen( text ), GL_UNSIGNED_BYTE, text );


    You can sub 32 from id after creation and add 32 before deletion.
    That way to save a couple of clocks, but the real killer is strlen.
    (Besides all the hidden code of course)

    I wrote a couple of font rendering method tests in assembler...
    (You need to register/logon to download source files)
    http://board.flatassembler.net/topic.php?t=9885

    Share this post


    Link to post
    Share on other sites
    You should use this tutorial from nehe instead, the fonts looks ways better, and the best is they can scale if ur willing to tweak the code a bit. Im using it in my engine and don't see any performance hit like i did with the wglUseFontBitmaps method.

    Share this post


    Link to post
    Share on other sites
    Quote:
    Original post by Vortez
    You should use this tutorial from nehe instead, the fonts looks ways better, and the best is they can scale if ur willing to tweak the code a bit. Im using it in my engine and don't see any performance hit like i did with the wglUseFontBitmaps method.


    Yea I had a look at that tutorial and got as far as downloading freetype and linking it before I got distracted with something else. I'll have a crack at implementing it if UseFontOutlines fails me.

    Share this post


    Link to post
    Share on other sites
    Ok I took a stab at implementing freetype. Good news is, framerate is now up nice and high. Bad news is:

    Share this post


    Link to post
    Share on other sites
    Good news! I got it to work! Thanks guys for all your help.

    In case someone wants to know, I had all the font handling code in a class and I wasn't allocating the class objects to the heap so bits of the class memory were getting used for other things. Including the list base.

    Share this post


    Link to post
    Share on other sites
    Sign in to follow this  

    • Advertisement
    • Advertisement
    • Popular Tags

    • Advertisement
    • Popular Now

    • Similar Content

      • By LifeArtist
        Good Evening,
        I want to make a 2D game which involves displaying some debug information. Especially for collision, enemy sights and so on ...
        First of I was thinking about all those shapes which I need will need for debugging purposes: circles, rectangles, lines, polygons.
        I am really stucked right now because of the fundamental question:
        Where do I store my vertices positions for each line (object)? Currently I am not using a model matrix because I am using orthographic projection and set the final position within the VBO. That means that if I add a new line I would have to expand the "points" array and re-upload (recall glBufferData) it every time. The other method would be to use a model matrix and a fixed vbo for a line but it would be also messy to exactly create a line from (0,0) to (100,20) calculating the rotation and scale to make it fit.
        If I proceed with option 1 "updating the array each frame" I was thinking of having 4 draw calls every frame for the lines vao, polygons vao and so on. 
        In addition to that I am planning to use some sort of ECS based architecture. So the other question would be:
        Should I treat those debug objects as entities/components?
        For me it would make sense to treat them as entities but that's creates a new issue with the previous array approach because it would have for example a transform and render component. A special render component for debug objects (no texture etc) ... For me the transform component is also just a matrix but how would I then define a line?
        Treating them as components would'nt be a good idea in my eyes because then I would always need an entity. Well entity is just an id !? So maybe its a component?
        Regards,
        LifeArtist
      • By QQemka
        Hello. I am coding a small thingy in my spare time. All i want to achieve is to load a heightmap (as the lowest possible walking terrain), some static meshes (elements of the environment) and a dynamic character (meaning i can move, collide with heightmap/static meshes and hold a varying item in a hand ). Got a bunch of questions, or rather problems i can't find solution to myself. Nearly all are deal with graphics/gpu, not the coding part. My c++ is on high enough level.
        Let's go:
        Heightmap - i obviously want it to be textured, size is hardcoded to 256x256 squares. I can't have one huge texture stretched over entire terrain cause every pixel would be enormous. Thats why i decided to use 2 specified textures. First will be a tileset consisting of 16 square tiles (u v range from 0 to 0.25 for first tile and so on) and second a 256x256 buffer with 0-15 value representing index of the tile from tileset for every heigtmap square. Problem is, how do i blend the edges nicely and make some computationally cheap changes so its not obvious there are only 16 tiles? Is it possible to generate such terrain with some existing program?
        Collisions - i want to use bounding sphere and aabb. But should i store them for a model or entity instance? Meaning i have 20 same trees spawned using the same tree model, but every entity got its own transformation (position, scale etc). Storing collision component per instance grats faster access + is precalculated and transformed (takes additional memory, but who cares?), so i stick with this, right? What should i do if object is dynamically rotated? The aabb is no longer aligned and calculating per vertex min/max everytime object rotates/scales is pretty expensive, right?
        Drawing aabb - problem similar to above (storing aabb data per instance or model). This time in my opinion per model is enough since every instance also does not have own vertex buffer but uses the shared one (so 20 trees share reference to one tree model). So rendering aabb is about taking the model's aabb, transforming with instance matrix and voila. What about aabb vertex buffer (this is more of a cosmetic question, just curious, bumped onto it in time of writing this). Is it better to make it as 8 points and index buffer (12 lines), or only 2 vertices with min/max x/y/z and having the shaders dynamically generate 6 other vertices and draw the box? Or maybe there should be just ONE 1x1x1 cube box template moved/scaled per entity?
        What if one model got a diffuse texture and a normal map, and other has only diffuse? Should i pass some bool flag to shader with that info, or just assume that my game supports only diffuse maps without fancy stuff?
        There were several more but i forgot/solved them at time of writing
        Thanks in advance
      • By RenanRR
        Hi All,
        I'm reading the tutorials from learnOpengl site (nice site) and I'm having a question on the camera (https://learnopengl.com/Getting-started/Camera).
        I always saw the camera being manipulated with the lookat, but in tutorial I saw the camera being changed through the MVP arrays, which do not seem to be camera, but rather the scene that changes:
        Vertex Shader:
        #version 330 core layout (location = 0) in vec3 aPos; layout (location = 1) in vec2 aTexCoord; out vec2 TexCoord; uniform mat4 model; uniform mat4 view; uniform mat4 projection; void main() { gl_Position = projection * view * model * vec4(aPos, 1.0f); TexCoord = vec2(aTexCoord.x, aTexCoord.y); } then, the matrix manipulated:
        ..... glm::mat4 projection = glm::perspective(glm::radians(fov), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f); ourShader.setMat4("projection", projection); .... glm::mat4 view = glm::lookAt(cameraPos, cameraPos + cameraFront, cameraUp); ourShader.setMat4("view", view); .... model = glm::rotate(model, glm::radians(angle), glm::vec3(1.0f, 0.3f, 0.5f)); ourShader.setMat4("model", model);  
        So, some doubts:
        - Why use it like that?
        - Is it okay to manipulate the camera that way?
        -in this way, are not the vertex's positions that changes instead of the camera?
        - I need to pass MVP to all shaders of object in my scenes ?
         
        What it seems, is that the camera stands still and the scenery that changes...
        it's right?
         
         
        Thank you
         
      • By dpadam450
        Sampling a floating point texture where the alpha channel holds 4-bytes of packed data into the float. I don't know how to cast the raw memory to treat it as an integer so I can perform bit-shifting operations.

        int rgbValue = int(textureSample.w);//4 bytes of data packed as color
        // algorithm might not be correct and endianness might need switching.
        vec3 extractedData = vec3(  rgbValue & 0xFF000000,  (rgbValue << 8) & 0xFF000000, (rgbValue << 16) & 0xFF000000);
        extractedData /= 255.0f;
      • By Devashish Khandelwal
        While writing a simple renderer using OpenGL, I faced an issue with the glGetUniformLocation function. For some reason, the location is coming to be -1.
        Anyone has any idea .. what should I do?
    • Advertisement