• 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 
38 #include "vkDefs.hpp"
39 
40 namespace vkt
41 {
42 namespace Draw
43 {
44 namespace
45 {
46 struct JunkData
47 {
JunkDatavkt::Draw::__anon61c504520111::JunkData48 	JunkData()
49 		: varA	(0xcd)
50 		, varB	(0xcd)
51 	{
52 	}
53 	const deUint16	varA;
54 	const deUint32	varB;
55 };
56 
57 class IndirectDraw : public DrawTestsBaseClass
58 {
59 public:
60 								IndirectDraw	(Context &context, ShaderMap shaders, vk::VkPrimitiveTopology topology);
61 	virtual	tcu::TestStatus		iterate			(void);
62 private:
63 	de::SharedPtr<Buffer>					m_indirectBuffer;
64 	std::vector<vk::VkDrawIndirectCommand>	m_indirectDrawCmd;
65 	vk::VkDeviceSize						m_offsetInBuffer;
66 	deUint32								m_strideInBuffer;
67 	deUint32								m_drawCount;
68 	JunkData								m_junkData;
69 protected:
70 	deBool									m_isMultiDrawEnabled;
71 	deUint32								m_drawIndirectMaxCount;
72 };
73 
74 struct FirtsInstanceSupported
75 {
getFirstInstancevkt::Draw::__anon61c504520111::FirtsInstanceSupported76 	static deUint32 getFirstInstance	(void)											{ return 2; }
isTestSupportedvkt::Draw::__anon61c504520111::FirtsInstanceSupported77 	static bool		isTestSupported		(const vk::VkPhysicalDeviceFeatures& features)	{ return features.drawIndirectFirstInstance == vk::VK_TRUE; }
78 };
79 
80 struct FirtsInstanceNotSupported
81 {
getFirstInstancevkt::Draw::__anon61c504520111::FirtsInstanceNotSupported82 	static deUint32 getFirstInstance	(void)											{ return 0; }
isTestSupportedvkt::Draw::__anon61c504520111::FirtsInstanceNotSupported83 	static bool		isTestSupported		(const vk::VkPhysicalDeviceFeatures&)			{ return true; }
84 };
85 
86 template<class FirstInstanceSupport>
87 class IndirectDrawInstanced : public IndirectDraw
88 {
89 public:
90 								IndirectDrawInstanced	(Context &context, ShaderMap shaders, vk::VkPrimitiveTopology topology);
91 	virtual tcu::TestStatus		iterate					(void);
92 private:
93 	de::SharedPtr<Buffer>					m_indirectBuffer;
94 	std::vector<vk::VkDrawIndirectCommand>	m_indirectDrawCmd;
95 	vk::VkDeviceSize						m_offsetInBuffer;
96 	deUint32								m_strideInBuffer;
97 	deUint32								m_drawCount;
98 	JunkData								m_junkData;
99 };
100 
IndirectDraw(Context & context,ShaderMap shaders,vk::VkPrimitiveTopology topology)101 IndirectDraw::IndirectDraw (Context &context, ShaderMap shaders, vk::VkPrimitiveTopology topology)
102 		: DrawTestsBaseClass(context, shaders[glu::SHADERTYPE_VERTEX], shaders[glu::SHADERTYPE_FRAGMENT])
103 {
104 	m_topology = topology;
105 
106 	switch (m_topology)
107 	{
108 		case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
109 			m_data.push_back(PositionColorVertex(tcu::Vec4(	 1.0f,	-1.0f,	1.0f,	1.0f), tcu::RGBA::blue().toVec()));
110 			m_data.push_back(PositionColorVertex(tcu::Vec4(	-1.0f,	 1.0f,	1.0f,	1.0f), tcu::RGBA::blue().toVec()));
111 			m_data.push_back(PositionColorVertex(tcu::Vec4(	-0.3f,	-0.3f,	1.0f,	1.0f), tcu::RGBA::blue().toVec()));
112 			m_data.push_back(PositionColorVertex(tcu::Vec4(	-0.3f,	 0.3f,	1.0f,	1.0f), tcu::RGBA::blue().toVec()));
113 			m_data.push_back(PositionColorVertex(tcu::Vec4(	 0.3f,	-0.3f,	1.0f,	1.0f), tcu::RGBA::blue().toVec()));
114 			m_data.push_back(PositionColorVertex(tcu::Vec4(	 0.3f,	-0.3f,	1.0f,	1.0f), tcu::RGBA::blue().toVec()));
115 			m_data.push_back(PositionColorVertex(tcu::Vec4(	 0.3f,	 0.3f,	1.0f,	1.0f), tcu::RGBA::blue().toVec()));
116 			m_data.push_back(PositionColorVertex(tcu::Vec4(	-0.3f,	 0.3f,	1.0f,	1.0f), tcu::RGBA::blue().toVec()));
117 			m_data.push_back(PositionColorVertex(tcu::Vec4(	-1.0f,	 1.0f,	1.0f,	1.0f), tcu::RGBA::blue().toVec()));
118 			break;
119 		case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
120 			m_data.push_back(PositionColorVertex(tcu::Vec4( 1.0f,	-1.0f,	 1.0f,	 1.0f),	 tcu::RGBA::blue().toVec()));
121 			m_data.push_back(PositionColorVertex(tcu::Vec4(-1.0f,	 1.0f,	 1.0f,	 1.0f),	 tcu::RGBA::blue().toVec()));
122 			m_data.push_back(PositionColorVertex(tcu::Vec4(-0.3f,	 0.0f,	 1.0f,	 1.0f),	 tcu::RGBA::blue().toVec()));
123 			m_data.push_back(PositionColorVertex(tcu::Vec4( 0.3f,	 0.0f,	 1.0f,	 1.0f),	 tcu::RGBA::blue().toVec()));
124 			m_data.push_back(PositionColorVertex(tcu::Vec4(-0.3f,	-0.3f,	 1.0f,	 1.0f),	 tcu::RGBA::blue().toVec()));
125 			m_data.push_back(PositionColorVertex(tcu::Vec4( 0.3f,	-0.3f,	 1.0f,	 1.0f),	 tcu::RGBA::blue().toVec()));
126 			m_data.push_back(PositionColorVertex(tcu::Vec4(-0.3f,	 0.3f,	 1.0f,	 1.0f),	 tcu::RGBA::blue().toVec()));
127 			m_data.push_back(PositionColorVertex(tcu::Vec4( 0.3f,	 0.3f,	 1.0f,	 1.0f),	 tcu::RGBA::blue().toVec()));
128 			m_data.push_back(PositionColorVertex(tcu::Vec4(-0.3f,	 0.0f,	 1.0f,	 1.0f),	 tcu::RGBA::blue().toVec()));
129 			m_data.push_back(PositionColorVertex(tcu::Vec4( 0.3f,	 0.0f,	 1.0f,	 1.0f),	 tcu::RGBA::blue().toVec()));
130 			m_data.push_back(PositionColorVertex(tcu::Vec4(-1.0f,	 1.0f,	 1.0f,	 1.0f),	 tcu::RGBA::blue().toVec()));
131 			break;
132 		case vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST:
133 		case vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
134 		case vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
135 		case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
136 		case vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY:
137 		case vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY:
138 		case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY:
139 		case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY:
140 		case vk::VK_PRIMITIVE_TOPOLOGY_PATCH_LIST:
141 		case vk::VK_PRIMITIVE_TOPOLOGY_LAST:
142 			DE_FATAL("Topology not implemented");
143 			break;
144 		default:
145 			DE_FATAL("Unknown topology");
146 			break;
147 	}
148 	initialize();
149 
150 	// Check device for multidraw support:
151 	if (m_context.getDeviceFeatures().multiDrawIndirect)
152 		m_isMultiDrawEnabled = true;
153 	else
154 		m_isMultiDrawEnabled = false;
155 
156 	m_drawIndirectMaxCount = m_context.getDeviceProperties().limits.maxDrawIndirectCount;
157 
158 }
159 
iterate(void)160 tcu::TestStatus IndirectDraw::iterate (void)
161 {
162 	tcu::TestLog &log = m_context.getTestContext().getLog();
163 	const vk::VkQueue queue = m_context.getUniversalQueue();
164 
165 	switch (m_topology)
166 	{
167 		case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
168 		{
169 			vk::VkDrawIndirectCommand drawCommands[] =
170 			{
171 				{
172 					3,		//vertexCount
173 					1,		//instanceCount
174 					2,		//firstVertex
175 					0		//firstInstance
176 				},
177 				{ (deUint32)-4, (deUint32)-2, (deUint32)-11, (deUint32)-9 }, // junk (stride)
178 				{
179 					3,		//vertexCount
180 					1,		//instanceCount
181 					5,		//firstVertex
182 					0		//firstInstance
183 				}
184 			};
185 			m_indirectDrawCmd.push_back(drawCommands[0]);
186 			m_indirectDrawCmd.push_back(drawCommands[1]);
187 			m_indirectDrawCmd.push_back(drawCommands[2]);
188 			break;
189 		}
190 		case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
191 		{
192 			vk::VkDrawIndirectCommand drawCommands[] =
193 			{
194 				{
195 					4,		//vertexCount
196 					1,		//instanceCount
197 					2,		//firstVertex
198 					0		//firstInstance
199 				},
200 				{ (deUint32)-4, (deUint32)-2, (deUint32)-11, (deUint32)-9 }, // junk (stride)
201 				{
202 					4,		//vertexCount
203 					1,		//instanceCount
204 					6,		//firstVertex
205 					0		//firstInstance
206 				}
207 			};
208 			m_indirectDrawCmd.push_back(drawCommands[0]);
209 			m_indirectDrawCmd.push_back(drawCommands[1]);
210 			m_indirectDrawCmd.push_back(drawCommands[2]);
211 			break;
212 		}
213 		case vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST:
214 		case vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
215 		case vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
216 		case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
217 		case vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY:
218 		case vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY:
219 		case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY:
220 		case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY:
221 		case vk::VK_PRIMITIVE_TOPOLOGY_PATCH_LIST:
222 		case vk::VK_PRIMITIVE_TOPOLOGY_LAST:
223 			DE_FATAL("Topology not implemented");
224 			break;
225 		default:
226 			DE_FATAL("Unknown topology");
227 			break;
228 	}
229 
230 	m_strideInBuffer	= 2 * (deUint32)sizeof(m_indirectDrawCmd[0]);
231 	m_drawCount			= 2;
232 	m_offsetInBuffer	= sizeof(m_junkData);
233 
234 	beginRenderPass();
235 
236 	const vk::VkDeviceSize vertexBufferOffset	= 0;
237 	const vk::VkBuffer vertexBuffer				= m_vertexBuffer->object();
238 
239 	m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
240 
241 	const vk::VkDeviceSize dataSize = m_indirectDrawCmd.size()*sizeof(m_indirectDrawCmd[0]);
242 
243 	m_indirectBuffer = Buffer::createAndAlloc(	m_vk,
244 												m_context.getDevice(),
245 												BufferCreateInfo(dataSize,
246 																 vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT),
247 												m_context.getDefaultAllocator(),
248 												vk::MemoryRequirement::HostVisible);
249 
250 	deUint8* ptr = reinterpret_cast<deUint8*>(m_indirectBuffer->getBoundMemory().getHostPtr());
251 
252 	deMemcpy(ptr, &m_junkData, static_cast<size_t>(m_offsetInBuffer));
253 	deMemcpy((ptr+m_offsetInBuffer), &m_indirectDrawCmd[0], static_cast<size_t>(dataSize));
254 
255 	vk::flushMappedMemoryRange(m_vk,
256 							   m_context.getDevice(),
257 							   m_indirectBuffer->getBoundMemory().getMemory(),
258 							   m_indirectBuffer->getBoundMemory().getOffset(),
259 							   dataSize);
260 
261 	m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
262 	if (m_isMultiDrawEnabled && m_drawCount <= m_drawIndirectMaxCount)
263 		m_vk.cmdDrawIndirect(*m_cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer, m_drawCount, m_strideInBuffer);
264 	else
265 	{
266 		for(deUint32 drawNdx = 0; drawNdx < m_drawCount; drawNdx++){
267 			m_vk.cmdDrawIndirect(*m_cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer + drawNdx*m_strideInBuffer, 1, m_strideInBuffer);
268 		}
269 	}
270 	m_vk.cmdEndRenderPass(*m_cmdBuffer);
271 	m_vk.endCommandBuffer(*m_cmdBuffer);
272 
273 	vk::VkSubmitInfo submitInfo =
274 	{
275 		vk::VK_STRUCTURE_TYPE_SUBMIT_INFO,	// VkStructureType			sType;
276 		DE_NULL,							// const void*				pNext;
277 		0,										// deUint32					waitSemaphoreCount;
278 		DE_NULL,								// const VkSemaphore*		pWaitSemaphores;
279 		(const vk::VkPipelineStageFlags*)DE_NULL,
280 		1,										// deUint32					commandBufferCount;
281 		&m_cmdBuffer.get(),					// const VkCommandBuffer*	pCommandBuffers;
282 		0,										// deUint32					signalSemaphoreCount;
283 		DE_NULL								// const VkSemaphore*		pSignalSemaphores;
284 	};
285 	VK_CHECK(m_vk.queueSubmit(queue, 1, &submitInfo, DE_NULL));
286 
287 	VK_CHECK(m_vk.queueWaitIdle(queue));
288 
289 	// Validation
290 	tcu::Texture2D referenceFrame(vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5 + WIDTH), (int)(0.5 + HEIGHT));
291 	referenceFrame.allocLevel(0);
292 
293 	const deInt32 frameWidth	= referenceFrame.getWidth();
294 	const deInt32 frameHeight	= referenceFrame.getHeight();
295 
296 	tcu::clear(referenceFrame.getLevel(0), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
297 
298 	ReferenceImageCoordinates refCoords;
299 
300 	for (int y = 0; y < frameHeight; y++)
301 	{
302 		const float yCoord = (float)(y / (0.5*frameHeight)) - 1.0f;
303 
304 		for (int x = 0; x < frameWidth; x++)
305 		{
306 			const float xCoord = (float)(x / (0.5*frameWidth)) - 1.0f;
307 
308 			if ((yCoord >= refCoords.bottom	&&
309 				 yCoord <= refCoords.top	&&
310 				 xCoord >= refCoords.left	&&
311 				 xCoord <= refCoords.right))
312 				referenceFrame.getLevel(0).setPixel(tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f), x, y);
313 		}
314 	}
315 
316 	const vk::VkOffset3D zeroOffset					= { 0, 0, 0 };
317 	const tcu::ConstPixelBufferAccess renderedFrame = m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(),
318 		vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
319 
320 	qpTestResult res = QP_TEST_RESULT_PASS;
321 
322 	if (!tcu::fuzzyCompare(log, "Result", "Image comparison result",
323 		referenceFrame.getLevel(0), renderedFrame, 0.05f,
324 		tcu::COMPARE_LOG_RESULT)) {
325 		res = QP_TEST_RESULT_FAIL;
326 	}
327 
328 	return tcu::TestStatus(res, qpGetTestResultName(res));
329 
330 }
331 
332 template<class FirstInstanceSupport>
IndirectDrawInstanced(Context & context,ShaderMap shaders,vk::VkPrimitiveTopology topology)333 IndirectDrawInstanced<FirstInstanceSupport>::IndirectDrawInstanced (Context &context, ShaderMap shaders, vk::VkPrimitiveTopology topology)
334 	: IndirectDraw	(context, shaders, topology)
335 {
336 	if (!FirstInstanceSupport::isTestSupported(m_context.getDeviceFeatures()))
337 	{
338 		throw tcu::NotSupportedError("Required 'drawIndirectFirstInstance' feature is not supported");
339 	}
340 }
341 
342 template<class FirstInstanceSupport>
iterate(void)343 tcu::TestStatus IndirectDrawInstanced<FirstInstanceSupport>::iterate (void)
344 {
345 	tcu::TestLog &log = m_context.getTestContext().getLog();
346 	const vk::VkQueue queue = m_context.getUniversalQueue();
347 
348 	switch (m_topology)
349 	{
350 		case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
351 		{
352 			vk::VkDrawIndirectCommand drawCmd[] =
353 			{
354 				{
355 					3,											//vertexCount
356 					4,											//instanceCount
357 					2,											//firstVertex
358 					FirstInstanceSupport::getFirstInstance()	//firstInstance
359 				},
360 				{ (deUint32)-4, (deUint32)-2, (deUint32)-11, (deUint32)-9 }, // junk (stride)
361 				{
362 					3,											//vertexCount
363 					4,											//instanceCount
364 					5,											//firstVertex
365 					FirstInstanceSupport::getFirstInstance()	//firstInstance
366 				}
367 			};
368 			m_indirectDrawCmd.push_back(drawCmd[0]);
369 			m_indirectDrawCmd.push_back(drawCmd[1]);
370 			m_indirectDrawCmd.push_back(drawCmd[2]);
371 			break;
372 		}
373 		case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
374 		{
375 			vk::VkDrawIndirectCommand drawCmd[] =
376 			{
377 				{
378 					4,											//vertexCount
379 					4,											//instanceCount
380 					2,											//firstVertex
381 					FirstInstanceSupport::getFirstInstance()	//firstInstance
382 				},
383 				{ (deUint32)-4, (deUint32)-2, (deUint32)-11, (deUint32)-9 },
384 				{
385 					4,											//vertexCount
386 					4,											//instanceCount
387 					6,											//firstVertex
388 					FirstInstanceSupport::getFirstInstance()	//firstInstance
389 				}
390 			};
391 			m_indirectDrawCmd.push_back(drawCmd[0]);
392 			m_indirectDrawCmd.push_back(drawCmd[1]);
393 			m_indirectDrawCmd.push_back(drawCmd[2]);
394 			break;
395 		}
396 		case vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST:
397 		case vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
398 		case vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
399 		case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
400 		case vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY:
401 		case vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY:
402 		case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY:
403 		case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY:
404 		case vk::VK_PRIMITIVE_TOPOLOGY_PATCH_LIST:
405 		case vk::VK_PRIMITIVE_TOPOLOGY_LAST:
406 			DE_FATAL("Topology not implemented");
407 			break;
408 		default:
409 			DE_FATAL("Unknown topology");
410 			break;
411 	}
412 
413 	m_strideInBuffer	= 2 * (deUint32)sizeof(m_indirectDrawCmd[0]);
414 	m_drawCount			= 2;
415 	m_offsetInBuffer	= sizeof(m_junkData);
416 
417 	beginRenderPass();
418 
419 	const vk::VkDeviceSize vertexBufferOffset = 0;
420 	const vk::VkBuffer vertexBuffer = m_vertexBuffer->object();
421 
422 	m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
423 
424 	const vk::VkDeviceSize dataSize = m_indirectDrawCmd.size()*sizeof(m_indirectDrawCmd[0]);
425 
426 	m_indirectBuffer = Buffer::createAndAlloc(	m_vk,
427 												m_context.getDevice(),
428 												BufferCreateInfo(dataSize,
429 																 vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT),
430 												m_context.getDefaultAllocator(),
431 												vk::MemoryRequirement::HostVisible);
432 
433 	deUint8* ptr = reinterpret_cast<deUint8*>(m_indirectBuffer->getBoundMemory().getHostPtr());
434 
435 	deMemcpy(ptr, &m_junkData, static_cast<size_t>(m_offsetInBuffer));
436 	deMemcpy((ptr + m_offsetInBuffer), &m_indirectDrawCmd[0], static_cast<size_t>(dataSize));
437 
438 	vk::flushMappedMemoryRange(m_vk,
439 							   m_context.getDevice(),
440 							   m_indirectBuffer->getBoundMemory().getMemory(),
441 							   m_indirectBuffer->getBoundMemory().getOffset(),
442 							   dataSize);
443 
444 	m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
445 	if (m_isMultiDrawEnabled && m_drawCount <= m_drawIndirectMaxCount)
446 		m_vk.cmdDrawIndirect(*m_cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer, m_drawCount, m_strideInBuffer);
447 	else
448 	{
449 		for (deUint32 drawNdx = 0; drawNdx < m_drawCount; drawNdx++){
450 			m_vk.cmdDrawIndirect(*m_cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer + drawNdx*m_strideInBuffer, 1, m_strideInBuffer);
451 		}
452 	}
453 	m_vk.cmdEndRenderPass(*m_cmdBuffer);
454 	m_vk.endCommandBuffer(*m_cmdBuffer);
455 
456 	vk::VkSubmitInfo submitInfo =
457 	{
458 		vk::VK_STRUCTURE_TYPE_SUBMIT_INFO,	// VkStructureType			sType;
459 		DE_NULL,							// const void*				pNext;
460 		0,										// deUint32					waitSemaphoreCount;
461 		DE_NULL,								// const VkSemaphore*		pWaitSemaphores;
462 		(const vk::VkPipelineStageFlags*)DE_NULL,
463 		1,										// deUint32					commandBufferCount;
464 		&m_cmdBuffer.get(),					// const VkCommandBuffer*	pCommandBuffers;
465 		0,										// deUint32					signalSemaphoreCount;
466 		DE_NULL								// const VkSemaphore*		pSignalSemaphores;
467 	};
468 	VK_CHECK(m_vk.queueSubmit(queue, 1, &submitInfo, DE_NULL));
469 
470 	VK_CHECK(m_vk.queueWaitIdle(queue));
471 
472 	// Validation
473 	VK_CHECK(m_vk.queueWaitIdle(queue));
474 
475 	tcu::Texture2D referenceFrame(vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5 + WIDTH), (int)(0.5 + HEIGHT));
476 
477 	referenceFrame.allocLevel(0);
478 
479 	const deInt32 frameWidth	= referenceFrame.getWidth();
480 	const deInt32 frameHeight	= referenceFrame.getHeight();
481 
482 	tcu::clear(referenceFrame.getLevel(0), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
483 
484 	ReferenceImageInstancedCoordinates refInstancedCoords;
485 
486 	for (int y = 0; y < frameHeight; y++)
487 	{
488 		const float yCoord = (float)(y / (0.5*frameHeight)) - 1.0f;
489 
490 		for (int x = 0; x < frameWidth; x++)
491 		{
492 			const float xCoord = (float)(x / (0.5*frameWidth)) - 1.0f;
493 
494 			if ((yCoord >= refInstancedCoords.bottom	&&
495 				 yCoord <= refInstancedCoords.top		&&
496 				 xCoord >= refInstancedCoords.left		&&
497 				 xCoord <= refInstancedCoords.right))
498 				referenceFrame.getLevel(0).setPixel(tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f), x, y);
499 		}
500 	}
501 
502 	const vk::VkOffset3D zeroOffset = { 0, 0, 0 };
503 	const tcu::ConstPixelBufferAccess renderedFrame = m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(),
504 		vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
505 
506 	qpTestResult res = QP_TEST_RESULT_PASS;
507 
508 	if (!tcu::fuzzyCompare(log, "Result", "Image comparison result",
509 		referenceFrame.getLevel(0), renderedFrame, 0.05f,
510 		tcu::COMPARE_LOG_RESULT)) {
511 		res = QP_TEST_RESULT_FAIL;
512 	}
513 
514 	return tcu::TestStatus(res, qpGetTestResultName(res));
515 
516 	}
517 
518 }	// anonymous
519 
IndirectDrawTests(tcu::TestContext & testCtx)520 IndirectDrawTests::IndirectDrawTests (tcu::TestContext &testCtx)
521 	: TestCaseGroup(testCtx, "indirect_draw", "indirect drawing simple geometry")
522 {
523 	/* Left blank on purpose */
524 }
525 
~IndirectDrawTests(void)526 IndirectDrawTests::~IndirectDrawTests (void) {}
527 
528 
init(void)529 void IndirectDrawTests::init (void)
530 {
531 	ShaderMap shaderPaths;
532 	shaderPaths[glu::SHADERTYPE_VERTEX]		= "vulkan/draw/VertexFetch.vert";
533 	shaderPaths[glu::SHADERTYPE_FRAGMENT]	= "vulkan/draw/VertexFetch.frag";
534 
535 	tcu::TestCaseGroup* indirectDrawGroup	= new tcu::TestCaseGroup(m_testCtx, "indirect_draw", "Draws geometry");
536 	{
537 		indirectDrawGroup->addChild(new InstanceFactory<IndirectDraw>(m_testCtx, "triangle_list", "Draws triangle list", shaderPaths, vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST));
538 		indirectDrawGroup->addChild(new InstanceFactory<IndirectDraw>(m_testCtx, "triangle_strip", "Draws triangle strip", shaderPaths, vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP));
539 	}
540 	addChild(indirectDrawGroup);
541 
542 
543 	tcu::TestCaseGroup* indirectDrawInstancedGroup	= new tcu::TestCaseGroup(m_testCtx, "indirect_draw_instanced", "Draws an instanced geometry");
544 	{
545 		tcu::TestCaseGroup*	noFirstInstanceGroup	= new tcu::TestCaseGroup(m_testCtx, "no_first_instance", "Use 0 as firstInstance");
546 		{
547 			shaderPaths[glu::SHADERTYPE_VERTEX] = "vulkan/draw/VertexFetchInstanced.vert";
548 
549 			noFirstInstanceGroup->addChild(new InstanceFactory<IndirectDrawInstanced<FirtsInstanceNotSupported> >(m_testCtx, "triangle_list", "Draws an instanced triangle list", shaderPaths, vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST));
550 			noFirstInstanceGroup->addChild(new InstanceFactory<IndirectDrawInstanced<FirtsInstanceNotSupported> >(m_testCtx, "triangle_strip", "Draws an instanced triangle strip", shaderPaths, vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP));
551 		}
552 		indirectDrawInstancedGroup->addChild(noFirstInstanceGroup);
553 
554 		tcu::TestCaseGroup*	firstInstanceGroup		= new tcu::TestCaseGroup(m_testCtx, "first_instance", "Use drawIndirectFirstInstance optional feature");
555 		{
556 			shaderPaths[glu::SHADERTYPE_VERTEX] = "vulkan/draw/VertexFetchInstancedFirstInstance.vert";
557 
558 			firstInstanceGroup->addChild(new InstanceFactory<IndirectDrawInstanced<FirtsInstanceSupported> >(m_testCtx, "triangle_list", "Draws an instanced triangle list", shaderPaths, vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST));
559 			firstInstanceGroup->addChild(new InstanceFactory<IndirectDrawInstanced<FirtsInstanceSupported> >(m_testCtx, "triangle_strip", "Draws an instanced triangle strip", shaderPaths, vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP));
560 		}
561 		indirectDrawInstancedGroup->addChild(firstInstanceGroup);
562 	}
563 	addChild(indirectDrawInstancedGroup);
564 }
565 
566 }	// DrawTests
567 }	// vkt