TextRenderer API

Hi folks,

how is the TextRenderer API implemented internally to render fonts? I know that "Renders bitmapped Java 2D text into an OpenGL window with high performance, full Unicode support, and a simple API. Performs appropriate caching of text rendering results in an OpenGL texture internally to avoid repeated font rasterization. The caching is completely automatic, does not require any user intervention, and has no visible controls in the public API. "

I’m asking this question because before using the API, we were getting better performance results rendering fonts using JAI at hand (that is, byte after byte). So, when we started using the API, our software benchmarks began to show terrible results.

And we are using the code template suggested in the API documentation. Can anyone explain the internals of the API?

Thanks,

First, make sure you’re using the latest version, for example from a current nightly build. Recent performance improvements were checked in that sped up the rendering of large amounts of dynamic text by a factor of 10.

Second, maybe some other people here on the forums can help you. I don’t think there are any outstanding performance problems with it at this point. You should also look at the text-related demos in demos.j2d in the jogl-demos workspace. Perhaps your poor performance is due to a misuse of the API.

Hi,
I can confirm that we experienced a 10 fold performance improvement between rc4 (or rc3 maybe) and rc6.
We also experienced a 7 fold perf improvement between the TextRenderer and the good old glutbitmap drawings.

I looked at the previous code where caching was done by “strings”, on textured quad was drawn for each string (basically).
Now with the new implementation I understand that little textured quads are rendered (one for each glyph). Moreover VBO seems to be used to improve performance.

Maybe our usages was not the same, and your performance problems are related to a different amount of text,…

PS : Do not hesitate to look at the TextRenderer 's code, it can helps.

Hi
I recently tried to upgrade from rc3 to rc6 and rc7. I’m experimenting quite a big performance loss with the TextRenderer…
(Note : I use openGL v2.1.1 on my test machine)

I measured the framerate on a given program with rc3 and rc7, skipping or not skipping the TextRenderer.draw calls.
On rc3, I obtained about 125fps with and without drawing(maybe a little less with)

On rc7, I obtained about 125fps without, and about 80fps with.

That’s for 13 calls per frame to this code :


	textRenderer.beginRendering (frustumWidth, frustumHeight);
								
	textRenderer.setColor(color);
	textRenderer.draw(textBlock.getText(), left + textStartX, top + y + lineBlock.getBaseLine());
	textRenderer.endRendering ();

and the strings size vary from 2 characters to 15. I don’t use any custom RenderDelegate. Do you have any idea ? :confused:

EDIT : I measured the time taken to execute only those 4 lines of code today.
RC3 : 0.06ms per execution
RC7 (nightlies from yesterday) : 0.975ms per execution. Which mean to have 30 frames per second, I can display 33 Strings of text, but nothing else :confused:

Please provide a test case. There are applications using the text renderer to draw hundreds or thousands of glyphs per second with no performance issues.

Hi, I tried to create a test case based on the TextRenderer demos. I noticed there that the performance loss isn’t as huge as in my application. Yet it is there.

I tweaked TestTextRenderer from the demos, changing the display() method :


  public void display(GLAutoDrawable drawable) {
    time.update();

    // Compute the next position of the text
    position = position.plus(velocity.times((float) time.deltaT()));
    // Figure out whether we have to switch directions
    if (position.x() < 0) {
      velocity.setX(Math.abs(velocity.x()));
    } else if (position.x() + textWidth > drawable.getWidth()) {
      velocity.setX(-1.0f * Math.abs(velocity.x()));
    }      
    if (position.y() < 0) {
      velocity.setY(Math.abs(velocity.y()));
    } else if (position.y() + textHeight > drawable.getHeight()) {
      velocity.setY(-1.0f * Math.abs(velocity.y()));
    }      

    GL gl = drawable.getGL();

    // Prepare to draw text
    long nano = 0;
    for (int i = 0; i < 12; ++i) {
    	renderer.beginRendering(drawable.getWidth(), drawable.getHeight());

    	// Draw text
    	renderer.draw(TEST_STRING, (int) position.x() + rand.nextInt(100) - 50, (int) position.y() + rand.nextInt(100) - 50);

    	// Draw FPS

    	// Clean up rendering
    	nano -= System.nanoTime();
    	renderer.endRendering();
    	nano += System.nanoTime();
    }
    System.out.println("time per frame : " + (nano / 1000000.0) + " ms");
    fps.draw();
  }

On my machine, the time to process 12 endRendering() calls has been increased 10 fold between rc3 and rc7. (from 0.2 to 2ms). For an unknown reason, on my application, it is about 40 fold. (from 0.25 to 10ms). Provided I use several TextRenderers and some other factors, I have to call beginRendering and endRendering several times per frame (I can’t group the draw() calls inside one begin/end pair).

No openGL Exception is thrown during my aplication is running. What do you think could cause the call to endRendering to be longer ?

I hope you’ll be able to help me.

i might be wrong on this, but the endRendering() method seems to do quite a bit of work, namely calling the function flushGlyphPipeline() which does the effective openGL rendering.

in this function you can change the call
mPipelinedQuadRenderer.draw();
to
mPipelinedQuadRenderer.drawIMMEDIATE();

it would be interesting if your measurements would differ with this change.

Indeed, replacing the draw method by the drawIMMEDIATE did bring my perfs back to normal.

I think the draw method is efficient when used to draw a lot of text, but in very few begin/endRendering calls. Could it be possible for the textRenderer to adapt to the amount of data or if not possible, to choose the rendering method for the textRenderer ?

Yes, we can make changes in this area, but please provide a small test case which shows the slowdown. We have not seen this during the development of for example NASA’s World Wind Java and related applications.