VK_EXT_shader_object(3)

# VK_EXT_shader_object(3) Manual Page

## Name

VK_EXT_shader_object - device extension

## Registered Extension Number

483

## Revision

1

## Ratification Status

Ratified

## Extension and Version Dependencies

VK_KHR_get_physical_device_properties2
or
Vulkan Version 1.1
and
VK_KHR_dynamic_rendering
or
Vulkan Version 1.3

## API Interactions

- Interacts with VK_VERSION_1_1

- Interacts with VK_VERSION_1_3

- Interacts with VK_VERSION_1_4

- Interacts with VK_EXT_blend_operation_advanced

- Interacts with VK_EXT_conservative_rasterization

- Interacts with VK_EXT_depth_clamp_control

- Interacts with VK_EXT_depth_clip_control

- Interacts with VK_EXT_depth_clip_enable

- Interacts with VK_EXT_fragment_density_map

- Interacts with VK_EXT_line_rasterization

- Interacts with VK_EXT_mesh_shader

- Interacts with VK_EXT_provoking_vertex

- Interacts with VK_EXT_sample_locations

- Interacts with VK_EXT_subgroup_size_control

- Interacts with VK_EXT_transform_feedback

- Interacts with VK_KHR_device_group

- Interacts with VK_KHR_fragment_shading_rate

- Interacts with VK_KHR_line_rasterization

- Interacts with VK_NV_clip_space_w_scaling

- Interacts with VK_NV_coverage_reduction_mode

- Interacts with VK_NV_fragment_coverage_to_color

- Interacts with VK_NV_framebuffer_mixed_samples

- Interacts with VK_NV_mesh_shader

- Interacts with VK_NV_representative_fragment_test

- Interacts with VK_NV_shading_rate_image

- Interacts with VK_NV_viewport_swizzle

## Contact

- Daniel Story [GitHub]daniel-story

## Extension Proposal

VK_EXT_shader_object

## Other Extension Metadata

Last Modified Date

  2023-03-30

Interactions and External Dependencies

  - Interacts with `VK_EXT_extended_dynamic_state`

  - Interacts with `VK_EXT_extended_dynamic_state2`

  - Interacts with `VK_EXT_extended_dynamic_state3`

  - Interacts with `VK_EXT_vertex_input_dynamic_state`

IP Status

  No known IP claims.

Contributors

  - Piers Daniell, NVIDIA

  - Sandy Jamieson, Nintendo

  - Žiga Markuš, LunarG

  - Tobias Hector, AMD

  - Alex Walters, Imagination

  - Shahbaz Youssefi, Google

  - Ralph Potter, Samsung

  - Jan-Harald Fredriksen, ARM

  - Connor Abott, Valve

  - Arseny Kapoulkine, Roblox

  - Patrick Doane, Activision

  - Jeff Leger, Qualcomm

  - Stu Smith, AMD

  - Chris Glover, Google

  - Ricardo Garcia, Igalia

  - Faith Ekstrand, Collabora

  - Timur Kristóf, Valve

  - Caterina Shablia, Collabora

  - Daniel Koch, NVIDIA

  - Alyssa Rosenzweig, Collabora

  - Mike Blumenkrantz, Valve

  - Samuel Pitoiset, Valve

  - Qun Lin, AMD

  - Spencer Fricke, LunarG

  - Soroush Faghihi Kashani, Imagination

## Description

This extension introduces a new VkShaderEXT object type which represents a single compiled shader stage. Shader objects provide a more flexible alternative to VkPipeline objects, which may be helpful in certain use cases.

## New Object Types

- VkShaderEXT

## New Commands

- vkCmdBindShadersEXT

- vkCmdBindVertexBuffers2EXT

- vkCmdSetAlphaToCoverageEnableEXT

- vkCmdSetAlphaToOneEnableEXT

- vkCmdSetColorBlendEnableEXT

- vkCmdSetColorBlendEquationEXT

- vkCmdSetColorWriteMaskEXT

- vkCmdSetCullModeEXT

- vkCmdSetDepthBiasEnableEXT

- vkCmdSetDepthBoundsTestEnableEXT

- vkCmdSetDepthClampEnableEXT

- vkCmdSetDepthCompareOpEXT

- vkCmdSetDepthTestEnableEXT

- vkCmdSetDepthWriteEnableEXT

- vkCmdSetFrontFaceEXT

- vkCmdSetLogicOpEXT

