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

TargetMeaning
GL_FRAMEBUFFERBoth read and draw (most common)
GL_DRAW_FRAMEBUFFERDraw target only (glClear, draw calls)
GL_READ_FRAMEBUFFERRead target only (glReadPixels, glBlitFramebuffer)

Attachment Points

AttachmentConnected to
GL_COLOR_ATTACHMENT0GL_COLOR_ATTACHMENT(n-1)Color buffers (n = GL_MAX_COLOR_ATTACHMENTS)
GL_DEPTH_ATTACHMENTDepth buffer
GL_STENCIL_ATTACHMENTStencil buffer
GL_DEPTH_STENCIL_ATTACHMENTCombined depth+stencil

Framebuffer Completeness

glCheckFramebufferStatus returns one of:

StatusMeaning
GL_FRAMEBUFFER_COMPLETEReady to use
GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENTAn attachment is not complete
GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENTNo attachment present
GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFERDraw buffer references missing attachment
GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFERRead buffer references missing attachment
GL_FRAMEBUFFER_UNSUPPORTEDFormat combination not supported by driver
GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLEMixed MSAA sample counts
GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETSInconsistent 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. Only GL_COLOR_BUFFER_BIT supports GL_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);