1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2020 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 Test procedural geometry with complex bouding box sets
22  *//*--------------------------------------------------------------------*/
23 
24 #include "vktRayTracingProceduralGeometryTests.hpp"
25 #include "vktCustomInstancesDevices.hpp"
26 #include "vkDefs.hpp"
27 #include "vktTestCase.hpp"
28 #include "vktTestGroupUtil.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 #include "vkImageUtil.hpp"
37 #include "vkRayTracingUtil.hpp"
38 #include "tcuVectorUtil.hpp"
39 #include "tcuTexture.hpp"
40 #include "tcuTestLog.hpp"
41 #include "tcuImageCompare.hpp"
42 #include "tcuCommandLine.hpp"
43 #include "tcuFloat.hpp"
44 
45 namespace vkt
46 {
47 namespace RayTracing
48 {
49 namespace
50 {
51 using namespace vk;
52 using namespace vkt;
53 
54 static const VkFlags ALL_RAY_TRACING_STAGES = VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR |
55                                               VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR |
56                                               VK_SHADER_STAGE_INTERSECTION_BIT_KHR | VK_SHADER_STAGE_CALLABLE_BIT_KHR;
57 
58 enum class TestType
59 {
60     OBJECT_BEHIND_BOUNDING_BOX = 0,
61     TRIANGLE_IN_BETWEEN
62 };
63 
64 struct DeviceHelper
65 {
66     Move<VkDevice> device;
67     de::MovePtr<DeviceDriver> vkd;
68     uint32_t queueFamilyIndex;
69     VkQueue queue;
70     de::MovePtr<SimpleAllocator> allocator;
71 
DeviceHelpervkt::RayTracing::__anon2dcffe700111::DeviceHelper72     DeviceHelper(Context &context)
73     {
74         const auto &vkp           = context.getPlatformInterface();
75         const auto &vki           = context.getInstanceInterface();
76         const auto instance       = context.getInstance();
77         const auto physicalDevice = context.getPhysicalDevice();
78 
79         queueFamilyIndex = context.getUniversalQueueFamilyIndex();
80 
81         // Get device features (these have to be checked in the test case)
82         VkPhysicalDeviceRayTracingPipelineFeaturesKHR rayTracingPipelineFeatures = initVulkanStructure();
83         VkPhysicalDeviceAccelerationStructureFeaturesKHR accelerationStructureFeatures =
84             initVulkanStructure(&rayTracingPipelineFeatures);
85         VkPhysicalDeviceBufferDeviceAddressFeaturesKHR deviceAddressFeatures =
86             initVulkanStructure(&accelerationStructureFeatures);
87         VkPhysicalDeviceFeatures2 deviceFeatures = initVulkanStructure(&deviceAddressFeatures);
88 
89         vki.getPhysicalDeviceFeatures2(physicalDevice, &deviceFeatures);
90 
91         // Make sure robust buffer access is disabled as in the default device
92         deviceFeatures.features.robustBufferAccess = VK_FALSE;
93 
94         const auto queuePriority = 1.0f;
95         const VkDeviceQueueCreateInfo queueInfo{
96             VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // VkStructureType sType;
97             nullptr,                                    // const void* pNext;
98             0u,                                         // VkDeviceQueueCreateFlags flags;
99             queueFamilyIndex,                           // uint32_t queueFamilyIndex;
100             1u,                                         // uint32_t queueCount;
101             &queuePriority,                             // const float* pQueuePriorities;
102         };
103 
104         // Required extensions - create device with VK_KHR_ray_tracing_pipeline but
105         // without VK_KHR_pipeline_library to also test that that combination works
106         std::vector<const char *> requiredExtensions{"VK_KHR_ray_tracing_pipeline",     "VK_KHR_acceleration_structure",
107                                                      "VK_KHR_deferred_host_operations", "VK_KHR_buffer_device_address",
108                                                      "VK_EXT_descriptor_indexing",      "VK_KHR_spirv_1_4",
109                                                      "VK_KHR_shader_float_controls"};
110 
111         const VkDeviceCreateInfo createInfo{
112             VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,             // VkStructureType sType;
113             deviceFeatures.pNext,                             // const void* pNext;
114             0u,                                               // VkDeviceCreateFlags flags;
115             1u,                                               // uint32_t queueCreateInfoCount;
116             &queueInfo,                                       // const VkDeviceQueueCreateInfo* pQueueCreateInfos;
117             0u,                                               // uint32_t enabledLayerCount;
118             nullptr,                                          // const char* const* ppEnabledLayerNames;
119             static_cast<uint32_t>(requiredExtensions.size()), // uint32_t enabledExtensionCount;
120             requiredExtensions.data(),                        // const char* const* ppEnabledExtensionNames;
121             &deviceFeatures.features,                         // const VkPhysicalDeviceFeatures* pEnabledFeatures;
122         };
123 
124         // Create custom device and related objects
125         device = createCustomDevice(context.getTestContext().getCommandLine().isValidationEnabled(), vkp, instance, vki,
126                                     physicalDevice, &createInfo);
127         vkd    = de::MovePtr<DeviceDriver>(new DeviceDriver(vkp, instance, device.get(), context.getUsedApiVersion(),
128                                                             context.getTestContext().getCommandLine()));
129         queue  = getDeviceQueue(*vkd, *device, queueFamilyIndex, 0u);
130         allocator = de::MovePtr<SimpleAllocator>(
131             new SimpleAllocator(*vkd, device.get(), getPhysicalDeviceMemoryProperties(vki, physicalDevice)));
132     }
133 };
134 
135 class RayTracingProceduralGeometryTestBase : public TestInstance
136 {
137 public:
138     RayTracingProceduralGeometryTestBase(Context &context);
139     ~RayTracingProceduralGeometryTestBase(void) = default;
140 
141     tcu::TestStatus iterate(void) override;
142 
143 protected:
144     virtual void setupRayTracingPipeline()     = 0;
145     virtual void setupAccelerationStructures() = 0;
146 
147 private:
148     VkWriteDescriptorSetAccelerationStructureKHR makeASWriteDescriptorSet(
149         const VkAccelerationStructureKHR *pAccelerationStructure);
150     void clearBuffer(de::SharedPtr<BufferWithMemory> buffer, VkDeviceSize bufferSize);
151 
152 protected:
153     DeviceHelper m_customDevice;
154     de::MovePtr<RayTracingPipeline> m_rayTracingPipeline;
155     Move<VkPipelineLayout> m_pipelineLayout;
156     Move<VkPipeline> m_pipeline;
157     de::MovePtr<BufferWithMemory> m_rgenShaderBT;
158     de::MovePtr<BufferWithMemory> m_chitShaderBT;
159     de::MovePtr<BufferWithMemory> m_missShaderBT;
160 
161     Move<VkDescriptorSetLayout> m_descriptorSetLayout;
162     Move<VkCommandPool> m_cmdPool;
163     Move<VkCommandBuffer> m_cmdBuffer;
164 
165     std::vector<de::SharedPtr<BottomLevelAccelerationStructure>> m_blasVect;
166     de::SharedPtr<TopLevelAccelerationStructure> m_referenceTLAS;
167     de::SharedPtr<TopLevelAccelerationStructure> m_resultTLAS;
168 };
169 
RayTracingProceduralGeometryTestBase(Context & context)170 RayTracingProceduralGeometryTestBase::RayTracingProceduralGeometryTestBase(Context &context)
171     : vkt::TestInstance(context)
172     , m_customDevice(context)
173     , m_referenceTLAS(makeTopLevelAccelerationStructure().release())
174     , m_resultTLAS(makeTopLevelAccelerationStructure().release())
175 {
176 }
177 
iterate(void)178 tcu::TestStatus RayTracingProceduralGeometryTestBase::iterate(void)
179 {
180     const DeviceInterface &vkd      = *m_customDevice.vkd;
181     const VkDevice device           = *m_customDevice.device;
182     const uint32_t queueFamilyIndex = m_customDevice.queueFamilyIndex;
183     const VkQueue queue             = m_customDevice.queue;
184     Allocator &allocator            = *m_customDevice.allocator;
185     const uint32_t sgHandleSize     = m_context.getRayTracingPipelineProperties().shaderGroupHandleSize;
186     const uint32_t imageSize        = 64u;
187 
188     const Move<VkDescriptorPool> descriptorPool =
189         DescriptorPoolBuilder()
190             .addType(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 2u)
191             .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 2u)
192             .build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 2u);
193 
194     m_descriptorSetLayout = DescriptorSetLayoutBuilder()
195                                 .addSingleBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR,
196                                                   ALL_RAY_TRACING_STAGES) // as with single/four aabb's
197                                 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
198                                                   ALL_RAY_TRACING_STAGES) // ssbo with result/reference values
199                                 .build(vkd, device);
200 
201     const Move<VkDescriptorSet> referenceDescriptorSet =
202         makeDescriptorSet(vkd, device, *descriptorPool, *m_descriptorSetLayout);
203     const Move<VkDescriptorSet> resultDescriptorSet =
204         makeDescriptorSet(vkd, device, *descriptorPool, *m_descriptorSetLayout);
205 
206     const VkDeviceSize resultBufferSize = imageSize * imageSize * sizeof(int);
207     const VkBufferCreateInfo resultBufferCreateInfo =
208         makeBufferCreateInfo(resultBufferSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT);
209     de::SharedPtr<BufferWithMemory> referenceBuffer = de::SharedPtr<BufferWithMemory>(
210         new BufferWithMemory(vkd, device, allocator, resultBufferCreateInfo, MemoryRequirement::HostVisible));
211     de::SharedPtr<BufferWithMemory> resultBuffer = de::SharedPtr<BufferWithMemory>(
212         new BufferWithMemory(vkd, device, allocator, resultBufferCreateInfo, MemoryRequirement::HostVisible));
213 
214     m_rayTracingPipeline = de::newMovePtr<RayTracingPipeline>();
215 
216     setupRayTracingPipeline();
217 
218     const VkStridedDeviceAddressRegionKHR rgenSBTR = makeStridedDeviceAddressRegionKHR(
219         getBufferDeviceAddress(vkd, device, m_rgenShaderBT->get(), 0), sgHandleSize, sgHandleSize);
220     const VkStridedDeviceAddressRegionKHR chitSBTR = makeStridedDeviceAddressRegionKHR(
221         getBufferDeviceAddress(vkd, device, m_chitShaderBT->get(), 0), sgHandleSize, sgHandleSize);
222     const VkStridedDeviceAddressRegionKHR missSBTR = makeStridedDeviceAddressRegionKHR(
223         getBufferDeviceAddress(vkd, device, m_missShaderBT->get(), 0), sgHandleSize, sgHandleSize);
224     const VkStridedDeviceAddressRegionKHR callableSBTR = makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0);
225 
226     m_cmdPool   = createCommandPool(vkd, device, 0, queueFamilyIndex);
227     m_cmdBuffer = allocateCommandBuffer(vkd, device, *m_cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
228 
229     // clear result and reference buffers
230     clearBuffer(resultBuffer, resultBufferSize);
231     clearBuffer(referenceBuffer, resultBufferSize);
232 
233     beginCommandBuffer(vkd, *m_cmdBuffer, 0u);
234     {
235         setupAccelerationStructures();
236 
237         // update descriptor sets
238         {
239             typedef DescriptorSetUpdateBuilder::Location DSL;
240 
241             const VkWriteDescriptorSetAccelerationStructureKHR referenceAS =
242                 makeASWriteDescriptorSet(m_referenceTLAS->getPtr());
243             const VkDescriptorBufferInfo referenceSSBO = makeDescriptorBufferInfo(**referenceBuffer, 0u, VK_WHOLE_SIZE);
244             DescriptorSetUpdateBuilder()
245                 .writeSingle(*referenceDescriptorSet, DSL::binding(0u), VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR,
246                              &referenceAS)
247                 .writeSingle(*referenceDescriptorSet, DSL::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
248                              &referenceSSBO)
249                 .update(vkd, device);
250 
251             const VkWriteDescriptorSetAccelerationStructureKHR resultAS =
252                 makeASWriteDescriptorSet(m_resultTLAS->getPtr());
253             const VkDescriptorBufferInfo resultSSBO = makeDescriptorBufferInfo(**resultBuffer, 0u, VK_WHOLE_SIZE);
254             DescriptorSetUpdateBuilder()
255                 .writeSingle(*resultDescriptorSet, DSL::binding(0u), VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR,
256                              &resultAS)
257                 .writeSingle(*resultDescriptorSet, DSL::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &resultSSBO)
258                 .update(vkd, device);
259         }
260 
261         // wait for data transfers
262         const VkMemoryBarrier bufferUploadBarrier =
263             makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT);
264         cmdPipelineMemoryBarrier(vkd, *m_cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT,
265                                  VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR, &bufferUploadBarrier, 1u);
266 
267         // wait for as build
268         const VkMemoryBarrier asBuildBarrier = makeMemoryBarrier(VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR,
269                                                                  VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR);
270         cmdPipelineMemoryBarrier(vkd, *m_cmdBuffer, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR,
271                                  VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR, &asBuildBarrier, 1u);
272 
273         vkd.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, *m_pipeline);
274 
275         // generate reference
276         vkd.cmdBindDescriptorSets(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, *m_pipelineLayout, 0, 1,
277                                   &referenceDescriptorSet.get(), 0, DE_NULL);
278         cmdTraceRays(vkd, *m_cmdBuffer, &rgenSBTR, &missSBTR, &chitSBTR, &callableSBTR, imageSize, imageSize, 1);
279 
280         // generate result
281         vkd.cmdBindDescriptorSets(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, *m_pipelineLayout, 0, 1,
282                                   &resultDescriptorSet.get(), 0, DE_NULL);
283         cmdTraceRays(vkd, *m_cmdBuffer, &rgenSBTR, &missSBTR, &chitSBTR, &callableSBTR, imageSize, imageSize, 1);
284 
285         const VkMemoryBarrier postTraceMemoryBarrier =
286             makeMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT);
287         cmdPipelineMemoryBarrier(vkd, *m_cmdBuffer, VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR,
288                                  VK_PIPELINE_STAGE_TRANSFER_BIT, &postTraceMemoryBarrier);
289     }
290     endCommandBuffer(vkd, *m_cmdBuffer);
291 
292     submitCommandsAndWait(vkd, device, queue, m_cmdBuffer.get());
293 
294     // verify result buffer
295     auto referenceAllocation = referenceBuffer->getAllocation();
296     invalidateMappedMemoryRange(vkd, device, referenceAllocation.getMemory(), referenceAllocation.getOffset(),
297                                 resultBufferSize);
298 
299     auto resultAllocation = resultBuffer->getAllocation();
300     invalidateMappedMemoryRange(vkd, device, resultAllocation.getMemory(), resultAllocation.getOffset(),
301                                 resultBufferSize);
302 
303     tcu::TextureFormat imageFormat(vk::mapVkFormat(VK_FORMAT_R8G8B8A8_UNORM));
304     tcu::PixelBufferAccess referenceAccess(imageFormat, imageSize, imageSize, 1, referenceAllocation.getHostPtr());
305     tcu::PixelBufferAccess resultAccess(imageFormat, imageSize, imageSize, 1, resultAllocation.getHostPtr());
306 
307     if (tcu::intThresholdCompare(m_context.getTestContext().getLog(), "Result comparison", "", referenceAccess,
308                                  resultAccess, tcu::UVec4(0), tcu::COMPARE_LOG_EVERYTHING))
309         return tcu::TestStatus::pass("Pass");
310     return tcu::TestStatus::fail("Fail");
311 }
312 
makeASWriteDescriptorSet(const VkAccelerationStructureKHR * pAccelerationStructure)313 VkWriteDescriptorSetAccelerationStructureKHR RayTracingProceduralGeometryTestBase::makeASWriteDescriptorSet(
314     const VkAccelerationStructureKHR *pAccelerationStructure)
315 {
316     return {
317         VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR, // VkStructureType                        sType
318         DE_NULL,               // const void*                            pNext
319         1u,                    // uint32_t                                accelerationStructureCount
320         pAccelerationStructure // const VkAccelerationStructureKHR*    pAccelerationStructures
321     };
322 }
323 
clearBuffer(de::SharedPtr<BufferWithMemory> buffer,VkDeviceSize bufferSize)324 void RayTracingProceduralGeometryTestBase::clearBuffer(de::SharedPtr<BufferWithMemory> buffer, VkDeviceSize bufferSize)
325 {
326     const DeviceInterface &vkd = *m_customDevice.vkd;
327     const VkDevice device      = *m_customDevice.device;
328     auto &bufferAlloc          = buffer->getAllocation();
329     void *bufferPtr            = bufferAlloc.getHostPtr();
330 
331     deMemset(bufferPtr, 1, static_cast<size_t>(bufferSize));
332     vk::flushAlloc(vkd, device, bufferAlloc);
333 }
334 
335 class ObjectBehindBoundingBoxInstance : public RayTracingProceduralGeometryTestBase
336 {
337 public:
338     ObjectBehindBoundingBoxInstance(Context &context);
339 
340     void setupRayTracingPipeline() override;
341     void setupAccelerationStructures() override;
342 };
343 
ObjectBehindBoundingBoxInstance(Context & context)344 ObjectBehindBoundingBoxInstance::ObjectBehindBoundingBoxInstance(Context &context)
345     : RayTracingProceduralGeometryTestBase(context)
346 {
347 }
348 
setupRayTracingPipeline()349 void ObjectBehindBoundingBoxInstance::setupRayTracingPipeline()
350 {
351     const DeviceInterface &vkd     = *m_customDevice.vkd;
352     const VkDevice device          = *m_customDevice.device;
353     Allocator &allocator           = *m_customDevice.allocator;
354     vk::BinaryCollection &bc       = m_context.getBinaryCollection();
355     const uint32_t sgHandleSize    = m_context.getRayTracingPipelineProperties().shaderGroupHandleSize;
356     const uint32_t sgBaseAlignment = m_context.getRayTracingPipelineProperties().shaderGroupBaseAlignment;
357 
358     m_rayTracingPipeline->addShader(VK_SHADER_STAGE_RAYGEN_BIT_KHR, createShaderModule(vkd, device, bc.get("rgen"), 0),
359                                     0);
360     m_rayTracingPipeline->addShader(VK_SHADER_STAGE_INTERSECTION_BIT_KHR,
361                                     createShaderModule(vkd, device, bc.get("isec"), 0), 1);
362     m_rayTracingPipeline->addShader(VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR,
363                                     createShaderModule(vkd, device, bc.get("chit"), 0), 1);
364     m_rayTracingPipeline->addShader(VK_SHADER_STAGE_MISS_BIT_KHR, createShaderModule(vkd, device, bc.get("miss"), 0),
365                                     2);
366 
367     m_pipelineLayout = makePipelineLayout(vkd, device, m_descriptorSetLayout.get());
368     m_pipeline       = m_rayTracingPipeline->createPipeline(vkd, device, *m_pipelineLayout);
369     m_rgenShaderBT   = m_rayTracingPipeline->createShaderBindingTable(vkd, device, *m_pipeline, allocator, sgHandleSize,
370                                                                       sgBaseAlignment, 0, 1);
371     m_chitShaderBT   = m_rayTracingPipeline->createShaderBindingTable(vkd, device, *m_pipeline, allocator, sgHandleSize,
372                                                                       sgBaseAlignment, 1, 1);
373     m_missShaderBT   = m_rayTracingPipeline->createShaderBindingTable(vkd, device, *m_pipeline, allocator, sgHandleSize,
374                                                                       sgBaseAlignment, 2, 1);
375 }
376 
setupAccelerationStructures()377 void ObjectBehindBoundingBoxInstance::setupAccelerationStructures()
378 {
379     const DeviceInterface &vkd = *m_customDevice.vkd;
380     const VkDevice device      = *m_customDevice.device;
381     Allocator &allocator       = *m_customDevice.allocator;
382 
383     // build reference acceleration structure - single aabb big enough to fit whole procedural geometry
384     de::SharedPtr<BottomLevelAccelerationStructure> referenceBLAS(makeBottomLevelAccelerationStructure().release());
385     referenceBLAS->setGeometryData(
386         {
387             {0.0, 0.0, -64.0},
388             {64.0, 64.0, -16.0},
389         },
390         false, 0);
391     referenceBLAS->createAndBuild(vkd, device, *m_cmdBuffer, allocator);
392     m_blasVect.push_back(referenceBLAS);
393 
394     m_referenceTLAS->setInstanceCount(1);
395     m_referenceTLAS->addInstance(m_blasVect.back());
396     m_referenceTLAS->createAndBuild(vkd, device, *m_cmdBuffer, allocator);
397 
398     // build result acceleration structure - wall of 4 aabb's and generated object is actualy behind it (as it is just 1.0 unit thick)
399     de::SharedPtr<BottomLevelAccelerationStructure> resultBLAS(makeBottomLevelAccelerationStructure().release());
400     resultBLAS->setGeometryData(
401         {
402             {0.0, 0.0, 0.0},   // |  |
403             {32.0, 32.0, 1.0}, // |* |
404             {32.0, 0.0, 0.0},  //    |  |
405             {64.0, 32.0, 1.0}, //    | *|
406             {0.0, 32.0, 0.0},  // |* |
407             {32.0, 64.0, 1.0}, // |  |
408             {32.0, 32.0, 0.0}, //    | *|
409             {64.0, 64.0, 1.0}, //    |  |
410         },
411         false, 0);
412     resultBLAS->createAndBuild(vkd, device, *m_cmdBuffer, allocator);
413     m_blasVect.push_back(resultBLAS);
414 
415     m_resultTLAS->setInstanceCount(1);
416     m_resultTLAS->addInstance(m_blasVect.back());
417     m_resultTLAS->createAndBuild(vkd, device, *m_cmdBuffer, allocator);
418 }
419 
420 class TriangleInBeteenInstance : public RayTracingProceduralGeometryTestBase
421 {
422 public:
423     TriangleInBeteenInstance(Context &context);
424 
425     void setupRayTracingPipeline() override;
426     void setupAccelerationStructures() override;
427 };
428 
TriangleInBeteenInstance(Context & context)429 TriangleInBeteenInstance::TriangleInBeteenInstance(Context &context) : RayTracingProceduralGeometryTestBase(context)
430 {
431 }
432 
setupRayTracingPipeline()433 void TriangleInBeteenInstance::setupRayTracingPipeline()
434 {
435     const DeviceInterface &vkd     = *m_customDevice.vkd;
436     const VkDevice device          = *m_customDevice.device;
437     Allocator &allocator           = *m_customDevice.allocator;
438     vk::BinaryCollection &bc       = m_context.getBinaryCollection();
439     const uint32_t sgHandleSize    = m_context.getRayTracingPipelineProperties().shaderGroupHandleSize;
440     const uint32_t sgBaseAlignment = m_context.getRayTracingPipelineProperties().shaderGroupBaseAlignment;
441 
442     m_rayTracingPipeline->addShader(VK_SHADER_STAGE_RAYGEN_BIT_KHR, createShaderModule(vkd, device, bc.get("rgen"), 0),
443                                     0);
444     m_rayTracingPipeline->addShader(VK_SHADER_STAGE_INTERSECTION_BIT_KHR,
445                                     createShaderModule(vkd, device, bc.get("isec"), 0), 1);
446     m_rayTracingPipeline->addShader(VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR,
447                                     createShaderModule(vkd, device, bc.get("chit"), 0), 1);
448     m_rayTracingPipeline->addShader(VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR,
449                                     createShaderModule(vkd, device, bc.get("chit_triangle"), 0), 2);
450     m_rayTracingPipeline->addShader(VK_SHADER_STAGE_MISS_BIT_KHR, createShaderModule(vkd, device, bc.get("miss"), 0),
451                                     3);
452 
453     m_pipelineLayout = makePipelineLayout(vkd, device, m_descriptorSetLayout.get());
454     m_pipeline       = m_rayTracingPipeline->createPipeline(vkd, device, *m_pipelineLayout);
455     m_rgenShaderBT   = m_rayTracingPipeline->createShaderBindingTable(vkd, device, *m_pipeline, allocator, sgHandleSize,
456                                                                       sgBaseAlignment, 0, 1);
457     m_chitShaderBT   = m_rayTracingPipeline->createShaderBindingTable(vkd, device, *m_pipeline, allocator, sgHandleSize,
458                                                                       sgBaseAlignment, 1, 2);
459     m_missShaderBT   = m_rayTracingPipeline->createShaderBindingTable(vkd, device, *m_pipeline, allocator, sgHandleSize,
460                                                                       sgBaseAlignment, 3, 1);
461 }
462 
setupAccelerationStructures()463 void TriangleInBeteenInstance::setupAccelerationStructures()
464 {
465     const DeviceInterface &vkd = *m_customDevice.vkd;
466     const VkDevice device      = *m_customDevice.device;
467     Allocator &allocator       = *m_customDevice.allocator;
468 
469     de::SharedPtr<BottomLevelAccelerationStructure> triangleBLAS(makeBottomLevelAccelerationStructure().release());
470     triangleBLAS->setGeometryData(
471         {
472             {16.0, 16.0, -8.0},
473             {56.0, 32.0, -8.0},
474             {32.0, 48.0, -8.0},
475         },
476         true, VK_GEOMETRY_OPAQUE_BIT_KHR);
477     triangleBLAS->createAndBuild(vkd, device, *m_cmdBuffer, allocator);
478     m_blasVect.push_back(triangleBLAS);
479 
480     de::SharedPtr<BottomLevelAccelerationStructure> fullElipsoidBLAS(makeBottomLevelAccelerationStructure().release());
481     fullElipsoidBLAS->setGeometryData(
482         {
483             {0.0, 0.0, -64.0},
484             {64.0, 64.0, -16.0},
485         },
486         false, 0);
487     fullElipsoidBLAS->createAndBuild(vkd, device, *m_cmdBuffer, allocator);
488     m_blasVect.push_back(fullElipsoidBLAS);
489 
490     // build reference acceleration structure - triangle and a single aabb big enough to fit whole procedural geometry
491     m_referenceTLAS->setInstanceCount(2);
492     m_referenceTLAS->addInstance(fullElipsoidBLAS);
493     m_referenceTLAS->addInstance(triangleBLAS);
494     m_referenceTLAS->createAndBuild(vkd, device, *m_cmdBuffer, allocator);
495 
496     de::SharedPtr<BottomLevelAccelerationStructure> elipsoidWallBLAS(makeBottomLevelAccelerationStructure().release());
497     elipsoidWallBLAS->setGeometryData(
498         {
499             {0.0, 0.0, 0.0}, // |*  |
500             {20.0, 64.0, 1.0},
501             {20.0, 0.0, 0.0}, // | * |
502             {44.0, 64.0, 1.0},
503             {44.0, 0.0, 0.0}, // |  *|
504             {64.0, 64.0, 1.0},
505         },
506         false, 0);
507     elipsoidWallBLAS->createAndBuild(vkd, device, *m_cmdBuffer, allocator);
508     m_blasVect.push_back(elipsoidWallBLAS);
509 
510     // build result acceleration structure - triangle and a three aabb's (they are in front of triangle but generate intersections behind it)
511     m_resultTLAS->setInstanceCount(2);
512     m_resultTLAS->addInstance(elipsoidWallBLAS);
513     m_resultTLAS->addInstance(triangleBLAS);
514     m_resultTLAS->createAndBuild(vkd, device, *m_cmdBuffer, allocator);
515 }
516 
517 class RayTracingProceduralGeometryTestCase : public TestCase
518 {
519 public:
520     RayTracingProceduralGeometryTestCase(tcu::TestContext &context, const char *name, TestType testType);
521     ~RayTracingProceduralGeometryTestCase(void) = default;
522 
523     void checkSupport(Context &context) const override;
524     void initPrograms(SourceCollections &programCollection) const override;
525     TestInstance *createInstance(Context &context) const override;
526 
527 protected:
528     TestType m_testType;
529 };
530 
RayTracingProceduralGeometryTestCase(tcu::TestContext & context,const char * name,TestType testType)531 RayTracingProceduralGeometryTestCase::RayTracingProceduralGeometryTestCase(tcu::TestContext &context, const char *name,
532                                                                            TestType testType)
533     : TestCase(context, name)
534     , m_testType(testType)
535 {
536 }
537 
checkSupport(Context & context) const538 void RayTracingProceduralGeometryTestCase::checkSupport(Context &context) const
539 {
540     context.requireDeviceFunctionality("VK_KHR_ray_tracing_pipeline");
541     context.requireDeviceFunctionality("VK_KHR_acceleration_structure");
542 
543     if (!context.getRayTracingPipelineFeatures().rayTracingPipeline)
544         TCU_THROW(NotSupportedError, "Requires VkPhysicalDeviceRayTracingPipelineFeaturesKHR.rayTracingPipeline");
545 
546     if (!context.getAccelerationStructureFeatures().accelerationStructure)
547         TCU_THROW(TestError, "VK_KHR_ray_tracing_pipeline requires "
548                              "VkPhysicalDeviceAccelerationStructureFeaturesKHR.accelerationStructure");
549 }
550 
initPrograms(SourceCollections & programCollection) const551 void RayTracingProceduralGeometryTestCase::initPrograms(SourceCollections &programCollection) const
552 {
553     const vk::ShaderBuildOptions glslBuildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_4, 0u, true);
554 
555     std::string rgenSource =
556         "#version 460 core\n"
557         "#extension GL_EXT_ray_tracing : require\n"
558         "layout(location = 0) rayPayloadEXT int payload;\n"
559 
560         "layout(set = 0, binding = 0) uniform accelerationStructureEXT tlas;\n"
561         "layout(set = 0, binding = 1, std430) writeonly buffer Result {\n"
562         "    int value[];\n"
563         "} result;\n"
564 
565         "void main()\n"
566         "{\n"
567         "  float tmin        = 0.0;\n"
568         "  float tmax        = 50.0;\n"
569         "  vec3  origin      = vec3(float(gl_LaunchIDEXT.x) + 0.5f, float(gl_LaunchIDEXT.y) + 0.5f, 2.0);\n"
570         "  vec3  direction   = vec3(0.0,0.0,-1.0);\n"
571         "  uint  resultIndex = gl_LaunchIDEXT.x + gl_LaunchIDEXT.y * gl_LaunchSizeEXT.x;\n"
572 
573         "  traceRayEXT(tlas, gl_RayFlagsCullBackFacingTrianglesEXT, 0xFF, 0, 0, 0, origin, tmin, direction, tmax, 0);\n"
574         // to be able to display result in cherry this is interpreated as r8g8b8a8 during verification
575         // we are using only red but we need to add alpha (note: r and a may be swapped depending on endianness)
576         "  result.value[resultIndex] = payload + 0xFF000000;\n"
577         "};\n";
578     programCollection.glslSources.add("rgen") << glu::RaygenSource(rgenSource) << glslBuildOptions;
579 
580     std::string isecSource = "#version 460 core\n"
581                              "#extension GL_EXT_ray_tracing : require\n"
582 
583                              "void main()\n"
584                              "{\n"
585                              // note: same elipsoid center and radii are also defined in chit shader
586                              "  vec3 center = vec3(32.0, 32.0, -30.0);\n"
587                              "  vec3 radii  = vec3(30.0, 15.0, 5.0);\n"
588 
589                              // simplify to ray sphere intersection
590                              "  vec3  eliDir = gl_WorldRayOriginEXT - center;\n"
591                              "  vec3  eliS   = eliDir / radii;\n"
592                              "  vec3  rayS   = gl_WorldRayDirectionEXT / radii;\n"
593 
594                              "  float a = dot(rayS, rayS);\n"
595                              "  float b = dot(eliS, rayS);\n"
596                              "  float c = dot(eliS, eliS);\n"
597                              "  float h = b * b - a * (c - 1.0);\n"
598                              "  if (h < 0.0)\n"
599                              "    return;\n"
600                              "  reportIntersectionEXT((-b - sqrt(h)) / a, 0);\n"
601                              "}\n";
602     programCollection.glslSources.add("isec") << glu::IntersectionSource(isecSource) << glslBuildOptions;
603 
604     std::string chitSource = "#version 460 core\n"
605                              "#extension GL_EXT_ray_tracing : require\n"
606                              "layout(location = 0) rayPayloadInEXT int payload;\n"
607                              "\n"
608                              "void main()\n"
609                              "{\n"
610                              // note: same elipsoid center and radii are also defined in chit shader
611                              "  vec3 center    = vec3(32.0, 32.0, -30.0);\n"
612                              "  vec3 radii     = vec3(30.0, 15.0, 5.0);\n"
613                              "  vec3 lightDir  = normalize(vec3(0.0, 0.0, 1.0));\n"
614                              "  vec3 hitPos    = gl_WorldRayOriginEXT + gl_HitTEXT * gl_WorldRayDirectionEXT;\n"
615                              "  vec3 hitNormal = normalize((hitPos - center) / radii);\n"
616 
617                              "  payload = 50 + int(200.0 * clamp(dot(hitNormal, lightDir), 0.0, 1.0));\n"
618                              "}\n";
619     programCollection.glslSources.add("chit") << glu::ClosestHitSource(chitSource) << glslBuildOptions;
620 
621     if (m_testType == TestType::TRIANGLE_IN_BETWEEN)
622     {
623         std::string chitTriangleSource = "#version 460 core\n"
624                                          "#extension GL_EXT_ray_tracing : require\n"
625                                          "layout(location = 0) rayPayloadInEXT int payload;\n"
626                                          "\n"
627                                          "void main()\n"
628                                          "{\n"
629                                          "  payload = 250;\n"
630                                          "}\n";
631         programCollection.glslSources.add("chit_triangle")
632             << glu::ClosestHitSource(chitTriangleSource) << glslBuildOptions;
633     }
634 
635     std::string missSource = "#version 460 core\n"
636                              "#extension GL_EXT_ray_tracing : require\n"
637                              "layout(location = 0) rayPayloadInEXT int payload;\n"
638                              "void main()\n"
639                              "{\n"
640                              "  payload = 30;\n"
641                              "}\n";
642     programCollection.glslSources.add("miss") << glu::MissSource(missSource) << glslBuildOptions;
643 }
644 
createInstance(Context & context) const645 TestInstance *RayTracingProceduralGeometryTestCase::createInstance(Context &context) const
646 {
647     if (m_testType == TestType::TRIANGLE_IN_BETWEEN)
648         return new TriangleInBeteenInstance(context);
649 
650     // TestType::OBJECT_BEHIND_BOUNDING_BOX
651     return new ObjectBehindBoundingBoxInstance(context);
652 }
653 
654 } // namespace
655 
createProceduralGeometryTests(tcu::TestContext & testCtx)656 tcu::TestCaseGroup *createProceduralGeometryTests(tcu::TestContext &testCtx)
657 {
658     // Test procedural geometry with complex bouding box sets
659     de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "procedural_geometry"));
660 
661     group->addChild(new RayTracingProceduralGeometryTestCase(testCtx, "object_behind_bounding_boxes",
662                                                              TestType::OBJECT_BEHIND_BOUNDING_BOX));
663     group->addChild(
664         new RayTracingProceduralGeometryTestCase(testCtx, "triangle_in_between", TestType::TRIANGLE_IN_BETWEEN));
665 
666     return group.release();
667 }
668 
669 } // namespace RayTracing
670 
671 } // namespace vkt
672