Index Buffer Object vs. Index Array

Started by
8 comments, last by marcClintDion 10 years, 10 months ago

After writing some code to load a 3ds mesh (using lib3ds) I found that rendering using indices caused problems, at least for me. After storing all the vertex data into one array. I divide each lib3dsMesh into my own Submesh subclass which stores index data.

My question is what are (if any) the performance differences in storing index data in an array and using it to call glDrawElements:



GLuint* indices;
void draw()
{
   ...
  glDrawElements(GL_TRIANGLES, submesh.i_data.size(), GL_UNSIGNED_SHORT, &indices[0]);
  ...
}
 

And using a BufferObject to store them


GLuint* indices;
...Fill array...

void build()
{
    glGenBuffers(1,&ibo);
    ...Fill buffer...
}

void draw()
{
  glBindBuffer(GL_ELEMENT_ARRAY,...);
   ...
  glDrawElements(GL_TRIANGLES, submesh.i_data.size(), GL_UNSIGNED_SHORT, <submesh offset>);
  ...
}

Advertisement

You use the Index buffer that way not only you save memory on reusing vertices. You can also used index buffers as a way to split the mesh by material id, that way If you have a mesh that uses multiple material, you can break each section into his own index buffer while referencing the same vertex buffer. For example let's say you wanted to draw an Quad, you would basically need 6 vertices. But with an index buffer you only need 4 vertices and the index buffer would reference which one of those vertices it needs to use to create the quad.

You use the Index buffer that way not only you save memory on reusing vertices. You can also used index buffers as a way to split the mesh by material id, that way If you have a mesh that uses multiple material, you can break each section into his own index buffer while referencing the same vertex buffer. For example let's say you wanted to draw an Quad, you would basically need 6 vertices. But with an index buffer you only need 4 vertices and the index buffer would reference which one of those vertices it needs to use to create the quad.

Wut? Whether the index data is stored in a vertex buffer, or whether it's stored in an array in system memory, they'll both consume exactly the same amount of memory.

My question is what are (if any) the performance differences in storing index data in an array and using it to call glDrawElements:

