1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2019 The Khronos Group Inc.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief Ray Tracing Watertightness tests
22 *//*--------------------------------------------------------------------*/
23
24 #include "vktRayTracingWatertightnessTests.hpp"
25
26 #include "vkDefs.hpp"
27
28 #include "vktTestCase.hpp"
29 #include "vkCmdUtil.hpp"
30 #include "vkObjUtil.hpp"
31 #include "vkBuilderUtil.hpp"
32 #include "vkBarrierUtil.hpp"
33 #include "vkBufferWithMemory.hpp"
34 #include "vkImageWithMemory.hpp"
35 #include "vkTypeUtil.hpp"
36
37 #include "vkRayTracingUtil.hpp"
38
39 #include "deRandom.hpp"
40
41 namespace vkt
42 {
43 namespace RayTracing
44 {
45 namespace
46 {
47 using namespace vk;
48 using namespace std;
49
50 static const VkFlags ALL_RAY_TRACING_STAGES = VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR |
51 VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR |
52 VK_SHADER_STAGE_INTERSECTION_BIT_KHR | VK_SHADER_STAGE_CALLABLE_BIT_KHR;
53
54 enum TestType
55 {
56 TEST_TYPE_INSIDE_STAGE,
57 TEST_TYPE_BETWEEN_STAGES,
58 };
59
60 struct CaseDef
61 {
62 TestType testType;
63 VkShaderStageFlagBits stage;
64 uint32_t width;
65 uint32_t height;
66 uint32_t squaresGroupCount;
67 uint32_t geometriesGroupCount;
68 uint32_t instancesGroupCount;
69 };
70
71 enum ShaderGroups
72 {
73 FIRST_GROUP = 0,
74 RAYGEN_GROUP = FIRST_GROUP,
75 MISS_GROUP,
76 HIT_GROUP,
77 GROUP_COUNT
78 };
79
getShaderGroupSize(const InstanceInterface & vki,const VkPhysicalDevice physicalDevice)80 uint32_t getShaderGroupSize(const InstanceInterface &vki, const VkPhysicalDevice physicalDevice)
81 {
82 de::MovePtr<RayTracingProperties> rayTracingPropertiesKHR;
83
84 rayTracingPropertiesKHR = makeRayTracingProperties(vki, physicalDevice);
85 return rayTracingPropertiesKHR->getShaderGroupHandleSize();
86 }
87
getShaderGroupBaseAlignment(const InstanceInterface & vki,const VkPhysicalDevice physicalDevice)88 uint32_t getShaderGroupBaseAlignment(const InstanceInterface &vki, const VkPhysicalDevice physicalDevice)
89 {
90 de::MovePtr<RayTracingProperties> rayTracingPropertiesKHR;
91
92 rayTracingPropertiesKHR = makeRayTracingProperties(vki, physicalDevice);
93 return rayTracingPropertiesKHR->getShaderGroupBaseAlignment();
94 }
95
makeImageCreateInfo(uint32_t width,uint32_t height,VkFormat format)96 VkImageCreateInfo makeImageCreateInfo(uint32_t width, uint32_t height, VkFormat format)
97 {
98 const VkImageUsageFlags usage =
99 VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
100 const VkImageCreateInfo imageCreateInfo = {
101 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
102 DE_NULL, // const void* pNext;
103 (VkImageCreateFlags)0u, // VkImageCreateFlags flags;
104 VK_IMAGE_TYPE_2D, // VkImageType imageType;
105 format, // VkFormat format;
106 makeExtent3D(width, height, 1u), // VkExtent3D extent;
107 1u, // uint32_t mipLevels;
108 1u, // uint32_t arrayLayers;
109 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
110 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
111 usage, // VkImageUsageFlags usage;
112 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
113 0u, // uint32_t queueFamilyIndexCount;
114 DE_NULL, // const uint32_t* pQueueFamilyIndices;
115 VK_IMAGE_LAYOUT_UNDEFINED // VkImageLayout initialLayout;
116 };
117
118 return imageCreateInfo;
119 }
120
121 class RayTracingBuildTestInstance : public TestInstance
122 {
123 public:
124 RayTracingBuildTestInstance(Context &context, const CaseDef &data);
125 ~RayTracingBuildTestInstance(void);
126 tcu::TestStatus iterate(void);
127
128 protected:
129 void checkSupportInInstance(void) const;
130 de::MovePtr<BufferWithMemory> runTest(void);
131 Move<VkPipeline> makePipeline(de::MovePtr<RayTracingPipeline> &rayTracingPipeline, VkPipelineLayout pipelineLayout);
132 de::MovePtr<BufferWithMemory> createShaderBindingTable(const InstanceInterface &vki, const DeviceInterface &vkd,
133 const VkDevice device, const VkPhysicalDevice physicalDevice,
134 const VkPipeline pipeline, Allocator &allocator,
135 de::MovePtr<RayTracingPipeline> &rayTracingPipeline,
136 const uint32_t group, const uint32_t groupCount = 1u);
137 de::MovePtr<TopLevelAccelerationStructure> initTopAccelerationStructure(
138 VkCommandBuffer cmdBuffer,
139 vector<de::SharedPtr<BottomLevelAccelerationStructure>> &bottomLevelAccelerationStructures);
140 vector<de::SharedPtr<BottomLevelAccelerationStructure>> initBottomAccelerationStructures(VkCommandBuffer cmdBuffer);
141 de::MovePtr<BottomLevelAccelerationStructure> initBottomAccelerationStructure(VkCommandBuffer cmdBuffer,
142 tcu::UVec2 &startPos);
143
144 private:
145 CaseDef m_data;
146 VkShaderStageFlags m_shaders;
147 VkShaderStageFlags m_extraCallShaders;
148 uint32_t m_raygenShaderGroup;
149 uint32_t m_missShaderGroup;
150 uint32_t m_hitShaderGroup;
151 uint32_t m_callableShaderGroup;
152 uint32_t m_shaderGroupCount;
153 };
154
RayTracingBuildTestInstance(Context & context,const CaseDef & data)155 RayTracingBuildTestInstance::RayTracingBuildTestInstance(Context &context, const CaseDef &data)
156 : vkt::TestInstance(context)
157 , m_data(data)
158 , m_shaders(0)
159 , m_extraCallShaders(0)
160 , m_raygenShaderGroup(~0u)
161 , m_missShaderGroup(~0u)
162 , m_hitShaderGroup(~0u)
163 , m_callableShaderGroup(~0u)
164 , m_shaderGroupCount(0)
165 {
166 const VkShaderStageFlags hitStages =
167 VK_SHADER_STAGE_ANY_HIT_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_INTERSECTION_BIT_KHR;
168 BinaryCollection &collection = m_context.getBinaryCollection();
169 uint32_t group = 0;
170 uint32_t shaderCount = 0;
171
172 if (collection.contains("rgen"))
173 m_shaders |= VK_SHADER_STAGE_RAYGEN_BIT_KHR;
174 if (collection.contains("ahit"))
175 m_shaders |= VK_SHADER_STAGE_ANY_HIT_BIT_KHR;
176 if (collection.contains("chit"))
177 m_shaders |= VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
178 if (collection.contains("miss"))
179 m_shaders |= VK_SHADER_STAGE_MISS_BIT_KHR;
180 if (collection.contains("sect"))
181 m_shaders |= VK_SHADER_STAGE_INTERSECTION_BIT_KHR;
182 if (collection.contains("call"))
183 m_shaders |= VK_SHADER_STAGE_CALLABLE_BIT_KHR;
184
185 if (collection.contains("cal0"))
186 m_extraCallShaders++;
187
188 for (BinaryCollection::Iterator it = collection.begin(); it != collection.end(); ++it)
189 shaderCount++;
190
191 if (shaderCount != m_extraCallShaders + (uint32_t)dePop32(m_shaders))
192 TCU_THROW(InternalError, "Unused shaders detected in the collection");
193
194 if (0 != (m_shaders & VK_SHADER_STAGE_RAYGEN_BIT_KHR))
195 m_raygenShaderGroup = group++;
196
197 if (0 != (m_shaders & VK_SHADER_STAGE_MISS_BIT_KHR))
198 m_missShaderGroup = group++;
199
200 if (0 != (m_shaders & hitStages))
201 m_hitShaderGroup = group++;
202
203 if (0 != (m_shaders & VK_SHADER_STAGE_CALLABLE_BIT_KHR) || m_extraCallShaders > 0)
204 m_callableShaderGroup = group++;
205
206 m_shaderGroupCount = group;
207 }
208
~RayTracingBuildTestInstance(void)209 RayTracingBuildTestInstance::~RayTracingBuildTestInstance(void)
210 {
211 }
212
213 class RayTracingTestCase : public TestCase
214 {
215 public:
216 RayTracingTestCase(tcu::TestContext &context, const char *name, const CaseDef data);
217 ~RayTracingTestCase(void);
218
219 virtual void initPrograms(SourceCollections &programCollection) const;
220 virtual TestInstance *createInstance(Context &context) const;
221 virtual void checkSupport(Context &context) const;
222
223 private:
224 static inline const std::string getIntersectionPassthrough(void);
225 static inline const std::string getMissPassthrough(void);
226 static inline const std::string getHitPassthrough(void);
227
228 CaseDef m_data;
229 };
230
RayTracingTestCase(tcu::TestContext & context,const char * name,const CaseDef data)231 RayTracingTestCase::RayTracingTestCase(tcu::TestContext &context, const char *name, const CaseDef data)
232 : vkt::TestCase(context, name)
233 , m_data(data)
234 {
235 DE_ASSERT((m_data.width * m_data.height) ==
236 (m_data.squaresGroupCount * m_data.geometriesGroupCount * m_data.instancesGroupCount));
237 }
238
~RayTracingTestCase(void)239 RayTracingTestCase::~RayTracingTestCase(void)
240 {
241 }
242
checkSupport(Context & context) const243 void RayTracingTestCase::checkSupport(Context &context) const
244 {
245 context.requireDeviceFunctionality("VK_KHR_acceleration_structure");
246 context.requireDeviceFunctionality("VK_KHR_ray_tracing_pipeline");
247
248 const VkPhysicalDeviceRayTracingPipelineFeaturesKHR &rayTracingPipelineFeaturesKHR =
249 context.getRayTracingPipelineFeatures();
250 if (rayTracingPipelineFeaturesKHR.rayTracingPipeline == false)
251 TCU_THROW(NotSupportedError, "Requires VkPhysicalDeviceRayTracingPipelineFeaturesKHR.rayTracingPipeline");
252
253 const VkPhysicalDeviceAccelerationStructureFeaturesKHR &accelerationStructureFeaturesKHR =
254 context.getAccelerationStructureFeatures();
255 if (accelerationStructureFeaturesKHR.accelerationStructure == false)
256 TCU_THROW(TestError, "VK_KHR_ray_tracing_pipeline requires "
257 "VkPhysicalDeviceAccelerationStructureFeaturesKHR.accelerationStructure");
258 }
259
getIntersectionPassthrough(void)260 const std::string RayTracingTestCase::getIntersectionPassthrough(void)
261 {
262 const std::string intersectionPassthrough = "#version 460 core\n"
263 "#extension GL_EXT_ray_tracing : require\n"
264 "hitAttributeEXT vec3 hitAttribute;\n"
265 "\n"
266 "void main()\n"
267 "{\n"
268 " reportIntersectionEXT(0.95f, 0x7Eu);\n"
269 "}\n";
270
271 return intersectionPassthrough;
272 }
273
getMissPassthrough(void)274 const std::string RayTracingTestCase::getMissPassthrough(void)
275 {
276 const std::string missPassthrough = "#version 460 core\n"
277 "#extension GL_EXT_ray_tracing : require\n"
278 "layout(location = 0) rayPayloadInEXT vec3 hitValue;\n"
279 "\n"
280 "void main()\n"
281 "{\n"
282 "}\n";
283
284 return missPassthrough;
285 }
286
getHitPassthrough(void)287 const std::string RayTracingTestCase::getHitPassthrough(void)
288 {
289 const std::string hitPassthrough = "#version 460 core\n"
290 "#extension GL_EXT_ray_tracing : require\n"
291 "hitAttributeEXT vec3 attribs;\n"
292 "layout(location = 0) rayPayloadInEXT vec3 hitValue;\n"
293 "\n"
294 "void main()\n"
295 "{\n"
296 "}\n";
297
298 return hitPassthrough;
299 }
300
initPrograms(SourceCollections & programCollection) const301 void RayTracingTestCase::initPrograms(SourceCollections &programCollection) const
302 {
303 const vk::ShaderBuildOptions buildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_4, 0u, true);
304
305 const std::string imageQualifiers = (m_data.testType == TEST_TYPE_BETWEEN_STAGES ? " shadercallcoherent " : "");
306 const std::string glslExtensions =
307 (m_data.testType == TEST_TYPE_BETWEEN_STAGES ? "#extension GL_KHR_memory_scope_semantics : require\n" : "");
308 const bool calleeIsAnyHit = (m_data.stage == VK_SHADER_STAGE_INTERSECTION_BIT_KHR);
309 const std::string repackInstruction =
310 calleeIsAnyHit ? "reportIntersectionEXT(0.95f, 0u)" : "executeCallableEXT(0, 0)";
311 const std::string updateBarrierCaller =
312 (m_data.testType == TEST_TYPE_BETWEEN_STAGES ?
313 " memoryBarrier(gl_ScopeShaderCallEXT, gl_StorageSemanticsImage, gl_SemanticsRelease);\n" :
314 "");
315 const std::string updateBarrierCallee =
316 (m_data.testType == TEST_TYPE_BETWEEN_STAGES ?
317 " memoryBarrier(gl_ScopeShaderCallEXT, gl_StorageSemanticsImage, gl_SemanticsAcquire);\n" :
318 "");
319 const std::string updateImage0 = " uint r = uint(gl_LaunchIDEXT.x + gl_LaunchSizeEXT.x * gl_LaunchIDEXT.y);\n"
320 " uvec4 c = uvec4(r, 0, 0, 1);\n"
321 " imageStore(result, ivec2(gl_LaunchIDEXT), c);\n"
322 "\n" +
323 updateBarrierCaller +
324 "\n"
325 " " +
326 repackInstruction + ";\n";
327 const std::string updateImage1 = " uint d = imageLoad(result, ivec2(gl_LaunchIDEXT)).x;\n"
328 " imageStore(result, ivec2(gl_LaunchIDEXT), uvec4(d + 1, 0, 0, 1));\n";
329 const std::string updateImageCaller =
330 updateImage0 + (m_data.testType == TEST_TYPE_INSIDE_STAGE ? updateImage1 : "");
331 const std::string updateImageCallee = (m_data.testType == TEST_TYPE_BETWEEN_STAGES ? updateImage1 : "");
332 const std::string calleeShaderParam = calleeIsAnyHit ? "" : "layout(location = 0) callableDataInEXT float dummy;\n";
333 const std::string calleeShader = "#version 460 core\n"
334 "#extension GL_EXT_ray_tracing : require\n" +
335 glslExtensions + calleeShaderParam +
336 "layout(set = 0, binding = 0, r32ui) uniform uimage2D result;\n"
337 "\n"
338 "void main()\n"
339 "{\n" +
340 updateBarrierCallee + updateImageCallee + "}\n";
341
342 switch (m_data.stage)
343 {
344 case VK_SHADER_STAGE_RAYGEN_BIT_KHR:
345 {
346 std::stringstream css;
347 css << "#version 460 core\n"
348 "#extension GL_EXT_ray_tracing : require\n" +
349 glslExtensions + "layout(set = 0, binding = 0, r32ui)" + imageQualifiers +
350 "uniform uimage2D result;\n"
351 "layout(location = 0) callableDataEXT float dummy;\n"
352 "\n"
353 "void main()\n"
354 "{\n"
355 << updateImageCaller << "}\n";
356
357 programCollection.glslSources.add("rgen") << glu::RaygenSource(updateRayTracingGLSL(css.str())) << buildOptions;
358 programCollection.glslSources.add("cal0")
359 << glu::CallableSource(updateRayTracingGLSL(calleeShader)) << buildOptions;
360
361 break;
362 }
363
364 case VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR:
365 {
366 programCollection.glslSources.add("rgen")
367 << glu::RaygenSource(updateRayTracingGLSL(getCommonRayGenerationShader())) << buildOptions;
368
369 std::stringstream css;
370 css << "#version 460 core\n"
371 "#extension GL_EXT_ray_tracing : require\n" +
372 glslExtensions +
373 "layout(location = 0) rayPayloadInEXT vec3 hitValue;\n"
374 "hitAttributeEXT vec3 attribs;\n"
375 "layout(r32ui, set = 0, binding = 0)" +
376 imageQualifiers +
377 "uniform uimage2D result;\n"
378 "layout(location = 0) callableDataEXT float dummy;\n"
379 "\n"
380 "void main()\n"
381 "{\n"
382 << updateImageCaller << "}\n";
383
384 programCollection.glslSources.add("chit")
385 << glu::ClosestHitSource(updateRayTracingGLSL(css.str())) << buildOptions;
386 programCollection.glslSources.add("cal0")
387 << glu::CallableSource(updateRayTracingGLSL(calleeShader)) << buildOptions;
388
389 programCollection.glslSources.add("ahit")
390 << glu::AnyHitSource(updateRayTracingGLSL(getHitPassthrough())) << buildOptions;
391 programCollection.glslSources.add("miss")
392 << glu::MissSource(updateRayTracingGLSL(getMissPassthrough())) << buildOptions;
393 programCollection.glslSources.add("sect")
394 << glu::IntersectionSource(updateRayTracingGLSL(getIntersectionPassthrough())) << buildOptions;
395
396 break;
397 }
398
399 case VK_SHADER_STAGE_MISS_BIT_KHR:
400 {
401 programCollection.glslSources.add("rgen")
402 << glu::RaygenSource(updateRayTracingGLSL(getCommonRayGenerationShader())) << buildOptions;
403
404 std::stringstream css;
405 css << "#version 460 core\n"
406 "#extension GL_EXT_ray_tracing : require\n" +
407 glslExtensions + "layout(r32ui, set = 0, binding = 0)" + imageQualifiers +
408 "uniform uimage2D result;\n"
409 "layout(location = 0) callableDataEXT float dummy;\n"
410 "\n"
411 "void main()\n"
412 "{\n"
413 << updateImageCaller << "}\n";
414
415 programCollection.glslSources.add("miss") << glu::MissSource(updateRayTracingGLSL(css.str())) << buildOptions;
416 programCollection.glslSources.add("cal0")
417 << glu::CallableSource(updateRayTracingGLSL(calleeShader)) << buildOptions;
418
419 programCollection.glslSources.add("ahit")
420 << glu::AnyHitSource(updateRayTracingGLSL(getHitPassthrough())) << buildOptions;
421 programCollection.glslSources.add("chit")
422 << glu::ClosestHitSource(updateRayTracingGLSL(getHitPassthrough())) << buildOptions;
423 programCollection.glslSources.add("sect")
424 << glu::IntersectionSource(updateRayTracingGLSL(getIntersectionPassthrough())) << buildOptions;
425
426 break;
427 }
428
429 case VK_SHADER_STAGE_INTERSECTION_BIT_KHR:
430 {
431 programCollection.glslSources.add("rgen")
432 << glu::RaygenSource(updateRayTracingGLSL(getCommonRayGenerationShader())) << buildOptions;
433
434 std::stringstream css;
435 css << "#version 460 core\n"
436 "#extension GL_EXT_ray_tracing : require\n" +
437 glslExtensions + "layout(r32ui, set = 0, binding = 0)" + imageQualifiers +
438 "uniform uimage2D result;\n"
439 "\n"
440 "void main()\n"
441 "{\n"
442 << updateImageCaller << "}\n";
443
444 programCollection.glslSources.add("sect")
445 << glu::IntersectionSource(updateRayTracingGLSL(css.str())) << buildOptions;
446 programCollection.glslSources.add("ahit")
447 << glu::AnyHitSource(updateRayTracingGLSL(calleeShader)) << buildOptions;
448
449 programCollection.glslSources.add("chit")
450 << glu::ClosestHitSource(updateRayTracingGLSL(getHitPassthrough())) << buildOptions;
451 programCollection.glslSources.add("miss")
452 << glu::MissSource(updateRayTracingGLSL(getMissPassthrough())) << buildOptions;
453
454 break;
455 }
456
457 case VK_SHADER_STAGE_CALLABLE_BIT_KHR:
458 {
459 {
460 std::stringstream css;
461 css << "#version 460 core\n"
462 "#extension GL_EXT_ray_tracing : require\n" +
463 glslExtensions +
464 "layout(location = 0) callableDataEXT float dummy;\n"
465 "layout(set = 0, binding = 0, r32ui)" +
466 imageQualifiers +
467 "uniform uimage2D result;\n"
468 "\n"
469 "void main()\n"
470 "{\n"
471 " executeCallableEXT(1, 0);\n"
472 "}\n";
473
474 programCollection.glslSources.add("rgen")
475 << glu::RaygenSource(updateRayTracingGLSL(css.str())) << buildOptions;
476 }
477
478 {
479 std::stringstream css;
480 css << "#version 460 core\n"
481 "#extension GL_EXT_ray_tracing : require\n" +
482 glslExtensions +
483 "layout(location = 1) callableDataInEXT float dummyIn;\n"
484 "layout(location = 0) callableDataEXT float dummyOut;\n"
485 "layout(set = 0, binding = 0, r32ui)" +
486 imageQualifiers +
487 "uniform uimage2D result;\n"
488 "\n"
489 "void main()\n"
490 "{\n"
491 << updateImageCaller << "}\n";
492
493 programCollection.glslSources.add("call")
494 << glu::CallableSource(updateRayTracingGLSL(css.str())) << buildOptions;
495 }
496
497 programCollection.glslSources.add("cal0")
498 << glu::CallableSource(updateRayTracingGLSL(calleeShader)) << buildOptions;
499
500 break;
501 }
502
503 default:
504 TCU_THROW(InternalError, "Unknown stage");
505 }
506 }
507
createInstance(Context & context) const508 TestInstance *RayTracingTestCase::createInstance(Context &context) const
509 {
510 return new RayTracingBuildTestInstance(context, m_data);
511 }
512
makePipeline(de::MovePtr<RayTracingPipeline> & rayTracingPipeline,VkPipelineLayout pipelineLayout)513 Move<VkPipeline> RayTracingBuildTestInstance::makePipeline(de::MovePtr<RayTracingPipeline> &rayTracingPipeline,
514 VkPipelineLayout pipelineLayout)
515 {
516 const DeviceInterface &vkd = m_context.getDeviceInterface();
517 const VkDevice device = m_context.getDevice();
518 vk::BinaryCollection &collection = m_context.getBinaryCollection();
519
520 if (0 != (m_shaders & VK_SHADER_STAGE_RAYGEN_BIT_KHR))
521 rayTracingPipeline->addShader(VK_SHADER_STAGE_RAYGEN_BIT_KHR,
522 createShaderModule(vkd, device, collection.get("rgen"), 0), m_raygenShaderGroup);
523 if (0 != (m_shaders & VK_SHADER_STAGE_ANY_HIT_BIT_KHR))
524 rayTracingPipeline->addShader(VK_SHADER_STAGE_ANY_HIT_BIT_KHR,
525 createShaderModule(vkd, device, collection.get("ahit"), 0), m_hitShaderGroup);
526 if (0 != (m_shaders & VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR))
527 rayTracingPipeline->addShader(VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR,
528 createShaderModule(vkd, device, collection.get("chit"), 0), m_hitShaderGroup);
529 if (0 != (m_shaders & VK_SHADER_STAGE_MISS_BIT_KHR))
530 rayTracingPipeline->addShader(VK_SHADER_STAGE_MISS_BIT_KHR,
531 createShaderModule(vkd, device, collection.get("miss"), 0), m_missShaderGroup);
532 if (0 != (m_shaders & VK_SHADER_STAGE_INTERSECTION_BIT_KHR))
533 rayTracingPipeline->addShader(VK_SHADER_STAGE_INTERSECTION_BIT_KHR,
534 createShaderModule(vkd, device, collection.get("sect"), 0), m_hitShaderGroup);
535 if (0 != (m_shaders & VK_SHADER_STAGE_CALLABLE_BIT_KHR))
536 rayTracingPipeline->addShader(VK_SHADER_STAGE_CALLABLE_BIT_KHR,
537 createShaderModule(vkd, device, collection.get("call"), 0),
538 m_callableShaderGroup + 1);
539 if (m_extraCallShaders)
540 rayTracingPipeline->addShader(VK_SHADER_STAGE_CALLABLE_BIT_KHR,
541 createShaderModule(vkd, device, collection.get("cal0"), 0),
542 m_callableShaderGroup);
543
544 Move<VkPipeline> pipeline = rayTracingPipeline->createPipeline(vkd, device, pipelineLayout);
545
546 return pipeline;
547 }
548
createShaderBindingTable(const InstanceInterface & vki,const DeviceInterface & vkd,const VkDevice device,const VkPhysicalDevice physicalDevice,const VkPipeline pipeline,Allocator & allocator,de::MovePtr<RayTracingPipeline> & rayTracingPipeline,const uint32_t group,const uint32_t groupCount)549 de::MovePtr<BufferWithMemory> RayTracingBuildTestInstance::createShaderBindingTable(
550 const InstanceInterface &vki, const DeviceInterface &vkd, const VkDevice device,
551 const VkPhysicalDevice physicalDevice, const VkPipeline pipeline, Allocator &allocator,
552 de::MovePtr<RayTracingPipeline> &rayTracingPipeline, const uint32_t group, const uint32_t groupCount)
553 {
554 de::MovePtr<BufferWithMemory> shaderBindingTable;
555
556 if (group < m_shaderGroupCount)
557 {
558 const uint32_t shaderGroupHandleSize = getShaderGroupSize(vki, physicalDevice);
559 const uint32_t shaderGroupBaseAlignment = getShaderGroupBaseAlignment(vki, physicalDevice);
560
561 shaderBindingTable = rayTracingPipeline->createShaderBindingTable(
562 vkd, device, pipeline, allocator, shaderGroupHandleSize, shaderGroupBaseAlignment, group, groupCount);
563 }
564
565 return shaderBindingTable;
566 }
567
initTopAccelerationStructure(VkCommandBuffer cmdBuffer,vector<de::SharedPtr<BottomLevelAccelerationStructure>> & bottomLevelAccelerationStructures)568 de::MovePtr<TopLevelAccelerationStructure> RayTracingBuildTestInstance::initTopAccelerationStructure(
569 VkCommandBuffer cmdBuffer,
570 vector<de::SharedPtr<BottomLevelAccelerationStructure>> &bottomLevelAccelerationStructures)
571 {
572 const DeviceInterface &vkd = m_context.getDeviceInterface();
573 const VkDevice device = m_context.getDevice();
574 Allocator &allocator = m_context.getDefaultAllocator();
575 de::MovePtr<TopLevelAccelerationStructure> result = makeTopLevelAccelerationStructure();
576
577 result->setInstanceCount(bottomLevelAccelerationStructures.size());
578
579 for (size_t structNdx = 0; structNdx < bottomLevelAccelerationStructures.size(); ++structNdx)
580 result->addInstance(bottomLevelAccelerationStructures[structNdx]);
581
582 result->createAndBuild(vkd, device, cmdBuffer, allocator);
583
584 return result;
585 }
586
initBottomAccelerationStructure(VkCommandBuffer cmdBuffer,tcu::UVec2 & startPos)587 de::MovePtr<BottomLevelAccelerationStructure> RayTracingBuildTestInstance::initBottomAccelerationStructure(
588 VkCommandBuffer cmdBuffer, tcu::UVec2 &startPos)
589 {
590 const DeviceInterface &vkd = m_context.getDeviceInterface();
591 const VkDevice device = m_context.getDevice();
592 Allocator &allocator = m_context.getDefaultAllocator();
593 de::MovePtr<BottomLevelAccelerationStructure> result = makeBottomLevelAccelerationStructure();
594
595 result->setGeometryCount(m_data.geometriesGroupCount);
596
597 for (size_t geometryNdx = 0; geometryNdx < m_data.geometriesGroupCount; ++geometryNdx)
598 {
599 const float z = (m_data.stage == VK_SHADER_STAGE_MISS_BIT_KHR) ? +1.0f : -1.0f;
600 std::vector<tcu::Vec3> geometryData;
601
602 geometryData.reserve(2u * m_data.squaresGroupCount);
603
604 for (size_t squareNdx = 0; squareNdx < m_data.squaresGroupCount; ++squareNdx)
605 {
606 const uint32_t n = m_data.width * startPos.y() + startPos.x();
607 const float x0 = float(startPos.x() + 0) / float(m_data.width);
608 const float y0 = float(startPos.y() + 0) / float(m_data.height);
609 const float x1 = float(startPos.x() + 1) / float(m_data.width);
610 const float y1 = float(startPos.y() + 1) / float(m_data.height);
611 const uint32_t m = (73 * (n + 1)) % (m_data.width * m_data.height);
612
613 geometryData.push_back(tcu::Vec3(x0, y0, z));
614 geometryData.push_back(tcu::Vec3(x1, y1, z));
615
616 startPos.y() = m / m_data.width;
617 startPos.x() = m % m_data.width;
618 }
619
620 result->addGeometry(geometryData, false);
621 }
622
623 result->createAndBuild(vkd, device, cmdBuffer, allocator);
624
625 return result;
626 }
627
initBottomAccelerationStructures(VkCommandBuffer cmdBuffer)628 vector<de::SharedPtr<BottomLevelAccelerationStructure>> RayTracingBuildTestInstance::initBottomAccelerationStructures(
629 VkCommandBuffer cmdBuffer)
630 {
631 tcu::UVec2 startPos;
632 vector<de::SharedPtr<BottomLevelAccelerationStructure>> result;
633
634 for (size_t instanceNdx = 0; instanceNdx < m_data.instancesGroupCount; ++instanceNdx)
635 {
636 de::MovePtr<BottomLevelAccelerationStructure> bottomLevelAccelerationStructure =
637 initBottomAccelerationStructure(cmdBuffer, startPos);
638
639 result.push_back(de::SharedPtr<BottomLevelAccelerationStructure>(bottomLevelAccelerationStructure.release()));
640 }
641
642 return result;
643 }
644
runTest(void)645 de::MovePtr<BufferWithMemory> RayTracingBuildTestInstance::runTest(void)
646 {
647 const InstanceInterface &vki = m_context.getInstanceInterface();
648 const DeviceInterface &vkd = m_context.getDeviceInterface();
649 const VkDevice device = m_context.getDevice();
650 const VkPhysicalDevice physicalDevice = m_context.getPhysicalDevice();
651 const uint32_t queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
652 const VkQueue queue = m_context.getUniversalQueue();
653 Allocator &allocator = m_context.getDefaultAllocator();
654 const VkFormat format = VK_FORMAT_R32_UINT;
655 const uint32_t pixelCount = m_data.width * m_data.height;
656 const uint32_t shaderGroupHandleSize = getShaderGroupSize(vki, physicalDevice);
657
658 const Move<VkDescriptorSetLayout> descriptorSetLayout =
659 DescriptorSetLayoutBuilder()
660 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, ALL_RAY_TRACING_STAGES)
661 .addSingleBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, ALL_RAY_TRACING_STAGES)
662 .build(vkd, device);
663 const Move<VkDescriptorPool> descriptorPool =
664 DescriptorPoolBuilder()
665 .addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE)
666 .addType(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR)
667 .build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
668 const Move<VkDescriptorSet> descriptorSet = makeDescriptorSet(vkd, device, *descriptorPool, *descriptorSetLayout);
669 const Move<VkPipelineLayout> pipelineLayout = makePipelineLayout(vkd, device, descriptorSetLayout.get());
670 const Move<VkCommandPool> cmdPool = createCommandPool(vkd, device, 0, queueFamilyIndex);
671 const Move<VkCommandBuffer> cmdBuffer =
672 allocateCommandBuffer(vkd, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
673
674 const uint32_t callableGroups = m_extraCallShaders + ((m_shaders & VK_SHADER_STAGE_CALLABLE_BIT_KHR) != 0 ? 1 : 0);
675 de::MovePtr<RayTracingPipeline> rayTracingPipeline = de::newMovePtr<RayTracingPipeline>();
676 const Move<VkPipeline> pipeline = makePipeline(rayTracingPipeline, *pipelineLayout);
677 const de::MovePtr<BufferWithMemory> raygenShaderBindingTable = createShaderBindingTable(
678 vki, vkd, device, physicalDevice, *pipeline, allocator, rayTracingPipeline, m_raygenShaderGroup);
679 const de::MovePtr<BufferWithMemory> missShaderBindingTable = createShaderBindingTable(
680 vki, vkd, device, physicalDevice, *pipeline, allocator, rayTracingPipeline, m_missShaderGroup);
681 const de::MovePtr<BufferWithMemory> hitShaderBindingTable = createShaderBindingTable(
682 vki, vkd, device, physicalDevice, *pipeline, allocator, rayTracingPipeline, m_hitShaderGroup);
683 const de::MovePtr<BufferWithMemory> callableShaderBindingTable =
684 createShaderBindingTable(vki, vkd, device, physicalDevice, *pipeline, allocator, rayTracingPipeline,
685 m_callableShaderGroup, callableGroups);
686
687 const VkStridedDeviceAddressRegionKHR raygenShaderBindingTableRegion =
688 raygenShaderBindingTable.get() != NULL ?
689 makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, raygenShaderBindingTable->get(), 0),
690 shaderGroupHandleSize, shaderGroupHandleSize) :
691 makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0);
692 const VkStridedDeviceAddressRegionKHR missShaderBindingTableRegion =
693 missShaderBindingTable.get() != NULL ?
694 makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, missShaderBindingTable->get(), 0),
695 shaderGroupHandleSize, shaderGroupHandleSize) :
696 makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0);
697 const VkStridedDeviceAddressRegionKHR hitShaderBindingTableRegion =
698 hitShaderBindingTable.get() != NULL ?
699 makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, hitShaderBindingTable->get(), 0),
700 shaderGroupHandleSize, shaderGroupHandleSize) :
701 makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0);
702 const VkStridedDeviceAddressRegionKHR callableShaderBindingTableRegion =
703 callableShaderBindingTable.get() != NULL ?
704 makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, callableShaderBindingTable->get(), 0),
705 shaderGroupHandleSize, shaderGroupHandleSize * callableGroups) :
706 makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0);
707
708 const VkImageCreateInfo imageCreateInfo = makeImageCreateInfo(m_data.width, m_data.height, format);
709 const VkImageSubresourceRange imageSubresourceRange =
710 makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0, 1u);
711 const de::MovePtr<ImageWithMemory> image = de::MovePtr<ImageWithMemory>(
712 new ImageWithMemory(vkd, device, allocator, imageCreateInfo, MemoryRequirement::Any));
713 const Move<VkImageView> imageView =
714 makeImageView(vkd, device, **image, VK_IMAGE_VIEW_TYPE_2D, format, imageSubresourceRange);
715
716 const VkBufferCreateInfo bufferCreateInfo =
717 makeBufferCreateInfo(pixelCount * sizeof(uint32_t), VK_BUFFER_USAGE_TRANSFER_DST_BIT);
718 const VkImageSubresourceLayers bufferImageSubresourceLayers =
719 makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u);
720 const VkBufferImageCopy bufferImageRegion =
721 makeBufferImageCopy(makeExtent3D(m_data.width, m_data.height, 1u), bufferImageSubresourceLayers);
722 de::MovePtr<BufferWithMemory> buffer = de::MovePtr<BufferWithMemory>(
723 new BufferWithMemory(vkd, device, allocator, bufferCreateInfo, MemoryRequirement::HostVisible));
724
725 const VkDescriptorImageInfo descriptorImageInfo =
726 makeDescriptorImageInfo(DE_NULL, *imageView, VK_IMAGE_LAYOUT_GENERAL);
727
728 const VkImageMemoryBarrier preImageBarrier =
729 makeImageMemoryBarrier(0u, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
730 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, **image, imageSubresourceRange);
731 const VkImageMemoryBarrier postImageBarrier = makeImageMemoryBarrier(
732 VK_ACCESS_TRANSFER_WRITE_BIT,
733 VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR | VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR,
734 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL, **image, imageSubresourceRange);
735 const VkMemoryBarrier postTraceMemoryBarrier =
736 makeMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT);
737 const VkMemoryBarrier postCopyMemoryBarrier =
738 makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
739 const VkClearValue clearValue = makeClearValueColorU32(1000000u, 0u, 0u, 255u);
740
741 vector<de::SharedPtr<BottomLevelAccelerationStructure>> bottomLevelAccelerationStructures;
742 de::MovePtr<TopLevelAccelerationStructure> topLevelAccelerationStructure;
743
744 beginCommandBuffer(vkd, *cmdBuffer, 0u);
745 {
746 cmdPipelineImageMemoryBarrier(vkd, *cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
747 VK_PIPELINE_STAGE_TRANSFER_BIT, &preImageBarrier);
748 vkd.cmdClearColorImage(*cmdBuffer, **image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clearValue.color, 1,
749 &imageSubresourceRange);
750 cmdPipelineImageMemoryBarrier(vkd, *cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT,
751 VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR, &postImageBarrier);
752
753 bottomLevelAccelerationStructures = initBottomAccelerationStructures(*cmdBuffer);
754 topLevelAccelerationStructure = initTopAccelerationStructure(*cmdBuffer, bottomLevelAccelerationStructures);
755
756 const TopLevelAccelerationStructure *topLevelAccelerationStructurePtr = topLevelAccelerationStructure.get();
757 VkWriteDescriptorSetAccelerationStructureKHR accelerationStructureWriteDescriptorSet = {
758 VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR, // VkStructureType sType;
759 DE_NULL, // const void* pNext;
760 1u, // uint32_t accelerationStructureCount;
761 topLevelAccelerationStructurePtr->getPtr(), // const VkAccelerationStructureKHR* pAccelerationStructures;
762 };
763
764 DescriptorSetUpdateBuilder()
765 .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u),
766 VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &descriptorImageInfo)
767 .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u),
768 VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, &accelerationStructureWriteDescriptorSet)
769 .update(vkd, device);
770
771 vkd.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, *pipelineLayout, 0, 1,
772 &descriptorSet.get(), 0, DE_NULL);
773
774 vkd.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, *pipeline);
775
776 cmdTraceRays(vkd, *cmdBuffer, &raygenShaderBindingTableRegion, &missShaderBindingTableRegion,
777 &hitShaderBindingTableRegion, &callableShaderBindingTableRegion, m_data.width, m_data.height, 1);
778
779 cmdPipelineMemoryBarrier(vkd, *cmdBuffer, VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR,
780 VK_PIPELINE_STAGE_TRANSFER_BIT, &postTraceMemoryBarrier);
781
782 vkd.cmdCopyImageToBuffer(*cmdBuffer, **image, VK_IMAGE_LAYOUT_GENERAL, **buffer, 1u, &bufferImageRegion);
783
784 cmdPipelineMemoryBarrier(vkd, *cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT,
785 &postCopyMemoryBarrier);
786 }
787 endCommandBuffer(vkd, *cmdBuffer);
788
789 submitCommandsAndWait(vkd, device, queue, cmdBuffer.get());
790
791 invalidateMappedMemoryRange(vkd, device, buffer->getAllocation().getMemory(), buffer->getAllocation().getOffset(),
792 pixelCount * sizeof(uint32_t));
793
794 return buffer;
795 }
796
checkSupportInInstance(void) const797 void RayTracingBuildTestInstance::checkSupportInInstance(void) const
798 {
799 const InstanceInterface &vki = m_context.getInstanceInterface();
800 const VkPhysicalDevice physicalDevice = m_context.getPhysicalDevice();
801 const vk::VkPhysicalDeviceProperties &properties = m_context.getDeviceProperties();
802 const uint32_t requiredAllocations =
803 8u + TopLevelAccelerationStructure::getRequiredAllocationCount() +
804 m_data.instancesGroupCount * BottomLevelAccelerationStructure::getRequiredAllocationCount();
805 de::MovePtr<RayTracingProperties> rayTracingProperties = makeRayTracingProperties(vki, physicalDevice);
806
807 if (rayTracingProperties->getMaxPrimitiveCount() < m_data.squaresGroupCount)
808 TCU_THROW(NotSupportedError, "Triangles required more than supported");
809
810 if (rayTracingProperties->getMaxGeometryCount() < m_data.geometriesGroupCount)
811 TCU_THROW(NotSupportedError, "Geometries required more than supported");
812
813 if (rayTracingProperties->getMaxInstanceCount() < m_data.instancesGroupCount)
814 TCU_THROW(NotSupportedError, "Instances required more than supported");
815
816 if (properties.limits.maxMemoryAllocationCount < requiredAllocations)
817 TCU_THROW(NotSupportedError, "Test requires more allocations allowed");
818 }
819
iterate(void)820 tcu::TestStatus RayTracingBuildTestInstance::iterate(void)
821 {
822 checkSupportInInstance();
823
824 const de::MovePtr<BufferWithMemory> buffer = runTest();
825 const uint32_t *bufferPtr = (uint32_t *)buffer->getAllocation().getHostPtr();
826 uint32_t failures = 0;
827 uint32_t pos = 0;
828
829 for (uint32_t y = 0; y < m_data.height; ++y)
830 {
831 for (uint32_t x = 0; x < m_data.width; ++x)
832 {
833 const uint32_t expectedValue = pos + 1;
834
835 if (bufferPtr[pos] != expectedValue)
836 failures++;
837
838 ++pos;
839 }
840 }
841
842 if (failures == 0)
843 return tcu::TestStatus::pass("Pass");
844 else
845 return tcu::TestStatus::fail("failures=" + de::toString(failures));
846 }
847
848 } // namespace
createMemGuaranteeTests(tcu::TestContext & testCtx)849 tcu::TestCaseGroup *createMemGuaranteeTests(tcu::TestContext &testCtx)
850 {
851 static const struct
852 {
853 const char *name;
854 VkShaderStageFlagBits stage;
855 } stages[]{
856 {"rgen", VK_SHADER_STAGE_RAYGEN_BIT_KHR}, {"chit", VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR},
857 {"sect", VK_SHADER_STAGE_INTERSECTION_BIT_KHR}, {"miss", VK_SHADER_STAGE_MISS_BIT_KHR},
858 {"call", VK_SHADER_STAGE_CALLABLE_BIT_KHR},
859 };
860
861 static const struct
862 {
863 const char *name;
864 TestType testType;
865 } testTypes[]{
866 {"inside", TEST_TYPE_INSIDE_STAGE},
867 {"between", TEST_TYPE_BETWEEN_STAGES},
868 };
869
870 // Ray tracing memory guarantee tests
871 de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "memguarantee"));
872
873 for (size_t testTypeNdx = 0; testTypeNdx < DE_LENGTH_OF_ARRAY(testTypes); ++testTypeNdx)
874 {
875 de::MovePtr<tcu::TestCaseGroup> testTypeGroup(new tcu::TestCaseGroup(testCtx, testTypes[testTypeNdx].name));
876
877 for (size_t stagesNdx = 0; stagesNdx < DE_LENGTH_OF_ARRAY(stages); ++stagesNdx)
878 {
879 const uint32_t width = 16u;
880 const uint32_t height = 16u;
881 const uint32_t geometriesGroupCount = 4;
882 const uint32_t instancesGroupCount = 8;
883 const uint32_t squaresGroupCount = width * height / geometriesGroupCount / instancesGroupCount;
884 const CaseDef caseDef = {
885 testTypes[testTypeNdx].testType, // TestType testType;
886 stages[stagesNdx].stage, // VkShaderStageFlagBits stage;
887 width, // uint32_t width;
888 height, // uint32_t height;
889 squaresGroupCount, // uint32_t squaresGroupCount;
890 geometriesGroupCount, // uint32_t geometriesGroupCount;
891 instancesGroupCount, // uint32_t instancesGroupCount;
892 };
893 const std::string testName = de::toString(stages[stagesNdx].name);
894
895 testTypeGroup->addChild(new RayTracingTestCase(testCtx, testName.c_str(), caseDef));
896 }
897
898 group->addChild(testTypeGroup.release());
899 }
900
901 return group.release();
902 }
903
904 } // namespace RayTracing
905 } // namespace vkt
906