Direct State Access
|Core in version||4.5|
|Core since version||4.5|
|Core ARB extension||ARB_direct_state_access|
Direct State Access (DSA) is a means of modifying OpenGL Objects without having to bind them to the context. This allows one to modify object state within a local context without affecting global state shared by all parts of an application. It also makes the API a bit more object-oriented, as functions that modify the state of objects can be clearly identified.
|This article is a stub. You can help the OpenGL Wiki by expanding it.|
The Nomenclature for Direct State Access's functions is a bit more consistent than the non-DSA naming. As with non-DSA functions, they follow the standard Verb-Object-Command syntax. However, there were several non-DSA functions that affected some object's state without naming the Object type in its function. In the case of DSA, all DSA functions consistently specify the Object, even if it makes the function name unwieldy.
The difference is that DSA functions use a different Object name from the non-DSA functions. Because OpenGL is defined to be implemented in C, function overloading cannot be used. So DSA functions are differentiated from their non-DSA versions by using a different Object name.
There is an inconsistency in how this new Object name was chosen. For some object types, the new Object name is the old Object name prefixed with "Named". Others objects use a longer version of the original, non-DSA Object name. Fortunately, all functions that act on a particular object will consistently use the same Object name:
|OpenGL Object Type||Context Object Name||DSA Object Name|
|Transform Feedback Object||"TransformFeedback"1||"TransformFeedback"|
|Vertex Array Object||N/A2||"VertexArray"|
- 1: Transform feedback objects have a lot of functions that use TF objects in rendering operations. But the actual state in them consists only of the buffers attached to GL_TRANSFORM_FEEDBACK_BUFFER via glBindBufferRange, as well as a captured primitive count. As such, while they had a formal Object name, it was only used for functions that used the object for feedback operations rather than state-accessing functions. So the existing name could be appropriated for DSA functions (to attach buffers to the feedback object).
- 2: The functions that manipulate this object were so inconsistently named that there was never really a consistent object name for them.
- 3: These object types already used DSA-style functions. For program objects, DSA-style uniform setting was added with separable programs in GL 4.2.
There are some functions which were introduced before OpenGL 4.5. These functions work in a DSA style, but use the old Object name. For example, glClearTexImage takes the texture object to be cleared as a parameter, rather than acting on context state. The DSA feature did not add variations on these that use the DSA-Object name.
Changes from EXT
The core DSA functionality, and the Core Extension equivalent, have some differences compared to the original EXT_direct_state_access extension. One of the most obvious is the fact that the EXT version supported a great deal of Compatibility state; the core version only supports core OpenGL functionality.
This also extends to not providing support for some things that are part of core OpenGL, but have been superseded by newer ways of doing the same thing. For example, the core DSA functions only allow the use of separate vertex format definitions, and storage allocated for Textures must be immutable. However, Buffer Object storage can still be mutable.
A more subtle change has to do with the dichotomy between object names and object data. In the pre-DSA days, glGen* functions generate object names only; they don't generate the state stored in those objects. That is generated by the various glBind* functions. This dichotomy became problematic if one wanted to modify an object's state without binding it. Newly created names would be associated with a state-less object.
Core DSA and EXT_DSA take different approaches to resolving this problem. In EXT_DSA, all of the DSA-style functions are permitted to take an object name that had no state data associated with it (ie: had not yet been bound). These functions were therefore required to be able to generate the default state behind those names, then perform whatever processing the function normally did.
Core DSA does not do this. If you pass a new object to any of the core DSA functions, they will fail with GL_INVALID_OPERATION. Instead, the object's state must be initialized. This can be done via glBind* functions (which goes against the point of the functionality), but the preferred method is to use the glCreate* set of functions. These create object names and fill them with their initial state. Those object types which have a target that defines the type of that object (Textures and Query Objects) have this type specified by their glCreate* function.
The core DSA functionality provides glCreate* support even for object types that technically do not need it. These being Sampler Objects, which already use a DSA-style interface, which is unchanged by core DSA (though sampler objects both use the EXT wording, where every DSA function that takes one will give it state).
This change also affected many of the API functions. For example, the DSA functions for modifying Textures all took both a texture and the texture's target in the EXT version. The core functions do not, as the texture type is defined when the object's state is created (either via glBindTexture or via glCreateTextures).
The core functionality also supports a few OpenGL features released since EXT_DSA was published. It provides full Multibind support for vertex array object buffer binding, and unlike EXT_DSA, it offers support for Query Objects.
Lastly, Cubemap Textures are more uniformly treated under core DSA. Immutable Storage Texture allocation made cubemap face targets unnecessary for allocating storage. But they were still used for uploading/downloading image data. DSA changes that. For pixel transfer commands, cubemaps are treated as a special case of Cubemap Array Textures; they're cubemap arrays with one layer, and therefore 6 layer-faces. So you always perform pixel transfers through the 3D versions of the SubImage functions. Though you still use Storage2D to allocate memory for them.