Is it worth to use index buffers?

Started by
11 comments, last by L. Spiro 8 years, 8 months ago

I'm making my own engine using C++ and DirectX 11 (I think I'm going to add support to DirectX 12 too, but I'm gonna wait for Windows 10 to download wink.png ). It uses its own format for meshes, which at the moment are converted from Wavefront (.obj).

I was thinking about making code to create a index buffer for each mesh, but then I thought:

Is there even a reason to use index buffers, other than memory consumption and storage?

Is there any performance advantage in using index buffers?

If there's no performance improvement at all, I'm only going to use index buffer if I ever go into trouble with memory usage and/or storage.

So, could you please help me?

Advertisement


Is there any performance advantage in using index buffers?

Yes, in some cases.

The first important thing to remember in most common cases is: Memory consumption reduction = performance improvement. This is due to the increasing gap between memory and processor speed, with processors getting faster at a rate much higher than memory (certainly true for CPUs and GPUs are likely not different).

Even outside from that, if you can eliminate "duplicate" shared vertices with an index buffer, the post-transform cache is more likely to being able to reuse the same vertices, which means that you can save many vertex shader executions/vertex processing. This goes along with common optimization techniques to make use of the post-transform cache, you might want to look into that.

There are exceptions, of course, you will not just have net gain by using index buffer. A 3D cube with lighting won't gain anything from an indexbuffer, since though the corner vertices share the same position they have different normals per side. But I belive that for general models, index buffers are almost always the right choice (you might want to use 16 bit indices if possible to save even more memory/performance).


Is there any performance advantage in using index buffers?

Yes, in some cases.

The first important thing to remember in most common cases is: Memory consumption reduction = performance improvement. This is due to the increasing gap between memory and processor speed, with processors getting faster at a rate much higher than memory (certainly true for CPUs and GPUs are likely not different).

Even outside from that, if you can eliminate "duplicate" shared vertices with an index buffer, the post-transform cache is more likely to being able to reuse the same vertices, which means that you can save many vertex shader executions/vertex processing. This goes along with common optimization techniques to make use of the post-transform cache, you might want to look into that.

There are exceptions, of course, you will not just have net gain by using index buffer. A 3D cube with lighting won't gain anything from an indexbuffer, since though the corner vertices share the same position they have different normals per side. But I belive that for general models, index buffers are almost always the right choice (you might want to use 16 bit indices if possible to save even more memory/performance).

At the moment, index buffers are a "optional" thing for meshes in my engine. So I might compare the size of the vertex-buffer-only file and the size of vertex-and-index-buffer-file and use the smallest. Thanks for your answer.

It is worth noting that some APIs (e.g. OpenGL ES 2) only allow for indexed drawing and if your engine wants to support that you then need to have fallback index buffers which contain a linear list of indices. But alone for the performance reasons mentioned above (and typical meshes) I would recommend using index buffers.

It is worth noting that some APIs (e.g. OpenGL ES 2) only allow for indexed drawing and if your engine wants to support that you then need to have fallback index buffers which contain a linear list of indices. But alone for the performance reasons mentioned above (and typical meshes) I would recommend using index buffers.

Thanks. Didn't think about that. If I ever make a port to Android or iOS (I think iOS uses OpenGL ES, doesn't it?) I'm gonna need that.

Almost in all cases using index buffers is a win. One nice property of index buffers is that they are guaranteed to be read contiguously forward by the hardware and hence its trivial for them to read ahead to ensure the data is there ahead of time. On some popular GPUs the index buffer read units don't even go though the main mem hierarchy and pollute the cache.

Another question to answer is whether to use index tri lists or indexed tri strips.

It is worth noting that some APIs (e.g. OpenGL ES 2) only allow for indexed drawing and if your engine wants to support that you then need to have fallback index buffers which contain a linear list of indices. But alone for the performance reasons mentioned above (and typical meshes) I would recommend using index buffers.

I don’t believe there are any API’s that require index buffers, and OpenGL ES * does not.

Another question to answer is whether to use index tri lists or indexed tri strips.

If you take a naive array of vertices then triangle strips are only faster generally speaking if the resulting index buffer is 75% or below compared to the original size (do your own research as well, as results may vary, but this is a rough good guess).

You should instead sort the vertices by best cache usage, which in my experience has yet to produce slower results than not (and significantly better than using triangle strips).
From there, if you then generate a triangle strip, my experiments show it only fruitful to keep the strip if the resulting index buffer is 25% or below (basically never).


L. Spiro

I restore Nintendo 64 video-game OST’s into HD! https://www.youtube.com/channel/UCCtX_wedtZ5BoyQBXEhnVZw/playlists?view=1&sort=lad&flow=grid

You should instead sort the vertices by best cache usage


what exactly does this mean? do you mean sorting the vertices so that when a triangle is drawn, each subsequent vertice of the triangle is next in line?(or at least as many as you can put together?)
Check out https://www.facebook.com/LiquidGames for some great games made by me on the Playstation Mobile market.
The way most GPU's work is that they have "post-transform vertex cache", which stores the results of the vertex shader for some number of vertices. The idea is that if you have the same index come up multiple times, it won't have to invoke the vertex shader every time. However since the cache size is limited, you want to sort your triangles so that the same indices are near each other in the index buffer.

Another thing to consider is that there is sometimes another cache (or caches) that's used for reading the actual vertex data needed by the vertex shader. For instance on AMD's recent hardware, all vertex fetching is done as standard vector memory loads that go through both the L2 and L1 caches. In light of that, you may also want to sort the order of the elements in your vertex buffer so that you get better locality, which reduces cache misses.

You should be able to find some links if you search for "vertex cache optimization" on Google. You'll probably want to use an existing implementation, like this one.

It is worth noting that some APIs (e.g. OpenGL ES 2) only allow for indexed drawing and if your engine wants to support that you then need to have fallback index buffers which contain a linear list of indices. But alone for the performance reasons mentioned above (and typical meshes) I would recommend using index buffers.

I don’t believe there are any API’s that require index buffers, and OpenGL ES * does not.

Another question to answer is whether to use index tri lists or indexed tri strips.

If you take a naive array of vertices then triangle strips are only faster generally speaking if the resulting index buffer is 75% or below compared to the original size.

You should instead sort the vertices by best cache usage, which in my experience has yet to produce slower results than not.
From there, if you then generate a triangle strip, my experiments show it only fruitful to keep the strip if the resulting index buffer is 25% or below (basically never).


L. Spiro

Actually both draw methods in GLES 2 need indices - glDrawArrays uses the indices from the bound array and glDrawElements gets the indices as an argument.

See https://www.khronos.org/opengles/sdk/docs/man/xhtml/glDrawArrays.xml for example. It says the index type needs to be unsigned byte or unsigned short - it doesn't look like the indices parameter is optional. And actually the documentation for draw elements that you linked states the number of indices to draw, not vertices..

And I know for a fact an API under NDA which definitely has no non-indexed draw capability ;)

This topic is closed to new replies.

Advertisement