- vkCmdSetLogicOpEnableEXT

- vkCmdSetPatchControlPointsEXT

- vkCmdSetPolygonModeEXT

- vkCmdSetPrimitiveRestartEnableEXT

- vkCmdSetPrimitiveTopologyEXT

- vkCmdSetRasterizationSamplesEXT

- vkCmdSetRasterizerDiscardEnableEXT

- vkCmdSetSampleMaskEXT

- vkCmdSetScissorWithCountEXT

- vkCmdSetStencilOpEXT

- vkCmdSetStencilTestEnableEXT

- vkCmdSetTessellationDomainOriginEXT

- vkCmdSetVertexInputEXT

- vkCmdSetViewportWithCountEXT

- vkCreateShadersEXT

- vkDestroyShaderEXT

- vkGetShaderBinaryDataEXT

If VK_EXT_blend_operation_advanced is supported:

- vkCmdSetColorBlendAdvancedEXT

If VK_EXT_conservative_rasterization is supported:

- vkCmdSetConservativeRasterizationModeEXT

- vkCmdSetExtraPrimitiveOverestimationSizeEXT

If VK_EXT_depth_clamp_control is supported:

- vkCmdSetDepthClampRangeEXT

If VK_EXT_depth_clip_control is supported:

- vkCmdSetDepthClipNegativeOneToOneEXT

If VK_EXT_depth_clip_enable is supported:

- vkCmdSetDepthClipEnableEXT

If VK_EXT_provoking_vertex is supported:

- vkCmdSetProvokingVertexModeEXT

If VK_EXT_sample_locations is supported:

- vkCmdSetSampleLocationsEnableEXT

If VK_EXT_transform_feedback is supported:

- vkCmdSetRasterizationStreamEXT

If VK_NV_clip_space_w_scaling is supported:

- vkCmdSetViewportWScalingEnableNV

If VK_NV_coverage_reduction_mode is supported:

- vkCmdSetCoverageReductionModeNV

If VK_NV_fragment_coverage_to_color is supported:

- vkCmdSetCoverageToColorEnableNV

- vkCmdSetCoverageToColorLocationNV

If VK_NV_framebuffer_mixed_samples is supported:

- vkCmdSetCoverageModulationModeNV

- vkCmdSetCoverageModulationTableEnableNV

- vkCmdSetCoverageModulationTableNV

If VK_NV_representative_fragment_test is supported:

- vkCmdSetRepresentativeFragmentTestEnableNV

If VK_NV_shading_rate_image is supported:

- vkCmdSetShadingRateImageEnableNV

If VK_NV_viewport_swizzle is supported:

- vkCmdSetViewportSwizzleNV

If Vulkan Version 1.4 or VK_KHR_line_rasterization or VK_EXT_line_rasterization is supported:

- vkCmdSetLineRasterizationModeEXT

- vkCmdSetLineStippleEnableEXT

## New Structures

- VkColorBlendAdvancedEXT

- VkColorBlendEquationEXT

- VkShaderCreateInfoEXT

- VkVertexInputAttributeDescription2EXT

- VkVertexInputBindingDescription2EXT

- Extending VkPhysicalDeviceFeatures2, VkDeviceCreateInfo:

  - VkPhysicalDeviceShaderObjectFeaturesEXT

- Extending VkPhysicalDeviceProperties2:

  - VkPhysicalDeviceShaderObjectPropertiesEXT

- Extending VkPipelineShaderStageCreateInfo, VkShaderCreateInfoEXT:

  - VkShaderRequiredSubgroupSizeCreateInfoEXT

## New Enums

- VkShaderCodeTypeEXT

- VkShaderCreateFlagBitsEXT

## New Bitmasks

- VkShaderCreateFlagsEXT

## New Enum Constants

- `VK_EXT_SHADER_OBJECT_EXTENSION_NAME`

- `VK_EXT_SHADER_OBJECT_SPEC_VERSION`

- Extending VkObjectType:

  - VK_OBJECT_TYPE_SHADER_EXT

- Extending VkResult:

  - VK_ERROR_INCOMPATIBLE_SHADER_BINARY_EXT

  - VK_INCOMPATIBLE_SHADER_BINARY_EXT

