Fork me on GitHub


Safe Rust wrapper around the Vulkan API

Descriptor sets

In the GLSL code of the previous section, the buffer accessed by the shader was declared like this:

layout(set = 0, binding = 0) buffer Data {
    uint data[];
} buf;

In Vulkan, the buffers that a compute pipeline needs to access must be bound to what are called descriptors. The code above declares such a descriptor.

Note: A descriptor can contain a buffer, but also other types that we haven't covered yet: a buffer view, an image, a sampled image, etc. Each descriptor can also be an array.

Descriptors are grouped by descriptor sets. The layout(set = 0, binding = 0) attribute in the GLSL code indicates that this descriptor is the descriptor 0 in the set 0. Descriptor indices and set indices are 0-based.

What we declared in the GLSL code is actually not a descriptor set, but only a slot for a descriptor set. Before we can invoke the compute pipeline, we first need to bind an actual descriptor set to that slot.

Creating a descriptor set

Just like there exist multiple kinds of buffers, there also exist multiple different structs that all represent a descriptor set. Here we are going to use a PersistentDescriptorSet:

use vulkano::descriptor::descriptor_set::PersistentDescriptorSet;
use vulkano::descriptor::PipelineLayoutAbstract;

let layout = compute_pipeline.layout().descriptor_set_layout(0).unwrap();
let set = Arc::new(PersistentDescriptorSet::start(layout.clone())

In order to create a descriptor set, you'll need to know the layout that it is targeting. We do this by calling layout() on our pipeline to obtain the pipeline's layout. Next we'll fetch the layout specfic to the pass that we want to target by using descriptor_set_layout(0) where zero indicates the index of the pass that we are targeting.

Once you have created a descriptor set, you may also use it with other pipelines, as long as the bindings' types match those the pipelines' shaders expect. But Vulkan requires that you provide a pipeline whenever you create a descriptor set; you cannot create one independently of any particular pipeline.

We then bind each descriptor one by one in order, which here is just the buf variable. Just like for compute_pipeline, cloning data_buffer only clones an Arc and isn't expensive.

Note: data_buffer was created in the introduction.

Now that we have a compute pipeline and a descriptor set to bind to it, we can start our operation. This is covered in the next section.