FramebuffersGL 1.0

glReadPixels

Copies pixels from the read framebuffer back to the CPU (or into a pixel buffer object).

Signature

void glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height,
                  GLenum format, GLenum type, void *data);

How it works

Reads a rectangle from the read buffer of the framebuffer bound to GL_READ_FRAMEBUFFER: screenshots, or the object ID under the mouse in picking.

Two things to know. The origin is the bottom-left corner, but window coordinates start at the top, so flip y: height − 1 − mouseY. And a plain call stalls: the CPU waits until the GPU has finished every pending draw. To avoid that, bind a buffer to GL_PIXEL_PACK_BUFFER first; data then becomes a byte offset into it, the call returns at once, and you map the buffer a frame later (or after a fence signals).

Parameters

x, yGLint

Bottom-left corner of the rectangle.

width, heightGLsizei

Size of the rectangle (1, 1 for a single pixel).

formatGLenum

Channels to return.

Common values

GL_RGBA / GL_RGB
Colour, for screenshots.
GL_RED_INTEGER
One integer channel, for ID buffers (GL_R32UI).
GL_DEPTH_COMPONENT
The depth value.
typeGLenum

Type of each value: GL_UNSIGNED_BYTE, GL_FLOAT, GL_UNSIGNED_INT…

datavoid *

Destination memory, or a byte offset when a GL_PIXEL_PACK_BUFFER is bound.

Tips & pitfalls

  • Rows are padded to GL_PACK_ALIGNMENT (4 bytes by default): reading GL_RGB rows of odd width needs glPixelStorei(GL_PACK_ALIGNMENT, 1) or a bigger buffer.

  • Reading a whole 1080p frame synchronously costs milliseconds; one pixel through a PBO costs almost nothing.

Errors

When the call is invalid it does nothing and sets an error, which glGetError returns:

GL_INVALID_OPERATION
format/type do not suit the read buffer (e.g. GL_RGBA with an integer texture), or the pack buffer is too small.
GL_INVALID_FRAMEBUFFER_OPERATION
The read framebuffer is incomplete.

Example

example.cpp
1// picking: the object ID under the mouse, without stalling
2glBindFramebuffer(GL_READ_FRAMEBUFFER, idFbo);
3glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo);
4glReadPixels(mx, height - 1 - my, 1, 1, GL_RED_INTEGER, GL_UNSIGNED_INT, nullptr);
5GLsync fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
Official Khronos documentation