Jump to content
  • Advertisement
Sign in to follow this  
Ubik

OpenGL Vertices and indices in the same buffer?

This topic is 1267 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm thinking of having a single Buffer concept against having a concept for each of VertexBuffer, IndexBuffer and so on, mainly from the perspective of type safety (i.e. type "Buffer" vs types "VertexBuffer", "IndexBuffer" and so on). Both OpenGL and Direct3D tell that it is possible to mix different kinds of data in the same buffer, but also say that it might come with a performance penalty.

OpenGL's vertex buffer object extension text says:
 

Note that it is expected that implementations may have different
memory type requirements for efficient storage of indices and
vertices.  For example, some systems may prefer indices in AGP
memory and vertices in video memory, or vice versa; or, on
systems where DMA of index data is not supported, index data must
be stored in (cacheable) system memory for acceptable
performance.  As a result, applications are strongly urged to
put their models' vertex and index data in separate buffers, to
assist drivers in choosing the most efficient locations.

But that is very old text, apparently from 2003, so it might be completely outdated. So I looked into what D3D documentation says. Here's what D3D11_BIND_FLAG's Remarks section tells:
 

In general, binding flags can be combined using a logical OR (except the constant-buffer flag); however, you should use a single flag to allow the device to optimize the resource usage.

D3D11 is from 2008, so it's documentation may be not very relevant anymore in this regard too. I don't know what would be good specific terms to find this out, and don't really have too good chances of just testing on a multitude of platforms, so am asking from you now.

I guess I could ask this in two ways:

1) Is it (more often than not) a bad idea to make heterogeneous buffers (I have no idea if there is an official term for this) today?
2) Is it (more often than not) a good idea to make heterogeneous buffers today?

For more specific context, I'm personally interested in how things are in current hardware (and drivers) in the PC, not mobile nor console world, but also the not so recent HW interests me. (Though I have access to one not exactly new GPU myself when I just boot up my own 'puter, to personally test things out...) My API of choice is OpenGL. But let's not restrict this only to my circumstances, it would be interesting to know how things are in general.

Share this post


Link to post
Share on other sites
Advertisement

I believe that on current (and recent) hardware it's all just "memory", and that the days where a driver may prefer to store different buffer types differently are behind us.  This is definitely confirmed by e.g the Mantle documentation:

 

 

In the Mantle API, specialized vertex and constant buffers are removed in favor of more general buffer support. An application can use regular buffers to store vertex data, shader constants, or any other data.

 

In any event there may be organizational or data reasons to keep the buffers separate, but it appears as though you no longer have to.

 

Under D3D12, and since it has feature levels going down to 9, I would expect at some stage you'll want to keep them separate for performance reasons too, but I haven't looked at the D3D12 documentation in great detail.

Share this post


Link to post
Share on other sites

With GL vertex layout is defined by vertex attrib function call, so you can mix different data type on the same buffer as long as you use correct offset/stride and pay attention to data alignment.

However I don't know if you can bind a buffer to several "type bind point", ie array_element_buffer and array_buffer, or array_element_buffer and shader_storage_buffer, at the same time. I never read it was forbidden by the spec but I don't know the spec by heart.

 

On D3D12 it isdefinitively be possible since you only pass gpu virtual address, gpu doesnt know that they belong to the same buffer from OS or app perspective.

Share this post


Link to post
Share on other sites

 I just tried to do that with D3D11, using both index and vertex bind flags. It seems to work without complaints. Data looks fine, too. 

Share this post


Link to post
Share on other sites

Back in the day, GPUs weren't actually able to read indices from GPU memory. They were always streamed from main memory. But that is ancient history. Nowadays, on at least some hardware, I've heard that uniform buffers, texture buffers, and possibly shader storage buffers get special handling. The glBufferStorage API (which you should be using, not BufferData) requires you to pick a specific buffer type, not a mask. However on closer reading this appears to be simply a question of the buffer's binding point, not anything to do with the actual usage (which doesn't kick in until BindBuffer). I don't see anything offhand that says you can't bind the same buffer to more than one binding point, and from there it's just a question of offsets.

 

So yeah, go for it. I would be inclined to keep constant/uniform buffers and texture buffers separate from everything else, though.

Edited by Promit

Share this post


Link to post
Share on other sites

@mhagain: Good point on the new APIs revealing much about the current state of the hardware and them being largely agnostic about the buffer contents (as far as I can tell too).

 

@vlj: Your wording on it being forbidden by the spec somehow brought up one OpenGL-related thought I've had on background - the API may permit things, but may not actually work outside the common ways of use.

 

@unbird: Thanks for testing this out!

 

@Promit: I may very well be reading incorrectly between the lines, but I get the impression that mixing different kinds of data in single buffer (in old or current GL or D3D anyway) is not something you've done or seen done, at least enough to be a somewhat common pattern?

Share this post


Link to post
Share on other sites


I get the impression that mixing different kinds of data in single buffer (in old or current GL or D3D anyway) is not something you've done or seen done

 

unbird is the only one I've heard of. Without a clear indication that performance is drastically enhanced, it would be a bit of a pain to fill the buffer correctly (vertex-data + offset + index-data, or index-data + offset + vertex-data), if a D3D11 DrawIndexed call would be used for rendering. In spite of the advertised behavior, I was surprised when I (also) experimented and found that D3D11 didn't complain when the same buffer was bound to the input as both a vertex and index buffer! I didn't go further than that - i.e., I didn't calc the offset, fill the buffer, etc.

Share this post


Link to post
Share on other sites

On modern OpenGL 4: You can use glBufferStorage to create a single chunk of memory that can be used for: vertex, index, constants, UAV and texture buffers. The first binding point the memory is used with can be used as a hint to the driver for performance, but it's just a hint (and afaik... ignored by modern implementations).

On D3D12: See OpenGL 4.

On D3D11: You can use same buffer for vertex & index buffers, but constants have their own. UAV and texture buffers have their own binding point as well.

 

On WebGL: Every buffer can only be used for one specific type for security reasons (the browser can assume what contents the buffer will contain and perform a lot of validation; as long as you don't modify the buffer again, the validation triggers when you upload data, if WebGL allowed multiple binding points, the validation would have to trigger every time it's bound differently or with a different range which could cripple performance).

Share this post


Link to post
Share on other sites

@vlj: Your wording on it being forbidden by the spec somehow brought up one OpenGL-related thought I've had on background - the API may permit things, but may not actually work outside the common ways of use.

The recommended use (AZDO) encourages one buffer for everything, being bound at multiple binding points with different offsets. This is not "uncommon".
Of course, if you bind the same region (or an overlapping region) as a vertex buffer and as SSDO with write access, don't expect it to run glitch-free (because that's literally a hazard); same if you bind a buffer at an unaligned offset, etc etc.

Share this post


Link to post
Share on other sites


@Promit: I may very well be reading incorrectly between the lines, but I get the impression that mixing different kinds of data in single buffer (in old or current GL or D3D anyway) is not something you've done or seen done, at least enough to be a somewhat common pattern?

Correct, but that's not to suggest there's any issue with it. I've just never seen any of the documentation from the IHVs suggest that you should do it, so it never really crossed my mind to try it. I think it's a good idea if GPU memory fragmentation is a concern. 

 

This was a few years ago: https://developer.nvidia.com/sites/default/files/akamai/gamedev/files/gdc12/Efficient_Buffer_Management_McDonald.pdf

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!