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 "tcuTestLog.hpp"
29#include "tcuResource.hpp"
30
31#include "vkDefs.hpp"
32#include "vkCmdUtil.hpp"
33#include "vkBuilderUtil.hpp"
34#include "vkObjUtil.hpp"
35#include "vkTypeUtil.hpp"
36#include "vkBufferWithMemory.hpp"
37
38namespace vkt
39{
40namespace conditional
41{
42namespace
43{
44
45enum DispatchCommandType
46{
47	DISPATCH_COMMAND_TYPE_DISPATCH = 0,
48	DISPATCH_COMMAND_TYPE_DISPATCH_INDIRECT,
49	DISPATCH_COMMAND_TYPE_DISPATCH_BASE,
50	DISPATCH_COMMAND_TYPE_DISPATCH_LAST
51};
52
53const char* getDispatchCommandTypeName (DispatchCommandType command)
54{
55	switch (command)
56	{
57		case DISPATCH_COMMAND_TYPE_DISPATCH:			    return "dispatch";
58		case DISPATCH_COMMAND_TYPE_DISPATCH_INDIRECT:	    return "dispatch_indirect";
59		case DISPATCH_COMMAND_TYPE_DISPATCH_BASE:			return "dispatch_base";
60		default:					                        DE_ASSERT(false);
61	}
62	return "";
63}
64
65struct ConditionalTestSpec
66{
67	DispatchCommandType	command;
68	int					numCalls;
69	ConditionalData		conditionalData;
70};
71
72class ConditionalDispatchTest : public vkt::TestCase
73{
74public:
75						ConditionalDispatchTest	(tcu::TestContext&			testCtx,
76												 const std::string&			name,
77												 const ConditionalTestSpec&	testSpec);
78
79	void				initPrograms			(vk::SourceCollections&	sourceCollections) const;
80	void				checkSupport			(Context&				context) const;
81	TestInstance*		createInstance			(Context&				context) const;
82
83private:
84	const ConditionalTestSpec m_testSpec;
85};
86
87class ConditionalDispatchTestInstance : public TestInstance
88{
89public:
90								ConditionalDispatchTestInstance	(Context &context, ConditionalTestSpec testSpec);
91
92	virtual		tcu::TestStatus iterate							(void);
93	void						recordDispatch					(const vk::DeviceInterface&	vk,
94																 vk::VkCommandBuffer cmdBuffer,
95																 vk::BufferWithMemory& indirectBuffer);
96
97protected:
98	const DispatchCommandType		m_command;
99	const int						m_numCalls;
100	const ConditionalData			m_conditionalData;
101};
102
103ConditionalDispatchTest::ConditionalDispatchTest(tcu::TestContext&			testCtx,
104												 const std::string&			name,
105												 const ConditionalTestSpec&	testSpec)
106	: TestCase		(testCtx, name)
107	, m_testSpec	(testSpec)
108{
109}
110
111void ConditionalDispatchTest::initPrograms (vk::SourceCollections& sourceCollections) const
112{
113	std::ostringstream src;
114	src << "#version 310 es\n"
115		<< "layout(local_size_x = 1u, local_size_y = 1u, local_size_z = 1u) in;\n"
116		<< "layout(set = 0, binding = 0, std140) buffer Out\n"
117		<< "{\n"
118		<< "    coherent uint count;\n"
119		<< "};\n"
120		<< "void main(void)\n"
121		<< "{\n"
122		<< "	atomicAdd(count, 1u);\n"
123		<< "}\n";
124
125	sourceCollections.glslSources.add("comp") << glu::ComputeSource(src.str());
126}
127
128void ConditionalDispatchTest::checkSupport(Context& context) const
129{
130	checkConditionalRenderingCapabilities(context, m_testSpec.conditionalData);
131
132	if (m_testSpec.command == DISPATCH_COMMAND_TYPE_DISPATCH_BASE)
133		context.requireDeviceFunctionality("VK_KHR_device_group");
134}
135
136TestInstance* ConditionalDispatchTest::createInstance (Context& context) const
137{
138	return new ConditionalDispatchTestInstance(context, m_testSpec);
139}
140
141ConditionalDispatchTestInstance::ConditionalDispatchTestInstance (Context &context, ConditionalTestSpec testSpec)
142	: TestInstance(context)
143	, m_command(testSpec.command)
144	, m_numCalls(testSpec.numCalls)
145	, m_conditionalData(testSpec.conditionalData)
146{
147}
148
149void ConditionalDispatchTestInstance::recordDispatch (const vk::DeviceInterface& vk,
150													  vk::VkCommandBuffer cmdBuffer,
151													  vk::BufferWithMemory& indirectBuffer)
152{
153	for (int i = 0; i < m_numCalls; i++)
154	{
155		switch (m_command)
156		{
157			case DISPATCH_COMMAND_TYPE_DISPATCH:
158			{
159				vk.cmdDispatch(cmdBuffer, 1, 1, 1);
160				break;
161			}
162			case DISPATCH_COMMAND_TYPE_DISPATCH_INDIRECT:
163			{
164				vk.cmdDispatchIndirect(cmdBuffer, *indirectBuffer, 0);
165				break;
166			}
167			case DISPATCH_COMMAND_TYPE_DISPATCH_BASE:
168			{
169				vk.cmdDispatchBase(cmdBuffer, 0, 0, 0, 1, 1, 1);
170				break;
171			}
172			default: DE_ASSERT(DE_FALSE);
173		}
174	}
175}
176
177tcu::TestStatus ConditionalDispatchTestInstance::iterate (void)
178{
179	const vk::DeviceInterface&	vk					= m_context.getDeviceInterface();
180	const vk::VkDevice			device				= m_context.getDevice();
181	const vk::VkQueue			queue				= m_context.getUniversalQueue();
182	const deUint32			    queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
183	vk::Allocator&				allocator			= m_context.getDefaultAllocator();
184
185	// Create a buffer and host-visible memory for it
186
187	const vk::VkDeviceSize bufferSizeBytes = sizeof(deUint32);
188	const vk::BufferWithMemory outputBuffer(vk, device, allocator, vk::makeBufferCreateInfo(bufferSizeBytes, vk::VK_BUFFER_USAGE_STORAGE_BUFFER_BIT), vk::MemoryRequirement::HostVisible);
189
190	{
191		const vk::Allocation& alloc = outputBuffer.getAllocation();
192		deUint8* outputBufferPtr = reinterpret_cast<deUint8*>(alloc.getHostPtr());
193		*(deUint32*)(outputBufferPtr) = 0;
194		vk::flushAlloc(vk, device, alloc);
195	}
196
197	// Create descriptor set
198
199	const vk::Unique<vk::VkDescriptorSetLayout> descriptorSetLayout(
200		vk::DescriptorSetLayoutBuilder()
201		.addSingleBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, vk::VK_SHADER_STAGE_COMPUTE_BIT)
202		.build(vk, device));
203
204	const vk::Unique<vk::VkDescriptorPool> descriptorPool(
205		vk::DescriptorPoolBuilder()
206		.addType(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
207		.build(vk, device, vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
208
209	const vk::Unique<vk::VkDescriptorSet> descriptorSet(makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
210
211	const vk::VkDescriptorBufferInfo descriptorInfo = vk::makeDescriptorBufferInfo(*outputBuffer, 0ull, bufferSizeBytes);
212	vk::DescriptorSetUpdateBuilder()
213		.writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descriptorInfo)
214		.update(vk, device);
215
216	// Setup pipeline
217
218	const vk::Unique<vk::VkShaderModule>	shaderModule		(createShaderModule(vk, device, m_context.getBinaryCollection().get("comp"), 0u));
219	const vk::Unique<vk::VkPipelineLayout>	pipelineLayout		(makePipelineLayout(vk, device, *descriptorSetLayout));
220	const vk::Unique<vk::VkPipeline>		pipeline			(makeComputePipeline(vk, device, *pipelineLayout, *shaderModule));
221
222	const vk::Unique<vk::VkCommandPool>		cmdPool				(makeCommandPool(vk, device, queueFamilyIndex));
223	const vk::Unique<vk::VkCommandBuffer>	cmdBuffer			(vk::allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
224	const vk::Unique<vk::VkCommandBuffer>	secondaryCmdBuffer	(vk::allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_SECONDARY));
225
226	// Create indirect buffer
227	const vk::VkDispatchIndirectCommand dispatchCommands[] = { { 1u, 1u, 1u } };
228
229	vk::BufferWithMemory indirectBuffer(
230		vk, device, allocator,
231		vk::makeBufferCreateInfo(sizeof(dispatchCommands), vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT | vk::VK_BUFFER_USAGE_STORAGE_BUFFER_BIT),
232		vk::MemoryRequirement::HostVisible);
233
234	deUint8* indirectBufferPtr = reinterpret_cast<deUint8*>(indirectBuffer.getAllocation().getHostPtr());
235	deMemcpy(indirectBufferPtr, &dispatchCommands[0], sizeof(dispatchCommands));
236
237	vk::flushAlloc(vk, device, indirectBuffer.getAllocation());
238
239	// Start recording commands
240
241	beginCommandBuffer(vk, *cmdBuffer);
242
243	vk::VkCommandBuffer targetCmdBuffer = *cmdBuffer;
244
245	const bool useSecondaryCmdBuffer = m_conditionalData.conditionInherited || m_conditionalData.conditionInSecondaryCommandBuffer;
246
247	if (useSecondaryCmdBuffer)
248	{
249		const vk::VkCommandBufferInheritanceConditionalRenderingInfoEXT conditionalRenderingInheritanceInfo =
250		{
251			vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_CONDITIONAL_RENDERING_INFO_EXT,
252			DE_NULL,
253			m_conditionalData.conditionInherited ? VK_TRUE : VK_FALSE	// conditionalRenderingEnable
254		};
255
256		const vk::VkCommandBufferInheritanceInfo inheritanceInfo =
257		{
258			vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO,
259			&conditionalRenderingInheritanceInfo,
260			0u,										        // renderPass
261			0u,												// subpass
262			0u,										        // framebuffer
263			VK_FALSE,										// occlusionQueryEnable
264			(vk::VkQueryControlFlags)0u,					// queryFlags
265			(vk::VkQueryPipelineStatisticFlags)0u,			// pipelineStatistics
266		};
267
268		const vk::VkCommandBufferBeginInfo commandBufferBeginInfo =
269		{
270			vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
271			DE_NULL,
272			vk::VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
273			&inheritanceInfo
274		};
275
276		VK_CHECK(vk.beginCommandBuffer(*secondaryCmdBuffer, &commandBufferBeginInfo));
277
278		targetCmdBuffer = *secondaryCmdBuffer;
279	}
280
281	vk.cmdBindPipeline(targetCmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
282	vk.cmdBindDescriptorSets(targetCmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &descriptorSet.get(), 0u, DE_NULL);
283
284	de::SharedPtr<Draw::Buffer> conditionalBuffer = createConditionalRenderingBuffer(m_context, m_conditionalData);
285
286	if (m_conditionalData.conditionInSecondaryCommandBuffer)
287	{
288		beginConditionalRendering(vk, *secondaryCmdBuffer, *conditionalBuffer, m_conditionalData);
289		recordDispatch(vk, *secondaryCmdBuffer, indirectBuffer);
290		vk.cmdEndConditionalRenderingEXT(*secondaryCmdBuffer);
291		vk.endCommandBuffer(*secondaryCmdBuffer);
292	}
293	else if (m_conditionalData.conditionInherited)
294	{
295		recordDispatch(vk, *secondaryCmdBuffer, indirectBuffer);
296		vk.endCommandBuffer(*secondaryCmdBuffer);
297	}
298
299	if (m_conditionalData.conditionInPrimaryCommandBuffer)
300	{
301		beginConditionalRendering(vk, *cmdBuffer, *conditionalBuffer, m_conditionalData);
302
303		if (m_conditionalData.conditionInherited)
304		{
305			vk.cmdExecuteCommands(*cmdBuffer, 1, &secondaryCmdBuffer.get());
306		}
307		else
308		{
309			recordDispatch(vk, *cmdBuffer, indirectBuffer);
310		}
311
312		vk.cmdEndConditionalRenderingEXT(*cmdBuffer);
313	}
314	else if (useSecondaryCmdBuffer)
315	{
316		vk.cmdExecuteCommands(*cmdBuffer, 1, &secondaryCmdBuffer.get());
317	}
318
319	const vk::VkBufferMemoryBarrier outputBufferMemoryBarrier =
320	{
321		vk::VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
322		DE_NULL,
323		vk::VK_ACCESS_SHADER_WRITE_BIT,
324		vk::VK_ACCESS_HOST_READ_BIT,
325		VK_QUEUE_FAMILY_IGNORED,
326		VK_QUEUE_FAMILY_IGNORED,
327		outputBuffer.get(),
328		0u,
329		VK_WHOLE_SIZE
330	};
331
332	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);
333
334	endCommandBuffer(vk, *cmdBuffer);
335
336	submitCommandsAndWait(vk, device, queue, *cmdBuffer);
337
338	// Check result
339
340	qpTestResult res = QP_TEST_RESULT_PASS;
341
342	const vk::Allocation& outputBufferAllocation = outputBuffer.getAllocation();
343	invalidateAlloc(vk, device, outputBufferAllocation);
344
345	const deUint32* bufferPtr = static_cast<deUint32*>(outputBufferAllocation.getHostPtr());
346
347	const deUint32 expectedResult = m_conditionalData.expectCommandExecution ? m_numCalls : 0u;
348	if (bufferPtr[0] != expectedResult)
349	{
350		res = QP_TEST_RESULT_FAIL;
351	}
352
353	return tcu::TestStatus(res, qpGetTestResultName(res));
354}
355
356}	// anonymous
357
358ConditionalDispatchTests::ConditionalDispatchTests (tcu::TestContext &testCtx)
359	: TestCaseGroup	(testCtx, "dispatch", "Conditional Rendering Of Dispatch Commands")
360{
361	/* Left blank on purpose */
362}
363
364ConditionalDispatchTests::~ConditionalDispatchTests (void) {}
365
366void ConditionalDispatchTests::init (void)
367{
368	for (int conditionNdx = 0; conditionNdx < DE_LENGTH_OF_ARRAY(conditional::s_testsData); conditionNdx++)
369	{
370		const ConditionalData& conditionData = conditional::s_testsData[conditionNdx];
371
372		if (conditionData.clearInRenderPass)
373			continue;
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	enum class ConditionLocation
393	{
394		PRIMARY_FLAT = 0,
395		PRIMARY_WITH_SECONDARY,
396		SECONDARY_NORMAL,
397		SECONDARY_INHERITED,
398	};
399
400	// Tests verifying the condition is interpreted as a 32-bit value.
401	{
402		de::MovePtr<tcu::TestCaseGroup> conditionSizeGroup(new tcu::TestCaseGroup(m_testCtx, "condition_size"));
403
404		struct ValuePaddingExecution
405		{
406			deUint32	value;
407			bool		padding;
408			bool		execution;
409			const char*	name;
410		};
411
412		const ValuePaddingExecution kConditionValueResults[] =
413		{
414			{	0x00000001u,	false,	true,	"first_byte"	},
415			{	0x00000100u,	false,	true,	"second_byte"	},
416			{	0x00010000u,	false,	true,	"third_byte"	},
417			{	0x01000000u,	false,	true,	"fourth_byte"	},
418			{	0u,				true,	false,	"padded_zero"	},
419		};
420
421		struct ConditionLocationSubcase
422		{
423			ConditionLocation	location;
424			const char*			name;
425		};
426
427		const ConditionLocationSubcase kConditionLocationSubcase[] =
428		{
429			{ ConditionLocation::PRIMARY_FLAT,				"primary"				},
430			{ ConditionLocation::PRIMARY_WITH_SECONDARY,	"inherited"				},
431			{ ConditionLocation::SECONDARY_NORMAL,			"secondary"				},
432			{ ConditionLocation::SECONDARY_INHERITED,		"secondary_inherited"	},
433		};
434
435		for (int subcaseNdx = 0; subcaseNdx < DE_LENGTH_OF_ARRAY(kConditionLocationSubcase); ++subcaseNdx)
436		{
437			const auto& subcase = kConditionLocationSubcase[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.location)
445			{
446				case ConditionLocation::PRIMARY_FLAT:
447					conditionalData.conditionInPrimaryCommandBuffer		= true;
448					conditionalData.conditionInSecondaryCommandBuffer	= false;
449					conditionalData.conditionInherited					= false;
450					break;
451
452				case ConditionLocation::PRIMARY_WITH_SECONDARY:
453					conditionalData.conditionInPrimaryCommandBuffer		= true;
454					conditionalData.conditionInSecondaryCommandBuffer	= false;
455					conditionalData.conditionInherited					= true;
456					break;
457
458				case ConditionLocation::SECONDARY_NORMAL:
459					conditionalData.conditionInPrimaryCommandBuffer		= false;
460					conditionalData.conditionInSecondaryCommandBuffer	= true;
461					conditionalData.conditionInherited					= false;
462					break;
463
464				case ConditionLocation::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	// Tests checking the buffer allocation offset is applied correctly when reading the condition.
498	{
499		de::MovePtr<tcu::TestCaseGroup> allocOffsetGroup(new tcu::TestCaseGroup(m_testCtx, "alloc_offset"));
500
501		const struct
502		{
503			ConditionLocation	location;
504			const char*			name;
505		} kLocationCases[] =
506		{
507			{ ConditionLocation::PRIMARY_FLAT,				"primary"				},
508			{ ConditionLocation::PRIMARY_WITH_SECONDARY,	"inherited"				},
509			{ ConditionLocation::SECONDARY_NORMAL,			"secondary"				},
510			{ ConditionLocation::SECONDARY_INHERITED,		"secondary_inherited"	},
511		};
512
513		const struct
514		{
515			bool		active;
516			const char*	name;
517		} kActiveCases[] =
518		{
519			{ false,	"zero"		},
520			{ true,		"nonzero"	},
521		};
522
523		const struct
524		{
525			ConditionalBufferMemory		memoryType;
526			const char*					name;
527		} kMemoryTypeCases[] =
528		{
529			{ LOCAL,	"device_local"	},
530			{ HOST,		"host_visible"	},
531		};
532
533		for (const auto& locationCase : kLocationCases)
534		{
535			de::MovePtr<tcu::TestCaseGroup> locationSubGroup(new tcu::TestCaseGroup(m_testCtx, locationCase.name));
536
537			for (const auto& activeCase : kActiveCases)
538			{
539				de::MovePtr<tcu::TestCaseGroup> activeSubGroup(new tcu::TestCaseGroup(m_testCtx, activeCase.name));
540
541				for (const auto& memoryTypeCase : kMemoryTypeCases)
542				{
543					ConditionalData conditionalData =
544					{
545						false,						//	bool					conditionInPrimaryCommandBuffer;
546						false,						//	bool					conditionInSecondaryCommandBuffer;
547						false,						//	bool					conditionInverted;
548						false,						//	bool					conditionInherited;
549						0u,							//	deUint32				conditionValue;
550						false,						//	bool					padConditionValue;
551						true,						//	bool					allocationOffset;
552						false,						//	bool					clearInRenderPass;
553						false,						//	bool					expectCommandExecution;
554						memoryTypeCase.memoryType,	//	ConditionalBufferMemory	memoryType;
555					};
556
557					switch (locationCase.location)
558					{
559						case ConditionLocation::PRIMARY_FLAT:
560							conditionalData.conditionInPrimaryCommandBuffer		= true;
561							conditionalData.conditionInSecondaryCommandBuffer	= false;
562							conditionalData.conditionInherited					= false;
563							break;
564
565						case ConditionLocation::PRIMARY_WITH_SECONDARY:
566							conditionalData.conditionInPrimaryCommandBuffer		= true;
567							conditionalData.conditionInSecondaryCommandBuffer	= false;
568							conditionalData.conditionInherited					= true;
569							break;
570
571						case ConditionLocation::SECONDARY_NORMAL:
572							conditionalData.conditionInPrimaryCommandBuffer		= false;
573							conditionalData.conditionInSecondaryCommandBuffer	= true;
574							conditionalData.conditionInherited					= false;
575							break;
576
577						case ConditionLocation::SECONDARY_INHERITED:
578							conditionalData.conditionInPrimaryCommandBuffer		= false;
579							conditionalData.conditionInSecondaryCommandBuffer	= true;
580							conditionalData.conditionInherited					= true;
581							break;
582
583						default:
584							DE_ASSERT(false);
585							break;
586					}
587
588					conditionalData.conditionValue			= (activeCase.active ? 1u : 0u);
589					conditionalData.expectCommandExecution	= activeCase.active;
590
591					const ConditionalTestSpec spec =
592					{
593						DISPATCH_COMMAND_TYPE_DISPATCH,	//	DispatchCommandType	command;
594						1,								//	int					numCalls;
595						conditionalData,				//	ConditionalData		conditionalData;
596					};
597
598					activeSubGroup->addChild(new ConditionalDispatchTest(m_testCtx, memoryTypeCase.name, spec));
599				}
600
601				locationSubGroup->addChild(activeSubGroup.release());
602			}
603
604			allocOffsetGroup->addChild(locationSubGroup.release());
605		}
606
607		addChild(allocOffsetGroup.release());
608	}
609}
610
611}	// conditional
612}	// vkt
613