• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*-------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2020 The Khronos Group Inc.
6  * Copyright (c) 2020 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 miscellaneous tests
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktRayQueryMiscTests.hpp"
26 #include "vktTestCase.hpp"
27 
28 #include "vkRayTracingUtil.hpp"
29 #include "vkBufferWithMemory.hpp"
30 #include "vkObjUtil.hpp"
31 #include "vkBuilderUtil.hpp"
32 #include "vkTypeUtil.hpp"
33 #include "vkCmdUtil.hpp"
34 #include "vkBarrierUtil.hpp"
35 #include "vkImageWithMemory.hpp"
36 #include "vkImageUtil.hpp"
37 
38 #include "tcuVector.hpp"
39 #include "tcuStringTemplate.hpp"
40 #include "tcuTextureUtil.hpp"
41 
42 #include "deUniquePtr.hpp"
43 #include "deRandom.hpp"
44 
45 #include <sstream>
46 #include <limits>
47 #include <vector>
48 #include <map>
49 
50 namespace vkt
51 {
52 namespace RayQuery
53 {
54 
55 namespace
56 {
57 
58 using namespace vk;
59 
60 class DynamicIndexingCase : public vkt::TestCase
61 {
62 public:
63 							DynamicIndexingCase		(tcu::TestContext& testCtx, const std::string& name, const std::string& description);
~DynamicIndexingCase(void)64 	virtual					~DynamicIndexingCase	(void) {}
65 
66 	virtual void			initPrograms			(vk::SourceCollections& programCollection) const override;
67 	virtual void			checkSupport			(Context& context) const override;
68 	virtual TestInstance*	createInstance			(Context& context) const override;
69 
70 	// Constants and data types.
71 	static constexpr deUint32	kLocalSizeX	= 48u;
72 	static constexpr deUint32	kNumQueries	= 48u;
73 
74 	// This must match the shader.
75 	struct InputData
76 	{
77 		deUint32 goodQueryIndex;
78 		deUint32 proceedQueryIndex;
79 	};
80 };
81 
82 class DynamicIndexingInstance : public vkt::TestInstance
83 {
84 public:
85 								DynamicIndexingInstance		(Context& context);
~DynamicIndexingInstance(void)86 	virtual						~DynamicIndexingInstance	(void) {}
87 
88 	virtual tcu::TestStatus		iterate						(void);
89 };
90 
DynamicIndexingCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description)91 DynamicIndexingCase::DynamicIndexingCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description)
92 	: vkt::TestCase (testCtx, name, description)
93 {}
94 
initPrograms(vk::SourceCollections & programCollection) const95 void DynamicIndexingCase::initPrograms (vk::SourceCollections& programCollection) const
96 {
97 	const vk::ShaderBuildOptions buildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_4, 0u, true);
98 
99 	std::ostringstream src;
100 
101 	src
102 		<< "#version 460\n"
103 		<< "#extension GL_EXT_ray_query : require\n"
104 		<< "#extension GL_EXT_ray_tracing : require\n"
105 		<< "\n"
106 		<< "layout (local_size_x=" << kLocalSizeX << ", local_size_y=1, local_size_z=1) in; \n"
107 		<< "\n"
108 		<< "struct InputData {\n"
109 		<< "    uint goodQueryIndex;\n"
110 		<< "    uint proceedQueryIndex; // Note: same index as the one above in practice.\n"
111 		<< "};\n"
112 		<< "\n"
113 		<< "layout (set=0, binding=0) uniform accelerationStructureEXT topLevelAS;\n"
114 		<< "layout (set=0, binding=1, std430) buffer InputBlock {\n"
115 		<< "    InputData inputData[];\n"
116 		<< "} inputBlock;\n"
117 		<< "layout (set=0, binding=2, std430) buffer OutputBlock {\n"
118 		<< "    uint outputData[];\n"
119 		<< "} outputBlock;\n"
120 		<< "\n"
121 		<< "void main()\n"
122 		<< "{\n"
123 		<< "    const uint numQueries = " << kNumQueries << ";\n"
124 		<< "\n"
125 		<< "    const uint rayFlags = 0u; \n"
126 		<< "    const uint cullMask = 0xFFu;\n"
127 		<< "    const float tmin = 0.1;\n"
128 		<< "    const float tmax = 10.0;\n"
129 		<< "    const vec3 direct = vec3(0, 0, 1); \n"
130 		<< "\n"
131 		<< "    rayQueryEXT rayQueries[numQueries];\n"
132 		<< "    vec3 origin;\n"
133 		<< "\n"
134 		<< "    InputData inputValues = inputBlock.inputData[gl_LocalInvocationID.x];\n"
135 		<< "\n"
136 		<< "    // Initialize all queries. Only goodQueryIndex will have the right origin for a hit.\n"
137 		<< "    for (int i = 0; i < numQueries; i++) {\n"
138 		<< "        origin = ((i == inputValues.goodQueryIndex) ? vec3(0, 0, 0) : vec3(5, 5, 0));\n"
139 		<< "        rayQueryInitializeEXT(rayQueries[i], topLevelAS, rayFlags, cullMask, origin, tmin, direct, tmax);\n"
140 		<< "    }\n"
141 		<< "\n"
142 		<< "    // Attempt to proceed with the good query to confirm a hit.\n"
143 		<< "    while (rayQueryProceedEXT(rayQueries[inputValues.proceedQueryIndex]))\n"
144 		<< "        outputBlock.outputData[gl_LocalInvocationID.x] = 1u; \n"
145 		<< "}\n"
146 		;
147 
148 	programCollection.glslSources.add("comp") << glu::ComputeSource(updateRayTracingGLSL(src.str())) << buildOptions;
149 }
150 
checkSupport(Context & context) const151 void DynamicIndexingCase::checkSupport (Context& context) const
152 {
153 	context.requireDeviceFunctionality("VK_KHR_acceleration_structure");
154 	context.requireDeviceFunctionality("VK_KHR_ray_query");
155 
156 	const auto& rayQueryFeaturesKHR = context.getRayQueryFeatures();
157 	if (!rayQueryFeaturesKHR.rayQuery)
158 		TCU_THROW(NotSupportedError, "Ray queries not supported");
159 
160 	const auto& accelerationStructureFeaturesKHR = context.getAccelerationStructureFeatures();
161 	if (!accelerationStructureFeaturesKHR.accelerationStructure)
162 		TCU_FAIL("Acceleration structures not supported but ray queries supported");
163 }
164 
createInstance(Context & context) const165 vkt::TestInstance* DynamicIndexingCase::createInstance (Context& context) const
166 {
167 	return new DynamicIndexingInstance(context);
168 }
169 
DynamicIndexingInstance(Context & context)170 DynamicIndexingInstance::DynamicIndexingInstance (Context& context)
171 	: vkt::TestInstance(context)
172 {}
173 
getRndIndex(de::Random & rng,deUint32 size)174 deUint32 getRndIndex (de::Random& rng, deUint32 size)
175 {
176 	DE_ASSERT(size > 0u);
177 	DE_ASSERT(size <= static_cast<deUint32>(std::numeric_limits<int>::max()));
178 
179 	const int	iMin = 0;
180 	const int	iMax = static_cast<int>(size) - 1;
181 
182 	return static_cast<deUint32>(rng.getInt(iMin, iMax));
183 }
184 
iterate(void)185 tcu::TestStatus DynamicIndexingInstance::iterate (void)
186 {
187 	using InputData = DynamicIndexingCase::InputData;
188 	constexpr auto	kLocalSizeX		= DynamicIndexingCase::kLocalSizeX;
189 	constexpr auto	kNumQueries		= DynamicIndexingCase::kNumQueries;
190 
191 	const auto&	vkd		= m_context.getDeviceInterface();
192 	const auto	device	= m_context.getDevice();
193 	auto&		alloc	= m_context.getDefaultAllocator();
194 	const auto	queue	= m_context.getUniversalQueue();
195 	const auto	qIndex	= m_context.getUniversalQueueFamilyIndex();
196 
197 	de::Random rng (1604936737u);
198 	InputData inputDataArray[kLocalSizeX];
199 	deUint32 outputDataArray[kLocalSizeX];
200 
201 	// Prepare input buffer.
202 	for (int i = 0; i < DE_LENGTH_OF_ARRAY(inputDataArray); ++i)
203 	{
204 		// The two values will contain the same query index.
205 		inputDataArray[i].goodQueryIndex	= getRndIndex(rng, kNumQueries);
206 		inputDataArray[i].proceedQueryIndex	= inputDataArray[i].goodQueryIndex;
207 	}
208 
209 	const auto			inputBufferSize		= static_cast<VkDeviceSize>(sizeof(inputDataArray));
210 	const auto			inputBufferInfo		= makeBufferCreateInfo(inputBufferSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
211 	BufferWithMemory	inputBuffer			(vkd, device, alloc, inputBufferInfo, MemoryRequirement::HostVisible);
212 	auto&				inputBufferAlloc	= inputBuffer.getAllocation();
213 	void*				inputBufferPtr		= inputBufferAlloc.getHostPtr();
214 
215 	deMemcpy(inputBufferPtr, inputDataArray, static_cast<size_t>(inputBufferSize));
216 	flushAlloc(vkd, device, inputBufferAlloc);
217 
218 	// Prepare output buffer.
219 	const auto			outputBufferSize	= static_cast<VkDeviceSize>(sizeof(outputDataArray));
220 	const auto			outputBufferInfo	= makeBufferCreateInfo(outputBufferSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
221 	BufferWithMemory	outputBuffer		(vkd, device, alloc, outputBufferInfo, MemoryRequirement::HostVisible);
222 	auto&				outputBufferAlloc	= outputBuffer.getAllocation();
223 	void*				outputBufferPtr		= outputBufferAlloc.getHostPtr();
224 
225 	deMemset(outputBufferPtr, 0, static_cast<size_t>(outputBufferSize));
226 	flushAlloc(vkd, device, outputBufferAlloc);
227 
228 	// Prepare acceleration structures.
229 	const auto cmdPool		= makeCommandPool(vkd, device, qIndex);
230 	const auto cmdBufferPtr	= allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
231 	const auto cmdBuffer	= cmdBufferPtr.get();
232 	beginCommandBuffer(vkd, cmdBuffer);
233 
234 	de::SharedPtr<TopLevelAccelerationStructure>	topLevelAS		(makeTopLevelAccelerationStructure().release());
235 	de::SharedPtr<BottomLevelAccelerationStructure>	bottomLevelAS	(makeBottomLevelAccelerationStructure().release());
236 
237 	// These need to match the origin and direction in the shader for a hit.
238 	const std::vector<tcu::Vec3> vertices =
239 	{
240 		tcu::Vec3(-1.0f, -1.0f, 1.0f),
241 		tcu::Vec3(-1.0f,  1.0f, 1.0f),
242 		tcu::Vec3( 1.0f, -1.0f, 1.0f),
243 
244 		tcu::Vec3(-1.0f,  1.0f, 1.0f),
245 		tcu::Vec3( 1.0f,  1.0f, 1.0f),
246 		tcu::Vec3( 1.0f, -1.0f, 1.0f),
247 	};
248 
249 	bottomLevelAS->addGeometry(vertices, /*triangles*/true, VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR);
250 	bottomLevelAS->createAndBuild(vkd, device, cmdBuffer, alloc);
251 
252 	topLevelAS->addInstance(bottomLevelAS);
253 	topLevelAS->createAndBuild(vkd, device, cmdBuffer, alloc);
254 
255 	// Descriptor set layout.
256 	const VkShaderStageFlagBits stageBit = VK_SHADER_STAGE_COMPUTE_BIT;
257 
258 	DescriptorSetLayoutBuilder layoutBuilder;
259 	layoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, stageBit);
260 	layoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, stageBit);
261 	layoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, stageBit);
262 	const auto descriptorSetLayout = layoutBuilder.build(vkd, device);
263 
264 	// Shader module.
265 	const auto shaderModule = createShaderModule(vkd, device, m_context.getBinaryCollection().get("comp"), 0u);
266 
267 	// Pipeline layout.
268 	const auto pipelineLayout = makePipelineLayout(vkd, device, descriptorSetLayout.get());
269 
270 	const VkPipelineShaderStageCreateInfo shaderStageInfo =
271 	{
272 		VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,	//	VkStructureType						sType;
273 		nullptr,												//	const void*							pNext;
274 		0u,														//	VkPipelineShaderStageCreateFlags	flags;
275 		stageBit,												//	VkShaderStageFlagBits				stage;
276 		shaderModule.get(),										//	VkShaderModule						module;
277 		"main",													//	const char*							pName;
278 		nullptr,												//	const VkSpecializationInfo*			pSpecializationInfo;
279 	};
280 
281 	const VkComputePipelineCreateInfo pipelineInfo =
282 	{
283 		VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,	//	VkStructureType					sType;
284 		nullptr,										//	const void*						pNext;
285 		0u,												//	VkPipelineCreateFlags			flags;
286 		shaderStageInfo,								//	VkPipelineShaderStageCreateInfo	stage;
287 		pipelineLayout.get(),							//	VkPipelineLayout				layout;
288 		DE_NULL,										//	VkPipeline						basePipelineHandle;
289 		0,												//	deInt32							basePipelineIndex;
290 	};
291 
292 	const auto pipeline = createComputePipeline(vkd, device, DE_NULL, &pipelineInfo);
293 
294 	// Create and update descriptor set.
295 	DescriptorPoolBuilder poolBuilder;
296 	poolBuilder.addType(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR);
297 	poolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 2u);
298 
299 	const auto descriptorPool	= poolBuilder.build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
300 	const auto descriptorSetPtr	= makeDescriptorSet(vkd, device, descriptorPool.get(), descriptorSetLayout.get());
301 	const auto descriptorSet	= descriptorSetPtr.get();
302 
303 	const VkWriteDescriptorSetAccelerationStructureKHR asWrite =
304 	{
305 		VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR,	//	VkStructureType						sType;
306 		nullptr,															//	const void*							pNext;
307 		1u,																	//	deUint32							accelerationStructureCount;
308 		topLevelAS->getPtr(),												//	const VkAccelerationStructureKHR*	pAccelerationStructures;
309 	};
310 
311 	const auto inputBufferWriteInfo		= makeDescriptorBufferInfo(inputBuffer.get(), 0ull, inputBufferSize);
312 	const auto outputBufferWriteInfo	= makeDescriptorBufferInfo(outputBuffer.get(), 0ull, outputBufferSize);
313 
314 	DescriptorSetUpdateBuilder updateBuilder;
315 	updateBuilder.writeSingle(descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, &asWrite);
316 	updateBuilder.writeSingle(descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &inputBufferWriteInfo);
317 	updateBuilder.writeSingle(descriptorSet, DescriptorSetUpdateBuilder::Location::binding(2u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &outputBufferWriteInfo);
318 	updateBuilder.update(vkd, device);
319 
320 	// Use pipeline.
321 	vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline.get());
322 	vkd.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipelineLayout.get(), 0u, 1u, &descriptorSet, 0u, nullptr);
323 	vkd.cmdDispatch(cmdBuffer, 1u, 1u, 1u);
324 
325 	const auto memBarrier = makeMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
326 	vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 1u, &memBarrier, 0u, nullptr, 0u, nullptr);
327 
328 	// Submit recorded commands.
329 	endCommandBuffer(vkd, cmdBuffer);
330 	submitCommandsAndWait(vkd, device, queue, cmdBuffer);
331 
332 	// Check output buffer.
333 	invalidateAlloc(vkd, device, outputBufferAlloc);
334 	deMemcpy(outputDataArray, outputBufferPtr, static_cast<size_t>(outputBufferSize));
335 
336 	for (int i = 0; i < DE_LENGTH_OF_ARRAY(outputDataArray); ++i)
337 	{
338 		constexpr auto	expected	= 1u;
339 		const auto&		value		= outputDataArray[i];
340 
341 		if (value != expected)
342 		{
343 			std::ostringstream msg;
344 			msg << "Unexpected value found at position " << i << " in the output buffer: expected " << expected << " but found " << value;
345 			TCU_FAIL(msg.str());
346 		}
347 	}
348 
349 	return tcu::TestStatus::pass("Pass");
350 }
351 
352 using namespace tcu;
353 
354 struct HelperInvocationsParamDefs
355 {
356 	enum DfStyle
357 	{
358 		Regular,
359 		Coarse,
360 		Fine
361 	};
362 
363 	enum FuncType
364 	{
365 		LINEAR,
366 		QUADRATIC,
367 		CUBIC
368 	};
369 
370 	typedef float (*F1D)(float);
371 	struct func2D_t {
372 		F1D			first;
373 		F1D			second;
374 	};
375 	struct func2D_mask {
376 		FuncType	first;
377 		FuncType	second;
378 	};
379 	struct test_mode_t {
380 		func2D_t	funcs;
381 		func2D_mask	types;
382 	};
383 
linearvkt::RayQuery::__anon278f47230111::HelperInvocationsParamDefs384 	static float linear(float x)	{ return x; }
quadraticvkt::RayQuery::__anon278f47230111::HelperInvocationsParamDefs385 	static float quadratic(float x)	{ return (x * x); }
cubicvkt::RayQuery::__anon278f47230111::HelperInvocationsParamDefs386 	static float cubic(float x)		{ return (x * x * x * 0.5f); }
387 
combinevkt::RayQuery::__anon278f47230111::HelperInvocationsParamDefs388 	static float combine(const func2D_t& f2D, float x, float y)
389 	{
390 		DE_ASSERT( (f2D.first) && (f2D.second) );
391 		const float z = ((*f2D.first)(x) + (*f2D.second)(y)) / 2.0f;
392 		return z;
393 	}
394 
395 	static constexpr func2D_t FUNC_LINEAR_QUADRATIC			= { linear,		quadratic	};
396 	static constexpr func2D_t FUNC_LINEAR_CUBIC				= { linear,		cubic		};
397 	static constexpr func2D_t FUNC_CUBIC_QUADRATIC			= { cubic,		quadratic	};
398 	#ifdef ENABLE_ALL_HELPER_COMBINATIONS
399 	static constexpr func2D_t FUNC_LINEAR_LINEAR			= { linear,		linear		};
400 	static constexpr func2D_t FUNC_QUADRATIC_LINEAR			= { quadratic,	linear		};
401 	static constexpr func2D_t FUNC_QUADRATIC_QUADRATIC		= { quadratic,	quadratic	};
402 	static constexpr func2D_t FUNC_QUADRATIC_CUBIC			= { quadratic,	cubic		};
403 	static constexpr func2D_t FUNC_CUBIC_LINEAR				= { cubic,		linear		};
404 	static constexpr func2D_t FUNC_CUBIC_CUBIC				= { cubic,		cubic		};
405 	#endif
406 
407 	static constexpr func2D_mask MASK_LINEAR_QUADRATIC		= { LINEAR,		QUADRATIC	};
408 	static constexpr func2D_mask MASK_LINEAR_CUBIC			= { LINEAR,		CUBIC		};
409 	static constexpr func2D_mask MASK_CUBIC_QUADRATIC		= { CUBIC,		QUADRATIC	};
410 	#ifdef ENABLE_ALL_HELPER_COMBINATIONS
411 	static constexpr func2D_mask MASK_LINEAR_LINEAR			= { LINEAR,		LINEAR		};
412 	static constexpr func2D_mask MASK_QUADRATIC_LINEAR		= { QUADRATIC,	LINEAR		};
413 	static constexpr func2D_mask MASK_QUADRATIC_QUADRATIC	= { QUADRATIC,	QUADRATIC	};
414 	static constexpr func2D_mask MASK_QUADRATIC_CUBIC		= { QUADRATIC,	CUBIC		};
415 	static constexpr func2D_mask MASK_CUBIC_LINEAR			= { CUBIC,		LINEAR		};
416 	static constexpr func2D_mask MASK_CUBIC_CUBIC			= { CUBIC,		CUBIC		};
417 	#endif
418 
419 	static constexpr test_mode_t MODE_LINEAR_QUADRATIC		= { FUNC_LINEAR_QUADRATIC,		MASK_LINEAR_QUADRATIC	};
420 	static constexpr test_mode_t MODE_LINEAR_CUBIC			= { FUNC_LINEAR_CUBIC,			MASK_LINEAR_CUBIC		};
421 	static constexpr test_mode_t MODE_CUBIC_QUADRATIC		= { FUNC_CUBIC_QUADRATIC,		MASK_CUBIC_QUADRATIC	};
422 	#ifdef ENABLE_ALL_HELPER_COMBINATIONS
423 	static constexpr test_mode_t MODE_LINEAR_LINEAR			= { FUNC_LINEAR_LINEAR,			MASK_LINEAR_LINEAR		};
424 	static constexpr test_mode_t MODE_QUADRATIC_LINEAR		= { FUNC_QUADRATIC_LINEAR,		MASK_QUADRATIC_LINEAR	};
425 	static constexpr test_mode_t MODE_QUADRATIC_QUADRATIC	= { FUNC_QUADRATIC_QUADRATIC,	MASK_QUADRATIC_QUADRATIC};
426 	static constexpr test_mode_t MODE_QUADRATIC_CUBIC		= { FUNC_QUADRATIC_CUBIC,		MASK_QUADRATIC_CUBIC	};
427 	static constexpr test_mode_t MODE_CUBIC_LINEAR			= { FUNC_CUBIC_LINEAR,			MASK_CUBIC_LINEAR		};
428 	static constexpr test_mode_t MODE_CUBIC_CUBIC			= { FUNC_CUBIC_CUBIC,			MASK_CUBIC_CUBIC		};
429 	#endif
430 };
431 
432 constexpr HelperInvocationsParamDefs::test_mode_t HelperInvocationsParamDefs::MODE_LINEAR_QUADRATIC;
433 constexpr HelperInvocationsParamDefs::test_mode_t HelperInvocationsParamDefs::MODE_LINEAR_CUBIC;
434 constexpr HelperInvocationsParamDefs::test_mode_t HelperInvocationsParamDefs::MODE_CUBIC_QUADRATIC;
435 #ifdef ENABLE_ALL_HELPER_COMBINATIONS
436 constexpr HelperInvocationsParamDefs::test_mode_t HelperInvocationsParamDefs::MODE_LINEAR_LINEAR;
437 constexpr HelperInvocationsParamDefs::test_mode_t HelperInvocationsParamDefs::MODE_QUADRATIC_LINEAR;
438 constexpr HelperInvocationsParamDefs::test_mode_t HelperInvocationsParamDefs::MODE_QUADRATIC_QUADRATIC;
439 constexpr HelperInvocationsParamDefs::test_mode_t HelperInvocationsParamDefs::MODE_QUADRATIC_CUBIC;
440 constexpr HelperInvocationsParamDefs::test_mode_t HelperInvocationsParamDefs::MODE_CUBIC_LINEAR;
441 constexpr HelperInvocationsParamDefs::test_mode_t HelperInvocationsParamDefs::MODE_CUBIC_CUBIC;
442 #endif
443 
444 struct HelperInvocationsParams : HelperInvocationsParamDefs
445 {
446 	test_mode_t						mode;
447 	std::pair<deUint32, deUint32>	screen;
448 	std::pair<deUint32, deUint32>	model;
449 	DfStyle							style;
450 	bool							buildGPU;
451 };
452 
453 class HelperInvocationsCase : public TestCase
454 {
455 public:
456 	HelperInvocationsCase					(TestContext&					testCtx,
457 											 const HelperInvocationsParams&	params,
458 											 const std::string&				name);
459 	virtual void			initPrograms	(SourceCollections&				programs) const override;
460 	virtual TestInstance*	createInstance	(Context&						context) const override;
461 	virtual void			checkSupport	(Context&						context) const override;
462 
463 private:
464 	HelperInvocationsParams	m_params;
465 };
466 
467 class HelperInvocationsInstance : public TestInstance
468 {
469 public:
470 	typedef de::MovePtr<TopLevelAccelerationStructure> TopLevelAccelerationStructurePtr;
471 	enum Points {
472 		Vertices,
473 		Coords,
474 		Centers
475 	};
476 
477 	HelperInvocationsInstance				(Context&									context,
478 											 const HelperInvocationsParams&				params);
479 	virtual	TestStatus		iterate			(void) override;
480 	static	auto			createSurface	(const Points								points,
481 											 const deUint32								divX,
482 											 const deUint32								divY,
483 											 const HelperInvocationsParams::func2D_t&	f2D,
484 											 bool										clockWise = false) -> std::vector<Vec3>;
485 	VkImageCreateInfo		makeImgInfo		(deUint32									queueFamilyIndexCount,
486 											 const deUint32*							pQueueFamilyIndices) const;
487 	Move<VkPipeline>		makePipeline	(const DeviceInterface&						vk,
488 											 const VkDevice								device,
489 											 const VkPipelineLayout						pipelineLayout,
490 											 const VkShaderModule						vertexShader,
491 											 const VkShaderModule						fragmentShader,
492 											 const VkRenderPass							renderPass) const;
493 	auto					makeResultBuff	(const DeviceInterface&						vk,
494 											 const VkDevice								device,
495 											 Allocator&									allocator) const -> de::MovePtr<BufferWithMemory>;
496 	auto					makeAttribBuff	(const DeviceInterface&						vk,
497 											 const VkDevice								device,
498 											 Allocator&									allocator,
499 											 const std::vector<Vec3>&					vertices,
500 											 const std::vector<Vec3>&					coords,
501 											 const std::vector<Vec3>&					centers) const -> de::MovePtr<BufferWithMemory>;
502 	auto					createAccStructs(const DeviceInterface&						vk,
503 											 const VkDevice								device,
504 											 Allocator&									allocator,
505 											 const VkCommandBuffer						cmdBuffer,
506 											 const std::vector<Vec3>					coords) const -> TopLevelAccelerationStructurePtr;
507 protected:
508 	bool					verifyResult	(const DeviceInterface&						vk,
509 											 const VkDevice								device,
510 											 const BufferWithMemory&					buffer) const;
511 	bool onlyPipeline();
512 private:
513 	VkFormat				m_format;
514 	HelperInvocationsParams	m_params;
515 };
516 
HelperInvocationsCase(TestContext & testCtx,const HelperInvocationsParams & params,const std::string & name)517 HelperInvocationsCase::HelperInvocationsCase (TestContext&						testCtx,
518 											  const HelperInvocationsParams&	params,
519 											  const std::string&				name)
520 	: TestCase	(testCtx, name, std::string())
521 	, m_params	(params)
522 {
523 }
524 
createInstance(Context & context) const525 TestInstance* HelperInvocationsCase::createInstance (Context& context) const
526 {
527 	return new HelperInvocationsInstance(context, m_params);
528 }
529 
checkSupport(Context & context) const530 void HelperInvocationsCase::checkSupport (Context& context) const
531 {
532 	context.requireDeviceFunctionality("VK_KHR_acceleration_structure");
533 	context.requireDeviceFunctionality("VK_KHR_ray_query");
534 
535 	const auto& rayQueryFeaturesKHR					= context.getRayQueryFeatures();
536 	const auto& accelerationStructureFeaturesKHR	= context.getAccelerationStructureFeatures();
537 
538 	if (!rayQueryFeaturesKHR.rayQuery)
539 		TCU_THROW(NotSupportedError, "Ray queries not supported");
540 
541 	if (!accelerationStructureFeaturesKHR.accelerationStructure)
542 		TCU_THROW(NotSupportedError, "Acceleration structures not supported but ray queries supported");
543 
544 	if (m_params.buildGPU == false && accelerationStructureFeaturesKHR.accelerationStructureHostCommands == DE_FALSE)
545 		TCU_THROW(NotSupportedError, "Requires VkPhysicalDeviceAccelerationStructureFeaturesKHR::accelerationStructureHostCommands");
546 }
547 
initPrograms(SourceCollections & programs) const548 void HelperInvocationsCase::initPrograms (SourceCollections& programs) const
549 {
550 	const ShaderBuildOptions buildOptions(programs.usedVulkanVersion, vk::SPIRV_VERSION_1_4, 0u, true);
551 
552 	std::string vertexCode (
553 	R"(
554 	#version 460
555 	#extension GL_EXT_ray_query : require
556 	#extension GL_EXT_ray_tracing : require
557 
558 	layout(location = 0) in vec3 pos;
559 	layout(location = 1) in vec3 inCoord;
560 	layout(location = 2) in vec3 inCenter;
561 	layout(location = 0) out vec3 outCoord;
562 	layout(location = 1) out vec3 outCenter;
563 
564 	void main()
565 	{
566 		gl_PointSize = 1.0;
567 		gl_Position = vec4(pos.xyz, 1.0);
568 		outCoord = inCoord;
569 		outCenter = inCenter;
570 	}
571 	)");
572 	programs.glslSources.add("vert") << glu::VertexSource(vertexCode) << buildOptions;
573 
574 	StringTemplate fragmentCode(
575 	R"(
576 	#version 460
577 	#extension GL_EXT_ray_query : require
578 	#extension GL_EXT_ray_tracing : require
579 
580 	#define LINEAR    0
581 	#define QUADRATIC 1
582 	#define CUBIC     2
583 
584 	layout(push_constant) uniform PC {
585 		int fun_x;
586 		int fun_y;
587 		float width;
588 		float height;
589 	} params;
590 	layout(location = 0) in vec3 coord;
591 	layout(location = 1) in vec3 center;
592 	layout(location = 0) out vec4 color;
593 	layout(set = 0, binding = 0) uniform accelerationStructureEXT topLevelAS;
594 
595 	float d_linear   (in float t) { return 0.5; }			// (x/2)'
596 	float d_quadratic(in float t) { return t; }				// (x^2/2)'
597 	float d_cubic    (in float t) { return 0.75 * t * t; }  // (x^3/4)'
598 
599 	float derivate(in int fun, in float u)
600 	{
601 		switch (fun)
602 		{
603 			case LINEAR:	return d_linear(u);
604 			case QUADRATIC:	return d_quadratic(u);
605 			case CUBIC:		return d_cubic(u);
606 		}
607 		return -1.0;
608 	}
609 	void main()
610 	{
611 		const uint rayFlags	= 0u;
612 		const uint cullMask	= 0xFFu;
613 		const float tmin	= 0.0;
614 		const float tmax	= 10.0;
615 		const vec3 direct	= vec3(0.0, 0.0, 1.0);
616 		const vec3 origin	= vec3(center.x, center.y, -1.0);
617 
618 		rayQueryEXT query;
619 		rayQueryInitializeEXT(query, topLevelAS, rayFlags, cullMask, origin, tmin, direct, tmax);
620 
621 		color = vec4(-1.0, -1.0, -1.0, -1.0);
622 
623 		while (rayQueryProceedEXT(query)) {
624 			if (rayQueryGetIntersectionTypeEXT(query, false)
625 				== gl_RayQueryCandidateIntersectionTriangleEXT)
626 			{
627 				float vx = derivate(params.fun_x, coord.x);
628 				float vy = derivate(params.fun_y, coord.y);
629 				float dx = ${DFDX}(coord.x);
630 				float dy = ${DFDY}(coord.y);
631 				float dzx = ${DFDX}(coord.z);
632 				float dzy = ${DFDY}(coord.z);
633 				float dfx = dzx / dx;
634 				float dfy = dzy / dy;
635 				float cx = dfx - vx;
636 				float cy = dfy - vy;
637 
638 				color = vec4(cx, cy, sign(dx-abs(cx)), sign(dy-abs(cy)));
639 			}
640 			else
641 			{
642 				color = vec4(0.0, 0.0, -1.0, -1.0);
643 			}
644 			rayQueryConfirmIntersectionEXT(query);
645 		}
646 	})");
647 
648 	std::map<std::string, std::string> m;
649 	switch (m_params.style)
650 	{
651 	case HelperInvocationsParams::DfStyle::Regular:
652 		m["DFDX"] = "dFdx";
653 		m["DFDY"] = "dFdy";
654 		break;
655 	case HelperInvocationsParams::DfStyle::Coarse:
656 		m["DFDX"] = "dFdxCoarse";
657 		m["DFDY"] = "dFdyCoarse";
658 		break;
659 	case HelperInvocationsParams::DfStyle::Fine:
660 		m["DFDX"] = "dFdxFine";
661 		m["DFDY"] = "dFdyFine";
662 		break;
663 	}
664 
665 	programs.glslSources.add("frag") << glu::FragmentSource(fragmentCode.specialize(m)) << buildOptions;
666 }
667 
HelperInvocationsInstance(Context & context,const HelperInvocationsParams & params)668 HelperInvocationsInstance::HelperInvocationsInstance (Context& context, const HelperInvocationsParams& params)
669 	: TestInstance	(context)
670 	, m_format		(VK_FORMAT_R32G32B32A32_SFLOAT)
671 	, m_params		(params)
672 {
673 }
674 
createSurface(const Points points,const deUint32 divX,const deUint32 divY,const HelperInvocationsParams::func2D_t & f2D,bool clockWise)675 std::vector<Vec3> HelperInvocationsInstance::createSurface (const Points points, const deUint32 divX, const deUint32 divY, const HelperInvocationsParams::func2D_t& f2D, bool clockWise)
676 {
677 	std::vector<Vec3> s;
678 	const float dx = (points == Points::Vertices ? 2.0f : 1.0f) / float(divX);
679 	const float dy = (points == Points::Vertices ? 2.0f : 1.0f) / float(divY);
680 	// Z is always scaled to range (0,1)
681 	auto z = [&](const deUint32 n, const deUint32 m) -> float
682 	{
683 		const float x = float(n) / float(divX);
684 		const float y = float(m) / float(divY);
685 		return HelperInvocationsParams::combine(f2D, x,y);
686 	};
687 	float y = (points == Points::Vertices) ? -1.0f : 0.0f;
688 	for (deUint32 j = 0; j < divY; ++j)
689 	{
690 		const float ny = ((j + 1) < divY) ? (y + dy) : 1.f;
691 		float x = (points == Points::Vertices) ? -1.0f : 0.0f;
692 
693 		for (deUint32 i = 0; i < divX; ++i)
694 		{
695 			const float nx = ((i + 1) < divX) ? (x + dx) : 1.f;
696 
697 			const Vec3	p0( x,  y, z( i,   j   ));
698 			const Vec3	p1(nx,  y, z( i+1 ,j   ));
699 			const Vec3	p2(nx, ny, z( i+1, j+1 ));
700 			const Vec3	p3( x, ny, z( i,   j+1 ));
701 
702 			if (points == Points::Centers)
703 			{
704 				const float cx1 = (p0.x() + p1.x() + p2.x()) / 3.0f;
705 				const float cy1 = (p0.y() + p1.y() + p2.y()) / 3.0f;
706 				const float cz1 = (p0.z() + p1.z() + p2.z()) / 3.0f;
707 				const float cx2 = (p0.x() + p2.x() + p3.x()) / 3.0f;
708 				const float cy2 = (p0.y() + p2.y() + p3.y()) / 3.0f;
709 				const float cz2 = (p0.z() + p2.z() + p3.z()) / 3.0f;
710 
711 				s.emplace_back(cx1, cy1, cz1); s.emplace_back(cx1, cy1, cz1); s.emplace_back(cx1, cy1, cz1);
712 				s.emplace_back(cx2, cy2, cz2); s.emplace_back(cx2, cy2, cz2); s.emplace_back(cx2, cy2, cz2);
713 			}
714 			else if (clockWise)
715 			{
716 				s.push_back(p0); s.push_back(p3); s.push_back(p2);
717 				s.push_back(p0); s.push_back(p2); s.push_back(p1);
718 			}
719 			else
720 			{
721 				s.push_back(p0); s.push_back(p1); s.push_back(p2);
722 				s.push_back(p2); s.push_back(p3); s.push_back(p0);
723 			}
724 
725 			x = nx;
726 		}
727 		y = ny;
728 	}
729 	return s;
730 }
731 
makeImgInfo(deUint32 queueFamilyIndexCount,const deUint32 * pQueueFamilyIndices) const732 VkImageCreateInfo HelperInvocationsInstance::makeImgInfo (deUint32			queueFamilyIndexCount,
733 														  const deUint32*	pQueueFamilyIndices) const
734 {
735 	const VkImageUsageFlags usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
736 	return
737 	{
738 		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,	// sType;
739 		nullptr,								// pNext;
740 		VkImageCreateFlags(0),					// flags;
741 		VK_IMAGE_TYPE_2D,						// imageType;
742 		m_format,								// format;
743 		{
744 			m_params.screen.first,
745 			m_params.screen.second,
746 			1u
747 		},										// extent;
748 		1u,										// mipLevels;
749 		1u,										// arrayLayers;
750 		VK_SAMPLE_COUNT_1_BIT,					// samples;
751 		VK_IMAGE_TILING_OPTIMAL,				// tiling;
752 		usage,									// usage;
753 		VK_SHARING_MODE_EXCLUSIVE,				// sharingMode;
754 		queueFamilyIndexCount,					// queueFamilyIndexCount;
755 		pQueueFamilyIndices,					// pQueueFamilyIndices;
756 		VK_IMAGE_LAYOUT_UNDEFINED				// initialLayout;
757 	};
758 }
759 
makePipeline(const DeviceInterface & vk,const VkDevice device,const VkPipelineLayout pipelineLayout,const VkShaderModule vertexShader,const VkShaderModule fragmentShader,const VkRenderPass renderPass) const760 Move<VkPipeline> HelperInvocationsInstance::makePipeline (const DeviceInterface&	vk,
761 														  const VkDevice			device,
762 														  const VkPipelineLayout	pipelineLayout,
763 														  const VkShaderModule		vertexShader,
764 														  const VkShaderModule		fragmentShader,
765 														  const VkRenderPass		renderPass) const
766 {
767 	DE_ASSERT(sizeof(Vec3) == mapVkFormat(VK_FORMAT_R32G32B32_SFLOAT).getPixelSize());
768 
769 	const std::vector<VkViewport>					viewports			{ makeViewport(m_params.screen.first, m_params.screen.second) };
770 	const std::vector<VkRect2D>						scissors			{ makeRect2D(m_params.screen.first, m_params.screen.second) };
771 
772 	const VkVertexInputBindingDescription			vertexInputBindingDescription
773 	{
774 		0u,														// deUint32             binding
775 		deUint32(sizeof(Vec3) * 3u),							// deUint32             stride
776 		VK_VERTEX_INPUT_RATE_VERTEX,							// VkVertexInputRate    inputRate
777 	};
778 
779 	const VkVertexInputAttributeDescription			vertexInputAttributeDescription[]
780 	{
781 		{
782 			0u,													// deUint32    location
783 			0u,													// deUint32    binding
784 			VK_FORMAT_R32G32B32_SFLOAT,							// VkFormat    format
785 			0u													// deUint32    offset
786 		},														// vertices
787 		{
788 			1u,													// deUint32    location
789 			0u,													// deUint32    binding
790 			VK_FORMAT_R32G32B32_SFLOAT,							// VkFormat    format
791 			deUint32(sizeof(Vec3))								// deUint32    offset
792 		},														// coords
793 		{
794 			2u,													// deUint32    location
795 			0u,													// deUint32    binding
796 			VK_FORMAT_R32G32B32_SFLOAT,							// VkFormat    format
797 			deUint32(sizeof(Vec3) * 2u)							// deUint32    offset
798 		}														// centers
799 	};
800 
801 	const VkPipelineVertexInputStateCreateInfo		vertexInputStateCreateInfo
802 	{
803 		VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,	// VkStructureType                             sType
804 		nullptr,													// const void*                                 pNext
805 		(VkPipelineVertexInputStateCreateFlags)0,					// VkPipelineVertexInputStateCreateFlags       flags
806 		1u,															// deUint32                                    vertexBindingDescriptionCount
807 		&vertexInputBindingDescription,								// const VkVertexInputBindingDescription*      pVertexBindingDescriptions
808 		DE_LENGTH_OF_ARRAY(vertexInputAttributeDescription),		// deUint32                                    vertexAttributeDescriptionCount
809 		vertexInputAttributeDescription								// const VkVertexInputAttributeDescription*    pVertexAttributeDescriptions
810 	};
811 
812 	return makeGraphicsPipeline(vk, device, pipelineLayout,
813 								vertexShader, DE_NULL, DE_NULL, DE_NULL, fragmentShader,
814 								renderPass, viewports, scissors, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
815 								0u, 0u, &vertexInputStateCreateInfo);
816 }
817 
createAccStructs(const DeviceInterface & vk,const VkDevice device,Allocator & allocator,const VkCommandBuffer cmdBuffer,const std::vector<Vec3> coords) const818 de::MovePtr<TopLevelAccelerationStructure> HelperInvocationsInstance::createAccStructs (const DeviceInterface&	vk,
819 																						const VkDevice			device,
820 																						Allocator&				allocator,
821 																						const VkCommandBuffer	cmdBuffer,
822 																						const std::vector<Vec3>	coords) const
823 {
824 	const VkAccelerationStructureBuildTypeKHR		buildType	= m_params.buildGPU
825 																	? VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR
826 																	: VK_ACCELERATION_STRUCTURE_BUILD_TYPE_HOST_KHR;
827 	de::MovePtr<TopLevelAccelerationStructure>		tlas		= makeTopLevelAccelerationStructure();
828 	de::MovePtr<BottomLevelAccelerationStructure>	blas		= makeBottomLevelAccelerationStructure();
829 
830 	blas->setBuildType(buildType);
831 	blas->addGeometry(coords, true, VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR);
832 	blas->createAndBuild(vk, device, cmdBuffer, allocator);
833 
834 	tlas->setBuildType(buildType);
835 	tlas->addInstance(de::SharedPtr<BottomLevelAccelerationStructure>(blas.release()));
836 	tlas->createAndBuild(vk, device, cmdBuffer, allocator);
837 
838 	return tlas;
839 }
840 
makeAttribBuff(const DeviceInterface & vk,const VkDevice device,Allocator & allocator,const std::vector<Vec3> & vertices,const std::vector<Vec3> & coords,const std::vector<Vec3> & centers) const841 de::MovePtr<BufferWithMemory> HelperInvocationsInstance::makeAttribBuff	(const DeviceInterface&		vk,
842 																		 const VkDevice				device,
843 																		 Allocator&					allocator,
844 																		 const std::vector<Vec3>&	vertices,
845 																		 const std::vector<Vec3>&	coords,
846 																		 const std::vector<Vec3>&	centers) const
847 {
848 	DE_ASSERT(sizeof(Vec3) == mapVkFormat(VK_FORMAT_R32G32B32_SFLOAT).getPixelSize());
849 	const deUint32					count				= deUint32(vertices.size());
850 	DE_ASSERT( count && (count == coords.size()) && (count == centers.size()) );
851 	const VkDeviceSize				bufferSize			= 3 * count * sizeof(Vec3);
852 	const VkBufferCreateInfo		bufferCreateInfo	= makeBufferCreateInfo(bufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
853 	de::MovePtr<BufferWithMemory>	buffer				(new BufferWithMemory(vk, device, allocator, bufferCreateInfo, MemoryRequirement::Coherent | MemoryRequirement::HostVisible));
854 
855 	Allocation&						allocation			= buffer->getAllocation();
856 	Vec3*							data				= static_cast<Vec3*>(allocation.getHostPtr());
857 	for (deUint32 c = 0; c < count; ++c)
858 	{
859 		data[3*c] = vertices.at(c);
860 		data[3*c+1] = coords.at(c);
861 		data[3*c+2] = centers.at(c);
862 	}
863 	flushMappedMemoryRange(vk, device, allocation.getMemory(), 0u, bufferSize);
864 
865 	return buffer;
866 }
867 
makeResultBuff(const DeviceInterface & vk,const VkDevice device,Allocator & allocator) const868 de::MovePtr<BufferWithMemory> HelperInvocationsInstance::makeResultBuff	(const DeviceInterface& vk,
869 																		 const VkDevice			device,
870 																		 Allocator&				allocator) const
871 {
872 	const TextureFormat				texFormat			= mapVkFormat(m_format);
873 	const VkDeviceSize				bufferSize			= (m_params.screen.first * m_params.screen.second * texFormat.getPixelSize());
874 	const VkBufferCreateInfo		bufferCreateInfo	= makeBufferCreateInfo(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
875 	de::MovePtr<BufferWithMemory>	buffer				(new BufferWithMemory(vk, device, allocator, bufferCreateInfo, MemoryRequirement::Coherent | MemoryRequirement::HostVisible));
876 
877 	Allocation&						allocation			= buffer->getAllocation();
878 	PixelBufferAccess				pixels				(texFormat, m_params.screen.first, m_params.screen.second, 1u, allocation.getHostPtr());
879 
880 	for (deUint32 y = 0; y < m_params.screen.second; ++y)
881 	{
882 		for (deUint32 x = 0; x < m_params.screen.first; ++x)
883 		{
884 			pixels.setPixel(Vec4(0.0f, 0.0f, 0.0f, -1.0f), x, y);
885 		}
886 	}
887 	flushMappedMemoryRange(vk, device, allocation.getMemory(), 0u, bufferSize);
888 
889 	return buffer;
890 }
891 
verifyResult(const DeviceInterface & vk,const VkDevice device,const BufferWithMemory & buffer) const892 bool HelperInvocationsInstance::verifyResult (const DeviceInterface&	vk,
893 											  const VkDevice			device,
894 											  const BufferWithMemory&	buffer) const
895 {
896 	int						invalid	= 0;
897 	Allocation&				alloc	= buffer.getAllocation();
898 	invalidateMappedMemoryRange(vk, device, alloc.getMemory(), 0u, VK_WHOLE_SIZE);
899 	ConstPixelBufferAccess	pixels	(mapVkFormat(m_format), m_params.screen.first, m_params.screen.second, 1u, alloc.getHostPtr());
900 
901 	for (deUint32 y = 0; y < m_params.screen.second; ++y)
902 	{
903 		for (deUint32 x = 0; x < m_params.screen.first; ++x)
904 		{
905 			const Vec4 px = pixels.getPixel(x,y);
906 			if (px.z() < 0.0f || px.w() < 0.0f)
907 				invalid += 1;
908 		}
909 	}
910 
911 	return (0 == invalid);
912 }
913 
makeAccStructDescriptorWrite(const VkAccelerationStructureKHR * ptr,deUint32 count=1u)914 VkWriteDescriptorSetAccelerationStructureKHR makeAccStructDescriptorWrite (const VkAccelerationStructureKHR* ptr, deUint32 count = 1u)
915 {
916 	return {
917 		VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR,	//	VkStructureType						sType;
918 		nullptr,															//	const void*							pNext;
919 		count,																//	deUint32							accelerationStructureCount;
920 		ptr};																//	const VkAccelerationStructureKHR*	pAccelerationStructures;
921 };
922 
iterate(void)923 TestStatus HelperInvocationsInstance::iterate (void)
924 {
925 	const VkDevice							device						= m_context.getDevice();
926 	const DeviceInterface&					vk							= m_context.getDeviceInterface();
927 	Allocator&								allocator					= m_context.getDefaultAllocator();
928 	const deUint32							queueFamilyIndex			= m_context.getUniversalQueueFamilyIndex();
929 	const VkQueue							queue						= m_context.getUniversalQueue();
930 
931 	const VkRect2D							renderArea					= makeRect2D(m_params.screen.first, m_params.screen.second);
932 	const VkImageCreateInfo					imageCreateInfo				= makeImgInfo(1, &queueFamilyIndex);
933 	const de::MovePtr<ImageWithMemory>		image						(new ImageWithMemory(vk, device, allocator, imageCreateInfo, MemoryRequirement::Any));
934 	const VkImageSubresourceRange			imageSubresourceRange		= makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0, 1u);
935 	const Move<VkImageView>					view						= makeImageView(vk, device, **image, VK_IMAGE_VIEW_TYPE_2D, m_format, imageSubresourceRange);
936 	const Move<VkRenderPass>				renderPass					= makeRenderPass(vk, device, m_format);
937 	const Move<VkFramebuffer>				frameBuffer					= makeFramebuffer(vk, device, *renderPass, *view, m_params.screen.first, m_params.screen.second);
938 	const de::MovePtr<BufferWithMemory>		resultBuffer				= makeResultBuff(vk, device, allocator);
939 	const VkImageSubresourceLayers			imageSubresourceLayers		= makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u);
940 	const VkBufferImageCopy					bufferCopyImageRegion		= makeBufferImageCopy(makeExtent3D(UVec3(m_params.screen.first, m_params.screen.second, 1u)), imageSubresourceLayers);
941 
942 	const HelperInvocationsParams::func2D_t	funcs						= m_params.mode.funcs;
943 	struct PushConstants
944 	{
945 		int fun_x, fun_y;
946 	} const                                 pushConstants				{ m_params.mode.types.first, m_params.mode.types.second };
947 	const VkPushConstantRange				pushConstantRange			{ VK_SHADER_STAGE_FRAGMENT_BIT, 0u, uint32_t(sizeof(pushConstants)) };
948 	const std::vector<Vec3>					vertices					= createSurface(Points::Vertices, m_params.model.first, m_params.model.second, funcs);
949 	const std::vector<Vec3>					coords						= createSurface(Points::Coords, m_params.model.first, m_params.model.second, funcs);
950 	const std::vector<Vec3>					centers						= createSurface(Points::Centers, m_params.model.first, m_params.model.second, funcs);
951 	const de::MovePtr<BufferWithMemory>		attribBuffer				= makeAttribBuff(vk, device, allocator, vertices, coords, centers);
952 
953 	TopLevelAccelerationStructurePtr		topAccStruct				{};
954 	Move<VkDescriptorSetLayout>				descriptorLayout			= DescriptorSetLayoutBuilder()
955 																			.addSingleBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, VK_SHADER_STAGE_FRAGMENT_BIT)
956 																			.build(vk, device);
957 	Move<VkDescriptorPool>					descriptorPool				= DescriptorPoolBuilder()
958 																			.addType(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR)
959 																			.build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
960 	Move<VkDescriptorSet>					descriptorSet				= makeDescriptorSet(vk, device, *descriptorPool, *descriptorLayout);
961 
962 	Move<VkShaderModule>					vertexShader				= createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0u);
963 	Move<VkShaderModule>					fragmentShader				= createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"), 0u);
964 	Move<VkPipelineLayout>					pipelineLayout				= makePipelineLayout(vk, device, 1u, &descriptorLayout.get(), 1u, &pushConstantRange);
965 	Move<VkPipeline>						pipeline					= makePipeline(vk, device, *pipelineLayout, *vertexShader, *fragmentShader, *renderPass);
966 	const Move<VkCommandPool>				cmdPool						= createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, queueFamilyIndex);
967 	const Move<VkCommandBuffer>				cmdBuffer					= allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
968 
969 	const Vec4								clearColor					( 0.1f, 0.2f, 0.3f, 0.4f );
970 	const VkImageMemoryBarrier				postDrawImageBarrier		= makeImageMemoryBarrier(VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
971 																								 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
972 																								 **image, imageSubresourceRange);
973 	const VkMemoryBarrier					postCopyMemoryBarrier		= makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
974 
975 	beginCommandBuffer(vk, *cmdBuffer, 0u);
976 
977 		topAccStruct = createAccStructs(vk, device, allocator, *cmdBuffer, coords);
978 		const auto accStructWrite = makeAccStructDescriptorWrite(topAccStruct->getPtr());
979 		DescriptorSetUpdateBuilder().writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u),
980 												 VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, &accStructWrite).update(vk, device);
981 
982 		vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
983 		vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &static_cast<const VkBuffer&>(**attribBuffer), &static_cast<const VkDeviceSize&>(0u));
984 		vk.cmdPushConstants(*cmdBuffer, *pipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0u, uint32_t(sizeof(pushConstants)), &pushConstants);
985 		vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u, &descriptorSet.get(), 0u, nullptr);
986 
987 		beginRenderPass(vk, *cmdBuffer, *renderPass, *frameBuffer, renderArea, clearColor);
988 			vk.cmdDraw(*cmdBuffer, uint32_t(vertices.size()), 1u, 0u, 0u);
989 		endRenderPass(vk, *cmdBuffer);
990 
991 		cmdPipelineImageMemoryBarrier(vk, *cmdBuffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, &postDrawImageBarrier);
992 		vk.cmdCopyImageToBuffer(*cmdBuffer, **image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, **resultBuffer, 1u, &bufferCopyImageRegion);
993 		cmdPipelineMemoryBarrier(vk, *cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, &postCopyMemoryBarrier);
994 
995 	endCommandBuffer(vk, *cmdBuffer);
996 
997 	submitCommandsAndWait(vk, device, queue, *cmdBuffer);
998 
999 	return verifyResult(vk, device, *resultBuffer) ? TestStatus::pass("") : TestStatus::fail("");
1000 }
1001 
1002 } // anonymous
1003 
addHelperInvocationsTests(TestContext & testCtx)1004 TestCaseGroup* addHelperInvocationsTests(TestContext& testCtx)
1005 {
1006 	std::pair<bool, const char*> const builds[]
1007 	{
1008 		{ true,		"gpu"	},
1009 		{ false,	"cpu"	}
1010 	};
1011 
1012 	std::pair<HelperInvocationsParams::DfStyle, const char*> const styles[]
1013 	{
1014 		{ HelperInvocationsParams::Regular,	"regular"	},
1015 		{ HelperInvocationsParams::Coarse,	"coarse"	},
1016 		{ HelperInvocationsParams::Fine,	"fine"		}
1017 	};
1018 
1019 	std::pair<HelperInvocationsParams::test_mode_t, const char*> const modes[] =
1020 	{
1021 		{ HelperInvocationsParams::MODE_LINEAR_QUADRATIC	, "linear_quadratic"	},
1022 		{ HelperInvocationsParams::MODE_LINEAR_CUBIC		, "linear_cubic"		},
1023 		{ HelperInvocationsParams::MODE_CUBIC_QUADRATIC		, "cubic_quadratic"		},
1024 #ifdef ENABLE_ALL_HELPER_COMBINATIONS
1025 		{ HelperInvocationsParams::MODE_LINEAR_LINEAR		, "linear_linear"		},
1026 		{ HelperInvocationsParams::MODE_QUADRATIC_LINEAR	, "quadratic_linear"	},
1027 		{ HelperInvocationsParams::MODE_QUADRATIC_QUADRATIC	, "quadratic_quadratic"	},
1028 		{ HelperInvocationsParams::MODE_QUADRATIC_CUBIC		, "quadratic_cubic"		},
1029 		{ HelperInvocationsParams::MODE_CUBIC_LINEAR		, "cubic_linear"		},
1030 		{ HelperInvocationsParams::MODE_CUBIC_CUBIC			, "cubic_cubic"			},
1031 #endif
1032 	};
1033 
1034 	std::pair<deUint32, deUint32> const screens[]
1035 	{
1036 		{ 64, 64 }, { 32, 64 }
1037 	};
1038 
1039 	std::pair<deUint32, deUint32> const models[]
1040 	{
1041 		{ 64, 64 }, { 64, 32 }
1042 	};
1043 
1044 	auto makeTestName = [](const std::pair<deUint32, deUint32>& d) -> std::string
1045 	{
1046 		return std::to_string(d.first) + "x" + std::to_string(d.second);
1047 	};
1048 
1049 	auto rootGroup = new TestCaseGroup(testCtx, "helper_invocations", "Ray query helper invocation tests");
1050 	for (auto& build : builds)
1051 	{
1052 		auto buildGroup = new tcu::TestCaseGroup(testCtx, build.second, "");
1053 		for (auto& style : styles)
1054 		{
1055 			auto styleGroup = new tcu::TestCaseGroup(testCtx, style.second, "");
1056 			for (auto& mode : modes)
1057 			{
1058 				auto modeGroup = new tcu::TestCaseGroup(testCtx, mode.second, "");
1059 				for (auto& screen : screens)
1060 				{
1061 					auto screenGroup = new TestCaseGroup(testCtx, makeTestName(screen).c_str(), "");
1062 					for (auto& model : models)
1063 					{
1064 						HelperInvocationsParams p;
1065 						p.mode		= mode.first;
1066 						p.screen	= screen;
1067 						p.model		= model;
1068 						p.style		= style.first;
1069 						p.buildGPU	= build.first;
1070 
1071 						screenGroup->addChild(new HelperInvocationsCase(testCtx, p, makeTestName(model)));
1072 					}
1073 					modeGroup->addChild(screenGroup);
1074 				}
1075 				styleGroup->addChild(modeGroup);
1076 			}
1077 			buildGroup->addChild(styleGroup);
1078 		}
1079 		rootGroup->addChild(buildGroup);
1080 	}
1081 	return rootGroup;
1082 }
1083 
createMiscTests(tcu::TestContext & testCtx)1084 tcu::TestCaseGroup*	createMiscTests	(tcu::TestContext& testCtx)
1085 {
1086 	de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "misc", "Miscellaneous ray query tests"));
1087 
1088 	group->addChild(new DynamicIndexingCase(testCtx, "dynamic_indexing", "Dynamic indexing of ray queries"));
1089 
1090 	return group.release();
1091 }
1092 
1093 } // RayQuery
1094 } // vkt
1095 
1096