xref: /aosp_15_r20/external/deqp/external/vulkancts/modules/vulkan/ray_query/vktRayQueryDirectionTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
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 &params);
~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 &params);
~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 &params)
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 &params)
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