The Buffer version *should* be quicker (unless you are using an integrated graphics card that makes use of system memory instead of its own dedicated GDDR5 ram. In general, prefer vertex buffer objects, to the older vertex array approach.

You use the Index buffer that way not only you save memory on reusing vertices. You can also used index buffers as a way to split the mesh by material id, that way If you have a mesh that uses multiple material, you can break each section into his own index buffer while referencing the same vertex buffer. For example let's say you wanted to draw an Quad, you would basically need 6 vertices. But with an index buffer you only need 4 vertices and the index buffer would reference which one of those vertices it needs to use to create the quad.

Wut? Whether the index data is stored in a vertex buffer, or whether it's stored in an array in system memory, they'll both consume exactly the same amount of memory.

>>>My question is what are (if any) the performance differences in storing index data in an array and using it to call glDrawElements:

The Buffer version *should* be quicker (unless you are using an integrated graphics card that makes use of system memory instead of its own dedicated GDDR5 ram. In general, prefer vertex buffer objects, to the older vertex array approach.

I think you are confuse, the OP is not asking if he is storing the index into the vertex buffer. He is talking about splitting his mesh into Submeshes.

Just use buffer objects, it's the right way nowadays.

I think you are confuse, the OP is not asking if he is storing the index into the vertex buffer. He is talking about splitting his mesh into Submeshes.

OP didn't ask anything about _not_ using indices. He wanted to know the difference in those two examples he gave, that reads in the topic. The first one has it's data saved on the system memory and the second one has it on the GPU. They'll both consume the same amount of memory, just like RobTheBloke said.

Derp

I think you are confuse, the OP is not asking if he is storing the index into the vertex buffer. He is talking about splitting his mesh into Submeshes.

Read the question again: the OP is talking about indexed drawing in both cases (notice the glDrawElements call in both). In case 1 he's got the index data in system memory, in case 2 he's got it in a buffer object. He does mention separate meshes for sure, but focus on the bit beginning with "my question is", which is nothing to do with separate meshes.

Direct3D has need of instancing, but we do not. We have plenty of glVertexAttrib calls.

There can be a substantial improvement when implementing glDrawElements vs. glDrawArrays, but not in all cases. If you have a lot of non-contiguous mesh then there may actually be a performance hit. Particles, for instance. There has to be lots of duplicate vertices for the index tracking method to improve performance because there is additional calculation overhead. I'm not sure that the extra memory used is much of a problem these days since fast, cheap ram is standard issue now. What 'BornToCode' said about using indices to break up multi-component models into pieces is something to consider, however if you do this, pay close attention to getting the index count perfect or you will likely see horrible crashes. There is a document called 'OpenGL ES Programming Guide for iOS' that has some advice on this matter. http://developer.apple.com/library/ios/#documentation/3ddrawing/conceptual/opengles_programmingguide/TechniquesforWorkingwithVertexData/TechniquesforWorkingwithVertexData.html Here's an nVdia document with many ideas for optimizations. http://http.developer.nvidia.com/GPUGems/gpugems_ch28.html Remember that their are now half a dozen excellent GPU companies and they all have different ways of doing things under the hood, even though the interfaces are mostly the same. What works best on one may not work best on all of them. That Apple document suggests that you try both ways and see what works best for your situation.

Consider it pure joy, my brothers and sisters, whenever you face trials of many kinds, 3 because you know that the testing of your faith produces perseverance. 4 Let perseverance finish its work so that you may be mature and complete, not lacking anything.

Sponji and mhagain are right, that was my question and thank you for your answers. As well as marcClintDion, thank you for your descriptive answer, and references(!).

This was more of a simply a conceptual question since I noticed it could work both ways.

One thing worth noting about indexed rendering. As well as saving memory from eliminating duplicate verts (not that important as memory is no longer a scarce resource for many use cases) and as well as saving VS transforms from being able to reuse the results of previous ones for duplicate verts (very important) indices also allow you to concatenate multiple primitives together to a single draw call.

Let's take that particle system example mentioned upthread. In the old days when you had the GL_QUADS primitive type this wasn't a big deal; with GL_QUADS deprecated in recent GL_VERSIONs (or not present at all in ES) a particle system may be exactly where you need indices the most. Represent each particle as a tristrip, and use indices to join them all in a single GL_TRIANGLES call, and you can get much greater efficiency than using degenerate triangles (an index will always be smaller than a vertex, and the 6 indices needed to join strips this way are much smaller than the extra verts needed).

Of course, there are other solutions available to this problem too (e.g. point sprites, instancing, geometry shaders, primitive restart) but they're not always available (particularly if we're thinking ES) and each has their own particular quirks. Using indices is the most robust general-case solution.

With specific relevance to meshes, one case where indices helps is with a mesh composed of multiple strips and fans. Indices are a great way of joining all those strips and fans together and being able to handle the entire mesh in a single draw call; you may not get much vertex reuse, and you may get extra memory usage, but that single draw call versus 10s, 100s or even 1000s of draw calls should more than offset things and give you faster overall performance on balance.

As always - profile and determine which is best for your own use case, but be aware that there is more to indices than just saving memory or reusing duplicate verts - even if neither of those two apply, you may still gain advantages from them.

Direct3D has need of instancing, but we do not. We have plenty of glVertexAttrib calls.

I clearly need to pay more attention to what I'm reading, I thought you were asking about whether or not to use indices, when really you were asking about whether or not you should store them in system memory or video memory. Silly. Anyways, on the this document http://http.developer.nvidia.com/GPUGems/gpugems_ch28.html it says under the heading "28.3.3 Optimizing Vertex Processing" that for some cache optimizations to take place, you have to use indexed geometry. I suspect that you'd have to use an index buffer for this to work but I'm guessing at this, I'm assuming that you have to explicitely send the index to the GPU for it to be aware of the index. The following document seems to hint at this, under the heading "Take full advantage of Tegra’s sophisticated post-transform cache by following these guidelines:" http://docs.nvidia.com/tegra/data/Optimize_OpenGL_ES_2_0_Performance_for_Tegra.html I think that what they are saying is: If the GPU does not have a copy of the index then the values calculated for the first vertex cannot be cached and reused for redundant vertices so the vertex processor has to now run again and again needlessly for overlapping points.

Consider it pure joy, my brothers and sisters, whenever you face trials of many kinds, 3 because you know that the testing of your faith produces perseverance. 4 Let perseverance finish its work so that you may be mature and complete, not lacking anything.

This topic is closed to new replies.

Advertisement