How Render Passes Work

In simple terms, a render pass is a single execution of the rendering pipeline. A render pass renders an output image into a set of framebuffer attachments in memory. Each attachment requires initialization in tile memory at the start of the render pass and may then need to be written back out to memory at the end.

Some attachments are likely to be transient. For example, an application that uses both color and depth attachments during the render, but the application only needs to keep the color attachment for use in later rendering operations. In this scenario depth is transient and can simply be discarded at the end of the render pass.

Because of the need to minimize both the start and end of pass overheads, render passes are essential for tile-based renders. However, not all APIs natively support render passes due to how these APIs have evolved. Because of this, it is important to understand what we mean by a render pass, and how to use the APIs to construct them.

Render Passes in Vulkan

Vulkan has added explicit support for render passes in the API with the VkRenderPass structure, and for the individual framebuffer attachments the render pass contains via the VkAttachmentDescription structure.

Each attachment description must specify explicit loadOp operations to perform at the start of the render pass, and storeOp operations to perform at the end of the render pass. Therefore, the API requires a clear statement of intent to be added by the application developer.

Render Passes in OpenGL

Unlike Vulkan, the older OpenGL ES API has no explicit render passes in the API, so the driver must infer which rendering operations form a single render pass.

For Mali GPUs, a render pass is submitted for processing when an API call changes the framebuffer or forces a flush of the queued work. The most common causes for ending a render pass are:

  • The application calls glBindFramebuffer() to change the GL_FRAMEBUFFER or GL_DRAW_FRAMEBUFFER target.
  • The application calls glFramebufferTexture*() or glFramebufferRenderbuffer() to change the attachments of the currently bound draw framebuffer object when the drawing is queued.
  • The application calls eglSwapBuffers() to signal the end of a frame.
  • The application calls glFlush() or glFinish() to explicitly flush any queued rendering.
  • The application creates a glFenceSync() for some rendering in the current render pass and then calls glClientWaitSync() to wait on the completion of that work, or an equivalent behavior with a query object.
Previous Next