![]() |
VPP
0.7
A high-level modern C++ API for Vulkan
|
After we have defined a render graph, we need to specify for each process node (vpp::Process) how actual rendering wil be done by that process and what additional resources will it consume. Same applies for computational engines. In both cases, the object representing a complete rendering or computation program is called a pipeline.
Constructing a pipeline is actually a three stage process.
First, we actually design a pipeline. That means writing shader code and defining resources to be used in that code. This is the most important and involved part. The result is an abstract object representing a pipeline configuration.
Second, we construct a compiled form of the pipeline configuration. This is very simple step, being done entirely by VPP, from given reference to the pipeline configuration and device. The result is called a pipeline layout.
Finally, we register the pipeline layout in the render pass (being a compiled form of the render graph itself), for specified process node. We also provide a set of rendering options here, allowing to further customize rendering. This step gives us a fully realized pipeline object, which can be selected for drawing commands. There can be multiple pipelines registered for single process, selectable at will inside a rendering command sequence. Among there can be:
Subsections below describe these three steps in more detail.
In order to define your custom pipeline configuration, create a class derived from vpp::PipelineConfig or vpp::ComputePipelineConfig. In this chapter, we will assume that we are making a rendering pipeline.
An example:
By convention, the first two arguments to the constructor should be vpp::Process and vpp::Device. You must pass the vpp::Process immediately to the base class constructor. This is not needed for vpp::Device, but it might be useful later, so just remember it in a field. Also as you can see, there is a possibility to define any number of your own optional parameters.
For more detail about pipeline configurations, please see documentation pages for vpp::PipelineConfig and vpp::ComputePipelineConfig.
Also note that you need to specify some rendering options right now, on pipeline configuration level, although actually most of the options are being set much later (by means of vpp::RenderingOptions objects). Among these exceptions are:
Not setting these options will result in using default values, which are: no blending, no logic operations, triangle topology, unspecified tessellation points (valid if no tessellation is being used).
A pipeline layout is a compiled form of pipeline configuration. Technically more precise would be to call it "half-compiled" as not all aspects are compiled yet, but we'll stick to that term.
In order to construct a pipeline layout, create an instance of vpp::PipelineLayout or vpp::ComputePipelineLayout template, giving your pipeline configuration class as the template argument:
Note that you never create a pipeline configuration object yourself - the pipeline layout does it internally. Pass mandatory vpp::Process and vpp::Device arguments. Also you may pass any custom arguments you defined for pipeline configuration constructor. Get the vpp::Process reference from your render graph, the vpp::Device should be already stored as a field in your rendering engine class, as this is required for many other purposes also.
To retrieve a reference to your pipeline configuration object maintained internally by vpp::PipelineLayout, call the vpp::PipelineLayout::definition() method. A need to do this arises frequently in command sequence definitions, like this:
This is because bindVertices()
is inherited from the vpp::PipelineConfig class. You can call also your own methods this way, as definition()
returns a reference to your class, not the base vpp::PipelineConfig.
See the docs for vpp::PipelineLayout and vpp::ComputePipelineLayout for more information.
This is the final stage where the pipeline layout is being registered in the render pass and attached to specified vpp::Process node. Also it is being associated with vpp::RenderingOptions object, configuring most rendering options (except few ones that are set on vpp::PipelineConfig level).
To perform this step, you need to call the vpp::RenderPass::addPipeline() method, with the following arguments:
This method call returns a numerical index of the pipeline within particular process. It is important when you register more than one pipeline for a process, as any number of such registrations is allowed. Nevertheless, single pipeline layout instance must be registered to only one process. The relation between processes and pipeline layouts is "one to many" type.
An example - single pipeline.
An example - multiple pipelines.
The vpp::RenderPass::pipeline() method retrieves an object of type vpp::Pipeline. This is the actual, fully compiled Vulkan pipeline object. This object is needed to bind the pipeline for subsequent draw operations. The vpp::Pipeline objects are maintained internally by VPP and are guaranteed to be accessible only inside command sequences (lambda functions) for vpp::Process nodes. Do not use this method elsewhere, unless for advanced senarios and knowing some VPP internals. The only generally usable function of these objects is to bind them to current command sequence via vpp::Pipeline::cmdBind() method.