Feb 26 '16
Authors:

The Framebuffer

A frame is one rendered image in an animated sequence. A common measurement of animation smoothness or speed is frames per second (FPS). A buffer is a block of memory used as temporary storage while moving and processing data. GPUs use many buffers internally, but a well known one is the framebuffer, which buffers each frame as it’s rendered. It simply stores pixel data, like an image, but holds the partial state and intermediate values during the rendering process. For example blending may continually update certain pixels as more geometry is rendered.

A deep framebuffer, with ties to G-buffers in deferred shading12, is typically implied by just “framebuffer” and stores many attributes per pixel. For example depth as well as RGBA colour. This may also be considered a collection of image buffers, one per attribute, which are grouped to form the deep framebuffer. Note that this is different to a deep image, such as a deep G-buffer3.

When creating an OpenGL context, the application typically requests a “default” framebuffer, with RGBA colour and depth for example. This holds the final image that ends up shown on the screen.

The framebuffer is continually updated as geometry is rendered. If shown directly, the updates would appear as flickering. Geometry that should be occluded may briefly be visible during the render. To avoid this, rendering is performed off-screen to a hidden back framebuffer. When a frame is ready, the back framebuffer is swapped with the front framebuffer to show only the final results all at once. This is called double buffering.

The back framebuffer allows off-screen rendering in one sense, but often two or more images need to be rendered and then combined to form the final result; or one is a pre-requisite for another, such as a dynamic texture. There are other fixed framebuffers that allow this, but most are deprecated and superseded by framebuffer objects.

Framebuffer Objects

Framebuffer objects (FBOs) allow off-screen rendering, render-to-texture and creating many different configurations of deep framebuffers. A primary example is rendering a shadow map. The scene is first rendered to a depth texture from the point of view of a light (1024×1024 for example). During the main 1920×1080 rendering recording RGB colour, the depth texture can be used to determine which fragments are in shadow. Different resolutions and pixel attributes are used to emphasize different FBO configurations, discussed next.

An FBO doesn’t actually store any image data by itself. It serves as a hub for connecting attachments, the actual buffer memory. Attachments can store colour, depth and stencil results from rendering. Although called colour by OpenGL, you can really store whatever data you want. The attachments themselves can be textures, render buffers, pixel buffers, buffer objects via texture buffers etc. They can also be 1D, 2D, 3D, array textures, cube maps, levels of the above and mipmaps.

Example usage is as follows:

int fbohandle;
// allocate an empty framebuffer and get a handle to it
glGenFramebuffers(1, &fbohandle);

// from now on, I'm modifying the FBO fbohandle
glBindFramebuffer(GL_FRAMEBUFFER, fbohandle);

// attach a texture to store colour when rendering
int texture = createTexture(...);
glFramebufferTexture2D(
    GL_FRAMEBUFFER,         //target. i.e. fbohandle from glBindFramebuffer
    GL_COLOR_ATTACHMENT0,   //attachment
    GL_TEXTURE_2D,          //texture target
    texture,                //texture ID
    0                       //mipmap level
    );

// zero the uninitialized texture
glClear(GL_COLOR_BUFFER_BIT);

// adjust the viewport to match the texture size
glViewport(...);

// render to the texture
drawScene();

// go back to rendering to the default framebuffer
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glViewport(...);

A handy function is glBlitFramebuffer, which is a very fast way to copy between framebuffers and convenient to view the results of off-screen renders, such as the above, without setting up further rendering passes.

glBindFramebuffer(GL_READ_FRAMEBUFFER, fbohandle);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glBlitFramebuffer(x0, y0, w0, h0, x1, y1, w1, h1, GL_COLOR_BUFFER_BIT, GL_NEAREST);
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);

  1. M. Deering, S. Winner, B. Schediwy, C. Duffy, and N. Hunt, “The triangle processor and normal vector shader: A vlsi system for high performance graphics,” SIGGRAPH Comput. Graph., vol. 22, no. 4, pp. 21–30, 1988. 

  2. T. Saito and T. Takahashi, “Comprehensible rendering of 3-d shapes,” SIGGRAPH Comput. Graph., vol. 24, no. 4, pp. 197–206, 1990. 

  3. M. Mara, M. McGuire, D. Nowrouzezahrai, and D. Luebke, “Fast global illumination approximations on deep g-buffers,” NVIDIA Corporation, Tech. Rep. NVR-2014-001, 2014, p. 16. 

There are no comments yet.