• 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 vkCmdDraw* functions
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktConditionalDrawTests.hpp"
26 #include "vktConditionalRenderingTestUtil.hpp"
27 
28 #include "vktTestCaseUtil.hpp"
29 #include "vktDrawTestCaseUtil.hpp"
30 
31 #include "vktDrawBaseClass.hpp"
32 
33 #include "vkTypeUtil.hpp"
34 
35 #include "tcuTestLog.hpp"
36 #include "tcuResource.hpp"
37 #include "tcuImageCompare.hpp"
38 #include "tcuTextureUtil.hpp"
39 #include "tcuRGBA.hpp"
40 
41 #include "vkDefs.hpp"
42 #include "vkCmdUtil.hpp"
43 
44 namespace vkt
45 {
46 namespace conditional
47 {
48 namespace
49 {
50 
51 enum DrawCommandType
52 {
53 	DRAW_COMMAND_TYPE_DRAW = 0,
54 	DRAW_COMMAND_TYPE_DRAW_INDEXED,
55 	DRAW_COMMAND_TYPE_DRAW_INDIRECT,
56 	DRAW_COMMAND_TYPE_DRAW_INDEXED_INDIRECT,
57 	DRAW_COMMAND_TYPE_DRAW_INDIRECT_COUNT,
58 	DRAW_COMMAND_TYPE_DRAW_INDEXED_INDIRECT_COUNT,
59 
60 	DRAW_COMMAND_TYPE_DRAW_LAST
61 };
62 
getDrawCommandTypeName(DrawCommandType command)63 const char* getDrawCommandTypeName (DrawCommandType command)
64 {
65 	switch (command)
66 	{
67 		case DRAW_COMMAND_TYPE_DRAW:					    return "draw";
68 		case DRAW_COMMAND_TYPE_DRAW_INDEXED:			    return "draw_indexed";
69 		case DRAW_COMMAND_TYPE_DRAW_INDIRECT:			    return "draw_indirect";
70 		case DRAW_COMMAND_TYPE_DRAW_INDEXED_INDIRECT:	    return "draw_indexed_indirect";
71 		case DRAW_COMMAND_TYPE_DRAW_INDIRECT_COUNT:			return "draw_indirect_count";
72 		case DRAW_COMMAND_TYPE_DRAW_INDEXED_INDIRECT_COUNT:	return "draw_indexed_indirect_count";
73 		default:					                        DE_ASSERT(false);
74 	}
75 	return "";
76 }
77 
78 struct ConditionalTestSpec : public Draw::TestSpecBase
79 {
80 	DrawCommandType		command;
81 	deUint32			drawCalls;
82 	ConditionalData		conditionalData;
83 };
84 
85 class ConditionalDraw : public Draw::DrawTestsBaseClass
86 {
87 public:
88 	typedef		ConditionalTestSpec	TestSpec;
89 
90 								ConditionalDraw				(Context &context, ConditionalTestSpec testSpec);
91 
92 	virtual		tcu::TestStatus iterate						(void);
93 				void			createAndBindIndexBuffer	(vk::VkCommandBuffer cmdBuffer);
94 				void			createIndirectBuffer		(void);
95 				void			createIndexedIndirectBuffer	(void);
96 				void			createIndirectCountBuffer	(void);
97 				void			recordDraw					(vk::VkCommandBuffer cmdBuffer);
98 
99 protected:
100 				void			createRenderPassWithClear	(void);
101 
102 	const DrawCommandType		    m_command;
103 	const deUint32					m_drawCalls;
104 
105 	const ConditionalData			m_conditionalData;
106 	de::SharedPtr<Draw::Buffer>		m_conditionalBuffer;
107 
108 	vk::Move<vk::VkCommandBuffer>	m_secondaryCmdBuffer;
109 
110 	std::vector<deUint32>		    m_indexes;
111 	de::SharedPtr<Draw::Buffer>		m_indexBuffer;
112 
113 	de::SharedPtr<Draw::Buffer>		m_indirectBuffer;
114 	de::SharedPtr<Draw::Buffer>		m_indirectCountBuffer;
115 
116 	// For cases where we want to clear the attachment in the render pass begin operation.
117 	vk::Move<vk::VkRenderPass>		m_rpWithClear;
118 	vk::Move<vk::VkFramebuffer>		m_fbWithClear;
119 };
120 
checkSupport(Context & context,DrawCommandType command)121 void checkSupport(Context& context, DrawCommandType command)
122 {
123 	if (command == DRAW_COMMAND_TYPE_DRAW_INDIRECT_COUNT || command == DRAW_COMMAND_TYPE_DRAW_INDEXED_INDIRECT_COUNT)
124 		context.requireDeviceFunctionality("VK_KHR_draw_indirect_count");
125 }
126 
ConditionalDraw(Context & context,ConditionalTestSpec testSpec)127 ConditionalDraw::ConditionalDraw (Context &context, ConditionalTestSpec testSpec)
128 	: Draw::DrawTestsBaseClass(context,
129 							   testSpec.shaders[glu::SHADERTYPE_VERTEX],
130 							   testSpec.shaders[glu::SHADERTYPE_FRAGMENT],
131 							   Draw::SharedGroupParams(new Draw::GroupParams{ false, false, false }),
132 							   vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST)
133 	, m_command(testSpec.command)
134 	, m_drawCalls(testSpec.drawCalls)
135 	, m_conditionalData(testSpec.conditionalData)
136 {
137 	checkConditionalRenderingCapabilities(context, m_conditionalData);
138 	checkSupport(context, m_command);
139 
140 	const float minX = -0.3f;
141 	const float maxX = 0.3f;
142 	const float drawStep = 0.6f / static_cast<float>(m_drawCalls);
143 
144 	for (deUint32 drawIdx = 0; drawIdx < m_drawCalls; drawIdx++)
145 	{
146 		const float minY = minX + static_cast<float>(drawIdx) * drawStep;
147 		const float maxY = minY + drawStep;
148 
149 		m_data.push_back(Draw::VertexElementData(tcu::Vec4(	minX,	maxY,	0.5f,	1.0f), tcu::RGBA::blue().toVec(), 0));
150 		m_data.push_back(Draw::VertexElementData(tcu::Vec4(	minX,	minY,	0.5f,	1.0f), tcu::RGBA::blue().toVec(), 0));
151 		m_data.push_back(Draw::VertexElementData(tcu::Vec4(	maxX,	maxY,	0.5f,	1.0f), tcu::RGBA::blue().toVec(), 0));
152 
153 		m_data.push_back(Draw::VertexElementData(tcu::Vec4(	minX,	minY,	0.5f,	1.0f), tcu::RGBA::blue().toVec(), 0));
154 		m_data.push_back(Draw::VertexElementData(tcu::Vec4(	maxX,	maxY,	0.5f,	1.0f), tcu::RGBA::blue().toVec(), 0));
155 		m_data.push_back(Draw::VertexElementData(tcu::Vec4(	maxX,	minY,	0.5f,	1.0f), tcu::RGBA::blue().toVec(), 0));
156 	}
157 
158 	m_data.push_back(Draw::VertexElementData(tcu::Vec4(	-1.0f,	1.0f,	0.0f,	1.0f), tcu::RGBA::red().toVec(), 0));
159 	m_data.push_back(Draw::VertexElementData(tcu::Vec4(	-1.0f,	-1.0f,	0.0f,	1.0f), tcu::RGBA::red().toVec(), 0));
160 	m_data.push_back(Draw::VertexElementData(tcu::Vec4(	1.0f,	1.0f,	0.0f,	1.0f), tcu::RGBA::red().toVec(), 0));
161 
162 	m_data.push_back(Draw::VertexElementData(tcu::Vec4(	-1.0f,	-1.0f,	0.0f,	1.0f), tcu::RGBA::red().toVec(), 0));
163 	m_data.push_back(Draw::VertexElementData(tcu::Vec4(	1.0f,	1.0f,	0.0f,	1.0f), tcu::RGBA::red().toVec(), 0));
164 	m_data.push_back(Draw::VertexElementData(tcu::Vec4(	1.0f,	-1.0f,	0.0f,	1.0f), tcu::RGBA::red().toVec(), 0));
165 
166 	for (deUint32 index = 0; index < m_data.size(); index++)
167 	{
168 		m_indexes.push_back(index);
169 	}
170 
171 	initialize();
172 
173 	DE_ASSERT(!(m_conditionalData.clearInRenderPass && m_conditionalData.conditionInSecondaryCommandBuffer));
174 
175 	if (m_conditionalData.clearInRenderPass)
176 		createRenderPassWithClear();
177 
178 	m_secondaryCmdBuffer = vk::allocateCommandBuffer(m_vk, m_context.getDevice(), *m_cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_SECONDARY);
179 }
180 
createRenderPassWithClear(void)181 void ConditionalDraw::createRenderPassWithClear (void)
182 {
183 	const auto					device					= m_context.getDevice();
184 	Draw::RenderPassCreateInfo	renderPassCreateInfo;
185 
186 	renderPassCreateInfo.addAttachment(Draw::AttachmentDescription(m_colorAttachmentFormat,
187 																   vk::VK_SAMPLE_COUNT_1_BIT,
188 																   vk::VK_ATTACHMENT_LOAD_OP_CLEAR,	// Clear with the render pass.
189 																   vk::VK_ATTACHMENT_STORE_OP_STORE,
190 																   vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE,
191 																   vk::VK_ATTACHMENT_STORE_OP_STORE,
192 																   vk::VK_IMAGE_LAYOUT_UNDEFINED,
193 																   vk::VK_IMAGE_LAYOUT_GENERAL));
194 
195 	const vk::VkAttachmentReference colorAttachmentReference
196 	{
197 		0,
198 		vk::VK_IMAGE_LAYOUT_GENERAL
199 	};
200 
201 	renderPassCreateInfo.addSubpass(Draw::SubpassDescription(vk::VK_PIPELINE_BIND_POINT_GRAPHICS,
202 															 0,
203 															 0,
204 															 DE_NULL,
205 															 1,
206 															 &colorAttachmentReference,
207 															 DE_NULL,
208 															 Draw::AttachmentReference(),
209 															 0,
210 															 DE_NULL));
211 
212 	m_rpWithClear = vk::createRenderPass(m_vk, device, &renderPassCreateInfo);
213 
214 	// Framebuffer.
215 	std::vector<vk::VkImageView>			colorAttachments		{ *m_colorTargetView };
216 	const Draw::FramebufferCreateInfo		framebufferCreateInfo	(*m_rpWithClear, colorAttachments, WIDTH, HEIGHT, 1);
217 
218 	m_fbWithClear = vk::createFramebuffer(m_vk, device, &framebufferCreateInfo);
219 }
220 
createAndBindIndexBuffer(vk::VkCommandBuffer cmdBuffer)221 void ConditionalDraw::createAndBindIndexBuffer (vk::VkCommandBuffer cmdBuffer)
222 {
223 	const vk::VkDeviceSize indexDataSize = m_indexes.size() * sizeof(deUint32);
224 	m_indexBuffer = Draw::Buffer::createAndAlloc(m_vk, m_context.getDevice(),
225 											Draw::BufferCreateInfo(indexDataSize,
226 															vk::VK_BUFFER_USAGE_INDEX_BUFFER_BIT),
227 											m_context.getDefaultAllocator(),
228 											vk::MemoryRequirement::HostVisible);
229 
230 	deUint8* indexBufferPtr = reinterpret_cast<deUint8*>(m_indexBuffer->getBoundMemory().getHostPtr());
231 	deMemcpy(indexBufferPtr, &m_indexes[0], static_cast<size_t>(indexDataSize));
232 
233 	vk::flushAlloc(m_vk, m_context.getDevice(), m_indexBuffer->getBoundMemory());
234 
235 	const vk::VkBuffer indexBuffer = m_indexBuffer->object();
236 	m_vk.cmdBindIndexBuffer(cmdBuffer, indexBuffer, 0, vk::VK_INDEX_TYPE_UINT32);
237 }
238 
createIndirectBuffer(void)239 void ConditionalDraw::createIndirectBuffer (void)
240 {
241 	const vk::VkDrawIndirectCommand badDrawCommand =
242 	{
243 		6u,					// vertexCount
244 		1u,					// instanceCount
245 		m_drawCalls * 6u,	// firstVertex
246 		0u					// firstInstance
247 	};
248 
249 	std::vector<vk::VkDrawIndirectCommand> drawCommands;
250 	for (deUint32 drawIdx = 0; drawIdx < m_drawCalls; drawIdx++)
251 	{
252 		const vk::VkDrawIndirectCommand goodDrawCommand =
253 		{
254 			6u,				// vertexCount
255 			1u,				// instanceCount
256 			6u * drawIdx,	// firstVertex
257 			0u				// firstInstance
258 		};
259 
260 		drawCommands.push_back(goodDrawCommand);
261 		// *Bad* commands should not be rendered by vkCmdDrawIndirectCountKHR
262 		drawCommands.push_back(badDrawCommand);
263 		drawCommands.push_back(badDrawCommand);
264 	}
265 
266 	const vk::VkDeviceSize drawCommandsSize = drawCommands.size() * sizeof(vk::VkDrawIndirectCommand);
267 
268 	m_indirectBuffer = Draw::Buffer::createAndAlloc(m_vk,
269 													m_context.getDevice(),
270 													Draw::BufferCreateInfo(drawCommandsSize,
271 																	vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT),
272 													m_context.getDefaultAllocator(),
273 													vk::MemoryRequirement::HostVisible);
274 
275 	deUint8* ptr = reinterpret_cast<deUint8*>(m_indirectBuffer->getBoundMemory().getHostPtr());
276 	deMemcpy(ptr, &drawCommands[0], static_cast<size_t>(drawCommandsSize));
277 
278 	vk::flushAlloc(m_vk, m_context.getDevice(), m_indirectBuffer->getBoundMemory());
279 }
280 
createIndexedIndirectBuffer(void)281 void ConditionalDraw::createIndexedIndirectBuffer (void)
282 {
283 	const vk::VkDrawIndexedIndirectCommand badDrawCommand =
284 	{
285 		6u,					// indexCount
286 		1u,					// instanceCount
287 		m_drawCalls * 6u,	// firstIndex
288 		0u,					// vertexOffset
289 		0u,					// firstInstance
290 	};
291 
292 	std::vector<vk::VkDrawIndexedIndirectCommand> drawCommands;
293 	for (deUint32 drawIdx = 0; drawIdx < m_drawCalls; drawIdx++)
294 	{
295 		const vk::VkDrawIndexedIndirectCommand goodDrawCommand =
296 		{
297 			6u,				// indexCount
298 			1u,				// instanceCount
299 			6u * drawIdx,	// firstIndex
300 			0u,				// vertexOffset
301 			0u,				// firstInstance
302 		};
303 
304 		drawCommands.push_back(goodDrawCommand);
305 		// *Bad* commands should not be rendered by vkCmdDrawIndexedIndirectCountKHR
306 		drawCommands.push_back(badDrawCommand);
307 		drawCommands.push_back(badDrawCommand);
308 	}
309 
310 	const vk::VkDeviceSize drawCommandsSize = drawCommands.size() * sizeof(vk::VkDrawIndexedIndirectCommand);
311 
312 	m_indirectBuffer = Draw::Buffer::createAndAlloc(m_vk,
313 													m_context.getDevice(),
314 													Draw::BufferCreateInfo(drawCommandsSize,
315 																	vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT),
316 													m_context.getDefaultAllocator(),
317 													vk::MemoryRequirement::HostVisible);
318 
319 	deUint8* ptr = reinterpret_cast<deUint8*>(m_indirectBuffer->getBoundMemory().getHostPtr());
320 	deMemcpy(ptr, &drawCommands[0], static_cast<size_t>(drawCommandsSize));
321 
322 	vk::flushAlloc(m_vk, m_context.getDevice(), m_indirectBuffer->getBoundMemory());
323 }
324 
createIndirectCountBuffer(void)325 void ConditionalDraw::createIndirectCountBuffer (void)
326 {
327 	m_indirectCountBuffer = Draw::Buffer::createAndAlloc(m_vk,
328 														m_context.getDevice(),
329 														Draw::BufferCreateInfo(sizeof(deUint32),
330 																			vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT),
331 														m_context.getDefaultAllocator(),
332 														vk::MemoryRequirement::HostVisible);
333 
334 	deUint8* countBufferPtr = reinterpret_cast<deUint8*>(m_indirectCountBuffer->getBoundMemory().getHostPtr());
335 	*(deUint32*)(countBufferPtr) = 1;
336 
337 	vk::flushAlloc(m_vk, m_context.getDevice(), m_indirectCountBuffer->getBoundMemory());
338 }
339 
recordDraw(vk::VkCommandBuffer cmdBuffer)340 void ConditionalDraw::recordDraw(vk::VkCommandBuffer cmdBuffer)
341 {
342 	for (deUint32 drawIdx = 0; drawIdx < m_drawCalls; drawIdx++)
343 	{
344 		/* Indirect buffer has next layout:
345 		 * goodCommand badCommand badCommand goodCommand badCommand badCommand ...
346 		 */
347 		const vk::VkDeviceSize indirectOffset = sizeof(vk::VkDrawIndirectCommand) * drawIdx * 3;
348 		const vk::VkDeviceSize indexedIndirectOffset = sizeof(vk::VkDrawIndexedIndirectCommand) * drawIdx * 3;
349 		switch (m_command)
350 		{
351 			case DRAW_COMMAND_TYPE_DRAW:
352 			{
353 				m_vk.cmdDraw(cmdBuffer, 6, 1, 6 * drawIdx, 0);
354 				break;
355 			}
356 			case DRAW_COMMAND_TYPE_DRAW_INDEXED:
357 			{
358 				m_vk.cmdDrawIndexed(cmdBuffer, 6, 1, 6 * drawIdx, 0, 0);
359 				break;
360 			}
361 			case DRAW_COMMAND_TYPE_DRAW_INDIRECT:
362 			{
363 				m_vk.cmdDrawIndirect(cmdBuffer, m_indirectBuffer->object(), indirectOffset, 1, 0);
364 				break;
365 			}
366 			case DRAW_COMMAND_TYPE_DRAW_INDEXED_INDIRECT:
367 			{
368 				m_vk.cmdDrawIndexedIndirect(cmdBuffer, m_indirectBuffer->object(), indexedIndirectOffset, 1, 0);
369 				break;
370 			}
371 			case DRAW_COMMAND_TYPE_DRAW_INDIRECT_COUNT:
372 			{
373 				m_vk.cmdDrawIndirectCount(	cmdBuffer,
374 											m_indirectBuffer->object(), indirectOffset,
375 											m_indirectCountBuffer->object(), 0, 3,
376 											sizeof(vk::VkDrawIndirectCommand));
377 				break;
378 			}
379 			case DRAW_COMMAND_TYPE_DRAW_INDEXED_INDIRECT_COUNT:
380 			{
381 				m_vk.cmdDrawIndexedIndirectCount(cmdBuffer,
382 												 m_indirectBuffer->object(), indexedIndirectOffset,
383 												 m_indirectCountBuffer->object(), 0, 3,
384 												 sizeof(vk::VkDrawIndexedIndirectCommand));
385 				break;
386 			}
387 			default: DE_ASSERT(false);
388 		}
389 	}
390 }
391 
iterate(void)392 tcu::TestStatus ConditionalDraw::iterate (void)
393 {
394 	tcu::TestLog&		log			= m_context.getTestContext().getLog();
395 	const vk::VkQueue	queue		= m_context.getUniversalQueue();
396 	const vk::VkDevice	device		= m_context.getDevice();
397 
398 	// We will clear to a different color to be sure.
399 	const auto			clearColor	= (m_conditionalData.clearInRenderPass ? tcu::RGBA::white().toVec() : tcu::RGBA::black().toVec());
400 
401 	m_conditionalBuffer = createConditionalRenderingBuffer(m_context, m_conditionalData);
402 
403 	beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
404 	preRenderBarriers();
405 
406 	const bool useSecondaryCmdBuffer	= m_conditionalData.conditionInherited || m_conditionalData.conditionInSecondaryCommandBuffer;
407 	const auto subpassContents			= (useSecondaryCmdBuffer ? vk::VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS : vk::VK_SUBPASS_CONTENTS_INLINE);
408 
409 	if (m_conditionalData.clearInRenderPass)
410 	{
411 		// When clearing in the render pass we want to check the render pass clear is executed properly.
412 		beginConditionalRendering(m_vk, *m_cmdBuffer, *m_conditionalBuffer, m_conditionalData);
413 		vk::beginRenderPass(m_vk, *m_cmdBuffer, *m_rpWithClear, *m_fbWithClear, vk::makeRect2D(WIDTH, HEIGHT), clearColor, subpassContents);
414 	}
415 	else
416 	{
417 		beginLegacyRender(*m_cmdBuffer, subpassContents);
418 	}
419 
420 	vk::VkCommandBuffer targetCmdBuffer = *m_cmdBuffer;
421 
422 	if (useSecondaryCmdBuffer)
423 	{
424 		const vk::VkCommandBufferInheritanceConditionalRenderingInfoEXT conditionalRenderingInheritanceInfo =
425 		{
426 			vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_CONDITIONAL_RENDERING_INFO_EXT,
427 			DE_NULL,
428 			m_conditionalData.conditionInherited ? VK_TRUE : VK_FALSE	// conditionalRenderingEnable
429 		};
430 
431 		const vk::VkCommandBufferInheritanceInfo inheritanceInfo =
432 		{
433 			vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO,
434 			&conditionalRenderingInheritanceInfo,
435 			*m_renderPass,										        // renderPass
436 			0u,															// subpass
437 			*m_framebuffer,										        // framebuffer
438 			VK_FALSE,													// occlusionQueryEnable
439 			(vk::VkQueryControlFlags)0u,								// queryFlags
440 			(vk::VkQueryPipelineStatisticFlags)0u,						// pipelineStatistics
441 		};
442 
443 		const vk::VkCommandBufferBeginInfo commandBufferBeginInfo =
444 		{
445 			vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
446 			DE_NULL,
447 			vk::VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT,
448 			&inheritanceInfo
449 		};
450 
451 		VK_CHECK(m_vk.beginCommandBuffer(*m_secondaryCmdBuffer, &commandBufferBeginInfo));
452 
453 		targetCmdBuffer = *m_secondaryCmdBuffer;
454 	}
455 
456 	const vk::VkDeviceSize vertexBufferOffset = 0;
457 	const vk::VkBuffer vertexBuffer = m_vertexBuffer->object();
458 
459 	m_vk.cmdBindVertexBuffers(targetCmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
460 
461 	switch(m_command)
462 	{
463 		case DRAW_COMMAND_TYPE_DRAW:
464 		{
465 			break;
466 		}
467 		case DRAW_COMMAND_TYPE_DRAW_INDEXED:
468 		{
469 			createAndBindIndexBuffer(targetCmdBuffer);
470 			break;
471 		}
472 		case DRAW_COMMAND_TYPE_DRAW_INDIRECT:
473 		{
474 			createIndirectBuffer();
475 			break;
476 		}
477 		case DRAW_COMMAND_TYPE_DRAW_INDEXED_INDIRECT:
478 		{
479 			createAndBindIndexBuffer(targetCmdBuffer);
480 			createIndexedIndirectBuffer();
481 			break;
482 		}
483 		case DRAW_COMMAND_TYPE_DRAW_INDIRECT_COUNT:
484 		{
485 			createIndirectBuffer();
486 			createIndirectCountBuffer();
487 			break;
488 		}
489 		case DRAW_COMMAND_TYPE_DRAW_INDEXED_INDIRECT_COUNT:
490 		{
491 			createAndBindIndexBuffer(targetCmdBuffer);
492 			createIndexedIndirectBuffer();
493 			createIndirectCountBuffer();
494 			break;
495 		}
496 		default: DE_ASSERT(false);
497 	}
498 
499 	m_vk.cmdBindPipeline(targetCmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
500 
501 	if (m_conditionalData.conditionInSecondaryCommandBuffer)
502 	{
503 		beginConditionalRendering(m_vk, *m_secondaryCmdBuffer, *m_conditionalBuffer, m_conditionalData);
504 		recordDraw(*m_secondaryCmdBuffer);
505 		m_vk.cmdEndConditionalRenderingEXT(*m_secondaryCmdBuffer);
506 		m_vk.endCommandBuffer(*m_secondaryCmdBuffer);
507 	}
508 	else if (m_conditionalData.conditionInherited)
509 	{
510 		recordDraw(*m_secondaryCmdBuffer);
511 		m_vk.endCommandBuffer(*m_secondaryCmdBuffer);
512 	}
513 
514 	if (m_conditionalData.conditionInPrimaryCommandBuffer)
515 	{
516 		if (!m_conditionalData.clearInRenderPass)
517 			beginConditionalRendering(m_vk, *m_cmdBuffer, *m_conditionalBuffer, m_conditionalData);
518 
519 		if (m_conditionalData.conditionInherited)
520 		{
521 			m_vk.cmdExecuteCommands(*m_cmdBuffer, 1, &m_secondaryCmdBuffer.get());
522 		}
523 		else
524 		{
525 			recordDraw(*m_cmdBuffer);
526 		}
527 
528 		if (!m_conditionalData.clearInRenderPass)
529 			m_vk.cmdEndConditionalRenderingEXT(*m_cmdBuffer);
530 	}
531 	else if (useSecondaryCmdBuffer)
532 	{
533 		m_vk.cmdExecuteCommands(*m_cmdBuffer, 1, &m_secondaryCmdBuffer.get());
534 	}
535 
536 	if (m_conditionalData.clearInRenderPass)
537 	{
538 		// Finish conditional rendering outside the render pass.
539 		vk::endRenderPass(m_vk, *m_cmdBuffer);
540 		m_vk.cmdEndConditionalRenderingEXT(*m_cmdBuffer);
541 	}
542 	else
543 	{
544 		endLegacyRender(*m_cmdBuffer);
545 	}
546 
547 	endCommandBuffer(m_vk, *m_cmdBuffer);
548 
549 	submitCommandsAndWait(m_vk, device, queue, m_cmdBuffer.get());
550 
551 	// Validation
552 	tcu::Texture2D referenceFrame(vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5f + static_cast<float>(WIDTH)), (int)(0.5f + static_cast<float>(HEIGHT)));
553 								  referenceFrame.allocLevel(0);
554 
555 	const deInt32 frameWidth	= referenceFrame.getWidth();
556 	const deInt32 frameHeight	= referenceFrame.getHeight();
557 
558 	tcu::clear(referenceFrame.getLevel(0), clearColor);
559 
560 	const tcu::Vec4 drawColor		= tcu::RGBA::blue().toVec();
561 	const tcu::Vec4 referenceColor	= m_conditionalData.expectCommandExecution ? drawColor : clearColor;
562 
563 	Draw::ReferenceImageCoordinates refCoords;
564 
565 	for (int y = 0; y < frameHeight; y++)
566 	{
567 		const float yCoord = (float)(y / (0.5*frameHeight)) - 1.0f;
568 
569 		for (int x = 0; x < frameWidth; x++)
570 		{
571 			const float xCoord = (float)(x / (0.5*frameWidth)) - 1.0f;
572 
573 			if ((yCoord >= refCoords.bottom &&
574 				 yCoord <= refCoords.top	&&
575 				 xCoord >= refCoords.left	&&
576 				 xCoord <= refCoords.right))
577 				referenceFrame.getLevel(0).setPixel(referenceColor, x, y);
578 		}
579 	}
580 
581 	const vk::VkOffset3D zeroOffset = { 0, 0, 0 };
582 	const tcu::ConstPixelBufferAccess renderedFrame = m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(),
583 		vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
584 
585 	qpTestResult res = QP_TEST_RESULT_PASS;
586 
587 	if (!tcu::fuzzyCompare(log, "Result", "Image comparison result",
588 		referenceFrame.getLevel(0), renderedFrame, 0.05f,
589 		tcu::COMPARE_LOG_RESULT))
590 	{
591 		res = QP_TEST_RESULT_FAIL;
592 	}
593 
594 	return tcu::TestStatus(res, qpGetTestResultName(res));
595 }
596 
597 }	// anonymous
598 
ConditionalDrawTests(tcu::TestContext & testCtx)599 ConditionalDrawTests::ConditionalDrawTests (tcu::TestContext &testCtx)
600 	: TestCaseGroup	(testCtx, "draw", "Conditional Rendering Of Draw Commands")
601 {
602 	/* Left blank on purpose */
603 }
604 
~ConditionalDrawTests(void)605 ConditionalDrawTests::~ConditionalDrawTests (void) {}
606 
init(void)607 void ConditionalDrawTests::init (void)
608 {
609 	for (int conditionNdx = 0; conditionNdx < DE_LENGTH_OF_ARRAY(conditional::s_testsData); conditionNdx++)
610 	{
611 		const ConditionalData& conditionData = conditional::s_testsData[conditionNdx];
612 
613 		tcu::TestCaseGroup* conditionalDrawRootGroup = new tcu::TestCaseGroup(m_testCtx, de::toString(conditionData).c_str(), "Conditionaly execute draw calls");
614 
615 		for (deUint32 commandTypeIdx = 0; commandTypeIdx < DRAW_COMMAND_TYPE_DRAW_LAST; ++commandTypeIdx)
616 		{
617 			const DrawCommandType	command	= DrawCommandType(commandTypeIdx);
618 
619 			ConditionalTestSpec testSpec;
620 			testSpec.command = command;
621 			testSpec.drawCalls = 4;
622 			testSpec.conditionalData = conditionData;
623 			testSpec.shaders[glu::SHADERTYPE_VERTEX] = "vulkan/dynamic_state/VertexFetch.vert";
624 			testSpec.shaders[glu::SHADERTYPE_FRAGMENT] = "vulkan/dynamic_state/VertexFetch.frag";
625 
626 			conditionalDrawRootGroup->addChild(new Draw::InstanceFactory<ConditionalDraw>(m_testCtx, getDrawCommandTypeName(command), "", testSpec));
627 		}
628 
629 		addChild(conditionalDrawRootGroup);
630 	}
631 }
632 
633 }	// conditional
634 }	// vkt
635