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