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 Query Direction Tests
23 *//*--------------------------------------------------------------------*/
24
25 #include "vktRayQueryDirectionTests.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 RayQuery
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::RayQuery::__anon028699060111::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::RayQuery::__anon028699060111::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::RayQuery::__anon028699060111::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 VkGeometryTypeKHR geometryType;
215 bool useArraysOfPointers;
216 bool updateMatrixAfterBuild;
217 RayOriginType rayOriginType;
218 RayEndType rayEndtype;
219 };
220
221 class DirectionTestCase : public vkt::TestCase
222 {
223 public:
224 DirectionTestCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestParams& params);
~DirectionTestCase(void)225 virtual ~DirectionTestCase (void) {}
226
227 virtual void checkSupport (Context& context) const;
228 virtual void initPrograms (vk::SourceCollections& programCollection) const;
229 virtual TestInstance* createInstance (Context& context) const;
230
231 protected:
232 TestParams m_params;
233 };
234
235 class DirectionTestInstance : public vkt::TestInstance
236 {
237 public:
238 DirectionTestInstance (Context& context, const TestParams& params);
~DirectionTestInstance(void)239 virtual ~DirectionTestInstance (void) {}
240
241 virtual tcu::TestStatus iterate (void);
242
243 protected:
244 TestParams m_params;
245 };
246
247
DirectionTestCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,const TestParams & params)248 DirectionTestCase::DirectionTestCase(tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestParams& params)
249 : vkt::TestCase (testCtx, name, description)
250 , m_params (params)
251 {}
252
checkSupport(Context & context) const253 void DirectionTestCase::checkSupport (Context& context) const
254 {
255 context.requireDeviceFunctionality("VK_KHR_acceleration_structure");
256 context.requireDeviceFunctionality("VK_KHR_ray_query");
257 }
258
259 // Push constants. They need to match the shaders.
260 // Note: origin and direction will be used as a Vec3. Declaring them as Vec4 eases matching alignments.
261 struct PushConstants
262 {
263 tcu::Vec4 origin;
264 tcu::Vec4 direction;
265 float tmix;
266 float tmax;
267 };
268
toVec4(const tcu::Vec3 & vec3)269 tcu::Vec4 toVec4 (const tcu::Vec3& vec3)
270 {
271 return tcu::Vec4(vec3.x(), vec3.y(), vec3.z(), 0.0f);
272 }
273
initPrograms(vk::SourceCollections & programCollection) const274 void DirectionTestCase::initPrograms (vk::SourceCollections& programCollection) const
275 {
276 const vk::ShaderBuildOptions buildOptions (programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_4, 0u, true);
277
278 std::ostringstream comp;
279 comp
280 << "#version 460 core\n"
281 << "#extension GL_EXT_ray_query : require\n"
282 << "\n"
283 << "layout(local_size_x=1, local_size_y=1, local_size_z=1) in;\n"
284 << "\n"
285 << "layout(set=0, binding=0) uniform accelerationStructureEXT topLevelAS;\n"
286 << "layout(set=0, binding=1, std430) buffer OutBuffer { float val; } outBuffer;\n"
287 // Needs to match the PushConstants struct above.
288 << "layout(push_constant, std430) uniform PushConstants {\n"
289 << " vec4 origin;\n"
290 << " vec4 direction;\n"
291 << " float tmin;\n"
292 << " float tmax;\n"
293 << "} pc;\n"
294 << "\n"
295 << "void main()\n"
296 << "{\n"
297 << " const uint cullMask = 0xFF;\n"
298 << " float outVal = -10000.0f;\n"
299 << " rayQueryEXT rq;\n"
300 << " rayQueryInitializeEXT(rq, topLevelAS, gl_RayFlagsNoneEXT, cullMask, pc.origin.xyz, pc.tmin, pc.direction.xyz, pc.tmax);\n"
301 << " while (rayQueryProceedEXT(rq)) {\n"
302 << " const uint candidateType = rayQueryGetIntersectionTypeEXT(rq, false);\n"
303 << " if (candidateType == gl_RayQueryCandidateIntersectionTriangleEXT) {\n"
304 << " outVal = rayQueryGetIntersectionTEXT(rq, false);\n"
305 << " }\n"
306 << " else if (candidateType == gl_RayQueryCandidateIntersectionAABBEXT) {\n"
307 << " outVal = pc.tmin;\n"
308 << " }\n"
309 << " }\n"
310 << " outBuffer.val = outVal;\n"
311 << "}\n"
312 ;
313
314 programCollection.glslSources.add("comp") << glu::ComputeSource(updateRayTracingGLSL(comp.str())) << buildOptions;
315 }
316
createInstance(Context & context) const317 TestInstance* DirectionTestCase::createInstance (Context& context) const
318 {
319 return new DirectionTestInstance(context, m_params);
320 }
321
DirectionTestInstance(Context & context,const TestParams & params)322 DirectionTestInstance::DirectionTestInstance (Context& context, const TestParams& params)
323 : vkt::TestInstance (context)
324 , m_params (params)
325 {}
326
iterate(void)327 tcu::TestStatus DirectionTestInstance::iterate (void)
328 {
329 const auto& vkd = m_context.getDeviceInterface();
330 const auto device = m_context.getDevice();
331 auto& alloc = m_context.getDefaultAllocator();
332 const auto qIndex = m_context.getUniversalQueueFamilyIndex();
333 const auto queue = m_context.getUniversalQueue();
334 const auto stages = VK_SHADER_STAGE_COMPUTE_BIT;
335 const auto pcSize = static_cast<deUint32>(sizeof(PushConstants));
336
337 const auto scaleMatrix = getScaleMatrix(m_params.directionScale);
338 const auto rotationMatrix = getRotationMatrix(m_params.rotationX, m_params.rotationY);
339 const auto transformMatrix = toTransformMatrixKHR(rotationMatrix);
340
341 // Command pool and buffer.
342 const auto cmdPool = makeCommandPool(vkd, device, qIndex);
343 const auto cmdBufferPtr = allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
344 const auto cmdBuffer = cmdBufferPtr.get();
345
346 beginCommandBuffer(vkd, cmdBuffer);
347
348 // Build acceleration structures.
349 auto topLevelAS = makeTopLevelAccelerationStructure();
350 auto bottomLevelAS = makeBottomLevelAccelerationStructure();
351
352 const bool isTriangles = (m_params.geometryType == VK_GEOMETRY_TYPE_TRIANGLES_KHR);
353 const VkGeometryInstanceFlagsKHR instanceFlags = (isTriangles ? VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR : 0);
354
355 bottomLevelAS->addGeometry(m_params.spaceObjects.geometry, isTriangles, VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR);
356 bottomLevelAS->createAndBuild(vkd, device, cmdBuffer, alloc);
357
358 de::SharedPtr<BottomLevelAccelerationStructure> blasSharedPtr (bottomLevelAS.release());
359 topLevelAS->setUseArrayOfPointers(m_params.useArraysOfPointers);
360 topLevelAS->setUsePPGeometries(m_params.useArraysOfPointers);
361 topLevelAS->setInstanceCount(1);
362 {
363 const auto& initialMatrix = (m_params.updateMatrixAfterBuild ? identityMatrix3x4 : transformMatrix);
364 topLevelAS->addInstance(blasSharedPtr, initialMatrix, 0, 0xFFu, 0u, instanceFlags);
365 }
366 topLevelAS->createAndBuild(vkd, device, cmdBuffer, alloc);
367 if (m_params.updateMatrixAfterBuild)
368 topLevelAS->updateInstanceMatrix(vkd, device, 0u, transformMatrix);
369
370 // Create output buffer.
371 const auto bufferSize = static_cast<VkDeviceSize>(sizeof(float));
372 const auto bufferCreateInfo = makeBufferCreateInfo(bufferSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
373 BufferWithMemory buffer (vkd, device, alloc, bufferCreateInfo, MemoryRequirement::HostVisible);
374 auto& bufferAlloc = buffer.getAllocation();
375
376 // Fill output buffer with an initial value.
377 deMemset(bufferAlloc.getHostPtr(), 0, sizeof(float));
378 flushAlloc(vkd, device, bufferAlloc);
379
380 // Descriptor set layout and pipeline layout.
381 DescriptorSetLayoutBuilder setLayoutBuilder;
382 setLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, stages);
383 setLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, stages);
384 const auto setLayout = setLayoutBuilder.build(vkd, device);
385
386 const auto pcRange = makePushConstantRange(stages, 0u, pcSize);
387 const auto pipelineLayout = makePipelineLayout(vkd, device, 1u, &setLayout.get(), 1u, &pcRange);
388
389 // Descriptor pool and set.
390 DescriptorPoolBuilder poolBuilder;
391 poolBuilder.addType(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR);
392 poolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1u);
393 const auto descriptorPool = poolBuilder.build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
394 const auto descriptorSet = makeDescriptorSet(vkd, device, descriptorPool.get(), setLayout.get());
395
396 // Update descriptor set.
397 {
398 const VkWriteDescriptorSetAccelerationStructureKHR accelDescInfo =
399 {
400 VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR,
401 nullptr,
402 1u,
403 topLevelAS.get()->getPtr(),
404 };
405
406 const auto bufferDescInfo = makeDescriptorBufferInfo(buffer.get(), 0ull, VK_WHOLE_SIZE);
407
408 DescriptorSetUpdateBuilder updateBuilder;
409 updateBuilder.writeSingle(descriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, &accelDescInfo);
410 updateBuilder.writeSingle(descriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &bufferDescInfo);
411 updateBuilder.update(vkd, device);
412 }
413
414 // Shader module and pipeline.
415 const auto compModule = createShaderModule(vkd, device, m_context.getBinaryCollection().get("comp"), 0);
416
417 const VkPipelineShaderStageCreateInfo shaderInfo =
418 {
419 VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
420 nullptr, // const void* pNext;
421 0u, // VkPipelineShaderStageCreateFlags flags;
422 VK_SHADER_STAGE_COMPUTE_BIT, // VkShaderStageFlagBits stage;
423 compModule.get(), // VkShaderModule module;
424 "main", // const char* pName;
425 nullptr, // const VkSpecializationInfo* pSpecializationInfo;
426 };
427 const VkComputePipelineCreateInfo pipelineInfo =
428 {
429 VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, // VkStructureType sType;
430 nullptr, // const void* pNext;
431 0u, // VkPipelineCreateFlags flags;
432 shaderInfo, // VkPipelineShaderStageCreateInfo stage;
433 pipelineLayout.get(), // VkPipelineLayout layout;
434 DE_NULL, // VkPipeline basePipelineHandle;
435 0, // deInt32 basePipelineIndex;
436 };
437 const auto pipeline = createComputePipeline(vkd, device, DE_NULL, &pipelineInfo);
438
439 // Push constants.
440 const auto rotatedOrigin = m_params.spaceObjects.origin * rotationMatrix;
441 const auto finalDirection = m_params.spaceObjects.direction * scaleMatrix * rotationMatrix;
442 const auto distanceToEdge = SpaceObjects::getDistanceToEdge(m_params.directionScale);
443 const auto tMinMax = calcTminTmax(m_params.rayOriginType, m_params.rayEndtype, distanceToEdge);
444 const PushConstants pcData =
445 {
446 toVec4(rotatedOrigin), // tcu::Vec4 origin;
447 toVec4(finalDirection), // tcu::Vec4 direction;
448 tMinMax.first, // float tmix;
449 tMinMax.second, // float tmax;
450 };
451
452 // Trace rays.
453 vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline.get());
454 vkd.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipelineLayout.get(), 0u, 1u, &descriptorSet.get(), 0u, nullptr);
455 vkd.cmdPushConstants(cmdBuffer, pipelineLayout.get(), stages, 0u, pcSize, &pcData);
456 vkd.cmdDispatch(cmdBuffer, 1u, 1u, 1u);
457
458 // Barrier for the output buffer.
459 const auto bufferBarrier = makeMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
460 vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 1u, &bufferBarrier, 0u, nullptr, 0u, nullptr);
461
462 endCommandBuffer(vkd, cmdBuffer);
463 submitCommandsAndWait(vkd, device, queue, cmdBuffer);
464
465 // Read value back from the buffer.
466 float bufferValue = 0.0f;
467 invalidateAlloc(vkd, device, bufferAlloc);
468 deMemcpy(&bufferValue, bufferAlloc.getHostPtr(), sizeof(bufferValue));
469
470 if (m_params.rayEndtype == RayEndType::CROSS)
471 {
472 // Shooting from the ouside.
473 if (de::abs(bufferValue - distanceToEdge) > kDefaultTolerance)
474 {
475 std::ostringstream msg;
476 msg << "Result distance (" << bufferValue << ") differs from expected distance (" << distanceToEdge << ", tolerance " << kDefaultTolerance << ")";
477 TCU_FAIL(msg.str());
478 }
479 }
480 else
481 {
482 // Rays are shot from inside AABBs, rayTMin should be zero and the reported hit distance.
483 if (bufferValue != 0.0f)
484 {
485 std::ostringstream msg;
486 msg << "Result distance nonzero (" << bufferValue << ")";
487 TCU_FAIL(msg.str());
488 }
489 }
490
491 return tcu::TestStatus::pass("Pass");
492 }
493
494 using GroupPtr = de::MovePtr<tcu::TestCaseGroup>;
495
496 // Generate a list of scaling factors suitable for the tests.
generateScalingFactors(de::Random & rnd)497 std::vector<float> generateScalingFactors (de::Random& rnd)
498 {
499 const float kMinScalingFactor = 0.5f;
500 const float kMaxScalingFactor = 10.0f;
501 const int kNumRandomScalingFactors = 5;
502
503 // Scaling factors: 1.0 and some randomly-generated ones.
504 std::vector<float> scalingFactors;
505
506 scalingFactors.reserve(kNumRandomScalingFactors + 1);
507 scalingFactors.push_back(1.0f);
508
509 for (int i = 0; i < kNumRandomScalingFactors; ++i)
510 scalingFactors.push_back(rnd.getFloat() * (kMaxScalingFactor - kMinScalingFactor) + kMinScalingFactor);
511
512 return scalingFactors;
513 }
514
515 // Generate a list of rotation angles suitable for the tests.
generateRotationAngles(de::Random & rnd)516 std::vector<std::pair<float, float>> generateRotationAngles (de::Random& rnd)
517 {
518 const float kPi2 = DE_PI * 2.0f;
519 const int kNumRandomRotations = 4;
520
521 // Rotations: 0.0 on both axis and some randomly-generated ones.
522 std::vector<std::pair<float, float>> rotationAngles;
523
524 rotationAngles.reserve(kNumRandomRotations + 1);
525 rotationAngles.push_back(std::make_pair(0.0f, 0.0f));
526
527 for (int i = 0; i < kNumRandomRotations; ++i)
528 rotationAngles.push_back(std::make_pair(rnd.getFloat() * kPi2, rnd.getFloat() * kPi2));
529
530 return rotationAngles;
531 }
532
533 } // anonymous
534
createDirectionLengthTests(tcu::TestContext & testCtx)535 tcu::TestCaseGroup* createDirectionLengthTests (tcu::TestContext& testCtx)
536 {
537 GroupPtr directionGroup (new tcu::TestCaseGroup(testCtx, "direction_length", "Test direction vector length when using ray queries"));
538
539 struct
540 {
541 VkGeometryTypeKHR geometryType;
542 const char* name;
543 } geometryTypes[] =
544 {
545 { VK_GEOMETRY_TYPE_TRIANGLES_KHR, "triangles" },
546 { VK_GEOMETRY_TYPE_AABBS_KHR, "aabbs" },
547 };
548
549 de::Random rnd(1614686501u);
550 deUint32 caseCounter = 0u;
551
552 // Scaling factors: 1.0 and some randomly-generated ones.
553 // Scaling factors and rotation angles.
554 const auto scalingFactors = generateScalingFactors(rnd);
555 const auto rotationAngles = generateRotationAngles(rnd);
556
557 for (int geometryTypeIdx = 0; geometryTypeIdx < DE_LENGTH_OF_ARRAY(geometryTypes); ++geometryTypeIdx)
558 {
559 const auto& gType = geometryTypes[geometryTypeIdx];
560
561 GroupPtr geomGroup (new tcu::TestCaseGroup(testCtx, gType.name, ""));
562
563 for (size_t scalingIdx = 0; scalingIdx < scalingFactors.size(); ++scalingIdx)
564 {
565 const auto scale = scalingFactors[scalingIdx];
566 const auto scaleName = "scaling_factor_" + de::toString(scalingIdx);
567 GroupPtr factorGroup (new tcu::TestCaseGroup(testCtx, scaleName.c_str(), ""));
568
569 for (size_t rotationIdx = 0; rotationIdx < rotationAngles.size(); ++rotationIdx)
570 {
571 const auto angles = rotationAngles[rotationIdx];
572 const auto angleName = "rotation_" + de::toString(rotationIdx);
573 const auto geometryType = gType.geometryType;
574 const auto rayOrigType = RayOriginType::OUTSIDE;
575 const auto rayEndType = RayEndType::CROSS;
576
577 SpaceObjects spaceObjects(rayOrigType, geometryType);
578
579 TestParams params =
580 {
581 spaceObjects, // SpaceObjects spaceObjects;
582 scale, // float directionScale;
583 angles.first, // float rotationX;
584 angles.second, // float rotationY;
585 geometryType, // VkGeometryTypeKHR geometryType;
586 // Use arrays of pointers when building the TLAS in every other test.
587 (caseCounter % 2u == 0u), // bool useArraysOfPointers;
588 // Sometimes, update matrix after building the lop level AS and before submitting the command buffer.
589 (caseCounter % 3u == 0u), // bool updateMatrixAfterBuild;
590 rayOrigType, // RayOriginType rayOriginType;
591 rayEndType, // RayEndType rayEndType;
592 };
593 ++caseCounter;
594
595 factorGroup->addChild(new DirectionTestCase(testCtx, angleName, "", params));
596 }
597
598 geomGroup->addChild(factorGroup.release());
599 }
600
601 directionGroup->addChild(geomGroup.release());
602 }
603
604 return directionGroup.release();
605 }
606
createInsideAABBsTests(tcu::TestContext & testCtx)607 tcu::TestCaseGroup* createInsideAABBsTests (tcu::TestContext& testCtx)
608 {
609 GroupPtr insideAABBsGroup (new tcu::TestCaseGroup(testCtx, "inside_aabbs", "Test shooting rays that start inside AABBs"));
610
611 struct
612 {
613 RayEndType rayEndType;
614 const char* name;
615 } rayEndCases[] =
616 {
617 { RayEndType::ZERO, "tmax_zero" },
618 { RayEndType::INSIDE, "inside" },
619 { RayEndType::EDGE, "edge" },
620 { RayEndType::OUTSIDE, "outside" },
621 };
622
623 de::Random rnd(1621948244u);
624
625 // Scaling factors: 1.0 and some randomly-generated ones.
626 // Scaling factors and rotation angles.
627 const auto scalingFactors = generateScalingFactors(rnd);
628 const auto rotationAngles = generateRotationAngles(rnd);
629
630 for (int rayEndCaseIdx = 0; rayEndCaseIdx < DE_LENGTH_OF_ARRAY(rayEndCases); ++rayEndCaseIdx)
631 {
632 const auto& rayEndCase = rayEndCases[rayEndCaseIdx];
633 const std::string rayEndName = std::string("ray_end_") + rayEndCase.name;
634 GroupPtr rayEndGroup (new tcu::TestCaseGroup(testCtx, rayEndName.c_str(), ""));
635
636 for (size_t scalingIdx = 0; scalingIdx < scalingFactors.size(); ++scalingIdx)
637 {
638 const auto scale = scalingFactors[scalingIdx];
639 const auto scaleName = "scaling_factor_" + de::toString(scalingIdx);
640 GroupPtr factorGroup (new tcu::TestCaseGroup(testCtx, scaleName.c_str(), ""));
641
642 for (size_t rotationIdx = 0; rotationIdx < rotationAngles.size(); ++rotationIdx)
643 {
644 const auto angles = rotationAngles[rotationIdx];
645 const auto angleName = "rotation_" + de::toString(rotationIdx);
646 const auto geometryType = VK_GEOMETRY_TYPE_AABBS_KHR;
647 const auto rayOrigType = RayOriginType::INSIDE;
648
649 SpaceObjects spaceObjects(rayOrigType, geometryType);
650
651 TestParams params =
652 {
653 spaceObjects, // SpaceObjects spaceObjects;
654 scale, // float directionScale;
655 angles.first, // float rotationX;
656 angles.second, // float rotationY;
657 geometryType, // VkGeometryTypeKHR geometryType;
658 false, // bool useArraysOfPointers;
659 false, // bool updateMatrixAfterBuild;
660 rayOrigType, // RayOriginType rayOriginType;
661 rayEndCase.rayEndType, // RayEndType rayEndType;
662 };
663
664 factorGroup->addChild(new DirectionTestCase(testCtx, angleName, "", params));
665 }
666
667 rayEndGroup->addChild(factorGroup.release());
668 }
669
670 insideAABBsGroup->addChild(rayEndGroup.release());
671 }
672
673 return insideAABBsGroup.release();
674 }
675
676 } // RayQuery
677 } // vkt
678