The Vulkan Pipeline

The structure of the pipeline in Vulkan is the same as OpenGL ES, but is immutable once it has been created

A pipeline is best described as a collection of stages in a rendering or compute process. Each stage processes the data it receives from the previous stage and then passes on its output to the next stage.

In OpenGL ES, some pipeline stages such as vertex and fragment shaders are programmable, so their functionality is entirely under the control of the application, while other stages such as the rasterizer and blending are fixed function so are immutable.

The states and parameters for each stage can be changed during runtime. This means that the pipeline can be set up to render an object, and then the programmable stages can be updated to render another object.

This is different in Vulkan as the pipeline is stored in one large, immutable object that needs to be prepared during initialisation and cannot be changed during runtime. If the pipeline does need to be altered, the object has to be destroyed and then re-created. Each object that needs to be rendered will therefore potentially use a different pipeline. The advantage of this approach is that the driver no longer has to check for the validity of the pipeline object during runtime, drastically reducing overhead.
Note: In addition to a graphics pipeline which performs rendering operations, Vulkan also offers a separate compute pipeline. The compute pipeline allows the application to perform more general computational work such as physics calculations.

Otherwise, the pipeline structure in Vulkan is virtually identical to the one in OpenGL ES, with a set of fixed function and programmable stages. The fixed function stages are somewhat configurable in Vulkan, but their general functionality is still immutable.

Creating a pipeline

When creating a pipeline object, each of the individual need to setup and configured individually before the entire pipeline is created with a single command. For the fixed function stages this includes configuring the vertex input, rasterization, colour blending, and multisampling stages. For the programmable stages this includes specifying which shader modules are going to be used and selecting a set of descriptor sets which link the resources that are going to be used by those shaders. Creating these shader modules was covered in Shaders and initialising the descriptor sets was in Descriptors and Descriptor Sets.

A note on the viewport

While most of pipeline cannot be modified after its creation, certain elements can be set as dynamic state, meaning they can be updated at a later point.

This is the case for the viewport which can be set as dynamic state during pipeline creation and then updated with the command buffer command vkCmdSetViewport.

An important point to remember is that the convention for specifying the viewport has been changed from OpenGL ES.

In OpenGL ES, the viewport has a left hand Normalised Device Coordinates (NDC) space, while in Vulkan it was switched to a right hand NDC space. This change in convention essentially means the coordinate (-1, -1) maps to the bottom left corner in OpenGL ES, but the top left corner in Vulkan.

Keeping this in mind is important.

When porting an application from OpenGL ES to Vulkan, there are two options to dealing with this switch:
  1. Convert the coordinates during runtime to ensure that it follows the correct coordinate space
  2. Convert all of the assets used in the application to follow the new convention

The choice depends on the specifics on the application.