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. Changes to the context state will then be 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. This creates an empty object of the given type. The state that the empty objects have is well-defined by the specification for each object's type. So these objects are not created with undefined state.
The functions to do this 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 names, 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
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.
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 should n'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 also means that any functions that change the encapsulated state will simply change the state within the object, thus preserving that state.
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 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. Buffer objects take 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. If the
object parameter is object 0 (not an object), then the currently bound object to that will be unbound, but no new object will be bound.
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. The unsharable objects tend to be ones made from simple state; objects that hold lots of data, like buffers or textures, are sharable.
Notable Object Types
- Buffer Objects, with a number of different uses:
- Vertex Array Objects
- Texture Objects
- Shader and Program Objects
- Framebuffer Objects