- Buffer Objects
- Vertex Array Objects
- Asynchronous query objects
- Framebuffer Objects
- Unconventional objects:
OpenGL Objects are defined in terms of the context state that they contain. When they are bound to the context, the state that they contain is mapped into the context's state. Thus, changes to context state will be stored in this object, and functions that act on this context state will use the state stored in the object.
State and Objects
OpenGL is defined as a state machine. The various API calls change the OpenGL state, query some part of that state, or cause OpenGL to use its current state to render something.
Objects are always containers for state. Each particular kind of object is defined by the particular state that it contains. An OpenGL object is a way to encapsulate a particular group of state and change all of it in one function call.
Remember: this is just how OpenGL is defined by its specification. How these objects are actually implemented in drivers is another matter. But that is nothing you need to worry about; what matters is how objects and state interact as defined by the specification.
Object Creation and Destruction
To create an object, you generate the object's name (an integer). This creates a reference to the object. The object will only contain its default state when it is first bound to the context.
The functions to generate the object's name are of the form
glGen*, where * is the object's type. All functions of this type have the same signature:
void glGen*(GLsizei n, GLuint *objects);
This function generates
n objects of the given type, storing them in the array given by the
objects parameter. This allows you to create multiple objects with one call.
An object name is always a GLuint. These names are not pointers, nor should you assume that they are. They are references, numbers that identify an object. They can be any 32-bit unsigned integer except 0. The object number 0 is never a valid object; it is how you specify that you don't want to use an object.
- Legacy Note: In OpenGL versions before 3.0, the user was allowed to ignore the generation step entirely. The user could just decide that "3" is a valid object name, and start using it like an object. The implementation would then have to accept that and create the object behind the scenes when you first start using it. In GL 3.0, this behavior was deprecated. In core GL 3.1 and above, this is no longer allowed. Regardless of the version of OpenGL, it is always good practice to use
glGen*rather than making up your own object names.
Once you are finished with an object, you should delete it. The functions for this are of the form
glDelete*, using the same object type as before. These functions have this signature:
void glDelete*(GLsizei n, const GLuint *objects);
This works like the
glGen functions, only it deletes the objects instead of creating them.
After an object is deleted, its name is no longer valid. A subsequent
glGen* call may or may not reuse a previously-deleted name; you should not make assumptions either way.
Object Attachment and Orphaning
glDelete* on an object does not guarantee its immediate deletion. Because OpenGL is allowed to execute rendering commands well after you issue them (for maximum parallelism and performance), it is entirely possible for an object to remain with the OpenGL server for some time before it actually deletes it.
Note that this is an implementation detail. Once you call
glDelete* on the object, the object name becomes useless. You can no longer refer to that object, even if the object is still being used by the rendering pipeline.
This is not the case for objects that can become attached to other objects. If you delete an object that is attached to another object, the object will continue to exist until all objects it is attached to are deleted, or the object becomes unattached. This is different from the orphaning described above; you can still refer to the object through normal commands. You shouldn't, because the object can be deleted later by commands that normally would not delete objects, but you still can.
If you have bound an object to the current GL context, and you call
glDelete* on it, this will also cause that binding to be terminated. The context will be as though you had bound object name "0" (not an object) to the context. If you have bound the object to another context (though object sharing, see below), then the object will not be deleted.
Because objects in OpenGL are defined as a collections of state, to modify objects, you must first bind them to the OpenGL context. Binding objects to the context causes the state in them to be set to be the current context's state. This means that any functions that change the state governed by that object will simply change the state within the object, thus preserving that state.
Binding a newly generated object name will create new state for that object. In some cases, the target to which it is first bound (see below) will affect properties of the newly created state for the object.
Different objects have different binding functions. They do share a naming convention and general parameters:
void glBind*(location, GLuint object);
The * is the type of object, and object is the object to be bound.
The location is where different object types differ. Some objects can be bound to multiple locations in the context, while others can only be bound to a single specific place. For example, a buffer object can be bound as an array buffer, index buffer, pixel buffer, transform buffer, or various other possibilities. If an object can be bound to multiple locations, then there will be some kind of parameter to define where the binding happens. glBindBuffer takes an enumeration, for example.
Different locations have separate bindings. So you can bind a buffer object as an array, and a different buffer object as an index buffer without having any crosstalk between them.
If an object is bound to a location where another object is also bound, the previously bound object will be unbound.
All OpenGL objects have the concept of an "object 0". But they don't all have an actual object that represents that concept. For example, with Framebuffer Objects, object 0 means the Default Framebuffer, which is a special case. Buffer Objects do not have an object 0, so attempting to do something that requires a bound buffer object while 0 is bound is an error. Texture objects do have an object 0; this is effectively an un-deletable object that you could theoretically store data in (but you never should).
If you bind object 0 to a target, then the currently bound object will be unbound. If that object type has an object 0, then that object will be bound to the target. Otherwise, nothing will be bound to that target.
You can create multiple OpenGL contexts. This is useful, as the current GL context is thread-specific. Normally, each context is entirely separate from the others; nothing done in one can affect the others.
At context creation time however, you are able to create a context that shares objects with another context. This means you can use objects created in one context in another context.
Not all object types can be shared across contexts. Objects that contain references to other objects cannot be shared. These include Framebuffer Objects, Program Pipeline objects, Query Objects, Transform Feedback objects, and Vertex Array Objects. All other object types can be shared. This includes GLSL Objects and Sync Objects, which do not follow the OpenGL Object model.
- Buffer Objects, with a number of different uses:
- Transform Feedback Objects
- Vertex Array Objects
- Texture Objects
- Query Objects
- Framebuffer Objects
The following are not OpenGL Objects. They are called "objects" in the OpenGL API, but they do not follow the well-defined conventions specified above:
- Sync Objects
- GLSL Shader and Program Objects
- Except for program pipeline objects, which do follow the OpenGL Object conventions.