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