• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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