Skip to main content
Add info about groups
Source Link
AzP
  • 165
  • 1
  • 8

There are 13 different groups, so the draw command will be called 13 times.

I've tried drawing the mesh in five different ways and the results are quite surprising.

I've tried drawing the mesh in five different ways and the results are quite surprising.

There are 13 different groups, so the draw command will be called 13 times.

I've tried drawing the mesh in five different ways and the results are quite surprising.

Source Link
AzP
  • 165
  • 1
  • 8

Performance of glDrawElements vs glDrawRangeElements vs glDrawArrays

I've looked around on the web trying to find a good answer to this, but am unable to find one. Different forums mention driver bugs and the likes, but these discussions are usually almost 10 years old, so bugs should probably have been fixed by now. So, to the question!

I'm drawing a mesh that consists of 628 008 vertices, normals and texture coordinates. I also have indices for the mesh, but the indices are the worst kind of indices: they do not re-use vertices, but actually just list the vertices in order (or close to). So we have 628 008 indices as well. Yes, I can re-write this to re-use vertices, but that's not really where my question is going.

The mesh is drawn using VBOs (vertices, normals, texture coords) in a VAO, and two different shaders: one for texturing one part of the mesh, and another shader for another non-textured part. To do this, I'm using the OBJ format and material groups (exported from Blender). The mesh is split into material groups, describing with which material a batch of indices shall be drawn.

The VBOs are set up to be drawn as GL_STATIC_DRAW since it is never changed.

I then loop over the material groups and draw the range of indices described in each group, like:

  for( const auto& group : mesh)
    if( group should use texturing )
    {
      enable texturing shader with phong material
      set texturing uniforms
      set material stuff
      set mvp, etc
    }
    else
    {
      enable phong material shader
      set material stuff
      set mvp, etc
    }
    draw(group)
  }

I've tried drawing the mesh in five different ways and the results are quite surprising.

  1. glDrawArrays.
  2. glDrawElements with indices fed using pointer to index array. (reffered to as CPU-side indices below)
  3. glDrawElements using GL_ELEMENT_ARRAY_BUFFER and offset fed to command
  4. glDrawRangeElements with indices fed using pointer to index array.
  5. glDrawRangeElements using GL_ELEMENT_ARRAY_BUFFER and offset fed to command

The [start, end] vertex indices fed to glDrawRangeElements are calculated when reading the mesh at start-up so they are correct and precise. This could be a performance problem otherwise, according to the spec.

The results in ms (measured on CPU side using C++11 timers, using 500 samples and calculated mean value, collecting 3 values since the first frame's timing is huge):

glDrawArrays:
            Median: 8.0 Mean: 8.9 Max: 217.0 Total: 4285.0 Samples: 482
            Median: 8.0 Mean: 8.8 Max: 43.0 Total: 4345.0 Samples: 494
            Median: 8.0 Mean: 8.2 Max: 14.0 Total: 4125.0 Samples: 501

glDrawElements:
GPU Indices (ELEMENT_ARRAY): 
            Median: 34.0 Mean: 44.1 Max: 597.0 Total: 20388.0 Samples: 462
            Median: 34.0 Mean: 33.9 Max: 63.0 Total: 16973.0 Samples: 500
            Median: 33.0 Mean: 33.5 Max: 80.0 Total: 16797.0 Samples: 501
CPU Indices (pointer to CPU-side indices):
            Median: 9.0 Mean: 10.3 Max: 236.0 Total: 5027.0 Samples: 488
            Median: 9.0 Mean: 9.2 Max: 32.0 Total: 4581.0 Samples: 500

glDrawRangeElements:
CPU Indices (pointer to CPU-side indices):
            Median: 9.0 Mean: 10.1 Max: 221.0 Total: 4640.0 Samples: 459
            Median: 10.0 Mean: 9.6 Max: 22.0 Total: 4780.0 Samples: 500
            Median: 10.0 Mean: 9.5 Max: 32.0 Total: 4774.0 Samples: 501

GPU Indices (ELEMENT_ARRAY): 
            Median: 35.0 Mean: 36.9 Max: 597.0 Total: 16101.0 Samples: 436
            Median: 34.0 Mean: 35.0 Max: 55.0 Total: 17517.0 Samples: 500
            Median: 39.0 Mean: 39.1 Max: 64.0 Total: 19448.0 Samples: 497

So my huge surprise is: How come GPU-side indices takes so much longer? The frame rate literally drops to less than half (from about 34 fps to 15 fps).

What can be the reason for this? My guess would have been that the performance timings should be in this order (since we have crappy indices and they aren't really re-using anything):

  1. glDrawArrays <- Fastest
  2. glDrawRangeElements (using ELEMENT_ARRAY)
  3. glDrawElements (using ELEMENT_ARRAY)
  4. glDrawRangeElements (using pointer to indices)
  5. glDrawElements (using pointer to indices) <- Slowest

Why do you think that the performance is so bad using ELEMENT_ARRAY_BUFFER bound to the VAO? Is this driver specific? Is it because there are so many indices and memory have to be swapped around in the driver?

Hardware: MacPro running Windows 8 Dual AMD FirePro D300, 2048 MB dedicated graphics memory