7
\$\begingroup\$

Interleaved - all vertex data (position, normal, texcoord...) kept in 1 vertex buffer, separate - each vertex attribute is kept in a separate vertex buffer (1 for positions, 1 for normals...).

I know this question came up many times and I also know there's no 1 right answer (sadly). But I'd like to try to list the main advantages/disadvantages of both. Or maybe you have some general rules of thumb for when to use each.

  1. Advantages of interleaved:

    • faster? (all data for 1 vertex is fetched at once? sth about cache working better)?
    • less API calls (for creating and setting buffers but that's probably a very small difference)
  2. Advantages of separate:

    • when different shaders need different vertex attributes (e.g. one shader needs only position and another needs position, normal and texcoord) it's possible to provide each shader only the data it needs and there's no data duplication
    • when updating only e.g. position of vertices it's not necessary to resend the other attribute data (e.g. normals and texcoords)

If you see any other differences please write. From the above it generally looks like a struggle between memory and performance optimisation. But maybe I'm wrong? Maybe one is better/worse in most cases?

Edit: One more concern, actually - with interleaved buffers I could end up sending unnecessary data to GPU and the data bandwidth is a big bottleneck in today's cards. Should I worry about that?

\$\endgroup\$

closed as off-topic by Sean Middleditch, Josh Nov 29 '13 at 21:56

  • This question does not appear to be about game development within the scope defined in the help center.
If this question can be reworded to fit the rules in the help center, please edit the question.

  • \$\begingroup\$ I read now. Cache lines are 32-bytes at the minimum, interleaved. This applies to both reads and uploads. \$\endgroup\$ – MickLH Nov 29 '13 at 18:59
  • \$\begingroup\$ If you're so sure then you have to have some very strong arguments for that approach - could you share with us? \$\endgroup\$ – NPS Nov 29 '13 at 19:00
  • \$\begingroup\$ Updated. goodnight xo \$\endgroup\$ – MickLH Nov 29 '13 at 19:01
  • \$\begingroup\$ possible duplicate of Interleaved formats for meshes confusion \$\endgroup\$ – Sean Middleditch Nov 29 '13 at 19:01
  • 1
    \$\begingroup\$ @SeanMiddleditch I believe the thread you linked to (both question and answer) present a different problem than mine. I'm asking about differences betweend interleaved and separate approaches, Steve asked if he could save some memory by not duplicating normal data for each vertex. \$\endgroup\$ – NPS Nov 29 '13 at 19:09
8
\$\begingroup\$

I've recently implemented both versions in OpenGL (4.3) and using the (Crytek) Sponza scene as a test render scene, I had shaders that used either only a subset or the complete set of all vertex attributes defined.

There was one difference to your setup: In the non-interleaved case, the attributes were inside the same vertex buffer, too. It easy to do this with OpenGL, you can just bind byte offsets to a certain attribute with glVertexAttribPointer(...) with the last parameter. An equivalent option probably exists for DirectX.

Specifically, while rendering a shadow map, which only needs vertex positions (in my case) went from ~210 to ~220 FPS when using non-interleaved buffers, which is a difference of about 0.2ms. In other words, you couldn't even go from 60 FPS to 61 FPS with that speedup.

When rendering the scene from the shadowing light's perspective, but using all attributes (in my case, a deferred shading geometry pass), the performance didn't change at all between the two versions.

I can only guess, but I think the reason the shadow map rendering improved is because GPUs probably (like CPUs) dont just pull single bytes, words or dwords out of memory with one memory access, but instead pull more bytes (on most modern CPUs this would be 64 bytes per access) and cache it somewhere. When data is interleaved, the GPU might pull one set of position/normal/texcoord/whatever per memory access at once, of which all but the position will be wasted memory bandwidth if you only use position.

One caveat: I was not memory bandwidth bound in my test case, so if memory throughput is your bottleneck, the measurements might come out differently.

Overall I'd suggest you leave it the way you have it now and change it later once you notice that some optimization is necessary. Changing it doesn't take long, you only need to change how the data is handed over to GPU memory and change how attributes are bound using your graphics API.

\$\endgroup\$
  • \$\begingroup\$ +1, especially for giving some hard data. I expect that a possible reason why you didn't see as much perf improvement with the non-interleaved case is that it also requires extra state changes, which the interleaved case may be able to avoid. It's all a balancing act... \$\endgroup\$ – Maximus Minimus Nov 29 '13 at 21:04
  • \$\begingroup\$ +1 for looking at shadow mapping - that's a good test for this question since shadows are often vertex-bound and only need one or two of the many vertex attributes. The benefits will vary according to scene and hardware - denser geometry would yield more of a speedup, and platforms with less memory BW would do so as well. This optimization was quite useful on the PS3 - probably not so much on modern high-end PCs or the new consoles, but probably still useful on mobile platforms. \$\endgroup\$ – Nathan Reed Nov 29 '13 at 21:55
0
\$\begingroup\$

interleaved: if is easier to understand and to manage memory wise and code wise. Instead of having 4 buffer you have just one and that's it.

separate: there is no practical advantage in sharing resources, managing 3d stuff is difficult as it is and by having the separate streams shared would only create a nightmare. You might gain some memory by doing that but it's not worth it.

on performance there might be a difference , at least on some Android GPU i know that you will have different results.

\$\endgroup\$
  • \$\begingroup\$ Only difficult for a human \$\endgroup\$ – MickLH Nov 29 '13 at 19:06
  • \$\begingroup\$ You said "might gain some memory" - when I have very big models (idk, 100k vertices? more?) and say 3 different shader types rendering that model isn't that a lot of memory? \$\endgroup\$ – NPS Nov 29 '13 at 19:07
  • 1
    \$\begingroup\$ @NPS the API provides workarounds you can have interleaved vertices with positions/normals etc and use in the shaders just what you want. \$\endgroup\$ – Raxvan Nov 29 '13 at 19:22
  • \$\begingroup\$ @Raxvan Ok then which one is better - 2 vertex buffers (1 with [position, normal] and the other with [position, normal, texcoord]) and using each one for its respective shader or having just 1 vertex buffer (the latter one) and using it for both shaders? \$\endgroup\$ – NPS Nov 29 '13 at 19:27
  • \$\begingroup\$ @NPS the last one for both, if the shader doesn't want the normals for example you can use that buffer with no problems , there will be a step in setup where you specify the streams and there you can just ignore the normals. \$\endgroup\$ – Raxvan Nov 29 '13 at 19:28

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