OpenGL Cheatsheet
Buffers (VBO, VAO, EBO)
Use this OpenGL reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.
Vertex Buffer Object (VBO)
A VBO is a GPU-side buffer holding raw vertex data. All buffer objects share the same API — only the bind target differs.
GLuint vbo; glGenBuffers(1, &vbo); glBindBuffer(GL_ARRAY_BUFFER, vbo); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
Buffer targets
| Target | Typical use |
|---|---|
GL_ARRAY_BUFFER | Vertex attribute data (VBO) |
GL_ELEMENT_ARRAY_BUFFER | Index data (EBO/IBO) |
GL_UNIFORM_BUFFER | UBO — block uniforms shared across shaders |
GL_SHADER_STORAGE_BUFFER | SSBO — large, shader-writable (GL 4.3+) |
GL_DRAW_INDIRECT_BUFFER | Indirect draw commands |
GL_DISPATCH_INDIRECT_BUFFER | Indirect compute dispatch |
GL_COPY_READ_BUFFER | Source for glCopyBufferSubData |
GL_COPY_WRITE_BUFFER | Destination for glCopyBufferSubData |
GL_PIXEL_PACK_BUFFER | GPU → CPU pixel transfer (readback) |
GL_PIXEL_UNPACK_BUFFER | CPU → GPU pixel transfer (upload) |
GL_TRANSFORM_FEEDBACK_BUFFER | Capture transformed vertices |
GL_QUERY_BUFFER | Write query result directly to buffer (GL 4.4+) |
GL_ATOMIC_COUNTER_BUFFER | Atomic counter bindings |
GL_TEXTURE_BUFFER | Buffer texture data |
Usage hints
| Hint | Access | Nature |
|---|---|---|
GL_STATIC_DRAW | CPU → GPU once | GPU reads many times |
GL_DYNAMIC_DRAW | CPU → GPU repeatedly | GPU reads many times |
GL_STREAM_DRAW | CPU → GPU once | GPU reads a few times |
GL_STATIC_READ | GPU → CPU once | CPU reads many times |
GL_DYNAMIC_READ | GPU → CPU repeatedly | CPU reads many times |
GL_STATIC_COPY | GPU → GPU once | GPU reads many times |
GL_DYNAMIC_COPY | GPU → GPU repeatedly | GPU reads many times |
These are hints to the driver for memory placement — they do not prevent any access pattern.
Uploading and Updating Data
// Full upload (allocates storage) glBufferData(target, sizeBytes, data, usage); // data can be nullptr to allocate without initializing // Partial update (does NOT reallocate — must fit in existing allocation) glBufferSubData(target, offsetBytes, sizeBytes, data); // Copy between two bound buffers glBindBuffer(GL_COPY_READ_BUFFER, src); glBindBuffer(GL_COPY_WRITE_BUFFER, dst); glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, readOffset, writeOffset, sizeBytes);
DSA (Direct State Access, GL 4.5+) — preferred, no bind required
GLuint vbo; glCreateBuffers(1, &vbo); // allocates immediately glNamedBufferData(vbo, sizeBytes, data, GL_STATIC_DRAW); glNamedBufferSubData(vbo, offset, size, data);
Buffer Mapping
// Map entire buffer void* ptr = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); memcpy(ptr, data, size); glUnmapBuffer(GL_ARRAY_BUFFER); // returns GL_FALSE if mapping corrupted // Map a range (more efficient — allows unsynchronized access) void* ptr = glMapBufferRange(GL_ARRAY_BUFFER, offset, length, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_UNSYNCHRONIZED_BIT); glUnmapBuffer(GL_ARRAY_BUFFER); // DSA version void* ptr = glMapNamedBufferRange(vbo, offset, length, accessFlags); glUnmapNamedBuffer(vbo);
Map access flags
| Flag | Meaning |
|---|---|
GL_MAP_READ_BIT | CPU will read from the buffer |
GL_MAP_WRITE_BIT | CPU will write to the buffer |
GL_MAP_INVALIDATE_RANGE_BIT | Driver may discard mapped range |
GL_MAP_INVALIDATE_BUFFER_BIT | Driver may discard entire buffer |
GL_MAP_FLUSH_EXPLICIT_BIT | CPU flushes via glFlushMappedBufferRange |
GL_MAP_UNSYNCHRONIZED_BIT | No sync — unsafe if GPU is reading |
GL_MAP_PERSISTENT_BIT | Mapping stays valid across draws (GL 4.4+) |
GL_MAP_COHERENT_BIT | No manual flush needed (GL 4.4+) |
Vertex Array Object (VAO)
A VAO records: which VBOs are bound to which attribute slots, the format of each attribute, and which EBO is active. Binding the VAO restores all of this.
GLuint vao; glGenVertexArrays(1, &vao); glBindVertexArray(vao); // start recording glBindBuffer(GL_ARRAY_BUFFER, vbo); // Attribute 0: 3 floats at offset 0, stride 20 bytes glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 20, (void*)0); glEnableVertexAttribArray(0); // Attribute 1: 2 floats at offset 12 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 20, (void*)12); glEnableVertexAttribArray(1); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); // EBO stored in VAO glBindVertexArray(0); // stop recording
glVertexAttribPointer signature
glVertexAttribPointer( GLuint index, // attribute location (layout(location=N)) GLint size, // number of components: 1, 2, 3, or 4 GLenum type, // GL_FLOAT, GL_INT, GL_UNSIGNED_BYTE, ... GLboolean normalized, // normalize integer types to [-1,1] or [0,1] GLsizei stride, // bytes between consecutive vertices (0 = tightly packed) const void* offset // byte offset within the buffer ); // Integer attributes (no normalization, no float conversion) glVertexAttribIPointer(index, size, type, stride, offset); // Double-precision attributes (GL 4.1+) glVertexAttribLPointer(index, size, GL_DOUBLE, stride, offset);
Attribute types
type | Description |
|---|---|
GL_FLOAT | 32-bit float |
GL_DOUBLE | 64-bit double |
GL_BYTE | Signed 8-bit integer |
GL_UNSIGNED_BYTE | Unsigned 8-bit integer |
GL_SHORT | Signed 16-bit |
GL_UNSIGNED_SHORT | Unsigned 16-bit |
GL_INT | Signed 32-bit |
GL_UNSIGNED_INT | Unsigned 32-bit |
GL_HALF_FLOAT | 16-bit float |
GL_FIXED | 16.16 fixed-point |
GL_INT_2_10_10_10_REV | Packed 4-component (normals) |
GL_UNSIGNED_INT_2_10_10_10_REV | Packed 4-component (unsigned) |
DSA VAO setup (GL 4.5+)
GLuint vao; glCreateVertexArrays(1, &vao); // Bind VBO to binding point 0 with stride glVertexArrayVertexBuffer(vao, /*bindingIndex=*/0, vbo, /*offset=*/0, /*stride=*/20); // Format of attribute 0 (bound to binding point 0) glVertexArrayAttribFormat(vao, /*attribIndex=*/0, 3, GL_FLOAT, GL_FALSE, /*relOffset=*/0); glVertexArrayAttribBinding(vao, 0, 0); // attrib 0 → binding point 0 glEnableVertexArrayAttrib(vao, 0); // Attribute 1 glVertexArrayAttribFormat(vao, 1, 2, GL_FLOAT, GL_FALSE, 12); glVertexArrayAttribBinding(vao, 1, 0); glEnableVertexArrayAttrib(vao, 1); // Attach EBO glVertexArrayElementBuffer(vao, ebo);
Element Buffer Object (EBO)
Stores indices for indexed drawing. The EBO binding is part of VAO state.
GLuint ebo; glGenBuffers(1, &ebo); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); // (while VAO is bound, this EBO is recorded into the VAO)
// Draw indexed glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, (void*)0);
EBO index types
type | Range | Bytes per index |
|---|---|---|
GL_UNSIGNED_BYTE | 0–255 | 1 |
GL_UNSIGNED_SHORT | 0–65535 | 2 |
GL_UNSIGNED_INT | 0–4294967295 | 4 |
Primitive restart
glEnable(GL_PRIMITIVE_RESTART); glPrimitiveRestartIndex(0xFFFF); // when this index is encountered, restart strip // GL 4.3+: glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX) — always uses max uint
Uniform Buffer Object (UBO)
// GLSL layout(std140, binding = 0) uniform Matrices { mat4 view; mat4 projection; }; // CPU: create and fill GLuint ubo; glCreateBuffers(1, &ubo); glNamedBufferData(ubo, sizeof(MatricesBlock), &data, GL_DYNAMIC_DRAW); // Bind to binding point 0 glBindBufferBase(GL_UNIFORM_BUFFER, 0, ubo); // or a range: glBindBufferRange(GL_UNIFORM_BUFFER, 0, ubo, offsetBytes, sizeBytes);
std140 layout rules:
vec3is padded to 16 bytes; arrays have stride of 16 bytes per element; always usestd140for UBOs to get predictable offsets. Usestd430(only for SSBOs) for tighter packing.
Shader Storage Buffer Object (SSBO, GL 4.3+)
layout(std430, binding = 1) buffer Particles { vec4 positions[]; };
GLuint ssbo; glCreateBuffers(1, &ssbo); glNamedBufferData(ssbo, size, data, GL_DYNAMIC_COPY); glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, ssbo); // After compute writes — flush before read glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
Buffer Invalidation
// Hint driver to discard contents (enables orphaning / avoid stall) glInvalidateBufferData(vbo); glInvalidateBufferSubData(vbo, offsetBytes, sizeBytes);
Persistent Mapped Buffers (GL 4.4+)
GLbitfield flags = GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT; glNamedBufferStorage(vbo, size, nullptr, flags); // immutable storage void* ptr = glMapNamedBufferRange(vbo, 0, size, flags); // ptr remains valid forever; use fences to avoid races
// Fence sync to prevent writing into in-flight data GLsync fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); GLenum result = glClientWaitSync(fence, GL_SYNC_FLUSH_COMMANDS_BIT, timeout_ns); glDeleteSync(fence);