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 Testing traversal control in ray tracing shaders
22 *//*--------------------------------------------------------------------*/
23
24 #include "vktRayTracingTraversalControlTests.hpp"
25
26 #include "vkDefs.hpp"
27
28 #include "vktTestCase.hpp"
29 #include "vktTestGroupUtil.hpp"
30 #include "vkCmdUtil.hpp"
31 #include "vkObjUtil.hpp"
32 #include "vkBuilderUtil.hpp"
33 #include "vkBarrierUtil.hpp"
34 #include "vkBufferWithMemory.hpp"
35 #include "vkImageWithMemory.hpp"
36 #include "vkTypeUtil.hpp"
37 #include "vkImageUtil.hpp"
38 #include "deRandom.hpp"
39 #include "tcuTexture.hpp"
40 #include "tcuTextureUtil.hpp"
41 #include "tcuTestLog.hpp"
42 #include "tcuImageCompare.hpp"
43
44 #include "vkRayTracingUtil.hpp"
45
46 namespace vkt
47 {
48 namespace RayTracing
49 {
50 namespace
51 {
52 using namespace vk;
53 using namespace vkt;
54
55 static const VkFlags ALL_RAY_TRACING_STAGES = VK_SHADER_STAGE_RAYGEN_BIT_KHR
56 | VK_SHADER_STAGE_ANY_HIT_BIT_KHR
57 | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR
58 | VK_SHADER_STAGE_MISS_BIT_KHR
59 | VK_SHADER_STAGE_INTERSECTION_BIT_KHR
60 | VK_SHADER_STAGE_CALLABLE_BIT_KHR;
61
62 enum HitShaderTestType
63 {
64 HSTT_ISECT_REPORT_INTERSECTION = 0,
65 HSTT_ISECT_DONT_REPORT_INTERSECTION = 1,
66 HSTT_AHIT_PASS_THROUGH = 2,
67 HSTT_AHIT_IGNORE_INTERSECTION = 3,
68 HSTT_AHIT_TERMINATE_RAY = 4,
69 HSTT_COUNT
70 };
71
72 enum BottomTestType
73 {
74 BTT_TRIANGLES,
75 BTT_AABBS
76 };
77
78 const deUint32 TEST_WIDTH = 8;
79 const deUint32 TEST_HEIGHT = 8;
80
81 struct TestParams;
82
83 class TestConfiguration
84 {
85 public:
86 virtual std::vector<de::SharedPtr<BottomLevelAccelerationStructure>> initBottomAccelerationStructures (Context& context,
87 TestParams& testParams) = 0;
88 virtual de::MovePtr<TopLevelAccelerationStructure> initTopAccelerationStructure (Context& context,
89 TestParams& testParams,
90 std::vector<de::SharedPtr<BottomLevelAccelerationStructure> >& bottomLevelAccelerationStructures) = 0;
91 virtual void initRayTracingShaders (de::MovePtr<RayTracingPipeline>& rayTracingPipeline,
92 Context& context,
93 TestParams& testParams) = 0;
94 virtual void initShaderBindingTables (de::MovePtr<RayTracingPipeline>& rayTracingPipeline,
95 Context& context,
96 TestParams& testParams,
97 VkPipeline pipeline,
98 deUint32 shaderGroupHandleSize,
99 deUint32 shaderGroupBaseAlignment,
100 de::MovePtr<BufferWithMemory>& raygenShaderBindingTable,
101 de::MovePtr<BufferWithMemory>& hitShaderBindingTable,
102 de::MovePtr<BufferWithMemory>& missShaderBindingTable,
103 de::MovePtr<BufferWithMemory>& callableShaderBindingTable,
104 VkStridedDeviceAddressRegionKHR& raygenShaderBindingTableRegion,
105 VkStridedDeviceAddressRegionKHR& hitShaderBindingTableRegion,
106 VkStridedDeviceAddressRegionKHR& missShaderBindingTableRegion,
107 VkStridedDeviceAddressRegionKHR& callableShaderBindingTableRegion) = 0;
108 virtual bool verifyImage (BufferWithMemory* resultBuffer,
109 Context& context,
110 TestParams& testParams) = 0;
111 virtual VkFormat getResultImageFormat () = 0;
112 virtual size_t getResultImageFormatSize () = 0;
113 virtual VkClearValue getClearValue () = 0;
114 };
115
116 struct TestParams
117 {
118 deUint32 width;
119 deUint32 height;
120 HitShaderTestType hitShaderTestType;
121 BottomTestType bottomType;
122 de::SharedPtr<TestConfiguration> testConfiguration;
123
124 };
125
getShaderGroupHandleSize(const InstanceInterface & vki,const VkPhysicalDevice physicalDevice)126 deUint32 getShaderGroupHandleSize (const InstanceInterface& vki,
127 const VkPhysicalDevice physicalDevice)
128 {
129 de::MovePtr<RayTracingProperties> rayTracingPropertiesKHR;
130
131 rayTracingPropertiesKHR = makeRayTracingProperties(vki, physicalDevice);
132 return rayTracingPropertiesKHR->getShaderGroupHandleSize();
133 }
134
getShaderGroupBaseAlignment(const InstanceInterface & vki,const VkPhysicalDevice physicalDevice)135 deUint32 getShaderGroupBaseAlignment (const InstanceInterface& vki,
136 const VkPhysicalDevice physicalDevice)
137 {
138 de::MovePtr<RayTracingProperties> rayTracingPropertiesKHR;
139
140 rayTracingPropertiesKHR = makeRayTracingProperties(vki, physicalDevice);
141 return rayTracingPropertiesKHR->getShaderGroupBaseAlignment();
142 }
143
makeImageCreateInfo(deUint32 width,deUint32 height,deUint32 depth,VkFormat format)144 VkImageCreateInfo makeImageCreateInfo (deUint32 width, deUint32 height, deUint32 depth, VkFormat format)
145 {
146 const VkImageCreateInfo imageCreateInfo =
147 {
148 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
149 DE_NULL, // const void* pNext;
150 (VkImageCreateFlags)0u, // VkImageCreateFlags flags;
151 VK_IMAGE_TYPE_3D, // VkImageType imageType;
152 format, // VkFormat format;
153 makeExtent3D(width, height, depth), // VkExtent3D extent;
154 1u, // deUint32 mipLevels;
155 1u, // deUint32 arrayLayers;
156 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
157 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
158 VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, // VkImageUsageFlags usage;
159 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
160 0u, // deUint32 queueFamilyIndexCount;
161 DE_NULL, // const deUint32* pQueueFamilyIndices;
162 VK_IMAGE_LAYOUT_UNDEFINED // VkImageLayout initialLayout;
163 };
164
165 return imageCreateInfo;
166 }
167
168 class SingleSquareConfiguration : public TestConfiguration
169 {
170 public:
171 std::vector<de::SharedPtr<BottomLevelAccelerationStructure>> initBottomAccelerationStructures (Context& context,
172 TestParams& testParams) override;
173 de::MovePtr<TopLevelAccelerationStructure> initTopAccelerationStructure (Context& context,
174 TestParams& testParams,
175 std::vector<de::SharedPtr<BottomLevelAccelerationStructure> >& bottomLevelAccelerationStructures) override;
176 void initRayTracingShaders (de::MovePtr<RayTracingPipeline>& rayTracingPipeline,
177 Context& context,
178 TestParams& testParams) override;
179 void initShaderBindingTables (de::MovePtr<RayTracingPipeline>& rayTracingPipeline,
180 Context& context,
181 TestParams& testParams,
182 VkPipeline pipeline,
183 deUint32 shaderGroupHandleSize,
184 deUint32 shaderGroupBaseAlignment,
185 de::MovePtr<BufferWithMemory>& raygenShaderBindingTable,
186 de::MovePtr<BufferWithMemory>& hitShaderBindingTable,
187 de::MovePtr<BufferWithMemory>& missShaderBindingTable,
188 de::MovePtr<BufferWithMemory>& callableShaderBindingTable,
189 VkStridedDeviceAddressRegionKHR& raygenShaderBindingTableRegion,
190 VkStridedDeviceAddressRegionKHR& hitShaderBindingTableRegion,
191 VkStridedDeviceAddressRegionKHR& missShaderBindingTableRegion,
192 VkStridedDeviceAddressRegionKHR& callableShaderBindingTableRegion) override;
193 bool verifyImage (BufferWithMemory* resultBuffer,
194 Context& context,
195 TestParams& testParams) override;
196 VkFormat getResultImageFormat () override;
197 size_t getResultImageFormatSize () override;
198 VkClearValue getClearValue () override;
199 };
200
initBottomAccelerationStructures(Context & context,TestParams & testParams)201 std::vector<de::SharedPtr<BottomLevelAccelerationStructure> > SingleSquareConfiguration::initBottomAccelerationStructures (Context& context,
202 TestParams& testParams)
203 {
204 DE_UNREF(context);
205
206 std::vector<de::SharedPtr<BottomLevelAccelerationStructure> > result;
207 de::MovePtr<BottomLevelAccelerationStructure> bottomLevelAccelerationStructure = makeBottomLevelAccelerationStructure();
208 bottomLevelAccelerationStructure->setGeometryCount(1);
209
210 de::SharedPtr<RaytracedGeometryBase> geometry;
211 if (testParams.bottomType == BTT_TRIANGLES)
212 {
213 tcu::Vec3 v0(1.0f, float(testParams.height) - 1.0f, 0.0f);
214 tcu::Vec3 v1(1.0f, 1.0f, 0.0f);
215 tcu::Vec3 v2(float(testParams.width) - 1.0f, float(testParams.height) - 1.0f, 0.0f);
216 tcu::Vec3 v3(float(testParams.width) - 1.0f, 1.0f, 0.0f);
217
218 geometry = makeRaytracedGeometry(VK_GEOMETRY_TYPE_TRIANGLES_KHR, VK_FORMAT_R32G32B32_SFLOAT, VK_INDEX_TYPE_NONE_KHR);
219 geometry->addVertex(v0);
220 geometry->addVertex(v1);
221 geometry->addVertex(v2);
222 geometry->addVertex(v2);
223 geometry->addVertex(v1);
224 geometry->addVertex(v3);
225 }
226 else // testParams.bottomType != BTT_TRIANGLES
227 {
228 tcu::Vec3 v0(1.0f, 1.0f, -0.1f);
229 tcu::Vec3 v1(float(testParams.width) - 1.0f, float(testParams.height) - 1.0f, 0.1f);
230
231 geometry = makeRaytracedGeometry(VK_GEOMETRY_TYPE_AABBS_KHR, VK_FORMAT_R32G32B32_SFLOAT, VK_INDEX_TYPE_NONE_KHR);
232 geometry->addVertex(v0);
233 geometry->addVertex(v1);
234 }
235 bottomLevelAccelerationStructure->addGeometry(geometry);
236
237 result.push_back(de::SharedPtr<BottomLevelAccelerationStructure>(bottomLevelAccelerationStructure.release()));
238
239 return result;
240 }
241
initTopAccelerationStructure(Context & context,TestParams & testParams,std::vector<de::SharedPtr<BottomLevelAccelerationStructure>> & bottomLevelAccelerationStructures)242 de::MovePtr<TopLevelAccelerationStructure> SingleSquareConfiguration::initTopAccelerationStructure (Context& context,
243 TestParams& testParams,
244 std::vector<de::SharedPtr<BottomLevelAccelerationStructure> >& bottomLevelAccelerationStructures)
245 {
246 DE_UNREF(context);
247 DE_UNREF(testParams);
248
249 de::MovePtr<TopLevelAccelerationStructure> result = makeTopLevelAccelerationStructure();
250 result->setInstanceCount(1);
251 result->addInstance(bottomLevelAccelerationStructures[0]);
252
253 return result;
254 }
255
initRayTracingShaders(de::MovePtr<RayTracingPipeline> & rayTracingPipeline,Context & context,TestParams & testParams)256 void SingleSquareConfiguration::initRayTracingShaders (de::MovePtr<RayTracingPipeline>& rayTracingPipeline,
257 Context& context,
258 TestParams& testParams)
259 {
260 const DeviceInterface& vkd = context.getDeviceInterface();
261 const VkDevice device = context.getDevice();
262
263 const std::vector<std::vector<std::string>> shaderNames =
264 {
265 { "rgen", "isect_report", "ahit", "chit", "miss" },
266 { "rgen", "isect_pass_through", "ahit", "chit", "miss" },
267 { "rgen", "isect_report", "ahit_pass_through", "chit", "miss" },
268 { "rgen", "isect_report", "ahit_ignore", "chit", "miss" },
269 { "rgen", "isect_report", "ahit_terminate", "chit", "miss" },
270 };
271 rayTracingPipeline->addShader(VK_SHADER_STAGE_RAYGEN_BIT_KHR, createShaderModule(vkd, device, context.getBinaryCollection().get(shaderNames[testParams.hitShaderTestType][0]), 0), 0);
272 if(testParams.bottomType == BTT_AABBS)
273 rayTracingPipeline->addShader(VK_SHADER_STAGE_INTERSECTION_BIT_KHR, createShaderModule(vkd, device, context.getBinaryCollection().get(shaderNames[testParams.hitShaderTestType][1]), 0), 1);
274 rayTracingPipeline->addShader(VK_SHADER_STAGE_ANY_HIT_BIT_KHR, createShaderModule(vkd, device, context.getBinaryCollection().get(shaderNames[testParams.hitShaderTestType][2]), 0), 1);
275 rayTracingPipeline->addShader(VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR, createShaderModule(vkd, device, context.getBinaryCollection().get(shaderNames[testParams.hitShaderTestType][3]), 0), 1);
276 rayTracingPipeline->addShader(VK_SHADER_STAGE_MISS_BIT_KHR, createShaderModule(vkd, device, context.getBinaryCollection().get(shaderNames[testParams.hitShaderTestType][4]), 0), 2);
277 }
278
initShaderBindingTables(de::MovePtr<RayTracingPipeline> & rayTracingPipeline,Context & context,TestParams & testParams,VkPipeline pipeline,deUint32 shaderGroupHandleSize,deUint32 shaderGroupBaseAlignment,de::MovePtr<BufferWithMemory> & raygenShaderBindingTable,de::MovePtr<BufferWithMemory> & hitShaderBindingTable,de::MovePtr<BufferWithMemory> & missShaderBindingTable,de::MovePtr<BufferWithMemory> & callableShaderBindingTable,VkStridedDeviceAddressRegionKHR & raygenShaderBindingTableRegion,VkStridedDeviceAddressRegionKHR & hitShaderBindingTableRegion,VkStridedDeviceAddressRegionKHR & missShaderBindingTableRegion,VkStridedDeviceAddressRegionKHR & callableShaderBindingTableRegion)279 void SingleSquareConfiguration::initShaderBindingTables (de::MovePtr<RayTracingPipeline>& rayTracingPipeline,
280 Context& context,
281 TestParams& testParams,
282 VkPipeline pipeline,
283 deUint32 shaderGroupHandleSize,
284 deUint32 shaderGroupBaseAlignment,
285 de::MovePtr<BufferWithMemory>& raygenShaderBindingTable,
286 de::MovePtr<BufferWithMemory>& hitShaderBindingTable,
287 de::MovePtr<BufferWithMemory>& missShaderBindingTable,
288 de::MovePtr<BufferWithMemory>& callableShaderBindingTable,
289 VkStridedDeviceAddressRegionKHR& raygenShaderBindingTableRegion,
290 VkStridedDeviceAddressRegionKHR& hitShaderBindingTableRegion,
291 VkStridedDeviceAddressRegionKHR& missShaderBindingTableRegion,
292 VkStridedDeviceAddressRegionKHR& callableShaderBindingTableRegion)
293 {
294 DE_UNREF(testParams);
295 DE_UNREF(callableShaderBindingTable);
296
297 const DeviceInterface& vkd = context.getDeviceInterface();
298 const VkDevice device = context.getDevice();
299 Allocator& allocator = context.getDefaultAllocator();
300
301 raygenShaderBindingTable = rayTracingPipeline->createShaderBindingTable(vkd, device, pipeline, allocator, shaderGroupHandleSize, shaderGroupBaseAlignment, 0, 1);
302 hitShaderBindingTable = rayTracingPipeline->createShaderBindingTable(vkd, device, pipeline, allocator, shaderGroupHandleSize, shaderGroupBaseAlignment, 1, 1);
303 missShaderBindingTable = rayTracingPipeline->createShaderBindingTable(vkd, device, pipeline, allocator, shaderGroupHandleSize, shaderGroupBaseAlignment, 2, 1);
304
305 raygenShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, raygenShaderBindingTable->get(), 0), shaderGroupHandleSize, shaderGroupHandleSize);
306 hitShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, hitShaderBindingTable->get(), 0), shaderGroupHandleSize, shaderGroupHandleSize);
307 missShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, missShaderBindingTable->get(), 0), shaderGroupHandleSize, shaderGroupHandleSize);
308 callableShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0);
309 }
310
verifyImage(BufferWithMemory * resultBuffer,Context & context,TestParams & testParams)311 bool SingleSquareConfiguration::verifyImage (BufferWithMemory* resultBuffer, Context& context, TestParams& testParams)
312 {
313 // create result image
314 tcu::TextureFormat imageFormat = vk::mapVkFormat(getResultImageFormat());
315 tcu::ConstPixelBufferAccess resultAccess(imageFormat, testParams.width, testParams.height, 2, resultBuffer->getAllocation().getHostPtr());
316
317 // create reference image
318 std::vector<deUint32> reference(testParams.width * testParams.height * 2);
319 tcu::PixelBufferAccess referenceAccess(imageFormat, testParams.width, testParams.height, 2, reference.data());
320
321 // clear reference image with hit and miss values
322 // Reference image has two layers:
323 // - ahit shader writes results to layer 0
324 // - chit shader writes results to layer 1
325 // - miss shader writes results to layer 0
326 // - rays that missed on layer 0 - should have value 0 on layer 1
327 tcu::UVec4 missValue0 = tcu::UVec4(4, 0, 0, 0);
328 tcu::UVec4 missValue1 = tcu::UVec4(0, 0, 0, 0);
329 tcu::UVec4 hitValue0, hitValue1;
330 switch (testParams.hitShaderTestType)
331 {
332 case HSTT_ISECT_REPORT_INTERSECTION:
333 hitValue0 = tcu::UVec4(1, 0, 0, 0); // ahit returns 1
334 hitValue1 = tcu::UVec4(3, 0, 0, 0); // chit returns 3
335 break;
336 case HSTT_ISECT_DONT_REPORT_INTERSECTION:
337 hitValue0 = missValue0; // no ahit - results should report miss value
338 hitValue1 = missValue1; // no chit - results should report miss value
339 break;
340 case HSTT_AHIT_PASS_THROUGH:
341 hitValue0 = tcu::UVec4(0, 0, 0, 0); // empty ahit shader. Initial value from rgen written to result
342 hitValue1 = tcu::UVec4(3, 0, 0, 0); // chit returns 3
343 break;
344 case HSTT_AHIT_IGNORE_INTERSECTION:
345 hitValue0 = missValue0; // ahit ignores intersection - results should report miss value
346 hitValue1 = missValue1; // no chit - results should report miss value
347 break;
348 case HSTT_AHIT_TERMINATE_RAY:
349 hitValue0 = tcu::UVec4(1, 0, 0, 0); // ahit should return 1. If it returned 2, then terminateRayEXT did not terminate ahit shader
350 hitValue1 = tcu::UVec4(3, 0, 0, 0); // chit returns 3
351 break;
352 default:
353 TCU_THROW(InternalError, "Wrong shader test type");
354 }
355
356 tcu::clear(referenceAccess, missValue0);
357 for (deUint32 y = 0; y < testParams.width; ++y)
358 for (deUint32 x = 0; x < testParams.height; ++x)
359 referenceAccess.setPixel(missValue1, x, y, 1);
360
361 for (deUint32 y = 1; y < testParams.width - 1; ++y)
362 for (deUint32 x = 1; x < testParams.height - 1; ++x)
363 {
364 referenceAccess.setPixel(hitValue0, x, y, 0);
365 referenceAccess.setPixel(hitValue1, x, y, 1);
366 }
367
368 // compare result and reference
369 return tcu::intThresholdCompare(context.getTestContext().getLog(), "Result comparison", "", referenceAccess, resultAccess, tcu::UVec4(0), tcu::COMPARE_LOG_RESULT);
370 }
371
getResultImageFormat()372 VkFormat SingleSquareConfiguration::getResultImageFormat ()
373 {
374 return VK_FORMAT_R32_UINT;
375 }
376
getResultImageFormatSize()377 size_t SingleSquareConfiguration::getResultImageFormatSize ()
378 {
379 return sizeof(deUint32);
380 }
381
getClearValue()382 VkClearValue SingleSquareConfiguration::getClearValue ()
383 {
384 return makeClearValueColorU32(0xFF, 0u, 0u, 0u);
385 }
386
387 class TraversalControlTestCase : public TestCase
388 {
389 public:
390 TraversalControlTestCase (tcu::TestContext& context, const char* name, const char* desc, const TestParams data);
391 ~TraversalControlTestCase (void);
392
393 virtual void checkSupport (Context& context) const;
394 virtual void initPrograms (SourceCollections& programCollection) const;
395 virtual TestInstance* createInstance (Context& context) const;
396 private:
397 TestParams m_data;
398 };
399
400 class TraversalControlTestInstance : public TestInstance
401 {
402 public:
403 TraversalControlTestInstance (Context& context, const TestParams& data);
404 ~TraversalControlTestInstance (void);
405 tcu::TestStatus iterate (void);
406
407 protected:
408 de::MovePtr<BufferWithMemory> runTest ();
409 private:
410 TestParams m_data;
411 };
412
TraversalControlTestCase(tcu::TestContext & context,const char * name,const char * desc,const TestParams data)413 TraversalControlTestCase::TraversalControlTestCase (tcu::TestContext& context, const char* name, const char* desc, const TestParams data)
414 : vkt::TestCase (context, name, desc)
415 , m_data (data)
416 {
417 }
418
~TraversalControlTestCase(void)419 TraversalControlTestCase::~TraversalControlTestCase (void)
420 {
421 }
422
checkSupport(Context & context) const423 void TraversalControlTestCase::checkSupport (Context& context) const
424 {
425 context.requireDeviceFunctionality("VK_KHR_acceleration_structure");
426 context.requireDeviceFunctionality("VK_KHR_ray_tracing_pipeline");
427
428 const VkPhysicalDeviceRayTracingPipelineFeaturesKHR& rayTracingPipelineFeaturesKHR = context.getRayTracingPipelineFeatures();
429 if (rayTracingPipelineFeaturesKHR.rayTracingPipeline == DE_FALSE )
430 TCU_THROW(NotSupportedError, "Requires VkPhysicalDeviceRayTracingPipelineFeaturesKHR.rayTracingPipeline");
431
432 const VkPhysicalDeviceAccelerationStructureFeaturesKHR& accelerationStructureFeaturesKHR = context.getAccelerationStructureFeatures();
433 if (accelerationStructureFeaturesKHR.accelerationStructure == DE_FALSE)
434 TCU_THROW(TestError, "VK_KHR_ray_tracing_pipeline requires VkPhysicalDeviceAccelerationStructureFeaturesKHR.accelerationStructure");
435 }
436
initPrograms(SourceCollections & programCollection) const437 void TraversalControlTestCase::initPrograms (SourceCollections& programCollection) const
438 {
439 const vk::ShaderBuildOptions buildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_4, 0u, true);
440 {
441 std::stringstream css;
442 css <<
443 "#version 460 core\n"
444 "#extension GL_EXT_ray_tracing : require\n"
445 "layout(location = 0) rayPayloadEXT uvec4 hitValue;\n"
446 "layout(r32ui, set = 0, binding = 0) uniform uimage3D result;\n"
447 "layout(set = 0, binding = 1) uniform accelerationStructureEXT topLevelAS;\n"
448 "\n"
449 "void main()\n"
450 "{\n"
451 " float tmin = 0.0;\n"
452 " float tmax = 1.0;\n"
453 " vec3 origin = vec3(float(gl_LaunchIDEXT.x) + 0.5f, float(gl_LaunchIDEXT.y) + 0.5f, 0.5f);\n"
454 " vec3 direct = vec3(0.0, 0.0, -1.0);\n"
455 " hitValue = uvec4(0,0,0,0);\n"
456 " traceRayEXT(topLevelAS, 0, 0xFF, 0, 0, 0, origin, tmin, direct, tmax, 0);\n"
457 " imageStore(result, ivec3(gl_LaunchIDEXT.xy, 0), uvec4(hitValue.x, 0, 0, 0));\n"
458 " imageStore(result, ivec3(gl_LaunchIDEXT.xy, 1), uvec4(hitValue.y, 0, 0, 0));\n"
459 "}\n";
460 programCollection.glslSources.add("rgen") << glu::RaygenSource(updateRayTracingGLSL(css.str())) << buildOptions;
461 }
462
463 {
464 std::stringstream css;
465 css <<
466 "#version 460 core\n"
467 "#extension GL_EXT_ray_tracing : require\n"
468 "hitAttributeEXT uvec4 hitAttribute;\n"
469 "void main()\n"
470 "{\n"
471 " hitAttribute = uvec4(0,0,0,0);\n"
472 " reportIntersectionEXT(0.5f, 0);\n"
473 "}\n";
474
475 programCollection.glslSources.add("isect_report") << glu::IntersectionSource(updateRayTracingGLSL(css.str())) << buildOptions;
476 }
477
478 {
479 std::stringstream css;
480 css <<
481 "#version 460 core\n"
482 "#extension GL_EXT_ray_tracing : require\n"
483 "void main()\n"
484 "{\n"
485 "}\n";
486
487 programCollection.glslSources.add("isect_pass_through") << glu::IntersectionSource(updateRayTracingGLSL(css.str())) << buildOptions;
488 }
489
490 {
491 std::stringstream css;
492 css <<
493 "#version 460 core\n"
494 "#extension GL_EXT_ray_tracing : require\n"
495 "layout(location = 0) rayPayloadInEXT uvec4 hitValue;\n"
496 "void main()\n"
497 "{\n"
498 " hitValue.x = 1;\n"
499 "}\n";
500
501 programCollection.glslSources.add("ahit") << glu::AnyHitSource(updateRayTracingGLSL(css.str())) << buildOptions;
502 }
503
504 {
505 std::stringstream css;
506 css <<
507 "#version 460 core\n"
508 "#extension GL_EXT_ray_tracing : require\n"
509 "void main()\n"
510 "{\n"
511 "}\n";
512
513 programCollection.glslSources.add("ahit_pass_through") << glu::AnyHitSource(updateRayTracingGLSL(css.str())) << buildOptions;
514 }
515
516 {
517 std::stringstream css;
518 css <<
519 "#version 460 core\n"
520 "#extension GL_EXT_ray_tracing : require\n"
521 "layout(location = 0) rayPayloadInEXT uvec4 hitValue;\n"
522 "void main()\n"
523 "{\n"
524 " hitValue.x = 1;\n"
525 " ignoreIntersectionEXT;\n"
526 " hitValue.x = 2;\n"
527 "}\n";
528
529 programCollection.glslSources.add("ahit_ignore") << glu::AnyHitSource(updateRayTracingGLSL(css.str())) << buildOptions;
530 }
531
532 {
533 std::stringstream css;
534 css <<
535 "#version 460 core\n"
536 "#extension GL_EXT_ray_tracing : require\n"
537 "layout(location = 0) rayPayloadInEXT uvec4 hitValue;\n"
538 "void main()\n"
539 "{\n"
540 " hitValue.x = 1;\n"
541 " terminateRayEXT;\n"
542 " hitValue.x = 2;\n"
543 "}\n";
544
545 programCollection.glslSources.add("ahit_terminate") << glu::AnyHitSource(updateRayTracingGLSL(css.str())) << buildOptions;
546 }
547
548 {
549 std::stringstream css;
550 css <<
551 "#version 460 core\n"
552 "#extension GL_EXT_ray_tracing : require\n"
553 "layout(location = 0) rayPayloadInEXT uvec4 hitValue;\n"
554 "void main()\n"
555 "{\n"
556 " hitValue.y = 3;\n"
557 "}\n";
558
559 programCollection.glslSources.add("chit") << glu::ClosestHitSource(updateRayTracingGLSL(css.str())) << buildOptions;
560 }
561
562 {
563 std::stringstream css;
564 css <<
565 "#version 460 core\n"
566 "#extension GL_EXT_ray_tracing : require\n"
567 "layout(location = 0) rayPayloadInEXT uvec4 hitValue;\n"
568 "void main()\n"
569 "{\n"
570 " hitValue.x = 4;\n"
571 "}\n";
572
573 programCollection.glslSources.add("miss") << glu::MissSource(updateRayTracingGLSL(css.str())) << buildOptions;
574 }
575 }
576
createInstance(Context & context) const577 TestInstance* TraversalControlTestCase::createInstance (Context& context) const
578 {
579 return new TraversalControlTestInstance(context, m_data);
580 }
581
TraversalControlTestInstance(Context & context,const TestParams & data)582 TraversalControlTestInstance::TraversalControlTestInstance (Context& context, const TestParams& data)
583 : vkt::TestInstance (context)
584 , m_data (data)
585 {
586 }
587
~TraversalControlTestInstance(void)588 TraversalControlTestInstance::~TraversalControlTestInstance (void)
589 {
590 }
591
runTest()592 de::MovePtr<BufferWithMemory> TraversalControlTestInstance::runTest ()
593 {
594 const InstanceInterface& vki = m_context.getInstanceInterface();
595 const DeviceInterface& vkd = m_context.getDeviceInterface();
596 const VkDevice device = m_context.getDevice();
597 const VkPhysicalDevice physicalDevice = m_context.getPhysicalDevice();
598 const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
599 const VkQueue queue = m_context.getUniversalQueue();
600 Allocator& allocator = m_context.getDefaultAllocator();
601
602 const Move<VkDescriptorSetLayout> descriptorSetLayout = DescriptorSetLayoutBuilder()
603 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, ALL_RAY_TRACING_STAGES)
604 .addSingleBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, ALL_RAY_TRACING_STAGES)
605 .build(vkd, device);
606 const Move<VkDescriptorPool> descriptorPool = DescriptorPoolBuilder()
607 .addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE)
608 .addType(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR)
609 .build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
610 const Move<VkDescriptorSet> descriptorSet = makeDescriptorSet(vkd, device, *descriptorPool, *descriptorSetLayout);
611 const Move<VkPipelineLayout> pipelineLayout = makePipelineLayout(vkd, device, descriptorSetLayout.get());
612
613 de::MovePtr<RayTracingPipeline> rayTracingPipeline = de::newMovePtr<RayTracingPipeline>();
614 m_data.testConfiguration->initRayTracingShaders(rayTracingPipeline, m_context, m_data);
615 Move<VkPipeline> pipeline = rayTracingPipeline->createPipeline(vkd, device, *pipelineLayout);
616
617 de::MovePtr<BufferWithMemory> raygenShaderBindingTable;
618 de::MovePtr<BufferWithMemory> hitShaderBindingTable;
619 de::MovePtr<BufferWithMemory> missShaderBindingTable;
620 de::MovePtr<BufferWithMemory> callableShaderBindingTable;
621 VkStridedDeviceAddressRegionKHR raygenShaderBindingTableRegion;
622 VkStridedDeviceAddressRegionKHR hitShaderBindingTableRegion;
623 VkStridedDeviceAddressRegionKHR missShaderBindingTableRegion;
624 VkStridedDeviceAddressRegionKHR callableShaderBindingTableRegion;
625 m_data.testConfiguration->initShaderBindingTables(rayTracingPipeline, m_context, m_data, *pipeline, getShaderGroupHandleSize(vki, physicalDevice), getShaderGroupBaseAlignment(vki, physicalDevice), raygenShaderBindingTable, hitShaderBindingTable, missShaderBindingTable, callableShaderBindingTable, raygenShaderBindingTableRegion, hitShaderBindingTableRegion, missShaderBindingTableRegion, callableShaderBindingTableRegion);
626
627 const VkFormat imageFormat = m_data.testConfiguration->getResultImageFormat();
628 const VkImageCreateInfo imageCreateInfo = makeImageCreateInfo(m_data.width, m_data.height, 2, imageFormat);
629 const VkImageSubresourceRange imageSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
630 const de::MovePtr<ImageWithMemory> image = de::MovePtr<ImageWithMemory>(new ImageWithMemory(vkd, device, allocator, imageCreateInfo, MemoryRequirement::Any));
631 const Move<VkImageView> imageView = makeImageView(vkd, device, **image, VK_IMAGE_VIEW_TYPE_3D, imageFormat, imageSubresourceRange);
632
633 const VkBufferCreateInfo resultBufferCreateInfo = makeBufferCreateInfo(m_data.width * m_data.height * 2 * m_data.testConfiguration->getResultImageFormatSize(), VK_BUFFER_USAGE_TRANSFER_DST_BIT);
634 const VkImageSubresourceLayers resultBufferImageSubresourceLayers = makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u);
635 const VkBufferImageCopy resultBufferImageRegion = makeBufferImageCopy(makeExtent3D(m_data.width, m_data.height, 2), resultBufferImageSubresourceLayers);
636 de::MovePtr<BufferWithMemory> resultBuffer = de::MovePtr<BufferWithMemory>(new BufferWithMemory(vkd, device, allocator, resultBufferCreateInfo, MemoryRequirement::HostVisible));
637
638 const VkDescriptorImageInfo descriptorImageInfo = makeDescriptorImageInfo(DE_NULL, *imageView, VK_IMAGE_LAYOUT_GENERAL);
639
640 const Move<VkCommandPool> cmdPool = createCommandPool(vkd, device, 0, queueFamilyIndex);
641 const Move<VkCommandBuffer> cmdBuffer = allocateCommandBuffer(vkd, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
642
643 std::vector<de::SharedPtr<BottomLevelAccelerationStructure> > bottomLevelAccelerationStructures;
644 de::MovePtr<TopLevelAccelerationStructure> topLevelAccelerationStructure;
645
646 beginCommandBuffer(vkd, *cmdBuffer, 0u);
647 {
648 const VkImageMemoryBarrier preImageBarrier = makeImageMemoryBarrier(0u, VK_ACCESS_TRANSFER_WRITE_BIT,
649 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
650 **image, imageSubresourceRange);
651 cmdPipelineImageMemoryBarrier(vkd, *cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, &preImageBarrier);
652
653 const VkClearValue clearValue = m_data.testConfiguration->getClearValue();
654 vkd.cmdClearColorImage(*cmdBuffer, **image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clearValue.color, 1, &imageSubresourceRange);
655
656 const VkImageMemoryBarrier postImageBarrier = makeImageMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR | VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR,
657 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL,
658 **image, imageSubresourceRange);
659 cmdPipelineImageMemoryBarrier(vkd, *cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR, &postImageBarrier);
660
661 bottomLevelAccelerationStructures = m_data.testConfiguration->initBottomAccelerationStructures(m_context, m_data);
662 for (auto& blas : bottomLevelAccelerationStructures)
663 blas->createAndBuild(vkd, device, *cmdBuffer, allocator);
664 topLevelAccelerationStructure = m_data.testConfiguration->initTopAccelerationStructure(m_context, m_data, bottomLevelAccelerationStructures);
665 topLevelAccelerationStructure->createAndBuild(vkd, device, *cmdBuffer, allocator);
666
667 const TopLevelAccelerationStructure* topLevelAccelerationStructurePtr = topLevelAccelerationStructure.get();
668 VkWriteDescriptorSetAccelerationStructureKHR accelerationStructureWriteDescriptorSet =
669 {
670 VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR, // VkStructureType sType;
671 DE_NULL, // const void* pNext;
672 1u, // deUint32 accelerationStructureCount;
673 topLevelAccelerationStructurePtr->getPtr(), // const VkAccelerationStructureKHR* pAccelerationStructures;
674 };
675
676 DescriptorSetUpdateBuilder()
677 .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &descriptorImageInfo)
678 .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, &accelerationStructureWriteDescriptorSet)
679 .update(vkd, device);
680
681 vkd.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, *pipelineLayout, 0, 1, &descriptorSet.get(), 0, DE_NULL);
682
683 vkd.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, *pipeline);
684
685 cmdTraceRays(vkd,
686 *cmdBuffer,
687 &raygenShaderBindingTableRegion,
688 &missShaderBindingTableRegion,
689 &hitShaderBindingTableRegion,
690 &callableShaderBindingTableRegion,
691 m_data.width, m_data.height, 1);
692
693 const VkMemoryBarrier postTraceMemoryBarrier = makeMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT);
694 const VkMemoryBarrier postCopyMemoryBarrier = makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
695 cmdPipelineMemoryBarrier(vkd, *cmdBuffer, VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR, VK_PIPELINE_STAGE_TRANSFER_BIT, &postTraceMemoryBarrier);
696
697 vkd.cmdCopyImageToBuffer(*cmdBuffer, **image, VK_IMAGE_LAYOUT_GENERAL, **resultBuffer, 1u, &resultBufferImageRegion);
698
699 cmdPipelineMemoryBarrier(vkd, *cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, &postCopyMemoryBarrier);
700 }
701 endCommandBuffer(vkd, *cmdBuffer);
702
703 submitCommandsAndWait(vkd, device, queue, cmdBuffer.get());
704
705 invalidateMappedMemoryRange(vkd, device, resultBuffer->getAllocation().getMemory(), resultBuffer->getAllocation().getOffset(), VK_WHOLE_SIZE);
706
707 return resultBuffer;
708 }
709
iterate(void)710 tcu::TestStatus TraversalControlTestInstance::iterate (void)
711 {
712 // run test using arrays of pointers
713 const de::MovePtr<BufferWithMemory> buffer = runTest();
714
715 if (!m_data.testConfiguration->verifyImage(buffer.get(), m_context, m_data))
716 return tcu::TestStatus::fail("Fail");
717 return tcu::TestStatus::pass("Pass");
718 }
719
720 } // anonymous
721
createTraversalControlTests(tcu::TestContext & testCtx)722 tcu::TestCaseGroup* createTraversalControlTests(tcu::TestContext& testCtx)
723 {
724 de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "traversal_control", "Tests verifying traversal control in RT hit shaders"));
725
726 struct HitShaderTestTypeData
727 {
728 HitShaderTestType shaderTestType;
729 bool onlyAabbTest;
730 const char* name;
731 } hitShaderTestTypes[] =
732 {
733 { HSTT_ISECT_REPORT_INTERSECTION, true, "isect_report_intersection" },
734 { HSTT_ISECT_DONT_REPORT_INTERSECTION, true, "isect_dont_report_intersection" },
735 { HSTT_AHIT_PASS_THROUGH, false, "ahit_pass_through" },
736 { HSTT_AHIT_IGNORE_INTERSECTION, false, "ahit_ignore_intersection" },
737 { HSTT_AHIT_TERMINATE_RAY, false, "ahit_terminate_ray" },
738 };
739
740 struct
741 {
742 BottomTestType testType;
743 const char* name;
744 } bottomTestTypes[] =
745 {
746 { BTT_TRIANGLES, "triangles" },
747 { BTT_AABBS, "aabbs" },
748 };
749
750
751 for (size_t shaderTestNdx = 0; shaderTestNdx < DE_LENGTH_OF_ARRAY(hitShaderTestTypes); ++shaderTestNdx)
752 {
753 de::MovePtr<tcu::TestCaseGroup> testTypeGroup(new tcu::TestCaseGroup(group->getTestContext(), hitShaderTestTypes[shaderTestNdx].name, ""));
754
755 for (size_t testTypeNdx = 0; testTypeNdx < DE_LENGTH_OF_ARRAY(bottomTestTypes); ++testTypeNdx)
756 {
757 if (hitShaderTestTypes[shaderTestNdx].onlyAabbTest && bottomTestTypes[testTypeNdx].testType != BTT_AABBS)
758 continue;
759
760 TestParams testParams
761 {
762 TEST_WIDTH,
763 TEST_HEIGHT,
764 hitShaderTestTypes[shaderTestNdx].shaderTestType,
765 bottomTestTypes[testTypeNdx].testType,
766 de::SharedPtr<TestConfiguration>(new SingleSquareConfiguration())
767 };
768 testTypeGroup->addChild(new TraversalControlTestCase(group->getTestContext(), bottomTestTypes[testTypeNdx].name, "", testParams));
769 }
770 group->addChild(testTypeGroup.release());
771
772 }
773
774 return group.release();
775 }
776
777 } // RayTracing
778
779 } // vkt
780