- Extending VkStructureType:

  - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_OBJECT_FEATURES_EXT

  - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_OBJECT_PROPERTIES_EXT

  - VK_STRUCTURE_TYPE_SHADER_CREATE_INFO_EXT

  - VK_STRUCTURE_TYPE_SHADER_REQUIRED_SUBGROUP_SIZE_CREATE_INFO_EXT

  - VK_STRUCTURE_TYPE_VERTEX_INPUT_ATTRIBUTE_DESCRIPTION_2_EXT

  - VK_STRUCTURE_TYPE_VERTEX_INPUT_BINDING_DESCRIPTION_2_EXT

If VK_EXT_fragment_density_map is supported:

- Extending VkShaderCreateFlagBitsEXT:

  - VK_SHADER_CREATE_FRAGMENT_DENSITY_MAP_ATTACHMENT_BIT_EXT

If VK_EXT_mesh_shader or VK_NV_mesh_shader is supported:

- Extending VkShaderCreateFlagBitsEXT:

  - VK_SHADER_CREATE_NO_TASK_SHADER_BIT_EXT

If VK_EXT_subgroup_size_control or Vulkan Version 1.3 is supported:

- Extending VkShaderCreateFlagBitsEXT:

  - VK_SHADER_CREATE_ALLOW_VARYING_SUBGROUP_SIZE_BIT_EXT

  - VK_SHADER_CREATE_REQUIRE_FULL_SUBGROUPS_BIT_EXT

If VK_KHR_device_group or Vulkan Version 1.1 is supported:

- Extending VkShaderCreateFlagBitsEXT:

  - VK_SHADER_CREATE_DISPATCH_BASE_BIT_EXT

If VK_KHR_fragment_shading_rate is supported:

- Extending VkShaderCreateFlagBitsEXT:

  - VK_SHADER_CREATE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_EXT

## Examples

Example 1

Create linked pair of vertex and fragment shaders.

    // Logical device created with the shaderObject feature enabled
    VkDevice device;

    // SPIR-V shader code for a vertex shader, along with its size in bytes
    void* pVertexSpirv;
    size_t vertexSpirvSize;

    // SPIR-V shader code for a fragment shader, along with its size in bytes
    void* pFragmentSpirv;
    size_t fragmentSpirvSize;

    // Descriptor set layout compatible with the shaders
    VkDescriptorSetLayout descriptorSetLayout;

    VkShaderCreateInfoEXT shaderCreateInfos[2] =
    {
        {
            .sType = VK_STRUCTURE_TYPE_SHADER_CREATE_INFO_EXT,
            .pNext = NULL,
            .flags = VK_SHADER_CREATE_LINK_STAGE_BIT_EXT,
            .stage = VK_SHADER_STAGE_VERTEX_BIT,
            .nextStage = VK_SHADER_STAGE_FRAGMENT_BIT,
            .codeType = VK_SHADER_CODE_TYPE_SPIRV_EXT,
            .codeSize = vertexSpirvSize,
            .pCode = pVertexSpirv,
            .pName = "main",
            .setLayoutCount = 1,
            .pSetLayouts = &descriptorSetLayout;
            .pushConstantRangeCount = 0,
            .pPushConstantRanges = NULL,
            .pSpecializationInfo = NULL
        },
        {
            .sType = VK_STRUCTURE_TYPE_SHADER_CREATE_INFO_EXT,
            .pNext = NULL,
            .flags = VK_SHADER_CREATE_LINK_STAGE_BIT_EXT,
            .stage = VK_SHADER_STAGE_FRAGMENT_BIT,
            .nextStage = 0,
            .codeType = VK_SHADER_CODE_TYPE_SPIRV_EXT,
            .codeSize = fragmentSpirvSize,
            .pCode = pFragmentSpirv,
            .pName = "main",
            .setLayoutCount = 1,
            .pSetLayouts = &descriptorSetLayout;
            .pushConstantRangeCount = 0,
            .pPushConstantRanges = NULL,
            .pSpecializationInfo = NULL
        }
    };

    VkResult result;
    VkShaderEXT shaders[2];

    result = vkCreateShadersEXT(device, 2, &shaderCreateInfos, NULL, shaders);
    if (result != VK_SUCCESS)
    {
        // Handle error
    }

