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