• 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 Barycentric Coordinates Tests
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktRayQueryBarycentricCoordinatesTests.hpp"
26 #include "vktTestCase.hpp"
27 
28 #include "vkRayTracingUtil.hpp"
29 #include "vkObjUtil.hpp"
30 #include "vkCmdUtil.hpp"
31 #include "vkBufferWithMemory.hpp"
32 #include "vkBuilderUtil.hpp"
33 #include "vkTypeUtil.hpp"
34 #include "vkBarrierUtil.hpp"
35 
36 #include "deUniquePtr.hpp"
37 #include "deRandom.hpp"
38 
39 #include <sstream>
40 #include <vector>
41 
42 namespace vkt
43 {
44 namespace RayQuery
45 {
46 
47 namespace
48 {
49 
50 using namespace vk;
51 
52 struct TestParams
53 {
54 	deUint32				seed;
55 };
56 
57 constexpr float		kZCoord		= 5.0f;
58 constexpr float		kXYCoordAbs	= 1.0f;
59 
60 constexpr float		kThreshold	= 0.001f;				// For the resulting coordinates.
61 constexpr float		kTMin		= 1.0f - kThreshold;	// Require the same precision in T.
62 constexpr float		kTMax		= 1.0f + kThreshold;	// Ditto.
63 constexpr deUint32	kNumRays	= 20u;
64 
65 class BarycentricCoordinatesCase : public TestCase
66 {
67 public:
68 							BarycentricCoordinatesCase	(tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestParams& params);
~BarycentricCoordinatesCase(void)69 	virtual					~BarycentricCoordinatesCase	(void) {}
70 
71 	virtual void			checkSupport				(Context& context) const;
72 	virtual void			initPrograms				(vk::SourceCollections& programCollection) const;
73 	virtual TestInstance*	createInstance				(Context& context) const;
74 
75 protected:
76 	TestParams				m_params;
77 };
78 
79 class BarycentricCoordinatesInstance : public TestInstance
80 {
81 public:
82 								BarycentricCoordinatesInstance	(Context& context, const TestParams& params);
~BarycentricCoordinatesInstance(void)83 	virtual						~BarycentricCoordinatesInstance	(void) {}
84 
85 	virtual tcu::TestStatus		iterate							(void);
86 
87 protected:
88 	TestParams					m_params;
89 };
90 
BarycentricCoordinatesCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,const TestParams & params)91 BarycentricCoordinatesCase::BarycentricCoordinatesCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestParams& params)
92 	: TestCase	(testCtx, name, description)
93 	, m_params	(params)
94 {}
95 
checkSupport(Context & context) const96 void BarycentricCoordinatesCase::checkSupport (Context& context) const
97 {
98 	context.requireDeviceFunctionality("VK_KHR_acceleration_structure");
99 	context.requireDeviceFunctionality("VK_KHR_ray_query");
100 }
101 
initPrograms(vk::SourceCollections & programCollection) const102 void BarycentricCoordinatesCase::initPrograms (vk::SourceCollections& programCollection) const
103 {
104 	const vk::ShaderBuildOptions buildOptions (programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_4, 0u, true);
105 
106 	std::ostringstream comp;
107 	comp
108 		<< "#version 460 core\n"
109 		<< "#extension GL_EXT_ray_query : require\n"
110 		<< "\n"
111 		<< "layout(local_size_x=" << kNumRays << ", local_size_y=1, local_size_z=1) in;\n"
112 		<< "\n"
113 		<< "layout(set=0, binding=0) uniform accelerationStructureEXT topLevelAS;\n"
114 		<< "layout(set=0, binding=1) uniform RayDirections {\n"
115 		<< "  vec4 values[" << kNumRays << "];\n"
116 		<< "} directions;\n"
117 		<< "layout(set=0, binding=2, std430) buffer OutputBarycentrics {\n"
118 		<< "  vec4 values[" << kNumRays << "];\n"
119 		<< "} coordinates;\n"
120 		<< "\n"
121 		<< "void main()\n"
122 		<< "{\n"
123 		<< "  const uint  cullMask  = 0xFF;\n"
124 		<< "  const vec3  origin    = vec3(0.0, 0.0, 0.0);\n"
125 		<< "  const vec3  direction = directions.values[gl_LocalInvocationID.x].xyz;\n"
126 		<< "  const float tMin      = " << kTMin << ";\n"
127 		<< "  const float tMax      = " << kTMax << ";\n"
128 		<< "  vec4        outputVal = vec4(-1.0, -1.0, -1.0, -1.0);\n"
129 		<< "  rayQueryEXT rq;\n"
130 		<< "  rayQueryInitializeEXT(rq, topLevelAS, gl_RayFlagsNoneEXT, cullMask, origin, tMin, direction, tMax);\n"
131 		<< "  while (rayQueryProceedEXT(rq)) {\n"
132 		<< "    if (rayQueryGetIntersectionTypeEXT(rq, false) == gl_RayQueryCandidateIntersectionTriangleEXT) {\n"
133 		<< "      outputVal = vec4(rayQueryGetIntersectionBarycentricsEXT(rq, false), 0.0, 0.0);\n"
134 		<< "    }\n"
135 		<< "  }\n"
136 		<< "  coordinates.values[gl_LocalInvocationID.x] = vec4(outputVal);\n"
137 		<< "}\n"
138 		;
139 
140 	programCollection.glslSources.add("comp") << glu::ComputeSource(updateRayTracingGLSL(comp.str())) << buildOptions;
141 }
142 
createInstance(Context & context) const143 TestInstance* BarycentricCoordinatesCase::createInstance (Context& context) const
144 {
145 	return new BarycentricCoordinatesInstance(context, m_params);
146 }
147 
BarycentricCoordinatesInstance(Context & context,const TestParams & params)148 BarycentricCoordinatesInstance::BarycentricCoordinatesInstance (Context& context, const TestParams& params)
149 	: TestInstance	(context)
150 	, m_params		(params)
151 {}
152 
153 // Calculates coordinates in a triangle given barycentric coordinates b and c.
calcCoordinates(const std::vector<tcu::Vec3> & triangle,float b,float c)154 tcu::Vec3 calcCoordinates (const std::vector<tcu::Vec3>& triangle, float b, float c)
155 {
156 	DE_ASSERT(triangle.size() == 3u);
157 	DE_ASSERT(b > 0.0f);
158 	DE_ASSERT(c > 0.0f);
159 	DE_ASSERT(b + c < 1.0f);
160 
161 	const float a = 1.0f - b - c;
162 	DE_ASSERT(a > 0.0f);
163 
164 	return triangle[0] * a + triangle[1] * b + triangle[2] * c;
165 }
166 
167 // Return a, b, c with a close to 1.0f and (b, c) close to 0.0f.
getBarycentricVertex(void)168 tcu::Vec3 getBarycentricVertex (void)
169 {
170 	const float a = 0.999f;
171 	const float aux = 1.0f - a;
172 	const float b = aux / 2.0f;
173 	const float c = b;
174 
175 	return tcu::Vec3(a, b, c);
176 }
177 
extendToV4(const tcu::Vec3 & vec3)178 tcu::Vec4 extendToV4 (const tcu::Vec3& vec3)
179 {
180 	return tcu::Vec4(vec3.x(), vec3.y(), vec3.z(), 0.0f);
181 }
182 
iterate(void)183 tcu::TestStatus BarycentricCoordinatesInstance::iterate (void)
184 {
185 	const auto&	vkd		= m_context.getDeviceInterface();
186 	const auto	device	= m_context.getDevice();
187 	auto&		alloc	= m_context.getDefaultAllocator();
188 	const auto	qIndex	= m_context.getUniversalQueueFamilyIndex();
189 	const auto	queue	= m_context.getUniversalQueue();
190 	const auto	stages	= VK_SHADER_STAGE_COMPUTE_BIT;
191 
192 	// Command pool and buffer.
193 	const auto cmdPool		= makeCommandPool(vkd, device, qIndex);
194 	const auto cmdBufferPtr	= allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
195 	const auto cmdBuffer	= cmdBufferPtr.get();
196 
197 	beginCommandBuffer(vkd, cmdBuffer);
198 
199 	// Build acceleration structures.
200 	auto topLevelAS		= makeTopLevelAccelerationStructure();
201 	auto bottomLevelAS	= makeBottomLevelAccelerationStructure();
202 
203 	const std::vector<tcu::Vec3> triangle =
204 	{
205 		tcu::Vec3(        0.0f, -kXYCoordAbs, kZCoord),
206 		tcu::Vec3(-kXYCoordAbs,  kXYCoordAbs, kZCoord),
207 		tcu::Vec3( kXYCoordAbs,  kXYCoordAbs, kZCoord),
208 	};
209 
210 	bottomLevelAS->addGeometry(triangle, true/*is triangles*/, VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR);
211 	bottomLevelAS->createAndBuild(vkd, device, cmdBuffer, alloc);
212 	de::SharedPtr<BottomLevelAccelerationStructure> blasSharedPtr (bottomLevelAS.release());
213 
214 	topLevelAS->setInstanceCount(1);
215 	topLevelAS->addInstance(blasSharedPtr, identityMatrix3x4, 0, 0xFFu, 0u, VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR);
216 	topLevelAS->createAndBuild(vkd, device, cmdBuffer, alloc);
217 
218 	// Uniform buffer for directions.
219 	const auto directionsBufferSize		= static_cast<VkDeviceSize>(sizeof(tcu::Vec4) * kNumRays);
220 	const auto directionsBufferInfo		= makeBufferCreateInfo(directionsBufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
221 	BufferWithMemory directionsBuffer	(vkd, device, alloc, directionsBufferInfo, MemoryRequirement::HostVisible);
222 	auto& directionsBufferAlloc			= directionsBuffer.getAllocation();
223 	void* directionsBufferData			= directionsBufferAlloc.getHostPtr();
224 
225 	// Generate rays towards the 3 triangle coordinates (avoiding exact vertices) and additional coordinates.
226 	std::vector<tcu::Vec4> directions;
227 	std::vector<tcu::Vec4> expectedOutputCoordinates;
228 	directions.reserve(kNumRays);
229 	expectedOutputCoordinates.reserve(kNumRays);
230 
231 	const auto barycentricABC = getBarycentricVertex();
232 
233 	directions.push_back(extendToV4(calcCoordinates(triangle, barycentricABC.x(), barycentricABC.y())));
234 	directions.push_back(extendToV4(calcCoordinates(triangle, barycentricABC.y(), barycentricABC.x())));
235 	directions.push_back(extendToV4(calcCoordinates(triangle, barycentricABC.y(), barycentricABC.z())));
236 
237 	expectedOutputCoordinates.push_back(tcu::Vec4(barycentricABC.x(), barycentricABC.y(), 0.0f, 0.0f));
238 	expectedOutputCoordinates.push_back(tcu::Vec4(barycentricABC.y(), barycentricABC.x(), 0.0f, 0.0f));
239 	expectedOutputCoordinates.push_back(tcu::Vec4(barycentricABC.y(), barycentricABC.z(), 0.0f, 0.0f));
240 
241 	de::Random rnd(m_params.seed);
242 	while (directions.size() < kNumRays)
243 	{
244 		// Avoid 0.0 when choosing b and c.
245 		float b;
246 		while ((b = rnd.getFloat()) == 0.0f)
247 			;
248 		float c;
249 		while ((c = rnd.getFloat(0.0f, 1.0f - b)) == 0.0f)
250 			;
251 
252 		expectedOutputCoordinates.push_back(tcu::Vec4(b, c, 0.0f, 0.0f));
253 		directions.push_back(extendToV4(calcCoordinates(triangle, b, c)));
254 	}
255 
256 	deMemcpy(directionsBufferData, directions.data(), directionsBufferSize);
257 	flushAlloc(vkd, device, directionsBufferAlloc);
258 
259 	// Storage buffer for output barycentric coordinates.
260 	const auto barycoordsBufferSize		= static_cast<VkDeviceSize>(sizeof(tcu::Vec4) * kNumRays);
261 	const auto barycoordsBufferInfo		= makeBufferCreateInfo(barycoordsBufferSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
262 	BufferWithMemory barycoordsBuffer	(vkd, device, alloc, barycoordsBufferInfo, MemoryRequirement::HostVisible);
263 	auto& barycoordsBufferAlloc			= barycoordsBuffer.getAllocation();
264 	void* barycoordsBufferData			= barycoordsBufferAlloc.getHostPtr();
265 	deMemset(barycoordsBufferData, 0, static_cast<size_t>(barycoordsBufferSize));
266 	flushAlloc(vkd, device, barycoordsBufferAlloc);
267 
268 	// Descriptor set layout.
269 	DescriptorSetLayoutBuilder dsLayoutBuilder;
270 	dsLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, stages);
271 	dsLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, stages);
272 	dsLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, stages);
273 	const auto setLayout = dsLayoutBuilder.build(vkd, device);
274 
275 	// Pipeline layout.
276 	const auto pipelineLayout = makePipelineLayout(vkd, device, setLayout.get());
277 
278 	// Descriptor pool and set.
279 	DescriptorPoolBuilder poolBuilder;
280 	poolBuilder.addType(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR);
281 	poolBuilder.addType(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
282 	poolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
283 	const auto descriptorPool	= poolBuilder.build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
284 	const auto descriptorSet	= makeDescriptorSet(vkd, device, descriptorPool.get(), setLayout.get());
285 
286 	// Update descriptor set.
287 	{
288 		const VkWriteDescriptorSetAccelerationStructureKHR accelDescInfo =
289 		{
290 			VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR,
291 			nullptr,
292 			1u,
293 			topLevelAS.get()->getPtr(),
294 		};
295 		const auto uniformBufferInfo = makeDescriptorBufferInfo(directionsBuffer.get(), 0ull, VK_WHOLE_SIZE);
296 		const auto storageBufferInfo = makeDescriptorBufferInfo(barycoordsBuffer.get(), 0ull, VK_WHOLE_SIZE);
297 
298 		DescriptorSetUpdateBuilder updateBuilder;
299 		updateBuilder.writeSingle(descriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, &accelDescInfo);
300 		updateBuilder.writeSingle(descriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &uniformBufferInfo);
301 		updateBuilder.writeSingle(descriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(2u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &storageBufferInfo);
302 		updateBuilder.update(vkd, device);
303 	}
304 
305 	// Shader module.
306 	const auto compModule = createShaderModule(vkd, device, m_context.getBinaryCollection().get("comp"), 0);
307 
308 	// Pipeline.
309 	const VkPipelineShaderStageCreateInfo shaderInfo =
310 	{
311 		VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,	//	VkStructureType						sType;
312 		nullptr,												//	const void*							pNext;
313 		0u,														//	VkPipelineShaderStageCreateFlags	flags;
314 		VK_SHADER_STAGE_COMPUTE_BIT,							//	VkShaderStageFlagBits				stage;
315 		compModule.get(),										//	VkShaderModule						module;
316 		"main",													//	const char*							pName;
317 		nullptr,												//	const VkSpecializationInfo*			pSpecializationInfo;
318 	};
319 	const VkComputePipelineCreateInfo pipelineInfo =
320 	{
321 		VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,	//	VkStructureType					sType;
322 		nullptr,										//	const void*						pNext;
323 		0u,												//	VkPipelineCreateFlags			flags;
324 		shaderInfo,										//	VkPipelineShaderStageCreateInfo	stage;
325 		pipelineLayout.get(),							//	VkPipelineLayout				layout;
326 		DE_NULL,										//	VkPipeline						basePipelineHandle;
327 		0,												//	deInt32							basePipelineIndex;
328 	};
329 	const auto pipeline = createComputePipeline(vkd, device, DE_NULL, &pipelineInfo);
330 
331 	// Dispatch work with ray queries.
332 	vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline.get());
333 	vkd.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipelineLayout.get(), 0u, 1u, &descriptorSet.get(), 0u, nullptr);
334 	vkd.cmdDispatch(cmdBuffer, 1u, 1u, 1u);
335 
336 	// Barrier for the output buffer.
337 	const auto bufferBarrier = makeMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
338 	vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 1u, &bufferBarrier, 0u, nullptr, 0u, nullptr);
339 
340 	endCommandBuffer(vkd, cmdBuffer);
341 	submitCommandsAndWait(vkd, device, queue, cmdBuffer);
342 
343 	// Verify results.
344 	std::vector<tcu::Vec4>	outputData				(expectedOutputCoordinates.size());
345 	const auto				barycoordsBufferSizeSz	= static_cast<size_t>(barycoordsBufferSize);
346 
347 	invalidateAlloc(vkd, device, barycoordsBufferAlloc);
348 	DE_ASSERT(de::dataSize(outputData) == barycoordsBufferSizeSz);
349 	deMemcpy(outputData.data(), barycoordsBufferData, barycoordsBufferSizeSz);
350 
351 	for (size_t i = 0; i < outputData.size(); ++i)
352 	{
353 		const auto& outVal		= outputData[i];
354 		const auto& expectedVal	= expectedOutputCoordinates[i];
355 
356 		if (outVal.z() != 0.0f || outVal.w() != 0.0f || de::abs(outVal.x() - expectedVal.x()) > kThreshold || de::abs(outVal.y() - expectedVal.y()) > kThreshold)
357 		{
358 			std::ostringstream msg;
359 			msg << "Unexpected value found for ray " << i << ": expected " << expectedVal << " and found " << outVal << ";";
360 			TCU_FAIL(msg.str());
361 		}
362 	}
363 
364 	return tcu::TestStatus::pass("Pass");
365 }
366 
367 } // anonymous
368 
createBarycentricCoordinatesTests(tcu::TestContext & testCtx)369 tcu::TestCaseGroup*	createBarycentricCoordinatesTests (tcu::TestContext& testCtx)
370 {
371 	using GroupPtr = de::MovePtr<tcu::TestCaseGroup>;
372 
373 	GroupPtr mainGroup(new tcu::TestCaseGroup(testCtx, "barycentric_coordinates", "Test barycentric coordinates reported by the ray query"));
374 
375 	deUint32 seed = 1614674687u;
376 	mainGroup->addChild(new BarycentricCoordinatesCase(testCtx, "compute", "", TestParams{seed++}));
377 
378 	return mainGroup.release();
379 }
380 
381 } // RayQuery
382 } // vkt
383 
384