Descriptor Sets

A descriptor set object is an opaque object containing storage for a set of descriptors, where the types and number of descriptors is defined by a descriptor set layout. The layout object may be used to define the association of each descriptor binding with memory or other implementation resources. The layout is used both for determining the resources that need to be associated with the descriptor set, and determining the interface between shader stages and shader resources.

Descriptor Set Layout

VkDescriptorSetLayoutOpaque handle to a descriptor set layout object
vkCreateDescriptorSetLayoutCreate a new descriptor set layout
VkDescriptorSetLayoutCreateInfoStructure specifying parameters of a newly created descriptor set layout
VkMutableDescriptorTypeCreateInfoEXTStructure describing the list of possible active descriptor types for mutable type descriptors
VkMutableDescriptorTypeListEXTStructure describing descriptor types that a given descriptor may mutate to
VkDescriptorSetLayoutCreateFlagBitsBitmask specifying descriptor set layout properties
VkDescriptorSetLayoutCreateFlagsBitmask of VkDescriptorSetLayoutCreateFlagBits
VkDescriptorSetLayoutBindingStructure specifying a descriptor set layout binding
VkDescriptorSetLayoutBindingFlagsCreateInfoStructure specifying creation flags for descriptor set layout bindings
VkDescriptorBindingFlagBitsBitmask specifying descriptor set layout binding properties
VkDescriptorBindingFlagsBitmask of VkDescriptorBindingFlagBits
vkGetDescriptorSetLayoutSupportQuery whether a descriptor set layout can be created
VkDescriptorSetLayoutSupportStructure returning information about whether a descriptor set layout can be supported
VkDescriptorSetVariableDescriptorCountLayoutSupportStructure returning information about whether a descriptor set layout can be supported

The following examples show a shader snippet using two descriptor sets, and application code that creates corresponding descriptor set layouts.

GLSL Example

//
// binding to a single sampled image descriptor in set 0
//
layout (set=0, binding=0) uniform texture2D mySampledImage;

//
// binding to an array of sampled image descriptors in set 0
//
layout (set=0, binding=1) uniform texture2D myArrayOfSampledImages[12];

//
// binding to a single uniform buffer descriptor in set 1
//
layout (set=1, binding=0) uniform myUniformBuffer
{
    vec4 myElement[32];
};

SPIR-V Example

               ...
          %1 = OpExtInstImport "GLSL.std.450"
               ...
               OpName %9 "mySampledImage"
               OpName %14 "myArrayOfSampledImages"
               OpName %18 "myUniformBuffer"
               OpMemberName %18 0 "myElement"
               OpName %20 ""
               OpDecorate %9 DescriptorSet 0
               OpDecorate %9 Binding 0
               OpDecorate %14 DescriptorSet 0
               OpDecorate %14 Binding 1
               OpDecorate %17 ArrayStride 16
               OpMemberDecorate %18 0 Offset 0
               OpDecorate %18 Block
               OpDecorate %20 DescriptorSet 1
               OpDecorate %20 Binding 0
          %2 = OpTypeVoid
          %3 = OpTypeFunction %2
          %6 = OpTypeFloat 32
          %7 = OpTypeImage %6 2D 0 0 0 1 Unknown
          %8 = OpTypePointer UniformConstant %7
          %9 = OpVariable %8 UniformConstant
         %10 = OpTypeInt 32 0
         %11 = OpConstant %10 12
         %12 = OpTypeArray %7 %11
         %13 = OpTypePointer UniformConstant %12
         %14 = OpVariable %13 UniformConstant
         %15 = OpTypeVector %6 4
         %16 = OpConstant %10 32
         %17 = OpTypeArray %15 %16
         %18 = OpTypeStruct %17
         %19 = OpTypePointer Uniform %18
         %20 = OpVariable %19 Uniform
               ...

API Example

VkResult myResult;

