• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2018 The Khronos Group Inc.
6  * Copyright (c) 2018 Danylo Piliaiev <danylo.piliaiev@gmail.com>
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 Test for conditional rendering of vkCmdDispatch* functions
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktConditionalDispatchTests.hpp"
26 #include "vktConditionalRenderingTestUtil.hpp"
27 
28 #include "vktTestCaseUtil.hpp"
29 #include "vktComputeTestsUtil.hpp"
30 
31 #include "tcuTestLog.hpp"
32 #include "tcuResource.hpp"
33 
34 #include "vkDefs.hpp"
35 #include "vkCmdUtil.hpp"
36 #include "vkBuilderUtil.hpp"
37 #include "vkObjUtil.hpp"
38 
39 namespace vkt
40 {
41 namespace conditional
42 {
43 namespace
44 {
45 
46 enum DispatchCommandType
47 {
48 	DISPATCH_COMMAND_TYPE_DISPATCH = 0,
49 	DISPATCH_COMMAND_TYPE_DISPATCH_INDIRECT,
50 	DISPATCH_COMMAND_TYPE_DISPATCH_BASE,
51 	DISPATCH_COMMAND_TYPE_DISPATCH_LAST
52 };
53 
getDispatchCommandTypeName(DispatchCommandType command)54 const char* getDispatchCommandTypeName (DispatchCommandType command)
55 {
56 	switch (command)
57 	{
58 		case DISPATCH_COMMAND_TYPE_DISPATCH:			    return "dispatch";
59 		case DISPATCH_COMMAND_TYPE_DISPATCH_INDIRECT:	    return "dispatch_indirect";
60 		case DISPATCH_COMMAND_TYPE_DISPATCH_BASE:			return "dispatch_base";
61 		default:					                        DE_ASSERT(false);
62 	}
63 	return "";
64 }
65 
66 struct ConditionalTestSpec
67 {
68 	DispatchCommandType	command;
69 	int					numCalls;
70 	ConditionalData		conditionalData;
71 };
72 
73 class ConditionalDispatchTest : public vkt::TestCase
74 {
75 public:
76 						ConditionalDispatchTest	(tcu::TestContext&			testCtx,
77 												 const std::string&			name,
78 												 const std::string&			description,
79 												 const ConditionalTestSpec&	testSpec);
80 
81 	void				initPrograms			(vk::SourceCollections&	sourceCollections) const;
82 	void				checkSupport			(Context&				context) const;
83 	TestInstance*		createInstance			(Context&				context) const;
84 
85 private:
86 	const ConditionalTestSpec m_testSpec;
87 };
88 
89 class ConditionalDispatchTestInstance : public TestInstance
90 {
91 public:
92 								ConditionalDispatchTestInstance	(Context &context, ConditionalTestSpec testSpec);
93 
94 	virtual		tcu::TestStatus iterate							(void);
95 	void						recordDispatch					(const vk::DeviceInterface&	vk,
96 																 vk::VkCommandBuffer cmdBuffer,
97 																 compute::Buffer& indirectBuffer);
98 
99 protected:
100 	const DispatchCommandType		m_command;
101 	const int						m_numCalls;
102 	const ConditionalData			m_conditionalData;
103 };
104 
ConditionalDispatchTest(tcu::TestContext & testCtx,const std::string & name,const std::string & description,const ConditionalTestSpec & testSpec)105 ConditionalDispatchTest::ConditionalDispatchTest(tcu::TestContext&			testCtx,
106 												 const std::string&			name,
107 												 const std::string&			description,
108 												 const ConditionalTestSpec&	testSpec)
109 	: TestCase		(testCtx, name, description)
110 	, m_testSpec	(testSpec)
111 {
112 }
113 
initPrograms(vk::SourceCollections & sourceCollections) const114 void ConditionalDispatchTest::initPrograms (vk::SourceCollections& sourceCollections) const
115 {
116 	std::ostringstream src;
117 	src << "#version 310 es\n"
118 		<< "layout(local_size_x = 1u, local_size_y = 1u, local_size_z = 1u) in;\n"
119 		<< "layout(set = 0, binding = 0, std140) buffer Out\n"
120 		<< "{\n"
121 		<< "    coherent uint count;\n"
122 		<< "};\n"
123 		<< "void main(void)\n"
124 		<< "{\n"
125 		<< "	atomicAdd(count, 1u);\n"
126 		<< "}\n";
127 
128 	sourceCollections.glslSources.add("comp") << glu::ComputeSource(src.str());
129 }
130 
checkSupport(Context & context) const131 void ConditionalDispatchTest::checkSupport(Context& context) const
132 {
133 	checkConditionalRenderingCapabilities(context, m_testSpec.conditionalData);
134 
135 	if (m_testSpec.command == DISPATCH_COMMAND_TYPE_DISPATCH_BASE)
136 		context.requireDeviceFunctionality("VK_KHR_device_group");
137 }
138 
createInstance(Context & context) const139 TestInstance* ConditionalDispatchTest::createInstance (Context& context) const
140 {
141 	return new ConditionalDispatchTestInstance(context, m_testSpec);
142 }
143 
ConditionalDispatchTestInstance(Context & context,ConditionalTestSpec testSpec)144 ConditionalDispatchTestInstance::ConditionalDispatchTestInstance (Context &context, ConditionalTestSpec testSpec)
145 	: TestInstance(context)
146 	, m_command(testSpec.command)
147 	, m_numCalls(testSpec.numCalls)
148 	, m_conditionalData(testSpec.conditionalData)
149 {
150 }
151 
recordDispatch(const vk::DeviceInterface & vk,vk::VkCommandBuffer cmdBuffer,compute::Buffer & indirectBuffer)152 void ConditionalDispatchTestInstance::recordDispatch (const vk::DeviceInterface& vk,
153 													  vk::VkCommandBuffer cmdBuffer,
154 													  compute::Buffer& indirectBuffer)
155 {
156 	for (int i = 0; i < m_numCalls; i++)
157 	{
158 		switch (m_command)
159 		{
160 			case DISPATCH_COMMAND_TYPE_DISPATCH:
161 			{
162 				vk.cmdDispatch(cmdBuffer, 1, 1, 1);
163 				break;
164 			}
165 			case DISPATCH_COMMAND_TYPE_DISPATCH_INDIRECT:
166 			{
167 				vk.cmdDispatchIndirect(cmdBuffer, *indirectBuffer, 0);
168 				break;
169 			}
170 			case DISPATCH_COMMAND_TYPE_DISPATCH_BASE:
171 			{
172 				vk.cmdDispatchBase(cmdBuffer, 0, 0, 0, 1, 1, 1);
173 				break;
174 			}
175 			default: DE_ASSERT(DE_FALSE);
176 		}
177 	}
178 }
179 
iterate(void)180 tcu::TestStatus ConditionalDispatchTestInstance::iterate (void)
181 {
182 	const vk::DeviceInterface&	vk					= m_context.getDeviceInterface();
183 	const vk::VkDevice			device				= m_context.getDevice();
184 	const vk::VkQueue			queue				= m_context.getUniversalQueue();
185 	const deUint32			    queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
186 	vk::Allocator&				allocator			= m_context.getDefaultAllocator();
187 
188 	// Create a buffer and host-visible memory for it
189 
190 	const vk::VkDeviceSize bufferSizeBytes = sizeof(deUint32);
191 	const compute::Buffer outputBuffer(vk, device, allocator, vk::makeBufferCreateInfo(bufferSizeBytes, vk::VK_BUFFER_USAGE_STORAGE_BUFFER_BIT), vk::MemoryRequirement::HostVisible);
192 
193 	{
194 		const vk::Allocation& alloc = outputBuffer.getAllocation();
195 		deUint8* outputBufferPtr = reinterpret_cast<deUint8*>(alloc.getHostPtr());
196 		*(deUint32*)(outputBufferPtr) = 0;
197 		vk::flushAlloc(vk, device, alloc);
198 	}
199 
200 	// Create descriptor set
201 
202 	const vk::Unique<vk::VkDescriptorSetLayout> descriptorSetLayout(
203 		vk::DescriptorSetLayoutBuilder()
204 		.addSingleBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, vk::VK_SHADER_STAGE_COMPUTE_BIT)
205 		.build(vk, device));
206 
207 	const vk::Unique<vk::VkDescriptorPool> descriptorPool(
208 		vk::DescriptorPoolBuilder()
209 		.addType(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
210 		.build(vk, device, vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
211 
212 	const vk::Unique<vk::VkDescriptorSet> descriptorSet(makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
213 
214 	const vk::VkDescriptorBufferInfo descriptorInfo = vk::makeDescriptorBufferInfo(*outputBuffer, 0ull, bufferSizeBytes);
215 	vk::DescriptorSetUpdateBuilder()
216 		.writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descriptorInfo)
217 		.update(vk, device);
218 
219 	// Setup pipeline
220 
221 	const vk::Unique<vk::VkShaderModule>	shaderModule		(createShaderModule(vk, device, m_context.getBinaryCollection().get("comp"), 0u));
222 	const vk::Unique<vk::VkPipelineLayout>	pipelineLayout		(makePipelineLayout(vk, device, *descriptorSetLayout));
223 	const vk::Unique<vk::VkPipeline>		pipeline			(compute::makeComputePipeline(vk, device, *pipelineLayout, *shaderModule));
224 
225 	const vk::Unique<vk::VkCommandPool>		cmdPool				(makeCommandPool(vk, device, queueFamilyIndex));
226 	const vk::Unique<vk::VkCommandBuffer>	cmdBuffer			(vk::allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
227 	const vk::Unique<vk::VkCommandBuffer>	secondaryCmdBuffer	(vk::allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_SECONDARY));
228 
229 	// Create indirect buffer
230 	const vk::VkDispatchIndirectCommand dispatchCommands[] = { { 1u, 1u, 1u } };
231 
232 	compute::Buffer indirectBuffer(
233 		vk, device, allocator,
234 		vk::makeBufferCreateInfo(sizeof(dispatchCommands), vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT | vk::VK_BUFFER_USAGE_STORAGE_BUFFER_BIT),
235 		vk::MemoryRequirement::HostVisible);
236 
237 	deUint8* indirectBufferPtr = reinterpret_cast<deUint8*>(indirectBuffer.getAllocation().getHostPtr());
238 	deMemcpy(indirectBufferPtr, &dispatchCommands[0], sizeof(dispatchCommands));
239 
240 	vk::flushAlloc(vk, device, indirectBuffer.getAllocation());
241 
242 	// Start recording commands
243 
244 	beginCommandBuffer(vk, *cmdBuffer);
245 
246 	vk::VkCommandBuffer targetCmdBuffer = *cmdBuffer;
247 
248 	const bool useSecondaryCmdBuffer = m_conditionalData.conditionInherited || m_conditionalData.conditionInSecondaryCommandBuffer;
249 
250 	if (useSecondaryCmdBuffer)
251 	{
252 		const vk::VkCommandBufferInheritanceConditionalRenderingInfoEXT conditionalRenderingInheritanceInfo =
253 		{
254 			vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_CONDITIONAL_RENDERING_INFO_EXT,
255 			DE_NULL,
256 			m_conditionalData.conditionInherited ? VK_TRUE : VK_FALSE	// conditionalRenderingEnable
257 		};
258 
259 		const vk::VkCommandBufferInheritanceInfo inheritanceInfo =
260 		{
261 			vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO,
262 			&conditionalRenderingInheritanceInfo,
263 			0u,										        // renderPass
264 			0u,												// subpass
265 			0u,										        // framebuffer
266 			VK_FALSE,										// occlusionQueryEnable
267 			(vk::VkQueryControlFlags)0u,					// queryFlags
268 			(vk::VkQueryPipelineStatisticFlags)0u,			// pipelineStatistics
269 		};
270 
271 		const vk::VkCommandBufferBeginInfo commandBufferBeginInfo =
272 		{
273 			vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
274 			DE_NULL,
275 			vk::VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
276 			&inheritanceInfo
277 		};
278 
279 		vk.beginCommandBuffer(*secondaryCmdBuffer, &commandBufferBeginInfo);
280 
281 		targetCmdBuffer = *secondaryCmdBuffer;
282 	}
283 
284 	vk.cmdBindPipeline(targetCmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
285 	vk.cmdBindDescriptorSets(targetCmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &descriptorSet.get(), 0u, DE_NULL);
286 
287 	de::SharedPtr<Draw::Buffer> conditionalBuffer = createConditionalRenderingBuffer(m_context, m_conditionalData);
288 
289 	if (m_conditionalData.conditionInSecondaryCommandBuffer)
290 	{
291 		beginConditionalRendering(vk, *secondaryCmdBuffer, *conditionalBuffer, m_conditionalData);
292 		recordDispatch(vk, *secondaryCmdBuffer, indirectBuffer);
293 		vk.cmdEndConditionalRenderingEXT(*secondaryCmdBuffer);
294 		vk.endCommandBuffer(*secondaryCmdBuffer);
295 	}
296 	else if (m_conditionalData.conditionInherited)
297 	{
298 		recordDispatch(vk, *secondaryCmdBuffer, indirectBuffer);
299 		vk.endCommandBuffer(*secondaryCmdBuffer);
300 	}
301 
302 	if (m_conditionalData.conditionInPrimaryCommandBuffer)
303 	{
304 		beginConditionalRendering(vk, *cmdBuffer, *conditionalBuffer, m_conditionalData);
305 
306 		if (m_conditionalData.conditionInherited)
307 		{
308 			vk.cmdExecuteCommands(*cmdBuffer, 1, &secondaryCmdBuffer.get());
309 		}
310 		else
311 		{
312 			recordDispatch(vk, *cmdBuffer, indirectBuffer);
313 		}
314 
315 		vk.cmdEndConditionalRenderingEXT(*cmdBuffer);
316 	}
317 	else if (useSecondaryCmdBuffer)
318 	{
319 		vk.cmdExecuteCommands(*cmdBuffer, 1, &secondaryCmdBuffer.get());
320 	}
321 
322 	const vk::VkBufferMemoryBarrier outputBufferMemoryBarrier =
323 	{
324 		vk::VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
325 		DE_NULL,
326 		vk::VK_ACCESS_SHADER_WRITE_BIT,
327 		vk::VK_ACCESS_HOST_READ_BIT,
328 		VK_QUEUE_FAMILY_IGNORED,
329 		VK_QUEUE_FAMILY_IGNORED,
330 		outputBuffer.get(),
331 		0u,
332 		VK_WHOLE_SIZE
333 	};
334 
335 	vk.cmdPipelineBarrier(*cmdBuffer, vk::VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, vk::VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u, DE_NULL, 1u, &outputBufferMemoryBarrier, 0u, DE_NULL);
336 
337 	endCommandBuffer(vk, *cmdBuffer);
338 
339 	submitCommandsAndWait(vk, device, queue, *cmdBuffer);
340 
341 	// Check result
342 
343 	qpTestResult res = QP_TEST_RESULT_PASS;
344 
345 	const vk::Allocation& outputBufferAllocation = outputBuffer.getAllocation();
346 	invalidateAlloc(vk, device, outputBufferAllocation);
347 
348 	const deUint32* bufferPtr = static_cast<deUint32*>(outputBufferAllocation.getHostPtr());
349 
350 	const deUint32 expectedResult = m_conditionalData.expectCommandExecution ? m_numCalls : 0u;
351 	if (bufferPtr[0] != expectedResult)
352 	{
353 		res = QP_TEST_RESULT_FAIL;
354 	}
355 
356 	return tcu::TestStatus(res, qpGetTestResultName(res));
357 }
358 
359 }	// anonymous
360 
ConditionalDispatchTests(tcu::TestContext & testCtx)361 ConditionalDispatchTests::ConditionalDispatchTests (tcu::TestContext &testCtx)
362 	: TestCaseGroup	(testCtx, "dispatch", "Conditional Rendering Of Dispatch Commands")
363 {
364 	/* Left blank on purpose */
365 }
366 
~ConditionalDispatchTests(void)367 ConditionalDispatchTests::~ConditionalDispatchTests (void) {}
368 
init(void)369 void ConditionalDispatchTests::init (void)
370 {
371 	for (int conditionNdx = 0; conditionNdx < DE_LENGTH_OF_ARRAY(conditional::s_testsData); conditionNdx++)
372 	{
373 		const ConditionalData& conditionData = conditional::s_testsData[conditionNdx];
374 
375 		de::MovePtr<tcu::TestCaseGroup> conditionalDrawRootGroup(new tcu::TestCaseGroup(m_testCtx, de::toString(conditionData).c_str(), "Conditionaly execute dispatch calls"));
376 
377 		for (deUint32 commandTypeIdx = 0; commandTypeIdx < DISPATCH_COMMAND_TYPE_DISPATCH_LAST; ++commandTypeIdx)
378 		{
379 			const DispatchCommandType command = DispatchCommandType(commandTypeIdx);
380 
381 			ConditionalTestSpec testSpec;
382 			testSpec.command = command;
383 			testSpec.numCalls = 3;
384 			testSpec.conditionalData = conditionData;
385 
386 			conditionalDrawRootGroup->addChild(new ConditionalDispatchTest(m_testCtx, getDispatchCommandTypeName(command), "", testSpec));
387 		}
388 
389 		addChild(conditionalDrawRootGroup.release());
390 	}
391 
392 	// Tests verifying the condition is interpreted as a 32-bit value.
393 	{
394 		de::MovePtr<tcu::TestCaseGroup> conditionSizeGroup(new tcu::TestCaseGroup(m_testCtx, "condition_size", "Tests verifying the condition is being read as a 32-bit value"));
395 
396 		struct ValuePaddingExecution
397 		{
398 			deUint32	value;
399 			bool		padding;
400 			bool		execution;
401 			const char*	name;
402 		};
403 
404 		const ValuePaddingExecution kConditionValueResults[] =
405 		{
406 			{	0x00000001u,	false,	true,	"first_byte"	},
407 			{	0x00000100u,	false,	true,	"second_byte"	},
408 			{	0x00010000u,	false,	true,	"third_byte"	},
409 			{	0x01000000u,	false,	true,	"fourth_byte"	},
410 			{	0u,				true,	false,	"padded_zero"	},
411 		};
412 
413 		enum class ConditionSizeSubcaseType
414 		{
415 			PRIMARY_FLAT = 0,
416 			PRIMARY_WITH_SECONDARY,
417 			SECONDARY_NORMAL,
418 			SECONDARY_INHERITED,
419 		};
420 
421 		struct ConditionSizeSubcase
422 		{
423 			ConditionSizeSubcaseType	type;
424 			const char*					name;
425 		};
426 
427 		const ConditionSizeSubcase kConditionSizeSubcase[] =
428 		{
429 			{ ConditionSizeSubcaseType::PRIMARY_FLAT,				"primary"				},
430 			{ ConditionSizeSubcaseType::PRIMARY_WITH_SECONDARY,		"inherited"				},
431 			{ ConditionSizeSubcaseType::SECONDARY_NORMAL,			"secondary"				},
432 			{ ConditionSizeSubcaseType::SECONDARY_INHERITED,		"secondary_inherited"	},
433 		};
434 
435 		for (int subcaseNdx = 0; subcaseNdx < DE_LENGTH_OF_ARRAY(kConditionSizeSubcase); ++subcaseNdx)
436 		{
437 			const auto& subcase = kConditionSizeSubcase[subcaseNdx];
438 
439 			de::MovePtr<tcu::TestCaseGroup> subcaseGroup(new tcu::TestCaseGroup(m_testCtx, subcase.name, ""));
440 
441 			ConditionalData conditionalData		= {};
442 			conditionalData.conditionInverted	= false;
443 
444 			switch (subcase.type)
445 			{
446 				case ConditionSizeSubcaseType::PRIMARY_FLAT:
447 					conditionalData.conditionInPrimaryCommandBuffer		= true;
448 					conditionalData.conditionInSecondaryCommandBuffer	= false;
449 					conditionalData.conditionInherited					= false;
450 					break;
451 
452 				case ConditionSizeSubcaseType::PRIMARY_WITH_SECONDARY:
453 					conditionalData.conditionInPrimaryCommandBuffer		= true;
454 					conditionalData.conditionInSecondaryCommandBuffer	= false;
455 					conditionalData.conditionInherited					= true;
456 					break;
457 
458 				case ConditionSizeSubcaseType::SECONDARY_NORMAL:
459 					conditionalData.conditionInPrimaryCommandBuffer		= false;
460 					conditionalData.conditionInSecondaryCommandBuffer	= true;
461 					conditionalData.conditionInherited					= false;
462 					break;
463 
464 				case ConditionSizeSubcaseType::SECONDARY_INHERITED:
465 					conditionalData.conditionInPrimaryCommandBuffer		= false;
466 					conditionalData.conditionInSecondaryCommandBuffer	= true;
467 					conditionalData.conditionInherited					= true;
468 					break;
469 
470 				default:
471 					DE_ASSERT(false);
472 					break;
473 			}
474 
475 			for (int valueNdx = 0; valueNdx < DE_LENGTH_OF_ARRAY(kConditionValueResults); ++valueNdx)
476 			{
477 				const auto& valueResults = kConditionValueResults[valueNdx];
478 
479 				conditionalData.conditionValue			= valueResults.value;
480 				conditionalData.padConditionValue		= valueResults.padding;
481 				conditionalData.expectCommandExecution	= valueResults.execution;
482 
483 				ConditionalTestSpec spec;
484 				spec.command			= DISPATCH_COMMAND_TYPE_DISPATCH;
485 				spec.numCalls			= 1;
486 				spec.conditionalData	= conditionalData;
487 
488 				subcaseGroup->addChild(new ConditionalDispatchTest(m_testCtx, valueResults.name, "", spec));
489 			}
490 
491 			conditionSizeGroup->addChild(subcaseGroup.release());
492 		}
493 
494 		addChild(conditionSizeGroup.release());
495 	}
496 }
497 
498 }	// conditional
499 }	// vkt
500