Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I'm working on a game that uses CEGUI and Ogre. Recently, we've discovered that some of our customers with GeForce4 MX 4000's, performance is terrible.

After a night spent debugging, I've tracked the issue down to a glDrawArrays call inside the Ogre GL Renderer. Most executions of this call are pretty quick (<10ms, which still sucks but is ok for this terrible card). But one execution of the GLRenderSystem::_render function takes 3500ms every single frame.

It's only drawing a 54-element TRIANGLE_LIST. All the other calls to it are drawing similar-sized TRIANGLE_LISTs, so it's not the size of the array or its type that is the problem.

I've:

  • disabled fragment shaders (the GF4 MX doesn't support them)
  • disabled vertex shaders (it supports them, but CEGUI can only do all types of shaders or none of them)
  • attempted to disable a nearby call for multitexturing
  • massively simplified the UI that I'm drawing so that it is only a single CEGUI::Window

But I'm really just shooting in the dark. I'm in a windows environment. What's a good tool to figure out the OpenGL state at the time of a function call? I'm guessing that there's a particularly piggish texture or a fragment shader somehow slipping through and getting rendered.

If there aren't any tools to do what I need, can anyone suggest ways that glDrawArrays could be made really slow on an old card?

Update:

  • I grabbed GLTrace and compared the calls that precede both a fast glDrawArrays and a slow one. They're absolutely identical, they're even binding the same texture IDs.
  • One consistent difference however, is that the call that executes slowly is the first one in each OGRE/cegui render frame. Perhaps there is some copying-over of texture data to the video card each frame (which would be ridiculous and clearly doesn't happen on other cards...). Update: this isn't the case - no matter where in the queue I draw the offending object, it still takes forever. See below.
  • There are 3 main objects being drawn: a full-window background (plain white, gets textured with a 128x128 texture), a smaller rectangular label, and text in that label. The ratios between their draw speeds are approximately the same the ratios between their areas
  • If I force the slow object to be drawn several times instead of drawing the entire render queue, it is slow every time, which means it's not a one-time-loading issue.

Update for current theory: this is somehow a fill-rate issue. Is there a way to configure a window so that the card has issues filling it? Since I'm drawing in windowed mode, will that mess up a card sometimes? My window doesn't have power-of-two dimensions (or dimensions similar to any standard resolution), could that be a chokepoint?

share|improve this question
    
Using vertex buffers of any kind? –  Sean Middleditch Jun 18 '13 at 2:51
1  
You might try gDEBugger. –  Nathan Reed Jun 18 '13 at 3:00
    
That does sound like the gpu is stalling, were the textures or vertex buffers used modified in the current frame? –  Archy Jun 18 '13 at 7:54
1  
Obviously. Do you have a specific profiler you use or can recommend for OpenGL-specific profiling? I've used very sleepy a ton, but since it can't resolve the call stack within the nVidia driver it hasn't been helpful. Plus through simple stepping-through, I know exactly which call is slow. –  user1158478 Jun 18 '13 at 13:49
1  
@user1158478: glBufferData, glBufferSubData, and glGenBuffers are the ones to look for. You should only be calling glGenBuffers during loading and you should be using glBufferData sparingly. Remember to discard buffers before updating them if you've already used them this frame; there's no guaranteed GL way to do this in any version supported by that ancient hardware, but drivers typically allow a hack for this by using glBufferData(GL_ARRAY_BUFFER, 0, NULL, GL_DYNAMIC_DRAW) (replacing GL_ARRAY_BUFFER as appropriate). –  Sean Middleditch Jun 18 '13 at 17:55
show 8 more comments

1 Answer

Got it:

  1. The Geforce4 MX with the newest-available nVidia drivers (circa 2006) doesn't support the glTexEnv approach to blending source and destination textures. At least, not in hardware. Drawing the simplest shapes results in crippling slowness.
  2. However, it does appear to support GL_BLEND combined with glBlendFunc in hardware.

Solution: Instead of the complicated cegui setup show below:

glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_COMBINE_EXT)
glTexEnvi(GL_TEXTURE_ENV,GL_COMBINE_RGB_EXT,GL_MODULATE)
glTexEnvi(GL_TEXTURE_ENV,GL_SOURCE0_RGB_EXT,GL_TEXTURE)
 glTexEnvi(GL_TEXTURE_ENV,GL_SOURCE1_RGB_EXT,GL_PRIMARY_COLOR_EXT)
glTexEnvi(GL_TEXTURE_ENV,GL_SOURCE2_RGB_EXT,GL_CONSTANT_EXT)
glTexEnvi(GL_TEXTURE_ENV,GL_RGB_SCALE_EXT,GL_LINES)
glTexEnvi(GL_TEXTURE_ENV,GL_OPERAND0_RGB_EXT,GL_SRC_COLOR)
glTexEnvi(GL_TEXTURE_ENV,GL_OPERAND1_RGB_EXT,GL_SRC_COLOR)
glTexEnvi(GL_TEXTURE_ENV,GL_OPERAND2_RGB_EXT,GL_SRC_ALPHA)
glTexEnvi(GL_TEXTURE_ENV,GL_OPERAND0_ALPHA_EXT,GL_SRC_ALPHA)
glTexEnvi(GL_TEXTURE_ENV,GL_OPERAND1_ALPHA_EXT,GL_SRC_ALPHA)
glTexEnvi(GL_TEXTURE_ENV,GL_OPERAND2_ALPHA_EXT,GL_SRC_ALPHA)
glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_COMBINE_EXT)
glTexEnvi(GL_TEXTURE_ENV,GL_COMBINE_ALPHA_EXT,GL_MODULATE)
glTexEnvi(GL_TEXTURE_ENV,GL_SOURCE0_ALPHA_EXT,GL_TEXTURE)

I'm going to do this: glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA)

If you, future reader, are modifying your OgreGLRenderSystem as well, I'm going to do this change in GLRenderSystem::_setTextureBlendMode in OgreGLRenderSystem.cpp.

share|improve this answer
    
Ouch! I knew it was bad but never realized it was that bad. I'd actually guess it more likely supports a more minimal subset of modes and something in there tripped it over. Maybe constant as source2? (That GL_LINES for RGB scale is OK as GL_LINES is defined as 1; looks like an error in whatever you used to dump the calls). –  Jimmy Shelter Jun 18 '13 at 23:26
1  
If the conditional switch to glBlendFunc works, I'm probably just going to stop there. I've thrown a lot of hours after this problem, and there are other areas I've got to work on. Notably, the card doesn't have GL_EXT_blend_func_separate, which makes me think that the separate blending of RGB and alpha that Ogre is attempting to do may not fly. –  user1158478 Jun 18 '13 at 23:53
    
If it works well for you there's no reason not to stop there. –  Jimmy Shelter Jun 20 '13 at 16:40
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.