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