• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
46 namespace vkt
47 {
48 namespace MeshShader
49 {
50 
51 namespace
52 {
53 
54 using namespace vk;
55 
56 using GroupPtr = de::MovePtr<tcu::TestCaseGroup>;
57 
58 enum class DrawType
59 {
60 	DRAW,
61 	DRAW_INDIRECT,
62 	DRAW_INDIRECT_WITH_COUNT,
63 };
64 
65 enum class CmdBufferType
66 {
67 	PRIMARY,
68 	SECONDARY,
69 	SECONDARY_WITH_INHERITANCE,
70 };
71 
72 static constexpr VkDeviceSize kBindOffset = 16u;
73 
getCondValues(void)74 std::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 
paddedHex(uint32_t value)88 std::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 
getOutputColor(void)95 tcu::Vec4 getOutputColor (void)
96 {
97 	return tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f);
98 }
99 
getClearColor(void)100 tcu::Vec4 getClearColor (void)
101 {
102 	return tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f);
103 }
104 
105 struct 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 
needsSecondaryCmdBuffervkt::MeshShader::__anoncd499dcc0111::TestParams115 	bool needsSecondaryCmdBuffer (void) const
116 	{
117 		return (cmdBufferType != CmdBufferType::PRIMARY);
118 	}
119 };
120 
121 class ConditionalRenderingCase : public vkt::TestCase
122 {
123 public:
ConditionalRenderingCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,const TestParams & params)124 					ConditionalRenderingCase	(tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestParams& params)
125 						: vkt::TestCase	(testCtx, name, description)
126 						, m_params		(params)
127 						{}
~ConditionalRenderingCase(void)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 
134 protected:
135 	const TestParams m_params;
136 };
137 
138 class ConditionBuffer
139 {
140 public:
ConditionBuffer(const DeviceInterface & vkd,VkDevice device,Allocator & alloc,uint32_t condValue,bool bindWithOffset,bool condWithOffset)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 
getCondOffset(void) const175 	VkDeviceSize getCondOffset (void) const
176 	{
177 		return m_condOffset;
178 	}
179 
getBuffer(void) const180 	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 
189 protected:
190 	Move<VkBuffer>			m_buffer;
191 	de::MovePtr<Allocation>	m_allocation;
192 	VkDeviceSize			m_condOffset;
193 };
194 
195 class ConditionalRenderingInstance : public vkt::TestInstance
196 {
197 public:
ConditionalRenderingInstance(Context & context,const TestParams & params)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 								{}
~ConditionalRenderingInstance(void)205 	virtual					~ConditionalRenderingInstance	(void) {}
206 
207 	tcu::TestStatus			iterate							(void) override;
208 
209 protected:
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.
223 template<class T>
makeIndirectBuffer(const DeviceInterface & vkd,const VkDevice device,Allocator & alloc,const T & data)224 std::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 
initIndirectBuffers(const DeviceInterface & vkd,const VkDevice device,Allocator & alloc)240 void 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 
drawMeshTasks(const DeviceInterface & vkd,const VkCommandBuffer cmdBuffer) const255 void 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 
initPrograms(vk::SourceCollections & programCollection) const275 void 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 
createInstance(Context & context) const330 TestInstance* ConditionalRenderingCase::createInstance (Context& context) const
331 {
332 	return new ConditionalRenderingInstance(context, m_params);
333 }
334 
checkSupport(Context & context) const335 void 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 
iterate()352 tcu::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 
createMeshShaderConditionalRenderingTestsEXT(tcu::TestContext & testCtx)558 tcu::TestCaseGroup* createMeshShaderConditionalRenderingTestsEXT (tcu::TestContext& testCtx)
559 {
560 	GroupPtr mainGroup (new tcu::TestCaseGroup(testCtx, "conditional_rendering", "Mesh Shader with 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