diff --git a/renderdoc/driver/vulkan/vk_info.cpp b/renderdoc/driver/vulkan/vk_info.cpp index 7af6eedb1..11f37487f 100644 --- a/renderdoc/driver/vulkan/vk_info.cpp +++ b/renderdoc/driver/vulkan/vk_info.cpp @@ -2949,6 +2949,8 @@ void DescUpdateTemplate::Apply(const void *pData, DescUpdateTemplateApplication void *dst = application.inlineData.data() + inlineOffset; memcpy(dst, src, inlineWrite.dataSize); inlineWrite.pData = dst; + inlineOffset += inlineWrite.dataSize; + inlineOffset = AlignUp4(inlineOffset); write.pNext = &inlineWrite; write.descriptorCount = entry.descriptorCount; diff --git a/util/test/demos/vk/vk_cbuffer_zoo.cpp b/util/test/demos/vk/vk_cbuffer_zoo.cpp index a03ca495e..9999b4a2c 100644 --- a/util/test/demos/vk/vk_cbuffer_zoo.cpp +++ b/util/test/demos/vk/vk_cbuffer_zoo.cpp @@ -742,16 +742,14 @@ float4 main() : SV_Target0 if(hasExt(VK_EXT_INLINE_UNIFORM_BLOCK_EXTENSION_NAME)) { - VkWriteDescriptorSetInlineUniformBlockEXT inlineUpdate = {}; - inlineUpdate.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK_EXT; - inlineUpdate.pData = &inlinedata; - inlineUpdate.dataSize = sizeof(inlinedata); vkh::updateDescriptorSets( - device, { - vkh::WriteDescriptorSet( - descset, 1, inlineUpdate, - vkh::DescriptorBufferInfo(cb.buffer, bindOffset * sizeof(Vec4f))), - }); + device, + { + vkh::WriteDescriptorSet( + descset, 1, + vkh::WriteDescriptorSetInlineUniformBlockEXT(&inlinedata, sizeof(inlinedata)), + vkh::DescriptorBufferInfo(cb.buffer, bindOffset * sizeof(Vec4f))), + }); } else { diff --git a/util/test/demos/vk/vk_helpers.h b/util/test/demos/vk/vk_helpers.h index 28acc31ba..40469574f 100644 --- a/util/test/demos/vk/vk_helpers.h +++ b/util/test/demos/vk/vk_helpers.h @@ -922,6 +922,19 @@ struct DescriptorImageInfo : public VkDescriptorImageInfo } }; +struct WriteDescriptorSetInlineUniformBlockEXT : public VkWriteDescriptorSetInlineUniformBlockEXT +{ + WriteDescriptorSetInlineUniformBlockEXT(void *data, uint32_t size) + { + sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK_EXT; + pNext = NULL; + this->pData = data; + this->dataSize = size; + } + + operator const VkWriteDescriptorSetInlineUniformBlockEXT *() const { return this; } +}; + struct WriteDescriptorSet : public VkWriteDescriptorSet { WriteDescriptorSet(VkDescriptorSet dstSet, uint32_t dstBinding, uint32_t dstArrayElement, diff --git a/util/test/demos/vk/vk_parameter_zoo.cpp b/util/test/demos/vk/vk_parameter_zoo.cpp index bea1e8aa2..e580c7570 100644 --- a/util/test/demos/vk/vk_parameter_zoo.cpp +++ b/util/test/demos/vk/vk_parameter_zoo.cpp @@ -104,6 +104,28 @@ void main() Color = ubos[7].data; } +)EOSHADER"; + + const std::string inlineubopixel = R"EOSHADER( +#version 450 core + +layout(location = 0, index = 0) out vec4 Color; + +layout(binding=0) uniform ubo_block1 +{ + vec4 col; +} ubo1; + +layout(binding=1) uniform ubo_block2 +{ + vec4 col; +} ubo2; + +void main() +{ + Color = ubo1.col + ubo2.col; +} + )EOSHADER"; const std::string refpixel = R"EOSHADER( @@ -263,6 +285,7 @@ void main() void Prepare(int argc, char **argv) { optDevExts.push_back(VK_EXT_GRAPHICS_PIPELINE_LIBRARY_EXTENSION_NAME); + optDevExts.push_back(VK_EXT_INLINE_UNIFORM_BLOCK_EXTENSION_NAME); optDevExts.push_back(VK_EXT_TOOLING_INFO_EXTENSION_NAME); optDevExts.push_back(VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME); optDevExts.push_back(VK_KHR_BIND_MEMORY_2_EXTENSION_NAME); @@ -363,6 +386,17 @@ void main() dyn.pNext = (void *)devInfoNext; devInfoNext = &dyn; } + + static VkPhysicalDeviceInlineUniformBlockFeaturesEXT inlineFeats = { + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES_EXT, + }; + + if(hasExt(VK_EXT_INLINE_UNIFORM_BLOCK_EXTENSION_NAME)) + { + inlineFeats.inlineUniformBlock = VK_TRUE; + inlineFeats.pNext = (void *)devInfoNext; + devInfoNext = &inlineFeats; + } } int main() @@ -566,6 +600,27 @@ void main() VkPipelineLayout dynamicarraylayout = createPipelineLayout(vkh::PipelineLayoutCreateInfo({dynamicarraysetlayout})); + VkDescriptorSetLayout inlineubosetlayout = VK_NULL_HANDLE; + + if(hasExt(VK_EXT_INLINE_UNIFORM_BLOCK_EXTENSION_NAME)) + { + inlineubosetlayout = createDescriptorSetLayout(vkh::DescriptorSetLayoutCreateInfo({ + {0, VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK, 16, VK_SHADER_STAGE_FRAGMENT_BIT}, + {1, VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK, 16, VK_SHADER_STAGE_FRAGMENT_BIT}, + })); + } + else + { + // dummy, won't be tested + inlineubosetlayout = createDescriptorSetLayout(vkh::DescriptorSetLayoutCreateInfo({ + {0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, + {1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, + })); + } + + VkPipelineLayout inlineubolayout = + createPipelineLayout(vkh::PipelineLayoutCreateInfo({inlineubosetlayout})); + VkDescriptorSet descset2 = allocateDescriptorSet(setlayout2); VkDescriptorSetLayout asm_setlayout = @@ -682,6 +737,15 @@ void main() VkPipeline dynarraypipe = createGraphicsPipeline(pipeCreateInfo); + pipeCreateInfo.layout = inlineubolayout; + + pipeCreateInfo.stages = { + CompileShaderModule(VKDefaultVertex, ShaderLang::glsl, ShaderStage::vert, "main"), + CompileShaderModule(inlineubopixel, ShaderLang::glsl, ShaderStage::frag, "main"), + }; + + VkPipeline inlineubopipe = createGraphicsPipeline(pipeCreateInfo); + pipeCreateInfo.stages = { CompileShaderModule(VKDefaultVertex, ShaderLang::glsl, ShaderStage::vert, "main"), CompileShaderModule(pixel2, ShaderLang::glsl, ShaderStage::frag, "main"), @@ -1201,6 +1265,53 @@ void main() vkCreateDescriptorUpdateTemplateKHR(device, &createInfo, NULL, &refpushtempl); } + Vec4f inlinetemplData[2] = { + Vec4f(1.0f, 0.0f, 0.0f, 0.0f), + Vec4f(0.0f, 0.0f, 1.0f, 1.0f), + }; + + VkDescriptorUpdateTemplateKHR inlinetempl = VK_NULL_HANDLE; + VkDescriptorSet inlineuboset = allocateDescriptorSet(inlineubosetlayout); + VkDescriptorSet inlineuboset_templ = allocateDescriptorSet(inlineubosetlayout); + VkDescriptorSet inlineuboset_templ_dyn = allocateDescriptorSet(inlineubosetlayout); + + if(hasExt(VK_EXT_INLINE_UNIFORM_BLOCK_EXTENSION_NAME)) + { + vkh::updateDescriptorSets( + device, { + vkh::WriteDescriptorSet(inlineuboset, 0, + vkh::WriteDescriptorSetInlineUniformBlockEXT( + &inlinetemplData[0], sizeof(Vec4f)), + vkh::DescriptorBufferInfo(validBuffer)), + vkh::WriteDescriptorSet(inlineuboset, 1, + vkh::WriteDescriptorSetInlineUniformBlockEXT( + &inlinetemplData[1], sizeof(Vec4f)), + vkh::DescriptorBufferInfo(validBuffer)), + }); + + if(KHR_descriptor_update_template) + { + std::vector entries = { + {0, 0, sizeof(Vec4f), VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK, 0, sizeof(Vec4f) * 2}, + {1, 0, sizeof(Vec4f), VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK, sizeof(Vec4f), + sizeof(Vec4f) * 2}, + }; + + VkDescriptorUpdateTemplateCreateInfoKHR createInfo = {}; + createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR; + createInfo.descriptorUpdateEntryCount = (uint32_t)entries.size(); + createInfo.pDescriptorUpdateEntries = entries.data(); + createInfo.templateType = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET_KHR; + createInfo.descriptorSetLayout = setlayout; + createInfo.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + + vkCreateDescriptorUpdateTemplateKHR(device, &createInfo, NULL, &inlinetempl); + + vkUpdateDescriptorSetWithTemplateKHR(device, inlineuboset_templ, inlinetempl, + &inlinetemplData); + } + } + // check that stale views in descriptors don't cause problems if the handle is re-used VkImageView view1, view2; @@ -1619,6 +1730,10 @@ void main() if(KHR_descriptor_update_template) vkUpdateDescriptorSetWithTemplateKHR(device, reftempldescset, reftempl, &reftempldata); + if(hasExt(VK_EXT_INLINE_UNIFORM_BLOCK_EXTENSION_NAME) && KHR_descriptor_update_template) + vkUpdateDescriptorSetWithTemplateKHR(device, inlineuboset_templ_dyn, inlinetempl, + &inlinetemplData); + VkCommandBuffer cmd = GetCommandBuffer(); vkBeginCommandBuffer(cmd, vkh::CommandBufferBeginInfo()); @@ -1800,6 +1915,33 @@ void main() setMarker(cmd, "Dynamic Array Draw"); vkCmdDraw(cmd, 3, 1, 0, 0); + if(hasExt(VK_EXT_INLINE_UNIFORM_BLOCK_EXTENSION_NAME)) + { + vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, inlineubopipe); + vkh::cmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, inlineubolayout, 0, + {inlineuboset}, {}); + + setMarker(cmd, "Inline UBO Draw"); + vkCmdDraw(cmd, 3, 1, 0, 0); + + if(KHR_descriptor_update_template) + { + vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, inlineubopipe); + vkh::cmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, inlineubolayout, 0, + {inlineuboset_templ}, {}); + + setMarker(cmd, "Inline UBO + Templ Draw"); + vkCmdDraw(cmd, 3, 1, 0, 0); + + vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, inlineubopipe); + vkh::cmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, inlineubolayout, 0, + {inlineuboset_templ_dyn}, {}); + + setMarker(cmd, "Inline UBO + Templ Dyn Draw"); + vkCmdDraw(cmd, 3, 1, 0, 0); + } + } + vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe2); vkh::cmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, layout2, 0, {descset2}, {}); @@ -1881,8 +2023,13 @@ void main() } if(KHR_descriptor_update_template) + { vkDestroyDescriptorUpdateTemplateKHR(device, reftempl, NULL); + if(hasExt(VK_EXT_INLINE_UNIFORM_BLOCK_EXTENSION_NAME)) + vkDestroyDescriptorUpdateTemplateKHR(device, inlinetempl, NULL); + } + return 0; } }; diff --git a/util/test/tests/Vulkan/VK_Parameter_Zoo.py b/util/test/tests/Vulkan/VK_Parameter_Zoo.py index bf3c621f2..8b1864a4d 100644 --- a/util/test/tests/Vulkan/VK_Parameter_Zoo.py +++ b/util/test/tests/Vulkan/VK_Parameter_Zoo.py @@ -217,6 +217,56 @@ class VK_Parameter_Zoo(rdtest.TestCase): rdtest.log.success("ASM Draw is as expected") + inline_ubo_actions = [ + self.find_action("Inline UBO Draw"), + self.find_action("Inline UBO + Templ Draw"), + self.find_action("Inline UBO + Templ Dyn Draw"), + ] + action = self.find_action("Inline UBO Draw") + + for action in inline_ubo_actions: + if action is None: + continue + + rdtest.log.print(f"Checking {action.customName}") + + self.controller.SetFrameEvent(action.next.eventId, False) + + self.check_triangle(fore=[1.0, 0.0, 1.0, 1.0]) + + stage = rd.ShaderStage.Pixel + + pipe = self.controller.GetPipelineState() + ubo1 = pipe.GetConstantBlock(stage, 0, 0).descriptor + ubo2 = pipe.GetConstantBlock(stage, 1, 0).descriptor + + ubo1_vars = self.controller.GetCBufferVariableContents(pipe.GetGraphicsPipelineObject(), + pipe.GetShader( + stage), stage, + pipe.GetShaderEntryPoint( + stage), 0, + ubo1.resource, ubo1.byteOffset, ubo1.byteSize) + ubo2_vars = self.controller.GetCBufferVariableContents(pipe.GetGraphicsPipelineObject(), + pipe.GetShader( + stage), stage, + pipe.GetShaderEntryPoint( + stage), 1, + ubo2.resource, ubo2.byteOffset, ubo2.byteSize) + + if len(ubo1_vars) != 1 or ubo1_vars[0].name != "col": + raise rdtest.TestFailureException("Didn't find ubo1 col variable") + + if len(ubo2_vars) != 1 or ubo2_vars[0].name != "col": + raise rdtest.TestFailureException("Didn't find ubo2 col variable") + + if ubo1_vars[0].value.f32v[0:4] != (1.0, 0.0, 0.0, 0.0): + raise rdtest.TestFailureException(f"ubo1 col value incorrect: {ubo1_vars[0].value.f32v[0:4]}") + + if ubo2_vars[0].value.f32v[0:4] != (0.0, 0.0, 1.0, 1.0): + raise rdtest.TestFailureException(f"ubo2 col value incorrect: {ubo2_vars[0].value.f32v[0:4]}") + + rdtest.log.success(f"{action.customName} is as expected") + action = self.find_action("Immutable Draw") self.check(action is not None)