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