diff --git a/renderdoc/driver/vulkan/vk_shader_feedback.cpp b/renderdoc/driver/vulkan/vk_shader_feedback.cpp index eef6cf2664..4df1eea6b6 100644 --- a/renderdoc/driver/vulkan/vk_shader_feedback.cpp +++ b/renderdoc/driver/vulkan/vk_shader_feedback.cpp @@ -1579,6 +1579,9 @@ bool VulkanReplay::FetchShaderFeedback(uint32_t eventId) if(pipeLayouts[i] == ResourceId()) continue; + const rdcarray<VulkanStatePipeline::DescriptorAndOffsets> &descSets = + (result.compute ? state.compute.descSets : state.graphics.descSets); + rdcspv::Binding key; for(size_t set = 0; set < pipeInfo.descSetLayouts.size(); set++) @@ -1599,11 +1602,26 @@ bool VulkanReplay::FetchShaderFeedback(uint32_t eventId) if(bindData.descriptorCount > 1 && bindData.layoutDescType != VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK) { + uint32_t descriptorCount = bindData.descriptorCount; + if(bindData.variableSize) + { + if(set < descSets.size()) + { + ResourceId descSet = descSets[set].descSet; + if(descSet != ResourceId()) + { + auto it = m_pDriver->m_DescriptorSetState.find(descSet); + if(it != m_pDriver->m_DescriptorSetState.end()) + descriptorCount = it->second.data.variableDescriptorCount; + } + } + } + key.binding = (uint32_t)binding; - offsetMap[key] = {feedbackStorageSize, bindData.descriptorCount}; + offsetMap[key] = {feedbackStorageSize, descriptorCount}; - feedbackStorageSize += bindData.descriptorCount * sizeof(uint32_t); + feedbackStorageSize += descriptorCount * sizeof(uint32_t); } } } diff --git a/util/test/demos/vk/vk_descriptor_index.cpp b/util/test/demos/vk/vk_descriptor_index.cpp index 9a4d0e2117..0da14b74df 100644 --- a/util/test/demos/vk/vk_descriptor_index.cpp +++ b/util/test/demos/vk/vk_descriptor_index.cpp @@ -38,11 +38,14 @@ #endif +#define DESC_ARRAY3_SIZE 3 + #define BUFIDX 15 #define INDEX3 4 #define INDEX1 49 #define INDEX2 381 #define NONUNIFORMIDX 20 +#define TEX3_INDEX 1 RD_TEST(VK_Descriptor_Indexing, VulkanGraphicsTest) { @@ -93,6 +96,7 @@ layout(push_constant) uniform PushData uint bufidx; uint idx1; uint idx2; + uint idx3; } push; struct tex_ref @@ -123,8 +127,11 @@ void main() outbuf[push.bufidx].outrefs[3].binding = 2; outbuf[push.bufidx].outrefs[3].idx = push.idx2+5; + outbuf[push.bufidx].outrefs[4].binding = 3; + outbuf[push.bufidx].outrefs[4].idx = push.idx3; + // terminator - outbuf[push.bufidx].outrefs[4].binding = 100; + outbuf[push.bufidx].outrefs[5].binding = 100; } )EOSHADER"; @@ -152,6 +159,7 @@ layout(binding = 0, std430) buffer inbuftype { layout(binding = 1) uniform sampler2D tex1[)EOSHADER" STRINGIZE(DESC_ARRAY1_SIZE) R"EOSHADER(]; layout(binding = 2) uniform sampler2D tex2[]; +layout(binding = 3) uniform sampler2D tex3[)EOSHADER" STRINGIZE(DESC_ARRAY3_SIZE) R"EOSHADER(]; void add_color(sampler2D tex) { @@ -220,8 +228,10 @@ void main() // function call with array parameters if(t.binding < 2) dispatch_indirect_color(0, tex1, tex1, 5.0f, t); - else + else if(t.binding < 3) add_color(tex2[t.idx]); + else + add_color(tex3[t.idx]); } } } @@ -269,6 +279,9 @@ void main() else if(!descIndexing.shaderSampledImageArrayNonUniformIndexing) Avail = "Descriptor indexing feature 'shaderSampledImageArrayNonUniformIndexing' not available"; + else if(!descIndexing.descriptorBindingVariableDescriptorCount) + Avail = + "Descriptor indexing feature 'descriptorBindingVariableDescriptorCount' not available"; static VkPhysicalDeviceDescriptorIndexingFeaturesEXT descIndexingEnable = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT, @@ -277,6 +290,7 @@ void main() descIndexingEnable.descriptorBindingPartiallyBound = VK_TRUE; descIndexingEnable.runtimeDescriptorArray = VK_TRUE; descIndexingEnable.shaderSampledImageArrayNonUniformIndexing = VK_TRUE; + descIndexingEnable.descriptorBindingVariableDescriptorCount = VK_TRUE; devInfoNext = &descIndexingEnable; } @@ -291,13 +305,14 @@ void main() VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO_EXT, }; - VkDescriptorBindingFlagsEXT bindFlags[3] = { + VkDescriptorBindingFlagsEXT bindFlags[4] = { VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT, 0, VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT, + VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT_EXT, }; - descFlags.bindingCount = 3; + descFlags.bindingCount = ARRAYSIZE(bindFlags); descFlags.pBindingFlags = bindFlags; VkDescriptorSetLayout setlayout = createDescriptorSetLayout( @@ -321,6 +336,12 @@ void main() DESC_ARRAY2_SIZE, VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_COMPUTE_BIT, }, + { + 3, + VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + UINT32_MAX, + VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_COMPUTE_BIT, + }, }) .next(&descFlags)); @@ -479,11 +500,26 @@ void main() }), NULL, &descpool)); - CHECK_VKR(vkAllocateDescriptorSets( - device, - vkh::DescriptorSetAllocateInfo(descpool, - {setlayout, setlayout, setlayout, setlayout, setlayout}), - descset)); + const static uint32_t numDescriptorSets = ARRAYSIZE(descset); + std::vector<VkDescriptorSetLayout> setLayouts(numDescriptorSets, setlayout); + std::vector<uint32_t> counts(numDescriptorSets, DESC_ARRAY3_SIZE); + + VkDescriptorSetVariableDescriptorCountAllocateInfoEXT countInfo = { + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO_EXT, + NULL, + numDescriptorSets, + counts.data(), + }; + + VkDescriptorSetAllocateInfo allocInfo = { + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, + &countInfo, + descpool, + numDescriptorSets, + setLayouts.data(), + }; + + CHECK_VKR(vkAllocateDescriptorSets(device, &allocInfo, descset)); } VkSampler sampler = createSampler(vkh::SamplerCreateInfo(VK_FILTER_LINEAR)); @@ -516,6 +552,12 @@ void main() up.descriptorCount = DESC_ARRAY2_SIZE - 20; ups.push_back(up); + + up.dstBinding = 3; + up.dstArrayElement = 0; + up.descriptorCount = DESC_ARRAY3_SIZE; + + ups.push_back(up); } vkh::updateDescriptorSets(device, ups); @@ -566,6 +608,11 @@ void main() { vkh::DescriptorImageInfo(imgview, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, sampler), }), + vkh::WriteDescriptorSet( + descset[0], 3, TEX3_INDEX, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + { + vkh::DescriptorImageInfo(imgview, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, sampler), + }), }); while(Running()) @@ -586,13 +633,14 @@ void main() vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, layout, 0, 1, &descset[0], 0, NULL); - Vec4i idx = {BUFIDX, INDEX1, INDEX2, 0}; + Vec4i idx = {BUFIDX, INDEX1, INDEX2, TEX3_INDEX}; vkCmdPushConstants(cmd, layout, VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(Vec4i), &idx); static_assert(BUFIDX < DESC_ARRAY1_SIZE, "Buffer index is out of bounds"); static_assert(INDEX1 < DESC_ARRAY1_SIZE, "Index 1 is out of bounds"); static_assert(INDEX2 < DESC_ARRAY2_SIZE, "Index 2 is out of bounds"); + static_assert(TEX3_INDEX < DESC_ARRAY3_SIZE, "Index 3 is out of bounds"); vkCmdFillBuffer(cmd, ssbo.buffer, 0, 1024 * 1024, 0); diff --git a/util/test/tests/Vulkan/VK_Descriptor_Indexing.py b/util/test/tests/Vulkan/VK_Descriptor_Indexing.py index 33ced052c8..aa161919b4 100644 --- a/util/test/tests/Vulkan/VK_Descriptor_Indexing.py +++ b/util/test/tests/Vulkan/VK_Descriptor_Indexing.py @@ -60,10 +60,12 @@ def check_capture(self): # images 49 & 59 in bind 1 should be used for the first fixed index # image 4 in bind 1 should be used for the global access from a function with no dynamic/patched parameters # - images 381 & 386 in bind 2 should be used for the second fixed index + # - image 1 in bind 3 should be used bind_info = { 0: { 'dynamicallyUsedCount': 1, 'used': [15] }, 1: { 'dynamicallyUsedCount': 6, 'used': [4, 19, 20, 21, 49, 59] }, 2: { 'dynamicallyUsedCount': 2, 'used': [381, 386] }, + 3: { 'dynamicallyUsedCount': 1, 'used': [1] }, } if len(vkpipe.graphics.descriptorSets) != 1: @@ -91,7 +93,7 @@ def check_capture(self): pipe = self.controller.GetPipelineState() ro = pipe.GetReadOnlyResources(rd.ShaderStage.Pixel, False) - self.check_eq(len(ro), 2) + self.check_eq(len(ro), 3) self.check_eq(ro[0].dynamicallyUsedCount, 6) self.check_eq(ro[0].firstIndex, 0) self.check_eq(len(ro[0].resources), 128) @@ -101,7 +103,7 @@ def check_capture(self): self.check(not ro[0].resources[18].dynamicallyUsed) self.check(ro[0].resources[19].dynamicallyUsed) ro = pipe.GetReadOnlyResources(rd.ShaderStage.Pixel, True) - self.check_eq(len(ro), 2) + self.check_eq(len(ro), 3) self.check_eq(ro[0].dynamicallyUsedCount, 6) self.check_eq(ro[0].firstIndex, 4) self.check_eq(len(ro[0].resources), 56)