I'd like to suggest a bit of optimization in the text rendering system. As of right now, the text rendering system (IGUIFont::draw and objects that use it such as IGUIStaticText) changes textures (using SetTexture in DirectX and a similar call in OGL) every single time a character is drawn, even if charactes are the same. This really increases the amount of GPU batches per frame, which really kills performance if you have a lot of text on your screen. I've been forced to use solid textures for all of my text labels to increase performance.
Would it be possible to change the IGUIFont rendering system so that it waits until all the draw() calls are made per frame before rendering the text? The system could keep track of all the characters it has to render in that frame, and then only have to switch textures for every different character on the screen. For example, if there are multiple instances of the character "A" on-screen, the system would only have to switch textures once to draw all the "A"s on screen, instead of switching textures for every single character.
Bitmap Font Rendering Optimization
I'm not sure if we could wait for all draw calls. They might be needed earlier maybe. But a SetTexture call for every char indeed sounds bad.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
-
hybrid
- Admin
- Posts: 14143
- Joined: Wed Apr 19, 2006 9:20 pm
- Location: Oldenburg(Oldb), Germany
- Contact:
Text should be rendered by the batch draw2d image call without changing the textures each character. Otherwise, there's an error in the implementation. OpenGL only implemented this for Irrlicht 1.7, but DirectX have had this already in 1.6
Collecting all calls might be problematic due to the render modes used in the GUI, at least it would require much testing and maybe also some additional administrative stuff. Maybe the full VBO GUI would be not much harder then.
Collecting all calls might be problematic due to the render modes used in the GUI, at least it would require much testing and maybe also some additional administrative stuff. Maybe the full VBO GUI would be not much harder then.
So I ran some tests, and here's the results I got.
First of all, hybrid is correct, and the implementation is working properly. Each call to IGUIText::draw() only creates one SetTexture() call.
Now onto performance:
I ran a test comparing the speed of rendering text using IGUIFont::draw() and using a solid texture. The code for drawing the text using IGUIFont is as follows:
The result (notice FPS):

I then made a solid texture of the same text (512 x 512, made in Notepad and GIMP) to see how much faster it rendered. The code:
And the result (notice the FPS again):

Notice how large the difference is (the solid texture is almost 2.5 times faster). Now I know it takes time to clip out each character from the font texture, but can anything be done to speed this process up and lessen the gap between these two figures?
The reason I originally was concerned about the amount of SetTexture() calls was because of the project I'm working on. It's a GUI-heavy dashboard designer for a robot dashboard (sorry if you've heard this already; there's already been 2 or 3 threads about it). Anyways, here's the dashboard designer with a single control (a meter) added:

Here's the data I gathered from PIX during that time:

Notice that there are 69 texture calls.
Now, when I select the meter, the properties window fills up with controls to edit properties like so:

Note that each static text label is a solid texture to increase performance. Here is PIX data from when the properties controls are in existence:

