1 /*-------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2021 The Khronos Group Inc.
6 * Copyright (c) 2021 Valve Corporation.
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 *
20 *//*!
21 * \file
22 * \brief Ray Tracing Direction Tests
23 *//*--------------------------------------------------------------------*/
24
25 #include "vktRayTracingDirectionTests.hpp"
26 #include "vktTestCase.hpp"
27
28 #include "vkObjUtil.hpp"
29 #include "vkCmdUtil.hpp"
30 #include "vkTypeUtil.hpp"
31 #include "vkBuilderUtil.hpp"
32 #include "vkRayTracingUtil.hpp"
33 #include "vkBufferWithMemory.hpp"
34 #include "vkBarrierUtil.hpp"
35
36 #include "tcuVector.hpp"
37 #include "tcuMatrix.hpp"
38
39 #include "deUniquePtr.hpp"
40 #include "deRandom.hpp"
41 #include "deStringUtil.hpp"
42 #include "deDefs.hpp"
43
44 #include <vector>
45 #include <cmath>
46 #include <sstream>
47 #include <utility>
48 #include <algorithm>
49 #include <limits>
50
51 namespace vkt
52 {
53 namespace RayTracing
54 {
55
56 namespace
57 {
58
59 using namespace vk;
60
61 using GeometryData = std::vector<tcu::Vec3>;
62
63 // Should rays be shot from inside the geometry or not?
64 enum class RayOriginType
65 {
66 OUTSIDE = 0, // Works with AABBs and triangles.
67 INSIDE, // Works with AABBs only.
68 };
69
70 // When rays are shot from the outside, they are expected to cross the geometry.
71 // When shot from the inside, they can end inside, at the edge or outside the geometry.
72 enum class RayEndType
73 {
74 CROSS = 0, // For RayOriginType::OUTSIDE.
75 ZERO, // For RayOriginType::INSIDE.
76 INSIDE, // For RayOriginType::INSIDE.
77 EDGE, // For RayOriginType::INSIDE.
78 OUTSIDE, // For RayOriginType::INSIDE.
79 };
80
81 struct SpaceObjects
82 {
83 tcu::Vec3 origin;
84 tcu::Vec3 direction;
85 GeometryData geometry;
86
SpaceObjectsvkt::RayTracing::__anon5f9dfc1d0111::SpaceObjects87 SpaceObjects (RayOriginType rayOriginType, VkGeometryTypeKHR geometryType)
88 : origin (0.0f, 0.0f, 1.0f) // Origin of the ray at (0, 0, 1).
89 , direction (0.0f, 0.0f, 1.0f) // Shooting towards (0, 0, 1).
90 , geometry ()
91 {
92 DE_ASSERT(geometryType == VK_GEOMETRY_TYPE_TRIANGLES_KHR || geometryType == VK_GEOMETRY_TYPE_AABBS_KHR);
93 DE_ASSERT(rayOriginType == RayOriginType::OUTSIDE || geometryType == VK_GEOMETRY_TYPE_AABBS_KHR);
94
95 if (geometryType == VK_GEOMETRY_TYPE_TRIANGLES_KHR)
96 {
97 // Triangle around (0, 0, 5).
98 geometry.reserve(3u);
99 geometry.push_back(tcu::Vec3( 0.0f, 0.5f, 5.0f));
100 geometry.push_back(tcu::Vec3(-0.5f, -0.5f, 5.0f));
101 geometry.push_back(tcu::Vec3( 0.5f, -0.5f, 5.0f));
102 }
103 else
104 {
105 // AABB around (0, 0, 5) or with its back side at that distance when shot from the inside.
106 geometry.reserve(2u);
107 geometry.push_back(tcu::Vec3(-0.5f, -0.5f, ((rayOriginType == RayOriginType::INSIDE) ? 0.0f : 5.0f)));
108 geometry.push_back(tcu::Vec3( 0.5f, 0.5f, 5.0f));
109 }
110 }
111
getDefaultDistancevkt::RayTracing::__anon5f9dfc1d0111::SpaceObjects112 static float getDefaultDistance (void)
113 {
114 // Consistent with the Z coordinates of the origin, direction and points in constructors.
115 return 4.0f;
116 }
117
118 // Calculates distance to geometry edge given the direction scaling factor.
getDistanceToEdgevkt::RayTracing::__anon5f9dfc1d0111::SpaceObjects119 static float getDistanceToEdge (float directionScale)
120 {
121 return getDefaultDistance() / directionScale;
122 }
123 };
124
125 // Default test tolerance for distance values.
126 constexpr float kDefaultTolerance = 0.001f;
127
128 // Calculates appropriate values for Tmin/Tmax given the distance to the geometry edge.
calcTminTmax(RayOriginType rayOriginType,RayEndType rayEndType,float distanceToEdge)129 std::pair<float, float> calcTminTmax (RayOriginType rayOriginType, RayEndType rayEndType, float distanceToEdge)
130 {
131 std::pair<float, float> result;
132
133 if (rayOriginType == RayOriginType::OUTSIDE)
134 {
135 DE_ASSERT(rayEndType == RayEndType::CROSS);
136 const auto margin = kDefaultTolerance / 2.0f;
137 result = std::make_pair(de::max(distanceToEdge - margin, 0.0f), distanceToEdge + margin);
138 }
139 else
140 {
141 result.first = 0.0f;
142 switch (rayEndType)
143 {
144 case RayEndType::ZERO: result.second = 0.0f; break;
145 case RayEndType::INSIDE: result.second = distanceToEdge / 2.0f; break;
146 case RayEndType::EDGE: result.second = distanceToEdge; break;
147 case RayEndType::OUTSIDE: result.second = distanceToEdge + 1.0f; break;
148 default: DE_ASSERT(false); break;
149 }
150 }
151
152 return result;
153 }
154
155 // Get matrix to scale a point with the given scale factor.
getScaleMatrix(float scaleFactor)156 tcu::Mat3 getScaleMatrix (float scaleFactor)
157 {
158 const float scaleDirectionMatrixData[] =
159 {
160 scaleFactor, 0.f, 0.f,
161 0.f, scaleFactor, 0.f,
162 0.f, 0.f, scaleFactor,
163 };
164 return tcu::Mat3(scaleDirectionMatrixData);
165 }
166
167 // Get a matrix to rotate a point around the X and Y axis by the given angles in radians.
getRotationMatrix(float rotationX,float rotationY)168 tcu::Mat3 getRotationMatrix (float rotationX, float rotationY)
169 {
170 const float cosA = std::cos(rotationX);
171 const float sinA = std::sin(rotationX);
172
173 const float cosB = std::cos(rotationY);
174 const float sinB = std::sin(rotationY);
175
176 const float rotationMatrixDataX[] =
177 {
178 1.0f, 0.0f, 0.0f,
179 0.0f, cosA,-sinA,
180 0.0f, sinA, cosA,
181 };
182 const tcu::Mat3 rotationMatrixX (rotationMatrixDataX);
183
184 const float rotationMatrixDataY[] =
185 {
186 cosB, 0.0f,-sinB,
187 0.0f, 1.0f, 0.0f,
188 sinB, 0.0f, cosB,
189 };
190 const tcu::Mat3 rotationMatrixY (rotationMatrixDataY);
191
192 return rotationMatrixX * rotationMatrixY;
193 }
194
195 // Converts transformation matrix to the expected KHR format.
toTransformMatrixKHR(const tcu::Mat3 & mat3)196 VkTransformMatrixKHR toTransformMatrixKHR (const tcu::Mat3& mat3)
197 {
198 VkTransformMatrixKHR result;
199
200 deMemset(result.matrix, 0, sizeof(result.matrix));
201 for (int y = 0; y < 3; ++y)
202 for (int x = 0; x < 3; ++x)
203 result.matrix[x][y] = mat3[x][y];
204
205 return result;
206 }
207
208 struct TestParams
209 {
210 SpaceObjects spaceObjects;
211 float directionScale;
212 float rotationX;
213 float rotationY;
214 VkShaderStageFlagBits testStage;
215 VkGeometryTypeKHR geometryType;
216 bool useArraysOfPointers;
217 bool updateMatrixAfterBuild;
218 RayOriginType rayOriginType;
219 RayEndType rayEndtype;
220
usedStagesvkt::RayTracing::__anon5f9dfc1d0111::TestParams221 VkShaderStageFlags usedStages (void) const
222 {
223 VkShaderStageFlags flags = (VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR | testStage);
224
225 if (geometryType == VK_GEOMETRY_TYPE_AABBS_KHR)
226 flags |= VK_SHADER_STAGE_INTERSECTION_BIT_KHR;
227
228 return flags;
229 }
230
231 // True if we are testing the intersection shader.
isecMainvkt::RayTracing::__anon5f9dfc1d0111::TestParams232 bool isecMain (void) const
233 {
234 return (testStage == VK_SHADER_STAGE_INTERSECTION_BIT_KHR);
235 }
236
237 // True if the intersection shader is needed as an auxiliar shader.
isecAuxvkt::RayTracing::__anon5f9dfc1d0111::TestParams238 bool isecAux (void) const
239 {
240 return (!isecMain() && geometryType == VK_GEOMETRY_TYPE_AABBS_KHR);
241 }
242
243 // True if the intersection shader is used in some capacity.
isecUsedvkt::RayTracing::__anon5f9dfc1d0111::TestParams244 bool isecUsed (void) const
245 {
246 return (isecMain() || isecAux());
247 }
248 };
249
250 class DirectionTestCase : public vkt::TestCase
251 {
252 public:
253 DirectionTestCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestParams& params);
~DirectionTestCase(void)254 virtual ~DirectionTestCase (void) {}
255
256 virtual void checkSupport (Context& context) const;
257 virtual void initPrograms (vk::SourceCollections& programCollection) const;
258 virtual TestInstance* createInstance (Context& context) const;
259
260 protected:
261 TestParams m_params;
262 };
263
264 class DirectionTestInstance : public vkt::TestInstance
265 {
266 public:
267 DirectionTestInstance (Context& context, const TestParams& params);
~DirectionTestInstance(void)268 virtual ~DirectionTestInstance (void) {}
269
270 virtual tcu::TestStatus iterate (void);
271
272 protected:
273 TestParams m_params;
274 };
275
276
DirectionTestCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,const TestParams & params)277 DirectionTestCase::DirectionTestCase(tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestParams& params)
278 : vkt::TestCase (testCtx, name, description)
279 , m_params (params)
280 {}
281
checkSupport(Context & context) const282 void DirectionTestCase::checkSupport (Context& context) const
283 {
284 context.requireDeviceFunctionality("VK_KHR_acceleration_structure");
285 context.requireDeviceFunctionality("VK_KHR_ray_tracing_pipeline");
286 }
287
288 // Push constants. They need to match the shaders.
289 // Note: origin and direction will be used as a Vec3. Declaring them as Vec4 eases matching alignments.
290 struct PushConstants
291 {
292 tcu::Vec4 origin;
293 tcu::Vec4 direction;
294 float tmix;
295 float tmax;
296 };
297
toVec4(const tcu::Vec3 & vec3)298 tcu::Vec4 toVec4 (const tcu::Vec3& vec3)
299 {
300 return tcu::Vec4(vec3.x(), vec3.y(), vec3.z(), 0.0f);
301 }
302
initPrograms(vk::SourceCollections & programCollection) const303 void DirectionTestCase::initPrograms (vk::SourceCollections& programCollection) const
304 {
305 const vk::ShaderBuildOptions buildOptions (programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_4, 0u, true);
306
307 std::ostringstream rgen;
308 rgen
309 << "#version 460 core\n"
310 << "#extension GL_EXT_ray_tracing : require\n"
311 << "layout(location=0) rayPayloadEXT vec3 hitValue;\n"
312 << "layout(set=0, binding=0) uniform accelerationStructureEXT topLevelAS;\n"
313 // Needs to match the PushConstants struct above.
314 << "layout(push_constant, std430) uniform PushConstants {\n"
315 << " vec4 origin;\n"
316 << " vec4 direction;\n"
317 << " float tmin;\n"
318 << " float tmax;\n"
319 << "} pc;\n"
320 << "\n"
321 << "void main()\n"
322 << "{\n"
323 << " const uint cullMask = 0xFF;\n"
324 << " traceRayEXT(topLevelAS, gl_RayFlagsNoneEXT, cullMask, 0, 0, 0, pc.origin.xyz, pc.tmin, pc.direction.xyz, pc.tmax, 0);\n"
325 << "}\n"
326 ;
327
328 programCollection.glslSources.add("rgen") << glu::RaygenSource(updateRayTracingGLSL(rgen.str())) << buildOptions;
329
330 const bool isecTest = m_params.isecMain();
331 const std::string bufferDecl = "layout(set=0, binding=1, std430) buffer OutBuffer { float val; } outBuffer;\n";
332
333 std::ostringstream isec;
334 isec
335 << "#version 460 core\n"
336 << "#extension GL_EXT_ray_tracing : require\n"
337 << "hitAttributeEXT vec3 hitAttribute;\n"
338 << (isecTest ? bufferDecl : "")
339 << "void main()\n"
340 << "{\n"
341 << " hitAttribute = vec3(0.0f, 0.0f, 0.0f);\n"
342 << (isecTest ? " outBuffer.val = gl_RayTminEXT;\n" : "")
343 << " reportIntersectionEXT(gl_RayTminEXT, 0);\n"
344 << "}\n"
345 ;
346
347 std::ostringstream hits;
348 hits
349 << "#version 460 core\n"
350 << "#extension GL_EXT_ray_tracing : require\n"
351 << "layout(location=0) rayPayloadInEXT vec3 hitValue;\n"
352 << "hitAttributeEXT vec3 attribs;\n"
353 << bufferDecl
354 << "\n"
355 << "void main()\n"
356 << "{\n"
357 << " outBuffer.val = gl_HitTEXT;\n"
358 << "}\n"
359 ;
360
361 switch (m_params.testStage)
362 {
363 case VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR:
364 programCollection.glslSources.add("hits") << glu::ClosestHitSource(updateRayTracingGLSL(hits.str())) << buildOptions;
365 break;
366 case VK_SHADER_STAGE_ANY_HIT_BIT_KHR:
367 programCollection.glslSources.add("hits") << glu::AnyHitSource(updateRayTracingGLSL(hits.str())) << buildOptions;
368 break;
369 case VK_SHADER_STAGE_INTERSECTION_BIT_KHR:
370 programCollection.glslSources.add("isec") << glu::IntersectionSource(updateRayTracingGLSL(isec.str())) << buildOptions;
371 break;
372 default:
373 DE_ASSERT(false);
374 break;
375 }
376
377 // Also add the intersection shader if needed for AABBs.
378 if (m_params.isecAux())
379 programCollection.glslSources.add("isec") << glu::IntersectionSource(updateRayTracingGLSL(isec.str())) << buildOptions;
380
381 std::ostringstream miss;
382 miss
383 << "#version 460 core\n"
384 << "#extension GL_EXT_ray_tracing : require\n"
385 << "layout(location = 0) rayPayloadInEXT vec3 hitValue;\n"
386 << bufferDecl
387 << "\n"
388 << "void main()\n"
389 << "{\n"
390 << " outBuffer.val = -10000.0f;\n"
391 << "}\n";
392
393 programCollection.glslSources.add("miss") << glu::MissSource(updateRayTracingGLSL(miss.str())) << buildOptions;
394 }
395
createInstance(Context & context) const396 TestInstance* DirectionTestCase::createInstance (Context& context) const
397 {
398 return new DirectionTestInstance(context, m_params);
399 }
400
DirectionTestInstance(Context & context,const TestParams & params)401 DirectionTestInstance::DirectionTestInstance (Context& context, const TestParams& params)
402 : vkt::TestInstance (context)
403 , m_params (params)
404 {}
405
iterate(void)406 tcu::TestStatus DirectionTestInstance::iterate (void)
407 {
408 const auto& vki = m_context.getInstanceInterface();
409 const auto physDev = m_context.getPhysicalDevice();
410 const auto& vkd = m_context.getDeviceInterface();
411 const auto device = m_context.getDevice();
412 auto& alloc = m_context.getDefaultAllocator();
413 const auto qIndex = m_context.getUniversalQueueFamilyIndex();
414 const auto queue = m_context.getUniversalQueue();
415 const auto stages = m_params.usedStages();
416 const auto pcSize = static_cast<deUint32>(sizeof(PushConstants));
417
418 const auto scaleMatrix = getScaleMatrix(m_params.directionScale);
419 const auto rotationMatrix = getRotationMatrix(m_params.rotationX, m_params.rotationY);
420 const auto transformMatrix = toTransformMatrixKHR(rotationMatrix);
421
422 // Command pool and buffer.
423 const auto cmdPool = makeCommandPool(vkd, device, qIndex);
424 const auto cmdBufferPtr = allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
425 const auto cmdBuffer = cmdBufferPtr.get();
426
427 beginCommandBuffer(vkd, cmdBuffer);
428
429 // Build acceleration structures.
430 auto topLevelAS = makeTopLevelAccelerationStructure();
431 auto bottomLevelAS = makeBottomLevelAccelerationStructure();
432
433 const bool isTriangles = (m_params.geometryType == VK_GEOMETRY_TYPE_TRIANGLES_KHR);
434 const VkGeometryInstanceFlagsKHR instanceFlags = (isTriangles ? VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR : 0);
435
436 bottomLevelAS->addGeometry(m_params.spaceObjects.geometry, isTriangles, VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR);
437 bottomLevelAS->createAndBuild(vkd, device, cmdBuffer, alloc);
438
439 de::SharedPtr<BottomLevelAccelerationStructure> blasSharedPtr (bottomLevelAS.release());
440 topLevelAS->setUseArrayOfPointers(m_params.useArraysOfPointers);
441 topLevelAS->setUsePPGeometries(m_params.useArraysOfPointers);
442 topLevelAS->setInstanceCount(1);
443 {
444 const auto& initialMatrix = (m_params.updateMatrixAfterBuild ? identityMatrix3x4 : transformMatrix);
445 topLevelAS->addInstance(blasSharedPtr, initialMatrix, 0, 0xFFu, 0u, instanceFlags);
446 }
447 topLevelAS->createAndBuild(vkd, device, cmdBuffer, alloc);
448 if (m_params.updateMatrixAfterBuild)
449 topLevelAS->updateInstanceMatrix(vkd, device, 0u, transformMatrix);
450
451 // Create output buffer.
452 const auto bufferSize = static_cast<VkDeviceSize>(sizeof(float));
453 const auto bufferCreateInfo = makeBufferCreateInfo(bufferSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
454 BufferWithMemory buffer (vkd, device, alloc, bufferCreateInfo, MemoryRequirement::HostVisible);
455 auto& bufferAlloc = buffer.getAllocation();
456
457 // Fill output buffer with an initial value.
458 deMemset(bufferAlloc.getHostPtr(), 0, sizeof(float));
459 flushAlloc(vkd, device, bufferAlloc);
460
461 // Descriptor set layout and pipeline layout.
462 DescriptorSetLayoutBuilder setLayoutBuilder;
463 setLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, stages);
464 setLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, stages);
465 const auto setLayout = setLayoutBuilder.build(vkd, device);
466
467 const VkPushConstantRange pcRange =
468 {
469 stages, // VkShaderStageFlags stageFlags;
470 0u, // deUint32 offset;
471 pcSize, // deUint32 size;
472 };
473
474 const VkPipelineLayoutCreateInfo pipelineLayoutInfo =
475 {
476 VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType;
477 nullptr, // const void* pNext;
478 0u, // VkPipelineLayoutCreateFlags flags;
479 1u, // deUint32 setLayoutCount;
480 &setLayout.get(), // const VkDescriptorSetLayout* pSetLayouts;
481 1u, // deUint32 pushConstantRangeCount;
482 &pcRange, // const VkPushConstantRange* pPushConstantRanges;
483 };
484 const auto pipelineLayout = createPipelineLayout(vkd, device, &pipelineLayoutInfo);
485
486 // Descriptor pool and set.
487 DescriptorPoolBuilder poolBuilder;
488 poolBuilder.addType(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR);
489 poolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1u);
490 const auto descriptorPool = poolBuilder.build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
491 const auto descriptorSet = makeDescriptorSet(vkd, device, descriptorPool.get(), setLayout.get());
492
493 // Update descriptor set.
494 {
495 const VkWriteDescriptorSetAccelerationStructureKHR accelDescInfo =
496 {
497 VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR,
498 nullptr,
499 1u,
500 topLevelAS.get()->getPtr(),
501 };
502
503 const auto bufferDescInfo = makeDescriptorBufferInfo(buffer.get(), 0ull, VK_WHOLE_SIZE);
504
505 DescriptorSetUpdateBuilder updateBuilder;
506 updateBuilder.writeSingle(descriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, &accelDescInfo);
507 updateBuilder.writeSingle(descriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &bufferDescInfo);
508 updateBuilder.update(vkd, device);
509 }
510
511 // Shader modules.
512 Move<VkShaderModule> rgenModule;
513 Move<VkShaderModule> missModule;
514 Move<VkShaderModule> hitsModule;
515 Move<VkShaderModule> isecModule;
516
517 rgenModule = createShaderModule(vkd, device, m_context.getBinaryCollection().get("rgen"), 0);
518 missModule = createShaderModule(vkd, device, m_context.getBinaryCollection().get("miss"), 0);
519
520 if (!m_params.isecMain())
521 hitsModule = createShaderModule(vkd, device, m_context.getBinaryCollection().get("hits"), 0);
522
523 if (m_params.isecUsed())
524 isecModule = createShaderModule(vkd, device, m_context.getBinaryCollection().get("isec"), 0);
525
526 // Get some ray tracing properties.
527 deUint32 shaderGroupHandleSize = 0u;
528 deUint32 shaderGroupBaseAlignment = 1u;
529 {
530 const auto rayTracingPropertiesKHR = makeRayTracingProperties(vki, physDev);
531 shaderGroupHandleSize = rayTracingPropertiesKHR->getShaderGroupHandleSize();
532 shaderGroupBaseAlignment = rayTracingPropertiesKHR->getShaderGroupBaseAlignment();
533 }
534
535 // Create raytracing pipeline and shader binding tables.
536 Move<VkPipeline> pipeline;
537
538 de::MovePtr<BufferWithMemory> raygenSBT;
539 de::MovePtr<BufferWithMemory> missSBT;
540 de::MovePtr<BufferWithMemory> hitSBT;
541 de::MovePtr<BufferWithMemory> callableSBT;
542
543 VkStridedDeviceAddressRegionKHR raygenSBTRegion = makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0);
544 VkStridedDeviceAddressRegionKHR missSBTRegion = makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0);
545 VkStridedDeviceAddressRegionKHR hitSBTRegion = makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0);
546 VkStridedDeviceAddressRegionKHR callableSBTRegion = makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0);
547
548 {
549 const auto hitModuleCount = (m_params.isecAux() ? 2 : 1);
550 const auto rayTracingPipeline = de::newMovePtr<RayTracingPipeline>();
551
552 rayTracingPipeline->addShader(VK_SHADER_STAGE_RAYGEN_BIT_KHR, rgenModule, 0);
553 rayTracingPipeline->addShader(VK_SHADER_STAGE_MISS_BIT_KHR, missModule, 1);
554
555 if (!m_params.isecMain())
556 rayTracingPipeline->addShader(m_params.testStage, hitsModule, 2);
557
558 if (m_params.isecUsed())
559 rayTracingPipeline->addShader(VK_SHADER_STAGE_INTERSECTION_BIT_KHR, isecModule, 2);
560
561 pipeline = rayTracingPipeline->createPipeline(vkd, device, pipelineLayout.get());
562
563 raygenSBT = rayTracingPipeline->createShaderBindingTable(vkd, device, pipeline.get(), alloc, shaderGroupHandleSize, shaderGroupBaseAlignment, 0, 1);
564 raygenSBTRegion = makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, raygenSBT->get(), 0), shaderGroupHandleSize, shaderGroupHandleSize);
565
566 missSBT = rayTracingPipeline->createShaderBindingTable(vkd, device, pipeline.get(), alloc, shaderGroupHandleSize, shaderGroupBaseAlignment, 1, 1);
567 missSBTRegion = makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, missSBT->get(), 0), shaderGroupHandleSize, shaderGroupHandleSize);
568
569 hitSBT = rayTracingPipeline->createShaderBindingTable(vkd, device, pipeline.get(), alloc, shaderGroupHandleSize, shaderGroupBaseAlignment, 2, 1);
570 hitSBTRegion = makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, hitSBT->get(), 0), shaderGroupHandleSize, shaderGroupHandleSize * hitModuleCount);
571 }
572
573 // Push constants.
574 const auto rotatedOrigin = m_params.spaceObjects.origin * rotationMatrix;
575 const auto finalDirection = m_params.spaceObjects.direction * scaleMatrix * rotationMatrix;
576 const auto distanceToEdge = SpaceObjects::getDistanceToEdge(m_params.directionScale);
577 const auto tMinMax = calcTminTmax(m_params.rayOriginType, m_params.rayEndtype, distanceToEdge);
578 const PushConstants pcData =
579 {
580 toVec4(rotatedOrigin), // tcu::Vec4 origin;
581 toVec4(finalDirection), // tcu::Vec4 direction;
582 tMinMax.first, // float tmix;
583 tMinMax.second, // float tmax;
584 };
585
586 // Trace rays.
587 vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline.get());
588 vkd.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipelineLayout.get(), 0u, 1u, &descriptorSet.get(), 0u, nullptr);
589 vkd.cmdPushConstants(cmdBuffer, pipelineLayout.get(), stages, 0u, pcSize, &pcData);
590 vkd.cmdTraceRaysKHR(cmdBuffer, &raygenSBTRegion, &missSBTRegion, &hitSBTRegion, &callableSBTRegion, 1u, 1u, 1u);
591
592 // Barrier for the output buffer.
593 const auto bufferBarrier = makeMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
594 vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR, VK_PIPELINE_STAGE_HOST_BIT, 0u, 1u, &bufferBarrier, 0u, nullptr, 0u, nullptr);
595
596 endCommandBuffer(vkd, cmdBuffer);
597 submitCommandsAndWait(vkd, device, queue, cmdBuffer);
598
599 // Read value back from the buffer.
600 float bufferValue = 0.0f;
601 invalidateAlloc(vkd, device, bufferAlloc);
602 deMemcpy(&bufferValue, bufferAlloc.getHostPtr(), sizeof(bufferValue));
603
604 if (m_params.rayEndtype == RayEndType::CROSS)
605 {
606 // Shooting from the ouside.
607 if (de::abs(bufferValue - distanceToEdge) > kDefaultTolerance)
608 {
609 std::ostringstream msg;
610 msg << "Result distance (" << bufferValue << ") differs from expected distance (" << distanceToEdge << ", tolerance " << kDefaultTolerance << ")";
611 TCU_FAIL(msg.str());
612 }
613 }
614 else
615 {
616 // Rays are shot from inside AABBs, rayTMin should be zero and the reported hit distance.
617 if (bufferValue != 0.0f)
618 {
619 std::ostringstream msg;
620 msg << "Result distance nonzero (" << bufferValue << ")";
621 TCU_FAIL(msg.str());
622 }
623 }
624
625 return tcu::TestStatus::pass("Pass");
626 }
627
628 using GroupPtr = de::MovePtr<tcu::TestCaseGroup>;
629
630 // Generate a list of scaling factors suitable for the tests.
generateScalingFactors(de::Random & rnd)631 std::vector<float> generateScalingFactors (de::Random& rnd)
632 {
633 const float kMinScalingFactor = 0.5f;
634 const float kMaxScalingFactor = 10.0f;
635 const int kNumRandomScalingFactors = 5;
636
637 // Scaling factors: 1.0 and some randomly-generated ones.
638 std::vector<float> scalingFactors;
639
640 scalingFactors.reserve(kNumRandomScalingFactors + 1);
641 scalingFactors.push_back(1.0f);
642
643 for (int i = 0; i < kNumRandomScalingFactors; ++i)
644 scalingFactors.push_back(rnd.getFloat() * (kMaxScalingFactor - kMinScalingFactor) + kMinScalingFactor);
645
646 return scalingFactors;
647 }
648
649 // Generate a list of rotation angles suitable for the tests.
generateRotationAngles(de::Random & rnd)650 std::vector<std::pair<float, float>> generateRotationAngles (de::Random& rnd)
651 {
652 const float kPi2 = DE_PI * 2.0f;
653 const int kNumRandomRotations = 4;
654
655 // Rotations: 0.0 on both axis and some randomly-generated ones.
656 std::vector<std::pair<float, float>> rotationAngles;
657
658 rotationAngles.reserve(kNumRandomRotations + 1);
659 rotationAngles.push_back(std::make_pair(0.0f, 0.0f));
660
661 for (int i = 0; i < kNumRandomRotations; ++i)
662 rotationAngles.push_back(std::make_pair(rnd.getFloat() * kPi2, rnd.getFloat() * kPi2));
663
664 return rotationAngles;
665 }
666
667 } // anonymous
668
createDirectionLengthTests(tcu::TestContext & testCtx)669 tcu::TestCaseGroup* createDirectionLengthTests(tcu::TestContext& testCtx)
670 {
671 GroupPtr directionGroup (new tcu::TestCaseGroup(testCtx, "direction_length", "Test direction vector length when tracing rays"));
672
673 struct
674 {
675 VkShaderStageFlagBits hitStage;
676 const char* name;
677 } stages[] =
678 {
679 { VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR, "chit" },
680 { VK_SHADER_STAGE_ANY_HIT_BIT_KHR, "ahit" },
681 { VK_SHADER_STAGE_INTERSECTION_BIT_KHR, "isec" },
682 };
683
684 struct
685 {
686 VkGeometryTypeKHR geometryType;
687 const char* name;
688 } geometryTypes[] =
689 {
690 { VK_GEOMETRY_TYPE_TRIANGLES_KHR, "triangles" },
691 { VK_GEOMETRY_TYPE_AABBS_KHR, "aabbs" },
692 };
693
694 de::Random rnd(1613648516u);
695 deUint32 caseCounter = 0u;
696
697 // Scaling factors and rotation angles.
698 const auto scalingFactors = generateScalingFactors(rnd);
699 const auto rotationAngles = generateRotationAngles(rnd);
700
701 for (int stageIdx = 0; stageIdx < DE_LENGTH_OF_ARRAY(stages); ++stageIdx)
702 {
703 const auto& stageData = stages[stageIdx];
704 GroupPtr stageGroup (new tcu::TestCaseGroup(testCtx, stageData.name, ""));
705
706 for (int geometryTypeIdx = 0; geometryTypeIdx < DE_LENGTH_OF_ARRAY(geometryTypes); ++geometryTypeIdx)
707 {
708 const auto& gType = geometryTypes[geometryTypeIdx];
709
710 // We cannot test triangles with the ray intersection stage.
711 if (gType.geometryType == VK_GEOMETRY_TYPE_TRIANGLES_KHR && stageData.hitStage == VK_SHADER_STAGE_INTERSECTION_BIT_KHR)
712 continue;
713
714 GroupPtr geomGroup (new tcu::TestCaseGroup(testCtx, gType.name, ""));
715
716 for (size_t scalingIdx = 0; scalingIdx < scalingFactors.size(); ++scalingIdx)
717 {
718 const auto scale = scalingFactors[scalingIdx];
719 const auto scaleName = "scaling_factor_" + de::toString(scalingIdx);
720 GroupPtr factorGroup (new tcu::TestCaseGroup(testCtx, scaleName.c_str(), ""));
721
722 for (size_t rotationIdx = 0; rotationIdx < rotationAngles.size(); ++rotationIdx)
723 {
724 const auto angles = rotationAngles[rotationIdx];
725 const auto angleName = "rotation_" + de::toString(rotationIdx);
726 const auto geometryType = gType.geometryType;
727 const auto rayOrigType = RayOriginType::OUTSIDE;
728 const auto rayEndType = RayEndType::CROSS;
729
730 SpaceObjects spaceObjects(rayOrigType, geometryType);
731
732 TestParams params =
733 {
734 spaceObjects, // SpaceObjects spaceObjects;
735 scale, // float directionScale;
736 angles.first, // float rotationX;
737 angles.second, // float rotationY;
738 stageData.hitStage, // VkShaderStageFlagBits hitStage;
739 geometryType, // VkGeometryTypeKHR geometryType;
740 // Use arrays of pointers when building the TLAS in every other test.
741 (caseCounter % 2u == 0u), // bool useArraysOfPointers;
742 // Sometimes, update matrix after building the lop level AS and before submitting the command buffer.
743 (caseCounter % 3u == 0u), // bool updateMatrixAfterBuild;
744 rayOrigType, // RayOriginType rayOriginType;
745 rayEndType, // RayEndType rayEndType;
746 };
747 ++caseCounter;
748
749 factorGroup->addChild(new DirectionTestCase(testCtx, angleName, "", params));
750 }
751
752 geomGroup->addChild(factorGroup.release());
753 }
754
755 stageGroup->addChild(geomGroup.release());
756 }
757
758 directionGroup->addChild(stageGroup.release());
759 }
760
761 return directionGroup.release();
762 }
763
createInsideAABBsTests(tcu::TestContext & testCtx)764 tcu::TestCaseGroup* createInsideAABBsTests(tcu::TestContext& testCtx)
765 {
766 GroupPtr insideAABBsGroup (new tcu::TestCaseGroup(testCtx, "inside_aabbs", "Test shooting rays that start inside AABBs"));
767
768 struct
769 {
770 VkShaderStageFlagBits hitStage;
771 const char* name;
772 } stages[] =
773 {
774 { VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR, "chit" },
775 { VK_SHADER_STAGE_ANY_HIT_BIT_KHR, "ahit" },
776 { VK_SHADER_STAGE_INTERSECTION_BIT_KHR, "isec" },
777 };
778
779 struct
780 {
781 RayEndType rayEndType;
782 const char* name;
783 } rayEndCases[] =
784 {
785 { RayEndType::ZERO, "tmax_zero" },
786 { RayEndType::INSIDE, "inside" },
787 { RayEndType::EDGE, "edge" },
788 { RayEndType::OUTSIDE, "outside" },
789 };
790
791 de::Random rnd(1621936010u);
792
793 // Scaling factors and rotation angles.
794 const auto scalingFactors = generateScalingFactors(rnd);
795 const auto rotationAngles = generateRotationAngles(rnd);
796
797 for (int stageIdx = 0; stageIdx < DE_LENGTH_OF_ARRAY(stages); ++stageIdx)
798 {
799 const auto& stageData = stages[stageIdx];
800 GroupPtr stageGroup (new tcu::TestCaseGroup(testCtx, stageData.name, ""));
801
802 for (int rayEndCaseIdx = 0; rayEndCaseIdx < DE_LENGTH_OF_ARRAY(rayEndCases); ++rayEndCaseIdx)
803 {
804 const auto& rayEndCase = rayEndCases[rayEndCaseIdx];
805 const std::string rayEndName = std::string("ray_end_") + rayEndCase.name;
806 GroupPtr rayEndGroup (new tcu::TestCaseGroup(testCtx, rayEndName.c_str(), ""));
807
808 for (size_t scalingIdx = 0; scalingIdx < scalingFactors.size(); ++scalingIdx)
809 {
810 const auto scale = scalingFactors[scalingIdx];
811 const auto scaleName = "scaling_factor_" + de::toString(scalingIdx);
812 GroupPtr factorGroup (new tcu::TestCaseGroup(testCtx, scaleName.c_str(), ""));
813
814 for (size_t rotationIdx = 0; rotationIdx < rotationAngles.size(); ++rotationIdx)
815 {
816 const auto angles = rotationAngles[rotationIdx];
817 const auto angleName = "rotation_" + de::toString(rotationIdx);
818 const auto geometryType = VK_GEOMETRY_TYPE_AABBS_KHR;
819 const auto rayOrigType = RayOriginType::INSIDE;
820
821 SpaceObjects spaceObjects(rayOrigType, geometryType);
822
823 TestParams params =
824 {
825 spaceObjects, // SpaceObjects spaceObjects;
826 scale, // float directionScale;
827 angles.first, // float rotationX;
828 angles.second, // float rotationY;
829 stageData.hitStage, // VkShaderStageFlagBits hitStage;
830 geometryType, // VkGeometryTypeKHR geometryType;
831 false, // bool useArraysOfPointers;
832 false, // bool updateMatrixAfterBuild;
833 rayOrigType, // RayOriginType rayOriginType;
834 rayEndCase.rayEndType, // RayEndType rayEndType;
835 };
836
837 factorGroup->addChild(new DirectionTestCase(testCtx, angleName, "", params));
838 }
839
840 rayEndGroup->addChild(factorGroup.release());
841 }
842
843 stageGroup->addChild(rayEndGroup.release());
844 }
845
846 insideAABBsGroup->addChild(stageGroup.release());
847 }
848
849 return insideAABBsGroup.release();
850 }
851
852 } // RayTracing
853 } // vkt
854