• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2015 The Khronos Group Inc.
6  * Copyright (c) 2015 Intel 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 Draw Indirect Test
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktDrawIndirectTest.hpp"
26 
27 #include "vktTestCaseUtil.hpp"
28 #include "vktDrawTestCaseUtil.hpp"
29 
30 #include "vktDrawBaseClass.hpp"
31 
32 #include "tcuTestLog.hpp"
33 #include "tcuResource.hpp"
34 #include "tcuImageCompare.hpp"
35 #include "tcuTextureUtil.hpp"
36 #include "tcuRGBA.hpp"
37 #include "vkQueryUtil.hpp"
38 
39 #include "vkDefs.hpp"
40 #include "vkCmdUtil.hpp"
41 
42 namespace vkt
43 {
44 namespace Draw
45 {
46 namespace
47 {
48 
49 enum
50 {
51 	VERTEX_OFFSET = 13
52 };
53 
54 struct JunkData
55 {
JunkDatavkt::Draw::__anonba46f01a0111::JunkData56 	JunkData()
57 		: varA	(0xcd)
58 		, varB	(0xcd)
59 	{
60 	}
61 	const deUint16	varA;
62 	const deUint32	varB;
63 };
64 
65 enum DrawType
66 {
67 	DRAW_TYPE_SEQUENTIAL,
68 	DRAW_TYPE_INDEXED,
69 
70 	DRAWTYPE_LAST
71 };
72 
73 struct DrawTypedTestSpec : public TestSpecBase
74 {
DrawTypedTestSpecvkt::Draw::__anonba46f01a0111::DrawTypedTestSpec75 	DrawTypedTestSpec()
76 		: testFirstInstanceNdx(false)
77 		, testIndirectCountExt(false)
78 	{};
79 
80 	DrawType	drawType;
81 	bool		testFirstInstanceNdx;
82 	bool		testIndirectCountExt;
83 };
84 
85 class IndirectDraw : public DrawTestsBaseClass
86 {
87 public:
88 	typedef DrawTypedTestSpec	TestSpec;
89 
90 								IndirectDraw	(Context &context, TestSpec testSpec);
91 	virtual	tcu::TestStatus		iterate			(void);
92 
93 	template<typename T> void	addCommand		(const T&);
94 
95 protected:
96 	void						setVertexBuffer						(void);
97 	void						setFirstInstanceVertexBuffer		(void);
98 
99 	std::vector<char>			m_indirectBufferContents;
100 	de::SharedPtr<Buffer>		m_indirectBuffer;
101 	vk::VkDeviceSize			m_offsetInBuffer;
102 	deUint32					m_strideInBuffer;
103 
104 	const bool					m_testIndirectCountExt;
105 	de::SharedPtr<Buffer>		m_indirectCountBuffer;
106 	vk::VkDeviceSize			m_offsetInCountBuffer;
107 	const deUint32				m_indirectCountExtDrawPadding;
108 
109 	deUint32					m_drawCount;
110 	JunkData					m_junkData;
111 
112 	const DrawType				m_drawType;
113 	const bool					m_testFirstInstanceNdx;
114 	deBool						m_isMultiDrawEnabled;
115 	deUint32					m_drawIndirectMaxCount;
116 
117 	de::SharedPtr<Buffer>		m_indexBuffer;
118 };
119 
120 struct FirstInstanceSupported
121 {
getFirstInstancevkt::Draw::__anonba46f01a0111::FirstInstanceSupported122 	static deUint32 getFirstInstance	(void)											{ return 2; }
isTestSupportedvkt::Draw::__anonba46f01a0111::FirstInstanceSupported123 	static bool		isTestSupported		(const vk::VkPhysicalDeviceFeatures& features)	{ return features.drawIndirectFirstInstance == VK_TRUE; }
124 };
125 
126 struct FirstInstanceNotSupported
127 {
getFirstInstancevkt::Draw::__anonba46f01a0111::FirstInstanceNotSupported128 	static deUint32 getFirstInstance	(void)											{ return 0; }
isTestSupportedvkt::Draw::__anonba46f01a0111::FirstInstanceNotSupported129 	static bool		isTestSupported		(const vk::VkPhysicalDeviceFeatures&)			{ return true; }
130 };
131 
132 template<class FirstInstanceSupport>
133 class IndirectDrawInstanced : public IndirectDraw
134 {
135 public:
136 								IndirectDrawInstanced	(Context &context, TestSpec testSpec);
137 	virtual tcu::TestStatus		iterate					(void);
138 };
139 
setVertexBuffer(void)140 void IndirectDraw::setVertexBuffer (void)
141 {
142 	int refVertexIndex = 2;
143 
144 	if (m_drawType == DRAW_TYPE_INDEXED)
145 	{
146 		for (int unusedIdx = 0; unusedIdx < VERTEX_OFFSET; unusedIdx++)
147 		{
148 			m_data.push_back(VertexElementData(tcu::Vec4(-1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), -1));
149 		}
150 		refVertexIndex += VERTEX_OFFSET;
151 	}
152 
153 	m_data.push_back(VertexElementData(tcu::Vec4( 1.0f, -1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), -1));
154 	m_data.push_back(VertexElementData(tcu::Vec4(-1.0f,  1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), -1));
155 
156 	switch (m_topology)
157 	{
158 		case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
159 			m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,	-0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++));
160 			m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,	 0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++));
161 			m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,	-0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++));
162 			m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,	-0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++));
163 			m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,	 0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++));
164 			m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,	 0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++));
165 			break;
166 		case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
167 			m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,	 0.0f, 1.0f, 1.0f),	 tcu::RGBA::blue().toVec(), refVertexIndex++));
168 			m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,	 0.0f, 1.0f, 1.0f),	 tcu::RGBA::blue().toVec(), refVertexIndex++));
169 			m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,	-0.3f, 1.0f, 1.0f),	 tcu::RGBA::blue().toVec(), refVertexIndex++));
170 			m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,	-0.3f, 1.0f, 1.0f),	 tcu::RGBA::blue().toVec(), refVertexIndex++));
171 			m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,	 0.3f, 1.0f, 1.0f),	 tcu::RGBA::blue().toVec(), refVertexIndex++));
172 			m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,	 0.3f, 1.0f, 1.0f),	 tcu::RGBA::blue().toVec(), refVertexIndex++));
173 			m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,	 0.0f, 1.0f, 1.0f),	 tcu::RGBA::blue().toVec(), refVertexIndex++));
174 			m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,	 0.0f, 1.0f, 1.0f),	 tcu::RGBA::blue().toVec(), refVertexIndex++));
175 			break;
176 		default:
177 			DE_FATAL("Unknown topology");
178 			break;
179 	}
180 
181 	m_data.push_back(VertexElementData(tcu::Vec4(-1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), -1));
182 }
183 
setFirstInstanceVertexBuffer(void)184 void IndirectDraw::setFirstInstanceVertexBuffer (void)
185 {
186 	if (m_context.getDeviceFeatures().drawIndirectFirstInstance != VK_TRUE)
187 	{
188 		TCU_THROW(NotSupportedError, "Required 'drawIndirectFirstInstance' feature is not supported");
189 	}
190 
191 	if (m_drawType == DRAW_TYPE_INDEXED)
192 	{
193 		for (int unusedIdx = 0; unusedIdx < VERTEX_OFFSET; unusedIdx++)
194 		{
195 			m_data.push_back(VertexElementData(tcu::Vec4(-1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), -1));
196 		}
197 	}
198 
199 	m_data.push_back(VertexElementData(tcu::Vec4( 1.0f, -1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), -1));
200 	m_data.push_back(VertexElementData(tcu::Vec4(-1.0f,  1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), -1));
201 
202 	switch (m_topology)
203 	{
204 		case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
205 		{
206 			int refInstanceIndex = 1;
207 			m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,	-0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refInstanceIndex));
208 			m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,	 0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refInstanceIndex));
209 			m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,	-0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refInstanceIndex));
210 
211 			refInstanceIndex = 0;
212 			m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,	-0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refInstanceIndex));
213 			m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,	 0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refInstanceIndex));
214 			m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,	 0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refInstanceIndex));
215 			break;
216 		}
217 		case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
218 		{
219 			int refInstanceIndex = 1;
220 			m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,	 0.0f, 1.0f, 1.0f),	 tcu::RGBA::blue().toVec(), refInstanceIndex));
221 			m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,	 0.0f, 1.0f, 1.0f),	 tcu::RGBA::blue().toVec(), refInstanceIndex));
222 			m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,	-0.3f, 1.0f, 1.0f),	 tcu::RGBA::blue().toVec(), refInstanceIndex));
223 			m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,	-0.3f, 1.0f, 1.0f),	 tcu::RGBA::blue().toVec(), refInstanceIndex));
224 
225 			refInstanceIndex = 0;
226 			m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,	 0.3f, 1.0f, 1.0f),	 tcu::RGBA::blue().toVec(), refInstanceIndex));
227 			m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,	 0.3f, 1.0f, 1.0f),	 tcu::RGBA::blue().toVec(), refInstanceIndex));
228 			m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,	 0.0f, 1.0f, 1.0f),	 tcu::RGBA::blue().toVec(), refInstanceIndex));
229 			m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,	 0.0f, 1.0f, 1.0f),	 tcu::RGBA::blue().toVec(), refInstanceIndex));
230 			break;
231 		}
232 		default:
233 			DE_FATAL("Unknown topology");
234 			break;
235 	}
236 
237 	m_data.push_back(VertexElementData(tcu::Vec4(-1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), -1));
238 }
239 
IndirectDraw(Context & context,TestSpec testSpec)240 IndirectDraw::IndirectDraw (Context &context, TestSpec testSpec)
241 	: DrawTestsBaseClass				(context, testSpec.shaders[glu::SHADERTYPE_VERTEX], testSpec.shaders[glu::SHADERTYPE_FRAGMENT], testSpec.topology)
242 	, m_testIndirectCountExt			(testSpec.testIndirectCountExt)
243 	, m_indirectCountExtDrawPadding		(1u)
244 	, m_drawType						(testSpec.drawType)
245 	, m_testFirstInstanceNdx			(testSpec.testFirstInstanceNdx)
246 {
247 	if (m_testIndirectCountExt && !vk::isDeviceExtensionSupported(m_context.getUsedApiVersion(), m_context.getDeviceExtensions(), "VK_KHR_draw_indirect_count"))
248 		TCU_THROW(NotSupportedError, "Missing extension: VK_KHR_draw_indirect_count");
249 
250 	if (m_testFirstInstanceNdx)
251 		setFirstInstanceVertexBuffer();
252 	else
253 		setVertexBuffer();
254 
255 	initialize();
256 
257 	if (testSpec.drawType == DRAW_TYPE_INDEXED)
258 	{
259 		const size_t indexBufferLength = m_data.size() - VERTEX_OFFSET;
260 
261 		m_indexBuffer = Buffer::createAndAlloc(m_vk, m_context.getDevice(), BufferCreateInfo(sizeof(deUint32) * indexBufferLength, vk::VK_BUFFER_USAGE_INDEX_BUFFER_BIT), m_context.getDefaultAllocator(), vk::MemoryRequirement::HostVisible);
262 		deUint32* indices = reinterpret_cast<deUint32*>(m_indexBuffer->getBoundMemory().getHostPtr());
263 		for (size_t i = 0; i < indexBufferLength; i++)
264 		{
265 			indices[i] = static_cast<deUint32>(i);
266 		}
267 		vk::flushAlloc(m_vk, m_context.getDevice(), m_indexBuffer->getBoundMemory());
268 	}
269 
270 	// Check device for multidraw support:
271 	if (!m_context.getDeviceFeatures().multiDrawIndirect || m_testFirstInstanceNdx)
272 		m_isMultiDrawEnabled = false;
273 	else
274 		m_isMultiDrawEnabled = true;
275 
276 	m_drawIndirectMaxCount = m_context.getDeviceProperties().limits.maxDrawIndirectCount;
277 }
278 
279 template<>
addCommand(const vk::VkDrawIndirectCommand & command)280 void IndirectDraw::addCommand<vk::VkDrawIndirectCommand> (const vk::VkDrawIndirectCommand& command)
281 {
282 	DE_ASSERT(m_drawType == DRAW_TYPE_SEQUENTIAL);
283 
284 	const size_t currentSize = m_indirectBufferContents.size();
285 
286 	m_indirectBufferContents.resize(currentSize + sizeof(command));
287 
288 	deMemcpy(&m_indirectBufferContents[currentSize], &command, sizeof(command));
289 }
290 
291 template<>
addCommand(const vk::VkDrawIndexedIndirectCommand & command)292 void IndirectDraw::addCommand<vk::VkDrawIndexedIndirectCommand> (const vk::VkDrawIndexedIndirectCommand& command)
293 {
294 	DE_ASSERT(m_drawType == DRAW_TYPE_INDEXED);
295 
296 	const size_t currentSize = m_indirectBufferContents.size();
297 
298 	m_indirectBufferContents.resize(currentSize + sizeof(command));
299 
300 	deMemcpy(&m_indirectBufferContents[currentSize], &command, sizeof(command));
301 }
302 
iterate(void)303 tcu::TestStatus IndirectDraw::iterate (void)
304 {
305 	tcu::TestLog&		log		= m_context.getTestContext().getLog();
306 	const vk::VkQueue	queue	= m_context.getUniversalQueue();
307 	const vk::VkDevice	device	= m_context.getDevice();
308 
309 	if (m_drawType == DRAW_TYPE_SEQUENTIAL)
310 	{
311 		switch (m_topology)
312 		{
313 		case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
314 		{
315 			vk::VkDrawIndirectCommand drawCommands[] =
316 			{
317 				{
318 					3u,									//vertexCount
319 					1u,									//instanceCount
320 					2u,									//firstVertex
321 					(m_testFirstInstanceNdx ? 1u : 0u)	//firstInstance
322 				},
323 				{ (deUint32)-4, (deUint32)-2, (deUint32)-11, (deUint32)-9 }, // junk (stride)
324 				{
325 					3u,									//vertexCount
326 					1u,									//instanceCount
327 					5u,									//firstVertex
328 					0u									//firstInstance
329 				}
330 			};
331 			addCommand(drawCommands[0]);
332 			addCommand(drawCommands[1]);
333 			addCommand(drawCommands[2]);
334 			if (m_testIndirectCountExt)
335 			{
336 				addCommand(drawCommands[1]);
337 				addCommand(drawCommands[1]);
338 			}
339 			break;
340 		}
341 		case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
342 		{
343 			vk::VkDrawIndirectCommand drawCommands[] =
344 			{
345 				{
346 					4u,									//vertexCount
347 					1u,									//instanceCount
348 					2u,									//firstVertex
349 					(m_testFirstInstanceNdx ? 1u : 0u)	//firstInstance
350 				},
351 				{ (deUint32)-4, (deUint32)-2, (deUint32)-11, (deUint32)-9 }, // junk (stride)
352 				{
353 					4u,									//vertexCount
354 					1u,									//instanceCount
355 					6u,									//firstVertex
356 					0u									//firstInstance
357 				}
358 			};
359 			addCommand(drawCommands[0]);
360 			addCommand(drawCommands[1]);
361 			addCommand(drawCommands[2]);
362 			if (m_testIndirectCountExt)
363 			{
364 				addCommand(drawCommands[1]);
365 				addCommand(drawCommands[1]);
366 			}
367 			break;
368 		}
369 		default:
370 			TCU_FAIL("impossible");
371 		}
372 
373 		m_strideInBuffer = 2 * (deUint32)sizeof(vk::VkDrawIndirectCommand);
374 	}
375 	else if (m_drawType == DRAW_TYPE_INDEXED)
376 	{
377 		switch (m_topology)
378 		{
379 		case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
380 		{
381 			vk::VkDrawIndexedIndirectCommand drawCommands[] =
382 			{
383 				{
384 					3u,									// indexCount
385 					1u,									// instanceCount
386 					2u,									// firstIndex
387 					VERTEX_OFFSET,						// vertexOffset
388 					(m_testFirstInstanceNdx ? 1u : 0u),	// firstInstance
389 				},
390 				{ (deUint32)-4, (deUint32)-2, (deUint32)-11, (deInt32)9, (deUint32)-7 }, // junk (stride)
391 				{
392 					3u,									// indexCount
393 					1u,									// instanceCount
394 					5u,									// firstIndex
395 					VERTEX_OFFSET,						// vertexOffset
396 					0u									// firstInstance
397 				}
398 			};
399 			addCommand(drawCommands[0]);
400 			addCommand(drawCommands[1]);
401 			addCommand(drawCommands[2]);
402 			if (m_testIndirectCountExt)
403 			{
404 				addCommand(drawCommands[1]);
405 				addCommand(drawCommands[1]);
406 			}
407 			break;
408 		}
409 		case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
410 		{
411 			vk::VkDrawIndexedIndirectCommand drawCommands[] =
412 			{
413 				{
414 					4u,									// indexCount
415 					1u,									// instanceCount
416 					2u,									// firstIndex
417 					VERTEX_OFFSET,						// vertexOffset
418 					(m_testFirstInstanceNdx ? 1u : 0u),	// firstInstance
419 				},
420 				{ (deUint32)-4, (deUint32)-2, (deUint32)-11, (deInt32)9, (deUint32)-7 }, // junk (stride)
421 				{
422 					4u,									// indexCount
423 					1u,									// instanceCount
424 					6u,									// firstIndex
425 					VERTEX_OFFSET,						// vertexOffset
426 					0u									// firstInstance
427 				}
428 			};
429 			addCommand(drawCommands[0]);
430 			addCommand(drawCommands[1]);
431 			addCommand(drawCommands[2]);
432 			if (m_testIndirectCountExt)
433 			{
434 				addCommand(drawCommands[1]);
435 				addCommand(drawCommands[1]);
436 			}
437 			break;
438 		}
439 		default:
440 			TCU_FAIL("impossible");
441 		}
442 
443 		m_strideInBuffer = 2 * (deUint32)sizeof(vk::VkDrawIndexedIndirectCommand);
444 	}
445 
446 	m_drawCount			= 2;
447 	m_offsetInBuffer	= sizeof(m_junkData);
448 
449 	beginRenderPass();
450 
451 	const vk::VkDeviceSize vertexBufferOffset	= 0;
452 	const vk::VkBuffer vertexBuffer				= m_vertexBuffer->object();
453 
454 	m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
455 
456 	const vk::VkDeviceSize dataSize = m_indirectBufferContents.size();
457 
458 	m_indirectBuffer = Buffer::createAndAlloc(	m_vk,
459 												m_context.getDevice(),
460 												BufferCreateInfo(dataSize + m_offsetInBuffer,
461 																 vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT),
462 												m_context.getDefaultAllocator(),
463 												vk::MemoryRequirement::HostVisible);
464 
465 	deUint8* ptr = reinterpret_cast<deUint8*>(m_indirectBuffer->getBoundMemory().getHostPtr());
466 
467 	deMemcpy(ptr, &m_junkData, static_cast<size_t>(m_offsetInBuffer));
468 	deMemcpy(ptr + m_offsetInBuffer, &m_indirectBufferContents[0], static_cast<size_t>(dataSize));
469 
470 	vk::flushAlloc(m_vk, m_context.getDevice(), m_indirectBuffer->getBoundMemory());
471 
472 	if (m_testIndirectCountExt)
473 	{
474 		m_offsetInCountBuffer = sizeof(tcu::Vec3);
475 		m_indirectCountBuffer = Buffer::createAndAlloc(m_vk,
476 													   m_context.getDevice(),
477 													   BufferCreateInfo(m_offsetInCountBuffer + sizeof(m_drawCount),
478 																		vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT),
479 													   m_context.getDefaultAllocator(),
480 													   vk::MemoryRequirement::HostVisible);
481 
482 		deUint8* countBufferPtr = reinterpret_cast<deUint8*>(m_indirectCountBuffer->getBoundMemory().getHostPtr());
483 
484 		if (m_isMultiDrawEnabled && m_drawCount <= m_drawIndirectMaxCount)
485 			*(deUint32*)(countBufferPtr + m_offsetInCountBuffer) = m_drawCount;
486 		else
487 			*(deUint32*)(countBufferPtr + m_offsetInCountBuffer) = 1u;
488 
489 		vk::flushAlloc(m_vk, m_context.getDevice(), m_indirectCountBuffer->getBoundMemory());
490 	}
491 
492 	m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
493 
494 	if (m_drawType == DRAW_TYPE_INDEXED)
495 	{
496 		m_vk.cmdBindIndexBuffer(*m_cmdBuffer, m_indexBuffer->object(), DE_NULL, vk::VK_INDEX_TYPE_UINT32);
497 	}
498 
499 	if (m_isMultiDrawEnabled && m_drawCount <= m_drawIndirectMaxCount)
500 	{
501 		switch (m_drawType)
502 		{
503 			case DRAW_TYPE_SEQUENTIAL:
504 			{
505 				if (m_testIndirectCountExt)
506 					m_vk.cmdDrawIndirectCountKHR(*m_cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer,
507 												 m_indirectCountBuffer->object(), m_offsetInCountBuffer, m_drawCount + m_indirectCountExtDrawPadding,
508 												 m_strideInBuffer);
509 				else
510 					m_vk.cmdDrawIndirect(*m_cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer, m_drawCount, m_strideInBuffer);
511 				break;
512 			}
513 			case DRAW_TYPE_INDEXED:
514 			{
515 				if (m_testIndirectCountExt)
516 					m_vk.cmdDrawIndexedIndirectCountKHR(*m_cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer,
517 														m_indirectCountBuffer->object(), m_offsetInCountBuffer, m_drawCount + m_indirectCountExtDrawPadding,
518 														m_strideInBuffer);
519 				else
520 					m_vk.cmdDrawIndexedIndirect(*m_cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer, m_drawCount, m_strideInBuffer);
521 				break;
522 			}
523 			default:
524 				TCU_FAIL("impossible");
525 		}
526 	}
527 	else
528 	{
529 		for (deUint32 drawNdx = 0; drawNdx < m_drawCount; drawNdx++)
530 		{
531 			switch (m_drawType)
532 			{
533 				case DRAW_TYPE_SEQUENTIAL:
534 				{
535 					if (m_testIndirectCountExt)
536 						m_vk.cmdDrawIndirectCountKHR(*m_cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer + drawNdx*m_strideInBuffer,
537 													 m_indirectCountBuffer->object(), m_offsetInCountBuffer, m_drawCount + m_indirectCountExtDrawPadding,
538 													 m_strideInBuffer);
539 					else
540 						m_vk.cmdDrawIndirect(*m_cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer + drawNdx*m_strideInBuffer, 1u, 0u);
541 					break;
542 				}
543 				case DRAW_TYPE_INDEXED:
544 				{
545 					if (m_testIndirectCountExt)
546 						m_vk.cmdDrawIndexedIndirectCountKHR(*m_cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer + drawNdx*m_strideInBuffer,
547 															m_indirectCountBuffer->object(), m_offsetInCountBuffer, m_drawCount + m_indirectCountExtDrawPadding,
548 															m_strideInBuffer);
549 					else
550 						m_vk.cmdDrawIndexedIndirect(*m_cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer + drawNdx*m_strideInBuffer, 1u, 0u);
551 					break;
552 				}
553 				default:
554 					TCU_FAIL("impossible");
555 			}
556 		}
557 	}
558 	endRenderPass(m_vk, *m_cmdBuffer);
559 	endCommandBuffer(m_vk, *m_cmdBuffer);
560 
561 	submitCommandsAndWait(m_vk, device, queue, m_cmdBuffer.get());
562 
563 	// Validation
564 	tcu::Texture2D referenceFrame(vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5 + WIDTH), (int)(0.5 + HEIGHT));
565 	referenceFrame.allocLevel(0);
566 
567 	const deInt32 frameWidth	= referenceFrame.getWidth();
568 	const deInt32 frameHeight	= referenceFrame.getHeight();
569 
570 	tcu::clear(referenceFrame.getLevel(0), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
571 
572 	ReferenceImageCoordinates refCoords;
573 
574 	for (int y = 0; y < frameHeight; y++)
575 	{
576 		const float yCoord = (float)(y / (0.5*frameHeight)) - 1.0f;
577 
578 		for (int x = 0; x < frameWidth; x++)
579 		{
580 			const float xCoord = (float)(x / (0.5*frameWidth)) - 1.0f;
581 
582 			if ((yCoord >= refCoords.bottom	&&
583 				 yCoord <= refCoords.top	&&
584 				 xCoord >= refCoords.left	&&
585 				 xCoord <= refCoords.right))
586 				referenceFrame.getLevel(0).setPixel(tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f), x, y);
587 		}
588 	}
589 
590 	const vk::VkOffset3D zeroOffset					= { 0, 0, 0 };
591 	const tcu::ConstPixelBufferAccess renderedFrame = m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(),
592 		vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
593 
594 	qpTestResult res = QP_TEST_RESULT_PASS;
595 
596 	if (!tcu::fuzzyCompare(log, "Result", "Image comparison result",
597 		referenceFrame.getLevel(0), renderedFrame, 0.05f, tcu::COMPARE_LOG_RESULT))
598 	{
599 		res = QP_TEST_RESULT_FAIL;
600 	}
601 
602 	return tcu::TestStatus(res, qpGetTestResultName(res));
603 }
604 
605 template<class FirstInstanceSupport>
IndirectDrawInstanced(Context & context,TestSpec testSpec)606 IndirectDrawInstanced<FirstInstanceSupport>::IndirectDrawInstanced (Context &context, TestSpec testSpec)
607 	: IndirectDraw(context, testSpec)
608 {
609 	if (!FirstInstanceSupport::isTestSupported(m_context.getDeviceFeatures()))
610 	{
611 		throw tcu::NotSupportedError("Required 'drawIndirectFirstInstance' feature is not supported");
612 	}
613 }
614 
615 template<class FirstInstanceSupport>
iterate(void)616 tcu::TestStatus IndirectDrawInstanced<FirstInstanceSupport>::iterate (void)
617 {
618 	tcu::TestLog&		log		= m_context.getTestContext().getLog();
619 	const vk::VkQueue	queue	= m_context.getUniversalQueue();
620 	const vk::VkDevice	device	= m_context.getDevice();
621 
622 	if (m_drawType == DRAW_TYPE_SEQUENTIAL)
623 	{
624 		switch (m_topology)
625 		{
626 			case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
627 			{
628 				vk::VkDrawIndirectCommand drawCmd[] =
629 				{
630 					{
631 						3,											//vertexCount
632 						4,											//instanceCount
633 						2,											//firstVertex
634 						FirstInstanceSupport::getFirstInstance()	//firstInstance
635 					},
636 					{ (deUint32)-4, (deUint32)-2, (deUint32)-11, (deUint32)-9 }, // junk (stride)
637 					{
638 						3,											//vertexCount
639 						4,											//instanceCount
640 						5,											//firstVertex
641 						FirstInstanceSupport::getFirstInstance()	//firstInstance
642 					}
643 				};
644 				addCommand(drawCmd[0]);
645 				addCommand(drawCmd[1]);
646 				addCommand(drawCmd[2]);
647 				if (m_testIndirectCountExt)
648 				{
649 					addCommand(drawCmd[1]);
650 					addCommand(drawCmd[1]);
651 				}
652 				break;
653 			}
654 			case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
655 			{
656 				vk::VkDrawIndirectCommand drawCmd[] =
657 				{
658 					{
659 						4,											//vertexCount
660 						4,											//instanceCount
661 						2,											//firstVertex
662 						FirstInstanceSupport::getFirstInstance()	//firstInstance
663 					},
664 					{ (deUint32)-4, (deUint32)-2, (deUint32)-11, (deUint32)-9 },
665 					{
666 						4,											//vertexCount
667 						4,											//instanceCount
668 						6,											//firstVertex
669 						FirstInstanceSupport::getFirstInstance()	//firstInstance
670 					}
671 				};
672 				addCommand(drawCmd[0]);
673 				addCommand(drawCmd[1]);
674 				addCommand(drawCmd[2]);
675 				if (m_testIndirectCountExt)
676 				{
677 					addCommand(drawCmd[1]);
678 					addCommand(drawCmd[1]);
679 				}
680 				break;
681 			}
682 			default:
683 				TCU_FAIL("impossible");
684 				break;
685 		}
686 
687 		m_strideInBuffer = 2 * (deUint32)sizeof(vk::VkDrawIndirectCommand);
688 	}
689 	else if (m_drawType == DRAW_TYPE_INDEXED)
690 	{
691 		switch (m_topology)
692 		{
693 			case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
694 			{
695 				vk::VkDrawIndexedIndirectCommand drawCmd[] =
696 				{
697 					{
698 						3,											// indexCount
699 						4,											// instanceCount
700 						2,											// firstIndex
701 						VERTEX_OFFSET,								// vertexOffset
702 						FirstInstanceSupport::getFirstInstance()	// firstInstance
703 					},
704 					{ (deUint32)-4, (deUint32)-2, (deUint32)-11, (deInt32)9, (deUint32)-7 },	// junk (stride)
705 					{
706 						3,											// indexCount
707 						4,											// instanceCount
708 						5,											// firstIndex
709 						VERTEX_OFFSET,								// vertexOffset
710 						FirstInstanceSupport::getFirstInstance()	// firstInstance
711 					}
712 				};
713 				addCommand(drawCmd[0]);
714 				addCommand(drawCmd[1]);
715 				addCommand(drawCmd[2]);
716 				if (m_testIndirectCountExt)
717 				{
718 					addCommand(drawCmd[1]);
719 					addCommand(drawCmd[1]);
720 				}
721 				break;
722 			}
723 			case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
724 			{
725 				vk::VkDrawIndexedIndirectCommand drawCmd[] =
726 				{
727 					{
728 						4,											// indexCount
729 						4,											// instanceCount
730 						2,											// firstIndex
731 						VERTEX_OFFSET,								// vertexOffset
732 						FirstInstanceSupport::getFirstInstance()	// firstInstance
733 					},
734 					{ (deUint32)-4, (deUint32)-2, (deUint32)-11, (deInt32)9, (deUint32)-7 },	// junk (stride)
735 					{
736 						4,											// indexCount
737 						4,											// instanceCount
738 						6,											// firstIndex
739 						VERTEX_OFFSET,								// vertexOffset
740 						FirstInstanceSupport::getFirstInstance()	// firstInstance
741 					}
742 				};
743 				addCommand(drawCmd[0]);
744 				addCommand(drawCmd[1]);
745 				addCommand(drawCmd[2]);
746 				if (m_testIndirectCountExt)
747 				{
748 					addCommand(drawCmd[1]);
749 					addCommand(drawCmd[1]);
750 				}
751 				break;
752 			}
753 			default:
754 				TCU_FAIL("impossible");
755 				break;
756 		}
757 
758 		m_strideInBuffer = 2 * (deUint32)sizeof(vk::VkDrawIndexedIndirectCommand);
759 	}
760 
761 	m_drawCount			= 2;
762 	m_offsetInBuffer	= sizeof(m_junkData);
763 
764 	beginRenderPass();
765 
766 	const vk::VkDeviceSize vertexBufferOffset = 0;
767 	const vk::VkBuffer vertexBuffer = m_vertexBuffer->object();
768 
769 	m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
770 
771 	const vk::VkDeviceSize dataSize = m_indirectBufferContents.size();
772 
773 	m_indirectBuffer = Buffer::createAndAlloc(	m_vk,
774 												m_context.getDevice(),
775 												BufferCreateInfo(dataSize + m_offsetInBuffer,
776 																 vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT),
777 												m_context.getDefaultAllocator(),
778 												vk::MemoryRequirement::HostVisible);
779 
780 	deUint8* ptr = reinterpret_cast<deUint8*>(m_indirectBuffer->getBoundMemory().getHostPtr());
781 
782 	deMemcpy(ptr, &m_junkData, static_cast<size_t>(m_offsetInBuffer));
783 	deMemcpy((ptr + m_offsetInBuffer), &m_indirectBufferContents[0], static_cast<size_t>(dataSize));
784 
785 	vk::flushAlloc(m_vk, m_context.getDevice(), m_indirectBuffer->getBoundMemory());
786 
787 	if (m_testIndirectCountExt)
788 	{
789 		m_offsetInCountBuffer = sizeof(tcu::Vec3);
790 		m_indirectCountBuffer = Buffer::createAndAlloc(m_vk,
791 													   m_context.getDevice(),
792 													   BufferCreateInfo(m_offsetInCountBuffer + sizeof(m_drawCount),
793 																		vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT),
794 													   m_context.getDefaultAllocator(),
795 													   vk::MemoryRequirement::HostVisible);
796 
797 		deUint8* countBufferPtr = reinterpret_cast<deUint8*>(m_indirectCountBuffer->getBoundMemory().getHostPtr());
798 
799 		if (m_isMultiDrawEnabled && m_drawCount <= m_drawIndirectMaxCount)
800 			*(deUint32*)(countBufferPtr + m_offsetInCountBuffer) = m_drawCount;
801 		else
802 			*(deUint32*)(countBufferPtr + m_offsetInCountBuffer) = 1u;
803 
804 		vk::flushAlloc(m_vk, m_context.getDevice(), m_indirectCountBuffer->getBoundMemory());
805 	}
806 
807 	m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
808 
809 	if (m_drawType == DRAW_TYPE_INDEXED)
810 	{
811 		m_vk.cmdBindIndexBuffer(*m_cmdBuffer, m_indexBuffer->object(), DE_NULL, vk::VK_INDEX_TYPE_UINT32);
812 	}
813 
814 	if (m_isMultiDrawEnabled && m_drawCount <= m_drawIndirectMaxCount)
815 	{
816 		switch (m_drawType)
817 		{
818 			case DRAW_TYPE_SEQUENTIAL:
819 			{
820 				if (m_testIndirectCountExt)
821 					m_vk.cmdDrawIndirectCountKHR(*m_cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer,
822 												 m_indirectCountBuffer->object(), m_offsetInCountBuffer,
823 												 m_drawCount + m_indirectCountExtDrawPadding, m_strideInBuffer);
824 				else
825 					m_vk.cmdDrawIndirect(*m_cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer, m_drawCount, m_strideInBuffer);
826 				break;
827 			}
828 			case DRAW_TYPE_INDEXED:
829 			{
830 				if (m_testIndirectCountExt)
831 					m_vk.cmdDrawIndexedIndirectCountKHR(*m_cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer,
832 														m_indirectCountBuffer->object(), m_offsetInCountBuffer,
833 														m_drawCount + m_indirectCountExtDrawPadding, m_strideInBuffer);
834 				else
835 					m_vk.cmdDrawIndexedIndirect(*m_cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer, m_drawCount, m_strideInBuffer);
836 				break;
837 			}
838 			default:
839 				TCU_FAIL("impossible");
840 		}
841 	}
842 	else
843 	{
844 		for (deUint32 drawNdx = 0; drawNdx < m_drawCount; drawNdx++)
845 		{
846 			switch (m_drawType)
847 			{
848 				case DRAW_TYPE_SEQUENTIAL:
849 				{
850 					if (m_testIndirectCountExt)
851 						m_vk.cmdDrawIndirectCountKHR(*m_cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer + drawNdx*m_strideInBuffer,
852 													 m_indirectCountBuffer->object(), m_offsetInCountBuffer, m_drawCount + m_indirectCountExtDrawPadding,
853 													 m_strideInBuffer);
854 					else
855 						m_vk.cmdDrawIndirect(*m_cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer + drawNdx*m_strideInBuffer, 1u, 0u);
856 					break;
857 				}
858 				case DRAW_TYPE_INDEXED:
859 				{
860 					if (m_testIndirectCountExt)
861 						m_vk.cmdDrawIndexedIndirectCountKHR(*m_cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer + drawNdx*m_strideInBuffer,
862 															m_indirectCountBuffer->object(), m_offsetInCountBuffer, m_drawCount + m_indirectCountExtDrawPadding,
863 															m_strideInBuffer);
864 					else
865 						m_vk.cmdDrawIndexedIndirect(*m_cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer + drawNdx*m_strideInBuffer, 1u, 0u);
866 					break;
867 				}
868 				default:
869 					TCU_FAIL("impossible");
870 			}
871 		}
872 	}
873 	endRenderPass(m_vk, *m_cmdBuffer);
874 	endCommandBuffer(m_vk, *m_cmdBuffer);
875 
876 	submitCommandsAndWait(m_vk, device, queue, m_cmdBuffer.get());
877 
878 	// Validation
879 	VK_CHECK(m_vk.queueWaitIdle(queue));
880 
881 	tcu::Texture2D referenceFrame(vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5 + WIDTH), (int)(0.5 + HEIGHT));
882 
883 	referenceFrame.allocLevel(0);
884 
885 	const deInt32 frameWidth	= referenceFrame.getWidth();
886 	const deInt32 frameHeight	= referenceFrame.getHeight();
887 
888 	tcu::clear(referenceFrame.getLevel(0), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
889 
890 	ReferenceImageInstancedCoordinates refInstancedCoords;
891 
892 	for (int y = 0; y < frameHeight; y++)
893 	{
894 		const float yCoord = (float)(y / (0.5*frameHeight)) - 1.0f;
895 
896 		for (int x = 0; x < frameWidth; x++)
897 		{
898 			const float xCoord = (float)(x / (0.5*frameWidth)) - 1.0f;
899 
900 			if ((yCoord >= refInstancedCoords.bottom	&&
901 				 yCoord <= refInstancedCoords.top		&&
902 				 xCoord >= refInstancedCoords.left		&&
903 				 xCoord <= refInstancedCoords.right))
904 				referenceFrame.getLevel(0).setPixel(tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f), x, y);
905 		}
906 	}
907 
908 	const vk::VkOffset3D zeroOffset = { 0, 0, 0 };
909 	const tcu::ConstPixelBufferAccess renderedFrame = m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(),
910 		vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
911 
912 	qpTestResult res = QP_TEST_RESULT_PASS;
913 
914 	if (!tcu::fuzzyCompare(log, "Result", "Image comparison result",
915 		referenceFrame.getLevel(0), renderedFrame, 0.05f, tcu::COMPARE_LOG_RESULT))
916 	{
917 		res = QP_TEST_RESULT_FAIL;
918 	}
919 
920 	return tcu::TestStatus(res, qpGetTestResultName(res));
921 }
922 
923 }	// anonymous
924 
IndirectDrawTests(tcu::TestContext & testCtx)925 IndirectDrawTests::IndirectDrawTests (tcu::TestContext& testCtx)
926 	: TestCaseGroup(testCtx, "indirect_draw", "indirect drawing simple geometry")
927 {
928 	/* Left blank on purpose */
929 }
930 
~IndirectDrawTests(void)931 IndirectDrawTests::~IndirectDrawTests (void) {}
932 
933 
init(void)934 void IndirectDrawTests::init (void)
935 {
936 	for (int drawTypeIdx = 0; drawTypeIdx < DRAWTYPE_LAST; drawTypeIdx++)
937 	{
938 		std::string drawTypeStr;
939 		switch (drawTypeIdx)
940 		{
941 			case DRAW_TYPE_SEQUENTIAL:
942 				drawTypeStr = "sequential";
943 				break;
944 			case DRAW_TYPE_INDEXED:
945 				drawTypeStr = "indexed";
946 				break;
947 			default:
948 				TCU_FAIL("impossible");
949 		}
950 
951 		tcu::TestCaseGroup* drawTypeGroup = new tcu::TestCaseGroup(m_testCtx, drawTypeStr.c_str(), ("Draws geometry using " + drawTypeStr + "draw call").c_str());
952 		{
953 			tcu::TestCaseGroup* indirectDrawGroup		= new tcu::TestCaseGroup(m_testCtx, "indirect_draw", "Draws geometry");
954 			tcu::TestCaseGroup* indirectDrawCountGroup	= new tcu::TestCaseGroup(m_testCtx, "indirect_draw_count", "Draws geometry with VK_KHR_draw_indirect_count extension");
955 			{
956 				IndirectDraw::TestSpec testSpec;
957 				testSpec.drawType = static_cast<DrawType>(drawTypeIdx);
958 				testSpec.shaders[glu::SHADERTYPE_VERTEX] = "vulkan/draw/VertexFetch.vert";
959 				testSpec.shaders[glu::SHADERTYPE_FRAGMENT] = "vulkan/draw/VertexFetch.frag";
960 				testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
961 				indirectDrawGroup->addChild(new InstanceFactory<IndirectDraw>(m_testCtx, "triangle_list", "Draws triangle list", testSpec));
962 				testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
963 				indirectDrawGroup->addChild(new InstanceFactory<IndirectDraw>(m_testCtx, "triangle_strip", "Draws triangle strip", testSpec));
964 
965 				testSpec.testIndirectCountExt = true;
966 				testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
967 				indirectDrawCountGroup->addChild(new InstanceFactory<IndirectDraw>(m_testCtx, "triangle_list", "Draws triangle list", testSpec));
968 				testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
969 				indirectDrawCountGroup->addChild(new InstanceFactory<IndirectDraw>(m_testCtx, "triangle_strip", "Draws triangle strip", testSpec));
970 			}
971 			drawTypeGroup->addChild(indirectDrawGroup);
972 			drawTypeGroup->addChild(indirectDrawCountGroup);
973 
974 			{
975 				tcu::TestCaseGroup* indirectDrawFirstInstanceGroup = new tcu::TestCaseGroup(m_testCtx, "indirect_draw_first_instance", "Draws geometry with different first instance in one commandbuffer");
976 				tcu::TestCaseGroup* indirectDrawCountFirstInstanceGroup = new tcu::TestCaseGroup(m_testCtx, "indirect_draw_count_first_instance", "Draws geometry with VK_KHR_draw_indirect_count extension with different first instance in one commandbuffer using ");
977 				{
978 					IndirectDraw::TestSpec testSpec;
979 					testSpec.testFirstInstanceNdx = true;
980 					testSpec.drawType = static_cast<DrawType>(drawTypeIdx);
981 					testSpec.shaders[glu::SHADERTYPE_VERTEX] = "vulkan/draw/VertexFetchInstanceIndex.vert";
982 					testSpec.shaders[glu::SHADERTYPE_FRAGMENT] = "vulkan/draw/VertexFetch.frag";
983 					testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
984 					indirectDrawFirstInstanceGroup->addChild(new InstanceFactory<IndirectDraw>(m_testCtx, "triangle_list", "Draws triangle list", testSpec));
985 					testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
986 					indirectDrawFirstInstanceGroup->addChild(new InstanceFactory<IndirectDraw>(m_testCtx, "triangle_strip", "Draws triangle strip", testSpec));
987 
988 					testSpec.testIndirectCountExt = true;
989 					testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
990 					indirectDrawCountFirstInstanceGroup->addChild(new InstanceFactory<IndirectDraw>(m_testCtx, "triangle_list", "Draws triangle list", testSpec));
991 					testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
992 					indirectDrawCountFirstInstanceGroup->addChild(new InstanceFactory<IndirectDraw>(m_testCtx, "triangle_strip", "Draws triangle strip", testSpec));
993 				}
994 				drawTypeGroup->addChild(indirectDrawFirstInstanceGroup);
995 				drawTypeGroup->addChild(indirectDrawCountFirstInstanceGroup);
996 			}
997 
998 			tcu::TestCaseGroup* indirectDrawInstancedGroup		= new tcu::TestCaseGroup(m_testCtx, "indirect_draw_instanced", "Draws an instanced geometry");
999 			tcu::TestCaseGroup* indirectDrawCountInstancedGroup	= new tcu::TestCaseGroup(m_testCtx, "indirect_draw_count_instanced", "Draws an instanced geometry with VK_KHR_draw_indirect_count extension");
1000 			{
1001 				tcu::TestCaseGroup*	indirectDrawNoFirstInstanceGroup		= new tcu::TestCaseGroup(m_testCtx, "no_first_instance", "Use 0 as firstInstance");
1002 				tcu::TestCaseGroup*	indirectDrawCountNoFirstInstanceGroup	= new tcu::TestCaseGroup(m_testCtx, "no_first_instance", "Use 0 as firstInstance");
1003 				{
1004 					IndirectDrawInstanced<FirstInstanceNotSupported>::TestSpec testSpec;
1005 					testSpec.drawType = static_cast<DrawType>(drawTypeIdx);
1006 
1007 					testSpec.shaders[glu::SHADERTYPE_VERTEX] = "vulkan/draw/VertexFetchInstanced.vert";
1008 					testSpec.shaders[glu::SHADERTYPE_FRAGMENT] = "vulkan/draw/VertexFetch.frag";
1009 
1010 					testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1011 					indirectDrawNoFirstInstanceGroup->addChild(new InstanceFactory<IndirectDrawInstanced<FirstInstanceNotSupported> >(m_testCtx, "triangle_list", "Draws an instanced triangle list", testSpec));
1012 					testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1013 					indirectDrawNoFirstInstanceGroup->addChild(new InstanceFactory<IndirectDrawInstanced<FirstInstanceNotSupported> >(m_testCtx, "triangle_strip", "Draws an instanced triangle strip", testSpec));
1014 
1015 					testSpec.testIndirectCountExt = true;
1016 					testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1017 					indirectDrawCountNoFirstInstanceGroup->addChild(new InstanceFactory<IndirectDrawInstanced<FirstInstanceNotSupported> >(m_testCtx, "triangle_list", "Draws an instanced triangle list", testSpec));
1018 					testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1019 					indirectDrawCountNoFirstInstanceGroup->addChild(new InstanceFactory<IndirectDrawInstanced<FirstInstanceNotSupported> >(m_testCtx, "triangle_strip", "Draws an instanced triangle strip", testSpec));
1020 				}
1021 				indirectDrawInstancedGroup->addChild(indirectDrawNoFirstInstanceGroup);
1022 				indirectDrawCountInstancedGroup->addChild(indirectDrawCountNoFirstInstanceGroup);
1023 
1024 				tcu::TestCaseGroup*	indirectDrawFirstInstanceGroup		= new tcu::TestCaseGroup(m_testCtx, "first_instance", "Use drawIndirectFirstInstance optional feature");
1025 				tcu::TestCaseGroup*	indirectDrawCountFirstInstanceGroup	= new tcu::TestCaseGroup(m_testCtx, "first_instance", "Use drawIndirectFirstInstance optional feature");
1026 				{
1027 					IndirectDrawInstanced<FirstInstanceSupported>::TestSpec testSpec;
1028 					testSpec.drawType = static_cast<DrawType>(drawTypeIdx);
1029 
1030 					testSpec.shaders[glu::SHADERTYPE_VERTEX] = "vulkan/draw/VertexFetchInstancedFirstInstance.vert";
1031 					testSpec.shaders[glu::SHADERTYPE_FRAGMENT] = "vulkan/draw/VertexFetch.frag";
1032 
1033 					testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1034 					indirectDrawFirstInstanceGroup->addChild(new InstanceFactory<IndirectDrawInstanced<FirstInstanceSupported> >(m_testCtx, "triangle_list", "Draws an instanced triangle list", testSpec));
1035 					testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1036 					indirectDrawFirstInstanceGroup->addChild(new InstanceFactory<IndirectDrawInstanced<FirstInstanceSupported> >(m_testCtx, "triangle_strip", "Draws an instanced triangle strip", testSpec));
1037 
1038 					testSpec.testIndirectCountExt = true;
1039 					testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1040 					indirectDrawCountFirstInstanceGroup->addChild(new InstanceFactory<IndirectDrawInstanced<FirstInstanceSupported> >(m_testCtx, "triangle_list", "Draws an instanced triangle list", testSpec));
1041 					testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1042 					indirectDrawCountFirstInstanceGroup->addChild(new InstanceFactory<IndirectDrawInstanced<FirstInstanceSupported> >(m_testCtx, "triangle_strip", "Draws an instanced triangle strip", testSpec));
1043 				}
1044 				indirectDrawInstancedGroup->addChild(indirectDrawFirstInstanceGroup);
1045 				indirectDrawCountInstancedGroup->addChild(indirectDrawCountFirstInstanceGroup);
1046 			}
1047 			drawTypeGroup->addChild(indirectDrawInstancedGroup);
1048 			drawTypeGroup->addChild(indirectDrawCountInstancedGroup);
1049 		}
1050 
1051 		addChild(drawTypeGroup);
1052 	}
1053 }
1054 
1055 }	// DrawTests
1056 }	// vkt
1057