diff --git a/util/test/demos/vk/vk_cbuffer_zoo.cpp b/util/test/demos/vk/vk_cbuffer_zoo.cpp index 1e919fdc3..50d853a52 100644 --- a/util/test/demos/vk/vk_cbuffer_zoo.cpp +++ b/util/test/demos/vk/vk_cbuffer_zoo.cpp @@ -269,13 +269,23 @@ layout(set = 0, binding = 0, std140) uniform constsbuf vec4 test; // {536, 537, 538, 539} }; +// this comes from inline uniform block data, where available + +layout(set = 0, binding = 1, std140) uniform inlineconsts +{ + vec4 inline_zero; + vec4 inline_a; + vec2 inline_b, inline_c; + vec3_1 inline_d; +}; + layout (constant_id = 0) const int A = 10; layout (constant_id = 1) const float B = 0; layout (constant_id = 3) const bool C = false; void main() { - Color = test + vec4(0.1f, 0.0f, 0.0f, 0.0f); + Color = test + inline_zero + vec4(0.1f, 0.0f, 0.0f, 0.0f); } )EOSHADER"; @@ -527,18 +537,53 @@ layout(set = 0, binding = 0) cbuffer consts float4 test; // {536, 537, 538, 539} }; +// this comes from inline uniform block data, where available +layout(set = 0, binding = 1) cbuffer inlineconsts +{ + float4 inline_zero; + float4 inline_a; + float2 inline_b, inline_c; + float3_1 inline_d; +}; + float4 main() : SV_Target0 { - return test + float4(0.1f, 0.0f, 0.0f, 0.0f); + return test + inline_zero + float4(0.1f, 0.0f, 0.0f, 0.0f); } )EOSHADER"; + struct float3_1 + { + float a[3]; + float b; + }; + + struct InlineData + { + float inline_zero[4]; + float inline_a[4]; + float inline_b[2], inline_c[2]; + float3_1 inline_d; + }; + void Prepare(int argc, char **argv) { devExts.push_back(VK_KHR_RELAXED_BLOCK_LAYOUT_EXTENSION_NAME); + optDevExts.push_back(VK_EXT_INLINE_UNIFORM_BLOCK_EXTENSION_NAME); VulkanGraphicsTest::Prepare(argc, argv); + + 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() @@ -547,8 +592,18 @@ float4 main() : SV_Target0 if(!Init()) return 3; + VkDescriptorType descType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + uint32_t descCount = 1; + + if(hasExt(VK_EXT_INLINE_UNIFORM_BLOCK_EXTENSION_NAME)) + { + descType = VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT; + descCount = 16 * sizeof(float); + } + VkDescriptorSetLayout setlayout = createDescriptorSetLayout(vkh::DescriptorSetLayoutCreateInfo({ {0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, + {1, descType, descCount, VK_SHADER_STAGE_FRAGMENT_BIT}, })); VkPipelineLayout layout = createPipelineLayout(vkh::PipelineLayoutCreateInfo({setlayout})); @@ -642,6 +697,31 @@ float4 main() : SV_Target0 cb.upload(cbufferdata); + InlineData inlinedata = {}; + + inlinedata.inline_a[0] = 10.0f; + inlinedata.inline_a[1] = 20.0f; + inlinedata.inline_a[2] = 30.0f; + inlinedata.inline_a[3] = 40.0f; + + inlinedata.inline_b[0] = 50.0f; + inlinedata.inline_b[1] = 60.0f; + + inlinedata.inline_c[0] = 70.0f; + inlinedata.inline_c[1] = 80.0f; + + inlinedata.inline_d.a[0] = 90.0f; + inlinedata.inline_d.a[1] = 100.0f; + inlinedata.inline_d.a[2] = 110.0f; + inlinedata.inline_d.b = 120.0f; + + AllocatedBuffer inlinecb( + this, vkh::BufferCreateInfo(sizeof(data), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | + VK_BUFFER_USAGE_TRANSFER_DST_BIT), + VmaAllocationCreateInfo({0, VMA_MEMORY_USAGE_CPU_TO_GPU})); + + inlinecb.upload(&inlinedata, sizeof(inlinedata)); + VkDescriptorSet descset = allocateDescriptorSet(setlayout); vkh::updateDescriptorSets( @@ -651,6 +731,30 @@ float4 main() : SV_Target0 {vkh::DescriptorBufferInfo(cb.buffer, bindOffset * sizeof(Vec4f))}), }); + 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, VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT, + {vkh::DescriptorBufferInfo(cb.buffer, bindOffset * sizeof(Vec4f))}) + .next(&inlineUpdate), + }); + } + else + { + vkh::updateDescriptorSets( + device, { + vkh::WriteDescriptorSet( + descset, 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + {vkh::DescriptorBufferInfo(cb.buffer, bindOffset * sizeof(Vec4f))}), + }); + } + while(Running()) { VkCommandBuffer cmd = GetCommandBuffer(); diff --git a/util/test/demos/vk/vk_helpers.h b/util/test/demos/vk/vk_helpers.h index 5b84315aa..6bb710e41 100644 --- a/util/test/demos/vk/vk_helpers.h +++ b/util/test/demos/vk/vk_helpers.h @@ -956,6 +956,12 @@ struct WriteDescriptorSet : public VkWriteDescriptorSet { } + WriteDescriptorSet &next(const void *next) + { + this->pNext = next; + return *this; + } + operator const VkWriteDescriptorSet *() const { return this; } }; diff --git a/util/test/demos/vk/vk_test.cpp b/util/test/demos/vk/vk_test.cpp index 730f870c1..5cbbe59d1 100644 --- a/util/test/demos/vk/vk_test.cpp +++ b/util/test/demos/vk/vk_test.cpp @@ -1415,6 +1415,11 @@ void VulkanGraphicsTest::getPhysProperties2(void *nextStruct) } } +bool VulkanGraphicsTest::hasExt(const char *ext) +{ + return std::find(devExts.begin(), devExts.end(), ext) != devExts.end(); +} + template <> VkFormat vkh::_FormatFromObj() { diff --git a/util/test/demos/vk/vk_test.h b/util/test/demos/vk/vk_test.h index 74b17e033..08ef44755 100644 --- a/util/test/demos/vk/vk_test.h +++ b/util/test/demos/vk/vk_test.h @@ -252,6 +252,8 @@ struct VulkanGraphicsTest : public GraphicsTest // optional extensions, will be added to devExts if supported (allows fallback paths) std::vector optDevExts; + bool hasExt(const char *ext); + // a custom struct to pass to vkDeviceCreateInfo::pNext const void *devInfoNext = NULL; diff --git a/util/test/tests/Vulkan/VK_CBuffer_Zoo.py b/util/test/tests/Vulkan/VK_CBuffer_Zoo.py index b8e9fcc48..264974c6f 100644 --- a/util/test/tests/Vulkan/VK_CBuffer_Zoo.py +++ b/util/test/tests/Vulkan/VK_CBuffer_Zoo.py @@ -36,17 +36,29 @@ class VK_CBuffer_Zoo(rdtest.TestCase): rdtest.log.success("GLSL CBuffer variables are as expected") + cbuf: rd.BoundCBuffer = pipe.GetConstantBuffer(stage, 1, 0) + + inline_check = rdtest.ConstantBufferChecker( + self.controller.GetCBufferVariableContents(pipe.GetGraphicsPipelineObject(), + pipe.GetShader(stage), + pipe.GetShaderEntryPoint(stage), 1, + cbuf.resourceId, cbuf.byteOffset, cbuf.byteSize)) + + self.check_inline_cbuffer(inline_check) + + rdtest.log.success("GLSL Inline uniform variables are as expected") + self.check_pixel_value(pipe.GetOutputTargets()[0].resourceId, 0.5, 0.5, [536.1, 537.0, 538.0, 539.0]) rdtest.log.success("GLSL picked value is as expected") # Check the specialization constants - cbuf: rd.BoundCBuffer = pipe.GetConstantBuffer(stage, 1, 0) + cbuf: rd.BoundCBuffer = pipe.GetConstantBuffer(stage, 2, 0) var_check = rdtest.ConstantBufferChecker( self.controller.GetCBufferVariableContents(pipe.GetGraphicsPipelineObject(), pipe.GetShader(stage), - pipe.GetShaderEntryPoint(stage), 1, + pipe.GetShaderEntryPoint(stage), 2, cbuf.resourceId, cbuf.byteOffset, cbuf.byteSize)) # int A; @@ -92,10 +104,43 @@ class VK_CBuffer_Zoo(rdtest.TestCase): rdtest.log.success("HLSL CBuffer variables are as expected") + cbuf: rd.BoundCBuffer = pipe.GetConstantBuffer(stage, 1, 0) + + inline_check = rdtest.ConstantBufferChecker( + self.controller.GetCBufferVariableContents(pipe.GetGraphicsPipelineObject(), + pipe.GetShader(stage), + pipe.GetShaderEntryPoint(stage), 1, + cbuf.resourceId, cbuf.byteOffset, cbuf.byteSize)) + + self.check_inline_cbuffer(inline_check) + + rdtest.log.success("HLSL Inline uniform variables are as expected") + self.check_pixel_value(pipe.GetOutputTargets()[0].resourceId, 0.5, 0.5, [536.1, 537.0, 538.0, 539.0]) rdtest.log.success("HLSL picked value is as expected") + def check_inline_cbuffer(self, inline_check): + # float4 zero; + inline_check.check('inline_zero').rows(1).cols(4).value([0.0, 0.0, 0.0, 0.0]) + + # float4 a; + inline_check.check('inline_a').rows(1).cols(4).value([10.0, 20.0, 30.0, 40.0]) + + # float2 b; + inline_check.check('inline_b').rows(1).cols(2).value([50.0, 60.0]) + + # float2 c; + inline_check.check('inline_c').rows(1).cols(2).value([70.0, 80.0]) + + # float3_1 d; + inline_check.check('inline_d').rows(0).cols(0).structSize(2).members({ + 'a': lambda y: y.rows(1).cols(3).value([90.0, 100.0, 110.0]), + 'b': lambda y: y.rows(1).cols(1).value([120.0]), + }) + + inline_check.done() + def check_glsl_cbuffer(self, var_check): # For more detailed reference for the below checks, see the commented definition of the cbuffer # in the shader source code in the demo itself