1/*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2022 The Khronos Group Inc.
6 * Copyright (c) 2022 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 Tests using VK_EXT_mesh_shader and VK_EXT_conditional_rendering
23 *//*--------------------------------------------------------------------*/
24
25#include "vktMeshShaderConditionalRenderingTestsEXT.hpp"
26#include "vktMeshShaderUtil.hpp"
27#include "vktTestCase.hpp"
28
29#include "vkObjUtil.hpp"
30#include "vkQueryUtil.hpp"
31#include "vkMemUtil.hpp"
32#include "vkTypeUtil.hpp"
33#include "vkImageUtil.hpp"
34#include "vkImageWithMemory.hpp"
35#include "vkBufferWithMemory.hpp"
36#include "vkCmdUtil.hpp"
37#include "vkBarrierUtil.hpp"
38
39#include "tcuVector.hpp"
40#include "tcuImageCompare.hpp"
41
42#include <vector>
43#include <sstream>
44#include <memory>
45
46namespace vkt
47{
48namespace MeshShader
49{
50
51namespace
52{
53
54using namespace vk;
55
56using GroupPtr = de::MovePtr<tcu::TestCaseGroup>;
57
58enum class DrawType
59{
60	DRAW,
61	DRAW_INDIRECT,
62	DRAW_INDIRECT_WITH_COUNT,
63};
64
65enum class CmdBufferType
66{
67	PRIMARY,
68	SECONDARY,
69	SECONDARY_WITH_INHERITANCE,
70};
71
72static constexpr VkDeviceSize kBindOffset = 16u;
73
74std::vector<uint32_t> getCondValues (void)
75{
76	const std::vector<uint32_t> values =
77	{
78		0x01000000u,
79		0x00010000u,
80		0x00000100u,
81		0x00000001u,
82		0x00000000u,
83	};
84
85	return values;
86}
87
88std::string paddedHex (uint32_t value)
89{
90	std::ostringstream repr;
91	repr << "0x" << std::hex << std::setw(8u) << std::setfill('0') << value;
92	return repr.str();
93}
94
95tcu::Vec4 getOutputColor (void)
96{
97	return tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f);
98}
99
100tcu::Vec4 getClearColor (void)
101{
102	return tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f);
103}
104
105struct TestParams
106{
107	DrawType		drawType;
108	CmdBufferType	cmdBufferType;
109	bool			bindWithOffset;
110	bool			condWithOffset;
111	uint32_t		condValue;
112	bool			inverted;
113	bool			useTask;
114
115	bool needsSecondaryCmdBuffer (void) const
116	{
117		return (cmdBufferType != CmdBufferType::PRIMARY);
118	}
119};
120
121class ConditionalRenderingCase : public vkt::TestCase
122{
123public:
124					ConditionalRenderingCase	(tcu::TestContext& testCtx, const std::string& name, const TestParams& params)
125						: vkt::TestCase	(testCtx, name)
126						, m_params		(params)
127						{}
128	virtual			~ConditionalRenderingCase	(void) {}
129
130	void			initPrograms				(vk::SourceCollections& programCollection) const override;
131	TestInstance*	createInstance				(Context& context) const override;
132	void			checkSupport				(Context& context) const override;
133
134protected:
135	const TestParams m_params;
136};
137
138class ConditionBuffer
139{
140public:
141	ConditionBuffer (const DeviceInterface& vkd, VkDevice device, Allocator& alloc, uint32_t condValue, bool bindWithOffset, bool condWithOffset)
142		: m_buffer		()
143		, m_allocation	()
144		, m_condOffset	(0ull)
145	{
146		// Create buffer with the desired size first.
147		const auto	condSize			= static_cast<VkDeviceSize>(sizeof(condValue));
148		const auto	condOffset			= (condWithOffset ? condSize : 0ull);
149		const auto	bufferSize			= condSize + condOffset;
150		const auto	bufferCreateInfo	= makeBufferCreateInfo(bufferSize, VK_BUFFER_USAGE_CONDITIONAL_RENDERING_BIT_EXT);
151		auto		buffer				= createBuffer(vkd, device, &bufferCreateInfo);
152
153		// Allocate memory taking bindWithOffset into account.
154		const auto bufferMemReqs	= getBufferMemoryRequirements(vkd, device, buffer.get());
155		const auto bindOffset		= (bindWithOffset ? de::roundUp(kBindOffset, bufferMemReqs.alignment) : 0ull);
156		const auto allocSize		= bufferMemReqs.size + bindOffset;
157
158		const auto	actualMemReqs	= makeMemoryRequirements(allocSize, bufferMemReqs.alignment, bufferMemReqs.memoryTypeBits);
159		auto		allocation		= alloc.allocate(actualMemReqs, MemoryRequirement::HostVisible);
160		vkd.bindBufferMemory(device, buffer.get(), allocation->getMemory(), bindOffset);
161
162		// Fill buffer data.
163		const uint32_t	fillValue	= ((condValue != 0u) ? 0u : 1u);
164		uint8_t*		hostPtr		= reinterpret_cast<uint8_t*>(allocation->getHostPtr());
165
166		deMemset(hostPtr,							0,			static_cast<size_t>(actualMemReqs.size));
167		deMemcpy(hostPtr + bindOffset,				&fillValue,	sizeof(fillValue));
168		deMemcpy(hostPtr + bindOffset + condOffset,	&condValue,	sizeof(condValue));
169
170		m_buffer		= buffer;
171		m_allocation	= allocation;
172		m_condOffset	= condOffset;
173	}
174
175	VkDeviceSize getCondOffset (void) const
176	{
177		return m_condOffset;
178	}
179
180	VkBuffer getBuffer (void) const
181	{
182		return m_buffer.get();
183	}
184
185	// Cannot copy or assign this.
186	ConditionBuffer (const ConditionBuffer&) = delete;
187	ConditionBuffer& operator=(const ConditionBuffer&) = delete;
188
189protected:
190	Move<VkBuffer>			m_buffer;
191	de::MovePtr<Allocation>	m_allocation;
192	VkDeviceSize			m_condOffset;
193};
194
195class ConditionalRenderingInstance : public vkt::TestInstance
196{
197public:
198							ConditionalRenderingInstance	(Context& context, const TestParams& params)
199								: vkt::TestInstance			(context)
200								, m_params					(params)
201								, m_conditionBuffer			()
202								, m_indirectDrawArgsBuffer	()
203								, m_indirectDrawCountBuffer	()
204								{}
205	virtual					~ConditionalRenderingInstance	(void) {}
206
207	tcu::TestStatus			iterate							(void) override;
208
209protected:
210	// Creates the indirect buffers that are needed according to the test parameters.
211	void					initIndirectBuffers				(const DeviceInterface& vkd, const VkDevice device, Allocator& alloc);
212
213	// Calls the appropriate drawing command depending on the test parameters.
214	void					drawMeshTasks					(const DeviceInterface& vkd, const VkCommandBuffer cmdBuffer) const;
215
216	const TestParams					m_params;
217	std::unique_ptr<ConditionBuffer>	m_conditionBuffer;
218	std::unique_ptr<BufferWithMemory>	m_indirectDrawArgsBuffer;
219	std::unique_ptr<BufferWithMemory>	m_indirectDrawCountBuffer;
220};
221
222// Makes an indirect buffer with the specified contents.
223template<class T>
224std::unique_ptr<BufferWithMemory> makeIndirectBuffer (const DeviceInterface& vkd, const VkDevice device, Allocator& alloc, const T& data)
225{
226	const auto bufferSize		= static_cast<VkDeviceSize>(sizeof(data));
227	const auto bufferCreateInfo	= makeBufferCreateInfo(bufferSize, VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT);
228
229	std::unique_ptr<BufferWithMemory> buffer (new BufferWithMemory(vkd, device, alloc, bufferCreateInfo, MemoryRequirement::HostVisible));
230
231	auto& allocation	= buffer->getAllocation();
232	void* dataPtr		= allocation.getHostPtr();
233
234	deMemcpy(dataPtr, &data, sizeof(data));
235	flushAlloc(vkd, device, allocation);
236
237	return buffer;
238}
239
240void ConditionalRenderingInstance::initIndirectBuffers (const DeviceInterface& vkd, const VkDevice device, Allocator& alloc)
241{
242	if (m_params.drawType != DrawType::DRAW)
243	{
244		const VkDrawMeshTasksIndirectCommandEXT drawArgs = { 1u, 1u, 1u };
245		m_indirectDrawArgsBuffer = makeIndirectBuffer(vkd, device, alloc, drawArgs);
246	}
247
248	if (m_params.drawType == DrawType::DRAW_INDIRECT_WITH_COUNT)
249	{
250		const uint32_t drawCount = 1u;
251		m_indirectDrawCountBuffer = makeIndirectBuffer(vkd, device, alloc, drawCount);
252	}
253}
254
255void ConditionalRenderingInstance::drawMeshTasks (const DeviceInterface& vkd, const VkCommandBuffer cmdBuffer) const
256{
257	const auto stride = static_cast<uint32_t>(sizeof(VkDrawMeshTasksIndirectCommandEXT));
258
259	if (m_params.drawType == DrawType::DRAW)
260	{
261		vkd.cmdDrawMeshTasksEXT(cmdBuffer, 1u, 1u, 1u);
262	}
263	else if (m_params.drawType == DrawType::DRAW_INDIRECT)
264	{
265		vkd.cmdDrawMeshTasksIndirectEXT(cmdBuffer, m_indirectDrawArgsBuffer->get(), 0ull, 1u, stride);
266	}
267	else if (m_params.drawType == DrawType::DRAW_INDIRECT_WITH_COUNT)
268	{
269		vkd.cmdDrawMeshTasksIndirectCountEXT(cmdBuffer, m_indirectDrawArgsBuffer->get(), 0ull, m_indirectDrawCountBuffer->get(), 0ull, 1u, stride);
270	}
271	else
272		DE_ASSERT(false);
273}
274
275void ConditionalRenderingCase::initPrograms (vk::SourceCollections& programCollection) const
276{
277	const auto buildOptions = getMinMeshEXTBuildOptions(programCollection.usedVulkanVersion);
278
279	if (m_params.useTask)
280	{
281		std::ostringstream task;
282		task
283			<< "#version 460\n"
284			<< "#extension GL_EXT_mesh_shader : enable\n"
285			<< "\n"
286			<< "layout (local_size_x=1, local_size_y=1, local_size_z=1) in;\n"
287			<< "\n"
288			<< "void main (void) {\n"
289			<< "    EmitMeshTasksEXT(1u, 1u, 1u);\n"
290			<< "}\n"
291			;
292		programCollection.glslSources.add("task") << glu::TaskSource(task.str()) << buildOptions;
293	}
294
295	std::ostringstream mesh;
296	mesh
297		<< "#version 460\n"
298		<< "#extension GL_EXT_mesh_shader : enable\n"
299		<< "\n"
300		<< "layout (local_size_x=1, local_size_y=1, local_size_z=1) in;\n"
301		<< "layout (triangles) out;\n"
302		<< "layout (max_vertices=3, max_primitives=1) out;\n"
303		<< "\n"
304		<< "void main (void) {\n"
305		<< "    SetMeshOutputsEXT(3u, 1u);\n"
306		<< "\n"
307		<< "    gl_PrimitiveTriangleIndicesEXT[0] = uvec3(0u, 1u, 2u);\n"
308		<< "\n"
309		<< "    gl_MeshVerticesEXT[0].gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n"
310		<< "    gl_MeshVerticesEXT[1].gl_Position = vec4(-1.0,  3.0, 0.0, 1.0);\n"
311		<< "    gl_MeshVerticesEXT[2].gl_Position = vec4( 3.0, -1.0, 0.0, 1.0);\n"
312		<< "}\n"
313		;
314	programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str()) << buildOptions;
315
316	const auto outColor = getOutputColor();
317	std::ostringstream frag;
318	frag
319		<< "#version 460\n"
320		<< "\n"
321		<< "layout (location=0) out vec4 outColor;\n"
322		<< "\n"
323		<< "void main (void) {\n"
324		<< "    outColor = vec4" << outColor << ";\n"
325		<< "}\n"
326		;
327	programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str());
328}
329
330TestInstance* ConditionalRenderingCase::createInstance (Context& context) const
331{
332	return new ConditionalRenderingInstance(context, m_params);
333}
334
335void ConditionalRenderingCase::checkSupport (Context& context) const
336{
337	checkTaskMeshShaderSupportEXT(context, m_params.useTask/*requireTask*/, true/*requireMesh*/);
338
339	context.requireDeviceFunctionality("VK_EXT_conditional_rendering");
340
341	if (m_params.drawType == DrawType::DRAW_INDIRECT_WITH_COUNT)
342		context.requireDeviceFunctionality("VK_KHR_draw_indirect_count");
343
344	if (m_params.cmdBufferType == CmdBufferType::SECONDARY_WITH_INHERITANCE)
345	{
346		const auto& condRenderingFeatures = context.getConditionalRenderingFeaturesEXT();
347		if (!condRenderingFeatures.inheritedConditionalRendering)
348			TCU_THROW(NotSupportedError, "inheritedConditionalRendering not supported");
349	}
350}
351
352tcu::TestStatus ConditionalRenderingInstance::iterate ()
353{
354	const auto&			vkd				= m_context.getDeviceInterface();
355	const auto			device			= m_context.getDevice();
356	auto&				alloc			= m_context.getDefaultAllocator();
357	const auto			queueIndex		= m_context.getUniversalQueueFamilyIndex();
358	const auto			queue			= m_context.getUniversalQueue();
359
360	const auto			colorFormat		= VK_FORMAT_R8G8B8A8_UNORM;
361	const auto			colorUsage		= (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
362	const auto			tcuFormat		= mapVkFormat(colorFormat);
363	const auto			colorExtent		= makeExtent3D(4u, 4u, 1u);
364	const tcu::IVec3	iExtent3D		(static_cast<int>(colorExtent.width), static_cast<int>(colorExtent.height), static_cast<int>(colorExtent.depth));
365	const auto			clearColor		= getClearColor();
366	const auto			drawColor		= getOutputColor();
367	const auto			bindPoint		= VK_PIPELINE_BIND_POINT_GRAPHICS;
368	const auto			needsSecCmd		= m_params.needsSecondaryCmdBuffer();
369
370	// Create color attachment.
371	const VkImageCreateInfo colorAttCreateInfo =
372	{
373		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,	//	VkStructureType			sType;
374		nullptr,								//	const void*				pNext;
375		0u,										//	VkImageCreateFlags		flags;
376		VK_IMAGE_TYPE_2D,						//	VkImageType				imageType;
377		colorFormat,							//	VkFormat				format;
378		colorExtent,							//	VkExtent3D				extent;
379		1u,										//	uint32_t				mipLevels;
380		1u,										//	uint32_t				arrayLayers;
381		VK_SAMPLE_COUNT_1_BIT,					//	VkSampleCountFlagBits	samples;
382		VK_IMAGE_TILING_OPTIMAL,				//	VkImageTiling			tiling;
383		colorUsage,								//	VkImageUsageFlags		usage;
384		VK_SHARING_MODE_EXCLUSIVE,				//	VkSharingMode			sharingMode;
385		0u,										//	uint32_t				queueFamilyIndexCount;
386		nullptr,								//	const uint32_t*			pQueueFamilyIndices;
387		VK_IMAGE_LAYOUT_UNDEFINED,				//	VkImageLayout			initialLayout;
388	};
389	ImageWithMemory	colorAtt		(vkd, device, alloc, colorAttCreateInfo, MemoryRequirement::Any);
390	const auto		colorSRR		= makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
391	const auto		colorSRL		= makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u);
392	const auto		colorAttView	= makeImageView(vkd, device, colorAtt.get(), VK_IMAGE_VIEW_TYPE_2D, colorFormat, colorSRR);
393
394	// Render pass and framebuffer.
395	const auto renderPass	= makeRenderPass(vkd, device, colorFormat);
396	const auto framebuffer	= makeFramebuffer(vkd, device, renderPass.get(), colorAttView.get(), colorExtent.width, colorExtent.height);
397
398	// Verification buffer.
399	const auto			verifBufferSize			= static_cast<VkDeviceSize>(tcu::getPixelSize(tcuFormat) * iExtent3D.x() * iExtent3D.y() * iExtent3D.z());
400	const auto			verifBufferCreateInfo	= makeBufferCreateInfo(verifBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
401	BufferWithMemory	verifBuffer				(vkd, device, alloc, verifBufferCreateInfo, MemoryRequirement::HostVisible);
402	auto&				verifBufferAlloc		= verifBuffer.getAllocation();
403	void*				verifBufferData			= verifBufferAlloc.getHostPtr();
404
405	// Create the condition buffer.
406	m_conditionBuffer.reset(new ConditionBuffer(vkd, device, alloc, m_params.condValue, m_params.bindWithOffset, m_params.condWithOffset));
407
408	// Create the indirect buffers if needed.
409	initIndirectBuffers(vkd, device, alloc);
410
411	// Pipeline.
412	const auto	pipelineLayout	= makePipelineLayout(vkd, device);
413	const auto&	binaries		= m_context.getBinaryCollection();
414	const auto	taskModule		= (binaries.contains("task") ? createShaderModule(vkd, device, binaries.get("task")) : Move<VkShaderModule>());
415	const auto	meshModule		= createShaderModule(vkd, device, binaries.get("mesh"));
416	const auto	fragModule		= createShaderModule(vkd, device, binaries.get("frag"));
417
418	const std::vector<VkViewport>	viewports	(1u, makeViewport(colorExtent));
419	const std::vector<VkRect2D>		scissors	(1u, makeRect2D(colorExtent));
420
421	const auto pipeline = makeGraphicsPipeline(
422		vkd, device, pipelineLayout.get(),
423		taskModule.get(), meshModule.get(), fragModule.get(),
424		renderPass.get(), viewports, scissors);
425
426	// Command pool and command buffers.
427	const auto cmdPool				= makeCommandPool(vkd, device, queueIndex);
428	const auto primaryCmdBuffer		= allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
429	const auto secondaryCmdBuffer	= (needsSecCmd ? allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_SECONDARY) : Move<VkCommandBuffer>());
430	const auto primary				= primaryCmdBuffer.get();
431	const auto secondary			= secondaryCmdBuffer.get();
432
433	// Common conditional rendering begin info.
434	const auto									conditionalRenderingFlags	=	(m_params.inverted
435																				? VK_CONDITIONAL_RENDERING_INVERTED_BIT_EXT
436																				: static_cast<VkConditionalRenderingFlagBitsEXT>(0));
437	const VkConditionalRenderingBeginInfoEXT	conditionalRenderingBegin	=
438	{
439		VK_STRUCTURE_TYPE_CONDITIONAL_RENDERING_BEGIN_INFO_EXT,					//	VkStructureType					sType;
440		nullptr,																//	const void*						pNext;
441		m_conditionBuffer->getBuffer(),											//	VkBuffer						buffer;
442		m_conditionBuffer->getCondOffset(),										//	VkDeviceSize					offset;
443		conditionalRenderingFlags,												//	VkConditionalRenderingFlagsEXT	flags;
444	};
445
446	// Inheritance info for the secondary command buffer.
447	const auto														conditionalRenderingEnable			= ((m_params.cmdBufferType == CmdBufferType::SECONDARY_WITH_INHERITANCE)
448																										? VK_TRUE
449																										: VK_FALSE);
450	const vk::VkCommandBufferInheritanceConditionalRenderingInfoEXT conditionalRenderingInheritanceInfo	=
451	{
452		VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_CONDITIONAL_RENDERING_INFO_EXT,	//	VkStructureType	sType;
453		nullptr,																		//	const void*		pNext;
454		conditionalRenderingEnable,														//	VkBool32		conditionalRenderingEnable;
455	};
456
457	const VkCommandBufferInheritanceInfo inheritanceInfo =
458	{
459		VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO,	//	VkStructureType					sType;
460		&conditionalRenderingInheritanceInfo,				//	const void*						pNext;
461		renderPass.get(),									//	VkRenderPass					renderPass;
462		0u,													//	uint32_t						subpass;
463		framebuffer.get(),									//	VkFramebuffer					framebuffer;
464		VK_FALSE,											//	VkBool32						occlusionQueryEnable;
465		0u,													//	VkQueryControlFlags				queryFlags;
466		0u,													//	VkQueryPipelineStatisticFlags	pipelineStatistics;
467	};
468
469	const VkCommandBufferUsageFlags	cmdBufferUsageFlags	= (VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT | VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT);
470	const VkCommandBufferBeginInfo	secondaryBeginInfo	=
471	{
472		VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,	//	VkStructureType							sType;
473		nullptr,										//	const void*								pNext;
474		cmdBufferUsageFlags,							//	VkCommandBufferUsageFlags				flags;
475		&inheritanceInfo,								//	const VkCommandBufferInheritanceInfo*	pInheritanceInfo;
476	};
477
478	beginCommandBuffer(vkd, primary);
479
480	if (m_params.cmdBufferType == CmdBufferType::PRIMARY)
481	{
482		// Do everything in the primary command buffer.
483		const auto cmdBuffer = primary;
484
485		vkd.cmdBeginConditionalRenderingEXT(cmdBuffer, &conditionalRenderingBegin);
486		beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffer.get(), scissors.at(0u), clearColor);
487		vkd.cmdBindPipeline(cmdBuffer, bindPoint, pipeline.get());
488		drawMeshTasks(vkd, cmdBuffer);
489		endRenderPass(vkd, cmdBuffer);
490		vkd.cmdEndConditionalRenderingEXT(cmdBuffer);
491	}
492	else if (m_params.cmdBufferType == CmdBufferType::SECONDARY)
493	{
494		// Do everything in the secondary command buffer.
495		// In addition, do the conditional rendering inside the render pass so it's a bit different from the primary case.
496		beginRenderPass(vkd, primary, renderPass.get(), framebuffer.get(), scissors.at(0u), clearColor, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
497
498		const auto cmdBuffer = secondaryCmdBuffer.get();
499
500		vkd.beginCommandBuffer(secondary, &secondaryBeginInfo);
501		vkd.cmdBindPipeline(cmdBuffer, bindPoint, pipeline.get());
502		vkd.cmdBeginConditionalRenderingEXT(cmdBuffer, &conditionalRenderingBegin);
503		drawMeshTasks(vkd, cmdBuffer);
504		vkd.cmdEndConditionalRenderingEXT(cmdBuffer);
505		endCommandBuffer(vkd, cmdBuffer);
506
507		vkd.cmdExecuteCommands(primary, 1u, &cmdBuffer);
508		endRenderPass(vkd, primary);
509	}
510	else if (m_params.cmdBufferType == CmdBufferType::SECONDARY_WITH_INHERITANCE)
511	{
512		// Inherit everything in the secondary command buffer.
513		vkd.beginCommandBuffer(secondary, &secondaryBeginInfo);
514		vkd.cmdBindPipeline(secondary, bindPoint, pipeline.get());
515		drawMeshTasks(vkd, secondary);
516		endCommandBuffer(vkd, secondary);
517
518		vkd.cmdBeginConditionalRenderingEXT(primary, &conditionalRenderingBegin);
519		beginRenderPass(vkd, primary, renderPass.get(), framebuffer.get(), scissors.at(0u), clearColor, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
520		vkd.cmdExecuteCommands(primary, 1u, &secondary);
521		endRenderPass(vkd, primary);
522		vkd.cmdEndConditionalRenderingEXT(primary);
523	}
524	else
525		DE_ASSERT(false);
526
527	// Transfer color attachment to the verification buffer.
528	const auto postTransferBarrier	= makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
529	const auto copyRegion			= makeBufferImageCopy(colorExtent, colorSRL);
530	const auto preTranferBarrier	= makeImageMemoryBarrier(
531		VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
532		VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
533		colorAtt.get(), colorSRR);
534
535	cmdPipelineImageMemoryBarrier(vkd, primary, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, &preTranferBarrier);
536	vkd.cmdCopyImageToBuffer(primary, colorAtt.get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, verifBuffer.get(), 1u, &copyRegion);
537	cmdPipelineMemoryBarrier(vkd, primary, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, &postTransferBarrier);
538
539	endCommandBuffer(vkd, primary);
540	submitCommandsAndWait(vkd, device, queue, primary);
541
542	invalidateAlloc(vkd, device, verifBufferAlloc);
543
544	const tcu::ConstPixelBufferAccess	resultAccess	(tcuFormat, iExtent3D, verifBufferData);
545	const bool							expectDraw		= ((m_params.condValue != 0u) != m_params.inverted);
546	const auto							expectedColor	= (expectDraw ? drawColor : clearColor);
547	const tcu::Vec4						threshold		(0.0f, 0.0f, 0.0f, 0.0f);
548
549	auto& log = m_context.getTestContext().getLog();
550	if (!tcu::floatThresholdCompare(log, "Result", "", expectedColor, resultAccess, threshold, tcu::COMPARE_LOG_ON_ERROR))
551		TCU_FAIL("Check log for details");
552
553	return tcu::TestStatus::pass("Pass");
554}
555
556} // anonymous
557
558tcu::TestCaseGroup* createMeshShaderConditionalRenderingTestsEXT (tcu::TestContext& testCtx)
559{
560	GroupPtr mainGroup (new tcu::TestCaseGroup(testCtx, "conditional_rendering"));
561
562	const struct
563	{
564		DrawType		drawType;
565		const char*		name;
566	} drawTypeCases[] =
567	{
568		{	DrawType::DRAW,						"draw"					},
569		{	DrawType::DRAW_INDIRECT,			"draw_indirect"			},
570		{	DrawType::DRAW_INDIRECT_WITH_COUNT,	"draw_indirect_count"	},
571	};
572
573	const struct
574	{
575		CmdBufferType	cmdBufferType;
576		const char*		name;
577	} cmdBufferTypeCases[] =
578	{
579		{	CmdBufferType::PRIMARY,						"primary_cmd_buffer"				},
580		{	CmdBufferType::SECONDARY,					"secondary_cmd_buffer"				},
581		{	CmdBufferType::SECONDARY_WITH_INHERITANCE,	"secondary_cmd_buffer_inheritance"	},
582	};
583
584	const struct
585	{
586		bool		bindWithOffset;
587		const char*	name;
588	} bindWithOffsetCases[] =
589	{
590		{ false,	"bind_without_offset"	},
591		{ true,		"bind_with_offset"		},
592	};
593
594	const struct
595	{
596		bool		condWithOffset;
597		const char*	name;
598	} condWithOffsetCases[] =
599	{
600		{ false,	"cond_without_offset"	},
601		{ true,		"cond_with_offset"		},
602	};
603
604	const struct
605	{
606		bool		inverted;
607		const char*	name;
608	} inversionCases[] =
609	{
610		{ false,	"normal_cond"	},
611		{ true,		"inverted_cond"	},
612	};
613
614	const struct
615	{
616		bool		useTask;
617		const char*	name;
618	} useTaskCases[] =
619	{
620		{ false,	"mesh_only"		},
621		{ true,		"mesh_and_task"	},
622	};
623
624	const auto condValues = getCondValues();
625
626	for (const auto& drawTypeCase : drawTypeCases)
627	{
628		GroupPtr drawTypeGroup (new tcu::TestCaseGroup(testCtx, drawTypeCase.name));
629
630		for (const auto& cmdBufferTypeCase : cmdBufferTypeCases)
631		{
632			GroupPtr cmdBufferTypeGroup (new tcu::TestCaseGroup(testCtx, cmdBufferTypeCase.name));
633
634			for (const auto& bindWithOffsetCase : bindWithOffsetCases)
635			{
636				GroupPtr bindWithOffsetGroup (new tcu::TestCaseGroup(testCtx, bindWithOffsetCase.name));
637
638				for (const auto& condWithOffsetCase : condWithOffsetCases)
639				{
640					GroupPtr condWithOffsetGroup (new tcu::TestCaseGroup(testCtx, condWithOffsetCase.name));
641
642					for (const auto& inversionCase : inversionCases)
643					{
644						GroupPtr inversionGroup (new tcu::TestCaseGroup(testCtx, inversionCase.name));
645
646						for (const auto& useTaskCase : useTaskCases)
647						{
648							GroupPtr useTaskGroup (new tcu::TestCaseGroup(testCtx, useTaskCase.name));
649
650							for (const auto& condValue : condValues)
651							{
652								const auto			testName	= "value_" + paddedHex(condValue);
653								const TestParams	params		=
654								{
655									drawTypeCase.drawType,				//	DrawType		drawType;
656									cmdBufferTypeCase.cmdBufferType,	//	CmdBufferType	cmdBufferType;
657									bindWithOffsetCase.bindWithOffset,	//	bool			bindWithOffset;
658									condWithOffsetCase.condWithOffset,	//	bool			condWithOffset;
659									condValue,							//	uint32_t		condValue;
660									inversionCase.inverted,				//	bool			inverted;
661									useTaskCase.useTask,				//	bool			useTask;
662								};
663								useTaskGroup->addChild(new ConditionalRenderingCase(testCtx, testName, params));
664							}
665
666							inversionGroup->addChild(useTaskGroup.release());
667						}
668
669						condWithOffsetGroup->addChild(inversionGroup.release());
670					}
671
672					bindWithOffsetGroup->addChild(condWithOffsetGroup.release());
673				}
674
675				cmdBufferTypeGroup->addChild(bindWithOffsetGroup.release());
676			}
677
678			drawTypeGroup->addChild(cmdBufferTypeGroup.release());
679		}
680
681		mainGroup->addChild(drawTypeGroup.release());
682	}
683
684	return mainGroup.release();
685}
686
687} // MeshShader
688} // vkt
689