Performance tips

From CEGUI Wiki - Crazy Eddie's GUI System (Open Source)
Jump to: navigation, search

Written for CEGUI 0.7


Works with versions 0.7.x (obsolete)

Written for CEGUI 0.8


Works with versions 0.8.x (stable)

Works with latest CEGUI stable!

This page provides some generic tips on getting the most performance out of CEGUI. People often claim that CEGUI is slow and don't realise it could be them doing something wrong. I will try to gather some areas where people claim CEGUI is slow and "just sucks" and try to provide tips about what is wrong.

Debug vs Release mode

The performance difference between Debug and Release (optimisations enabled) CEGUI can be quite dramatic. Ensure you run everything in release mode when judging performance.

Small tiled images

A very common mistake. If you have a very small (lets say 1px * 1px image) in your imageset and you set your looknfeel to tile that image over 100 px, CEGUI has to generate a lot of triangles to fulfil your wishes! This will lead to very bad performance and should be avoided. Tiling is fine but keep it under control!

(Note: Stretching doesn't have the same caveat, you can stretch 1px image over as many pixels as you want with just 2 triangles and one batch.)

Imagesets & Texture atlases

Texture switching is a very expensive operation, which is why CEGUI uses imagesets. Imagesets allows you to put several images in one texture (imageset ~= texture atlas), thus (potentially) lowering the amount of texture switches when rendering. If you however are from the "Imagesets suck, it sucks that CEGUI uses them!" and use one bitmap file and one imageset per image, you might expect very poor performance (many many texture switches even when rendering a single widgets - all corners are in separate file, also batching is simply not possible since you need a separate texture per every rectangle, so one widget might end up being 20 batches or even more!).

The bottom line is: Use imagesets, don't hate them! And if you still hate them and use separate files, stop whining that CEGUI is slow and sucks :-D

(Note: CEGUI 0.8 will completely change the way imagesets work. We will have images, these will simply have a reference to texture file and UV coords of the rectangle we should use in the texture file, .imageset files will still load though, so all of this still applies, furthermore the new CEED editor will support automatic imageset/atlas creation from multiple files to lessen the imageset maintenance pain)

Problem: Loading layouts takes few seconds and halts my application!

This is a complaint I have seen multiple times. The reporter usually has a dialog that in its constructor loads a XML layout off the HDD and constructs its hierarchy based on that. Depending on how the layout is complex, this can indeed take a few seconds (depending on many many factors). What is flawed about this is the fact that the user loads the layout always when the dialog is constructed. Wouldn't it be better if we loaded the layout once, stored it somewhere and reused that whenever the dialog has to reappear instead of deleting the layout when user closes the dialog and loading it from scratch when it's opened?

There are two ways of avoiding this. If the dialog is modal and can only appear once, it pays off to just load it, set it to invisible and the show/hide as necessary. This is the fastest solution.

If you need multiple instances of the dialog, you need to clone the widget tree somehow. This is why Widget (Window in 0.7 and previous) ::clone method has been implemented (only CEGUI 0.7.5 and newer!). It allows you to clone the entire widget hiearchy. The idea is to load this when the dialog is first used (or even when loading the application, depends on how the dialog is used). Store the widget pointer somewhere (could be a static member variable in the Dialog class) and upon construction, just clone the hierarchy and add the cloned widget while leaving the original alone for further cloning. (TODO: add some example code)

Speeding up a rarely changing info window (or any widget) with complex elements inside it

CEGUI allows caching. This is done with the "AutoRenderingSurface" property. What this means is that the widget gets rendered once with its child widgets (the entire hierarchy). The result is stored in a texture and from this moment on, whenever rendering needs to be done, just one quad with the texture is drawn. When widgets change inside, it invalidates the cache and everything is redrawn from scratch. This is especially useful for complex deep hierarchy widgets that users rarely interact with or aren't interactive at all.

Caveat: The texture caching causes the widget to hard clip its children to its dimensions! That means that a combobox at the bottom of a frame window will get "cut" when you open the options of it. This is likely to get fixed but as of now (5th January 2011) it's still a problem in both 0.7 and 0.8.

A quick and (relatively) painless way to get roughly 40% performance increase in certain areas (0.8 only!)

By default, CEGUI uses no custom allocators at all. That means the plain old new and delete. You can set the allocator to anything you want but we recommend nedmalloc. It's a very robust memory allocator tailored to give maximum performance. It speeds things up especially when initialising, loading layouts, creating windows, ... Give it a try. See Memory Allocation for more details.