• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2016 The Khronos Group Inc.
6  * Copyright (c) 2016 Samsung Electronics Co., Ltd.
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 Instanced Draw Tests
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktDrawInstancedTests.hpp"
26 
27 #include <climits>
28 
29 #include "deSharedPtr.hpp"
30 #include "rrRenderer.hpp"
31 #include "tcuImageCompare.hpp"
32 #include "tcuRGBA.hpp"
33 #include "tcuTextureUtil.hpp"
34 #include "vkImageUtil.hpp"
35 #include "vkPrograms.hpp"
36 #include "vkCmdUtil.hpp"
37 #include "vkTypeUtil.hpp"
38 #include "vkQueryUtil.hpp"
39 #include "vktDrawBufferObjectUtil.hpp"
40 #include "vktDrawCreateInfoUtil.hpp"
41 #include "vktDrawImageObjectUtil.hpp"
42 #include "vktDrawTestCaseUtil.hpp"
43 
44 namespace vkt
45 {
46 namespace Draw
47 {
48 namespace
49 {
50 
51 static const int	QUAD_GRID_SIZE	= 8;
52 static const int	WIDTH			= 128;
53 static const int	HEIGHT			= 128;
54 
55 struct TestParams
56 {
57 	enum DrawFunction
58 	{
59 		FUNCTION_DRAW = 0,
60 		FUNCTION_DRAW_INDEXED,
61 		FUNCTION_DRAW_INDIRECT,
62 		FUNCTION_DRAW_INDEXED_INDIRECT,
63 
64 		FUNTION_LAST
65 	};
66 
67 	DrawFunction			function;
68 	vk::VkPrimitiveTopology	topology;
69 
70 	deBool					testAttribDivisor;
71 	deUint32				attribDivisor;
72 };
73 
74 struct VertexPositionAndColor
75 {
VertexPositionAndColorvkt::Draw::__anonbc71c0ab0111::VertexPositionAndColor76 				VertexPositionAndColor (tcu::Vec4 position_, tcu::Vec4 color_)
77 					: position	(position_)
78 					, color		(color_)
79 				{
80 				}
81 
82 	tcu::Vec4	position;
83 	tcu::Vec4	color;
84 };
85 
operator <<(std::ostream & str,TestParams const & v)86 std::ostream & operator<<(std::ostream & str, TestParams const & v)
87 {
88 	std::ostringstream string;
89 	switch (v.function)
90 	{
91 		case TestParams::FUNCTION_DRAW:
92 			string << "draw";
93 			break;
94 		case TestParams::FUNCTION_DRAW_INDEXED:
95 			string << "draw_indexed";
96 			break;
97 		case TestParams::FUNCTION_DRAW_INDIRECT:
98 			string << "draw_indirect";
99 			break;
100 		case TestParams::FUNCTION_DRAW_INDEXED_INDIRECT:
101 			string << "draw_indexed_indirect";
102 			break;
103 		default:
104 			DE_ASSERT(false);
105 	}
106 
107 	string << "_" << de::toString(v.topology);
108 
109 	if (v.testAttribDivisor)
110 		string << "_attrib_divisor_" << v.attribDivisor;
111 
112 	return str << string.str();
113 }
114 
mapVkPrimitiveTopology(vk::VkPrimitiveTopology primitiveTopology)115 rr::PrimitiveType mapVkPrimitiveTopology (vk::VkPrimitiveTopology primitiveTopology)
116 {
117 	switch (primitiveTopology)
118 	{
119 		case vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST:						return rr::PRIMITIVETYPE_POINTS;
120 		case vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST:						return rr::PRIMITIVETYPE_LINES;
121 		case vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:						return rr::PRIMITIVETYPE_LINE_STRIP;
122 		case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:					return rr::PRIMITIVETYPE_TRIANGLES;
123 		case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:					return rr::PRIMITIVETYPE_TRIANGLE_FAN;
124 		case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:					return rr::PRIMITIVETYPE_TRIANGLE_STRIP;
125 		case vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY:		return rr::PRIMITIVETYPE_LINES_ADJACENCY;
126 		case vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY:		return rr::PRIMITIVETYPE_LINE_STRIP_ADJACENCY;
127 		case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY:	return rr::PRIMITIVETYPE_TRIANGLES_ADJACENCY;
128 		case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY:	return rr::PRIMITIVETYPE_TRIANGLE_STRIP_ADJACENCY;
129 		default:
130 			DE_ASSERT(false);
131 	}
132 	return rr::PRIMITIVETYPE_LAST;
133 }
134 
135 template<typename T>
createAndUploadBuffer(const std::vector<T> data,const vk::DeviceInterface & vk,const Context & context,vk::VkBufferUsageFlags usage)136 de::SharedPtr<Buffer> createAndUploadBuffer(const std::vector<T> data, const vk::DeviceInterface& vk, const Context& context, vk::VkBufferUsageFlags usage)
137 {
138 	const vk::VkDeviceSize dataSize = data.size() * sizeof(T);
139 	de::SharedPtr<Buffer> buffer = Buffer::createAndAlloc(vk, context.getDevice(),
140 														  BufferCreateInfo(dataSize, usage),
141 														  context.getDefaultAllocator(),
142 														  vk::MemoryRequirement::HostVisible);
143 
144 	deUint8* ptr = reinterpret_cast<deUint8*>(buffer->getBoundMemory().getHostPtr());
145 
146 	deMemcpy(ptr, &data[0], static_cast<size_t>(dataSize));
147 
148 	vk::flushAlloc(vk, context.getDevice(), buffer->getBoundMemory());
149 	return buffer;
150 }
151 
152 class TestVertShader : public rr::VertexShader
153 {
154 public:
TestVertShader(int numInstances,int firstInstance)155 	TestVertShader (int numInstances, int firstInstance)
156 		: rr::VertexShader	(3, 1)
157 		, m_numInstances	(numInstances)
158 		, m_firstInstance	(firstInstance)
159 	{
160 		m_inputs[0].type	= rr::GENERICVECTYPE_FLOAT;
161 		m_inputs[1].type	= rr::GENERICVECTYPE_FLOAT;
162 		m_inputs[2].type	= rr::GENERICVECTYPE_FLOAT;
163 		m_outputs[0].type	= rr::GENERICVECTYPE_FLOAT;
164 	}
165 
shadeVertices(const rr::VertexAttrib * inputs,rr::VertexPacket * const * packets,const int numPackets) const166 	void shadeVertices (const rr::VertexAttrib* inputs,
167 						rr::VertexPacket* const* packets,
168 						const int numPackets) const
169 	{
170 		for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
171 		{
172 			const int		instanceNdx		= packets[packetNdx]->instanceNdx + m_firstInstance;
173 			const tcu::Vec4	position		= rr::readVertexAttribFloat(inputs[0], packets[packetNdx]->instanceNdx,	packets[packetNdx]->vertexNdx, m_firstInstance);
174 			const tcu::Vec4	color			= rr::readVertexAttribFloat(inputs[1], packets[packetNdx]->instanceNdx,	packets[packetNdx]->vertexNdx, m_firstInstance);
175 			const tcu::Vec4	color2			= rr::readVertexAttribFloat(inputs[2], packets[packetNdx]->instanceNdx, packets[packetNdx]->vertexNdx, m_firstInstance);
176 			packets[packetNdx]->position	= position + tcu::Vec4((float)(packets[packetNdx]->instanceNdx * 2.0 / m_numInstances), 0.0, 0.0, 0.0);
177 			packets[packetNdx]->outputs[0]	= color + tcu::Vec4((float)instanceNdx / (float)m_numInstances, 0.0, 0.0, 1.0) + color2;
178 		}
179 	}
180 
181 private:
182 	const int m_numInstances;
183 	const int m_firstInstance;
184 };
185 
186 class TestFragShader : public rr::FragmentShader
187 {
188 public:
TestFragShader(void)189 	TestFragShader (void)
190 		: rr::FragmentShader(1, 1)
191 	{
192 		m_inputs[0].type	= rr::GENERICVECTYPE_FLOAT;
193 		m_outputs[0].type	= rr::GENERICVECTYPE_FLOAT;
194 	}
195 
shadeFragments(rr::FragmentPacket * packets,const int numPackets,const rr::FragmentShadingContext & context) const196 	void shadeFragments (rr::FragmentPacket* packets,
197 						 const int numPackets,
198 						 const rr::FragmentShadingContext& context) const
199 	{
200 		for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
201 		{
202 			rr::FragmentPacket& packet = packets[packetNdx];
203 			for (int fragNdx = 0; fragNdx < rr::NUM_FRAGMENTS_PER_PACKET; ++fragNdx)
204 			{
205 				const tcu::Vec4 color = rr::readVarying<float>(packet, context, 0, fragNdx);
206 				rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, color);
207 			}
208 		}
209 	}
210 };
211 
212 class InstancedDrawInstance : public TestInstance
213 {
214 public:
215 												InstancedDrawInstance	(Context& context, TestParams params);
216 	virtual	tcu::TestStatus						iterate					(void);
217 
218 private:
219 	void										prepareVertexData		(int instanceCount, int firstInstance, int instanceDivisor);
220 
221 	const TestParams							m_params;
222 	const vk::DeviceInterface&					m_vk;
223 
224 	vk::VkFormat								m_colorAttachmentFormat;
225 
226 	vk::Move<vk::VkPipeline>					m_pipeline;
227 	vk::Move<vk::VkPipelineLayout>				m_pipelineLayout;
228 
229 	de::SharedPtr<Image>						m_colorTargetImage;
230 	vk::Move<vk::VkImageView>					m_colorTargetView;
231 
232 	PipelineCreateInfo::VertexInputState		m_vertexInputState;
233 
234 	vk::Move<vk::VkCommandPool>					m_cmdPool;
235 	vk::Move<vk::VkCommandBuffer>				m_cmdBuffer;
236 
237 	vk::Move<vk::VkFramebuffer>					m_framebuffer;
238 	vk::Move<vk::VkRenderPass>					m_renderPass;
239 
240 	// Vertex data
241 	std::vector<VertexPositionAndColor>			m_data;
242 	std::vector<deUint32>						m_indexes;
243 	std::vector<tcu::Vec4>						m_instancedColor;
244 };
245 
246 class InstancedDrawCase : public TestCase
247 {
248 public:
InstancedDrawCase(tcu::TestContext & testCtx,const std::string & name,const std::string & desc,TestParams params)249 	InstancedDrawCase (tcu::TestContext&	testCtx,
250 					   const std::string&	name,
251 					   const std::string&	desc,
252 					   TestParams			params)
253 		: TestCase	(testCtx, name, desc)
254 		, m_params	(params)
255 	{
256 		m_vertexShader = "#version 430\n"
257 				"layout(location = 0) in vec4 in_position;\n"
258 				"layout(location = 1) in vec4 in_color;\n"
259 				"layout(location = 2) in vec4 in_color_2;\n"
260 				"layout(push_constant) uniform TestParams {\n"
261 				"	float firstInstance;\n"
262 				"	float instanceCount;\n"
263 				"} params;\n"
264 				"layout(location = 0) out vec4 out_color;\n"
265 				"out gl_PerVertex {\n"
266 				"    vec4  gl_Position;\n"
267 				"    float gl_PointSize;\n"
268 				"};\n"
269 				"void main() {\n"
270 				"    gl_PointSize = 1.0;\n"
271 				"    gl_Position  = in_position + vec4(float(gl_InstanceIndex - params.firstInstance) * 2.0 / params.instanceCount, 0.0, 0.0, 0.0);\n"
272 				"    out_color    = in_color + vec4(float(gl_InstanceIndex) / params.instanceCount, 0.0, 0.0, 1.0) + in_color_2;\n"
273 				"}\n";
274 
275 		m_fragmentShader = "#version 430\n"
276 				"layout(location = 0) in vec4 in_color;\n"
277 				"layout(location = 0) out vec4 out_color;\n"
278 				"void main()\n"
279 				"{\n"
280 				"    out_color = in_color;\n"
281 				"}\n";
282 	}
283 
createInstance(Context & context) const284 	TestInstance* createInstance (Context& context) const
285 	{
286 		if (m_params.testAttribDivisor)
287 		{
288 			const vk::VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT& vertexAttributeDivisorFeatures = context.getVertexAttributeDivisorFeatures();
289 			if (!vk::isDeviceExtensionSupported(context.getUsedApiVersion(), context.getDeviceExtensions(), "VK_EXT_vertex_attribute_divisor"))
290 				TCU_THROW(NotSupportedError, "Implementation does not support VK_EXT_vertex_attribute_divisor");
291 
292 			if (m_params.attribDivisor != 1 && !vertexAttributeDivisorFeatures.vertexAttributeInstanceRateDivisor)
293 				TCU_THROW(NotSupportedError, "Implementation does not support vertexAttributeInstanceRateDivisor");
294 
295 			if (m_params.attribDivisor == 0 && !vertexAttributeDivisorFeatures.vertexAttributeInstanceRateZeroDivisor)
296 				TCU_THROW(NotSupportedError, "Implementation does not support vertexAttributeInstanceRateDivisorZero");
297 		}
298 
299 		return new InstancedDrawInstance(context, m_params);
300 	}
301 
initPrograms(vk::SourceCollections & programCollection) const302 	virtual void initPrograms (vk::SourceCollections& programCollection) const
303 	{
304 		programCollection.glslSources.add("InstancedDrawVert") << glu::VertexSource(m_vertexShader);
305 		programCollection.glslSources.add("InstancedDrawFrag") << glu::FragmentSource(m_fragmentShader);
306 	}
307 
308 private:
309 	const TestParams	m_params;
310 	std::string			m_vertexShader;
311 	std::string			m_fragmentShader;
312 };
313 
InstancedDrawInstance(Context & context,TestParams params)314 InstancedDrawInstance::InstancedDrawInstance(Context &context, TestParams params)
315 	: TestInstance				(context)
316 	, m_params					(params)
317 	, m_vk						(context.getDeviceInterface())
318 	, m_colorAttachmentFormat	(vk::VK_FORMAT_R8G8B8A8_UNORM)
319 {
320 	const vk::VkDevice device				= m_context.getDevice();
321 	const deUint32 queueFamilyIndex			= m_context.getUniversalQueueFamilyIndex();
322 
323 	const vk::VkPushConstantRange pushConstantRange = {
324 		vk::VK_SHADER_STAGE_VERTEX_BIT,				// VkShaderStageFlags    stageFlags;
325 		0u,											// uint32_t              offset;
326 		(deUint32)sizeof(float) * 2,				// uint32_t              size;
327 	};
328 
329 	const PipelineLayoutCreateInfo pipelineLayoutCreateInfo(0, DE_NULL, 1, &pushConstantRange);
330 	m_pipelineLayout						= vk::createPipelineLayout(m_vk, device, &pipelineLayoutCreateInfo);
331 
332 	const vk::VkExtent3D targetImageExtent	= { WIDTH, HEIGHT, 1 };
333 	const ImageCreateInfo targetImageCreateInfo(vk::VK_IMAGE_TYPE_2D, m_colorAttachmentFormat, targetImageExtent, 1, 1, vk::VK_SAMPLE_COUNT_1_BIT,
334 		vk::VK_IMAGE_TILING_OPTIMAL, vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT | vk::VK_IMAGE_USAGE_TRANSFER_DST_BIT);
335 
336 	m_colorTargetImage						= Image::createAndAlloc(m_vk, device, targetImageCreateInfo, m_context.getDefaultAllocator(), m_context.getUniversalQueueFamilyIndex());
337 
338 	const ImageViewCreateInfo colorTargetViewInfo(m_colorTargetImage->object(), vk::VK_IMAGE_VIEW_TYPE_2D, m_colorAttachmentFormat);
339 	m_colorTargetView						= vk::createImageView(m_vk, device, &colorTargetViewInfo);
340 
341 	RenderPassCreateInfo renderPassCreateInfo;
342 	renderPassCreateInfo.addAttachment(AttachmentDescription(m_colorAttachmentFormat,
343 															 vk::VK_SAMPLE_COUNT_1_BIT,
344 															 vk::VK_ATTACHMENT_LOAD_OP_LOAD,
345 															 vk::VK_ATTACHMENT_STORE_OP_STORE,
346 															 vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE,
347 															 vk::VK_ATTACHMENT_STORE_OP_STORE,
348 															 vk::VK_IMAGE_LAYOUT_GENERAL,
349 															 vk::VK_IMAGE_LAYOUT_GENERAL));
350 
351 	const vk::VkAttachmentReference colorAttachmentReference =
352 	{
353 		0,
354 		vk::VK_IMAGE_LAYOUT_GENERAL
355 	};
356 
357 	renderPassCreateInfo.addSubpass(SubpassDescription(vk::VK_PIPELINE_BIND_POINT_GRAPHICS,
358 													   0,
359 													   0,
360 													   DE_NULL,
361 													   1,
362 													   &colorAttachmentReference,
363 													   DE_NULL,
364 													   AttachmentReference(),
365 													   0,
366 													   DE_NULL));
367 
368 	m_renderPass		= vk::createRenderPass(m_vk, device, &renderPassCreateInfo);
369 
370 	std::vector<vk::VkImageView> colorAttachments(1);
371 	colorAttachments[0] = *m_colorTargetView;
372 
373 	const FramebufferCreateInfo framebufferCreateInfo(*m_renderPass, colorAttachments, WIDTH, HEIGHT, 1);
374 
375 	m_framebuffer		= vk::createFramebuffer(m_vk, device, &framebufferCreateInfo);
376 
377 	const vk::VkVertexInputBindingDescription vertexInputBindingDescription[2] =
378 	{
379 		{
380 			0u,
381 			(deUint32)sizeof(VertexPositionAndColor),
382 			vk::VK_VERTEX_INPUT_RATE_VERTEX,
383 		},
384 		{
385 			1u,
386 			(deUint32)sizeof(tcu::Vec4),
387 			vk::VK_VERTEX_INPUT_RATE_INSTANCE,
388 		},
389 	};
390 
391 	const vk::VkVertexInputAttributeDescription vertexInputAttributeDescriptions[] =
392 	{
393 		{
394 			0u,
395 			0u,
396 			vk::VK_FORMAT_R32G32B32A32_SFLOAT,
397 			0u
398 		},
399 		{
400 			1u,
401 			0u,
402 			vk::VK_FORMAT_R32G32B32A32_SFLOAT,
403 			(deUint32)sizeof(tcu::Vec4),
404 		},
405 		{
406 			2u,
407 			1u,
408 			vk::VK_FORMAT_R32G32B32A32_SFLOAT,
409 			0,
410 		}
411 	};
412 
413 	m_vertexInputState = PipelineCreateInfo::VertexInputState(2,
414 															  vertexInputBindingDescription,
415 															  DE_LENGTH_OF_ARRAY(vertexInputAttributeDescriptions),
416 															  vertexInputAttributeDescriptions);
417 
418 	const vk::VkVertexInputBindingDivisorDescriptionEXT vertexInputBindingDivisorDescription =
419 	{
420 		1u,
421 		m_params.attribDivisor,
422 	};
423 	if (m_params.testAttribDivisor)
424 		m_vertexInputState.addDivisors(1, &vertexInputBindingDivisorDescription);
425 
426 	const CmdPoolCreateInfo cmdPoolCreateInfo(queueFamilyIndex);
427 	m_cmdPool = vk::createCommandPool(m_vk, device, &cmdPoolCreateInfo);
428 
429 	m_cmdBuffer = vk::allocateCommandBuffer(m_vk, device, *m_cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY);
430 
431 	const vk::Unique<vk::VkShaderModule> vs(createShaderModule(m_vk, device, m_context.getBinaryCollection().get("InstancedDrawVert"), 0));
432 	const vk::Unique<vk::VkShaderModule> fs(createShaderModule(m_vk, device, m_context.getBinaryCollection().get("InstancedDrawFrag"), 0));
433 
434 	const PipelineCreateInfo::ColorBlendState::Attachment vkCbAttachmentState;
435 
436 	vk::VkViewport	viewport	= vk::makeViewport(WIDTH, HEIGHT);
437 	vk::VkRect2D	scissor		= vk::makeRect2D(WIDTH, HEIGHT);
438 
439 	PipelineCreateInfo pipelineCreateInfo(*m_pipelineLayout, *m_renderPass, 0, 0);
440 	pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*vs, "main", vk::VK_SHADER_STAGE_VERTEX_BIT));
441 	pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*fs, "main", vk::VK_SHADER_STAGE_FRAGMENT_BIT));
442 	pipelineCreateInfo.addState(PipelineCreateInfo::VertexInputState(m_vertexInputState));
443 	pipelineCreateInfo.addState(PipelineCreateInfo::InputAssemblerState(m_params.topology));
444 	pipelineCreateInfo.addState(PipelineCreateInfo::ColorBlendState(1, &vkCbAttachmentState));
445 	pipelineCreateInfo.addState(PipelineCreateInfo::ViewportState(1, std::vector<vk::VkViewport>(1, viewport), std::vector<vk::VkRect2D>(1, scissor)));
446 	pipelineCreateInfo.addState(PipelineCreateInfo::DepthStencilState());
447 	pipelineCreateInfo.addState(PipelineCreateInfo::RasterizerState());
448 	pipelineCreateInfo.addState(PipelineCreateInfo::MultiSampleState());
449 
450 	m_pipeline = vk::createGraphicsPipeline(m_vk, device, DE_NULL, &pipelineCreateInfo);
451 }
452 
iterate()453 tcu::TestStatus InstancedDrawInstance::iterate()
454 {
455 	const vk::VkQueue		queue					= m_context.getUniversalQueue();
456 	const vk::VkDevice		device					= m_context.getDevice();
457 	static const deUint32	instanceCounts[]		= { 0, 1, 2, 4, 20 };
458 	static const deUint32	firstInstanceIndices[]	= { 0, 1, 3, 4, 20 };
459 
460 	qpTestResult			res						= QP_TEST_RESULT_PASS;
461 
462 	const vk::VkClearColorValue clearColor = { { 0.0f, 0.0f, 0.0f, 1.0f } };
463 	int firstInstanceIndicesCount = 1;
464 
465 	// Require 'drawIndirectFirstInstance' feature to run non-zero firstInstance indirect draw tests.
466 	if (m_context.getDeviceFeatures().drawIndirectFirstInstance)
467 		firstInstanceIndicesCount = DE_LENGTH_OF_ARRAY(firstInstanceIndices);
468 
469 	for (int instanceCountNdx = 0; instanceCountNdx < DE_LENGTH_OF_ARRAY(instanceCounts); instanceCountNdx++)
470 	{
471 		const deUint32 instanceCount = instanceCounts[instanceCountNdx];
472 		for (int firstInstanceIndexNdx = 0; firstInstanceIndexNdx < firstInstanceIndicesCount; firstInstanceIndexNdx++)
473 		{
474 			// Prepare vertex data for at least one instance
475 			const deUint32				prepareCount			= de::max(instanceCount, 1u);
476 			const deUint32				firstInstance			= firstInstanceIndices[firstInstanceIndexNdx];
477 
478 			prepareVertexData(prepareCount, firstInstance, m_params.testAttribDivisor ? m_params.attribDivisor : 1);
479 			const de::SharedPtr<Buffer>	vertexBuffer			= createAndUploadBuffer(m_data, m_vk, m_context, vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
480 			const de::SharedPtr<Buffer>	instancedVertexBuffer	= createAndUploadBuffer(m_instancedColor, m_vk, m_context, vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
481 			de::SharedPtr<Buffer>		indexBuffer;
482 			de::SharedPtr<Buffer>		indirectBuffer;
483 			beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
484 
485 			initialTransitionColor2DImage(m_vk, *m_cmdBuffer, m_colorTargetImage->object(), vk::VK_IMAGE_LAYOUT_GENERAL,
486 										  vk::VK_ACCESS_TRANSFER_WRITE_BIT, vk::VK_PIPELINE_STAGE_TRANSFER_BIT);
487 
488 			const ImageSubresourceRange subresourceRange(vk::VK_IMAGE_ASPECT_COLOR_BIT);
489 			m_vk.cmdClearColorImage(*m_cmdBuffer, m_colorTargetImage->object(),
490 				vk::VK_IMAGE_LAYOUT_GENERAL, &clearColor, 1, &subresourceRange);
491 
492 			const vk::VkMemoryBarrier memBarrier =
493 			{
494 				vk::VK_STRUCTURE_TYPE_MEMORY_BARRIER,
495 				DE_NULL,
496 				vk::VK_ACCESS_TRANSFER_WRITE_BIT,
497 				vk::VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT
498 			};
499 
500 			m_vk.cmdPipelineBarrier(*m_cmdBuffer, vk::VK_PIPELINE_STAGE_TRANSFER_BIT,
501 				vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
502 				0, 1, &memBarrier, 0, DE_NULL, 0, DE_NULL);
503 
504 			const vk::VkRect2D renderArea = vk::makeRect2D(WIDTH, HEIGHT);
505 			beginRenderPass(m_vk, *m_cmdBuffer, *m_renderPass, *m_framebuffer, renderArea);
506 
507 			if (m_params.function == TestParams::FUNCTION_DRAW_INDEXED || m_params.function == TestParams::FUNCTION_DRAW_INDEXED_INDIRECT)
508 			{
509 				indexBuffer = createAndUploadBuffer(m_indexes, m_vk, m_context, vk::VK_BUFFER_USAGE_INDEX_BUFFER_BIT);
510 				m_vk.cmdBindIndexBuffer(*m_cmdBuffer, indexBuffer->object(), 0, vk::VK_INDEX_TYPE_UINT32);
511 			}
512 
513 			const vk::VkBuffer vertexBuffers[] =
514 			{
515 				vertexBuffer->object(),
516 				instancedVertexBuffer->object(),
517 			};
518 
519 			const vk::VkDeviceSize vertexBufferOffsets[] =
520 			{
521 				0,	// vertexBufferOffset
522 				0,	// instancedVertexBufferOffset
523 			};
524 
525 			m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, DE_LENGTH_OF_ARRAY(vertexBuffers), vertexBuffers, vertexBufferOffsets);
526 
527 			const float pushConstants[] = { (float)firstInstance, (float)instanceCount };
528 			m_vk.cmdPushConstants(*m_cmdBuffer, *m_pipelineLayout, vk::VK_SHADER_STAGE_VERTEX_BIT, 0u, (deUint32)sizeof(pushConstants), pushConstants);
529 
530 			m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
531 
532 			switch (m_params.function)
533 			{
534 				case TestParams::FUNCTION_DRAW:
535 					m_vk.cmdDraw(*m_cmdBuffer, (deUint32)m_data.size(), instanceCount, 0u, firstInstance);
536 					break;
537 
538 				case TestParams::FUNCTION_DRAW_INDEXED:
539 					m_vk.cmdDrawIndexed(*m_cmdBuffer, (deUint32)m_indexes.size(), instanceCount, 0u, 0u, firstInstance);
540 					break;
541 
542 				case TestParams::FUNCTION_DRAW_INDIRECT:
543 				{
544 					vk::VkDrawIndirectCommand drawCommand =
545 					{
546 						(deUint32)m_data.size(),	// uint32_t	vertexCount;
547 						instanceCount,				// uint32_t	instanceCount;
548 						0u,							// uint32_t	firstVertex;
549 						firstInstance,				// uint32_t	firstInstance;
550 					};
551 					std::vector<vk::VkDrawIndirectCommand> drawCommands;
552 					drawCommands.push_back(drawCommand);
553 					indirectBuffer = createAndUploadBuffer(drawCommands, m_vk, m_context, vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT);
554 
555 					m_vk.cmdDrawIndirect(*m_cmdBuffer, indirectBuffer->object(), 0, 1u, 0u);
556 					break;
557 				}
558 				case TestParams::FUNCTION_DRAW_INDEXED_INDIRECT:
559 				{
560 					vk::VkDrawIndexedIndirectCommand drawCommand =
561 					{
562 						(deUint32)m_indexes.size(),	// uint32_t	indexCount;
563 						instanceCount,				// uint32_t	instanceCount;
564 						0u,							// uint32_t	firstIndex;
565 						0,							// int32_t	vertexOffset;
566 						firstInstance,				// uint32_t	firstInstance;
567 					};
568 					std::vector<vk::VkDrawIndexedIndirectCommand> drawCommands;
569 					drawCommands.push_back(drawCommand);
570 					indirectBuffer = createAndUploadBuffer(drawCommands, m_vk, m_context, vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT);
571 
572 					m_vk.cmdDrawIndexedIndirect(*m_cmdBuffer, indirectBuffer->object(), 0, 1u, 0u);
573 					break;
574 				}
575 				default:
576 					DE_ASSERT(false);
577 			}
578 
579 			endRenderPass(m_vk, *m_cmdBuffer);
580 			endCommandBuffer(m_vk, *m_cmdBuffer);
581 
582 			submitCommandsAndWait(m_vk, device, queue, m_cmdBuffer.get());
583 
584 			// Reference rendering
585 			std::vector<tcu::Vec4>	vetrices;
586 			std::vector<tcu::Vec4>	colors;
587 
588 			for (std::vector<VertexPositionAndColor>::const_iterator it = m_data.begin(); it != m_data.end(); ++it)
589 			{
590 				vetrices.push_back(it->position);
591 				colors.push_back(it->color);
592 			}
593 
594 			tcu::TextureLevel refImage (vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5 + WIDTH), (int)(0.5 + HEIGHT));
595 
596 			tcu::clear(refImage.getAccess(), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
597 
598 			const TestVertShader					vertShader(instanceCount, firstInstance);
599 			const TestFragShader					fragShader;
600 			const rr::Program						program			(&vertShader, &fragShader);
601 			const rr::MultisamplePixelBufferAccess	colorBuffer		= rr::MultisamplePixelBufferAccess::fromSinglesampleAccess(refImage.getAccess());
602 			const rr::RenderTarget					renderTarget	(colorBuffer);
603 			const rr::RenderState					renderState		((rr::ViewportState(colorBuffer)));
604 			const rr::Renderer						renderer;
605 
606 			const rr::VertexAttrib	vertexAttribs[] =
607 			{
608 				rr::VertexAttrib(rr::VERTEXATTRIBTYPE_FLOAT, 4, sizeof(tcu::Vec4), 0, &vetrices[0]),
609 				rr::VertexAttrib(rr::VERTEXATTRIBTYPE_FLOAT, 4, sizeof(tcu::Vec4), 0, &colors[0]),
610 				// The reference renderer treats a divisor of 0 as meaning per-vertex.  Use INT_MAX instead; it should work just as well.
611 				rr::VertexAttrib(rr::VERTEXATTRIBTYPE_FLOAT, 4, sizeof(tcu::Vec4), m_params.testAttribDivisor ? (m_params.attribDivisor == 0 ? INT_MAX : m_params.attribDivisor) : 1, &m_instancedColor[0])
612 			};
613 
614 			if (m_params.function == TestParams::FUNCTION_DRAW || m_params.function == TestParams::FUNCTION_DRAW_INDIRECT)
615 			{
616 				const rr::PrimitiveList	primitives = rr::PrimitiveList(mapVkPrimitiveTopology(m_params.topology), (int)vetrices.size(), 0);
617 				const rr::DrawCommand	command(renderState, renderTarget, program, DE_LENGTH_OF_ARRAY(vertexAttribs), &vertexAttribs[0],
618 												primitives);
619 				renderer.drawInstanced(command, instanceCount);
620 			}
621 			else
622 			{
623 				const rr::DrawIndices indicies(m_indexes.data());
624 
625 				const rr::PrimitiveList	primitives = rr::PrimitiveList(mapVkPrimitiveTopology(m_params.topology), (int)m_indexes.size(), indicies);
626 				const rr::DrawCommand	command(renderState, renderTarget, program, DE_LENGTH_OF_ARRAY(vertexAttribs), &vertexAttribs[0],
627 												primitives);
628 				renderer.drawInstanced(command, instanceCount);
629 			}
630 
631 			const vk::VkOffset3D zeroOffset = { 0, 0, 0 };
632 			const tcu::ConstPixelBufferAccess renderedFrame = m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(),
633 				vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
634 
635 			tcu::TestLog &log		= m_context.getTestContext().getLog();
636 
637 			std::ostringstream resultDesc;
638 			resultDesc << "Image comparison result. Instance count: " << instanceCount << " first instance index: " << firstInstance;
639 
640 			if (m_params.topology == vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST)
641 			{
642 				const bool ok = tcu::intThresholdPositionDeviationCompare(
643 					log, "Result", resultDesc.str().c_str(), refImage.getAccess(), renderedFrame,
644 					tcu::UVec4(4u),					// color threshold
645 					tcu::IVec3(1, 1, 0),			// position deviation tolerance
646 					true,							// don't check the pixels at the boundary
647 					tcu::COMPARE_LOG_RESULT);
648 
649 				if (!ok)
650 					res = QP_TEST_RESULT_FAIL;
651 			}
652 			else
653 			{
654 				if (!tcu::fuzzyCompare(log, "Result", resultDesc.str().c_str(), refImage.getAccess(), renderedFrame, 0.05f, tcu::COMPARE_LOG_RESULT))
655 					res = QP_TEST_RESULT_FAIL;
656 			}
657 		}
658 	}
659 	return tcu::TestStatus(res, qpGetTestResultName(res));
660 }
661 
prepareVertexData(int instanceCount,int firstInstance,int instanceDivisor)662 void InstancedDrawInstance::prepareVertexData(int instanceCount, int firstInstance, int instanceDivisor)
663 {
664 	m_data.clear();
665 	m_indexes.clear();
666 	m_instancedColor.clear();
667 
668 	if (m_params.function == TestParams::FUNCTION_DRAW || m_params.function == TestParams::FUNCTION_DRAW_INDIRECT)
669 	{
670 		for (int y = 0; y < QUAD_GRID_SIZE; y++)
671 		{
672 			for (int x = 0; x < QUAD_GRID_SIZE; x++)
673 			{
674 				const float fx0 = -1.0f + (float)(x+0) / (float)QUAD_GRID_SIZE * 2.0f / (float)instanceCount;
675 				const float fx1 = -1.0f + (float)(x+1) / (float)QUAD_GRID_SIZE * 2.0f / (float)instanceCount;
676 				const float fy0 = -1.0f + (float)(y+0) / (float)QUAD_GRID_SIZE * 2.0f;
677 				const float fy1 = -1.0f + (float)(y+1) / (float)QUAD_GRID_SIZE * 2.0f;
678 
679 				// Vertices of a quad's lower-left triangle: (fx0, fy0), (fx1, fy0) and (fx0, fy1)
680 				m_data.push_back(VertexPositionAndColor(tcu::Vec4(fx0, fy0, 1.0f, 1.0f), tcu::RGBA::blue().toVec()));
681 				m_data.push_back(VertexPositionAndColor(tcu::Vec4(fx1, fy0, 1.0f, 1.0f), tcu::RGBA::blue().toVec()));
682 				m_data.push_back(VertexPositionAndColor(tcu::Vec4(fx0, fy1, 1.0f, 1.0f), tcu::RGBA::green().toVec()));
683 
684 				// Vertices of a quad's upper-right triangle: (fx1, fy1), (fx0, fy1) and (fx1, fy0)
685 				m_data.push_back(VertexPositionAndColor(tcu::Vec4(fx1, fy1, 1.0f, 1.0f), tcu::RGBA::green().toVec()));
686 				m_data.push_back(VertexPositionAndColor(tcu::Vec4(fx0, fy1, 1.0f, 1.0f), tcu::RGBA::green().toVec()));
687 				m_data.push_back(VertexPositionAndColor(tcu::Vec4(fx1, fy0, 1.0f, 1.0f), tcu::RGBA::blue().toVec()));
688 			}
689 		}
690 	}
691 	else
692 	{
693 		for (int y = 0; y < QUAD_GRID_SIZE + 1; y++)
694 		{
695 			for (int x = 0; x < QUAD_GRID_SIZE + 1; x++)
696 			{
697 				const float fx = -1.0f + (float)x / (float)QUAD_GRID_SIZE * 2.0f / (float)instanceCount;
698 				const float fy = -1.0f + (float)y / (float)QUAD_GRID_SIZE * 2.0f;
699 
700 				m_data.push_back(VertexPositionAndColor(tcu::Vec4(fx, fy, 1.0f, 1.0f),
701 														(y % 2 ? tcu::RGBA::blue().toVec() : tcu::RGBA::green().toVec())));
702 			}
703 		}
704 
705 		for (int y = 0; y < QUAD_GRID_SIZE; y++)
706 		{
707 			for (int x = 0; x < QUAD_GRID_SIZE; x++)
708 			{
709 				const int ndx00 = y*(QUAD_GRID_SIZE + 1) + x;
710 				const int ndx10 = y*(QUAD_GRID_SIZE + 1) + x + 1;
711 				const int ndx01 = (y + 1)*(QUAD_GRID_SIZE + 1) + x;
712 				const int ndx11 = (y + 1)*(QUAD_GRID_SIZE + 1) + x + 1;
713 
714 				// Lower-left triangle of a quad.
715 				m_indexes.push_back((deUint16)ndx00);
716 				m_indexes.push_back((deUint16)ndx10);
717 				m_indexes.push_back((deUint16)ndx01);
718 
719 				// Upper-right triangle of a quad.
720 				m_indexes.push_back((deUint16)ndx11);
721 				m_indexes.push_back((deUint16)ndx01);
722 				m_indexes.push_back((deUint16)ndx10);
723 			}
724 		}
725 	}
726 
727 	const int colorCount = instanceDivisor == 0 ? 1 : (instanceCount + firstInstance + instanceDivisor - 1) / instanceDivisor;
728 	for (int i = 0; i < instanceCount + firstInstance; i++)
729 	{
730 		m_instancedColor.push_back(tcu::Vec4(0.0, (float)(1.0 - i * 1.0 / colorCount) / 2, 0.0, 1.0));
731 	}
732 }
733 
734 } // anonymus
735 
InstancedTests(tcu::TestContext & testCtx)736 InstancedTests::InstancedTests(tcu::TestContext& testCtx)
737 	: TestCaseGroup	(testCtx, "instanced", "Instanced drawing tests")
738 {
739 	static const vk::VkPrimitiveTopology	topologies[]			=
740 	{
741 		vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST,
742 		vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST,
743 		vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP,
744 		vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
745 		vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
746 		vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN,
747 	};
748 	static const TestParams::DrawFunction	functions[]				=
749 	{
750 		TestParams::FUNCTION_DRAW,
751 		TestParams::FUNCTION_DRAW_INDEXED,
752 		TestParams::FUNCTION_DRAW_INDIRECT,
753 		TestParams::FUNCTION_DRAW_INDEXED_INDIRECT,
754 	};
755 
756 	static const deUint32 divisors[] = { 0, 1, 2, 4, 20 };
757 
758 	for (int topologyNdx = 0; topologyNdx < DE_LENGTH_OF_ARRAY(topologies); topologyNdx++)
759 	{
760 		for (int functionNdx = 0; functionNdx < DE_LENGTH_OF_ARRAY(functions); functionNdx++)
761 		{
762 			for (int testAttribDivisor = 0; testAttribDivisor < 2; testAttribDivisor++)
763 			{
764 				for (int divisorNdx = 0; divisorNdx < DE_LENGTH_OF_ARRAY(divisors); divisorNdx++)
765 				{
766 					// If we don't have VK_EXT_vertex_attribute_divisor, we only get a divisor or 1.
767 					if (!testAttribDivisor && divisors[divisorNdx] != 1)
768 						continue;
769 
770 					TestParams param;
771 					param.function = functions[functionNdx];
772 					param.topology = topologies[topologyNdx];
773 					param.testAttribDivisor = testAttribDivisor ? DE_TRUE : DE_FALSE;
774 					param.attribDivisor = divisors[divisorNdx];
775 
776 					std::string testName = de::toString(param);
777 
778 					addChild(new InstancedDrawCase(m_testCtx, de::toLower(testName), "Instanced drawing test", param));
779 				}
780 			}
781 		}
782 	}
783 }
784 
~InstancedTests()785 InstancedTests::~InstancedTests() {}
786 
787 } // DrawTests
788 } // vkt
789