Bug in TextRenderer using custom RenderDelegate

I have encountered a rather annoying bug with the TextRenderer.

I wanted to implement my own RenderDelegate to add a simple shade and outline effect on my text, but found that the backstore got currupted under certain circumstances when my delegate returned false in intensityOnly(). I’ve tried my best to isolate the problem in a test case, and the result is attached this post as a java file. It apparently happens when I draw a series of long dynamic strings after which I draw a smaller string. The most frustrating thing about this is that when I enable jogl.debug.TextRenderer the darn thing works like a charm! This made me think that the TextureRenderer fails to clear it’s content when in non-“alpha only” mode, and simply by showing this texture (as you do in debug mode) the backstore gets properly flushed or whatever. Anyway that was a sick theory of mine :slight_smile:

Screenshot

http://nerf.dk/images/textbug.gif

(the text in this shot should read “Simple String”)

Test case:
DebugTextRenderer.java

Does anyone else have similar experiences with the TextRenderer?

My setup is as follows

GL Strings:
GL_VENDOR: NVIDIA Corporation
GL_RENDERER: GeForce 6800/AGP/SSE2
GL_VERSION: 2.0.3

OS:
Windows XP SP2

Graphic driver:
ForceWare version: 91.31

JDK:
1.5.0_06

First, it’s good to see people starting to use this new functionality. Sorry for the trouble.

The problem was related to the semantics of Graphics.copyArea() and the fact that when you have a non-intensity-only TextRenderer you have an alpha channel so some of the pixels are transparent.

I’ve checked in a fix which will show up in nightly builds dated 5/17 or later. Note that I believe tonight’s nightly build will fail because our Linux box is in the process of being reinstalled, so if you need the fix right away then check out and build the source tree.

Thank you for the quick fix Ken.

[quote]First, it’s good to see people starting to use this new functionality
[/quote]
Speaking of that I might aswell share my thoughts about this with you. The RenderDelegate is a fine solution for the most simplest of effects but it just doesn’t cut it down the road. I need to have access to the raw pixel data to make effects like soft shadows, outer glow and more than 1px outline. This leaves me with two options:

  1. Do some heavy modification to the TextRenderer
  2. Write my own
    I’m probably gonna go with option 2 because the string caching mechanism you are using in the TextRenderer is really geared towards alot of simple static text (which is why it’s perfect for java2d). As the complexity of the effects on the text goes op the effectiveness of the TextRenderer goes down because you are rendering much more than a simple glyph caching text renderer would.

[quote]I’ve checked in a fix which will show up in nightly builds dated 5/17 or later. Note that I believe tonight’s nightly build will fail because our Linux box is in the process of being reinstalled, so if you need the fix right away then check out and build the source tree.
[/quote]
I can’t pull the jogl project from the CVS for some reason. I probably messed something up in my CVS configuration, but nevermind I’ll just wait for the nightly build.

One last thing i wanted to ask. When i throw the TextRenderer in debug I’m getting spammed with these messages (several every second):

Clearing unused entries in preExpand(): attempt number 0
Clearing unused entries in preExpand(): attempt number 0
Compacting TextRenderer backing store due to vertical fragmentation 0.8
 TextRenderer allocating backing store 256 x 256

Is it really re-allocating 256x256 textures everytime it writes this? If so, isn’t that MAJOR overhead and should be considered a bug?

Can you suggest changes to the RenderDelegate mechanism that would make it more useful? I think it would be unfortunate if you couldn’t just reuse the TextRenderer. You could allocate (and reuse) a BufferedImage in your RenderDelegate, render your text there with effects, and then draw it into the TextRenderer’s Graphics context.

Please note that its string-by-string caching should provide much higher quality results than most glyph-by-glyph caching schemes. Note also that it fully supports Unicode and bi-directional text, even within the same string, which is very hard to do in a glyph based scheme.

The intent of the TextRenderer was to do well in the case of mostly static text but to also handle reasonably well the case of dynamically rendered text. If you have a real-world test case where it doesn’t work well, please file a bug.


cvs -d :pserver:guest@cvs.dev.java.net:/cvs co jogl gluegen

Yes, and there is more overhead than I’d like; but it doesn’t appear to be a killer for most apps out there. There is a bug filed but I’ve found it’s fairly difficult to come up with a heuristic that works well in all cases. I’ll look into this more.

[quote]Can you suggest changes to the RenderDelegate mechanism that would make it more useful? I think it would be unfortunate if you couldn’t just reuse the TextRenderer. You could allocate (and reuse) a BufferedImage in your RenderDelegate, render your text there with effects, and then draw it into the TextRenderer’s Graphics context.
[/quote]
Yes that would be a solution but this would require more memory allocation and an extra read’n’write of pixels, and I think I’m a little old-fashioned in the way that I hate going through these extra loops because it’s better OOP. Hmm also you would have to re-allocate this backbuffer on-the-fly because you can’t predict how big a string you would have to render. I’m afraid I don’t have a better solution myself.

But again, the main reason I think the TextRenderer is less than perfect for my needs is it’s string caching scheme. Consider the extreme case where rendering a string takes 1 second: The TextRenderer would lag the game 1 second everytime it renders a dynamic string while a glyph caching renderer would lag just like the TextRenderer in the beginning of the game until all used glyphs has been cached, after which it will run totally smooth.

