glMultiDrawElementsIndirect
Runs many indexed draws, each described by a command in a GPU buffer, in one call.
Signature
void glMultiDrawElementsIndirect(GLenum mode, GLenum type, const void *indirect, GLsizei drawcount, GLsizei stride);
How it works
The core of a GPU-driven renderer. Put every mesh's vertices and indices in shared buffers, write one command per object into a GL_DRAW_INDIRECT_BUFFER, and a single call draws them all:
struct DrawElementsIndirectCommand { GLuint count; // indices to draw GLuint instanceCount; // copies (0 = skip this draw) GLuint firstIndex; // first index in the element buffer GLint baseVertex; // added to every index GLuint baseInstance; // first instance for per-instance attributes };
The CPU cost becomes one call instead of thousands. A culling compute shader can set instanceCount to 0 for objects outside the view, and the shader tells draws apart with gl_DrawID to fetch each object's matrix and material.
Parameters
Primitive type.
Index type: GL_UNSIGNED_INT or GL_UNSIGNED_SHORT.
Byte offset of the first command in the indirect buffer.
Number of commands.
Bytes between commands; 0 = tightly packed (20 bytes each).
Tips & pitfalls
gl_DrawID (GL 4.6, or ARB_shader_draw_parameters) gives the index of the current command in the shader.
All draws share the same VAO, program and textures; use bindless textures or texture arrays to vary materials.
Errors
When the call is invalid it does nothing and sets an error, which glGetError returns:
- GL_INVALID_OPERATION
- No indirect buffer bound, or the commands go past its end.
- GL_INVALID_VALUE
- drawcount is negative, or stride is not a multiple of 4.
Example
1glBindVertexArray(sharedVao);
2glBindBuffer(GL_DRAW_INDIRECT_BUFFER, cmdBuffer);
3glMultiDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr,
4 GLsizei(cmds.size()), 0);