const VkDescriptorSetLayoutBinding myDescriptorSetLayoutBinding[] =
{
    // binding to a single image descriptor
    {
        .binding = 0,
        .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
        .descriptorCount = 1,
        .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
        .pImmutableSamplers = NULL
    },

    // binding to an array of image descriptors
    {
        .binding = 1,
        .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
        .descriptorCount = 12,
        .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
        .pImmutableSamplers = NULL
    },

    // binding to a single uniform buffer descriptor
    {
        .binding = 0,
        .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
        .descriptorCount = 1,
        .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
        .pImmutableSamplers = NULL
    }
};

const VkDescriptorSetLayoutCreateInfo myDescriptorSetLayoutCreateInfo[] =
{
    // Information for first descriptor set with two descriptor bindings
    {
        .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
        .pNext = NULL,
        .flags = 0,
        .bindingCount = 2,
        .pBindings = &myDescriptorSetLayoutBinding[0]
    },

    // Information for second descriptor set with one descriptor binding
    {
        .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
        .pNext = NULL,
        .flags = 0,
        .bindingCount = 1,
        .pBindings = &myDescriptorSetLayoutBinding[2]
    }
};

VkDescriptorSetLayout myDescriptorSetLayout[2];

//
// Create first descriptor set layout
//
myResult = vkCreateDescriptorSetLayout(
    myDevice,
    &myDescriptorSetLayoutCreateInfo[0],
    NULL,
    &myDescriptorSetLayout[0]);

//
// Create second descriptor set layout
//
myResult = vkCreateDescriptorSetLayout(
    myDevice,
    &myDescriptorSetLayoutCreateInfo[1],
    NULL,
    &myDescriptorSetLayout[1]);
vkDestroyDescriptorSetLayoutDestroy a descriptor set layout object

Pipeline Layouts

VkPipelineLayoutOpaque handle to a pipeline layout object
vkCreatePipelineLayoutCreates a new pipeline layout object
VkPipelineLayoutCreateInfoStructure specifying the parameters of a newly created pipeline layout object
VkPipelineLayoutCreateFlagBitsPipeline layout creation flag bits
VkPipelineLayoutCreateFlagsBitmask of pipeline layout creation flag bits
VkPushConstantRangeStructure specifying a push constant range

Once created, pipeline layouts can be used as part of pipeline creation (see Pipelines), as part of binding descriptor sets (see Descriptor Set Binding), and as part of setting push constants (see Push Constant Updates). Pipeline creation accepts a pipeline layout as input, and the layout may be used to map (set, binding, arrayElement) tuples to implementation resources or memory locations within a descriptor set. The assignment of implementation resources depends only on the bindings defined in the descriptor sets that comprise the pipeline layout, and not on any shader source.

All resource variables statically used in all shaders in a pipeline must be declared with a (set, binding, arrayElement) that exists in the corresponding descriptor set layout and is of an appropriate descriptor type and includes the set of shader stages it is used by in stageFlags. The pipeline layout can include entries that are not used by a particular pipeline. The pipeline layout allows the application to provide a consistent set of bindings across multiple pipeline compiles, which enables those pipelines to be compiled in a way that the implementation may cheaply switch pipelines without reprogramming the bindings.

Similarly, the push constant block declared in each shader (if present) must only place variables at offsets that are each included in a push constant range with stageFlags including the bit corresponding to the shader stage that uses it. The pipeline layout can include ranges or portions of ranges that are not used by a particular pipeline.

There is a limit on the total number of resources of each type that can be included in bindings in all descriptor set layouts in a pipeline layout as shown in Pipeline Layout Resource Limits. The Total Resources Available column gives the limit on the number of each type of resource that can be included in bindings in all descriptor sets in the pipeline layout. Some resource types count against multiple limits. Additionally, there are limits on the total number of each type of resource that can be used in any pipeline stage as described in Shader Resource Limits.

Total Resources AvailableResource Types

maxDescriptorSetSamplers or maxDescriptorSetUpdateAfterBindSamplers

sampler

combined image sampler

maxDescriptorSetSampledImages or maxDescriptorSetUpdateAfterBindSampledImages

sampled image

combined image sampler

uniform texel buffer

maxDescriptorSetStorageImages or maxDescriptorSetUpdateAfterBindStorageImages

storage image

storage texel buffer

