OpenGL Cheatsheet
Drawing
Use this OpenGL reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.
Draw Call Fundamentals
Every draw call reads vertex data from the currently bound VAO and submits primitives to the pipeline.
glBindVertexArray(vao); glUseProgram(prog); // Non-indexed glDrawArrays(GL_TRIANGLES, 0, 6); // first=0, count=6 vertices // Indexed glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, (void*)0); // last arg = byte offset into the EBO (not a pointer when EBO is bound)
Primitive Modes
| Mode | Description | Min verts to draw |
|---|---|---|
GL_POINTS | One point per vertex | 1 |
GL_LINES | Independent line segments (2 verts each) | 2 |
GL_LINE_STRIP | Connected line segments | 2 |
GL_LINE_LOOP | Strip + closing segment | 2 |
GL_TRIANGLES | Independent triangles (3 verts each) | 3 |
GL_TRIANGLE_STRIP | Shared-edge triangles | 3 |
GL_TRIANGLE_FAN | Fan from first vertex | 3 |
GL_LINES_ADJACENCY | Lines with 2 adjacency verts each | 4 |
GL_LINE_STRIP_ADJACENCY | Strip with adjacency | 4 |
GL_TRIANGLES_ADJACENCY | Triangles with edge neighbors | 6 |
GL_TRIANGLE_STRIP_ADJACENCY | Strip with adjacency | 6 |
GL_PATCHES | Patch for tessellation shaders | GL_PATCH_VERTICES |
// Set patch size for tessellation glPatchParameteri(GL_PATCH_VERTICES, 3); // triangles (default)
All Draw Functions
Non-indexed
glDrawArrays(mode, first, count); // Instanced — gl_InstanceID in shader glDrawArraysInstanced(mode, first, count, instanceCount); // Instanced with base instance (gl_BaseInstance) glDrawArraysInstancedBaseInstance(mode, first, count, instanceCount, baseInstance); // Multi-draw — separate range per sub-call const GLint firsts[] = { 0, 6 }; const GLsizei counts[] = { 6, 3 }; glMultiDrawArrays(mode, firsts, counts, 2); // Indirect (command from GPU buffer) glBindBuffer(GL_DRAW_INDIRECT_BUFFER, indirectBuf); glDrawArraysIndirect(mode, (void*)offset); // Multi indirect (GL 4.3+) glMultiDrawArraysIndirect(mode, (void*)offset, drawCount, stride);
Indexed
glDrawElements(mode, count, indexType, offsetPtr); glDrawElementsBaseVertex(mode, count, indexType, offsetPtr, baseVertex); // baseVertex added to each index before fetching (allows shared VBO regions) glDrawElementsInstanced(mode, count, indexType, offsetPtr, instanceCount); glDrawElementsInstancedBaseVertex(mode, count, indexType, offsetPtr, instanceCount, baseVertex); glDrawElementsInstancedBaseVertexBaseInstance(mode, count, indexType, offsetPtr, instanceCount, baseVertex, baseInstance); glDrawRangeElements(mode, start, end, count, indexType, offsetPtr); // Hint: indices are in [start, end] — may improve performance glMultiDrawElements(mode, counts, indexType, offsets, drawCount); glMultiDrawElementsBaseVertex(mode, counts, indexType, offsets, drawCount, baseVertices); glDrawElementsIndirect(mode, indexType, (void*)offset); glMultiDrawElementsIndirect(mode, indexType, (void*)offset, drawCount, stride);
Indirect draw command structs
// For glDrawArraysIndirect struct DrawArraysIndirectCommand { GLuint count; GLuint instanceCount; GLuint first; GLuint baseInstance; }; // For glDrawElementsIndirect struct DrawElementsIndirectCommand { GLuint count; GLuint instanceCount; GLuint firstIndex; // index into EBO (in element units, not bytes) GLint baseVertex; GLuint baseInstance; };
Instanced Rendering
Draw many copies of the same geometry in one call. Use gl_InstanceID or per-instance vertex attributes.
// Per-instance vertex attribute (divisor = 1 means advance once per instance) glVertexAttribDivisor(attribIndex, 1); // 0 = per-vertex (default), N = per N instances // DSA equivalent glVertexArrayBindingDivisor(vao, bindingIndex, 1);
// Vertex shader layout(location = 2) in vec3 aOffset; // divisor=1 attribute void main() { gl_Position = uVP * vec4(aPos + aOffset, 1.0); }
Transform Feedback
Capture transformed vertices back to a buffer before rasterization.
// Setup GLuint tfo; glGenTransformFeedbacks(1, &tfo); glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, tfo); const char* varyings[] = { "outPos", "outVel" }; glTransformFeedbackVaryings(prog, 2, varyings, GL_INTERLEAVED_ATTRIBS); // GL_SEPARATE_ATTRIBS: one binding point per varying glLinkProgram(prog); // must relink after setting varyings glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, captureBuffer); // Draw glEnable(GL_RASTERIZER_DISCARD); // optional: skip fragment stage glBeginTransformFeedback(GL_TRIANGLES); glDrawArrays(GL_TRIANGLES, 0, vertCount); glEndTransformFeedback(); glDisable(GL_RASTERIZER_DISCARD);
Conditional Rendering
Draw only if a query recorded at least one sample.
GLuint query; glGenQueries(1, &query); glBeginQuery(GL_SAMPLES_PASSED, query); // bounding box draw glEndQuery(GL_SAMPLES_PASSED); glBeginConditionalRender(query, GL_QUERY_WAIT); // expensive draw — skipped if query result == 0 glEndConditionalRender();
Conditional render modes
| Mode | Behavior |
|---|---|
GL_QUERY_WAIT | Stall until result available |
GL_QUERY_NO_WAIT | Skip if result unavailable (may draw anyway) |
GL_QUERY_BY_REGION_WAIT | Stall; only renders in screen region |
GL_QUERY_BY_REGION_NO_WAIT | No stall; only in region |
Occlusion Queries
GLuint query; glGenQueries(1, &query); glBeginQuery(GL_SAMPLES_PASSED, query); // or GL_ANY_SAMPLES_PASSED // draw occluder glEndQuery(GL_SAMPLES_PASSED); // Non-blocking check GLint available = 0; glGetQueryObjectiv(query, GL_QUERY_RESULT_AVAILABLE, &available); if (available) { GLuint result; glGetQueryObjectuiv(query, GL_QUERY_RESULT, &result); }
Query types
| Type | What it counts |
|---|---|
GL_SAMPLES_PASSED | Fragments that pass depth/stencil |
GL_ANY_SAMPLES_PASSED | Returns 1 or 0 (boolean) |
GL_ANY_SAMPLES_PASSED_CONSERVATIVE | Conservative (faster) boolean |
GL_PRIMITIVES_GENERATED | Primitives emitted by geometry stage |
GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN | Primitives written to XFB buffer |
GL_TIME_ELAPSED | GPU time in nanoseconds |
GL_TIMESTAMP | Absolute GPU timestamp |
Timer Queries
GLuint queries[2]; glGenQueries(2, queries); glQueryCounter(queries[0], GL_TIMESTAMP); // draw calls glQueryCounter(queries[1], GL_TIMESTAMP); GLuint64 t0, t1; glGetQueryObjectui64v(queries[0], GL_QUERY_RESULT, &t0); glGetQueryObjectui64v(queries[1], GL_QUERY_RESULT, &t1); double ms = (t1 - t0) / 1e6;
Scissor Test
glEnable(GL_SCISSOR_TEST); glScissor(x, y, width, height); // pixels, lower-left origin // Only fragments within this rect are written glDisable(GL_SCISSOR_TEST);
Multi-viewport / Layered Rendering (GL 4.1+)
// Set multiple viewports at once float vps[8] = { 0,0,400,600, 400,0,400,600 }; glViewportArrayv(0, 2, vps); float depths[4] = { 0,1, 0,1 }; glDepthRangeArrayv(0, 2, depths); // Geometry shader selects viewport/layer // gl_ViewportIndex = 0 or 1; // gl_Layer = cubemap face index;
Sync Objects / Memory Barriers
// Insert a fence GLsync fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); // CPU waits for GPU GLenum result = glClientWaitSync(fence, GL_SYNC_FLUSH_COMMANDS_BIT, 5000000000ULL); // result: GL_ALREADY_SIGNALED, GL_CONDITION_SATISFIED, GL_TIMEOUT_EXPIRED, GL_WAIT_FAILED // GPU waits for fence (no CPU stall) glWaitSync(fence, 0, GL_TIMEOUT_IGNORED); glDeleteSync(fence); // Memory barrier — order shader writes before subsequent reads glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT | GL_TEXTURE_FETCH_BARRIER_BIT);
glMemoryBarrier bits
| Bit | Protects |
|---|---|
GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT | VBO reads after shader writes |
GL_ELEMENT_ARRAY_BARRIER_BIT | EBO reads |
GL_UNIFORM_BARRIER_BIT | Uniform reads after SSBO writes |
GL_TEXTURE_FETCH_BARRIER_BIT | Texture sampling after image writes |
GL_SHADER_IMAGE_ACCESS_BARRIER_BIT | Image load/store ordering |
GL_COMMAND_BARRIER_BIT | Indirect draw commands |
GL_PIXEL_BUFFER_BARRIER_BIT | PBO reads/writes |
GL_TEXTURE_UPDATE_BARRIER_BIT | glTexImage calls |
GL_BUFFER_UPDATE_BARRIER_BIT | glBufferData / map |
GL_FRAMEBUFFER_BARRIER_BIT | FBO reads after rendering |
GL_TRANSFORM_FEEDBACK_BARRIER_BIT | XFB buffer reads |
GL_ATOMIC_COUNTER_BARRIER_BIT | Atomic counter reads |
GL_SHADER_STORAGE_BARRIER_BIT | SSBO reads/writes |
GL_ALL_BARRIER_BITS | All of the above |