OpenGL Cheatsheet
Framebuffers
Use this OpenGL reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.
Framebuffer Basics
The default framebuffer is provided by the windowing system (GLFW). Custom framebuffer objects (FBOs) let you render to textures or renderbuffers.
GLuint fbo; glGenFramebuffers(1, &fbo); glBindFramebuffer(GL_FRAMEBUFFER, fbo); // binds for both read and draw // Attach a texture glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTex, /*mip=*/0); // Attach a renderbuffer for depth glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rbo); // Check completeness (must check before first use) GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); if (status != GL_FRAMEBUFFER_COMPLETE) { /* handle error */ } glBindFramebuffer(GL_FRAMEBUFFER, 0); // rebind default framebuffer
DSA (GL 4.5+) — preferred
GLuint fbo; glCreateFramebuffers(1, &fbo); glNamedFramebufferTexture(fbo, GL_COLOR_ATTACHMENT0, colorTex, 0); glNamedFramebufferRenderbuffer(fbo, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rbo); GLenum status = glCheckNamedFramebufferStatus(fbo, GL_FRAMEBUFFER);
Framebuffer Bind Targets
| Target | Meaning |
|---|---|
GL_FRAMEBUFFER | Both read and draw (most common) |
GL_DRAW_FRAMEBUFFER | Draw target only (glClear, draw calls) |
GL_READ_FRAMEBUFFER | Read target only (glReadPixels, glBlitFramebuffer) |
Attachment Points
| Attachment | Connected to |
|---|---|
GL_COLOR_ATTACHMENT0 … GL_COLOR_ATTACHMENT(n-1) | Color buffers (n = GL_MAX_COLOR_ATTACHMENTS) |
GL_DEPTH_ATTACHMENT | Depth buffer |
GL_STENCIL_ATTACHMENT | Stencil buffer |
GL_DEPTH_STENCIL_ATTACHMENT | Combined depth+stencil |
Framebuffer Completeness
glCheckFramebufferStatus returns one of:
| Status | Meaning |
|---|---|
GL_FRAMEBUFFER_COMPLETE | Ready to use |
GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT | An attachment is not complete |
GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT | No attachment present |
GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER | Draw buffer references missing attachment |
GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER | Read buffer references missing attachment |
GL_FRAMEBUFFER_UNSUPPORTED | Format combination not supported by driver |
GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE | Mixed MSAA sample counts |
GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS | Inconsistent layered attachments |
Renderbuffer Objects (RBO)
Renderbuffers are faster than textures for attachments you don't need to sample (depth, stencil).
GLuint rbo; glGenRenderbuffers(1, &rbo); glBindRenderbuffer(GL_RENDERBUFFER, rbo); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo); // MSAA renderbuffer glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_DEPTH24_STENCIL8, w, h); // DSA glCreateRenderbuffers(1, &rbo); glNamedRenderbufferStorage(rbo, GL_DEPTH24_STENCIL8, width, height); glNamedRenderbufferStorageMultisample(rbo, 4, GL_DEPTH24_STENCIL8, w, h);
Attaching Textures
// 2D texture glFramebufferTexture2D(target, attachment, GL_TEXTURE_2D, tex, mipLevel); // Cube map face glFramebufferTexture2D(target, attachment, GL_TEXTURE_CUBE_MAP_POSITIVE_X, tex, 0); // Layered attachment — geometry shader selects gl_Layer glFramebufferTexture(target, attachment, tex, mipLevel); // Specific layer of a 3D or array texture glFramebufferTextureLayer(target, attachment, tex, mipLevel, layer); // DSA versions glNamedFramebufferTexture(fbo, attachment, tex, mipLevel); glNamedFramebufferTextureLayer(fbo, attachment, tex, mipLevel, layer);
Multiple Render Targets (MRT)
Write to multiple color attachments simultaneously (used in deferred rendering).
// Tell which attachments are active draw buffers GLenum drawBuffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2 }; glDrawBuffers(3, drawBuffers); // or glNamedFramebufferDrawBuffers(fbo, 3, drawBuffers)
// Fragment shader — write to each layout(location = 0) out vec4 gPosition; layout(location = 1) out vec3 gNormal; layout(location = 2) out vec4 gAlbedoSpec;
// Select which attachment to read from glReadBuffer(GL_COLOR_ATTACHMENT0); // for FBO glNamedFramebufferReadBuffer(fbo, GL_COLOR_ATTACHMENT0);
Blitting Between Framebuffers
Copies a region from the read FBO to the draw FBO — supports format conversion and multi-sample resolve.
glBindFramebuffer(GL_READ_FRAMEBUFFER, srcFBO); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dstFBO); glBlitFramebuffer( srcX0, srcY0, srcX1, srcY1, // source rectangle dstX0, dstY0, dstX1, dstY1, // destination rectangle mask, // GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT filter // GL_LINEAR or GL_NEAREST (depth/stencil must use GL_NEAREST) ); // DSA glBlitNamedFramebuffer(srcFBO, dstFBO, /* same args */);
Gotcha: Depth and stencil blits require
GL_NEAREST. OnlyGL_COLOR_BUFFER_BITsupportsGL_LINEAR.
Reading Pixels
// Synchronous (causes GPU stall — avoid in render loop) glReadBuffer(GL_BACK); // or GL_COLOR_ATTACHMENTn for FBO glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); // Asynchronous via PBO (pipeline-friendly) glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo); glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, 0); // async // ... do other work ... void* data = glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY); memcpy(dest, data, size); glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
Post-Processing Pipeline
// Full-screen quad FBO pass glBindFramebuffer(GL_FRAMEBUFFER, fbo); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); renderScene(); // writes to colorTex glBindFramebuffer(GL_FRAMEBUFFER, 0); glClear(GL_COLOR_BUFFER_BIT); glUseProgram(postProcessProg); glBindTextureUnit(0, colorTex); drawFullScreenTriangle(); // applies effect
// Full-screen vertex shader (no VBO needed) void main() { vec2 positions[3] = vec2[](vec2(-1,-1), vec2(3,-1), vec2(-1,3)); vec2 uvs[3] = vec2[](vec2(0,0), vec2(2,0), vec2(0,2)); vUV = uvs[gl_VertexID]; gl_Position = vec4(positions[gl_VertexID], 0.0, 1.0); }
MSAA Framebuffer
// Create MSAA color texture glCreateTextures(GL_TEXTURE_2D_MULTISAMPLE, 1, &msTex); glTextureStorage2DMultisample(msTex, 4, GL_RGBA8, width, height, GL_TRUE); // Create MSAA FBO glCreateFramebuffers(1, &msFBO); glNamedFramebufferTexture(msFBO, GL_COLOR_ATTACHMENT0, msTex, 0); GLuint msRBO; glCreateRenderbuffers(1, &msRBO); glNamedRenderbufferStorageMultisample(msRBO, 4, GL_DEPTH24_STENCIL8, width, height); glNamedFramebufferRenderbuffer(msFBO, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, msRBO); // Resolve to single-sample FBO glBlitNamedFramebuffer(msFBO, resolveFBO, 0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
Framebuffer Invalidation
Tells the driver it can discard contents (especially useful on tiled GPUs / mobile).
GLenum attachments[] = { GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT };
glInvalidateFramebuffer(GL_FRAMEBUFFER, 2, attachments);
glInvalidateSubFramebuffer(GL_FRAMEBUFFER, 2, attachments, x, y, w, h);
glInvalidateNamedFramebufferData(fbo, 2, attachments);Framebuffer Parameters (GL 4.3+)
Set FBO size/samples without any attachments (useful for layered/sparse rendering).
glNamedFramebufferParameteri(fbo, GL_FRAMEBUFFER_DEFAULT_WIDTH, 800); glNamedFramebufferParameteri(fbo, GL_FRAMEBUFFER_DEFAULT_HEIGHT, 600); glNamedFramebufferParameteri(fbo, GL_FRAMEBUFFER_DEFAULT_SAMPLES, 4); glNamedFramebufferParameteri(fbo, GL_FRAMEBUFFER_DEFAULT_LAYERS, 6);
Common FBO Configurations
Color-only (no depth)
glCreateTextures(GL_TEXTURE_2D, 1, &colorTex); glTextureStorage2D(colorTex, 1, GL_RGBA8, w, h); glCreateFramebuffers(1, &fbo); glNamedFramebufferTexture(fbo, GL_COLOR_ATTACHMENT0, colorTex, 0); // No depth attachment — disable depth test when rendering to this FBO
Depth-only (shadow map)
glCreateTextures(GL_TEXTURE_2D, 1, &depthTex); glTextureStorage2D(depthTex, 1, GL_DEPTH_COMPONENT24, w, h); glTextureParameteri(depthTex, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); glTextureParameteri(depthTex, GL_TEXTURE_COMPARE_FUNC, GL_LESS); glCreateFramebuffers(1, &shadowFBO); glNamedFramebufferTexture(shadowFBO, GL_DEPTH_ATTACHMENT, depthTex, 0); GLenum none = GL_NONE; glNamedFramebufferDrawBuffers(shadowFBO, 1, &none); glNamedFramebufferReadBuffer(shadowFBO, GL_NONE);
HDR color + depth
glCreateTextures(GL_TEXTURE_2D, 1, &hdrTex); glTextureStorage2D(hdrTex, 1, GL_RGBA16F, w, h); // float for HDR values glCreateRenderbuffers(1, &rbo); glNamedRenderbufferStorage(rbo, GL_DEPTH24_STENCIL8, w, h); glCreateFramebuffers(1, &hdrFBO); glNamedFramebufferTexture(hdrFBO, GL_COLOR_ATTACHMENT0, hdrTex, 0); glNamedFramebufferRenderbuffer(hdrFBO, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo);
Cube map FBO (for point shadows / env capture)
glCreateTextures(GL_TEXTURE_CUBE_MAP, 1, &cubeTex); glTextureStorage2D(cubeTex, 1, GL_DEPTH_COMPONENT24, w, h); glCreateFramebuffers(1, &cubeFBO); // Layered attachment — geometry shader renders all 6 faces in one pass glNamedFramebufferTexture(cubeFBO, GL_DEPTH_ATTACHMENT, cubeTex, 0); GLenum none = GL_NONE; glNamedFramebufferDrawBuffers(cubeFBO, 1, &none); glNamedFramebufferReadBuffer(cubeFBO, GL_NONE);
Cleanup
glDeleteFramebuffers(1, &fbo); glDeleteRenderbuffers(1, &rbo); // Textures attached to FBOs are NOT auto-deleted — delete manually glDeleteTextures(1, &colorTex);