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
- Constantine Shablya, 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
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:
If VK_EXT_conservative_rasterization is supported:
If VK_EXT_depth_clamp_control is supported:
If VK_EXT_depth_clip_control is supported:
If VK_EXT_depth_clip_enable is supported:
If VK_EXT_line_rasterization is supported:
If VK_EXT_provoking_vertex is supported:
If VK_EXT_sample_locations is supported:
If VK_EXT_transform_feedback is supported:
If VK_NV_clip_space_w_scaling is supported:
If VK_NV_coverage_reduction_mode is supported:
If VK_NV_fragment_coverage_to_color is supported:
If VK_NV_framebuffer_mixed_samples is supported:
- vkCmdSetCoverageModulationModeNV
- vkCmdSetCoverageModulationTableEnableNV
- vkCmdSetCoverageModulationTableNV
If VK_NV_representative_fragment_test is supported:
If VK_NV_shading_rate_image is supported:
If VK_NV_viewport_swizzle is supported:
New Structures
- VkColorBlendAdvancedEXT
- VkColorBlendEquationEXT
- VkShaderCreateInfoEXT
- VkVertexInputAttributeDescription2EXT
- VkVertexInputBindingDescription2EXT
- Extending VkPhysicalDeviceFeatures2, VkDeviceCreateInfo:
- Extending VkPhysicalDeviceProperties2:
- Extending VkPipelineShaderStageCreateInfo, VkShaderCreateInfoEXT:
New Enums
New Bitmasks
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