Effifcient State Changing

Sage
Posts: 1,066
Joined: 2004.07
Post: #1
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
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?
Quote this message in a reply
Moderator
Posts: 365
Joined: 2002.04
Post: #2
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.

Neil Carter
Nether - Mac games and comic art
Quote this message in a reply
Moderator
Posts: 3,571
Joined: 2003.06
Post: #3
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.

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...
Quote this message in a reply
Sage
Posts: 1,482
Joined: 2002.09
Post: #4
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.
Quote this message in a reply
Sage
Posts: 1,066
Joined: 2004.07
Post: #5
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.
Quote this message in a reply
Oldtimer
Posts: 834
Joined: 2002.09
Post: #6
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. Smile
Quote this message in a reply
Moderator
Posts: 3,571
Joined: 2003.06
Post: #7
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.
Quote this message in a reply
Sage
Posts: 1,199
Joined: 2004.10
Post: #8
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!
Quote this message in a reply
Post Reply 

Possibly Related Threads...
Thread: Author Replies: Views: Last Post
  Changing Pixel Values using CG LIPH700 1 4,464 Nov 25, 2010 03:17 PM
Last Post: SethWillits
  Changing the Mask in OpenGL kodex 2 3,756 Jan 18, 2006 09:21 PM
Last Post: kodex
  changing resolution in fullscreen ghettotek 22 8,269 Jan 18, 2005 09:39 PM
Last Post: arekkusu
  OpenGL state dump tool wanted MattDiamond 2 2,842 Sep 21, 2004 05:49 AM
Last Post: MattDiamond
  Blending when changing screens Blake 9 3,352 Oct 18, 2003 03:05 AM
Last Post: Fenris