[quote]Please note that its string-by-string caching should provide much higher quality results than most glyph-by-glyph caching schemes. Note also that it fully supports Unicode and bi-directional text, even within the same string, which is very hard to do in a glyph based scheme.
[/quote]
Please specify what you mean by much higher quality. Are we talking kerning between glyphs? A glyph-by-glyph caching scheme can easily support this by creating and caching the GlyphVectors of entire strings much like the TextRenderer does but unlike the TextRenderer it would only use these GlyphVectors for positioning of the individual glyphs which are prerendered on a backstore. It’s true that bi-directional text would prove a challenge, but atleast for games I don’t consider this to be a concern.

I don’t think this is likely to happen. As one concrete example, we switched over NASA World Wind’s original glyph-by-glyph text rendering scheme to use JOGL’s TextRenderer and there have been no performance issues with it that I’m aware of.

My limited understanding is that Java 2D supports concepts like fractional metrics which are not exposed at the API layer, so if you render entire Strings with Java 2D it can provide better kerning than you can get with the public APIs.

If you decide to go down the glyph-by-glyph route, please consider implementing something that others can use. For example, if you can offer full Unicode and bidirectional text support, I’d consider replacing the current TextRenderer implementation.

If you have concrete examples of where JOGL’s current TextRenderer is failing in the performance area, I would like to see them; please file bugs with the Issue Tracker. I think you should give it a try and see how it performs in your application though.

I went ahead and made a quick’n’dirty text renderer based on glyph caching and pitched it against the TextRenderer in a benchmark battle to the death!

The benchmark consisted of drawing 456 strings destributed over 8 columns and 57 rows using the default java font in 3 different cases:

  1. Where all strings were identical and unchanged each frame
  2. Where all strings were unique but unchanged each frame
  3. Where all strings were unique and changed each frame
    I did the 3 benchmarks with the default RenderDelegate and with a complex RenderDelegate where I simulated heavy effects by drawing the string 10 times on top of it self.

Results below

Simple RenderDelegate

All strings static and identical
TextRenderer: 542.0 FPS
GlyphRenderer: 68.5 FPS

All strings static but different
TextRenderer: ~15.0 FPS
GlyphRenderer: 72.0 FPS

All strings dynamic
TextRenderer: ~15.0 FPS
GlyphRenderer: 71.0 FPS


Complex RenderDelegate

All strings static and identical
TextRenderer: 526.0 FPS
GlyphRenderer: 66.0 FPS

All strings static but different
TextRenderer: 7.0 FPS
GlyphRenderer: 70.0 FPS

All strings dynamic
TextRenderer: 7.0 FPS
GlyphRenderer: 69.5 FPS

The results were pretty much as i expected. The TextRenderer excels in alot of static text as long as it can fit them in the backstore, but when you reach the enough unique strings each frame to triggers a clear of the backstore the FPS really takes a hit. Also I noticed sudden radical changes in FPS while testing the TextRenderer. Stuff like it being stable on 70 FPS then suddenly dropping to 40 FPS for a couple of seconds and then back up to 70 FPS.

If you want to test for yourself the GlyphRenderer can be found here: glyphrenderer.zip
Keep in mind that it’s a really quick’n’dirty alteration of the TextRenderer and shouldn’t really be used for anything. I also included a interface wrapped TextRenderer for easier benchmarking.

Thanks for doing these benchmarks and building your prototype. I would very much like to improve the performance of the TextRenderer to handle more cases such as yours.

There are a couple of things that can be done. One would be to improve the management of the current TextRenderer’s backing store. The heuristics that drive it could almost certainly be improved for some situations.

Another would be to incorporate a glyph-based caching system in the TextRenderer. I think the rectangle packing algorithm it uses internally would be well suited for building such a cache.

From discussions with Phil Race from the Java 2D team, my understanding is that if you want full Unicode support, you really need to do string-by-string caching. Apparently there are some languages like Arabic where certain glyphs behave differently in different situations so it isn’t easy to render them in isolation into a glyph cache.

If we could have essentially two implementations of the TextRenderer which are switched between with some boolean flag, where the user can indicate whether they want for example “high performance” or “high fidelity”, that would probably be ideal.

Would you be willing to push your glyph caching implementation further to make it a viable alternative in this context?

[quote]From discussions with Phil Race from the Java 2D team, my understanding is that if you want full Unicode support, you really need to do string-by-string caching. Apparently there are some languages like Arabic where certain glyphs behave differently in different situations so it isn’t easy to render them in isolation into a glyph cache.
[/quote]
Yes that’s indeed a major problem. I also believe certain combinations of characters will be represented by only a single glyph in some languages. These are problems I don’t even believe can be solved because of the limited access to such information from the API.

[quote]If we could have essentially two implementations of the TextRenderer which are switched between with some boolean flag, where the user can indicate whether they want for example “high performance” or “high fidelity”, that would probably be ideal.
[/quote]
Yes I agree that this would be optimal. We could limit the “high performance” renderer to only support one-to-one glyph mapping and thereby open up for all the glyph-caching-based optimizations.

[quote]Would you be willing to push your glyph caching implementation further to make it a viable alternative in this context?
[/quote]
I will definately be working on making a glyph-by-glyph caching renderer. My few tests only confirmed my feelings that string caching is not the way to go for games atleast. But I believe making a generic solution for the masses is beyond the scope of my current project. The best I can offer is to make my source code available when I’m done. I could perhaps commit it to the util project?

If you would try to reuse some of the TextRenderer’s internals for your glyph-by-glyph renderer, and make your source code available afterward, I and the rest of the community would really appreciate it. If you haven’t, please fill out the Sun Contributor Agreement on the JOGL home page. You can either fax it in or scan and email it to me – contact me at kbr at dev dot java dot net for my fax number if you need it.