Skip to main content
GameDev.net gamedev.net
🔒 Locked

GUI - Render Lists

Started by TechnoGoth Apr 8, 2005 at 11:56 AM 10 replies 1.9k views
Original Post
TechnoGoth
TechnoGoth
I'm building a simple GUI system in openGL for my video game. I've doing it for several reasons, one because if never done it before and two to seperate the rendering code from the code for displaying a screen. Thus making it easier to build and maintain and it allows me to change to API should I choose without effect anything but the rendering code. Now, I've come up with an idea that I belive should in theory improve the performance of my GUI since I'm getting a slow down of around 20% when going from 11 objects on screen to 54. The idea is to create a render list the idea being that instead of rendering an object when its called, the render list is checked and if the texture for that request is not found(indicated by its index value in the texture array) that request is added to the list. If it is found that that request is added to a stack in the render list for all requests using that texture . Then another method would be called to render all requests in the render list. The whole idea is based on the theory that by reducing texture swaping to a bare minium, the over all frame should increase. So, before I being attempting to tackle this issue will it work and what sort improvement am I likely to get? Also has anyone developed something like this before? And how did you handle this issue?
rick_appleton
rick_appleton
I am in the process of doing some of this as well. I've just done it with a single font (putting al the text into a single list and drawing that in a single go. I'm going to be expanding this for multiple fonts and then probably for the rest of the GUI as well. All textures used for the GUI will be added into a single texture, so the entire GUI can be drawn in one call (two actually, one for the elements, and one for the text).
Hardguy
Hardguy
I have done this for my game and some things you wanna consider is:

- Have some class that loads several images into a larger texture. This will reduce the texture state changes and save some space when using non pow2 images.

- Have a class that is your GUI obejct to be rendered. This contains the texture, offset on the texture, size, position on the screen,etc. When you want to draw something add this to a sorted container (STL:s map or set works) where you sort by texture. The you just call some function that goes through the list and adds the objects into a vertexbuffer until the texture changes, draws the vertexbuff er, adds the next objects until texture change and so on.

Hope that helped.
cragwolf
cragwolf
I've been looking at this problem lately. I sort my visible entities according to their attributes, and the attributes (or states) that are expensive to change I sort first. So if you had 4 visible entities (with attributes in brackets):

Manuel (Texture=Tex1; Color=Col2; Camera=Cam1)
Bob (Texture=Tex2; Color=Col2; Camera=Cam1)
Button (Texture=Tex1; Color=Col1; Camera=Cam2)
House (Texture=Tex2; Color=Col1; Camera=Cam1)

If I rendered in that order, there would be 4 texture changes. No good. If I sorted them by color first, then by camera, then by texture, I would get:

House (Texture=Tex2; Color=Col1; Camera=Cam1)
Button (Texture=Tex1; Color=Col1; Camera=Cam2)
Manuel (Texture=Tex1; Color=Col2; Camera=Cam1)
Bob (Texture=Tex2; Color=Col2; Camera=Cam1)

Rendering in this order would involve 3 texture changes. Better, but still not good enough. But if I sorted by texture first, then camera next, then colour next -- in other words, in decreasing order of state change expense (and let's just assume for this example that changing camera is more expensive than changing color) -- then I get:

Manuel (Texture=Tex1; Color=Col2; Camera=Cam1)
Button (Texture=Tex1; Color=Col1; Camera=Cam2)
House (Texture=Tex2; Color=Col1; Camera=Cam1)
Bob (Texture=Tex2; Color=Col2; Camera=Cam1)

That would involve 2 texture changes. Best. For large numbers of objects this results in huge savings. Of course, it helps to minimise the number of textures you use. Also, I sort right at the beginning and not every frame, so I need to handle the spawning of new entities. I haven't thought about that yet.
TechnoGoth
TechnoGoth
hmm, having one big texture seems so impracticale to me, It makes things difficult to change and maintain. I currently group all of an objets diffrent states in a single texture but I don't want to have one massive texture file if I can help it.

Sorting textures seems to me to be the most practicle solution, although I am also concerned that having large numbers of objects might make sorting more expensive then numerous texture changes. Although this might not be a problem if I only sort when objects are added to the screen. So a I'll probably do that.
rick_appleton
rick_appleton
Technogoth: I agree that having all the seperate GUI elements in a single textures is impractical. Therefore what I'm going to be doing is at initialization, load all the seperate parts of the texture, and join them into a single texture page/atlas/sheet. This keeps the ease of editing the files, it allows non-power-of-2 textures for the element, and everything can be drawn in a single call.

I'd use two calls, one for texture elements, and one for text (ie. fonts).

The only point that this breaks down is if the GUI is partly transparent. The you'll have to render it piece by piece, but you can still do the calculations only once, and store them in a long list.
TechnoGoth
TechnoGoth
hmmm. That could work. Taking the seperate files and joining them together at intilization might be an elegent solution. Some aspects of my GUI will need to be transperent, but I haven't got around to working on that aspect, yet so it doesn't changing methods doesn't effect that. It means changing my texture accessing method but not a great deal. Although I'm not sure how to go about joing the textures together in to one texture though, I'll have to do some more reading on textures in openGL.
rick_appleton
rick_appleton
There's no functions in OpenGL that do that. I still need to implement this in my engine although I did a small test some time ago, so take the following with a grain of salt ;)

- You can change parts of a texture with glSubTexImage2D (if I recall correctly)
- Or you can store the entire texture in memory, until the 'user' indicates that all elements have been loaded, and only then create the texture (this is what I will be doing)
- Calculating where in the texture atlas your texture fits is something akin to the BSP algorithm, so if you need more info on that you know what to search for.

Good luck.
superpig
superpig
A render list is going to be a good idea because you can sort arbitrarily - not just by texture. If it isn't the texture swaps that are slowing you down (though it probably is) then you can easily change the sort function to account for whatever it is.

Also, I like the atlas idea partly because it would let you put most of the work onto the GPU. You could have a buffer full of quads from (0,0)-(1,1), each one with an element ID number which maps to a vertex shader constant index. Into that vsh constant you can then put scale/offset data for the geometry as well as the tex coords - probably pack it all into two or three constants per element, allowing you to draw 30-50 UI elements in a single call. Moving/resizing elements just becomes a question of updating a vertex shader constant.
Richard "Superpig" Fine - saving pigs from untimely fates - Microsoft DirectX MVP 2006/2007/2008/2009
"Shaders are not meant to do everything. Of course you can try to use it for everything, but it's like playing football using cabbage." - MickeyMouse
superpig
superpig
Quote:
Original post by rick_appleton
Of course that is only an option on newer hardware, but it'd be interesting to make something like that.
No, it runs on any [lack of] hardware. Vertex shaders, not pixel shaders. [wink]
Richard "Superpig" Fine - saving pigs from untimely fates - Microsoft DirectX MVP 2006/2007/2008/2009
"Shaders are not meant to do everything. Of course you can try to use it for everything, but it's like playing football using cabbage." - MickeyMouse
rick_appleton
rick_appleton
Hmm, indeed. I've always been equating the two, but I really shouldn't (especially since I've had my ass bitten by a laptop supporting only vertex_programs).

I might give it a go once my own GUI rendering list is working correctly.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.