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