maxDescriptorSetUniformBuffers or maxDescriptorSetUpdateAfterBindUniformBuffers

uniform buffer

uniform buffer dynamic

maxDescriptorSetUniformBuffersDynamic or maxDescriptorSetUpdateAfterBindUniformBuffersDynamic or maxDescriptorSetUpdateAfterBindTotalUniformBuffersDynamic

uniform buffer dynamic

maxDescriptorSetStorageBuffers or maxDescriptorSetUpdateAfterBindStorageBuffers

storage buffer

storage buffer dynamic

maxDescriptorSetStorageBuffersDynamic or maxDescriptorSetUpdateAfterBindStorageBuffersDynamic or maxDescriptorSetUpdateAfterBindTotalStorageBuffersDynamic

storage buffer dynamic

maxDescriptorSetInputAttachments or maxDescriptorSetUpdateAfterBindInputAttachments

input attachment

maxDescriptorSetInlineUniformBlocks or maxDescriptorSetUpdateAfterBindInlineUniformBlocks

inline uniform block

maxDescriptorSetAccelerationStructures or maxDescriptorSetUpdateAfterBindAccelerationStructures

acceleration structure

maxDescriptorSetStorageTensors or maxDescriptorSetUpdateAfterBindStorageTensors

storage tensor

vkDestroyPipelineLayoutDestroy a pipeline layout object

Pipeline Layout Compatibility

Two pipeline layouts are defined to be compatible for push constants if they were created with identical push constant ranges. Two pipeline layouts are defined to be compatible for set N if they were created with identically defined descriptor set layouts for sets zero through N, if both of them either were or were not created with VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT, and if they were created with identical push constant ranges.

When binding a descriptor set (see Descriptor Set Binding) to set number N, a previously bound descriptor set bound with lower index M than N is disturbed if the pipeline layouts for set M and N are not compatible for set M. Otherwise, the bound descriptor set in M is not disturbed.

If, additionally, the previously bound descriptor set for set N was bound using a pipeline layout not compatible for set N, then all bindings in sets numbered greater than N are disturbed.

When binding a pipeline, the pipeline can correctly access any previously bound descriptor set N if it was bound with compatible pipeline layout for set N, and it was not disturbed.

Layout compatibility means that descriptor sets can be bound to a command buffer for use by any pipeline created with a compatible pipeline layout, and without having bound a particular pipeline first. It also means that descriptor sets can remain valid across a pipeline change, and the same resources will be accessible to the newly bound pipeline.

When a descriptor set is disturbed by binding descriptor sets, the disturbed set is considered to contain undefined descriptors bound with the same pipeline layout as the disturbing descriptor set.

Place the least frequently changing descriptor sets near the start of the pipeline layout, and place the descriptor sets representing the most frequently changing resources near the end. When pipelines are switched, only the descriptor set bindings that have been invalidated will need to be updated and the remainder of the descriptor set bindings will remain in place.

The maximum number of descriptor sets that can be bound to a pipeline layout is queried from physical device properties (see maxBoundDescriptorSets in Limits).

API Example

const VkDescriptorSetLayout layouts[] = { layout1, layout2 };

const VkPushConstantRange ranges[] =
{
    {
        .stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
        .offset = 0,
        .size = 4
    },
    {
        .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
        .offset = 4,
        .size = 4
    },
};

const VkPipelineLayoutCreateInfo createInfo =
{
    .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
    .pNext = NULL,
    .flags = 0,
    .setLayoutCount = 2,
    .pSetLayouts = layouts,
    .pushConstantRangeCount = 2,
    .pPushConstantRanges = ranges
};

VkPipelineLayout myPipelineLayout;
myResult = vkCreatePipelineLayout(
    myDevice,
    &createInfo,
    NULL,
    &myPipelineLayout);

Allocation of Descriptor Sets

