Home | History | Annotate | Download | only in draw
      1 /*------------------------------------------------------------------------
      2  * Vulkan Conformance Tests
      3  * ------------------------
      4  *
      5  * Copyright (c) 2016 The Khronos Group Inc.
      6  *
      7  * Licensed under the Apache License, Version 2.0 (the "License");
      8  * you may not use this file except in compliance with the License.
      9  * You may obtain a copy of the License at
     10  *
     11  *      http://www.apache.org/licenses/LICENSE-2.0
     12  *
     13  * Unless required by applicable law or agreed to in writing, software
     14  * distributed under the License is distributed on an "AS IS" BASIS,
     15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     16  * See the License for the specific language governing permissions and
     17  * limitations under the License.
     18  *
     19  *//*!
     20  * \file
     21  * \brief VK_KHR_shader_draw_parameters tests
     22  *//*--------------------------------------------------------------------*/
     23 
     24 #include "vktDrawShaderDrawParametersTests.hpp"
     25 
     26 #include "vktTestCaseUtil.hpp"
     27 #include "vktDrawTestCaseUtil.hpp"
     28 #include "vktDrawBaseClass.hpp"
     29 
     30 #include "vkQueryUtil.hpp"
     31 
     32 #include "tcuTestLog.hpp"
     33 #include "tcuImageCompare.hpp"
     34 #include "tcuTextureUtil.hpp"
     35 
     36 namespace vkt
     37 {
     38 namespace Draw
     39 {
     40 namespace
     41 {
     42 
     43 enum TestFlagBits
     44 {
     45 	TEST_FLAG_INSTANCED			= 1u << 0,
     46 	TEST_FLAG_INDEXED			= 1u << 1,
     47 	TEST_FLAG_INDIRECT			= 1u << 2,
     48 	TEST_FLAG_MULTIDRAW			= 1u << 3,	//!< multiDrawIndirect
     49 	TEST_FLAG_FIRST_INSTANCE	= 1u << 4,	//!< drawIndirectFirstInstance
     50 };
     51 typedef deUint32 TestFlags;
     52 
     53 struct FlagsTestSpec : public TestSpecBase
     54 {
     55 	TestFlags	flags;
     56 };
     57 
     58 inline FlagsTestSpec addFlags (FlagsTestSpec spec, const TestFlags flags)
     59 {
     60 	spec.flags |= flags;
     61 	return spec;
     62 }
     63 
     64 enum Constants
     65 {
     66 	// \note Data layout in buffers (junk data and good data is intertwined).
     67 	//       Values are largely arbitrary, but we try to avoid "nice" numbers to make sure the test doesn't pass by accident.
     68 	NUM_VERTICES			= 4,	//!< number of consecutive good vertices
     69 	NDX_FIRST_VERTEX		= 2,	//!< index of first good vertex data
     70 	NDX_SECOND_VERTEX		= 9,	//!< index of second good vertex data
     71 	NDX_FIRST_INDEX			= 11,	//!< index of a first good index (in index data)
     72 	NDX_SECOND_INDEX		= 17,	//!< index of a second good index
     73 	OFFSET_FIRST_INDEX		= 1,	//!< offset added to the first index
     74 	OFFSET_SECOND_INDEX		= 4,	//!< offset added to the second index
     75 	MAX_INSTANCE_COUNT		= 3,	//!< max number of draw instances
     76 	MAX_INDIRECT_DRAW_COUNT	= 3,	//!< max drawCount of indirect calls
     77 };
     78 
     79 class DrawTest : public DrawTestsBaseClass
     80 {
     81 public:
     82 	typedef FlagsTestSpec	TestSpec;
     83 							DrawTest				(Context &context, TestSpec testSpec);
     84 	tcu::TestStatus			iterate					(void);
     85 
     86 private:
     87 	template<typename T, std::size_t N>
     88 	void					setIndirectCommand		(const T (&pCmdData)[N]);
     89 
     90 	void					drawReferenceImage		(const tcu::PixelBufferAccess& refImage) const;
     91 
     92 	bool					isInstanced				(void) const { return (m_flags & TEST_FLAG_INSTANCED)		!= 0; }
     93 	bool					isIndexed				(void) const { return (m_flags & TEST_FLAG_INDEXED)			!= 0; }
     94 	bool					isIndirect				(void) const { return (m_flags & TEST_FLAG_INDIRECT)		!= 0; }
     95 	bool					isMultiDraw				(void) const { return (m_flags & TEST_FLAG_MULTIDRAW)		!= 0; }
     96 	bool					isFirstInstance			(void) const { return (m_flags & TEST_FLAG_FIRST_INSTANCE)	!= 0; }
     97 
     98 	const TestFlags			m_flags;
     99 	de::SharedPtr<Buffer>	m_indexBuffer;
    100 	de::SharedPtr<Buffer>	m_indirectBuffer;
    101 };
    102 
    103 DrawTest::DrawTest (Context &context, TestSpec testSpec)
    104 	: DrawTestsBaseClass(context, testSpec.shaders[glu::SHADERTYPE_VERTEX], testSpec.shaders[glu::SHADERTYPE_FRAGMENT], testSpec.topology)
    105 	, m_flags			(testSpec.flags)
    106 {
    107 	DE_ASSERT(m_topology == vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP);
    108 	DE_ASSERT(!isMultiDraw()     || isIndirect());
    109 	DE_ASSERT(!isFirstInstance() || (isIndirect() && isInstanced()));
    110 
    111 	// Requirements
    112 	{
    113 		if (!vk::isDeviceExtensionSupported(context.getUsedApiVersion(), context.getDeviceExtensions(), "VK_KHR_shader_draw_parameters"))
    114 			TCU_THROW(NotSupportedError, "Missing extension: VK_KHR_shader_draw_parameters");
    115 
    116 		// Shader draw parameters is part of Vulkan 1.1 but is optional
    117 		if ( context.contextSupports(vk::ApiVersion(1, 1, 0)) )
    118 		{
    119 			// Check if shader draw parameters is supported on the physical device.
    120 			vk::VkPhysicalDeviceShaderDrawParameterFeatures	drawParameters =
    121 			{
    122 				vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETER_FEATURES,	// sType
    123 				DE_NULL,																// pNext
    124 				VK_FALSE																// shaderDrawParameters
    125 			};
    126 			vk::VkPhysicalDeviceFeatures					features;
    127 			deMemset(&features, 0, sizeof(vk::VkPhysicalDeviceFeatures));
    128 
    129 			vk::VkPhysicalDeviceFeatures2					featuresExt		=
    130 			{
    131 				vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,					// sType
    132 				&drawParameters,													// pNext
    133 				features
    134 			};
    135 
    136 			context.getInstanceInterface().getPhysicalDeviceFeatures2(context.getPhysicalDevice(), &featuresExt);
    137 
    138 			if (drawParameters.shaderDrawParameters == VK_FALSE)
    139 				TCU_THROW(NotSupportedError, "shaderDrawParameters feature not supported by the device");
    140 		}
    141 
    142 		if (isMultiDraw() && !m_context.getDeviceFeatures().multiDrawIndirect)
    143 			TCU_THROW(NotSupportedError, "Missing feature: multiDrawIndirect");
    144 
    145 		if (isFirstInstance() && !m_context.getDeviceFeatures().drawIndirectFirstInstance)
    146 			TCU_THROW(NotSupportedError, "Missing feature: drawIndirectFirstInstance");
    147 	}
    148 
    149 	// Vertex data
    150 	{
    151 		int refIndex = NDX_FIRST_VERTEX - OFFSET_FIRST_INDEX;
    152 
    153 		m_data.push_back(VertexElementData(tcu::Vec4( 1.0f, -1.0f, 1.0f, 1.0f), tcu::Vec4(1.0f), -1));
    154 		m_data.push_back(VertexElementData(tcu::Vec4(-1.0f,  1.0f, 1.0f, 1.0f), tcu::Vec4(1.0f), -1));
    155 
    156 		if (!isIndexed())
    157 			refIndex = 0;
    158 
    159 		m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,	-0.3f, 1.0f, 1.0f), tcu::Vec4(1.0f), refIndex++));
    160 		m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,	 0.3f, 1.0f, 1.0f), tcu::Vec4(1.0f), refIndex++));
    161 		m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,	-0.3f, 1.0f, 1.0f), tcu::Vec4(1.0f), refIndex++));
    162 		m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,	 0.3f, 1.0f, 1.0f), tcu::Vec4(1.0f), refIndex++));
    163 
    164 		m_data.push_back(VertexElementData(tcu::Vec4(-1.0f,  1.0f, 1.0f, 1.0f), tcu::Vec4(1.0f), -1));
    165 		m_data.push_back(VertexElementData(tcu::Vec4( 1.0f, -1.0f, 1.0f, 1.0f), tcu::Vec4(1.0f), -1));
    166 		m_data.push_back(VertexElementData(tcu::Vec4(-1.0f, -1.0f, 1.0f, 1.0f), tcu::Vec4(1.0f), -1));
    167 
    168 		if (!isIndexed())
    169 			refIndex = 0;
    170 
    171 		m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,	-0.3f, 1.0f, 1.0f), tcu::Vec4(1.0f), refIndex++));
    172 		m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,	 0.3f, 1.0f, 1.0f), tcu::Vec4(1.0f), refIndex++));
    173 		m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,	-0.3f, 1.0f, 1.0f), tcu::Vec4(1.0f), refIndex++));
    174 		m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,	 0.3f, 1.0f, 1.0f), tcu::Vec4(1.0f), refIndex++));
    175 
    176 		m_data.push_back(VertexElementData(tcu::Vec4(-1.0f,  1.0f, 1.0f, 1.0f), tcu::Vec4(1.0f), -1));
    177 		m_data.push_back(VertexElementData(tcu::Vec4( 1.0f, -1.0f, 1.0f, 1.0f), tcu::Vec4(1.0f), -1));
    178 
    179 		// Make sure constants are up to date
    180 		DE_ASSERT(m_data.size() == NDX_SECOND_VERTEX + NUM_VERTICES + 2);
    181 		DE_ASSERT(NDX_SECOND_VERTEX - NDX_FIRST_VERTEX - NUM_VERTICES == 3);
    182 	}
    183 
    184 	if (isIndirect())
    185 	{
    186 		const std::size_t	indirectBufferSize	= MAX_INDIRECT_DRAW_COUNT * 32;	// space for COUNT commands plus some gratuitous padding
    187 							m_indirectBuffer	= Buffer::createAndAlloc(m_vk, m_context.getDevice(), BufferCreateInfo(indirectBufferSize, vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT),
    188 												  m_context.getDefaultAllocator(), vk::MemoryRequirement::HostVisible);
    189 
    190 		deMemset(m_indirectBuffer->getBoundMemory().getHostPtr(), 0, indirectBufferSize);
    191 		vk::flushMappedMemoryRange(m_vk, m_context.getDevice(), m_indirectBuffer->getBoundMemory().getMemory(), m_indirectBuffer->getBoundMemory().getOffset(), VK_WHOLE_SIZE);
    192 	}
    193 
    194 	if (isIndexed())
    195 	{
    196 		DE_ASSERT(NDX_FIRST_INDEX + NUM_VERTICES <= NDX_SECOND_INDEX);
    197 		const std::size_t	indexBufferSize	= sizeof(deUint32) * (NDX_SECOND_INDEX + NUM_VERTICES);
    198 							m_indexBuffer	= Buffer::createAndAlloc(m_vk, m_context.getDevice(), BufferCreateInfo(indexBufferSize, vk::VK_BUFFER_USAGE_INDEX_BUFFER_BIT),
    199 																	 m_context.getDefaultAllocator(), vk::MemoryRequirement::HostVisible);
    200 		deUint32*			indices			= static_cast<deUint32*>(m_indexBuffer->getBoundMemory().getHostPtr());
    201 
    202 		deMemset(indices, 0, indexBufferSize);
    203 
    204 		for (int i = 0; i < NUM_VERTICES; i++)
    205 		{
    206 			indices[NDX_FIRST_INDEX  + i] = static_cast<deUint32>(NDX_FIRST_VERTEX  + i) - OFFSET_FIRST_INDEX;
    207 			indices[NDX_SECOND_INDEX + i] = static_cast<deUint32>(NDX_SECOND_VERTEX + i) - OFFSET_SECOND_INDEX;
    208 		}
    209 
    210 		vk::flushMappedMemoryRange(m_vk, m_context.getDevice(), m_indexBuffer->getBoundMemory().getMemory(), m_indexBuffer->getBoundMemory().getOffset(), VK_WHOLE_SIZE);
    211 	}
    212 
    213 	initialize();
    214 }
    215 
    216 template<typename T, std::size_t N>
    217 void DrawTest::setIndirectCommand (const T (&pCmdData)[N])
    218 {
    219 	DE_ASSERT(N != 0 && N <= MAX_INDIRECT_DRAW_COUNT);
    220 
    221 	const std::size_t dataSize = N * sizeof(T);
    222 
    223 	deMemcpy(m_indirectBuffer->getBoundMemory().getHostPtr(), pCmdData, dataSize);
    224 	vk::flushMappedMemoryRange(m_vk, m_context.getDevice(), m_indirectBuffer->getBoundMemory().getMemory(), m_indirectBuffer->getBoundMemory().getOffset(), VK_WHOLE_SIZE);
    225 }
    226 
    227 //! This function must be kept in sync with the shader.
    228 void DrawTest::drawReferenceImage (const tcu::PixelBufferAccess& refImage) const
    229 {
    230 	using tcu::Vec2;
    231 	using tcu::Vec4;
    232 	using tcu::IVec4;
    233 
    234 	const Vec2	perInstanceOffset[]	= { Vec2(0.0f, 0.0f), Vec2(-0.3f,  0.0f), Vec2(0.0f, 0.3f) };
    235 	const Vec2	perDrawOffset[]		= { Vec2(0.0f, 0.0f), Vec2(-0.3f, -0.3f), Vec2(0.3f, 0.3f) };
    236 	const Vec4	allColors[]			= { Vec4(1.0f), Vec4(0.0f, 0.0f, 1.0f, 1.0f), Vec4(0.0f, 1.0f, 0.0f, 1.0f) };
    237 	const int	numInstances		= isInstanced() ? MAX_INSTANCE_COUNT		: 1;
    238 	const int	numIndirectDraws	= isMultiDraw() ? MAX_INDIRECT_DRAW_COUNT	: 1;
    239 	const int	rectWidth			= static_cast<int>(WIDTH  * 0.6f / 2.0f);
    240 	const int	rectHeight			= static_cast<int>(HEIGHT * 0.6f / 2.0f);
    241 
    242 	DE_ASSERT(DE_LENGTH_OF_ARRAY(perInstanceOffset) >= numInstances);
    243 	DE_ASSERT(DE_LENGTH_OF_ARRAY(allColors) >= numInstances && DE_LENGTH_OF_ARRAY(allColors) >= numIndirectDraws);
    244 	DE_ASSERT(DE_LENGTH_OF_ARRAY(perDrawOffset) >= numIndirectDraws);
    245 
    246 	tcu::clear(refImage, tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
    247 
    248 	for (int drawNdx     = 0; drawNdx     < numIndirectDraws; ++drawNdx)
    249 	for (int instanceNdx = 0; instanceNdx < numInstances;     ++instanceNdx)
    250 	{
    251 		const Vec2	offset	= perInstanceOffset[instanceNdx] + perDrawOffset[drawNdx];
    252 		const Vec4&	color	= allColors[isMultiDraw() ? drawNdx : instanceNdx];
    253 		int			x		= static_cast<int>(WIDTH  * (1.0f - 0.3f + offset.x()) / 2.0f);
    254 		int			y		= static_cast<int>(HEIGHT * (1.0f - 0.3f + offset.y()) / 2.0f);
    255 
    256 		tcu::clear(tcu::getSubregion(refImage, x, y, rectWidth, rectHeight), color);
    257 	}
    258 }
    259 
    260 tcu::TestStatus DrawTest::iterate (void)
    261 {
    262 	// Draw
    263 	{
    264 		beginRenderPass();
    265 
    266 		const vk::VkDeviceSize	vertexBufferOffset	= 0;
    267 		const vk::VkBuffer		vertexBuffer		= m_vertexBuffer->object();
    268 
    269 		m_vk.cmdBindVertexBuffers	(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
    270 		m_vk.cmdBindPipeline		(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
    271 
    272 		if (isIndexed())
    273 			m_vk.cmdBindIndexBuffer(*m_cmdBuffer, m_indexBuffer->object(), 0ull, vk::VK_INDEX_TYPE_UINT32);
    274 
    275 		const deUint32			numInstances		= isInstanced() ? MAX_INSTANCE_COUNT : 1;
    276 
    277 		if (isIndirect())
    278 		{
    279 			if (isIndexed())
    280 			{
    281 				const vk::VkDrawIndexedIndirectCommand commands[] =
    282 				{
    283 					// indexCount, instanceCount, firstIndex, vertexOffset, firstInstance
    284 					{ NUM_VERTICES,	numInstances,	NDX_FIRST_INDEX,	OFFSET_FIRST_INDEX,		(isFirstInstance() ? 2u : 0u) },
    285 					{ NUM_VERTICES,	numInstances,	NDX_SECOND_INDEX,	OFFSET_SECOND_INDEX,	(isFirstInstance() ? 1u : 0u) },
    286 					{ NUM_VERTICES,	numInstances,	NDX_FIRST_INDEX,	OFFSET_FIRST_INDEX,		(isFirstInstance() ? 3u : 0u) },
    287 				};
    288 				setIndirectCommand(commands);
    289 			}
    290 			else
    291 			{
    292 				const vk::VkDrawIndirectCommand commands[] =
    293 				{
    294 					// vertexCount, instanceCount, firstVertex, firstInstance
    295 					{ NUM_VERTICES,	numInstances,	NDX_FIRST_VERTEX,	(isFirstInstance() ? 2u : 0u) },
    296 					{ NUM_VERTICES,	numInstances,	NDX_SECOND_VERTEX,	(isFirstInstance() ? 1u : 0u) },
    297 					{ NUM_VERTICES,	numInstances,	NDX_FIRST_VERTEX,	(isFirstInstance() ? 3u : 0u) },
    298 				};
    299 				setIndirectCommand(commands);
    300 			}
    301 		}
    302 
    303 		if (isIndirect())
    304 		{
    305 			const deUint32 numIndirectDraws = isMultiDraw() ? MAX_INDIRECT_DRAW_COUNT : 1;
    306 
    307 			if (isIndexed())
    308 				m_vk.cmdDrawIndexedIndirect(*m_cmdBuffer, m_indirectBuffer->object(), 0ull, numIndirectDraws, sizeof(vk::VkDrawIndexedIndirectCommand));
    309 			else
    310 				m_vk.cmdDrawIndirect(*m_cmdBuffer, m_indirectBuffer->object(), 0ull, numIndirectDraws, sizeof(vk::VkDrawIndirectCommand));
    311 		}
    312 		else
    313 		{
    314 			const deUint32 firstInstance = 2;
    315 
    316 			if (isIndexed())
    317 				m_vk.cmdDrawIndexed(*m_cmdBuffer, NUM_VERTICES, numInstances, NDX_FIRST_INDEX, OFFSET_FIRST_INDEX, firstInstance);
    318 			else
    319 				m_vk.cmdDraw(*m_cmdBuffer, NUM_VERTICES, numInstances, NDX_FIRST_VERTEX, firstInstance);
    320 		}
    321 
    322 		m_vk.cmdEndRenderPass(*m_cmdBuffer);
    323 		m_vk.endCommandBuffer(*m_cmdBuffer);
    324 	}
    325 
    326 	// Submit
    327 	{
    328 		const vk::VkQueue		queue		= m_context.getUniversalQueue();
    329 		const vk::VkSubmitInfo	submitInfo	=
    330 		{
    331 			vk::VK_STRUCTURE_TYPE_SUBMIT_INFO,			// VkStructureType			sType;
    332 			DE_NULL,									// const void*				pNext;
    333 			0,											// deUint32					waitSemaphoreCount;
    334 			DE_NULL,									// const VkSemaphore*		pWaitSemaphores;
    335 			(const vk::VkPipelineStageFlags*)DE_NULL,
    336 			1,											// deUint32					commandBufferCount;
    337 			&m_cmdBuffer.get(),							// const VkCommandBuffer*	pCommandBuffers;
    338 			0,											// deUint32					signalSemaphoreCount;
    339 			DE_NULL										// const VkSemaphore*		pSignalSemaphores;
    340 		};
    341 		VK_CHECK(m_vk.queueSubmit(queue, 1, &submitInfo, DE_NULL));
    342 		VK_CHECK(m_vk.queueWaitIdle(queue));
    343 	}
    344 
    345 	// Validate
    346 	{
    347 		tcu::TextureLevel referenceFrame(vk::mapVkFormat(m_colorAttachmentFormat), static_cast<int>(0.5f + WIDTH), static_cast<int>(0.5f + HEIGHT));
    348 
    349 		drawReferenceImage(referenceFrame.getAccess());
    350 
    351 		const vk::VkOffset3D				zeroOffset		= { 0, 0, 0 };
    352 		const tcu::ConstPixelBufferAccess	renderedFrame	= m_colorTargetImage->readSurface(m_context.getUniversalQueue(), m_context.getDefaultAllocator(),
    353 															  vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
    354 
    355 		if (!tcu::fuzzyCompare(m_context.getTestContext().getLog(), "Result", "Image comparison result", referenceFrame.getAccess(), renderedFrame, 0.05f, tcu::COMPARE_LOG_RESULT))
    356 			return tcu::TestStatus::fail("Rendered image is incorrect");
    357 		else
    358 			return tcu::TestStatus::pass("OK");
    359 	}
    360 }
    361 
    362 void addDrawCase (tcu::TestCaseGroup* group, const DrawTest::TestSpec testSpec, const TestFlags flags)
    363 {
    364 	std::ostringstream name;
    365 	name << "draw";
    366 
    367 	if (flags & TEST_FLAG_INDEXED)			name << "_indexed";
    368 	if (flags & TEST_FLAG_INDIRECT)			name << "_indirect";
    369 	if (flags & TEST_FLAG_INSTANCED)		name << "_instanced";
    370 	if (flags & TEST_FLAG_FIRST_INSTANCE)	name << "_first_instance";
    371 
    372 	group->addChild(new InstanceFactory<DrawTest>(group->getTestContext(), name.str(), "", addFlags(testSpec, flags)));
    373 }
    374 
    375 }	// anonymous
    376 
    377 ShaderDrawParametersTests::ShaderDrawParametersTests (tcu::TestContext &testCtx)
    378 	: TestCaseGroup	(testCtx, "shader_draw_parameters", "VK_KHR_shader_draw_parameters")
    379 {
    380 }
    381 
    382 void ShaderDrawParametersTests::init (void)
    383 {
    384 	{
    385 		DrawTest::TestSpec testSpec;
    386 		testSpec.shaders[glu::SHADERTYPE_VERTEX]	= "vulkan/draw/VertexFetchShaderDrawParameters.vert";
    387 		testSpec.shaders[glu::SHADERTYPE_FRAGMENT]	= "vulkan/draw/VertexFetch.frag";
    388 		testSpec.topology							= vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
    389 		testSpec.flags								= 0;
    390 
    391 		de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(getTestContext(), "base_vertex", ""));
    392 		addDrawCase(group.get(), testSpec, 0);
    393 		addDrawCase(group.get(), testSpec, TEST_FLAG_INDEXED);
    394 		addDrawCase(group.get(), testSpec, TEST_FLAG_INDIRECT);
    395 		addDrawCase(group.get(), testSpec, TEST_FLAG_INDEXED | TEST_FLAG_INDIRECT);
    396 		addChild(group.release());
    397 	}
    398 	{
    399 		DrawTest::TestSpec testSpec;
    400 		testSpec.shaders[glu::SHADERTYPE_VERTEX]	= "vulkan/draw/VertexFetchShaderDrawParameters.vert";
    401 		testSpec.shaders[glu::SHADERTYPE_FRAGMENT]	= "vulkan/draw/VertexFetch.frag";
    402 		testSpec.topology							= vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
    403 		testSpec.flags								= TEST_FLAG_INSTANCED;
    404 
    405 		de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(getTestContext(), "base_instance", ""));
    406 		addDrawCase(group.get(), testSpec, 0);
    407 		addDrawCase(group.get(), testSpec, TEST_FLAG_INDEXED);
    408 		addDrawCase(group.get(), testSpec, TEST_FLAG_INDIRECT);
    409 		addDrawCase(group.get(), testSpec, TEST_FLAG_INDIRECT | TEST_FLAG_FIRST_INSTANCE);
    410 		addDrawCase(group.get(), testSpec, TEST_FLAG_INDEXED  | TEST_FLAG_INDIRECT);
    411 		addDrawCase(group.get(), testSpec, TEST_FLAG_INDEXED  | TEST_FLAG_INDIRECT | TEST_FLAG_FIRST_INSTANCE);
    412 		addChild(group.release());
    413 	}
    414 	{
    415 		DrawTest::TestSpec testSpec;
    416 		testSpec.shaders[glu::SHADERTYPE_VERTEX]	= "vulkan/draw/VertexFetchShaderDrawParametersDrawIndex.vert";
    417 		testSpec.shaders[glu::SHADERTYPE_FRAGMENT]	= "vulkan/draw/VertexFetch.frag";
    418 		testSpec.topology							= vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
    419 		testSpec.flags								= TEST_FLAG_INDIRECT | TEST_FLAG_MULTIDRAW;
    420 
    421 		de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(getTestContext(), "draw_index", ""));
    422 		addDrawCase(group.get(), testSpec, 0);
    423 		addDrawCase(group.get(), testSpec, TEST_FLAG_INSTANCED);
    424 		addDrawCase(group.get(), testSpec, TEST_FLAG_INDEXED);
    425 		addDrawCase(group.get(), testSpec, TEST_FLAG_INDEXED | TEST_FLAG_INSTANCED);
    426 		addChild(group.release());
    427 	}
    428 }
    429 
    430 }	// DrawTests
    431 }	// vkt
    432