Later, during command buffer recording, bind the linked shaders and draw.

    // Command buffer in the recording state
    VkCommandBuffer commandBuffer;

    // Vertex and fragment shader objects created above
    VkShaderEXT shaders[2];

    // Assume vertex buffers, descriptor sets, etc. have been bound, and existing
    // state setting commands have been called to set all required state

    const VkShaderStageFlagBits stages[2] =
    {
        VK_SHADER_STAGE_VERTEX_BIT,
        VK_SHADER_STAGE_FRAGMENT_BIT
    };

    // Bind linked shaders
    vkCmdBindShadersEXT(commandBuffer, 2, stages, shaders);

    // Equivalent to the previous line. Linked shaders can be bound one at a time,
    // in any order:
    // vkCmdBindShadersEXT(commandBuffer, 1, &stages[1], &shaders[1]);
    // vkCmdBindShadersEXT(commandBuffer, 1, &stages[0], &shaders[0]);

    // The above is sufficient to draw if the device was created with the
    // tessellationShader and geometryShader features disabled. Otherwise, since
    // those stages should not execute, vkCmdBindShadersEXT() must be called at
    // least once with each of their stages in pStages before drawing:

    const VkShaderStageFlagBits unusedStages[3] =
    {
        VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,
        VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT,
        VK_SHADER_STAGE_GEOMETRY_BIT
    };

    // NULL pShaders is equivalent to an array of stageCount VK_NULL_HANDLE values,
    // meaning no shaders are bound to those stages, and that any previously bound
    // shaders are unbound
    vkCmdBindShadersEXT(commandBuffer, 3, unusedStages, NULL);

    // Graphics shader objects may only be used to draw inside dynamic render pass
    // instances begun with vkCmdBeginRendering(), assume one has already been begun

    // Draw a triangle
    vkCmdDraw(commandBuffer, 3, 1, 0, 0);

Example 2

Create unlinked vertex, geometry, and fragment shaders.

    // Logical device created with the shaderObject feature enabled
    VkDevice device;

    // SPIR-V shader code for vertex shaders, along with their sizes in bytes
    void* pVertexSpirv[2];
    size_t vertexSpirvSize[2];

    // SPIR-V shader code for a geometry shader, along with its size in bytes
    void pGeometrySpirv;
    size_t geometrySpirvSize;

    // SPIR-V shader code for fragment shaders, along with their sizes in bytes
    void* pFragmentSpirv[2];
    size_t fragmentSpirvSize[2];

    // Descriptor set layout compatible with the shaders
    VkDescriptorSetLayout descriptorSetLayout;

    VkShaderCreateInfoEXT shaderCreateInfos[5] =
    {
        // Stage order does not matter
        {
            .sType = VK_STRUCTURE_TYPE_SHADER_CREATE_INFO_EXT,
            .pNext = NULL,
            .flags = 0,
            .stage = VK_SHADER_STAGE_GEOMETRY_BIT,
            .nextStage = VK_SHADER_STAGE_FRAGMENT_BIT,
            .codeType = VK_SHADER_CODE_TYPE_SPIRV_EXT,
            .codeSize = pGeometrySpirv,
            .pCode = geometrySpirvSize,
            .pName = "main",
            .setLayoutCount = 1,
            .pSetLayouts = &descriptorSetLayout;
            .pushConstantRangeCount = 0,
            .pPushConstantRanges = NULL,
            .pSpecializationInfo = NULL
        },
        {
            .sType = VK_STRUCTURE_TYPE_SHADER_CREATE_INFO_EXT,
            .pNext = NULL,
            .flags = 0,
            .stage = VK_SHADER_STAGE_VERTEX_BIT,
            .nextStage = VK_SHADER_STAGE_GEOMETRY_BIT,
            .codeType = VK_SHADER_CODE_TYPE_SPIRV_EXT,
            .codeSize = vertexSpirvSize[0],
            .pCode = pVertexSpirv[0],
            .pName = "main",
            .setLayoutCount = 1,
            .pSetLayouts = &descriptorSetLayout;
            .pushConstantRangeCount = 0,
            .pPushConstantRanges = NULL,
            .pSpecializationInfo = NULL
        },
        {
            .sType = VK_STRUCTURE_TYPE_SHADER_CREATE_INFO_EXT,
            .pNext = NULL,
            .flags = 0,
            .stage = VK_SHADER_STAGE_FRAGMENT_BIT,
            .nextStage = 0,
            .codeType = VK_SHADER_CODE_TYPE_SPIRV_EXT,
            .codeSize = fragmentSpirvSize[0],
            .pCode = pFragmentSpirv[0],
            .pName = "main",
            .setLayoutCount = 1,
            .pSetLayouts = &descriptorSetLayout;
            .pushConstantRangeCount = 0,
            .pPushConstantRanges = NULL,
            .pSpecializationInfo = NULL
        },
        {
            .sType = VK_STRUCTURE_TYPE_SHADER_CREATE_INFO_EXT,
            .pNext = NULL,
            .flags = 0,
            .stage = VK_SHADER_STAGE_FRAGMENT_BIT,
            .nextStage = 0,
            .codeType = VK_SHADER_CODE_TYPE_SPIRV_EXT,
            .codeSize = fragmentSpirvSize[1],
            .pCode = pFragmentSpirv[1],
            .pName = "main",
            .setLayoutCount = 1,
            .pSetLayouts = &descriptorSetLayout;
            .pushConstantRangeCount = 0,
            .pPushConstantRanges = NULL,
            .pSpecializationInfo = NULL
        },
        {
            .sType = VK_STRUCTURE_TYPE_SHADER_CREATE_INFO_EXT,
            .pNext = NULL,
            .flags = 0,
            .stage = VK_SHADER_STAGE_VERTEX_BIT,
            // Suppose we want this vertex shader to be able to be followed by
            // either a geometry shader or fragment shader:
            .nextStage = VK_SHADER_STAGE_GEOMETRY_BIT | VK_SHADER_STAGE_FRAGMENT_BIT,
            .codeType = VK_SHADER_CODE_TYPE_SPIRV_EXT,
            .codeSize = vertexSpirvSize[1],
            .pCode = pVertexSpirv[1],
            .pName = "main",
            .setLayoutCount = 1,
            .pSetLayouts = &descriptorSetLayout;
            .pushConstantRangeCount = 0,
            .pPushConstantRanges = NULL,
            .pSpecializationInfo = NULL
        }
    };

    VkResult result;
    VkShaderEXT shaders[5];

    result = vkCreateShadersEXT(device, 5, &shaderCreateInfos, NULL, shaders);
    if (result != VK_SUCCESS)
    {
        // Handle error
    }