VkDescriptorPoolOpaque handle to a descriptor pool object
vkCreateDescriptorPoolCreates a descriptor pool object
VkDescriptorPoolCreateInfoStructure specifying parameters of a newly created descriptor pool
VkDescriptorPoolInlineUniformBlockCreateInfoStructure specifying the maximum number of inline uniform block bindings of a newly created descriptor pool
VkDescriptorPoolCreateFlagBitsBitmask specifying certain supported operations on a descriptor pool
VkDescriptorPoolCreateFlagsBitmask of VkDescriptorPoolCreateFlagBits
VkDescriptorPoolSizeStructure specifying descriptor pool size
vkDestroyDescriptorPoolDestroy a descriptor pool object
VkDescriptorSetOpaque handle to a descriptor set object
vkAllocateDescriptorSetsAllocate one or more descriptor sets
VkDescriptorSetAllocateInfoStructure specifying the allocation parameters for descriptor sets
VkDescriptorSetVariableDescriptorCountAllocateInfoStructure specifying additional allocation parameters for descriptor sets
vkFreeDescriptorSetsFree one or more descriptor sets
vkResetDescriptorPoolResets a descriptor pool object
VkDescriptorPoolResetFlagsReserved for future use

Descriptor Set Updates

vkUpdateDescriptorSetsUpdate the contents of a descriptor set object
VkWriteDescriptorSetStructure specifying the parameters of a descriptor set write operation
VkDescriptorBufferInfoStructure specifying descriptor buffer information
VkDescriptorImageInfoStructure specifying descriptor image information
VkWriteDescriptorSetInlineUniformBlockStructure specifying inline uniform block data
VkWriteDescriptorSetAccelerationStructureKHRStructure specifying acceleration structure descriptor information
VkWriteDescriptorSetPartitionedAccelerationStructureNVStructure specifying descriptor for PTLAS
VkWriteDescriptorSetAccelerationStructureNVStructure specifying acceleration structure descriptor information
VkWriteDescriptorSetTensorARMStructure specifying descriptor tensor info
VkCopyDescriptorSetStructure specifying a copy descriptor set operation

Descriptor Update Templates

VkDescriptorUpdateTemplateOpaque handle to a descriptor update template

Descriptor Set Updates With Templates

vkCreateDescriptorUpdateTemplateCreate a new descriptor update template
VkDescriptorUpdateTemplateCreateInfoStructure specifying parameters of a newly created descriptor update template
VkDescriptorUpdateTemplateCreateFlagsReserved for future use
VkDescriptorUpdateTemplateTypeIndicates the valid usage of the descriptor update template
VkDescriptorUpdateTemplateEntryDescribes a single descriptor update of the descriptor update template
vkDestroyDescriptorUpdateTemplateDestroy a descriptor update template object
vkUpdateDescriptorSetWithTemplateUpdate the contents of a descriptor set object using an update template

Descriptor Set Binding

vkCmdBindDescriptorSetsBinds descriptor sets to a command buffer
vkCmdBindDescriptorSets2Binds descriptor sets to a command buffer
VkBindDescriptorSetsInfoStructure specifying a descriptor set binding operation

Push Descriptor Updates

In addition to allocating descriptor sets and binding them to a command buffer, an application can record descriptor updates into the command buffer.

vkCmdPushDescriptorSetPushes descriptor updates into a command buffer
vkCmdPushDescriptorSet2Pushes descriptor updates into a command buffer
VkPushDescriptorSetInfoStructure specifying a descriptor set push operation

Push Descriptor Updates With Descriptor Update Templates

vkCmdPushDescriptorSetWithTemplatePushes descriptor updates into a command buffer using a descriptor update template
vkCmdPushDescriptorSetWithTemplate2Pushes descriptor updates into a command buffer using a descriptor update template
VkPushDescriptorSetWithTemplateInfoStructure specifying a descriptor set push operation using a descriptor update template

Push Constant Updates

As described above in section Pipeline Layouts, the pipeline layout defines shader push constants which are updated via Vulkan commands rather than via writes to memory or copy commands.

Push constants represent a high speed path to modify constant data in pipelines that is expected to outperform memory-backed resource updates.
vkCmdPushConstantsUpdate the values of push constants
vkCmdPushConstants2Update the values of push constants
VkPushConstantsInfoStructure specifying a push constant update operation