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