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