3
\$\begingroup\$

I'm benchmarking some simple code for drawing using OpenGL.

In the following code, the number of indices being drawn is 4,644 (or 1,548 triangles per frame = @60fps 92,880 Triangles per second).

glMatrixMode(GL_PROJECTION);                        
glLoadIdentity();                                   
glOrtho(0, screenSize.width, screenSize.height, 0, 0, 1);
glMatrixMode(GL_MODELVIEW);                         
glLoadIdentity();                                   
glDisable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnable(GL_TEXTURE_2D);

glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(venomGLAttribute), ,drawingTexturedList.attrib[0].color);
glVertexPointer(2, GL_SHORT, sizeof(venomGLAttribute), &drawingTexturedList.attrib[0].pos[0]);
glTexCoordPointer(2, GL_FLOAT, sizeof(venomGLAttribute), &drawingTexturedList.attrib[0].UV[0]);
glDrawElements(GL_TRIANGLES, drawingTexturedList[cnt].currentIndice /*4644*/, GL_UNSIGNED_INT, drawingTexturedList[cnt].Indices);

This takes 100% of one of my CPU's. If I take out the call to glDrawElements but still perform all the other steps (geometry preperation, gl*Pointer setup) I see my CPU stay at ~3%.

Is this expected behaviour? The machine I'm running on has a GeForce 8800GTX and a Dual Core @ 2.66Ghz.

Using fps as a measurement (which isn't perfect I realise) and using gDEBugger to confirm my findings, rendering 27,904 triangles a frame in a single call to glDrawElements brings my frame rate down to ~35fps (or 977,640 triangles a second).

Is there a better way to pack my data than I'm doing or perhaps a better way to send the data than glDrawElements? I don't think using a VBO will help as the data being sent changes every frame.

Any idea's would be appreciated!

\$\endgroup\$

2 Answers 2

3
\$\begingroup\$

Yes, it's somewhat to be expected (although your throughput is really low).

You're using about the worst method of drawing with vertex arrays: drawing indexed with client-side vertex data requires the GL implementation to:

  • parse all the indices to find the min/max on each draw
  • transfer all the vertex data from min to max on each draw.

Note that if you remove the draw, the GL will not do any of it, and it will be real fast.

if you don't want to use VBOs (they still help in that the GL can figure out easier how much to transfer), you can use glDrawRangeElements, which specifies the range of indices that the GL will transfer (ie the first of the 2 bullets).

Also, are the indices changing each frame too ? If they don't, you can store them in an index buffer. (but be careful: at that point, if you don't use glDrawRangeElements, the GL usually has to bring the index buffer back from the device, find min/max, and transfer vertex data. That's even worse than your current state)

\$\endgroup\$
4
  • \$\begingroup\$ Moving over to glDrawRangeElements didn't seem to make a difference. However moving to VBO's did actually speed it up considerably even though the data is being changed every frame. I'm seeing a throughput of about 15 million triangles / second now and a much lower CPU cost. Cheers! \$\endgroup\$
    – Olly
    Aug 6, 2010 at 13:12
  • \$\begingroup\$ @Olly: good to know you solved it. Whether the GL implements the optimizations I talked about really depends on each implementation you use, sadly. \$\endgroup\$
    – Bahbar
    Aug 7, 2010 at 12:11
  • \$\begingroup\$ I currently changed my implementation (using VBOs) from using glDrawElements, with a specified range, and client-side indices to using an ELEMENT_ARRAY_BUFFER (an "index buffer"), and still drawing with glDrawElements (not RangeElements), and the performance just dropped! My draw calls went from taking 9 ms to 34 ms for the same mesh. Is that expected? I expected the opposite. \$\endgroup\$
    – AzP
    Feb 17, 2016 at 12:54
  • \$\begingroup\$ Now I even tried implementing using glDrawRangeElements with proper min/max and it still takes 34 ms. \$\endgroup\$
    – AzP
    Feb 17, 2016 at 16:47
0
\$\begingroup\$

Have you tried simply reducing the size of the array, and seeing if it makes a difference? I have a feeling you are getting a false positive; by taking out the ONLY draw call, I think you are affecting OpenGL more significantly and I'm pretty sure if you replace it with an easier call you'll still see 100% CPU.

If that is the case, then you need to make sure you are sleeping in each iteration of the game loop, or enable vsync. If you don't sleep and just have a tight draw loop then you will naturally take up 100% of one CPU, but if you just add a sleep(0) call it should reduce to ~0% CPU.

Or I could be totally wrong; if that's the case, I apologize in advance.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ I have VSync enabled. Plus I'm seeing the higher CPU when the draw call is in. If I take the draw call out I idle at ~3%. In fact if I do everything apart from the call to glDrawElements, it is steady at 3%. With the one call in, 100% on one CPU. \$\endgroup\$
    – Olly
    Aug 4, 2010 at 18:07

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .