Home | History | Annotate | Download | only in draw
      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 {
     48 	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 {
     76 	static deUint32 getFirstInstance	(void)											{ return 2; }
     77 	static bool		isTestSupported		(const vk::VkPhysicalDeviceFeatures& features)	{ return features.drawIndirectFirstInstance == vk::VK_TRUE; }
     78 };
     79 
     80 struct FirtsInstanceNotSupported
     81 {
     82 	static deUint32 getFirstInstance	(void)											{ return 0; }
     83 	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 
    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 
    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>
    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>
    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 
    520 IndirectDrawTests::IndirectDrawTests (tcu::TestContext &testCtx)
    521 	: TestCaseGroup(testCtx, "indirect_draw", "indirect drawing simple geometry")
    522 {
    523 	/* Left blank on purpose */
    524 }
    525 
    526 IndirectDrawTests::~IndirectDrawTests (void) {}
    527 
    528 
    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