Later, during command buffer recording, bind the linked shaders in different combinations and draw.

    // Command buffer in the recording state
    VkCommandBuffer commandBuffer;

    // Vertex, geometry, and fragment shader objects created above
    VkShaderEXT shaders[5];

    // Assume vertex buffers, descriptor sets, etc. have been bound, and existing
    // state setting commands have been called to set all required state

    const VkShaderStageFlagBits stages[3] =
    {
        // Any order is allowed
        VK_SHADER_STAGE_FRAGMENT_BIT,
        VK_SHADER_STAGE_VERTEX_BIT,
        VK_SHADER_STAGE_GEOMETRY_BIT,
    };

    VkShaderEXT bindShaders[3] =
    {
        shaders[2], // FS
        shaders[1], // VS
        shaders[0]  // GS
    };

    // Bind unlinked shaders
    vkCmdBindShadersEXT(commandBuffer, 3, stages, bindShaders);

    // Assume the tessellationShader feature is disabled, so vkCmdBindShadersEXT()
    // need not have been called with either tessellation stage

    // Graphics shader objects may only be used to draw inside dynamic render pass
    // instances begun with vkCmdBeginRendering(), assume one has already been begun

    // Draw a triangle
    vkCmdDraw(commandBuffer, 3, 1, 0, 0);

    // Bind a different unlinked fragment shader
    const VkShaderStageFlagBits fragmentStage = VK_SHADER_STAGE_FRAGMENT_BIT;
    vkCmdBindShadersEXT(commandBuffer, 1, &fragmentStage, &shaders[3]);

    // Draw another triangle
    vkCmdDraw(commandBuffer, 3, 1, 0, 0);

    // Bind a different unlinked vertex shader
    const VkShaderStageFlagBits vertexStage = VK_SHADER_STAGE_VERTEX_BIT;
    vkCmdBindShadersEXT(commandBuffer, 1, &vertexStage, &shaders[4]);

    // Draw another triangle
    vkCmdDraw(commandBuffer, 3, 1, 0, 0);

## Version History

- Revision 1, 2023-03-30 (Daniel Story)

  - Initial draft

## See Also

No cross-references are available

## Document Notes

For more information, see the Vulkan Specification.

This page is a generated document. Fixes and changes should be made to the generator scripts, not directly.

## Copyright

Copyright 2014-2026 The Khronos Group Inc.

SPDX-License-Identifier: CC-BY-4.0