Notice both the drop in FPS and the new SetTexture() call number (90 more than before). What could cause such a jump in texture changes, and therefore such a drop in performance? I didn't think that a few GUI elements were so performance intensive.
As far as setup goes,
Irrlicht 1.7.1
Direct3D 9
GeForce 260GTX
Windows 7 Pro
First of all, hybrid is correct, and the implementation is working properly. Each call to IGUIText::draw() only creates one SetTexture() call.
Now onto performance:
I ran a test comparing the speed of rendering text using IGUIFont::draw() and using a solid texture. The code for drawing the text using IGUIFont is as follows:
Code: Select all
#include <irrlicht.h>
#ifdef _IRR_WINDOWS_
#pragma comment(lib, "Irrlicht.lib")
#pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup")
#endif
using namespace irr;
using namespace core;
using namespace video;
using namespace gui;
const SColor BG_COLOR(255, 0xe4, 0xe7, 0xec);
int main(void)
{
IrrlichtDevice* device = createDevice(EDT_DIRECT3D9, dimension2d<u32>(800, 600), 32);
if(device == NULL)
return 1;
IVideoDriver* driver = device->getVideoDriver();
IGUIEnvironment* guienv = device->getGUIEnvironment();
IGUIFont* font = device->getGUIEnvironment()->getSkin()->getFont();
static wchar_t* str = L"I am Andrew Ryan and I am here to ask you a question:\n"
L"Is a man not entitled to the sweat of his brow?\n\n"
L"No, says the man in Washington; it belongs to the poor.\n"
L"No, says the man in the Vatican; it belongs to God.\n"
L"No, says the man in Moscow; it belongs to everyone.\n\n"
L"I rejected those answers. Instead, I chose something different.\n"
L"I chose the impossible. I chose...\n\n"
L"Rapture.\n\n"
L"A city where the artist would not fear the censor.\n"
L"Where the scientist would not be bound by petty morality.\n"
L"Where the great would not be constrained by the small.\n"
L"And with the sweat of your brow,\n"
L"Rapture can become your city as well.";
static const u32 len = wcslen(str);
rect<s32> fontRect(0, 0, 800, 600);
guienv->addStaticText(str, fontRect);
u16 framesSinceLastFPS = 0;
while(device->run())
{
if(device->isWindowActive())
{
if(++framesSinceLastFPS == 20)
{
framesSinceLastFPS = 0;
stringw cap(driver->getFPS());
cap += " FPS, ";
cap += len;
cap += " characters";
device->setWindowCaption(cap.c_str());
}
driver->beginScene(true, true, BG_COLOR);
guienv->drawAll();
driver->endScene();
}
else
device->yield();
}
return 0;
}

I then made a solid texture of the same text (512 x 512, made in Notepad and GIMP) to see how much faster it rendered. The code:
Code: Select all
#include <irrlicht.h>
#ifdef _IRR_WINDOWS_
#pragma comment(lib, "Irrlicht.lib")
#pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup")
#endif
using namespace irr;
using namespace core;
using namespace video;
using namespace gui;
const SColor BG_COLOR(255, 0xe4, 0xe7, 0xec);
int main(void)
{
IrrlichtDevice* device = createDevice(EDT_DIRECT3D9, dimension2d<u32>(800, 600), 32);
if(device == NULL)
return 1;
IVideoDriver* driver = device->getVideoDriver();
IGUIEnvironment* guienv = device->getGUIEnvironment();
IImage* textImage = driver->createImageFromFile("Text.png");
ITexture* textTexture = driver->addTexture("Text Texture", textImage);
textImage->drop();
guienv->addImage(textTexture, vector2d<s32>(10, 10));
u16 framesSinceLastFPS = 0;
while(device->run())
{
if(device->isWindowActive())
{
if(++framesSinceLastFPS == 20)
{
framesSinceLastFPS = 0;
stringw cap(driver->getFPS());
cap += " FPS, ";
cap += " Drawn with a solid texture";
device->setWindowCaption(cap.c_str());
}
driver->beginScene(true, true, BG_COLOR);
guienv->drawAll();
driver->endScene();
}
else
device->yield();
}
return 0;
}

Notice how large the difference is (the solid texture is almost 2.5 times faster). Now I know it takes time to clip out each character from the font texture, but can anything be done to speed this process up and lessen the gap between these two figures?
The reason I originally was concerned about the amount of SetTexture() calls was because of the project I'm working on. It's a GUI-heavy dashboard designer for a robot dashboard (sorry if you've heard this already; there's already been 2 or 3 threads about it). Anyways, here's the dashboard designer with a single control (a meter) added:

Here's the data I gathered from PIX during that time:

Notice that there are 69 texture calls.
Now, when I select the meter, the properties window fills up with controls to edit properties like so:

Note that each static text label is a solid texture to increase performance. Here is PIX data from when the properties controls are in existence:

Notice both the drop in FPS and the new SetTexture() call number (90 more than before). What could cause such a jump in texture changes, and therefore such a drop in performance? I didn't think that a few GUI elements were so performance intensive.
As far as setup goes,
Irrlicht 1.7.1
Direct3D 9
GeForce 260GTX
Windows 7 Pro
-
Lonesome Ducky
- Competition winner
- Posts: 1123
- Joined: Sun Jun 10, 2007 11:14 pm