poor performance of DirectLabel

Hi,

I’m doing a lot with Panda’s GUI these days, and I always found the performance of DirectLabel to be somewhat slow.
To nail things, I’ve written a mini test-app that renders about 1.6k of text using a single DirectLabel:

import direct.directbase.DirectStart
from direct.gui.DirectGui import *
from pandac.PandaModules import TextNode
import time

start = time.clock()
b = DirectLabel(scale=.05, relief = None, text_mayChange = 0, text_wordwrap = 30, text_align = TextNode.ALeft, pos = (-1,0,0.9),
                text = "Panda3D Basics\nPanda3D is a 3D engine: a library of subroutines for 3D rendering and game development. The library is C++ with a set of Python bindings. Game development with Panda3D usually consists of writing a Python or C++ program that controls the Panda3D library. Panda was created for commercial game development, and its primary users are still commercial game developers. Because of this, Panda3D needs to emphasize four areas: power, speed, completeness, and error tolerance. Everyone knows what power and speed are. But completeness and error tolerance deserve some extra commentary. Completeness means that Panda3D contains tons of unexciting but essential tools: scene graph browsing, performance monitoring, animation optimizers, and so forth. These things may not be sexy, and as a result, open-source engines often don't have them. But when you're serious about getting work done, and not just playing, these tools need to be there. Error tolerance is about the fact that all game developers create bugs. When you do, you want your engine to give you a clear error message and help you find the mistake. Too many engines will just crash if you pass the wrong value to a function. Panda3D almost never crashes, and much code is dedicated to the problem of tracking and isolating errors. Finally, to come back to power and speed: the best way to gauge Panda3D's capabilities is to take a look at the Sample Programs. These are short programs that demonstrate a sampling of Panda3D's capabilities. The screenshots have frame-rates in the upper-right corner, taken on a Radeon X700. ")
end = time.clock()
print "duration: ", end-start


#run the tutorial
run()

As you can see, the program measures the time it needs to create the DirectLabel. On my machine (a 2Ghz Dual Core, Geforce 8700 M GT) it takes 1.8 seconds to prepare the text.
On a 3Ghz Dual Core Imac, which is a lot snappier than my laptop it still takes 0.6 seconds.

Is there a way to get Panda to render text quicker somehow?

Thanks,

Erik

Note: I tried using a TextNode instead of a DirectLabel and got the same performance results… :cry:

2.8 GHz P4Prescott HT : 0.344716744798

Do you need it for RTT or what ?
If its lifetime is short, trade the gen time with render time, i.e. don’t flatten it. It’s where most time is spent.

loadPrcFileData('','text-flatten 0')

It’s a dynamic config variable, you can change it as needed before generating the text. It’s used per text generation.
Result :
.
.
.
.
.
0.0417725860393 !

oh. wow.

I hadn’t realised before that TextNode generates a single geom for each character and then merges them together.
That explains a lot.

Thanks for your hint, ynjh_jo.

Still, the game I’m working on has a lot of text in it, like an RPG with lengthy mission briefings etc.
Basically, I need that text to be generated quickly and displayed at good frame rates.
Any suggestions? Pre-transforming all text resources in flattened TextNodes feels wrong. Hm. Don’t know. maybe it’s just a unfamiliar concept.

Has anybody ever tried changing the way TextNode generates the text? I mean, it should be possible to generate fewer geoms to start with: if the font is spread over e.g. four textures, one shouldn’t need more than 4 geoms…

hm…

I’m not quite sure what you’ve got in mind there–it’s hard to imagine a text system that does better than one geom per letter, and then merging them together. I guess you could improve things a bit by pre-caching all of the common two- and three-letter combinations into their own geoms, but I don’t know how much this will actually help you.

Arguably, the TextNode could do things a bit better, by essentially doing the flatten operation as it goes–building up a big GeomVertexData and adding in the vertices for each letter–instead of building up a scene graph of GeomNodes and then calling flattenStrong() on it. Doing it this way would save on the overhead of creating and destroying all of those GeomNodes. This would require a fair amount of additional code. And you’d still have to process each vertex, so with a page full of text it still wouldn’t be cheap.

In any case, one way to force the font texture to spread over e.g. four textures is to decrease the size available for each texture. Try:

text-page-size 128 128

David

Hi Dave,

Yes, that’s exactly what I had in mind…
But I already peeked a lit into the textAssembler code and see that it would be no piece of cake to do it.

hm.
Maybe I can get away with generating the text without flattening (with the ‘text-flatten 0’ option), so I quickly get something to display.
Once it’s on screen (and people are reading) I could flatten it…

Hm. lets see…

If you are bold, you could try loader.asyncFlattenStrong(node). You have to be bold because this code was written once, but never used in production, and is largely unexercised. This will also require building Panda with some kind of thread support. If you aren’t using threads otherwise, you could define just:

#define SIMPLE_THREADS 1
#define SIMPLE_THREADS_NO_IMPLICIT_YIELD 1

to minimize the overhead of enabling threads.

David