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