Effifcient State Changing
I was wondering the other day, is it more effective, when changing states such as lighting or texturing, to simply use glDisable()/glEnable or to use something like
I didn't know if it would save time not having to try and disable what is already off. Anyone know?
Code:
if(glIsEnabled(GL_LIGHTING))
glDisable(GL_LIGHTING);I didn't know if it would save time not having to try and disable what is already off. Anyone know?
Without profiling, it's difficult to know, but I bet there's little to no difference between calling glIsEnabled() and glDisable() on their own, since all they're doing internally is checking a boolean in a table. However, if glIsEnabled() returns true, you need to call glDisable() as well, so that's two function calls instead of one. In that case it could actually be slower.
If you have a lot of attributes you need to enable or disable, it may be more efficient to use glPush/PopAttrib() to save or restore a block of attributes all at once. You may end up saving more state than you really need, but you'll be calling less functions to do it, so it's likely to be more efficient.
If you have a lot of attributes you need to enable or disable, it may be more efficient to use glPush/PopAttrib() to save or restore a block of attributes all at once. You may end up saving more state than you really need, but you'll be calling less functions to do it, so it's likely to be more efficient.
Some video card drivers handle state changes poorly and might stall the rendering pipeline with glEnable/Disable() state changes. glPush/PopAttrib() are known to cause problems as well, so it is best to avoid using them altogether. The way to get around this is to cache the state yourself.
Call your InitStates() function at program startup, and after that you have to remain consistent throughout your entire program and only call these functions when you want to enable or disable your states -- IOW, you can't call glEnable() or glDisable() yourself somewhere else, or else this caching method won't work. I don't use glPush/PopAttrib() at all because of its supposed performance problems, but you could design your own version with a stack based type of system which uses this caching method.
[edit] I should note that the way I use this is that I just call EnableState or DisableState right before the drawing calls in whatever code block I'm in at the time. Essentially you just call them to set the required states for the current drawing as you please, without regard to pipeline stalls. Since this caching method catches any unecessary state calls you don't have to pay attention to detail and could call EnableLighting (or EnableFog or whatever you cache) two or more times in a row and it doesn't matter. Of course you don't want to be *too* flippant about its usage since it is in fact another function call, but you get the idea...
Code:
BOOL lightingState;
void InitStates(void)
{
glEnable(GL_LIGHTING);
lightingState = true;
}
void EnableLighting(void)
{
if (!lightingState)
{
glEnable(GL_LIGHTING);
lightingState = true;
}
}
void DisableLighting(void)
{
if (lightingState)
{
glDisable(GL_LIGHTING);
lightingState = false;
}
}Call your InitStates() function at program startup, and after that you have to remain consistent throughout your entire program and only call these functions when you want to enable or disable your states -- IOW, you can't call glEnable() or glDisable() yourself somewhere else, or else this caching method won't work. I don't use glPush/PopAttrib() at all because of its supposed performance problems, but you could design your own version with a stack based type of system which uses this caching method.
[edit] I should note that the way I use this is that I just call EnableState or DisableState right before the drawing calls in whatever code block I'm in at the time. Essentially you just call them to set the required states for the current drawing as you please, without regard to pipeline stalls. Since this caching method catches any unecessary state calls you don't have to pay attention to detail and could call EnableLighting (or EnableFog or whatever you cache) two or more times in a row and it doesn't matter. Of course you don't want to be *too* flippant about its usage since it is in fact another function call, but you get the idea...
If your state changes are so complicated that they are causing performance problems, wouldn't it be better to put them in a display list?
Scott Lembcke - Howling Moon Software
Author of Chipmunk Physics - A fast and simple rigid body physics library in C.
It's not that I have complicated state changes at all, I was mainly just curious. I'm working on a making my own little renderer/scene graph engine so I'm planning on making sure that all lit objects are rendered at the same time and all textured objects are lit at the same time. I was just wondering in case there comes a time when I'm not sure if something is enabled (like when switching from textured to non-textured, and also potentially needing lighting changes if lighting is on) if it would be worthwhile to use glIsEnabled(). I'll probably just use AnotherJake's idea and have my renderer keep track of all the variables by itself.
Unless you're changing states in the middle of tight GL code, it shouldn't matter much. It's not that the state change itself is expensive, but when you change state, the GL has to stop any asynchronous processes and flush any commands that have been sent already. The library blocks and the graphics hardware is flushed, and that's a bad thing.
This is why a software implementation will do state changes for virtually free.
Bottom line: don't worry that much about state changes, unless you're doing state changes between every model, or every vertex. Doing a couple of state changes between each node in a tree shouldn't be too much of a problem. Use glPushAttrib, profile and write your own implementation if you feel the need to.
This is why a software implementation will do state changes for virtually free.
Bottom line: don't worry that much about state changes, unless you're doing state changes between every model, or every vertex. Doing a couple of state changes between each node in a tree shouldn't be too much of a problem. Use glPushAttrib, profile and write your own implementation if you feel the need to.
Fenris Wrote:The library blocks and the graphics hardware is flushed, and that's a bad thing.Right. The fact of the matter is that state changes *will* have to be made, and sometimes frequently. It is *more* efficient to limit the amount of state changes so as not to create unnecessary pipleline stalls. Grouping like-state code together is going to be more efficient. The caching method I mentioned above is especially helpful to avoid unnecessary stalls, when like state changes are called in succession. Some video card drivers apparently do not take this simple inefficiency into account themselves, so it is helpful to do it yourself.
My scenegraph, after generating a visibility set for the current frame groups objects which report requiring the same gl state to display. Obviously, the issue is *how* you determine which objects need what to draw, so I have a relatively crude interface, "SetDrawable" which basically allows objects to generate a state identifier ( a number ).
There's a lot going on to make it work well, but in the end, I've got a stress test with 10,000 models on my stage, with maybe 30 unique drawing operations ( trees with one texture, rocks with another + detail, more rocks with another + detail, models with two textures + cubemap + emissive lighting, etc ) and when rendering, I only have to perform enough state changes to display the unique states of the visible set.
It works well enough, for me!
There's a lot going on to make it work well, but in the end, I've got a stress test with 10,000 models on my stage, with maybe 30 unique drawing operations ( trees with one texture, rocks with another + detail, more rocks with another + detail, models with two textures + cubemap + emissive lighting, etc ) and when rendering, I only have to perform enough state changes to display the unique states of the visible set.
It works well enough, for me!
Possibly Related Threads...
| Thread: | Author | Replies: | Views: | Last Post | |
| Changing Pixel Values using CG | LIPH700 | 1 | 3,763 |
Nov 25, 2010 03:17 PM Last Post: SethWillits |
|
| Changing the Mask in OpenGL | kodex | 2 | 3,404 |
Jan 18, 2006 09:21 PM Last Post: kodex |
|
| changing resolution in fullscreen | ghettotek | 22 | 7,601 |
Jan 18, 2005 09:39 PM Last Post: arekkusu |
|
| OpenGL state dump tool wanted | MattDiamond | 2 | 2,487 |
Sep 21, 2004 05:49 AM Last Post: MattDiamond |
|
| Blending when changing screens | Blake | 9 | 3,165 |
Oct 18, 2003 03:05 AM Last Post: Fenris |
|

