1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2019 The Khronos Group Inc.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Ray Tracing Build Large Shader Set tests
22  *//*--------------------------------------------------------------------*/
23 
24 #include "vktRayTracingBuildIndirectTests.hpp"
25 
26 #include "vkDefs.hpp"
27 
28 #include "vktTestCase.hpp"
29 #include "vkCmdUtil.hpp"
30 #include "vkObjUtil.hpp"
31 #include "vkBuilderUtil.hpp"
32 #include "vkBarrierUtil.hpp"
33 #include "vkBufferWithMemory.hpp"
34 #include "vkImageWithMemory.hpp"
35 #include "vkTypeUtil.hpp"
36 
37 #include "vkRayTracingUtil.hpp"
38 
39 namespace vkt
40 {
41 namespace RayTracing
42 {
43 namespace
44 {
45 using namespace vk;
46 using namespace std;
47 
48 static const VkFlags ALL_RAY_TRACING_STAGES = VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR |
49                                               VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR |
50                                               VK_SHADER_STAGE_INTERSECTION_BIT_KHR | VK_SHADER_STAGE_CALLABLE_BIT_KHR;
51 
52 struct CaseDef
53 {
54     uint32_t width;
55     uint32_t height;
56     uint32_t depth;
57     uint32_t squaresGroupCount;
58     uint32_t geometriesGroupCount;
59     uint32_t instancesGroupCount;
60 };
61 
62 enum ShaderGroups
63 {
64     FIRST_GROUP  = 0,
65     RAYGEN_GROUP = FIRST_GROUP,
66     MISS_GROUP,
67     HIT_GROUP,
68     GROUP_COUNT
69 };
70 
71 const uint32_t HIT              = 1;
72 const uint32_t MISS             = 2;
73 const uint32_t HIT_MISS_PATTERN = 7;
74 
getShaderGroupSize(const InstanceInterface & vki,const VkPhysicalDevice physicalDevice)75 uint32_t getShaderGroupSize(const InstanceInterface &vki, const VkPhysicalDevice physicalDevice)
76 {
77     de::MovePtr<RayTracingProperties> rayTracingPropertiesKHR;
78 
79     rayTracingPropertiesKHR = makeRayTracingProperties(vki, physicalDevice);
80 
81     return rayTracingPropertiesKHR->getShaderGroupHandleSize();
82 }
83 
getShaderGroupBaseAlignment(const InstanceInterface & vki,const VkPhysicalDevice physicalDevice)84 uint32_t getShaderGroupBaseAlignment(const InstanceInterface &vki, const VkPhysicalDevice physicalDevice)
85 {
86     de::MovePtr<RayTracingProperties> rayTracingPropertiesKHR;
87 
88     rayTracingPropertiesKHR = makeRayTracingProperties(vki, physicalDevice);
89 
90     return rayTracingPropertiesKHR->getShaderGroupBaseAlignment();
91 }
92 
makePipeline(const DeviceInterface & vkd,const VkDevice device,vk::BinaryCollection & collection,de::MovePtr<RayTracingPipeline> & rayTracingPipeline,VkPipelineLayout pipelineLayout,const std::string & shaderName)93 Move<VkPipeline> makePipeline(const DeviceInterface &vkd, const VkDevice device, vk::BinaryCollection &collection,
94                               de::MovePtr<RayTracingPipeline> &rayTracingPipeline, VkPipelineLayout pipelineLayout,
95                               const std::string &shaderName)
96 {
97     Move<VkShaderModule> raygenShader = createShaderModule(vkd, device, collection.get(shaderName), 0);
98 
99     rayTracingPipeline->addShader(VK_SHADER_STAGE_RAYGEN_BIT_KHR, raygenShader, 0);
100 
101     Move<VkPipeline> pipeline = rayTracingPipeline->createPipeline(vkd, device, pipelineLayout);
102 
103     return pipeline;
104 }
105 
makePipeline(const DeviceInterface & vkd,const VkDevice device,vk::BinaryCollection & collection,de::MovePtr<RayTracingPipeline> & rayTracingPipeline,VkPipelineLayout pipelineLayout,const uint32_t raygenGroup,const uint32_t missGroup,const uint32_t hitGroup)106 Move<VkPipeline> makePipeline(const DeviceInterface &vkd, const VkDevice device, vk::BinaryCollection &collection,
107                               de::MovePtr<RayTracingPipeline> &rayTracingPipeline, VkPipelineLayout pipelineLayout,
108                               const uint32_t raygenGroup, const uint32_t missGroup, const uint32_t hitGroup)
109 {
110     Move<VkShaderModule> raygenShader = createShaderModule(vkd, device, collection.get("rgen"), 0);
111     Move<VkShaderModule> hitShader    = createShaderModule(vkd, device, collection.get("chit"), 0);
112     Move<VkShaderModule> missShader   = createShaderModule(vkd, device, collection.get("miss"), 0);
113 
114     rayTracingPipeline->addShader(VK_SHADER_STAGE_RAYGEN_BIT_KHR, raygenShader, raygenGroup);
115     rayTracingPipeline->addShader(VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR, hitShader, hitGroup);
116     rayTracingPipeline->addShader(VK_SHADER_STAGE_MISS_BIT_KHR, missShader, missGroup);
117 
118     Move<VkPipeline> pipeline = rayTracingPipeline->createPipeline(vkd, device, pipelineLayout);
119 
120     return pipeline;
121 }
122 
makeImageCreateInfo(uint32_t width,uint32_t height,uint32_t depth,VkFormat format)123 VkImageCreateInfo makeImageCreateInfo(uint32_t width, uint32_t height, uint32_t depth, VkFormat format)
124 {
125     const VkImageUsageFlags usage =
126         VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
127     const VkImageCreateInfo imageCreateInfo = {
128         VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
129         DE_NULL,                             // const void* pNext;
130         (VkImageCreateFlags)0u,              // VkImageCreateFlags flags;
131         VK_IMAGE_TYPE_3D,                    // VkImageType imageType;
132         format,                              // VkFormat format;
133         makeExtent3D(width, height, depth),  // VkExtent3D extent;
134         1u,                                  // uint32_t mipLevels;
135         1u,                                  // uint32_t arrayLayers;
136         VK_SAMPLE_COUNT_1_BIT,               // VkSampleCountFlagBits samples;
137         VK_IMAGE_TILING_OPTIMAL,             // VkImageTiling tiling;
138         usage,                               // VkImageUsageFlags usage;
139         VK_SHARING_MODE_EXCLUSIVE,           // VkSharingMode sharingMode;
140         0u,                                  // uint32_t queueFamilyIndexCount;
141         DE_NULL,                             // const uint32_t* pQueueFamilyIndices;
142         VK_IMAGE_LAYOUT_UNDEFINED            // VkImageLayout initialLayout;
143     };
144 
145     return imageCreateInfo;
146 }
147 
148 class RayTracingBuildIndirectTestInstance : public TestInstance
149 {
150 public:
151     RayTracingBuildIndirectTestInstance(Context &context, const CaseDef &data);
152     ~RayTracingBuildIndirectTestInstance(void);
153     tcu::TestStatus iterate(void);
154 
155 protected:
156     void checkSupportInInstance(void) const;
157     de::MovePtr<BufferWithMemory> prepareBuffer(VkDeviceSize bufferSizeBytes, const std::string &shaderName);
158     de::MovePtr<BufferWithMemory> runTest(const VkBuffer indirectBottomAccelerationStructure,
159                                           const VkBuffer indirectTopAccelerationStructure);
160     de::SharedPtr<TopLevelAccelerationStructure> initTopAccelerationStructure(
161         VkCommandBuffer cmdBuffer, de::SharedPtr<BottomLevelAccelerationStructure> &bottomLevelAccelerationStructure,
162         const VkBuffer indirectBuffer, const VkDeviceSize indirectBufferOffset, const uint32_t indirectBufferStride);
163     de::SharedPtr<BottomLevelAccelerationStructure> initBottomAccelerationStructure(
164         VkCommandBuffer cmdBuffer, const VkBuffer indirectBuffer, const VkDeviceSize indirectBufferOffset,
165         const uint32_t indirectBufferStride);
166     VkBuffer initIndirectTopAccelerationStructure(void);
167     VkBuffer initIndirectBottomAccelerationStructure(void);
168 
169 private:
170     CaseDef m_data;
171     de::MovePtr<BufferWithMemory> m_indirectAccelerationStructureBottom;
172     de::MovePtr<BufferWithMemory> m_indirectAccelerationStructureTop;
173 };
174 
RayTracingBuildIndirectTestInstance(Context & context,const CaseDef & data)175 RayTracingBuildIndirectTestInstance::RayTracingBuildIndirectTestInstance(Context &context, const CaseDef &data)
176     : vkt::TestInstance(context)
177     , m_data(data)
178     , m_indirectAccelerationStructureBottom()
179     , m_indirectAccelerationStructureTop()
180 {
181 }
182 
~RayTracingBuildIndirectTestInstance(void)183 RayTracingBuildIndirectTestInstance::~RayTracingBuildIndirectTestInstance(void)
184 {
185 }
186 
187 class RayTracingTestCase : public TestCase
188 {
189 public:
190     RayTracingTestCase(tcu::TestContext &context, const char *name, const CaseDef data);
191     ~RayTracingTestCase(void);
192 
193     virtual void initPrograms(SourceCollections &programCollection) const;
194     virtual TestInstance *createInstance(Context &context) const;
195     virtual void checkSupport(Context &context) const;
196 
197 private:
198     CaseDef m_data;
199 };
200 
RayTracingTestCase(tcu::TestContext & context,const char * name,const CaseDef data)201 RayTracingTestCase::RayTracingTestCase(tcu::TestContext &context, const char *name, const CaseDef data)
202     : vkt::TestCase(context, name)
203     , m_data(data)
204 {
205     DE_ASSERT((m_data.width * m_data.height * m_data.depth) ==
206               (m_data.squaresGroupCount * m_data.geometriesGroupCount * m_data.instancesGroupCount));
207 }
208 
~RayTracingTestCase(void)209 RayTracingTestCase::~RayTracingTestCase(void)
210 {
211 }
212 
checkSupport(Context & context) const213 void RayTracingTestCase::checkSupport(Context &context) const
214 {
215     const VkPhysicalDeviceAccelerationStructureFeaturesKHR &accelerationStructureFeaturesKHR =
216         context.getAccelerationStructureFeatures();
217     if (accelerationStructureFeaturesKHR.accelerationStructure == false)
218         TCU_THROW(NotSupportedError, "Requires VkPhysicalDeviceAccelerationStructureFeaturesKHR.accelerationStructure");
219 
220     const VkPhysicalDeviceRayTracingPipelineFeaturesKHR &rayTracingPipelineFeaturesKHR =
221         context.getRayTracingPipelineFeatures();
222     if (rayTracingPipelineFeaturesKHR.rayTracingPipeline == false)
223         TCU_THROW(NotSupportedError, "Requires VkPhysicalDeviceRayTracingPipelineFeaturesKHR.rayTracingPipeline");
224 
225     if (accelerationStructureFeaturesKHR.accelerationStructureIndirectBuild == false)
226         TCU_THROW(NotSupportedError,
227                   "Requires VkPhysicalDeviceAccelerationStructureFeaturesKHR.accelerationStructureIndirectBuild");
228 }
229 
initPrograms(SourceCollections & programCollection) const230 void RayTracingTestCase::initPrograms(SourceCollections &programCollection) const
231 {
232     const vk::ShaderBuildOptions buildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_4, 0u, true);
233     {
234         std::stringstream css;
235         css << "#version 460 core\n"
236                "#extension GL_EXT_ray_tracing : require\n"
237                "layout(set = 0, binding = 0, std140) writeonly buffer OutBuf\n"
238                "{\n"
239                "  uvec4 accelerationStructureBuildOffsetInfoKHR["
240             << m_data.depth
241             << "];\n"
242                "} b_out;\n"
243                "\n"
244                "void main()\n"
245                "{\n"
246                "  for (uint i = 0; i < "
247             << m_data.depth
248             << "; i++)\n"
249                "  {\n"
250                "    uint primitiveCount  = "
251             << m_data.width * m_data.height
252             << "u;\n"
253                "    uint primitiveOffset = "
254             << m_data.width * m_data.height * 3u * sizeof(tcu::Vec3)
255             << "u * i;\n"
256                "    uint firstVertex     = "
257             << 0
258             << "u;\n"
259                "    uint transformOffset = "
260             << 0
261             << "u;\n"
262                "\n"
263                "    b_out.accelerationStructureBuildOffsetInfoKHR[i] = uvec4(primitiveCount, primitiveOffset, "
264                "firstVertex, transformOffset);\n"
265                "  }\n"
266                "}\n";
267 
268         programCollection.glslSources.add("wr-asb")
269             << glu::RaygenSource(updateRayTracingGLSL(css.str())) << buildOptions;
270     }
271 
272     {
273         std::stringstream css;
274         css << "#version 460 core\n"
275                "#extension GL_EXT_ray_tracing : require\n"
276                "layout(set = 0, binding = 0, std140) writeonly buffer OutBuf\n"
277                "{\n"
278                "  uvec4 accelerationStructureBuildOffsetInfoKHR;\n"
279                "} b_out;\n"
280                "\n"
281                "void main()\n"
282                "{\n"
283                "  uint primitiveCount  = "
284             << m_data.instancesGroupCount
285             << "u;\n"
286                "  uint primitiveOffset = "
287             << 0
288             << "u;\n"
289                "  uint firstVertex     = "
290             << 0
291             << "u;\n"
292                "  uint transformOffset = "
293             << 0
294             << "u;\n"
295                "\n"
296                "  b_out.accelerationStructureBuildOffsetInfoKHR = uvec4(primitiveCount, primitiveOffset, firstVertex, "
297                "transformOffset);\n"
298                "}\n";
299 
300         programCollection.glslSources.add("wr-ast")
301             << glu::RaygenSource(updateRayTracingGLSL(css.str())) << buildOptions;
302     }
303 
304     {
305         std::stringstream css;
306         css << "#version 460 core\n"
307                "#extension GL_EXT_ray_tracing : require\n"
308                "layout(location = 0) rayPayloadEXT vec3 hitValue;\n"
309                "layout(set = 0, binding = 1) uniform accelerationStructureEXT topLevelAS;\n"
310                "\n"
311                "void main()\n"
312                "{\n"
313                "  uint  rayFlags = 0;\n"
314                "  uint  cullMask = 0xFF;\n"
315                "  float tmin     = 0.0;\n"
316                "  float tmax     = 9.0;\n"
317                "  float x        = (float(gl_LaunchIDEXT.x) + 0.5f) / float(gl_LaunchSizeEXT.x);\n"
318                "  float y        = (float(gl_LaunchIDEXT.y) + 0.5f) / float(gl_LaunchSizeEXT.y);\n"
319                "  float z        = (float(gl_LaunchIDEXT.z) + 0.5f) / float(gl_LaunchSizeEXT.z);\n"
320                "  vec3  origin   = vec3(x, y, z);\n"
321                "  vec3  direct   = vec3(0.0, 0.0, -1.0);\n"
322                "  traceRayEXT(topLevelAS, rayFlags, cullMask, 0, 0, 0, origin, tmin, direct, tmax, 0);\n"
323                "}\n";
324 
325         programCollection.glslSources.add("rgen") << glu::RaygenSource(updateRayTracingGLSL(css.str())) << buildOptions;
326     }
327 
328     {
329         std::stringstream css;
330         css << "#version 460 core\n"
331                "#extension GL_EXT_ray_tracing : require\n"
332                "layout(location = 0) rayPayloadInEXT vec3 hitValue;\n"
333                "hitAttributeEXT vec3 attribs;\n"
334                "layout(set = 0, binding = 0, r32ui) uniform uimage3D result;\n"
335                "void main()\n"
336                "{\n"
337                "  uvec4 color = uvec4("
338             << HIT
339             << ",0,0,1);\n"
340                "  imageStore(result, ivec3(gl_LaunchIDEXT.xyz), color);\n"
341                "}\n";
342 
343         programCollection.glslSources.add("chit")
344             << glu::ClosestHitSource(updateRayTracingGLSL(css.str())) << buildOptions;
345     }
346 
347     {
348         std::stringstream css;
349         css << "#version 460 core\n"
350                "#extension GL_EXT_ray_tracing : require\n"
351                "layout(location = 0) rayPayloadInEXT vec3 unusedPayload;\n"
352                "layout(set = 0, binding = 0, r32ui) uniform uimage3D result;\n"
353                "void main()\n"
354                "{\n"
355                "  uvec4 color = uvec4("
356             << MISS
357             << ",0,0,1);\n"
358                "  imageStore(result, ivec3(gl_LaunchIDEXT.xyz), color);\n"
359                "}\n";
360 
361         programCollection.glslSources.add("miss") << glu::MissSource(updateRayTracingGLSL(css.str())) << buildOptions;
362     }
363 }
364 
createInstance(Context & context) const365 TestInstance *RayTracingTestCase::createInstance(Context &context) const
366 {
367     return new RayTracingBuildIndirectTestInstance(context, m_data);
368 }
369 
initTopAccelerationStructure(VkCommandBuffer cmdBuffer,de::SharedPtr<BottomLevelAccelerationStructure> & bottomLevelAccelerationStructure,const VkBuffer indirectBuffer,const VkDeviceSize indirectBufferOffset,const uint32_t indirectBufferStride)370 de::SharedPtr<TopLevelAccelerationStructure> RayTracingBuildIndirectTestInstance::initTopAccelerationStructure(
371     VkCommandBuffer cmdBuffer, de::SharedPtr<BottomLevelAccelerationStructure> &bottomLevelAccelerationStructure,
372     const VkBuffer indirectBuffer, const VkDeviceSize indirectBufferOffset, const uint32_t indirectBufferStride)
373 {
374     const DeviceInterface &vkd                        = m_context.getDeviceInterface();
375     const VkDevice device                             = m_context.getDevice();
376     Allocator &allocator                              = m_context.getDefaultAllocator();
377     de::MovePtr<TopLevelAccelerationStructure> result = makeTopLevelAccelerationStructure();
378 
379     result->setInstanceCount(1);
380     result->addInstance(bottomLevelAccelerationStructure);
381     result->setIndirectBuildParameters(indirectBuffer, indirectBufferOffset, indirectBufferStride);
382 
383     result->createAndBuild(vkd, device, cmdBuffer, allocator);
384 
385     return de::SharedPtr<TopLevelAccelerationStructure>(result.release());
386 }
387 
initBottomAccelerationStructure(VkCommandBuffer cmdBuffer,const VkBuffer indirectBuffer,const VkDeviceSize indirectBufferOffset,const uint32_t indirectBufferStride)388 de::SharedPtr<BottomLevelAccelerationStructure> RayTracingBuildIndirectTestInstance::initBottomAccelerationStructure(
389     VkCommandBuffer cmdBuffer, const VkBuffer indirectBuffer, const VkDeviceSize indirectBufferOffset,
390     const uint32_t indirectBufferStride)
391 {
392     const DeviceInterface &vkd                           = m_context.getDeviceInterface();
393     const VkDevice device                                = m_context.getDevice();
394     Allocator &allocator                                 = m_context.getDefaultAllocator();
395     de::MovePtr<BottomLevelAccelerationStructure> result = makeBottomLevelAccelerationStructure();
396 
397     result->setGeometryCount(m_data.geometriesGroupCount);
398     result->setIndirectBuildParameters(indirectBuffer, indirectBufferOffset, indirectBufferStride);
399 
400     for (size_t geometryNdx = 0; geometryNdx < m_data.geometriesGroupCount; ++geometryNdx)
401     {
402         std::vector<tcu::Vec3> geometryData;
403 
404         geometryData.reserve(m_data.squaresGroupCount * 3u);
405 
406         tcu::UVec2 startPos = tcu::UVec2(0u, 0u);
407 
408         for (size_t squareNdx = 0; squareNdx < m_data.squaresGroupCount; ++squareNdx)
409         {
410             const uint32_t n = m_data.width * startPos.y() + startPos.x();
411             const float x0   = float(startPos.x() + 0) / float(m_data.width);
412             const float y0   = float(startPos.y() + 0) / float(m_data.height);
413             const float x1   = float(startPos.x() + 1) / float(m_data.width);
414             const float y1   = float(startPos.y() + 1) / float(m_data.height);
415             const float xm   = (x0 + x1) / 2.0f;
416             const float ym   = (y0 + y1) / 2.0f;
417             const float z =
418                 (n % HIT_MISS_PATTERN == 0) ? +1.0f : (float(geometryNdx) + 0.25f) / float(m_data.geometriesGroupCount);
419 
420             geometryData.push_back(tcu::Vec3(x0, y0, z));
421             geometryData.push_back(tcu::Vec3(xm, y1, z));
422             geometryData.push_back(tcu::Vec3(x1, ym, z));
423 
424             startPos.y() = (n + 1) / m_data.width;
425             startPos.x() = (n + 1) % m_data.width;
426         }
427 
428         result->addGeometry(geometryData, true);
429     }
430 
431     result->createAndBuild(vkd, device, cmdBuffer, allocator);
432 
433     return de::SharedPtr<BottomLevelAccelerationStructure>(result.release());
434 }
435 
prepareBuffer(VkDeviceSize bufferSizeBytes,const std::string & shaderName)436 de::MovePtr<BufferWithMemory> RayTracingBuildIndirectTestInstance::prepareBuffer(VkDeviceSize bufferSizeBytes,
437                                                                                  const std::string &shaderName)
438 {
439     const InstanceInterface &vki            = m_context.getInstanceInterface();
440     const DeviceInterface &vkd              = m_context.getDeviceInterface();
441     const VkDevice device                   = m_context.getDevice();
442     const VkPhysicalDevice physicalDevice   = m_context.getPhysicalDevice();
443     const uint32_t queueFamilyIndex         = m_context.getUniversalQueueFamilyIndex();
444     const VkQueue queue                     = m_context.getUniversalQueue();
445     Allocator &allocator                    = m_context.getDefaultAllocator();
446     const uint32_t shaderGroupHandleSize    = getShaderGroupSize(vki, physicalDevice);
447     const uint32_t shaderGroupBaseAlignment = getShaderGroupBaseAlignment(vki, physicalDevice);
448 
449     const VkBufferCreateInfo bufferCreateInfo = makeBufferCreateInfo(
450         bufferSizeBytes, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT);
451     de::MovePtr<BufferWithMemory> buffer = de::MovePtr<BufferWithMemory>(new BufferWithMemory(
452         vkd, device, allocator, bufferCreateInfo, MemoryRequirement::HostVisible | MemoryRequirement::DeviceAddress));
453 
454     const Move<VkDescriptorSetLayout> descriptorSetLayout =
455         DescriptorSetLayoutBuilder()
456             .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, ALL_RAY_TRACING_STAGES)
457             .build(vkd, device);
458     const Move<VkDescriptorPool> descriptorPool =
459         DescriptorPoolBuilder()
460             .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
461             .build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
462     const Move<VkDescriptorSet> descriptorSet   = makeDescriptorSet(vkd, device, *descriptorPool, *descriptorSetLayout);
463     const Move<VkPipelineLayout> pipelineLayout = makePipelineLayout(vkd, device, descriptorSetLayout.get());
464     const Move<VkCommandPool> cmdPool           = createCommandPool(vkd, device, 0, queueFamilyIndex);
465     const Move<VkCommandBuffer> cmdBuffer =
466         allocateCommandBuffer(vkd, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
467 
468     const vk::VkDescriptorBufferInfo descriptorBufferInfo = makeDescriptorBufferInfo(**buffer, 0ull, bufferSizeBytes);
469 
470     de::MovePtr<RayTracingPipeline> rayTracingPipeline = de::newMovePtr<RayTracingPipeline>();
471     const Move<VkPipeline> pipeline =
472         makePipeline(vkd, device, m_context.getBinaryCollection(), rayTracingPipeline, *pipelineLayout, shaderName);
473     const de::MovePtr<BufferWithMemory> shaderBindingTable = rayTracingPipeline->createShaderBindingTable(
474         vkd, device, *pipeline, allocator, shaderGroupHandleSize, shaderGroupBaseAlignment, 0, 1);
475     const VkStridedDeviceAddressRegionKHR raygenShaderBindingTableRegion =
476         makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, shaderBindingTable->get(), 0),
477                                           shaderGroupHandleSize, shaderGroupHandleSize);
478     const VkStridedDeviceAddressRegionKHR missShaderBindingTableRegion =
479         makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0);
480     const VkStridedDeviceAddressRegionKHR hitShaderBindingTableRegion =
481         makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0);
482     const VkStridedDeviceAddressRegionKHR callableShaderBindingTableRegion =
483         makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0);
484 
485     beginCommandBuffer(vkd, *cmdBuffer, 0u);
486     {
487         DescriptorSetUpdateBuilder()
488             .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u),
489                          VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descriptorBufferInfo)
490             .update(vkd, device);
491 
492         vkd.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, *pipelineLayout, 0, 1,
493                                   &descriptorSet.get(), 0, DE_NULL);
494 
495         vkd.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, *pipeline);
496 
497         cmdTraceRays(vkd, *cmdBuffer, &raygenShaderBindingTableRegion, &missShaderBindingTableRegion,
498                      &hitShaderBindingTableRegion, &callableShaderBindingTableRegion, 1u, 1u, 1u);
499     }
500     endCommandBuffer(vkd, *cmdBuffer);
501 
502     submitCommandsAndWait(vkd, device, queue, cmdBuffer.get());
503 
504     return buffer;
505 }
506 
runTest(const VkBuffer indirectBottomAccelerationStructure,const VkBuffer indirectTopAccelerationStructure)507 de::MovePtr<BufferWithMemory> RayTracingBuildIndirectTestInstance::runTest(
508     const VkBuffer indirectBottomAccelerationStructure, const VkBuffer indirectTopAccelerationStructure)
509 {
510     const InstanceInterface &vki            = m_context.getInstanceInterface();
511     const DeviceInterface &vkd              = m_context.getDeviceInterface();
512     const VkDevice device                   = m_context.getDevice();
513     const VkPhysicalDevice physicalDevice   = m_context.getPhysicalDevice();
514     const uint32_t queueFamilyIndex         = m_context.getUniversalQueueFamilyIndex();
515     const VkQueue queue                     = m_context.getUniversalQueue();
516     Allocator &allocator                    = m_context.getDefaultAllocator();
517     const VkFormat format                   = VK_FORMAT_R32_UINT;
518     const uint32_t pixelCount               = m_data.width * m_data.height * m_data.depth;
519     const uint32_t shaderGroupHandleSize    = getShaderGroupSize(vki, physicalDevice);
520     const uint32_t shaderGroupBaseAlignment = getShaderGroupBaseAlignment(vki, physicalDevice);
521 
522     const Move<VkDescriptorSetLayout> descriptorSetLayout =
523         DescriptorSetLayoutBuilder()
524             .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, ALL_RAY_TRACING_STAGES)
525             .addSingleBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, ALL_RAY_TRACING_STAGES)
526             .build(vkd, device);
527     const Move<VkDescriptorPool> descriptorPool =
528         DescriptorPoolBuilder()
529             .addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE)
530             .addType(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR)
531             .build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
532     const Move<VkDescriptorSet> descriptorSet   = makeDescriptorSet(vkd, device, *descriptorPool, *descriptorSetLayout);
533     const Move<VkPipelineLayout> pipelineLayout = makePipelineLayout(vkd, device, descriptorSetLayout.get());
534     const Move<VkCommandPool> cmdPool           = createCommandPool(vkd, device, 0, queueFamilyIndex);
535     const Move<VkCommandBuffer> cmdBuffer =
536         allocateCommandBuffer(vkd, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
537 
538     de::MovePtr<RayTracingPipeline> rayTracingPipeline = de::newMovePtr<RayTracingPipeline>();
539     const Move<VkPipeline> pipeline = makePipeline(vkd, device, m_context.getBinaryCollection(), rayTracingPipeline,
540                                                    *pipelineLayout, RAYGEN_GROUP, MISS_GROUP, HIT_GROUP);
541     const de::MovePtr<BufferWithMemory> raygenShaderBindingTable = rayTracingPipeline->createShaderBindingTable(
542         vkd, device, *pipeline, allocator, shaderGroupHandleSize, shaderGroupBaseAlignment, RAYGEN_GROUP, 1u);
543     const de::MovePtr<BufferWithMemory> missShaderBindingTable = rayTracingPipeline->createShaderBindingTable(
544         vkd, device, *pipeline, allocator, shaderGroupHandleSize, shaderGroupBaseAlignment, MISS_GROUP, 1u);
545     const de::MovePtr<BufferWithMemory> hitShaderBindingTable = rayTracingPipeline->createShaderBindingTable(
546         vkd, device, *pipeline, allocator, shaderGroupHandleSize, shaderGroupBaseAlignment, HIT_GROUP, 1u);
547     const VkStridedDeviceAddressRegionKHR raygenShaderBindingTableRegion =
548         makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, raygenShaderBindingTable->get(), 0),
549                                           shaderGroupHandleSize, shaderGroupHandleSize);
550     const VkStridedDeviceAddressRegionKHR missShaderBindingTableRegion =
551         makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, missShaderBindingTable->get(), 0),
552                                           shaderGroupHandleSize, shaderGroupHandleSize);
553     const VkStridedDeviceAddressRegionKHR hitShaderBindingTableRegion =
554         makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, hitShaderBindingTable->get(), 0),
555                                           shaderGroupHandleSize, shaderGroupHandleSize);
556     const VkStridedDeviceAddressRegionKHR callableShaderBindingTableRegion =
557         makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0);
558 
559     const VkImageCreateInfo imageCreateInfo = makeImageCreateInfo(m_data.width, m_data.height, m_data.depth, format);
560     const VkImageSubresourceRange imageSubresourceRange =
561         makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0, 1u);
562     const de::MovePtr<ImageWithMemory> image = de::MovePtr<ImageWithMemory>(
563         new ImageWithMemory(vkd, device, allocator, imageCreateInfo, MemoryRequirement::Any));
564     const Move<VkImageView> imageView =
565         makeImageView(vkd, device, **image, VK_IMAGE_VIEW_TYPE_3D, format, imageSubresourceRange);
566 
567     const VkBufferCreateInfo bufferCreateInfo =
568         makeBufferCreateInfo(pixelCount * sizeof(uint32_t), VK_BUFFER_USAGE_TRANSFER_DST_BIT);
569     const VkImageSubresourceLayers bufferImageSubresourceLayers =
570         makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u);
571     const VkBufferImageCopy bufferImageRegion =
572         makeBufferImageCopy(makeExtent3D(m_data.width, m_data.height, m_data.depth), bufferImageSubresourceLayers);
573     de::MovePtr<BufferWithMemory> buffer = de::MovePtr<BufferWithMemory>(
574         new BufferWithMemory(vkd, device, allocator, bufferCreateInfo, MemoryRequirement::HostVisible));
575 
576     const VkDescriptorImageInfo descriptorImageInfo =
577         makeDescriptorImageInfo(DE_NULL, *imageView, VK_IMAGE_LAYOUT_GENERAL);
578 
579     const VkImageMemoryBarrier preImageBarrier =
580         makeImageMemoryBarrier(0u, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
581                                VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, **image, imageSubresourceRange);
582     const VkImageMemoryBarrier postImageBarrier = makeImageMemoryBarrier(
583         VK_ACCESS_TRANSFER_WRITE_BIT,
584         VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR | VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR,
585         VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL, **image, imageSubresourceRange);
586     const VkMemoryBarrier postTraceMemoryBarrier =
587         makeMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT);
588     const VkMemoryBarrier postCopyMemoryBarrier =
589         makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
590     const VkClearValue clearValue                      = makeClearValueColorU32(5u, 5u, 5u, 255u);
591     const uint32_t indirectAccelerationStructureStride = sizeof(VkAccelerationStructureBuildRangeInfoKHR);
592 
593     de::SharedPtr<BottomLevelAccelerationStructure> bottomLevelAccelerationStructure;
594     de::SharedPtr<TopLevelAccelerationStructure> topLevelAccelerationStructure;
595 
596     beginCommandBuffer(vkd, *cmdBuffer, 0u);
597     {
598         cmdPipelineImageMemoryBarrier(vkd, *cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
599                                       VK_PIPELINE_STAGE_TRANSFER_BIT, &preImageBarrier);
600         vkd.cmdClearColorImage(*cmdBuffer, **image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clearValue.color, 1,
601                                &imageSubresourceRange);
602         cmdPipelineImageMemoryBarrier(vkd, *cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT,
603                                       VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR, &postImageBarrier);
604 
605         bottomLevelAccelerationStructure = initBottomAccelerationStructure(
606             *cmdBuffer, indirectBottomAccelerationStructure, 0, indirectAccelerationStructureStride);
607         topLevelAccelerationStructure =
608             initTopAccelerationStructure(*cmdBuffer, bottomLevelAccelerationStructure, indirectTopAccelerationStructure,
609                                          0, indirectAccelerationStructureStride);
610 
611         const TopLevelAccelerationStructure *topLevelAccelerationStructurePtr = topLevelAccelerationStructure.get();
612         VkWriteDescriptorSetAccelerationStructureKHR accelerationStructureWriteDescriptorSet = {
613             VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR, //  VkStructureType sType;
614             DE_NULL,                                                           //  const void* pNext;
615             1u,                                                                //  uint32_t accelerationStructureCount;
616             topLevelAccelerationStructurePtr->getPtr(), //  const VkAccelerationStructureKHR* pAccelerationStructures;
617         };
618 
619         DescriptorSetUpdateBuilder()
620             .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u),
621                          VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &descriptorImageInfo)
622             .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u),
623                          VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, &accelerationStructureWriteDescriptorSet)
624             .update(vkd, device);
625 
626         vkd.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, *pipelineLayout, 0, 1,
627                                   &descriptorSet.get(), 0, DE_NULL);
628 
629         vkd.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, *pipeline);
630 
631         cmdTraceRays(vkd, *cmdBuffer, &raygenShaderBindingTableRegion, &missShaderBindingTableRegion,
632                      &hitShaderBindingTableRegion, &callableShaderBindingTableRegion, m_data.width, m_data.height,
633                      m_data.depth);
634 
635         cmdPipelineMemoryBarrier(vkd, *cmdBuffer, VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR,
636                                  VK_PIPELINE_STAGE_TRANSFER_BIT, &postTraceMemoryBarrier);
637 
638         vkd.cmdCopyImageToBuffer(*cmdBuffer, **image, VK_IMAGE_LAYOUT_GENERAL, **buffer, 1u, &bufferImageRegion);
639 
640         cmdPipelineMemoryBarrier(vkd, *cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT,
641                                  &postCopyMemoryBarrier);
642     }
643     endCommandBuffer(vkd, *cmdBuffer);
644 
645     submitCommandsAndWait(vkd, device, queue, cmdBuffer.get());
646 
647     invalidateMappedMemoryRange(vkd, device, buffer->getAllocation().getMemory(), buffer->getAllocation().getOffset(),
648                                 pixelCount * sizeof(uint32_t));
649 
650     return buffer;
651 }
652 
checkSupportInInstance(void) const653 void RayTracingBuildIndirectTestInstance::checkSupportInInstance(void) const
654 {
655     const InstanceInterface &vki                           = m_context.getInstanceInterface();
656     const VkPhysicalDevice physicalDevice                  = m_context.getPhysicalDevice();
657     de::MovePtr<RayTracingProperties> rayTracingProperties = makeRayTracingProperties(vki, physicalDevice);
658 
659     if (rayTracingProperties->getMaxPrimitiveCount() < m_data.squaresGroupCount)
660         TCU_THROW(NotSupportedError, "Triangles required more than supported");
661 
662     if (rayTracingProperties->getMaxGeometryCount() < m_data.geometriesGroupCount)
663         TCU_THROW(NotSupportedError, "Geometries required more than supported");
664 
665     if (rayTracingProperties->getMaxInstanceCount() < m_data.instancesGroupCount)
666         TCU_THROW(NotSupportedError, "Instances required more than supported");
667 }
668 
initIndirectTopAccelerationStructure(void)669 VkBuffer RayTracingBuildIndirectTestInstance::initIndirectTopAccelerationStructure(void)
670 {
671     VkBuffer result = DE_NULL;
672 
673     m_indirectAccelerationStructureTop = prepareBuffer(sizeof(VkAccelerationStructureBuildRangeInfoKHR), "wr-ast");
674     result                             = **m_indirectAccelerationStructureTop;
675 
676     return result;
677 }
678 
initIndirectBottomAccelerationStructure(void)679 VkBuffer RayTracingBuildIndirectTestInstance::initIndirectBottomAccelerationStructure(void)
680 {
681     VkBuffer result = DE_NULL;
682 
683     m_indirectAccelerationStructureBottom =
684         prepareBuffer(sizeof(VkAccelerationStructureBuildRangeInfoKHR) * m_data.geometriesGroupCount, "wr-asb");
685     result = **m_indirectAccelerationStructureBottom;
686 
687     return result;
688 }
689 
iterate(void)690 tcu::TestStatus RayTracingBuildIndirectTestInstance::iterate(void)
691 {
692     checkSupportInInstance();
693 
694     const VkBuffer indirectAccelerationStructureBottom = initIndirectBottomAccelerationStructure();
695     const VkBuffer indirectAccelerationStructureTop    = initIndirectTopAccelerationStructure();
696     const de::MovePtr<BufferWithMemory> buffer =
697         runTest(indirectAccelerationStructureBottom, indirectAccelerationStructureTop);
698     const uint32_t *bufferPtr = (uint32_t *)buffer->getAllocation().getHostPtr();
699     uint32_t failures         = 0;
700 
701     for (uint32_t z = 0; z < m_data.depth; ++z)
702     {
703         const uint32_t *bufferPtrLevel = &bufferPtr[z * m_data.height * m_data.width];
704 
705         for (uint32_t y = 0; y < m_data.height; ++y)
706             for (uint32_t x = 0; x < m_data.width; ++x)
707             {
708                 const uint32_t n             = m_data.width * y + x;
709                 const uint32_t expectedValue = (n % HIT_MISS_PATTERN == 0) ? MISS : HIT;
710 
711                 if (bufferPtrLevel[n] != expectedValue)
712                     failures++;
713             }
714     }
715 
716     if (failures == 0)
717         return tcu::TestStatus::pass("Pass");
718     else
719         return tcu::TestStatus::fail("failures=" + de::toString(failures));
720 }
721 
722 } // namespace
723 
createBuildIndirectTests(tcu::TestContext & testCtx)724 tcu::TestCaseGroup *createBuildIndirectTests(tcu::TestContext &testCtx)
725 {
726     // Build acceleration structure indirect ray tracing tests
727     de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "indirect"));
728 
729     const uint32_t width                = 512u;
730     const uint32_t height               = 128u;
731     const uint32_t depth                = 4u;
732     const uint32_t largestGroup         = width * height;
733     const uint32_t squaresGroupCount    = largestGroup;
734     const uint32_t geometriesGroupCount = depth;
735     const uint32_t instancesGroupCount  = 1;
736     const CaseDef caseDef               = {
737         width, height, depth, squaresGroupCount, geometriesGroupCount, instancesGroupCount,
738     };
739     const std::string testName = "build_structure";
740 
741     group->addChild(new RayTracingTestCase(testCtx, testName.c_str(), caseDef));
742 
743     return group.release();
744 }
745 
746 } // namespace RayTracing
747 } // namespace vkt
748