1// Copyright 2023 The Khronos Group Inc. 2// 3// SPDX-License-Identifier: CC-BY-4.0 4 5include::{generated}/meta/{refprefix}VK_EXT_shader_object.adoc[] 6 7=== Other Extension Metadata 8 9*Last Modified Date*:: 10 2023-03-30 11*Interactions and External Dependencies*:: 12 - Interacts with `apiext:VK_EXT_extended_dynamic_state` 13 - Interacts with `apiext:VK_EXT_extended_dynamic_state2` 14 - Interacts with `apiext:VK_EXT_extended_dynamic_state3` 15 - Interacts with `apiext:VK_EXT_vertex_input_dynamic_state` 16*IP Status*:: 17 No known IP claims. 18*Contributors*:: 19 - Piers Daniell, NVIDIA 20 - Sandy Jamieson, Nintendo 21 - Žiga Markuš, LunarG 22 - Tobias Hector, AMD 23 - Alex Walters, Imagination 24 - Shahbaz Youssefi, Google 25 - Ralph Potter, Samsung 26 - Jan-Harald Fredriksen, ARM 27 - Connor Abott, Valve 28 - Arseny Kapoulkine, Roblox 29 - Patrick Doane, Activision 30 - Jeff Leger, Qualcomm 31 - Stu Smith, AMD 32 - Chris Glover, Google 33 - Ricardo Garcia, Igalia 34 - Faith Ekstrand, Collabora 35 - Timur Kristóf, Valve 36 - Constantine Shablya, Collabora 37 - Daniel Koch, NVIDIA 38 - Alyssa Rosenzweig, Collabora 39 - Mike Blumenkrantz, Valve 40 - Samuel Pitoiset, Valve 41 - Qun Lin, AMD 42 - Spencer Fricke, LunarG 43 - Soroush Faghihi Kashani, Imagination 44 45=== Description 46 47This extension introduces a new slink:VkShaderEXT object type which 48represents a single compiled shader stage. 49Shader objects provide a more flexible alternative to slink:VkPipeline 50objects, which may be helpful in certain use cases. 51 52include::{generated}/interfaces/VK_EXT_shader_object.adoc[] 53 54=== Examples 55 56*Example 1* 57 58Create linked pair of vertex and fragment shaders. 59 60[source,c++] 61---- 62// Logical device created with the shaderObject feature enabled 63VkDevice device; 64 65// SPIR-V shader code for a vertex shader, along with its size in bytes 66void* pVertexSpirv; 67size_t vertexSpirvSize; 68 69// SPIR-V shader code for a fragment shader, along with its size in bytes 70void* pFragmentSpirv; 71size_t fragmentSpirvSize; 72 73// Descriptor set layout compatible with the shaders 74VkDescriptorSetLayout descriptorSetLayout; 75 76VkShaderCreateInfoEXT shaderCreateInfos[2] = 77{ 78 { 79 .sType = VK_STRUCTURE_TYPE_SHADER_CREATE_INFO_EXT, 80 .pNext = NULL, 81 .flags = VK_SHADER_CREATE_LINK_STAGE_BIT_EXT, 82 .stage = VK_SHADER_STAGE_VERTEX_BIT, 83 .nextStage = VK_SHADER_STAGE_FRAGMENT_BIT, 84 .codeType = VK_SHADER_CODE_TYPE_SPIRV_EXT, 85 .codeSize = vertexSpirvSize, 86 .pCode = pVertexSpirv, 87 .pName = "main", 88 .setLayoutCount = 1, 89 .pSetLayouts = &descriptorSetLayout; 90 .pushConstantRangeCount = 0, 91 .pPushConstantRanges = NULL, 92 .pSpecializationInfo = NULL 93 }, 94 { 95 .sType = VK_STRUCTURE_TYPE_SHADER_CREATE_INFO_EXT, 96 .pNext = NULL, 97 .flags = VK_SHADER_CREATE_LINK_STAGE_BIT_EXT, 98 .stage = VK_SHADER_STAGE_FRAGMENT_BIT, 99 .nextStage = 0, 100 .codeType = VK_SHADER_CODE_TYPE_SPIRV_EXT, 101 .codeSize = fragmentSpirvSize, 102 .pCode = pFragmentSpirv, 103 .pName = "main", 104 .setLayoutCount = 1, 105 .pSetLayouts = &descriptorSetLayout; 106 .pushConstantRangeCount = 0, 107 .pPushConstantRanges = NULL, 108 .pSpecializationInfo = NULL 109 } 110}; 111 112VkResult result; 113VkShaderEXT shaders[2]; 114 115result = vkCreateShadersEXT(device, 2, &shaderCreateInfos, NULL, shaders); 116if (result != VK_SUCCESS) 117{ 118 // Handle error 119} 120---- 121 122Later, during command buffer recording, bind the linked shaders and draw. 123 124[source,c++] 125---- 126// Command buffer in the recording state 127VkCommandBuffer commandBuffer; 128 129// Vertex and fragment shader objects created above 130VkShaderEXT shaders[2]; 131 132// Assume vertex buffers, descriptor sets, etc. have been bound, and existing 133// state setting commands have been called to set all required state 134 135const VkShaderStageFlagBits stages[2] = 136{ 137 VK_SHADER_STAGE_VERTEX_BIT, 138 VK_SHADER_STAGE_FRAGMENT_BIT 139}; 140 141// Bind linked shaders 142vkCmdBindShadersEXT(commandBuffer, 2, stages, shaders); 143 144// Equivalent to the previous line. Linked shaders can be bound one at a time, 145// in any order: 146// vkCmdBindShadersEXT(commandBuffer, 1, &stages[1], &shaders[1]); 147// vkCmdBindShadersEXT(commandBuffer, 1, &stages[0], &shaders[0]); 148 149// The above is sufficient to draw if the device was created with the 150// tessellationShader and geometryShader features disabled. Otherwise, since 151// those stages should not execute, vkCmdBindShadersEXT() must be called at 152// least once with each of their stages in pStages before drawing: 153 154const VkShaderStageFlagBits unusedStages[3] = 155{ 156 VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, 157 VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, 158 VK_SHADER_STAGE_GEOMETRY_BIT 159}; 160 161// NULL pShaders is equivalent to an array of stageCount VK_NULL_HANDLE values, 162// meaning no shaders are bound to those stages, and that any previously bound 163// shaders are unbound 164vkCmdBindShadersEXT(commandBuffer, 3, unusedStages, NULL); 165 166// Graphics shader objects may only be used to draw inside dynamic render pass 167// instances begun with vkCmdBeginRendering(), assume one has already been begun 168 169// Draw a triangle 170vkCmdDraw(commandBuffer, 3, 1, 0, 0); 171---- 172 173*Example 2* 174 175Create unlinked vertex, geometry, and fragment shaders. 176 177[source,c++] 178---- 179// Logical device created with the shaderObject feature enabled 180VkDevice device; 181 182// SPIR-V shader code for vertex shaders, along with their sizes in bytes 183void* pVertexSpirv[2]; 184size_t vertexSpirvSize[2]; 185 186// SPIR-V shader code for a geometry shader, along with its size in bytes 187void pGeometrySpirv; 188size_t geometrySpirvSize; 189 190// SPIR-V shader code for fragment shaders, along with their sizes in bytes 191void* pFragmentSpirv[2]; 192size_t fragmentSpirvSize[2]; 193 194// Descriptor set layout compatible with the shaders 195VkDescriptorSetLayout descriptorSetLayout; 196 197VkShaderCreateInfoEXT shaderCreateInfos[5] = 198{ 199 // Stage order does not matter 200 { 201 .sType = VK_STRUCTURE_TYPE_SHADER_CREATE_INFO_EXT, 202 .pNext = NULL, 203 .flags = 0, 204 .stage = VK_SHADER_STAGE_GEOMETRY_BIT, 205 .nextStage = VK_SHADER_STAGE_FRAGMENT_BIT, 206 .codeType = VK_SHADER_CODE_TYPE_SPIRV_EXT, 207 .codeSize = pGeometrySpirv, 208 .pCode = geometrySpirvSize, 209 .pName = "main", 210 .setLayoutCount = 1, 211 .pSetLayouts = &descriptorSetLayout; 212 .pushConstantRangeCount = 0, 213 .pPushConstantRanges = NULL, 214 .pSpecializationInfo = NULL 215 }, 216 { 217 .sType = VK_STRUCTURE_TYPE_SHADER_CREATE_INFO_EXT, 218 .pNext = NULL, 219 .flags = 0, 220 .stage = VK_SHADER_STAGE_VERTEX_BIT, 221 .nextStage = VK_SHADER_STAGE_GEOMETRY_BIT, 222 .codeType = VK_SHADER_CODE_TYPE_SPIRV_EXT, 223 .codeSize = vertexSpirvSize[0], 224 .pCode = pVertexSpirv[0], 225 .pName = "main", 226 .setLayoutCount = 1, 227 .pSetLayouts = &descriptorSetLayout; 228 .pushConstantRangeCount = 0, 229 .pPushConstantRanges = NULL, 230 .pSpecializationInfo = NULL 231 }, 232 { 233 .sType = VK_STRUCTURE_TYPE_SHADER_CREATE_INFO_EXT, 234 .pNext = NULL, 235 .flags = 0, 236 .stage = VK_SHADER_STAGE_FRAGMENT_BIT, 237 .nextStage = 0, 238 .codeType = VK_SHADER_CODE_TYPE_SPIRV_EXT, 239 .codeSize = fragmentSpirvSize[0], 240 .pCode = pFragmentSpirv[0], 241 .pName = "main", 242 .setLayoutCount = 1, 243 .pSetLayouts = &descriptorSetLayout; 244 .pushConstantRangeCount = 0, 245 .pPushConstantRanges = NULL, 246 .pSpecializationInfo = NULL 247 }, 248 { 249 .sType = VK_STRUCTURE_TYPE_SHADER_CREATE_INFO_EXT, 250 .pNext = NULL, 251 .flags = 0, 252 .stage = VK_SHADER_STAGE_FRAGMENT_BIT, 253 .nextStage = 0, 254 .codeType = VK_SHADER_CODE_TYPE_SPIRV_EXT, 255 .codeSize = fragmentSpirvSize[1], 256 .pCode = pFragmentSpirv[1], 257 .pName = "main", 258 .setLayoutCount = 1, 259 .pSetLayouts = &descriptorSetLayout; 260 .pushConstantRangeCount = 0, 261 .pPushConstantRanges = NULL, 262 .pSpecializationInfo = NULL 263 }, 264 { 265 .sType = VK_STRUCTURE_TYPE_SHADER_CREATE_INFO_EXT, 266 .pNext = NULL, 267 .flags = 0, 268 .stage = VK_SHADER_STAGE_VERTEX_BIT, 269 // Suppose we want this vertex shader to be able to be followed by 270 // either a geometry shader or fragment shader: 271 .nextStage = VK_SHADER_STAGE_GEOMETRY_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 272 .codeType = VK_SHADER_CODE_TYPE_SPIRV_EXT, 273 .codeSize = vertexSpirvSize[1], 274 .pCode = pVertexSpirv[1], 275 .pName = "main", 276 .setLayoutCount = 1, 277 .pSetLayouts = &descriptorSetLayout; 278 .pushConstantRangeCount = 0, 279 .pPushConstantRanges = NULL, 280 .pSpecializationInfo = NULL 281 } 282}; 283 284VkResult result; 285VkShaderEXT shaders[5]; 286 287result = vkCreateShadersEXT(device, 5, &shaderCreateInfos, NULL, shaders); 288if (result != VK_SUCCESS) 289{ 290 // Handle error 291} 292---- 293 294Later, during command buffer recording, bind the linked shaders in different 295combinations and draw. 296 297[source,c++] 298---- 299// Command buffer in the recording state 300VkCommandBuffer commandBuffer; 301 302// Vertex, geometry, and fragment shader objects created above 303VkShaderEXT shaders[5]; 304 305// Assume vertex buffers, descriptor sets, etc. have been bound, and existing 306// state setting commands have been called to set all required state 307 308const VkShaderStageFlagBits stages[3] = 309{ 310 // Any order is allowed 311 VK_SHADER_STAGE_FRAGMENT_BIT, 312 VK_SHADER_STAGE_VERTEX_BIT, 313 VK_SHADER_STAGE_GEOMETRY_BIT, 314}; 315 316VkShaderEXT bindShaders[3] = 317{ 318 shaders[2], // FS 319 shaders[1], // VS 320 shaders[0] // GS 321}; 322 323// Bind unlinked shaders 324vkCmdBindShadersEXT(commandBuffer, 3, stages, bindShaders); 325 326// Assume the tessellationShader feature is disabled, so vkCmdBindShadersEXT() 327// need not have been called with either tessellation stage 328 329// Graphics shader objects may only be used to draw inside dynamic render pass 330// instances begun with vkCmdBeginRendering(), assume one has already been begun 331 332// Draw a triangle 333vkCmdDraw(commandBuffer, 3, 1, 0, 0); 334 335// Bind a different unlinked fragment shader 336const VkShaderStageFlagBits fragmentStage = VK_SHADER_STAGE_FRAGMENT_BIT; 337vkCmdBindShadersEXT(commandBuffer, 1, &fragmentStage, &shaders[3]); 338 339// Draw another triangle 340vkCmdDraw(commandBuffer, 3, 1, 0, 0); 341 342// Bind a different unlinked vertex shader 343const VkShaderStageFlagBits vertexStage = VK_SHADER_STAGE_VERTEX_BIT; 344vkCmdBindShadersEXT(commandBuffer, 1, &vertexStage, &shaders[4]); 345 346// Draw another triangle 347vkCmdDraw(commandBuffer, 3, 1, 0, 0); 348---- 349 350=== Version History 351 352 * Revision 1, 2023-03-30 (Daniel Story) 353 ** Initial draft 354