// Copyright (c) 2020-2024 Huawei Technologies Co. Ltd. // // SPDX-License-Identifier: CC-BY-4.0 include::{generated}/meta/{refprefix}VK_HUAWEI_subpass_shading.adoc[] === Other Extension Metadata *Last Modified Date*:: 2021-06-01 *Interactions and External Dependencies*:: - This extension provides API support for {GLSLregistry}/huawei/GLSL_HUAWEI_subpass_shading.txt[`GL_HUAWEI_subpass_shading`]. *Contributors*:: - Hueilong Wang - Juntao Li, Huawei - Renmiao Lu, Huawei - Pan Gao, Huawei === 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 <> of the slink:VkRenderPassBeginInfo::pname: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 <> of the slink:VkRenderPassBeginInfo::pname: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.adoc[] === 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_SHADER_BIT_HUAWEI, VK_ACCESS_INPUT_ATTACHMENT_READ_BIT }; VkMemoryBarrier2KHR subpassShadingToFragment = { VK_STRUCTURE_TYPE_MEMORY_BARRIER_2_KHR, NULL, VK_PIPELINE_STAGE_2_SUBPASS_SHADER_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 3, 2023-06-19 (Pan Gao) ** Rename `VK_PIPELINE_STAGE_2_SUBPASS_SHADING_BIT_HUAWEI` to `VK_PIPELINE_STAGE_2_SUBPASS_SHADER_BIT_HUAWEI` to better aligned with naming of other pipeline stages * 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.