| // Copyright (c) 2020-2024 Huawei Technologies Co. Ltd. |
| // |
| // SPDX-License-Identifier: CC-BY-4.0 |
| |
| include::{generated}/meta/{refprefix}VK_HUAWEI_subpass_shading.txt[] |
| |
| === Other Extension Metadata |
| |
| *Last Modified Date*:: |
| 2021-06-01 |
| *Interactions and External Dependencies*:: |
| - This extension requires |
| https://github.com/KhronosGroup/GLSL/blob/master/extensions/huawei/GLSL_HUAWEI_subpass_shading.txt[`GL_HUAWEI_subpass_shading`]. |
| - This extension requires |
| {spirv}/HUAWEI/SPV_HUAWEI_subpass_shading.html[`SPV_HUAWEI_subpass_shading`]. |
| *Contributors*:: |
| - Hueilong Wang |
| |
| === Description |
| |
| This extension allows applications to execute a subpass shading pipeline in |
| a subpass of a render pass in order to save memory bandwidth for algorithms |
| like tile-based deferred rendering and forward plus. |
| A subpass shading pipeline is a pipeline with the compute pipeline ability, |
| allowed to read values from input attachments, and only allowed to be |
| dispatched inside a stand-alone subpass. |
| Its work dimension is defined by the render pass's render area size. |
| Its workgroup size (width, height) shall be a power-of-two number in width |
| or height, with minimum value from 8, and maximum value shall be decided |
| from the render pass attachments and sample counts but depends on |
| implementation. |
| |
| The code:GlobalInvocationId.xy of a subpass shading pipeline is equal to the |
| code:FragCoord.xy of a graphic pipeline in the same render pass subtracted |
| the <<VkRect2D,pname:offset>> of the |
| slink:VkRenderPassBeginInfo::code:renderArea. |
| code:GlobalInvocationId.z is mapped to the Layer if |
| `apiext:VK_EXT_shader_viewport_index_layer` is supported. |
| The code:GlobalInvocationId.xy is equal to the index of the local workgroup |
| multiplied by the size of the local workgroup plus the |
| code:LocalInvocationId and the <<VkRect2D,pname:offset>> of the |
| slink:VkRenderPassBeginInfo::code:renderArea. |
| |
| This extension allows a subpass's pipeline bind point to be |
| ename:VK_PIPELINE_BIND_POINT_SUBPASS_SHADING_HUAWEI. |
| |
| include::{generated}/interfaces/VK_HUAWEI_subpass_shading.txt[] |
| |
| |
| === Sample Code |
| |
| Example of subpass shading in a GLSL shader |
| |
| [source,c] |
| --------------------------------------------------- |
| #extension GL_HUAWEI_subpass_shading: enable |
| #extension GL_KHR_shader_subgroup_arithmetic: enable |
| |
| layout(constant_id = 0) const uint tileWidth = 8; |
| layout(constant_id = 1) const uint tileHeight = 8; |
| layout(local_size_x_id = 0, local_size_y_id = 1, local_size_z = 1) in; |
| layout (set=0, binding=0, input_attachment_index=0) uniform subpassInput depth; |
| |
| void main() |
| { |
| float d = subpassLoad(depth).x; |
| float minD = subgroupMin(d); |
| float maxD = subgroupMax(d); |
| } |
| --------------------------------------------------- |
| |
| Example of subpass shading dispatching in a subpass |
| |
| [source,c] |
| --------------------------------------------------- |
| vkCmdNextSubpass(commandBuffer, VK_SUBPASS_CONTENTS_INLINE); |
| vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_SUBPASS_SHADING_HUAWEI, subpassShadingPipeline); |
| vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_SUBPASS_SHADING_HUAWEI, subpassShadingPipelineLayout, |
| firstSet, descriptorSetCount, pDescriptorSets, dynamicOffsetCount, pDynamicOffsets); |
| vkCmdSubpassShadingHUAWEI(commandBuffer) |
| vkCmdEndRenderPass(commandBuffer); |
| --------------------------------------------------- |
| |
| Example of subpass shading render pass creation |
| |
| [source,c] |
| --------------------------------------------------- |
| VkAttachmentDescription2 attachments[] = { |
| { |
| VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2, NULL, |
| 0, VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_1_BIT, |
| VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_DONT_CARE, |
| VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_LOAD_OP_DONT_CARE, |
| VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL |
| }, |
| { |
| VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2, NULL, |
| 0, VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_1_BIT, |
| VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_DONT_CARE, |
| VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_LOAD_OP_DONT_CARE, |
| VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL |
| }, |
| { |
| VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2, NULL, |
| 0, VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_1_BIT, |
| VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_DONT_CARE, |
| VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_LOAD_OP_DONT_CARE, |
| VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL |
| }, |
| { |
| VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2, NULL, |
| 0, VK_FORMAT_D24_UNORM_S8_UINT, VK_SAMPLE_COUNT_1_BIT, |
| VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_DONT_CARE, |
| VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_LOAD_OP_DONT_CARE, |
| VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL |
| }, |
| { |
| VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2, NULL, |
| 0, VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_1_BIT, |
| VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_STORE, |
| VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_LOAD_OP_DONT_CARE, |
| VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL |
| } |
| }; |
| |
| VkAttachmentReference2 gBufferAttachmentReferences[] = { |
| { VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2, NULL, 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT }, |
| { VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2, NULL, 1, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT }, |
| { VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2, NULL, 2, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT } |
| }; |
| VkAttachmentReference2 gBufferDepthStencilAttachmentReferences = |
| { VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2, NULL, 3, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_DEPTH_BIT|VK_IMAGE_ASPECT_STENCIL_BIT }; |
| VkAttachmentReference2 depthInputAttachmentReferences[] = { |
| { VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2, NULL, 3, VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL, VK_IMAGE_ASPECT_DEPTH_BIT|VK_IMAGE_ASPECT_STENCIL_BIT }; |
| }; |
| VkAttachmentReference2 preserveAttachmentReferences[] = { |
| { VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2, NULL, 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT }, |
| { VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2, NULL, 1, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT }, |
| { VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2, NULL, 2, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT }, |
| { VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2, NULL, 3, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_DEPTH_BIT|VK_IMAGE_ASPECT_STENCIL_BIT } |
| }; // G buffer including depth/stencil |
| VkAttachmentReference2 colorAttachmentReferences[] = { |
| { VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2, NULL, 4, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT } |
| }; |
| VkAttachmentReference2 resolveAttachmentReference = |
| { VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2, NULL, 4, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT }; |
| |
| VkSubpassDescription2 subpasses[] = { |
| { |
| VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2, NULL, 0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, |
| 0, NULL, // input |
| sizeof(gBufferAttachmentReferences)/sizeof(gBufferAttachmentReferences[0]), gBufferAttachmentReferences, // color |
| NULL, &gBufferDepthStencilAttachmentReferences, // resolve & DS |
| 0, NULL |
| }, |
| { |
| VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2, NULL, 0, VK_PIPELINE_BIND_POINT_SUBPASS_SHADING_HUAWEI , 0, |
| sizeof(depthInputAttachmentReferences)/sizeof(depthInputAttachmentReferences[0]), depthInputAttachmentReferences, // input |
| 0, NULL, // color |
| NULL, NULL, // resolve & DS |
| sizeof(preserveAttachmentReferences)/sizeof(preserveAttachmentReferences[0]), preserveAttachmentReferences, |
| }, |
| { |
| VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2, NULL, 0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, |
| sizeof(gBufferAttachmentReferences)/sizeof(gBufferAttachmentReferences[0]), gBufferAttachmentReferences, // input |
| sizeof(colorAttachmentReferences)/sizeof(colorAttachmentReferences[0]), colorAttachmentReferences, // color |
| &resolveAttachmentReference, &gBufferDepthStencilAttachmentReferences, // resolve & DS |
| 0, NULL |
| }, |
| }; |
| |
| VkMemoryBarrier2KHR fragmentToSubpassShading = { |
| VK_STRUCTURE_TYPE_MEMORY_BARRIER_2_KHR, NULL, |
| VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT_KHR, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT|VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, |
| VK_PIPELINE_STAGE_2_SUBPASS_SHADING_BIT_HUAWEI, VK_ACCESS_INPUT_ATTACHMENT_READ_BIT |
| }; |
| |
| VkMemoryBarrier2KHR subpassShadingToFragment = { |
| VK_STRUCTURE_TYPE_MEMORY_BARRIER_2_KHR, NULL, |
| VK_PIPELINE_STAGE_2_SUBPASS_SHADING_BIT_HUAWEI, VK_ACCESS_SHADER_WRITE_BIT, |
| VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT_KHR, VK_ACCESS_SHADER_READ_BIT |
| }; |
| |
| VkSubpassDependency2 dependencies[] = { |
| { |
| VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2, &fragmentToSubpassShading, |
| 0, 1, |
| 0, 0, 0, 0, |
| 0, 0 |
| }, |
| { |
| VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2, &subpassShadingToFragment, |
| 1, 2, |
| 0, 0, 0, 0, |
| 0, 0 |
| }, |
| }; |
| |
| VkRenderPassCreateInfo2 renderPassCreateInfo = { |
| VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2, NULL, 0, |
| sizeof(attachments)/sizeof(attachments[0]), attachments, |
| sizeof(subpasses)/sizeof(subpasses[0]), subpasses, |
| sizeof(dependencies)/sizeof(dependencies[0]), dependencies, |
| 0, NULL |
| }; |
| VKRenderPass renderPass; |
| vkCreateRenderPass2(device, &renderPassCreateInfo, NULL, &renderPass); |
| --------------------------------------------------- |
| |
| Example of subpass shading pipeline creation |
| |
| [source,c] |
| --------------------------------------------------- |
| VkExtent2D maxWorkgroupSize; |
| |
| VkSpecializationMapEntry subpassShadingConstantMapEntries[] = { |
| { 0, 0 * sizeof(uint32_t), sizeof(uint32_t) }, |
| { 1, 1 * sizeof(uint32_t), sizeof(uint32_t) } |
| }; |
| |
| VkSpecializationInfo subpassShadingConstants = { |
| 2, subpassShadingConstantMapEntries, |
| sizeof(VkExtent2D), &maxWorkgroupSize |
| }; |
| |
| VkSubpassShadingPipelineCreateInfoHUAWEI subpassShadingPipelineCreateInfo { |
| VK_STRUCTURE_TYPE_SUBPASSS_SHADING_PIPELINE_CREATE_INFO_HUAWEI, NULL, |
| renderPass, 1 |
| }; |
| |
| VkPipelineShaderStageCreateInfo subpassShadingPipelineStageCreateInfo { |
| VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, NULL, |
| 0, VK_SHADER_STAGE_SUBPASS_SHADING_BIT_HUAWEI, |
| shaderModule, "main", |
| &subpassShadingConstants |
| }; |
| |
| VkComputePipelineCreateInfo subpassShadingComputePipelineCreateInfo = { |
| VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, &subpassShadingPipelineCreateInfo, |
| 0, &subpassShadingPipelineStageCreateInfo, |
| pipelineLayout, basePipelineHandle, basePipelineIndex |
| }; |
| |
| VKPipeline pipeline; |
| |
| vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI(device, renderPass, &maxWorkgroupSize); |
| vkCreateComputePipelines(device, pipelineCache, 1, &subpassShadingComputePipelineCreateInfo, NULL, &pipeline); |
| |
| --------------------------------------------------- |
| |
| |
| === Version History |
| |
| * Revision 2, 2021-06-28 (Hueilong Wang) |
| - Change vkGetSubpassShadingMaxWorkgroupSizeHUAWEI to |
| vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI to resolve issue |
| https://github.com/KhronosGroup/Vulkan-Docs/issues/1564[`pub1564`] |
| * Revision 1, 2020-12-15 (Hueilong Wang) |
| - Initial draft. |
| |