23
votes

Given we are using OpenGL 4.5 or have support for the GL_ARB_direct_state_access extension, we have the new function glCreateBuffers.

This function has an identical signature to glGenBuffers, but specifies:

returns n previously unused buffer names in buffers, each representing a new buffer object initialized as if it had been bound to an unspecified target

glGenBuffers has the following specification:

Buffer object names returned by a call to glGenBuffers are not returned by subsequent calls, unless they are first deleted with glDeleteBuffers.

So any buffer name returned by glCreateBuffers will never be used again by itself, but could be used by glGenBuffers.

It seems that glCreateBuffers will always create new buffer objects and return their names, and glGenBuffers will only create new buffers if there are no previous buffers that have since been deleted.

What advantage does adding this function have?

When should I use glCreateBuffers over glGenBuffers?


P.S.
I think this stands for all glCreate* functions added by GL_ARB_direct_state_access

3
One says "each representing a new buffer object", the other says "no buffer objects are associated with the returned buffer object names". You say "glGenBuffers will only create new buffers if there are no previous buffers that have since been deleted", but glGenBuffers will never create new buffers.Ben Voigt
Ah, so you never need to call glBindBuffer, makes senseRamblingMad
@BenVoigt make an answer man, that's all the answer I need.RamblingMad
But you will still need to call glBindBuffer, because "initialized as if it had been bound to an unspecified target" is not terribly useful. Probably there's some difference as what operations are allowed before calling glBindBuffer.Ben Voigt
@BenVoigt but it is useful if used with glVertexArray*Buffer[s]RamblingMad

3 Answers

15
votes

What you are noticing here is basically tidying up the API for consistency against Shader and Program object creation. Those have always been generated and initialized in a single call and were the only part of the API that worked that way. Every other object was reserved first using glGen* (...) and later initialized by binding the reserved name to a target.

In fact, prior to GL 3.0 it was permissible to skip glGen* (...) altogether and create an object simply by binding a unique number somewhere.

In GL 4.5, every type of object was given a glCreate* (...) function that generates and initializes them in a single call in GL 4.5. This methodology fits nicely with Direct State Access, where modifying (in this case creating) an object does not require altering (and potentially restoring) a binding state.


Many objects require a target (e.g. textures) when using the API this way, but buffer objects are for all intents and purposes typeless. That is why the API signature is identical. When you create a buffer object with this interface, it is "initialized as if it had been bound to an unspecified target." That would be complete nonsense for most types of objects in GL; they need a target to properly initialize them.

The primary consideration here is that you may want to create and setup state for an object in GL without affecting some other piece of code that expects the object bound to a certain target to remain unchanged. That is what Direct State Access was created for, and that is the primary reason these functions exist.

In theory, as dari points out, initializing a buffer object by binding it to a specific target potentially gives the driver hints about its intended usage. I would not put much stock in that though, that is as iffy as the actual usage flags when glBufferData (...) is called; a hint at best.

4
votes

OpenGL 4.5 Specification - 6.1 Creating and Binding Buffer Objects:

A buffer object is created by binding a name returned by GenBuffers to a buffer target. The binding is effected by calling

void BindBuffer( enum target, uint buffer );

target must be one of the targets listed in table 6.1. If the buffer object named buffer has not been previously bound, the GL creates a new state vector, initialized with a zero-sized memory buffer and comprising all the state and with the same initial values listed in table 6.2.

So the difference between glGenBuffers and glCreateBuffers is, that glGenBuffers only returns an unused name, while glCreateBuffers also creates and initializes the state vector described above.


Usage:

It is recommended to use glGenBuffers + glBindBuffer, because

the GL may make different choices about storage location and layout based on the initial binding.

Since in glCreateBuffers no initial binding is given this choice cannot be made.

4
votes

glCreateBuffers does not have a target because buffer objects are not typed. The first binding target was only ever used as a hint in OpenGL. And Khronos considered giving glCreateBuffers a target parameter, but they decided against it:

NamedBufferData (and the corresponding function from the original EXT) do not include the <target> parameter. Does implementations may make initial assumptions about the usage of a data store based on this parameter. Where did it go? Should we bring it back?

RESOLVED: No need for a target parameter for buffer. Implemetations[sic] don't make usage assumption based on the <target> parameter. Only one vendor extension do so AMD_pinned_memory. A[sic] for consistent approach to specify a buffer usage would be to add a new flag for that <flags> parameter of BufferStorage.

Emphasis added.