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 #include "../compute/vktComputeTestsUtil.hpp"
30 
31 #include "vktDrawBaseClass.hpp"
32 
33 #include "tcuTestLog.hpp"
34 #include "tcuResource.hpp"
35 #include "tcuImageCompare.hpp"
36 #include "tcuTextureUtil.hpp"
37 #include "tcuRGBA.hpp"
38 #include "vkQueryUtil.hpp"
39 
40 #include "vkDefs.hpp"
41 #include "vkCmdUtil.hpp"
42 #include "vkBuilderUtil.hpp"
43 #include "vkObjUtil.hpp"
44 #include "vkTypeUtil.hpp"
45 #include "vkBarrierUtil.hpp"
46 
47 namespace vkt
48 {
49 namespace Draw
50 {
51 namespace
52 {
53 
54 enum
55 {
56 	VERTEX_OFFSET = 13
57 };
58 
59 struct JunkData
60 {
JunkDatavkt::Draw::__anon29155::JunkData61 	JunkData()
62 		: varA	(0xcd)
63 		, varB	(0xcd)
64 	{
65 	}
66 	const deUint16	varA;
67 	const deUint32	varB;
68 };
69 
70 enum DrawType
71 {
72 	DRAW_TYPE_SEQUENTIAL,
73 	DRAW_TYPE_INDEXED,
74 
75 	DRAWTYPE_LAST
76 };
77 
78 enum class IndirectCountType
79 {
80 	NONE,
81 	BUFFER_LIMIT,
82 	PARAM_LIMIT,
83 
84 	LAST
85 };
86 
87 struct DrawTypedTestSpec : public TestSpecBase
88 {
DrawTypedTestSpecvkt::Draw::__anon29155::DrawTypedTestSpec89 	DrawTypedTestSpec(const SharedGroupParams groupParams_)
90 		: TestSpecBase{ {}, vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, groupParams_ }
91 		, drawType(DRAWTYPE_LAST)
92 		, testFirstInstanceNdx(false)
93 		, testIndirectCountExt(IndirectCountType::NONE)
dataFromComputevkt::Draw::__anon29155::DrawTypedTestSpec94 		, dataFromCompute(false)
95 	{}
96 
97 	DrawType			drawType;
98 	bool				testFirstInstanceNdx;
99 	IndirectCountType	testIndirectCountExt;
100 	bool				dataFromCompute;
101 };
102 
103 class IndirectDraw : public DrawTestsBaseClass
104 {
105 public:
106 	typedef DrawTypedTestSpec			TestSpec;
107 
108 										IndirectDraw					(Context &context, TestSpec testSpec);
109 	virtual	tcu::TestStatus				iterate							(void);
110 
111 	void								draw							(vk::VkCommandBuffer cmdBuffer);
112 	template<typename T> void			addCommand						(const T&);
113 
114 protected:
115 	void								setVertexBuffer					(void);
116 	void								setFirstInstanceVertexBuffer	(void);
117 	void								negateDataUsingCompute			(vk::VkDeviceSize indirectBufferSize, vk::VkDeviceSize countBufferSize);
118 
119 	std::vector<char>					m_indirectBufferContents;
120 	de::SharedPtr<Buffer>				m_indirectBuffer;
121 	vk::VkDeviceSize					m_offsetInBuffer;
122 	deUint32							m_strideInBuffer;
123 
124 	const IndirectCountType				m_testIndirectCountExt;
125 	de::SharedPtr<Buffer>				m_indirectCountBuffer;
126 	vk::VkDeviceSize					m_offsetInCountBuffer;
127 	const deUint32						m_indirectCountExtDrawPadding;
128 
129 	deUint32							m_drawCount;
130 	JunkData							m_junkData;
131 
132 	const DrawType						m_drawType;
133 	const bool							m_testFirstInstanceNdx;
134 	deBool								m_isMultiDrawEnabled;
135 	deUint32							m_drawIndirectMaxCount;
136 	deBool								m_dataFromComputeShader;
137 
138 	de::SharedPtr<Buffer>				m_indexBuffer;
139 
140 	vk::Move<vk::VkDescriptorSetLayout>	m_descriptorSetLayout;
141 	vk::Move<vk::VkDescriptorPool>		m_descriptorPool;
142 	vk::Move<vk::VkDescriptorSet>		m_descriptorSetIndirectBuffer;
143 	vk::Move<vk::VkDescriptorSet>		m_descriptorSetCountBuffer;
144 	vk::Move<vk::VkShaderModule>		m_computeShaderModule;
145 	vk::Move<vk::VkPipelineLayout>		m_pipelineLayout;
146 	vk::Move<vk::VkPipeline>			m_computePipeline;
147 };
148 
149 struct FirstInstanceSupported
150 {
getFirstInstancevkt::Draw::__anon29155::FirstInstanceSupported151 	static deUint32 getFirstInstance	(void)											{ return 2; }
isTestSupportedvkt::Draw::__anon29155::FirstInstanceSupported152 	static bool		isTestSupported		(const vk::VkPhysicalDeviceFeatures& features)	{ return features.drawIndirectFirstInstance == VK_TRUE; }
153 };
154 
155 struct FirstInstanceNotSupported
156 {
getFirstInstancevkt::Draw::__anon29155::FirstInstanceNotSupported157 	static deUint32 getFirstInstance	(void)											{ return 0; }
isTestSupportedvkt::Draw::__anon29155::FirstInstanceNotSupported158 	static bool		isTestSupported		(const vk::VkPhysicalDeviceFeatures&)			{ return true; }
159 };
160 
161 template<class FirstInstanceSupport>
162 class IndirectDrawInstanced : public IndirectDraw
163 {
164 public:
165 								IndirectDrawInstanced	(Context &context, TestSpec testSpec);
166 	virtual tcu::TestStatus		iterate					(void);
167 };
168 
setVertexBuffer(void)169 void IndirectDraw::setVertexBuffer (void)
170 {
171 	int refVertexIndex = 2;
172 
173 	if (m_drawType == DRAW_TYPE_INDEXED)
174 	{
175 		for (int unusedIdx = 0; unusedIdx < VERTEX_OFFSET; unusedIdx++)
176 		{
177 			m_data.push_back(VertexElementData(tcu::Vec4(-1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), -1));
178 		}
179 		refVertexIndex += VERTEX_OFFSET;
180 	}
181 
182 	m_data.push_back(VertexElementData(tcu::Vec4( 1.0f, -1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), -1));
183 	m_data.push_back(VertexElementData(tcu::Vec4(-1.0f,  1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), -1));
184 
185 	switch (m_topology)
186 	{
187 		case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
188 			m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,	-0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++));
189 			m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,	 0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++));
190 			m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,	-0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++));
191 			m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,	-0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++));
192 			m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,	 0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++));
193 			m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,	 0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++));
194 			break;
195 		case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
196 			m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,	 0.0f, 1.0f, 1.0f),	 tcu::RGBA::blue().toVec(), refVertexIndex++));
197 			m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,	 0.0f, 1.0f, 1.0f),	 tcu::RGBA::blue().toVec(), refVertexIndex++));
198 			m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,	-0.3f, 1.0f, 1.0f),	 tcu::RGBA::blue().toVec(), refVertexIndex++));
199 			m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,	-0.3f, 1.0f, 1.0f),	 tcu::RGBA::blue().toVec(), refVertexIndex++));
200 			m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,	 0.3f, 1.0f, 1.0f),	 tcu::RGBA::blue().toVec(), refVertexIndex++));
201 			m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,	 0.3f, 1.0f, 1.0f),	 tcu::RGBA::blue().toVec(), refVertexIndex++));
202 			m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,	 0.0f, 1.0f, 1.0f),	 tcu::RGBA::blue().toVec(), refVertexIndex++));
203 			m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,	 0.0f, 1.0f, 1.0f),	 tcu::RGBA::blue().toVec(), refVertexIndex++));
204 			break;
205 		default:
206 			DE_FATAL("Unknown topology");
207 			break;
208 	}
209 
210 	m_data.push_back(VertexElementData(tcu::Vec4(-1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), -1));
211 }
212 
setFirstInstanceVertexBuffer(void)213 void IndirectDraw::setFirstInstanceVertexBuffer (void)
214 {
215 	if (m_context.getDeviceFeatures().drawIndirectFirstInstance != VK_TRUE)
216 	{
217 		TCU_THROW(NotSupportedError, "Required 'drawIndirectFirstInstance' feature is not supported");
218 	}
219 
220 	if (m_drawType == DRAW_TYPE_INDEXED)
221 	{
222 		for (int unusedIdx = 0; unusedIdx < VERTEX_OFFSET; unusedIdx++)
223 		{
224 			m_data.push_back(VertexElementData(tcu::Vec4(-1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), -1));
225 		}
226 	}
227 
228 	m_data.push_back(VertexElementData(tcu::Vec4( 1.0f, -1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), -1));
229 	m_data.push_back(VertexElementData(tcu::Vec4(-1.0f,  1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), -1));
230 
231 	switch (m_topology)
232 	{
233 		case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
234 		{
235 			int refInstanceIndex = 1;
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.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refInstanceIndex));
238 			m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,	-0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refInstanceIndex));
239 
240 			refInstanceIndex = 0;
241 			m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,	-0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refInstanceIndex));
242 			m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,	 0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refInstanceIndex));
243 			m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,	 0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refInstanceIndex));
244 			break;
245 		}
246 		case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
247 		{
248 			int refInstanceIndex = 1;
249 			m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,	 0.0f, 1.0f, 1.0f),	 tcu::RGBA::blue().toVec(), refInstanceIndex));
250 			m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,	 0.0f, 1.0f, 1.0f),	 tcu::RGBA::blue().toVec(), refInstanceIndex));
251 			m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,	-0.3f, 1.0f, 1.0f),	 tcu::RGBA::blue().toVec(), refInstanceIndex));
252 			m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,	-0.3f, 1.0f, 1.0f),	 tcu::RGBA::blue().toVec(), refInstanceIndex));
253 
254 			refInstanceIndex = 0;
255 			m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,	 0.3f, 1.0f, 1.0f),	 tcu::RGBA::blue().toVec(), refInstanceIndex));
256 			m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,	 0.3f, 1.0f, 1.0f),	 tcu::RGBA::blue().toVec(), refInstanceIndex));
257 			m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,	 0.0f, 1.0f, 1.0f),	 tcu::RGBA::blue().toVec(), refInstanceIndex));
258 			m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,	 0.0f, 1.0f, 1.0f),	 tcu::RGBA::blue().toVec(), refInstanceIndex));
259 			break;
260 		}
261 		default:
262 			DE_FATAL("Unknown topology");
263 			break;
264 	}
265 
266 	m_data.push_back(VertexElementData(tcu::Vec4(-1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), -1));
267 }
268 
269 // When testing indirect data generation from a compute shader, the original data is negated bitwise
270 // and compute shader restores it before being used in an indirect draw.
negateDataUsingCompute(vk::VkDeviceSize indirectBufferSize, vk::VkDeviceSize countBufferSize)271 void IndirectDraw::negateDataUsingCompute(vk::VkDeviceSize indirectBufferSize, vk::VkDeviceSize countBufferSize)
272 {
273 	m_descriptorSetLayout	= vk::DescriptorSetLayoutBuilder().addSingleBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, vk::VK_SHADER_STAGE_COMPUTE_BIT).build(m_vk, m_context.getDevice());
274 	m_descriptorPool		= vk::DescriptorPoolBuilder().addType(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 2u).build(m_vk, m_context.getDevice(), vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 2u);
275 
276 	// Indirect buffer
277 	{
278 		m_descriptorSetIndirectBuffer = vk::makeDescriptorSet(m_vk, m_context.getDevice(), *m_descriptorPool, *m_descriptorSetLayout);
279 		const vk::VkDescriptorBufferInfo bufferDescriptorInfo = vk::makeDescriptorBufferInfo(m_indirectBuffer->object(), 0ull, indirectBufferSize);
280 		vk::DescriptorSetUpdateBuilder()
281 				.writeSingle(*m_descriptorSetIndirectBuffer, vk::DescriptorSetUpdateBuilder::Location::binding(0u),
282 							 vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &bufferDescriptorInfo)
283 				.update(m_vk, m_context.getDevice());
284 	}
285 
286 	// Indirect count buffer
287 	if (m_testIndirectCountExt != IndirectCountType::NONE)
288 	{
289 		m_descriptorSetCountBuffer = vk::makeDescriptorSet(m_vk, m_context.getDevice(), *m_descriptorPool, *m_descriptorSetLayout);
290 		const vk::VkDescriptorBufferInfo bufferDescriptorInfo = vk::makeDescriptorBufferInfo(m_indirectCountBuffer->object(), 0ull, countBufferSize);
291 		vk::DescriptorSetUpdateBuilder()
292 				.writeSingle(*m_descriptorSetCountBuffer, vk::DescriptorSetUpdateBuilder::Location::binding(0u),
293 							 vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &bufferDescriptorInfo)
294 				.update(m_vk, m_context.getDevice());
295 	}
296 
297 	m_computeShaderModule	= vk::createShaderModule(m_vk, m_context.getDevice(), m_context.getBinaryCollection().get("vulkan/draw/NegateData.comp"), 0u);
298 	m_pipelineLayout		= vk::makePipelineLayout(m_vk, m_context.getDevice(), *m_descriptorSetLayout);
299 	m_computePipeline		= makeComputePipeline(m_vk, m_context.getDevice(), *m_pipelineLayout, *m_computeShaderModule);
300 
301 	const vk::VkBufferMemoryBarrier		hostWriteBarrier	= vk::makeBufferMemoryBarrier(vk::VK_ACCESS_HOST_WRITE_BIT, vk::VK_ACCESS_SHADER_READ_BIT, m_indirectBuffer->object(), 0ull, indirectBufferSize);
302 	const vk::VkBufferMemoryBarrier		indirectDrawBarrier	= vk::makeBufferMemoryBarrier(vk::VK_ACCESS_SHADER_WRITE_BIT, vk::VK_ACCESS_INDIRECT_COMMAND_READ_BIT, m_indirectBuffer->object(), 0ull, indirectBufferSize);
303 
304 	m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, *m_computePipeline);
305 	m_vk.cmdBindDescriptorSets(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, *m_pipelineLayout, 0u, 1u, &m_descriptorSetIndirectBuffer.get(), 0u, DE_NULL);
306 	m_vk.cmdPipelineBarrier(*m_cmdBuffer, vk::VK_PIPELINE_STAGE_HOST_BIT, vk::VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, (vk::VkDependencyFlags)0, 0, (const vk::VkMemoryBarrier*)DE_NULL, 1, &hostWriteBarrier, 0, (const vk::VkImageMemoryBarrier*)DE_NULL);
307 	m_vk.cmdDispatch(*m_cmdBuffer, 1, 1, 1);
308 	m_vk.cmdPipelineBarrier(*m_cmdBuffer, vk::VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, vk::VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT, (vk::VkDependencyFlags)0, 0, (const vk::VkMemoryBarrier*)DE_NULL, 1, &indirectDrawBarrier, 0, (const vk::VkImageMemoryBarrier*)DE_NULL);
309 
310 	if (m_testIndirectCountExt != IndirectCountType::NONE)
311 	{
312 		m_vk.cmdBindDescriptorSets(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, *m_pipelineLayout, 0u, 1u, &m_descriptorSetCountBuffer.get(), 0u, DE_NULL);
313 		m_vk.cmdPipelineBarrier(*m_cmdBuffer, vk::VK_PIPELINE_STAGE_HOST_BIT, vk::VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, (vk::VkDependencyFlags)0, 0, (const vk::VkMemoryBarrier*)DE_NULL, 1, &hostWriteBarrier, 0, (const vk::VkImageMemoryBarrier*)DE_NULL);
314 		m_vk.cmdDispatch(*m_cmdBuffer, 1, 1, 1);
315 		m_vk.cmdPipelineBarrier(*m_cmdBuffer, vk::VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, vk::VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT, (vk::VkDependencyFlags)0, 0, (const vk::VkMemoryBarrier*)DE_NULL, 1, &indirectDrawBarrier, 0, (const vk::VkImageMemoryBarrier*)DE_NULL);
316 	}
317 }
318 
IndirectDraw(Context &context, TestSpec testSpec)319 IndirectDraw::IndirectDraw (Context &context, TestSpec testSpec)
320 	: DrawTestsBaseClass				(context, testSpec.shaders[glu::SHADERTYPE_VERTEX], testSpec.shaders[glu::SHADERTYPE_FRAGMENT], testSpec.groupParams, testSpec.topology)
321 	, m_testIndirectCountExt			(testSpec.testIndirectCountExt)
322 	, m_indirectCountExtDrawPadding		(1u)
323 	, m_drawType						(testSpec.drawType)
324 	, m_testFirstInstanceNdx			(testSpec.testFirstInstanceNdx)
325 	, m_dataFromComputeShader			(testSpec.dataFromCompute)
326 {
327 	if (m_testFirstInstanceNdx)
328 		setFirstInstanceVertexBuffer();
329 	else
330 		setVertexBuffer();
331 
332 	initialize();
333 
334 	if (testSpec.drawType == DRAW_TYPE_INDEXED)
335 	{
336 		const size_t indexBufferLength = m_data.size() - VERTEX_OFFSET;
337 
338 		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);
339 		deUint32* indices = reinterpret_cast<deUint32*>(m_indexBuffer->getBoundMemory().getHostPtr());
340 		for (size_t i = 0; i < indexBufferLength; i++)
341 		{
342 			indices[i] = static_cast<deUint32>(i);
343 		}
344 		vk::flushAlloc(m_vk, m_context.getDevice(), m_indexBuffer->getBoundMemory());
345 	}
346 
347 	// Check device for multidraw support:
348 	if (!m_context.getDeviceFeatures().multiDrawIndirect || m_testFirstInstanceNdx)
349 		m_isMultiDrawEnabled = false;
350 	else
351 		m_isMultiDrawEnabled = true;
352 
353 	m_drawIndirectMaxCount = m_context.getDeviceProperties().limits.maxDrawIndirectCount;
354 }
355 
356 template<>
addCommand(const vk::VkDrawIndirectCommand& command)357 void IndirectDraw::addCommand<vk::VkDrawIndirectCommand> (const vk::VkDrawIndirectCommand& command)
358 {
359 	DE_ASSERT(m_drawType == DRAW_TYPE_SEQUENTIAL);
360 
361 	const size_t currentSize = m_indirectBufferContents.size();
362 
363 	m_indirectBufferContents.resize(currentSize + sizeof(command));
364 
365 	deMemcpy(&m_indirectBufferContents[currentSize], &command, sizeof(command));
366 }
367 
368 template<>
addCommand(const vk::VkDrawIndexedIndirectCommand& command)369 void IndirectDraw::addCommand<vk::VkDrawIndexedIndirectCommand> (const vk::VkDrawIndexedIndirectCommand& command)
370 {
371 	DE_ASSERT(m_drawType == DRAW_TYPE_INDEXED);
372 
373 	const size_t currentSize = m_indirectBufferContents.size();
374 
375 	m_indirectBufferContents.resize(currentSize + sizeof(command));
376 
377 	deMemcpy(&m_indirectBufferContents[currentSize], &command, sizeof(command));
378 }
379 
draw(vk::VkCommandBuffer cmdBuffer)380 void IndirectDraw::draw (vk::VkCommandBuffer cmdBuffer)
381 {
382 	const vk::VkDeviceSize	vertexBufferOffset	= 0;
383 	const vk::VkBuffer		vertexBuffer		= m_vertexBuffer->object();
384 
385 	m_vk.cmdBindVertexBuffers(cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
386 	m_vk.cmdBindPipeline(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
387 	if (m_drawType == DRAW_TYPE_INDEXED)
388 		m_vk.cmdBindIndexBuffer(cmdBuffer, m_indexBuffer->object(), DE_NULL, vk::VK_INDEX_TYPE_UINT32);
389 
390 	if (m_isMultiDrawEnabled && m_drawCount <= m_drawIndirectMaxCount)
391 	{
392 		switch (m_drawType)
393 		{
394 			case DRAW_TYPE_SEQUENTIAL:
395 			{
396 				if (m_testIndirectCountExt != IndirectCountType::NONE)
397 				{
398 					const deUint32 maxDrawCount = m_drawCount + (m_testIndirectCountExt == IndirectCountType::BUFFER_LIMIT ? m_indirectCountExtDrawPadding : 0u);
399 					m_vk.cmdDrawIndirectCount(cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer,
400 											  m_indirectCountBuffer->object(), m_offsetInCountBuffer, maxDrawCount,
401 											  m_strideInBuffer);
402 				}
403 				else
404 					m_vk.cmdDrawIndirect(cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer, m_drawCount, m_strideInBuffer);
405 				break;
406 			}
407 			case DRAW_TYPE_INDEXED:
408 			{
409 				if (m_testIndirectCountExt != IndirectCountType::NONE)
410 				{
411 					const deUint32 maxDrawCount = m_drawCount + (m_testIndirectCountExt == IndirectCountType::BUFFER_LIMIT ? m_indirectCountExtDrawPadding : 0u);
412 					m_vk.cmdDrawIndexedIndirectCount(cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer,
413 													 m_indirectCountBuffer->object(), m_offsetInCountBuffer, maxDrawCount,
414 													 m_strideInBuffer);
415 				}
416 				else
417 					m_vk.cmdDrawIndexedIndirect(cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer, m_drawCount, m_strideInBuffer);
418 				break;
419 			}
420 			default:
421 				TCU_FAIL("impossible");
422 		}
423 	}
424 	else
425 	{
426 		for (deUint32 drawNdx = 0; drawNdx < m_drawCount; drawNdx++)
427 		{
428 			switch (m_drawType)
429 			{
430 				case DRAW_TYPE_SEQUENTIAL:
431 				{
432 					if (m_testIndirectCountExt != IndirectCountType::NONE)
433 					{
434 						const deUint32 maxDrawCount = (m_testIndirectCountExt == IndirectCountType::BUFFER_LIMIT ? m_drawCount + m_indirectCountExtDrawPadding : 1u);
435 						m_vk.cmdDrawIndirectCount(cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer + drawNdx*m_strideInBuffer,
436 												  m_indirectCountBuffer->object(), m_offsetInCountBuffer, maxDrawCount,
437 												  m_strideInBuffer);
438 					}
439 					else
440 						m_vk.cmdDrawIndirect(cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer + drawNdx*m_strideInBuffer, 1u, 0u);
441 					break;
442 				}
443 				case DRAW_TYPE_INDEXED:
444 				{
445 					if (m_testIndirectCountExt != IndirectCountType::NONE)
446 					{
447 						const deUint32 maxDrawCount = (m_testIndirectCountExt == IndirectCountType::BUFFER_LIMIT ? m_drawCount + m_indirectCountExtDrawPadding : 1u);
448 						m_vk.cmdDrawIndexedIndirectCount(cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer + drawNdx*m_strideInBuffer,
449 														 m_indirectCountBuffer->object(), m_offsetInCountBuffer, maxDrawCount,
450 														 m_strideInBuffer);
451 					}
452 					else
453 						m_vk.cmdDrawIndexedIndirect(cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer + drawNdx*m_strideInBuffer, 1u, 0u);
454 					break;
455 				}
456 				default:
457 					TCU_FAIL("impossible");
458 			}
459 		}
460 	}
461 }
462 
iterate(void)463 tcu::TestStatus IndirectDraw::iterate (void)
464 {
465 	tcu::TestLog&		log		= m_context.getTestContext().getLog();
466 	const vk::VkQueue	queue	= m_context.getUniversalQueue();
467 	const vk::VkDevice	device	= m_context.getDevice();
468 
469 					m_drawCount			= 2;
470 					m_offsetInBuffer	= sizeof(m_junkData);
471 	const deUint32	m_bufferDrawCount	= 2u * m_drawCount;
472 
473 	if (m_drawType == DRAW_TYPE_SEQUENTIAL)
474 	{
475 		switch (m_topology)
476 		{
477 		case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
478 		{
479 			vk::VkDrawIndirectCommand drawCommands[] =
480 			{
481 				{
482 					3u,									//vertexCount
483 					1u,									//instanceCount
484 					2u,									//firstVertex
485 					(m_testFirstInstanceNdx ? 1u : 0u)	//firstInstance
486 				},
487 				{ (deUint32)-4, (deUint32)-2, (deUint32)-11, (deUint32)-9 }, // junk (stride)
488 				{
489 					3u,									//vertexCount
490 					1u,									//instanceCount
491 					5u,									//firstVertex
492 					0u									//firstInstance
493 				}
494 			};
495 			addCommand(drawCommands[0]);
496 			addCommand(drawCommands[1]);
497 			addCommand(drawCommands[2]);
498 			addCommand(drawCommands[1]);
499 			if (m_testIndirectCountExt != IndirectCountType::NONE)
500 			{
501 				// Add padding data to the buffer to make sure it's large enough.
502 				for (deUint32 i = 0; i < m_bufferDrawCount; ++i)
503 				{
504 					addCommand(drawCommands[1]);
505 					addCommand(drawCommands[1]);
506 				}
507 			}
508 			break;
509 		}
510 		case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
511 		{
512 			vk::VkDrawIndirectCommand drawCommands[] =
513 			{
514 				{
515 					4u,									//vertexCount
516 					1u,									//instanceCount
517 					2u,									//firstVertex
518 					(m_testFirstInstanceNdx ? 1u : 0u)	//firstInstance
519 				},
520 				{ (deUint32)-4, (deUint32)-2, (deUint32)-11, (deUint32)-9 }, // junk (stride)
521 				{
522 					4u,									//vertexCount
523 					1u,									//instanceCount
524 					6u,									//firstVertex
525 					0u									//firstInstance
526 				}
527 			};
528 			addCommand(drawCommands[0]);
529 			addCommand(drawCommands[1]);
530 			addCommand(drawCommands[2]);
531 			addCommand(drawCommands[1]);
532 			if (m_testIndirectCountExt != IndirectCountType::NONE)
533 			{
534 				// Add padding data to the buffer to make sure it's large enough.
535 				for (deUint32 i = 0; i < m_bufferDrawCount; ++i)
536 				{
537 					addCommand(drawCommands[1]);
538 					addCommand(drawCommands[1]);
539 				}
540 			}
541 			break;
542 		}
543 		default:
544 			TCU_FAIL("impossible");
545 		}
546 
547 		m_strideInBuffer = 2 * (deUint32)sizeof(vk::VkDrawIndirectCommand);
548 	}
549 	else if (m_drawType == DRAW_TYPE_INDEXED)
550 	{
551 		switch (m_topology)
552 		{
553 		case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
554 		{
555 			vk::VkDrawIndexedIndirectCommand drawCommands[] =
556 			{
557 				{
558 					3u,									// indexCount
559 					1u,									// instanceCount
560 					2u,									// firstIndex
561 					VERTEX_OFFSET,						// vertexOffset
562 					(m_testFirstInstanceNdx ? 1u : 0u),	// firstInstance
563 				},
564 				{ (deUint32)-4, (deUint32)-2, (deUint32)-11, (deInt32)9, (deUint32)-7 }, // junk (stride)
565 				{
566 					3u,									// indexCount
567 					1u,									// instanceCount
568 					5u,									// firstIndex
569 					VERTEX_OFFSET,						// vertexOffset
570 					0u									// firstInstance
571 				}
572 			};
573 			addCommand(drawCommands[0]);
574 			addCommand(drawCommands[1]);
575 			addCommand(drawCommands[2]);
576 			addCommand(drawCommands[1]);
577 			if (m_testIndirectCountExt != IndirectCountType::NONE)
578 			{
579 				// Add padding data to the buffer to make sure it's large enough.
580 				for (deUint32 i = 0; i < m_bufferDrawCount; ++i)
581 				{
582 					addCommand(drawCommands[1]);
583 					addCommand(drawCommands[1]);
584 				}
585 			}
586 			break;
587 		}
588 		case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
589 		{
590 			vk::VkDrawIndexedIndirectCommand drawCommands[] =
591 			{
592 				{
593 					4u,									// indexCount
594 					1u,									// instanceCount
595 					2u,									// firstIndex
596 					VERTEX_OFFSET,						// vertexOffset
597 					(m_testFirstInstanceNdx ? 1u : 0u),	// firstInstance
598 				},
599 				{ (deUint32)-4, (deUint32)-2, (deUint32)-11, (deInt32)9, (deUint32)-7 }, // junk (stride)
600 				{
601 					4u,									// indexCount
602 					1u,									// instanceCount
603 					6u,									// firstIndex
604 					VERTEX_OFFSET,						// vertexOffset
605 					0u									// firstInstance
606 				}
607 			};
608 			addCommand(drawCommands[0]);
609 			addCommand(drawCommands[1]);
610 			addCommand(drawCommands[2]);
611 			addCommand(drawCommands[1]);
612 			if (m_testIndirectCountExt != IndirectCountType::NONE)
613 			{
614 				// Add padding data to the buffer to make sure it's large enough.
615 				for (deUint32 i = 0; i < m_bufferDrawCount; ++i)
616 				{
617 					addCommand(drawCommands[1]);
618 					addCommand(drawCommands[1]);
619 				}
620 			}
621 			break;
622 		}
623 		default:
624 			TCU_FAIL("impossible");
625 		}
626 
627 		m_strideInBuffer = 2 * (deUint32)sizeof(vk::VkDrawIndexedIndirectCommand);
628 	}
629 
630 	const vk::VkDeviceSize	dataSize			= m_indirectBufferContents.size();
631 	const vk::VkDeviceSize	indirectBufferSize	= dataSize + m_offsetInBuffer;
632 	vk::VkBufferUsageFlags	usageFlags			= vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT;
633 	if (m_dataFromComputeShader)
634 		usageFlags |= vk::VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
635 
636 	m_indirectBuffer = Buffer::createAndAlloc(	m_vk,
637 												m_context.getDevice(),
638 												BufferCreateInfo(indirectBufferSize, usageFlags),
639 												m_context.getDefaultAllocator(),
640 												vk::MemoryRequirement::HostVisible);
641 
642 	deUint8* ptr = reinterpret_cast<deUint8*>(m_indirectBuffer->getBoundMemory().getHostPtr());
643 
644 	deMemcpy(ptr, &m_junkData, static_cast<size_t>(m_offsetInBuffer));
645 	deMemcpy(ptr + m_offsetInBuffer, &m_indirectBufferContents[0], static_cast<size_t>(dataSize));
646 
647 	if (m_dataFromComputeShader)
648 	{
649 		// Negate all the buffer data and let a compute shader restore it to original.
650 		for (int i = 0; i < static_cast<int>(indirectBufferSize); i++)
651 		{
652 			ptr[i] = static_cast<deUint8>(~ptr[i]);
653 		}
654 	}
655 
656 	vk::flushAlloc(m_vk, m_context.getDevice(), m_indirectBuffer->getBoundMemory());
657 
658 	m_offsetInCountBuffer = sizeof(tcu::Vec3);
659 	const vk::VkDeviceSize countBufferSize	= m_offsetInCountBuffer + sizeof(m_drawCount);
660 
661 	if (m_testIndirectCountExt != IndirectCountType::NONE)
662 	{
663 		m_indirectCountBuffer = Buffer::createAndAlloc(m_vk,
664 													   m_context.getDevice(),
665 													   BufferCreateInfo(countBufferSize, usageFlags),
666 													   m_context.getDefaultAllocator(),
667 													   vk::MemoryRequirement::HostVisible);
668 
669 		deUint8* countBufferPtr = reinterpret_cast<deUint8*>(m_indirectCountBuffer->getBoundMemory().getHostPtr());
670 
671 		// For IndirectCountType::PARAM_LIMIT, the real limit will be set using the call parameter.
672 		if (m_isMultiDrawEnabled && m_drawCount <= m_drawIndirectMaxCount)
673 			*(deUint32*)(countBufferPtr + m_offsetInCountBuffer) = m_drawCount + (m_testIndirectCountExt == IndirectCountType::BUFFER_LIMIT ? 0u : m_indirectCountExtDrawPadding);
674 		else
675 			*(deUint32*)(countBufferPtr + m_offsetInCountBuffer) = (m_testIndirectCountExt == IndirectCountType::BUFFER_LIMIT ? 1u : m_drawCount + m_indirectCountExtDrawPadding);
676 
677 		if (m_dataFromComputeShader)
678 		{
679 			// Negate all the buffer data and let a compute shader restore it to original.
680 			for (int i = 0; i < static_cast<int>(countBufferSize); i++)
681 			{
682 				countBufferPtr[i] = static_cast<deUint8>(~countBufferPtr[i]);
683 			}
684 		}
685 
686 		vk::flushAlloc(m_vk, m_context.getDevice(), m_indirectCountBuffer->getBoundMemory());
687 	}
688 
689 #ifndef CTS_USES_VULKANSC
690 	if (m_groupParams->useSecondaryCmdBuffer)
691 	{
692 		// record secondary command buffer
693 		if (m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
694 		{
695 			beginSecondaryCmdBuffer(m_vk, vk::VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT);
696 			beginDynamicRender(*m_secCmdBuffer);
697 		}
698 		else
699 			beginSecondaryCmdBuffer(m_vk);
700 
701 		draw(*m_secCmdBuffer);
702 
703 		if (m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
704 			endDynamicRender(*m_secCmdBuffer);
705 
706 		endCommandBuffer(m_vk, *m_secCmdBuffer);
707 
708 		// record primary command buffer
709 		beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
710 
711 		if (m_dataFromComputeShader)
712 			negateDataUsingCompute(indirectBufferSize, countBufferSize);
713 
714 		preRenderBarriers();
715 
716 		if (!m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
717 			beginDynamicRender(*m_cmdBuffer, vk::VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
718 
719 		m_vk.cmdExecuteCommands(*m_cmdBuffer, 1u, &*m_secCmdBuffer);
720 
721 		if (!m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
722 			endDynamicRender(*m_cmdBuffer);
723 
724 		endCommandBuffer(m_vk, *m_cmdBuffer);
725 	}
726 	else if (m_groupParams->useDynamicRendering)
727 	{
728 		beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
729 
730 		if (m_dataFromComputeShader)
731 			negateDataUsingCompute(indirectBufferSize, countBufferSize);
732 
733 		preRenderBarriers();
734 		beginDynamicRender(*m_cmdBuffer);
735 
736 		draw(*m_cmdBuffer);
737 
738 		endDynamicRender(*m_cmdBuffer);
739 		endCommandBuffer(m_vk, *m_cmdBuffer);
740 	}
741 #endif // CTS_USES_VULKANSC
742 
743 	if (!m_groupParams->useDynamicRendering)
744 	{
745 		beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
746 
747 		if (m_dataFromComputeShader)
748 			negateDataUsingCompute(indirectBufferSize, countBufferSize);
749 
750 		preRenderBarriers();
751 		beginLegacyRender(*m_cmdBuffer);
752 
753 		draw(*m_cmdBuffer);
754 
755 		endLegacyRender(*m_cmdBuffer);
756 		endCommandBuffer(m_vk, *m_cmdBuffer);
757 	}
758 
759 	submitCommandsAndWait(m_vk, device, queue, m_cmdBuffer.get());
760 
761 	// Validation
762 	tcu::Texture2D referenceFrame(vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5f + static_cast<float>(WIDTH)), (int)(0.5f + static_cast<float>(HEIGHT)));
763 	referenceFrame.allocLevel(0);
764 
765 	const deInt32 frameWidth	= referenceFrame.getWidth();
766 	const deInt32 frameHeight	= referenceFrame.getHeight();
767 
768 	tcu::clear(referenceFrame.getLevel(0), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
769 
770 	ReferenceImageCoordinates refCoords;
771 
772 	for (int y = 0; y < frameHeight; y++)
773 	{
774 		const float yCoord = (float)(y / (0.5*frameHeight)) - 1.0f;
775 
776 		for (int x = 0; x < frameWidth; x++)
777 		{
778 			const float xCoord = (float)(x / (0.5*frameWidth)) - 1.0f;
779 
780 			if ((yCoord >= refCoords.bottom	&&
781 				 yCoord <= refCoords.top	&&
782 				 xCoord >= refCoords.left	&&
783 				 xCoord <= refCoords.right))
784 				referenceFrame.getLevel(0).setPixel(tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f), x, y);
785 		}
786 	}
787 
788 	const vk::VkOffset3D zeroOffset					= { 0, 0, 0 };
789 	const tcu::ConstPixelBufferAccess renderedFrame = m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(),
790 		vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
791 
792 	qpTestResult res = QP_TEST_RESULT_PASS;
793 
794 	if (!tcu::fuzzyCompare(log, "Result", "Image comparison result",
795 		referenceFrame.getLevel(0), renderedFrame, 0.05f, tcu::COMPARE_LOG_RESULT))
796 	{
797 		res = QP_TEST_RESULT_FAIL;
798 	}
799 
800 	return tcu::TestStatus(res, qpGetTestResultName(res));
801 }
802 
803 template<class FirstInstanceSupport>
IndirectDrawInstanced(Context &context, TestSpec testSpec)804 IndirectDrawInstanced<FirstInstanceSupport>::IndirectDrawInstanced (Context &context, TestSpec testSpec)
805 	: IndirectDraw(context, testSpec)
806 {
807 	if (!FirstInstanceSupport::isTestSupported(m_context.getDeviceFeatures()))
808 	{
809 		throw tcu::NotSupportedError("Required 'drawIndirectFirstInstance' feature is not supported");
810 	}
811 }
812 
813 template<class FirstInstanceSupport>
iterate(void)814 tcu::TestStatus IndirectDrawInstanced<FirstInstanceSupport>::iterate (void)
815 {
816 	tcu::TestLog&		log		= m_context.getTestContext().getLog();
817 	const vk::VkQueue	queue	= m_context.getUniversalQueue();
818 	const vk::VkDevice	device	= m_context.getDevice();
819 
820 					m_drawCount			= 2;
821 					m_offsetInBuffer	= sizeof(m_junkData);
822 	const deUint32	m_bufferDrawCount	= 2u * m_drawCount;
823 
824 	if (m_drawType == DRAW_TYPE_SEQUENTIAL)
825 	{
826 		switch (m_topology)
827 		{
828 			case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
829 			{
830 				vk::VkDrawIndirectCommand drawCmd[] =
831 				{
832 					{
833 						3,											//vertexCount
834 						4,											//instanceCount
835 						2,											//firstVertex
836 						FirstInstanceSupport::getFirstInstance()	//firstInstance
837 					},
838 					{ (deUint32)-4, (deUint32)-2, (deUint32)-11, (deUint32)-9 }, // junk (stride)
839 					{
840 						3,											//vertexCount
841 						4,											//instanceCount
842 						5,											//firstVertex
843 						FirstInstanceSupport::getFirstInstance()	//firstInstance
844 					}
845 				};
846 				addCommand(drawCmd[0]);
847 				addCommand(drawCmd[1]);
848 				addCommand(drawCmd[2]);
849 				if (m_testIndirectCountExt != IndirectCountType::NONE)
850 				{
851 					// Add padding data to the buffer to make sure it's large enough.
852 					for (deUint32 i = 0; i < m_bufferDrawCount; ++i)
853 					{
854 						addCommand(drawCmd[1]);
855 						addCommand(drawCmd[1]);
856 					}
857 				}
858 				break;
859 			}
860 			case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
861 			{
862 				vk::VkDrawIndirectCommand drawCmd[] =
863 				{
864 					{
865 						4,											//vertexCount
866 						4,											//instanceCount
867 						2,											//firstVertex
868 						FirstInstanceSupport::getFirstInstance()	//firstInstance
869 					},
870 					{ (deUint32)-4, (deUint32)-2, (deUint32)-11, (deUint32)-9 },
871 					{
872 						4,											//vertexCount
873 						4,											//instanceCount
874 						6,											//firstVertex
875 						FirstInstanceSupport::getFirstInstance()	//firstInstance
876 					}
877 				};
878 				addCommand(drawCmd[0]);
879 				addCommand(drawCmd[1]);
880 				addCommand(drawCmd[2]);
881 				if (m_testIndirectCountExt != IndirectCountType::NONE)
882 				{
883 					// Add padding data to the buffer to make sure it's large enough.
884 					for (deUint32 i = 0; i < m_bufferDrawCount; ++i)
885 					{
886 						addCommand(drawCmd[1]);
887 						addCommand(drawCmd[1]);
888 					}
889 				}
890 				break;
891 			}
892 			default:
893 				TCU_FAIL("impossible");
894 				break;
895 		}
896 
897 		m_strideInBuffer = 2 * (deUint32)sizeof(vk::VkDrawIndirectCommand);
898 	}
899 	else if (m_drawType == DRAW_TYPE_INDEXED)
900 	{
901 		switch (m_topology)
902 		{
903 			case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
904 			{
905 				vk::VkDrawIndexedIndirectCommand drawCmd[] =
906 				{
907 					{
908 						3,											// indexCount
909 						4,											// instanceCount
910 						2,											// firstIndex
911 						VERTEX_OFFSET,								// vertexOffset
912 						FirstInstanceSupport::getFirstInstance()	// firstInstance
913 					},
914 					{ (deUint32)-4, (deUint32)-2, (deUint32)-11, (deInt32)9, (deUint32)-7 },	// junk (stride)
915 					{
916 						3,											// indexCount
917 						4,											// instanceCount
918 						5,											// firstIndex
919 						VERTEX_OFFSET,								// vertexOffset
920 						FirstInstanceSupport::getFirstInstance()	// firstInstance
921 					}
922 				};
923 				addCommand(drawCmd[0]);
924 				addCommand(drawCmd[1]);
925 				addCommand(drawCmd[2]);
926 				if (m_testIndirectCountExt != IndirectCountType::NONE)
927 				{
928 					// Add padding data to the buffer to make sure it's large enough.
929 					for (deUint32 i = 0; i < m_bufferDrawCount; ++i)
930 					{
931 						addCommand(drawCmd[1]);
932 						addCommand(drawCmd[1]);
933 					}
934 				}
935 				break;
936 			}
937 			case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
938 			{
939 				vk::VkDrawIndexedIndirectCommand drawCmd[] =
940 				{
941 					{
942 						4,											// indexCount
943 						4,											// instanceCount
944 						2,											// firstIndex
945 						VERTEX_OFFSET,								// vertexOffset
946 						FirstInstanceSupport::getFirstInstance()	// firstInstance
947 					},
948 					{ (deUint32)-4, (deUint32)-2, (deUint32)-11, (deInt32)9, (deUint32)-7 },	// junk (stride)
949 					{
950 						4,											// indexCount
951 						4,											// instanceCount
952 						6,											// firstIndex
953 						VERTEX_OFFSET,								// vertexOffset
954 						FirstInstanceSupport::getFirstInstance()	// firstInstance
955 					}
956 				};
957 				addCommand(drawCmd[0]);
958 				addCommand(drawCmd[1]);
959 				addCommand(drawCmd[2]);
960 				if (m_testIndirectCountExt != IndirectCountType::NONE)
961 				{
962 					// Add padding data to the buffer to make sure it's large enough.
963 					for (deUint32 i = 0; i < m_bufferDrawCount; ++i)
964 					{
965 						addCommand(drawCmd[1]);
966 						addCommand(drawCmd[1]);
967 					}
968 				}
969 				break;
970 			}
971 			default:
972 				TCU_FAIL("impossible");
973 				break;
974 		}
975 
976 		m_strideInBuffer = 2 * (deUint32)sizeof(vk::VkDrawIndexedIndirectCommand);
977 	}
978 
979 	const vk::VkDeviceSize dataSize				= m_indirectBufferContents.size();
980 	const vk::VkDeviceSize indirectBufferSize	= dataSize + m_offsetInBuffer;
981 	vk::VkBufferUsageFlags	usageFlags			= vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT;
982 	if (m_dataFromComputeShader)
983 		usageFlags |= vk::VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
984 
985 	m_indirectBuffer = Buffer::createAndAlloc(	m_vk,
986 												m_context.getDevice(),
987 												BufferCreateInfo(indirectBufferSize, usageFlags),
988 												m_context.getDefaultAllocator(),
989 												vk::MemoryRequirement::HostVisible);
990 
991 	deUint8* ptr = reinterpret_cast<deUint8*>(m_indirectBuffer->getBoundMemory().getHostPtr());
992 
993 	deMemcpy(ptr, &m_junkData, static_cast<size_t>(m_offsetInBuffer));
994 	deMemcpy((ptr + m_offsetInBuffer), &m_indirectBufferContents[0], static_cast<size_t>(dataSize));
995 
996 	if (m_dataFromComputeShader)
997 	{
998 		// Negate all the buffer data and let a compute shader restore it to original.
999 		for (int i = 0; i < static_cast<int>(indirectBufferSize); i++)
1000 		{
1001 			ptr[i] = static_cast<deUint8>(~ptr[i]);
1002 		}
1003 	}
1004 
1005 	vk::flushAlloc(m_vk, m_context.getDevice(), m_indirectBuffer->getBoundMemory());
1006 
1007 	m_offsetInCountBuffer = sizeof(tcu::Vec3);
1008 	const vk::VkDeviceSize	countBufferSize	= m_offsetInCountBuffer + sizeof(m_drawCount);
1009 
1010 	if (m_testIndirectCountExt != IndirectCountType::NONE)
1011 	{
1012 		m_indirectCountBuffer = Buffer::createAndAlloc(m_vk,
1013 													   m_context.getDevice(),
1014 													   BufferCreateInfo(countBufferSize, usageFlags),
1015 													   m_context.getDefaultAllocator(),
1016 													   vk::MemoryRequirement::HostVisible);
1017 
1018 		deUint8* countBufferPtr = reinterpret_cast<deUint8*>(m_indirectCountBuffer->getBoundMemory().getHostPtr());
1019 
1020 		// For IndirectCountType::PARAM_LIMIT, the real limit will be set using the call parameter.
1021 		if (m_isMultiDrawEnabled && m_drawCount <= m_drawIndirectMaxCount)
1022 			*(deUint32*)(countBufferPtr + m_offsetInCountBuffer) = m_drawCount + (m_testIndirectCountExt == IndirectCountType::BUFFER_LIMIT ? 0u : m_indirectCountExtDrawPadding);
1023 		else
1024 			*(deUint32*)(countBufferPtr + m_offsetInCountBuffer) = 1u;
1025 
1026 		if (m_dataFromComputeShader)
1027 		{
1028 			// Negate all the buffer data and let a compute shader restore it to original.
1029 			for (int i = 0; i < static_cast<int>(countBufferSize); i++)
1030 			{
1031 				countBufferPtr[i] = static_cast<deUint8>(~countBufferPtr[i]);
1032 			}
1033 		}
1034 
1035 		vk::flushAlloc(m_vk, m_context.getDevice(), m_indirectCountBuffer->getBoundMemory());
1036 	}
1037 
1038 #ifndef CTS_USES_VULKANSC
1039 	if (m_groupParams->useSecondaryCmdBuffer)
1040 	{
1041 		// record secondary command buffer
1042 		if (m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
1043 		{
1044 			beginSecondaryCmdBuffer(m_vk, vk::VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT);
1045 			beginDynamicRender(*m_secCmdBuffer);
1046 		}
1047 		else
1048 			beginSecondaryCmdBuffer(m_vk);
1049 
1050 		draw(*m_secCmdBuffer);
1051 
1052 		if (m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
1053 			endDynamicRender(*m_secCmdBuffer);
1054 
1055 		endCommandBuffer(m_vk, *m_secCmdBuffer);
1056 
1057 		// record primary command buffer
1058 		beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
1059 
1060 		if (m_dataFromComputeShader)
1061 			negateDataUsingCompute(indirectBufferSize, countBufferSize);
1062 
1063 		preRenderBarriers();
1064 
1065 		if (!m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
1066 			beginDynamicRender(*m_cmdBuffer, vk::VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
1067 
1068 		m_vk.cmdExecuteCommands(*m_cmdBuffer, 1u, &*m_secCmdBuffer);
1069 
1070 		if (!m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
1071 			endDynamicRender(*m_cmdBuffer);
1072 
1073 		endCommandBuffer(m_vk, *m_cmdBuffer);
1074 	}
1075 	else if(m_groupParams->useDynamicRendering)
1076 	{
1077 		beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
1078 
1079 		if (m_dataFromComputeShader)
1080 			negateDataUsingCompute(indirectBufferSize, countBufferSize);
1081 
1082 		preRenderBarriers();
1083 		beginDynamicRender(*m_cmdBuffer);
1084 		draw(*m_cmdBuffer);
1085 		endDynamicRender(*m_cmdBuffer);
1086 
1087 		endCommandBuffer(m_vk, *m_cmdBuffer);
1088 	}
1089 #endif // CTS_USES_VULKANSC
1090 
1091 	if (!m_groupParams->useDynamicRendering)
1092 	{
1093 		beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
1094 
1095 		if (m_dataFromComputeShader)
1096 			negateDataUsingCompute(indirectBufferSize, countBufferSize);
1097 
1098 		preRenderBarriers();
1099 		beginLegacyRender(*m_cmdBuffer);
1100 		draw(*m_cmdBuffer);
1101 		endLegacyRender(*m_cmdBuffer);
1102 
1103 		endCommandBuffer(m_vk, *m_cmdBuffer);
1104 	}
1105 
1106 	submitCommandsAndWait(m_vk, device, queue, m_cmdBuffer.get());
1107 
1108 	// Validation
1109 	VK_CHECK(m_vk.queueWaitIdle(queue));
1110 
1111 	tcu::Texture2D referenceFrame(vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5f + static_cast<float>(WIDTH)), (int)(0.5 + static_cast<float>(HEIGHT)));
1112 
1113 	referenceFrame.allocLevel(0);
1114 
1115 	const deInt32 frameWidth	= referenceFrame.getWidth();
1116 	const deInt32 frameHeight	= referenceFrame.getHeight();
1117 
1118 	tcu::clear(referenceFrame.getLevel(0), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
1119 
1120 	ReferenceImageInstancedCoordinates refInstancedCoords;
1121 
1122 	for (int y = 0; y < frameHeight; y++)
1123 	{
1124 		const float yCoord = (float)(y / (0.5*frameHeight)) - 1.0f;
1125 
1126 		for (int x = 0; x < frameWidth; x++)
1127 		{
1128 			const float xCoord = (float)(x / (0.5*frameWidth)) - 1.0f;
1129 
1130 			if ((yCoord >= refInstancedCoords.bottom	&&
1131 				 yCoord <= refInstancedCoords.top		&&
1132 				 xCoord >= refInstancedCoords.left		&&
1133 				 xCoord <= refInstancedCoords.right))
1134 				referenceFrame.getLevel(0).setPixel(tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f), x, y);
1135 		}
1136 	}
1137 
1138 	const vk::VkOffset3D zeroOffset = { 0, 0, 0 };
1139 	const tcu::ConstPixelBufferAccess renderedFrame = m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(),
1140 		vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
1141 
1142 	qpTestResult res = QP_TEST_RESULT_PASS;
1143 
1144 	if (!tcu::fuzzyCompare(log, "Result", "Image comparison result",
1145 		referenceFrame.getLevel(0), renderedFrame, 0.05f, tcu::COMPARE_LOG_RESULT))
1146 	{
1147 		res = QP_TEST_RESULT_FAIL;
1148 	}
1149 
1150 	return tcu::TestStatus(res, qpGetTestResultName(res));
1151 }
1152 
checkSupport(Context& context, IndirectDraw::TestSpec testSpec)1153 void checkSupport(Context& context, IndirectDraw::TestSpec testSpec)
1154 {
1155 	if (testSpec.testIndirectCountExt != IndirectCountType::NONE)
1156 		context.requireDeviceFunctionality("VK_KHR_draw_indirect_count");
1157 
1158 	if (testSpec.groupParams->useDynamicRendering)
1159 		context.requireDeviceFunctionality("VK_KHR_dynamic_rendering");
1160 }
1161 
1162 }	// anonymous
1163 
IndirectDrawTests(tcu::TestContext& testCtx, const SharedGroupParams groupParams)1164 IndirectDrawTests::IndirectDrawTests (tcu::TestContext& testCtx, const SharedGroupParams groupParams)
1165 	: TestCaseGroup		(testCtx, "indirect_draw", "indirect drawing simple geometry")
1166 	, m_groupParams		(groupParams)
1167 {
1168 	/* Left blank on purpose */
1169 }
1170 
~IndirectDrawTests(void)1171 IndirectDrawTests::~IndirectDrawTests (void) {}
1172 
1173 
init(void)1174 void IndirectDrawTests::init (void)
1175 {
1176 	for (auto dataFromCompute : {false, true})
1177 	for (int drawTypeIdx = 0; drawTypeIdx < DRAWTYPE_LAST; drawTypeIdx++)
1178 	{
1179 		// reduce number of tests for dynamic rendering cases where secondary command buffer is used
1180 		if (m_groupParams->useSecondaryCmdBuffer && (dataFromCompute == m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass))
1181 			continue;
1182 
1183 		std::string drawTypeStr;
1184 		switch (drawTypeIdx)
1185 		{
1186 			case DRAW_TYPE_SEQUENTIAL:
1187 				drawTypeStr = "sequential";
1188 				break;
1189 			case DRAW_TYPE_INDEXED:
1190 				drawTypeStr = "indexed";
1191 				break;
1192 			default:
1193 				TCU_FAIL("impossible");
1194 		}
1195 
1196 		if (dataFromCompute)
1197 			drawTypeStr += "_data_from_compute";
1198 
1199 		tcu::TestCaseGroup* drawTypeGroup = new tcu::TestCaseGroup(m_testCtx, drawTypeStr.c_str(), ("Draws geometry using " + drawTypeStr + "draw call").c_str());
1200 		{
1201 			tcu::TestCaseGroup* indirectDrawGroup			= new tcu::TestCaseGroup(m_testCtx, "indirect_draw", "Draws geometry");
1202 			tcu::TestCaseGroup* indirectDrawCountGroup		= new tcu::TestCaseGroup(m_testCtx, "indirect_draw_count", "Draws geometry with VK_KHR_draw_indirect_count extension");
1203 			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");
1204 			{
1205 				IndirectDraw::TestSpec testSpec(m_groupParams);
1206 				testSpec.drawType = static_cast<DrawType>(drawTypeIdx);
1207 				testSpec.dataFromCompute = dataFromCompute;
1208 				testSpec.shaders[glu::SHADERTYPE_VERTEX] = "vulkan/draw/VertexFetch.vert";
1209 				testSpec.shaders[glu::SHADERTYPE_FRAGMENT] = "vulkan/draw/VertexFetch.frag";
1210 				if (dataFromCompute)
1211 					testSpec.shaders[glu::SHADERTYPE_COMPUTE] = "vulkan/draw/NegateData.comp";
1212 
1213 				testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1214 				indirectDrawGroup->addChild(new InstanceFactory<IndirectDraw, FunctionSupport1<IndirectDraw::TestSpec> >
1215 					(m_testCtx, "triangle_list", "Draws triangle list", testSpec, FunctionSupport1<IndirectDraw::TestSpec>::Args(checkSupport, testSpec)));
1216 				testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1217 				indirectDrawGroup->addChild(new InstanceFactory<IndirectDraw, FunctionSupport1<IndirectDraw::TestSpec> >
1218 					(m_testCtx, "triangle_strip", "Draws triangle strip", testSpec, FunctionSupport1<IndirectDraw::TestSpec>::Args(checkSupport, testSpec)));
1219 
1220 				testSpec.testIndirectCountExt = IndirectCountType::BUFFER_LIMIT;
1221 				testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1222 				indirectDrawCountGroup->addChild(new InstanceFactory<IndirectDraw, FunctionSupport1<IndirectDraw::TestSpec> >
1223 					(m_testCtx, "triangle_list", "Draws triangle list", testSpec, FunctionSupport1<IndirectDraw::TestSpec>::Args(checkSupport, testSpec)));
1224 				testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1225 				indirectDrawCountGroup->addChild(new InstanceFactory<IndirectDraw, FunctionSupport1<IndirectDraw::TestSpec> >
1226 					(m_testCtx, "triangle_strip", "Draws triangle strip", testSpec, FunctionSupport1<IndirectDraw::TestSpec>::Args(checkSupport, testSpec)));
1227 
1228 				testSpec.testIndirectCountExt = IndirectCountType::PARAM_LIMIT;
1229 				testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1230 				indirectDrawParamCountGroup->addChild(new InstanceFactory<IndirectDraw, FunctionSupport1<IndirectDraw::TestSpec> >
1231 					(m_testCtx, "triangle_list", "Draws triangle list", testSpec, FunctionSupport1<IndirectDraw::TestSpec>::Args(checkSupport, testSpec)));
1232 				testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1233 				indirectDrawParamCountGroup->addChild(new InstanceFactory<IndirectDraw, FunctionSupport1<IndirectDraw::TestSpec> >
1234 					(m_testCtx, "triangle_strip", "Draws triangle strip", testSpec, FunctionSupport1<IndirectDraw::TestSpec>::Args(checkSupport, testSpec)));
1235 			}
1236 			drawTypeGroup->addChild(indirectDrawGroup);
1237 			drawTypeGroup->addChild(indirectDrawCountGroup);
1238 			drawTypeGroup->addChild(indirectDrawParamCountGroup);
1239 
1240 			{
1241 				tcu::TestCaseGroup* indirectDrawFirstInstanceGroup				= new tcu::TestCaseGroup(m_testCtx, "indirect_draw_first_instance", "Draws geometry with different first instance in one commandbuffer");
1242 				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");
1243 				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");
1244 				{
1245 					IndirectDraw::TestSpec testSpec(m_groupParams);
1246 					testSpec.testFirstInstanceNdx = true;
1247 					testSpec.drawType = static_cast<DrawType>(drawTypeIdx);
1248 					testSpec.dataFromCompute = dataFromCompute;
1249 					testSpec.shaders[glu::SHADERTYPE_VERTEX] = "vulkan/draw/VertexFetchInstanceIndex.vert";
1250 					testSpec.shaders[glu::SHADERTYPE_FRAGMENT] = "vulkan/draw/VertexFetch.frag";
1251 					if (dataFromCompute)
1252 						testSpec.shaders[glu::SHADERTYPE_COMPUTE] = "vulkan/draw/NegateData.comp";
1253 
1254 					testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1255 					indirectDrawFirstInstanceGroup->addChild(new InstanceFactory<IndirectDraw, FunctionSupport1<IndirectDraw::TestSpec> >
1256 						(m_testCtx, "triangle_list", "Draws triangle list", testSpec, FunctionSupport1<IndirectDraw::TestSpec>::Args(checkSupport, testSpec)));
1257 					testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1258 					indirectDrawFirstInstanceGroup->addChild(new InstanceFactory<IndirectDraw, FunctionSupport1<IndirectDraw::TestSpec> >
1259 						(m_testCtx, "triangle_strip", "Draws triangle strip", testSpec, FunctionSupport1<IndirectDraw::TestSpec>::Args(checkSupport, testSpec)));
1260 
1261 					testSpec.testIndirectCountExt = IndirectCountType::BUFFER_LIMIT;
1262 					testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1263 					indirectDrawCountFirstInstanceGroup->addChild(new InstanceFactory<IndirectDraw, FunctionSupport1<IndirectDraw::TestSpec> >
1264 						(m_testCtx, "triangle_list", "Draws triangle list", testSpec, FunctionSupport1<IndirectDraw::TestSpec>::Args(checkSupport, testSpec)));
1265 					testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1266 					indirectDrawCountFirstInstanceGroup->addChild(new InstanceFactory<IndirectDraw, FunctionSupport1<IndirectDraw::TestSpec> >
1267 						(m_testCtx, "triangle_strip", "Draws triangle strip", testSpec, FunctionSupport1<IndirectDraw::TestSpec>::Args(checkSupport, testSpec)));
1268 
1269 					testSpec.testIndirectCountExt = IndirectCountType::PARAM_LIMIT;
1270 					testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1271 					indirectDrawParamCountFirstInstanceGroup->addChild(new InstanceFactory<IndirectDraw, FunctionSupport1<IndirectDraw::TestSpec> >
1272 						(m_testCtx, "triangle_list", "Draws triangle list", testSpec, FunctionSupport1<IndirectDraw::TestSpec>::Args(checkSupport, testSpec)));
1273 					testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1274 					indirectDrawParamCountFirstInstanceGroup->addChild(new InstanceFactory<IndirectDraw, FunctionSupport1<IndirectDraw::TestSpec> >
1275 						(m_testCtx, "triangle_strip", "Draws triangle strip", testSpec, FunctionSupport1<IndirectDraw::TestSpec>::Args(checkSupport, testSpec)));
1276 				}
1277 				drawTypeGroup->addChild(indirectDrawFirstInstanceGroup);
1278 				drawTypeGroup->addChild(indirectDrawCountFirstInstanceGroup);
1279 				drawTypeGroup->addChild(indirectDrawParamCountFirstInstanceGroup);
1280 			}
1281 
1282 			tcu::TestCaseGroup* indirectDrawInstancedGroup				= new tcu::TestCaseGroup(m_testCtx, "indirect_draw_instanced", "Draws an instanced geometry");
1283 			tcu::TestCaseGroup* indirectDrawCountInstancedGroup			= new tcu::TestCaseGroup(m_testCtx, "indirect_draw_count_instanced", "Draws an instanced geometry with VK_KHR_draw_indirect_count extension");
1284 			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");
1285 			{
1286 				tcu::TestCaseGroup*	indirectDrawNoFirstInstanceGroup			= new tcu::TestCaseGroup(m_testCtx, "no_first_instance", "Use 0 as firstInstance");
1287 				tcu::TestCaseGroup*	indirectDrawCountNoFirstInstanceGroup		= new tcu::TestCaseGroup(m_testCtx, "no_first_instance", "Use 0 as firstInstance");
1288 				tcu::TestCaseGroup*	indirectDrawParamCountNoFirstInstanceGroup	= new tcu::TestCaseGroup(m_testCtx, "no_first_instance", "Use 0 as firstInstance");
1289 				{
1290 					typedef IndirectDrawInstanced<FirstInstanceNotSupported> IDFirstInstanceNotSupported;
1291 
1292 					IDFirstInstanceNotSupported::TestSpec testSpec(m_groupParams);
1293 					testSpec.drawType = static_cast<DrawType>(drawTypeIdx);
1294 					testSpec.dataFromCompute = dataFromCompute;
1295 
1296 					testSpec.shaders[glu::SHADERTYPE_VERTEX] = "vulkan/draw/VertexFetchInstanced.vert";
1297 					testSpec.shaders[glu::SHADERTYPE_FRAGMENT] = "vulkan/draw/VertexFetch.frag";
1298 					if (dataFromCompute)
1299 						testSpec.shaders[glu::SHADERTYPE_COMPUTE] = "vulkan/draw/NegateData.comp";
1300 
1301 					testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1302 					indirectDrawNoFirstInstanceGroup->addChild(new InstanceFactory<IDFirstInstanceNotSupported, FunctionSupport1<IDFirstInstanceNotSupported::TestSpec> >
1303 						(m_testCtx, "triangle_list", "Draws an instanced triangle list", testSpec, FunctionSupport1<IDFirstInstanceNotSupported::TestSpec>::Args(checkSupport, testSpec)));
1304 					testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1305 					indirectDrawNoFirstInstanceGroup->addChild(new InstanceFactory<IDFirstInstanceNotSupported, FunctionSupport1<IDFirstInstanceNotSupported::TestSpec> >
1306 						(m_testCtx, "triangle_strip", "Draws an instanced triangle strip", testSpec, FunctionSupport1<IDFirstInstanceNotSupported::TestSpec>::Args(checkSupport, testSpec)));
1307 
1308 					testSpec.testIndirectCountExt = IndirectCountType::BUFFER_LIMIT;
1309 					testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1310 					indirectDrawCountNoFirstInstanceGroup->addChild(new InstanceFactory<IDFirstInstanceNotSupported, FunctionSupport1<IDFirstInstanceNotSupported::TestSpec> >
1311 						(m_testCtx, "triangle_list", "Draws an instanced triangle list", testSpec, FunctionSupport1<IDFirstInstanceNotSupported::TestSpec>::Args(checkSupport, testSpec)));
1312 					testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1313 					indirectDrawCountNoFirstInstanceGroup->addChild(new InstanceFactory<IDFirstInstanceNotSupported, FunctionSupport1<IDFirstInstanceNotSupported::TestSpec> >
1314 						(m_testCtx, "triangle_strip", "Draws an instanced triangle strip", testSpec, FunctionSupport1<IDFirstInstanceNotSupported::TestSpec>::Args(checkSupport, testSpec)));
1315 
1316 					testSpec.testIndirectCountExt = IndirectCountType::PARAM_LIMIT;
1317 					testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1318 					indirectDrawParamCountNoFirstInstanceGroup->addChild(new InstanceFactory<IDFirstInstanceNotSupported, FunctionSupport1<IDFirstInstanceNotSupported::TestSpec> >
1319 						(m_testCtx, "triangle_list", "Draws an instanced triangle list", testSpec, FunctionSupport1<IDFirstInstanceNotSupported::TestSpec>::Args(checkSupport, testSpec)));
1320 					testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1321 					indirectDrawParamCountNoFirstInstanceGroup->addChild(new InstanceFactory<IDFirstInstanceNotSupported, FunctionSupport1<IDFirstInstanceNotSupported::TestSpec> >
1322 						(m_testCtx, "triangle_strip", "Draws an instanced triangle strip", testSpec, FunctionSupport1<IDFirstInstanceNotSupported::TestSpec>::Args(checkSupport, testSpec)));
1323 				}
1324 				indirectDrawInstancedGroup->addChild(indirectDrawNoFirstInstanceGroup);
1325 				indirectDrawCountInstancedGroup->addChild(indirectDrawCountNoFirstInstanceGroup);
1326 				indirectDrawParamCountInstancedGroup->addChild(indirectDrawParamCountNoFirstInstanceGroup);
1327 
1328 				tcu::TestCaseGroup*	indirectDrawFirstInstanceGroup				= new tcu::TestCaseGroup(m_testCtx, "first_instance", "Use drawIndirectFirstInstance optional feature");
1329 				tcu::TestCaseGroup*	indirectDrawCountFirstInstanceGroup			= new tcu::TestCaseGroup(m_testCtx, "first_instance", "Use drawIndirectFirstInstance optional feature");
1330 				tcu::TestCaseGroup*	indirectDrawParamCountFirstInstanceGroup	= new tcu::TestCaseGroup(m_testCtx, "first_instance", "Use drawIndirectFirstInstance optional feature");
1331 				{
1332 					typedef IndirectDrawInstanced<FirstInstanceSupported> IDFirstInstanceSupported;
1333 
1334 					IDFirstInstanceSupported::TestSpec testSpec(m_groupParams);
1335 					testSpec.drawType = static_cast<DrawType>(drawTypeIdx);
1336 					testSpec.dataFromCompute = dataFromCompute;
1337 
1338 					testSpec.shaders[glu::SHADERTYPE_VERTEX] = "vulkan/draw/VertexFetchInstancedFirstInstance.vert";
1339 					testSpec.shaders[glu::SHADERTYPE_FRAGMENT] = "vulkan/draw/VertexFetch.frag";
1340 					if (dataFromCompute)
1341 						testSpec.shaders[glu::SHADERTYPE_COMPUTE] = "vulkan/draw/NegateData.comp";
1342 
1343 					testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1344 					indirectDrawFirstInstanceGroup->addChild(new InstanceFactory<IDFirstInstanceSupported, FunctionSupport1<IDFirstInstanceSupported::TestSpec> >
1345 						(m_testCtx, "triangle_list", "Draws an instanced triangle list", testSpec, FunctionSupport1<IDFirstInstanceSupported::TestSpec>::Args(checkSupport, testSpec)));
1346 					testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1347 					indirectDrawFirstInstanceGroup->addChild(new InstanceFactory<IDFirstInstanceSupported, FunctionSupport1<IDFirstInstanceSupported::TestSpec> >
1348 						(m_testCtx, "triangle_strip", "Draws an instanced triangle strip", testSpec, FunctionSupport1<IDFirstInstanceSupported::TestSpec>::Args(checkSupport, testSpec)));
1349 
1350 					testSpec.testIndirectCountExt = IndirectCountType::BUFFER_LIMIT;
1351 					testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1352 					indirectDrawCountFirstInstanceGroup->addChild(new InstanceFactory<IDFirstInstanceSupported, FunctionSupport1<IDFirstInstanceSupported::TestSpec> >
1353 						(m_testCtx, "triangle_list", "Draws an instanced triangle list", testSpec, FunctionSupport1<IDFirstInstanceSupported::TestSpec>::Args(checkSupport, testSpec)));
1354 					testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1355 					indirectDrawCountFirstInstanceGroup->addChild(new InstanceFactory<IDFirstInstanceSupported, FunctionSupport1<IDFirstInstanceSupported::TestSpec> >
1356 						(m_testCtx, "triangle_strip", "Draws an instanced triangle strip", testSpec, FunctionSupport1<IDFirstInstanceSupported::TestSpec>::Args(checkSupport, testSpec)));
1357 
1358 					testSpec.testIndirectCountExt = IndirectCountType::PARAM_LIMIT;
1359 					testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1360 					indirectDrawParamCountFirstInstanceGroup->addChild(new InstanceFactory<IDFirstInstanceSupported, FunctionSupport1<IDFirstInstanceSupported::TestSpec> >
1361 						(m_testCtx, "triangle_list", "Draws an instanced triangle list", testSpec, FunctionSupport1<IDFirstInstanceSupported::TestSpec>::Args(checkSupport, testSpec)));
1362 					testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1363 					indirectDrawParamCountFirstInstanceGroup->addChild(new InstanceFactory<IDFirstInstanceSupported, FunctionSupport1<IDFirstInstanceSupported::TestSpec> >
1364 						(m_testCtx, "triangle_strip", "Draws an instanced triangle strip", testSpec, FunctionSupport1<IDFirstInstanceSupported::TestSpec>::Args(checkSupport, testSpec)));
1365 				}
1366 				indirectDrawInstancedGroup->addChild(indirectDrawFirstInstanceGroup);
1367 				indirectDrawCountInstancedGroup->addChild(indirectDrawCountFirstInstanceGroup);
1368 				indirectDrawParamCountInstancedGroup->addChild(indirectDrawParamCountFirstInstanceGroup);
1369 			}
1370 			drawTypeGroup->addChild(indirectDrawInstancedGroup);
1371 			drawTypeGroup->addChild(indirectDrawCountInstancedGroup);
1372 			drawTypeGroup->addChild(indirectDrawParamCountInstancedGroup);
1373 		}
1374 
1375 		addChild(drawTypeGroup);
1376 	}
1377 }
1378 
1379 }	// DrawTests
1380 }	// vkt
1381