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