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 Simple Draw Tests
23 *//*--------------------------------------------------------------------*/
24
25#include "vktBasicDrawTests.hpp"
26
27#include "vktDrawBaseClass.hpp"
28#include "vkQueryUtil.hpp"
29#include "vktTestGroupUtil.hpp"
30
31#include "deDefs.h"
32#include "deRandom.hpp"
33#include "deString.h"
34
35#include "tcuTestCase.hpp"
36#include "tcuRGBA.hpp"
37#include "tcuTextureUtil.hpp"
38#include "tcuImageCompare.hpp"
39
40#include "rrRenderer.hpp"
41
42#include <string>
43#include <sstream>
44
45namespace vkt
46{
47namespace Draw
48{
49namespace
50{
51static const deUint32 SEED			= 0xc2a39fu;
52static const deUint32 INDEX_LIMIT	= 10000;
53// To avoid too big and mostly empty structures
54static const deUint32 OFFSET_LIMIT	= 1000;
55// Number of primitives to draw
56static const deUint32 PRIMITIVE_COUNT[] = {1, 3, 17, 45};
57
58enum DrawCommandType
59{
60	DRAW_COMMAND_TYPE_DRAW,
61	DRAW_COMMAND_TYPE_DRAW_INDEXED,
62	DRAW_COMMAND_TYPE_DRAW_INDIRECT,
63	DRAW_COMMAND_TYPE_DRAW_INDEXED_INDIRECT,
64
65	DRAW_COMMAND_TYPE_DRAW_LAST
66};
67
68const char* getDrawCommandTypeName (DrawCommandType command)
69{
70	switch (command)
71	{
72		case DRAW_COMMAND_TYPE_DRAW:					return "draw";
73		case DRAW_COMMAND_TYPE_DRAW_INDEXED:			return "draw_indexed";
74		case DRAW_COMMAND_TYPE_DRAW_INDIRECT:			return "draw_indirect";
75		case DRAW_COMMAND_TYPE_DRAW_INDEXED_INDIRECT:	return "draw_indexed_indirect";
76		default:					DE_ASSERT(false);
77	}
78	return "";
79}
80
81rr::PrimitiveType mapVkPrimitiveTopology (vk::VkPrimitiveTopology primitiveTopology)
82{
83	switch (primitiveTopology)
84	{
85		case vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST:						return rr::PRIMITIVETYPE_POINTS;
86		case vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST:						return rr::PRIMITIVETYPE_LINES;
87		case vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:						return rr::PRIMITIVETYPE_LINE_STRIP;
88		case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:					return rr::PRIMITIVETYPE_TRIANGLES;
89		case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:					return rr::PRIMITIVETYPE_TRIANGLE_FAN;
90		case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:					return rr::PRIMITIVETYPE_TRIANGLE_STRIP;
91		case vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY:		return rr::PRIMITIVETYPE_LINES_ADJACENCY;
92		case vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY:		return rr::PRIMITIVETYPE_LINE_STRIP_ADJACENCY;
93		case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY:	return rr::PRIMITIVETYPE_TRIANGLES_ADJACENCY;
94		case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY:	return rr::PRIMITIVETYPE_TRIANGLE_STRIP_ADJACENCY;
95		default:
96			DE_ASSERT(false);
97	}
98	return rr::PRIMITIVETYPE_LAST;
99}
100
101struct DrawParamsBase
102{
103	std::vector<PositionColorVertex>	vertices;
104	vk::VkPrimitiveTopology				topology;
105
106	DrawParamsBase ()
107	{}
108
109	DrawParamsBase (const vk::VkPrimitiveTopology top)
110		: topology	(top)
111	{}
112};
113
114struct IndexedParamsBase
115{
116	std::vector<deUint32>	indexes;
117	const vk::VkIndexType	indexType;
118
119	IndexedParamsBase (const vk::VkIndexType indexT)
120		: indexType	(indexT)
121	{}
122};
123
124// Structs to store draw parameters
125struct DrawParams : DrawParamsBase
126{
127	// vkCmdDraw parameters is like a single VkDrawIndirectCommand
128	vk::VkDrawIndirectCommand	params;
129
130	DrawParams (const vk::VkPrimitiveTopology top, const deUint32 vertexC, const deUint32 instanceC, const deUint32 firstV, const deUint32 firstI)
131		: DrawParamsBase	(top)
132	{
133		params.vertexCount		= vertexC;
134		params.instanceCount	= instanceC;
135		params.firstVertex		= firstV;
136		params.firstInstance	= firstI;
137	}
138};
139
140struct DrawIndexedParams : DrawParamsBase, IndexedParamsBase
141{
142	// vkCmdDrawIndexed parameters is like a single VkDrawIndexedIndirectCommand
143	vk::VkDrawIndexedIndirectCommand	params;
144
145	DrawIndexedParams (const vk::VkPrimitiveTopology top, const vk::VkIndexType indexT, const deUint32 indexC, const deUint32 instanceC, const deUint32 firstIdx, const deInt32 vertexO, const deUint32 firstIns)
146		: DrawParamsBase	(top)
147		, IndexedParamsBase	(indexT)
148	{
149		params.indexCount		= indexC;
150		params.instanceCount	= instanceC;
151		params.firstIndex		= firstIdx;
152		params.vertexOffset		= vertexO;
153		params.firstInstance	= firstIns;
154	}
155};
156
157struct DrawIndirectParams : DrawParamsBase
158{
159	std::vector<vk::VkDrawIndirectCommand>	commands;
160
161	DrawIndirectParams (const vk::VkPrimitiveTopology top)
162		: DrawParamsBase	(top)
163	{}
164
165	void addCommand (const deUint32 vertexC, const deUint32 instanceC, const deUint32 firstV, const deUint32 firstI)
166	{
167		vk::VkDrawIndirectCommand	cmd;
168		cmd.vertexCount				= vertexC;
169		cmd.instanceCount			= instanceC;
170		cmd.firstVertex				= firstV;
171		cmd.firstInstance			= firstI;
172
173		commands.push_back(cmd);
174	}
175};
176
177struct DrawIndexedIndirectParams : DrawParamsBase, IndexedParamsBase
178{
179	std::vector<vk::VkDrawIndexedIndirectCommand>	commands;
180
181	DrawIndexedIndirectParams (const vk::VkPrimitiveTopology top, const vk::VkIndexType indexT)
182		: DrawParamsBase	(top)
183		, IndexedParamsBase	(indexT)
184	{}
185
186	void addCommand (const deUint32 indexC, const deUint32 instanceC, const deUint32 firstIdx, const deInt32 vertexO, const deUint32 firstIns)
187	{
188		vk::VkDrawIndexedIndirectCommand	cmd;
189		cmd.indexCount						= indexC;
190		cmd.instanceCount					= instanceC;
191		cmd.firstIndex						= firstIdx;
192		cmd.vertexOffset					= vertexO;
193		cmd.firstInstance					= firstIns;
194
195		commands.push_back(cmd);
196	}
197};
198
199// Reference renderer shaders
200class PassthruVertShader : public rr::VertexShader
201{
202public:
203	PassthruVertShader (void)
204	: rr::VertexShader (2, 1)
205	{
206		m_inputs[0].type	= rr::GENERICVECTYPE_FLOAT;
207		m_inputs[1].type	= rr::GENERICVECTYPE_FLOAT;
208		m_outputs[0].type	= rr::GENERICVECTYPE_FLOAT;
209	}
210
211	void shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
212	{
213		for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
214		{
215			packets[packetNdx]->position = rr::readVertexAttribFloat(inputs[0],
216																	 packets[packetNdx]->instanceNdx,
217																	 packets[packetNdx]->vertexNdx);
218
219			tcu::Vec4 color = rr::readVertexAttribFloat(inputs[1],
220														packets[packetNdx]->instanceNdx,
221														packets[packetNdx]->vertexNdx);
222
223			packets[packetNdx]->outputs[0] = color;
224		}
225	}
226};
227
228class PassthruFragShader : public rr::FragmentShader
229{
230public:
231	PassthruFragShader (void)
232		: rr::FragmentShader(1, 1)
233	{
234		m_inputs[0].type	= rr::GENERICVECTYPE_FLOAT;
235		m_outputs[0].type	= rr::GENERICVECTYPE_FLOAT;
236	}
237
238	void shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
239	{
240		for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
241		{
242			rr::FragmentPacket& packet = packets[packetNdx];
243			for (deUint32 fragNdx = 0; fragNdx < rr::NUM_FRAGMENTS_PER_PACKET; ++fragNdx)
244			{
245				tcu::Vec4 color = rr::readVarying<float>(packet, context, 0, fragNdx);
246				rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, color);
247			}
248		}
249	}
250};
251
252inline bool imageCompare (tcu::TestLog& log, const tcu::ConstPixelBufferAccess& reference, const tcu::ConstPixelBufferAccess& result, const vk::VkPrimitiveTopology topology)
253{
254	if (topology == vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST)
255	{
256		return tcu::intThresholdPositionDeviationCompare(
257			log, "Result", "Image comparison result", reference, result,
258			tcu::UVec4(4u),					// color threshold
259			tcu::IVec3(1, 1, 0),			// position deviation tolerance
260			true,							// don't check the pixels at the boundary
261			tcu::COMPARE_LOG_RESULT);
262	}
263	else
264		return tcu::fuzzyCompare(log, "Result", "Image comparison result", reference, result, 0.05f, tcu::COMPARE_LOG_RESULT);
265}
266
267class DrawTestInstanceBase : public TestInstance
268{
269public:
270									DrawTestInstanceBase	(Context& context);
271	virtual							~DrawTestInstanceBase	(void) = 0;
272	void							initialize				(const DrawParamsBase& data);
273	void							initPipeline			(const vk::VkDevice device);
274	void							beginRenderPass			(void);
275
276	// Specialize this function for each type
277	virtual tcu::TestStatus			iterate					(void) = 0;
278protected:
279	// Specialize this function for each type
280	virtual void					generateDrawData		(void) = 0;
281	void							generateRefImage		(const tcu::PixelBufferAccess& access, const std::vector<tcu::Vec4>& vertices, const std::vector<tcu::Vec4>& colors) const;
282
283	DrawParamsBase											m_data;
284	const vk::DeviceInterface&								m_vk;
285	vk::Move<vk::VkPipeline>								m_pipeline;
286	vk::Move<vk::VkPipelineLayout>							m_pipelineLayout;
287	vk::VkFormat											m_colorAttachmentFormat;
288	de::SharedPtr<Image>									m_colorTargetImage;
289	vk::Move<vk::VkImageView>								m_colorTargetView;
290	vk::Move<vk::VkRenderPass>								m_renderPass;
291	vk::Move<vk::VkFramebuffer>								m_framebuffer;
292	PipelineCreateInfo::VertexInputState					m_vertexInputState;
293	de::SharedPtr<Buffer>									m_vertexBuffer;
294	vk::Move<vk::VkCommandPool>								m_cmdPool;
295	vk::Move<vk::VkCommandBuffer>							m_cmdBuffer;
296
297	enum
298	{
299		WIDTH = 256,
300		HEIGHT = 256
301	};
302};
303
304DrawTestInstanceBase::DrawTestInstanceBase (Context& context)
305	: vkt::TestInstance			(context)
306	, m_vk						(context.getDeviceInterface())
307	, m_colorAttachmentFormat	(vk::VK_FORMAT_R8G8B8A8_UNORM)
308{
309}
310
311DrawTestInstanceBase::~DrawTestInstanceBase (void)
312{
313}
314
315void DrawTestInstanceBase::initialize (const DrawParamsBase& data)
316{
317	m_data	= data;
318
319	const vk::VkDevice	device				= m_context.getDevice();
320	const deUint32		queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
321
322	const PipelineLayoutCreateInfo pipelineLayoutCreateInfo;
323	m_pipelineLayout						= vk::createPipelineLayout(m_vk, device, &pipelineLayoutCreateInfo);
324
325	const vk::VkExtent3D targetImageExtent	= { WIDTH, HEIGHT, 1 };
326	const ImageCreateInfo targetImageCreateInfo(vk::VK_IMAGE_TYPE_2D, m_colorAttachmentFormat, targetImageExtent, 1, 1, vk::VK_SAMPLE_COUNT_1_BIT,
327		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);
328
329	m_colorTargetImage						= Image::createAndAlloc(m_vk, device, targetImageCreateInfo, m_context.getDefaultAllocator());
330
331	const ImageViewCreateInfo colorTargetViewInfo(m_colorTargetImage->object(), vk::VK_IMAGE_VIEW_TYPE_2D, m_colorAttachmentFormat);
332	m_colorTargetView						= vk::createImageView(m_vk, device, &colorTargetViewInfo);
333
334	RenderPassCreateInfo renderPassCreateInfo;
335	renderPassCreateInfo.addAttachment(AttachmentDescription(m_colorAttachmentFormat,
336															 vk::VK_SAMPLE_COUNT_1_BIT,
337															 vk::VK_ATTACHMENT_LOAD_OP_LOAD,
338															 vk::VK_ATTACHMENT_STORE_OP_STORE,
339															 vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE,
340															 vk::VK_ATTACHMENT_STORE_OP_STORE,
341															 vk::VK_IMAGE_LAYOUT_GENERAL,
342															 vk::VK_IMAGE_LAYOUT_GENERAL));
343
344	const vk::VkAttachmentReference colorAttachmentReference =
345	{
346		0,
347		vk::VK_IMAGE_LAYOUT_GENERAL
348	};
349
350	renderPassCreateInfo.addSubpass(SubpassDescription(vk::VK_PIPELINE_BIND_POINT_GRAPHICS,
351													   0,
352													   0,
353													   DE_NULL,
354													   1,
355													   &colorAttachmentReference,
356													   DE_NULL,
357													   AttachmentReference(),
358													   0,
359													   DE_NULL));
360
361	m_renderPass		= vk::createRenderPass(m_vk, device, &renderPassCreateInfo);
362
363	std::vector<vk::VkImageView> colorAttachments(1);
364	colorAttachments[0] = *m_colorTargetView;
365
366	const FramebufferCreateInfo framebufferCreateInfo(*m_renderPass, colorAttachments, WIDTH, HEIGHT, 1);
367
368	m_framebuffer		= vk::createFramebuffer(m_vk, device, &framebufferCreateInfo);
369
370	const vk::VkVertexInputBindingDescription vertexInputBindingDescription =
371	{
372		0,
373		(deUint32)sizeof(tcu::Vec4) * 2,
374		vk::VK_VERTEX_INPUT_RATE_VERTEX,
375	};
376
377	const vk::VkVertexInputAttributeDescription vertexInputAttributeDescriptions[2] =
378	{
379		{
380			0u,
381			0u,
382			vk::VK_FORMAT_R32G32B32A32_SFLOAT,
383			0u
384		},
385		{
386			1u,
387			0u,
388			vk::VK_FORMAT_R32G32B32A32_SFLOAT,
389			(deUint32)(sizeof(float)* 4),
390		}
391	};
392
393	m_vertexInputState = PipelineCreateInfo::VertexInputState(1,
394															  &vertexInputBindingDescription,
395															  2,
396															  vertexInputAttributeDescriptions);
397
398	const vk::VkDeviceSize dataSize = m_data.vertices.size() * sizeof(PositionColorVertex);
399	m_vertexBuffer = Buffer::createAndAlloc(m_vk, device, BufferCreateInfo(dataSize,
400		vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT), m_context.getDefaultAllocator(), vk::MemoryRequirement::HostVisible);
401
402	deUint8* ptr = reinterpret_cast<deUint8*>(m_vertexBuffer->getBoundMemory().getHostPtr());
403	deMemcpy(ptr, &(m_data.vertices[0]), static_cast<size_t>(dataSize));
404
405	vk::flushMappedMemoryRange(m_vk,
406							   device,
407							   m_vertexBuffer->getBoundMemory().getMemory(),
408							   m_vertexBuffer->getBoundMemory().getOffset(),
409							   VK_WHOLE_SIZE);
410
411	const CmdPoolCreateInfo cmdPoolCreateInfo(queueFamilyIndex);
412	m_cmdPool = vk::createCommandPool(m_vk, device, &cmdPoolCreateInfo);
413
414	const vk::VkCommandBufferAllocateInfo cmdBufferAllocateInfo =
415	{
416		vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,	// VkStructureType			sType;
417		DE_NULL,											// const void*				pNext;
418		*m_cmdPool,											// VkCommandPool			commandPool;
419		vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY,				// VkCommandBufferLevel		level;
420		1u,													// deUint32					bufferCount;
421	};
422	m_cmdBuffer = vk::allocateCommandBuffer(m_vk, device, &cmdBufferAllocateInfo);
423
424	initPipeline(device);
425}
426
427void DrawTestInstanceBase::initPipeline (const vk::VkDevice device)
428{
429	const vk::Unique<vk::VkShaderModule>	vs(createShaderModule(m_vk, device, m_context.getBinaryCollection().get("vert"), 0));
430	const vk::Unique<vk::VkShaderModule>	fs(createShaderModule(m_vk, device, m_context.getBinaryCollection().get("frag"), 0));
431
432	const PipelineCreateInfo::ColorBlendState::Attachment vkCbAttachmentState;
433
434	vk::VkViewport viewport;
435	viewport.x				= 0;
436	viewport.y				= 0;
437	viewport.width			= static_cast<float>(WIDTH);
438	viewport.height			= static_cast<float>(HEIGHT);
439	viewport.minDepth		= 0.0f;
440	viewport.maxDepth		= 1.0f;
441
442	vk::VkRect2D scissor;
443	scissor.offset.x		= 0;
444	scissor.offset.y		= 0;
445	scissor.extent.width	= WIDTH;
446	scissor.extent.height	= HEIGHT;
447
448	PipelineCreateInfo pipelineCreateInfo(*m_pipelineLayout, *m_renderPass, 0, 0);
449	pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*vs, "main", vk::VK_SHADER_STAGE_VERTEX_BIT));
450	pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*fs, "main", vk::VK_SHADER_STAGE_FRAGMENT_BIT));
451	pipelineCreateInfo.addState(PipelineCreateInfo::VertexInputState(m_vertexInputState));
452	pipelineCreateInfo.addState(PipelineCreateInfo::InputAssemblerState(m_data.topology));
453	pipelineCreateInfo.addState(PipelineCreateInfo::ColorBlendState(1, &vkCbAttachmentState));
454	pipelineCreateInfo.addState(PipelineCreateInfo::ViewportState(1, std::vector<vk::VkViewport>(1, viewport), std::vector<vk::VkRect2D>(1, scissor)));
455	pipelineCreateInfo.addState(PipelineCreateInfo::DepthStencilState());
456	pipelineCreateInfo.addState(PipelineCreateInfo::RasterizerState());
457	pipelineCreateInfo.addState(PipelineCreateInfo::MultiSampleState());
458
459	m_pipeline = vk::createGraphicsPipeline(m_vk, device, DE_NULL, &pipelineCreateInfo);
460}
461
462void DrawTestInstanceBase::beginRenderPass (void)
463{
464	const vk::VkClearColorValue clearColor = { { 0.0f, 0.0f, 0.0f, 1.0f } };
465	const CmdBufferBeginInfo beginInfo;
466
467	m_vk.beginCommandBuffer(*m_cmdBuffer, &beginInfo);
468
469	initialTransitionColor2DImage(m_vk, *m_cmdBuffer, m_colorTargetImage->object(), vk::VK_IMAGE_LAYOUT_GENERAL);
470
471	const ImageSubresourceRange subresourceRange(vk::VK_IMAGE_ASPECT_COLOR_BIT);
472	m_vk.cmdClearColorImage(*m_cmdBuffer, m_colorTargetImage->object(),
473		vk::VK_IMAGE_LAYOUT_GENERAL, &clearColor, 1, &subresourceRange);
474
475	const vk::VkMemoryBarrier memBarrier =
476	{
477		vk::VK_STRUCTURE_TYPE_MEMORY_BARRIER,
478		DE_NULL,
479		vk::VK_ACCESS_TRANSFER_WRITE_BIT,
480		vk::VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT
481	};
482
483	m_vk.cmdPipelineBarrier(*m_cmdBuffer, vk::VK_PIPELINE_STAGE_TRANSFER_BIT,
484		vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
485		0, 1, &memBarrier, 0, DE_NULL, 0, DE_NULL);
486
487	const vk::VkRect2D renderArea = { { 0, 0 }, { WIDTH, HEIGHT } };
488	const RenderPassBeginInfo renderPassBegin(*m_renderPass, *m_framebuffer, renderArea);
489
490	m_vk.cmdBeginRenderPass(*m_cmdBuffer, &renderPassBegin, vk::VK_SUBPASS_CONTENTS_INLINE);
491}
492
493void DrawTestInstanceBase::generateRefImage (const tcu::PixelBufferAccess& access, const std::vector<tcu::Vec4>& vertices, const std::vector<tcu::Vec4>& colors) const
494{
495	const PassthruVertShader				vertShader;
496	const PassthruFragShader				fragShader;
497	const rr::Program						program			(&vertShader, &fragShader);
498	const rr::MultisamplePixelBufferAccess	colorBuffer		= rr::MultisamplePixelBufferAccess::fromSinglesampleAccess(access);
499	const rr::RenderTarget					renderTarget	(colorBuffer);
500	const rr::RenderState					renderState		((rr::ViewportState(colorBuffer)));
501	const rr::Renderer						renderer;
502
503	const rr::VertexAttrib	vertexAttribs[] =
504	{
505		rr::VertexAttrib(rr::VERTEXATTRIBTYPE_FLOAT, 4, sizeof(tcu::Vec4), 0, &vertices[0]),
506		rr::VertexAttrib(rr::VERTEXATTRIBTYPE_FLOAT, 4, sizeof(tcu::Vec4), 0, &colors[0])
507	};
508
509	renderer.draw(rr::DrawCommand(renderState,
510								  renderTarget,
511								  program,
512								  DE_LENGTH_OF_ARRAY(vertexAttribs),
513								  &vertexAttribs[0],
514								  rr::PrimitiveList(mapVkPrimitiveTopology(m_data.topology), (deUint32)vertices.size(), 0)));
515}
516
517template<typename T>
518class DrawTestInstance : public DrawTestInstanceBase
519{
520public:
521							DrawTestInstance		(Context& context, const T& data);
522	virtual					~DrawTestInstance		(void);
523	virtual void			generateDrawData		(void);
524	virtual tcu::TestStatus	iterate					(void);
525private:
526	T						m_data;
527};
528
529template<typename T>
530DrawTestInstance<T>::DrawTestInstance (Context& context, const T& data)
531	: DrawTestInstanceBase	(context)
532	, m_data				(data)
533{
534	generateDrawData();
535	initialize(m_data);
536}
537
538template<typename T>
539DrawTestInstance<T>::~DrawTestInstance (void)
540{
541}
542
543template<typename T>
544void DrawTestInstance<T>::generateDrawData (void)
545{
546	DE_FATAL("Using the general case of this function is forbidden!");
547}
548
549template<typename T>
550tcu::TestStatus DrawTestInstance<T>::iterate (void)
551{
552	DE_FATAL("Using the general case of this function is forbidden!");
553	return tcu::TestStatus::fail("");
554}
555
556template<typename T>
557class DrawTestCase : public TestCase
558{
559	public:
560									DrawTestCase		(tcu::TestContext& context, const char* name, const char* desc, const T data);
561									~DrawTestCase		(void);
562	virtual	void					initPrograms		(vk::SourceCollections& programCollection) const;
563	virtual void					initShaderSources	(void);
564	virtual TestInstance*			createInstance		(Context& context) const;
565
566private:
567	T													m_data;
568	std::string											m_vertShaderSource;
569	std::string											m_fragShaderSource;
570};
571
572template<typename T>
573DrawTestCase<T>::DrawTestCase (tcu::TestContext& context, const char* name, const char* desc, const T data)
574	: vkt::TestCase	(context, name, desc)
575	, m_data		(data)
576{
577	initShaderSources();
578}
579
580template<typename T>
581DrawTestCase<T>::~DrawTestCase	(void)
582{
583}
584
585template<typename T>
586void DrawTestCase<T>::initPrograms (vk::SourceCollections& programCollection) const
587{
588	programCollection.glslSources.add("vert") << glu::VertexSource(m_vertShaderSource);
589	programCollection.glslSources.add("frag") << glu::FragmentSource(m_fragShaderSource);
590}
591
592template<typename T>
593void DrawTestCase<T>::initShaderSources (void)
594{
595	std::stringstream vertShader;
596	vertShader	<< "#version 430\n"
597				<< "layout(location = 0) in vec4 in_position;\n"
598				<< "layout(location = 1) in vec4 in_color;\n"
599				<< "layout(location = 0) out vec4 out_color;\n"
600
601				<< "out gl_PerVertex {\n"
602				<< "    vec4  gl_Position;\n"
603				<< "    float gl_PointSize;\n"
604				<< "};\n"
605				<< "void main() {\n"
606				<< "    gl_PointSize = 1.0;\n"
607				<< "    gl_Position  = in_position;\n"
608				<< "    out_color    = in_color;\n"
609				<< "}\n";
610
611	m_vertShaderSource = vertShader.str();
612
613	std::stringstream fragShader;
614	fragShader	<< "#version 430\n"
615				<< "layout(location = 0) in vec4 in_color;\n"
616				<< "layout(location = 0) out vec4 out_color;\n"
617				<< "void main()\n"
618				<< "{\n"
619				<< "    out_color = in_color;\n"
620				<< "}\n";
621
622	m_fragShaderSource = fragShader.str();
623}
624
625template<typename T>
626TestInstance* DrawTestCase<T>::createInstance (Context& context) const
627{
628	return new DrawTestInstance<T>(context, m_data);
629}
630
631// Specialized cases
632template<>
633void DrawTestInstance<DrawParams>::generateDrawData (void)
634{
635	de::Random		rnd			(SEED ^ m_data.params.firstVertex ^ m_data.params.vertexCount);
636
637	const deUint32	vectorSize	= m_data.params.firstVertex + m_data.params.vertexCount;
638
639	// Initialize the vector
640	m_data.vertices = std::vector<PositionColorVertex>(vectorSize, PositionColorVertex(tcu::Vec4(0.0, 0.0, 0.0, 0.0), tcu::Vec4(0.0, 0.0, 0.0, 0.0)));
641
642	// Fill only the used indexes
643	for (deUint32 vertexIdx = m_data.params.firstVertex; vertexIdx < vectorSize; ++vertexIdx)
644	{
645		m_data.vertices[vertexIdx] = PositionColorVertex(
646			tcu::Vec4(rnd.getFloat(-1.0, 1.0), rnd.getFloat(-1.0, 1.0), 1.0, 1.0),										// Coord
647			tcu::Vec4(rnd.getFloat(0.0, 1.0), rnd.getFloat(0.0, 1.0), rnd.getFloat(0.0, 1.0), rnd.getFloat(0.0, 1.0)));	// Color
648	}
649}
650
651template<>
652tcu::TestStatus DrawTestInstance<DrawParams>::iterate (void)
653{
654	tcu::TestLog			&log				= m_context.getTestContext().getLog();
655	const vk::VkQueue		queue				= m_context.getUniversalQueue();
656
657	beginRenderPass();
658
659	const vk::VkDeviceSize	vertexBufferOffset	= 0;
660	const vk::VkBuffer		vertexBuffer		= m_vertexBuffer->object();
661
662	m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
663	m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
664	m_vk.cmdDraw(*m_cmdBuffer, m_data.params.vertexCount, m_data.params.instanceCount, m_data.params.firstVertex, m_data.params.firstInstance);
665	m_vk.cmdEndRenderPass(*m_cmdBuffer);
666	m_vk.endCommandBuffer(*m_cmdBuffer);
667
668	vk::VkSubmitInfo	submitInfo =
669	{
670		vk::VK_STRUCTURE_TYPE_SUBMIT_INFO,			// VkStructureType			sType;
671		DE_NULL,									// const void*				pNext;
672		0,											// deUint32					waitSemaphoreCount;
673		DE_NULL,									// const VkSemaphore*		pWaitSemaphores;
674		(const vk::VkPipelineStageFlags*)DE_NULL,
675		1,											// deUint32					commandBufferCount;
676		&m_cmdBuffer.get(),							// const VkCommandBuffer*	pCommandBuffers;
677		0,											// deUint32					signalSemaphoreCount;
678		DE_NULL										// const VkSemaphore*		pSignalSemaphores;
679	};
680	VK_CHECK(m_vk.queueSubmit(queue, 1, &submitInfo, DE_NULL));
681
682	// Validation
683	tcu::TextureLevel refImage (vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5 + WIDTH), (int)(0.5 + HEIGHT));
684	tcu::clear(refImage.getAccess(), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
685
686	std::vector<tcu::Vec4>	vertices;
687	std::vector<tcu::Vec4>	colors;
688
689	for (std::vector<PositionColorVertex>::const_iterator vertex = m_data.vertices.begin() + m_data.params.firstVertex; vertex != m_data.vertices.end(); ++vertex)
690	{
691		vertices.push_back(vertex->position);
692		colors.push_back(vertex->color);
693	}
694	generateRefImage(refImage.getAccess(), vertices, colors);
695
696	VK_CHECK(m_vk.queueWaitIdle(queue));
697
698	const vk::VkOffset3D zeroOffset = { 0, 0, 0 };
699	const tcu::ConstPixelBufferAccess renderedFrame = m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(),
700		vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
701
702	qpTestResult res = QP_TEST_RESULT_PASS;
703
704	if (!imageCompare(log, refImage.getAccess(), renderedFrame, m_data.topology))
705		res = QP_TEST_RESULT_FAIL;
706
707	return tcu::TestStatus(res, qpGetTestResultName(res));
708}
709
710template<>
711void DrawTestInstance<DrawIndexedParams>::generateDrawData (void)
712{
713	de::Random		rnd			(SEED ^ m_data.params.firstIndex ^ m_data.params.indexCount);
714	const deUint32	indexSize	= m_data.params.firstIndex + m_data.params.indexCount;
715
716	// Initialize the vector with zeros
717	m_data.indexes = std::vector<deUint32>(indexSize, 0);
718
719	deUint32		highestIndex	= 0;	// Store to highest index to calculate the vertices size
720	// Fill the indexes from firstIndex
721	for (deUint32 idx = 0; idx < m_data.params.indexCount; ++idx)
722	{
723		deUint32	vertexIdx	= rnd.getInt(m_data.params.vertexOffset, INDEX_LIMIT);
724		highestIndex = (vertexIdx > highestIndex) ? vertexIdx : highestIndex;
725
726		m_data.indexes[m_data.params.firstIndex + idx]	= vertexIdx;
727	}
728
729	// Fill up the vertex coordinates with zeros until the highestIndex including the vertexOffset
730	m_data.vertices = std::vector<PositionColorVertex>(m_data.params.vertexOffset + highestIndex + 1, PositionColorVertex(tcu::Vec4(0.0, 0.0, 0.0, 0.0), tcu::Vec4(0.0, 0.0, 0.0, 0.0)));
731
732	// Generate random vertex only where you have index pointing at
733	for (std::vector<deUint32>::const_iterator indexIt = m_data.indexes.begin() + m_data.params.firstIndex; indexIt != m_data.indexes.end(); ++indexIt)
734	{
735		// Get iterator to the vertex position  with the vertexOffset
736		std::vector<PositionColorVertex>::iterator vertexIt = m_data.vertices.begin() + m_data.params.vertexOffset + *indexIt;
737
738		tcu::VecAccess<float, 4, 4>	positionAccess = vertexIt->position.xyzw();
739		positionAccess = tcu::Vec4(rnd.getFloat(-1.0, 1.0), rnd.getFloat(-1.0, 1.0), 1.0, 1.0);
740
741		tcu::VecAccess<float, 4, 4>	colorAccess = vertexIt->color.xyzw();
742		colorAccess = tcu::Vec4(rnd.getFloat(0.0, 1.0), rnd.getFloat(0.0, 1.0), rnd.getFloat(0.0, 1.0), rnd.getFloat(0.0, 1.0));
743	}
744}
745
746template<>
747tcu::TestStatus DrawTestInstance<DrawIndexedParams>::iterate (void)
748{
749	tcu::TestLog				&log				= m_context.getTestContext().getLog();
750	const vk::DeviceInterface&	vk					= m_context.getDeviceInterface();
751	const vk::VkDevice			vkDevice			= m_context.getDevice();
752	const deUint32				queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
753	const vk::VkQueue			queue				= m_context.getUniversalQueue();
754	vk::Allocator&				allocator			= m_context.getDefaultAllocator();
755
756	beginRenderPass();
757
758	const vk::VkDeviceSize	vertexBufferOffset = 0;
759	const vk::VkBuffer	vertexBuffer = m_vertexBuffer->object();
760
761	m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
762	m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
763
764	const deUint32	bufferSize	= (deUint32)(m_data.indexes.size() * sizeof(deUint32));
765
766	vk::Move<vk::VkBuffer>	indexBuffer;
767
768	const vk::VkBufferCreateInfo	bufferCreateInfo =
769	{
770		vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,	// VkStructureType		sType;
771		DE_NULL,									// const void*			pNext;
772		0u,											// VkBufferCreateFlags	flags;
773		bufferSize,									// VkDeviceSize			size;
774		vk::VK_BUFFER_USAGE_INDEX_BUFFER_BIT,		// VkBufferUsageFlags	usage;
775		vk::VK_SHARING_MODE_EXCLUSIVE,				// VkSharingMode		sharingMode;
776		1u,											// deUint32				queueFamilyIndexCount;
777		&queueFamilyIndex,							// const deUint32*		pQueueFamilyIndices;
778	};
779
780	indexBuffer = createBuffer(vk, vkDevice, &bufferCreateInfo);
781
782	de::MovePtr<vk::Allocation>	indexAlloc;
783
784	indexAlloc = allocator.allocate(getBufferMemoryRequirements(vk, vkDevice, *indexBuffer), vk::MemoryRequirement::HostVisible);
785	VK_CHECK(vk.bindBufferMemory(vkDevice, *indexBuffer, indexAlloc->getMemory(), indexAlloc->getOffset()));
786
787	deMemcpy(indexAlloc->getHostPtr(), &(m_data.indexes[0]), bufferSize);
788
789	vk::flushMappedMemoryRange(m_vk, vkDevice, indexAlloc->getMemory(), indexAlloc->getOffset(), bufferSize);
790
791	m_vk.cmdBindIndexBuffer(*m_cmdBuffer, *indexBuffer, 0u, m_data.indexType);
792	m_vk.cmdDrawIndexed(*m_cmdBuffer, m_data.params.indexCount, m_data.params.instanceCount, m_data.params.firstIndex, m_data.params.vertexOffset, m_data.params.firstInstance);
793	m_vk.cmdEndRenderPass(*m_cmdBuffer);
794	m_vk.endCommandBuffer(*m_cmdBuffer);
795
796	vk::VkSubmitInfo	submitInfo =
797	{
798		vk::VK_STRUCTURE_TYPE_SUBMIT_INFO,			// VkStructureType			sType;
799		DE_NULL,									// const void*				pNext;
800		0,											// deUint32					waitSemaphoreCount;
801		DE_NULL,									// const VkSemaphore*		pWaitSemaphores;
802		(const vk::VkPipelineStageFlags*)DE_NULL,
803		1,											// deUint32					commandBufferCount;
804		&m_cmdBuffer.get(),							// const VkCommandBuffer*	pCommandBuffers;
805		0,											// deUint32					signalSemaphoreCount;
806		DE_NULL										// const VkSemaphore*		pSignalSemaphores;
807	};
808	VK_CHECK(m_vk.queueSubmit(queue, 1, &submitInfo, DE_NULL));
809
810	// Validation
811	tcu::TextureLevel	refImage	(vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5 + WIDTH), (int)(0.5 + HEIGHT));
812	tcu::clear(refImage.getAccess(), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
813
814	std::vector<tcu::Vec4>	vertices;
815	std::vector<tcu::Vec4>	colors;
816
817	for (std::vector<deUint32>::const_iterator it = m_data.indexes.begin() + m_data.params.firstIndex; it != m_data.indexes.end(); ++it)
818	{
819		deUint32 idx = m_data.params.vertexOffset + *it;
820		vertices.push_back(m_data.vertices[idx].position);
821		colors.push_back(m_data.vertices[idx].color);
822	}
823	generateRefImage(refImage.getAccess(), vertices, colors);
824
825	VK_CHECK(m_vk.queueWaitIdle(queue));
826
827	const vk::VkOffset3D zeroOffset = { 0, 0, 0 };
828	const tcu::ConstPixelBufferAccess renderedFrame = m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(),
829		vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
830
831	qpTestResult res = QP_TEST_RESULT_PASS;
832
833	if (!imageCompare(log, refImage.getAccess(), renderedFrame, m_data.topology))
834		res = QP_TEST_RESULT_FAIL;
835
836	return tcu::TestStatus(res, qpGetTestResultName(res));
837}
838
839template<>
840void DrawTestInstance<DrawIndirectParams>::generateDrawData (void)
841{
842	de::Random	rnd(SEED ^ m_data.commands[0].vertexCount ^ m_data.commands[0].firstVertex);
843
844	deUint32 lastIndex	= 0;
845
846	// Find the interval which will be used
847	for (std::vector<vk::VkDrawIndirectCommand>::const_iterator it = m_data.commands.begin(); it != m_data.commands.end(); ++it)
848	{
849		const deUint32	index = it->firstVertex + it->vertexCount;
850		lastIndex	= (index > lastIndex) ? index : lastIndex;
851	}
852
853	// Initialize with zeros
854	m_data.vertices = std::vector<PositionColorVertex>(lastIndex, PositionColorVertex(tcu::Vec4(0.0, 0.0, 0.0, 0.0), tcu::Vec4(0.0, 0.0, 0.0, 0.0)));
855
856	// Generate random vertices only where necessary
857	for (std::vector<vk::VkDrawIndirectCommand>::const_iterator it = m_data.commands.begin(); it != m_data.commands.end(); ++it)
858	{
859		std::vector<PositionColorVertex>::iterator vertexStart = m_data.vertices.begin() + it->firstVertex;
860
861		for (deUint32 idx = 0; idx < it->vertexCount; ++idx)
862		{
863			std::vector<PositionColorVertex>::iterator vertexIt = vertexStart + idx;
864
865			tcu::VecAccess<float, 4, 4> positionAccess = vertexIt->position.xyzw();
866			positionAccess = tcu::Vec4(rnd.getFloat(-1.0, 1.0), rnd.getFloat(-1.0, 1.0), 1.0, 1.0);
867
868			tcu::VecAccess<float, 4, 4> colorAccess = vertexIt->color.xyzw();
869			colorAccess = tcu::Vec4(rnd.getFloat(0.0, 1.0), rnd.getFloat(0.0, 1.0), rnd.getFloat(0.0, 1.0), rnd.getFloat(0.0, 1.0));
870		}
871	}
872}
873
874template<>
875tcu::TestStatus DrawTestInstance<DrawIndirectParams>::iterate (void)
876{
877	tcu::TestLog						&log				= m_context.getTestContext().getLog();
878	const vk::DeviceInterface&			vk					= m_context.getDeviceInterface();
879	const vk::VkDevice					vkDevice			= m_context.getDevice();
880	vk::Allocator&						allocator			= m_context.getDefaultAllocator();
881	const vk::VkQueue					queue				= m_context.getUniversalQueue();
882	const deUint32						queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
883	const vk::VkPhysicalDeviceFeatures	features			= m_context.getDeviceFeatures();
884
885	beginRenderPass();
886
887	const vk::VkDeviceSize	vertexBufferOffset	= 0;
888	const vk::VkBuffer		vertexBuffer		= m_vertexBuffer->object();
889
890	m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
891	m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
892
893	vk::Move<vk::VkBuffer>		indirectBuffer;
894	de::MovePtr<vk::Allocation>	indirectAlloc;
895
896	{
897		const vk::VkDeviceSize	indirectInfoSize	= m_data.commands.size() * sizeof(vk::VkDrawIndirectCommand);
898
899		const vk::VkBufferCreateInfo	indirectCreateInfo =
900		{
901			vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,	// VkStructureType		sType;
902			DE_NULL,									// const void*			pNext;
903			0u,											// VkBufferCreateFlags	flags;
904			indirectInfoSize,							// VkDeviceSize			size;
905			vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT,	// VkBufferUsageFlags	usage;
906			vk::VK_SHARING_MODE_EXCLUSIVE,				// VkSharingMode		sharingMode;
907			1u,											// deUint32				queueFamilyIndexCount;
908			&queueFamilyIndex,							// const deUint32*		pQueueFamilyIndices;
909		};
910
911		indirectBuffer	= createBuffer(vk, vkDevice, &indirectCreateInfo);
912		indirectAlloc	= allocator.allocate(getBufferMemoryRequirements(vk, vkDevice, *indirectBuffer), vk::MemoryRequirement::HostVisible);
913		VK_CHECK(vk.bindBufferMemory(vkDevice, *indirectBuffer, indirectAlloc->getMemory(), indirectAlloc->getOffset()));
914
915		deMemcpy(indirectAlloc->getHostPtr(), &(m_data.commands[0]), (size_t)indirectInfoSize);
916
917		vk::flushMappedMemoryRange(m_vk, vkDevice, indirectAlloc->getMemory(), indirectAlloc->getOffset(), indirectInfoSize);
918	}
919
920	// If multiDrawIndirect not supported execute single calls
921	if (m_data.commands.size() > 1 && !(features.multiDrawIndirect))
922	{
923		for (deUint32 cmdIdx = 0; cmdIdx < m_data.commands.size(); ++cmdIdx)
924		{
925			const deUint32	offset	= (deUint32)(indirectAlloc->getOffset() + cmdIdx * sizeof(vk::VkDrawIndirectCommand));
926			m_vk.cmdDrawIndirect(*m_cmdBuffer, *indirectBuffer, offset, 1, sizeof(vk::VkDrawIndirectCommand));
927		}
928	}
929	else
930	{
931		m_vk.cmdDrawIndirect(*m_cmdBuffer, *indirectBuffer, indirectAlloc->getOffset(), (deUint32)m_data.commands.size(), sizeof(vk::VkDrawIndirectCommand));
932	}
933
934	m_vk.cmdEndRenderPass(*m_cmdBuffer);
935	m_vk.endCommandBuffer(*m_cmdBuffer);
936
937	vk::VkSubmitInfo	submitInfo =
938	{
939		vk::VK_STRUCTURE_TYPE_SUBMIT_INFO,			// VkStructureType			sType;
940		DE_NULL,									// const void*				pNext;
941		0,											// deUint32					waitSemaphoreCount;
942		DE_NULL,									// const VkSemaphore*		pWaitSemaphores;
943		(const vk::VkPipelineStageFlags*)DE_NULL,
944		1,											// deUint32					commandBufferCount;
945		&m_cmdBuffer.get(),							// const VkCommandBuffer*	pCommandBuffers;
946		0,											// deUint32					signalSemaphoreCount;
947		DE_NULL										// const VkSemaphore*		pSignalSemaphores;
948	};
949	VK_CHECK(m_vk.queueSubmit(queue, 1, &submitInfo, DE_NULL));
950
951	// Validation
952	tcu::TextureLevel refImage (vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5 + WIDTH), (int)(0.5 + HEIGHT));
953	tcu::clear(refImage.getAccess(), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
954
955	for (std::vector<vk::VkDrawIndirectCommand>::const_iterator it = m_data.commands.begin(); it != m_data.commands.end(); ++it)
956	{
957		std::vector<tcu::Vec4>	vertices;
958		std::vector<tcu::Vec4>	colors;
959
960		std::vector<PositionColorVertex>::const_iterator	firstIt	= m_data.vertices.begin() + it->firstVertex;
961		std::vector<PositionColorVertex>::const_iterator	lastIt	= firstIt + it->vertexCount;
962
963		for (std::vector<PositionColorVertex>::const_iterator vertex = firstIt; vertex != lastIt; ++vertex)
964		{
965			vertices.push_back(vertex->position);
966			colors.push_back(vertex->color);
967		}
968		generateRefImage(refImage.getAccess(), vertices, colors);
969	}
970
971	VK_CHECK(m_vk.queueWaitIdle(queue));
972
973	const vk::VkOffset3D zeroOffset = { 0, 0, 0 };
974	const tcu::ConstPixelBufferAccess renderedFrame = m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(),
975		vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
976
977	qpTestResult res = QP_TEST_RESULT_PASS;
978
979	if (!imageCompare(log, refImage.getAccess(), renderedFrame, m_data.topology))
980		res = QP_TEST_RESULT_FAIL;
981
982	return tcu::TestStatus(res, qpGetTestResultName(res));
983}
984
985template<>
986void DrawTestInstance<DrawIndexedIndirectParams>::generateDrawData (void)
987{
988	de::Random		rnd			(SEED ^ m_data.commands[0].firstIndex ^ m_data.commands[0].indexCount);
989
990	deUint32		lastIndex	= 0;
991
992	// Get the maximum range of indexes
993	for (std::vector<vk::VkDrawIndexedIndirectCommand>::const_iterator it = m_data.commands.begin(); it != m_data.commands.end(); ++it)
994	{
995		const deUint32	index		= it->firstIndex + it->indexCount;
996						lastIndex	= (index > lastIndex) ? index : lastIndex;
997	}
998
999	// Initialize the vector with zeros
1000	m_data.indexes = std::vector<deUint32>(lastIndex, 0);
1001
1002	deUint32	highestIndex	= 0;
1003
1004	// Generate random indexes for the ranges
1005	for (std::vector<vk::VkDrawIndexedIndirectCommand>::const_iterator it = m_data.commands.begin(); it != m_data.commands.end(); ++it)
1006	{
1007		for (deUint32 idx = 0; idx < it->indexCount; ++idx)
1008		{
1009			const deUint32	vertexIdx	= rnd.getInt(it->vertexOffset, INDEX_LIMIT);
1010			const deUint32	maxIndex	= vertexIdx + it->vertexOffset;
1011
1012			highestIndex = (maxIndex > highestIndex) ? maxIndex : highestIndex;
1013			m_data.indexes[it->firstIndex + idx] = vertexIdx;
1014		}
1015	}
1016
1017	// Initialize the vertex vector
1018	m_data.vertices = std::vector<PositionColorVertex>(highestIndex + 1, PositionColorVertex(tcu::Vec4(0.0, 0.0, 0.0, 0.0), tcu::Vec4(0.0, 0.0, 0.0, 0.0)));
1019
1020	// Generate random vertices in the used locations
1021	for (std::vector<vk::VkDrawIndexedIndirectCommand>::const_iterator cmdIt = m_data.commands.begin(); cmdIt != m_data.commands.end(); ++cmdIt)
1022	{
1023		deUint32	firstIdx	= cmdIt->firstIndex;
1024		deUint32	lastIdx		= firstIdx + cmdIt->indexCount;
1025
1026		for (deUint32 idx = firstIdx; idx < lastIdx; ++idx)
1027		{
1028			std::vector<PositionColorVertex>::iterator	vertexIt = m_data.vertices.begin() + cmdIt->vertexOffset + m_data.indexes[idx];
1029
1030			tcu::VecAccess<float, 4, 4> positionAccess = vertexIt->position.xyzw();
1031			positionAccess = tcu::Vec4(rnd.getFloat(-1.0, 1.0), rnd.getFloat(-1.0, 1.0), 1.0, 1.0);
1032
1033			tcu::VecAccess<float, 4, 4> colorAccess = vertexIt->color.xyzw();
1034			colorAccess = tcu::Vec4(rnd.getFloat(0.0, 1.0), rnd.getFloat(0.0, 1.0), rnd.getFloat(0.0, 1.0), rnd.getFloat(0.0, 1.0));
1035		}
1036	}
1037}
1038
1039template<>
1040tcu::TestStatus DrawTestInstance<DrawIndexedIndirectParams>::iterate (void)
1041{
1042	tcu::TestLog						&log				= m_context.getTestContext().getLog();
1043	const vk::DeviceInterface&			vk					= m_context.getDeviceInterface();
1044	const vk::VkDevice					vkDevice			= m_context.getDevice();
1045	const deUint32						queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
1046	const vk::VkQueue					queue				= m_context.getUniversalQueue();
1047	vk::Allocator&						allocator			= m_context.getDefaultAllocator();
1048	const vk::VkPhysicalDeviceFeatures	features			= m_context.getDeviceFeatures();
1049
1050	beginRenderPass();
1051
1052	const vk::VkDeviceSize	vertexBufferOffset	= 0;
1053	const vk::VkBuffer		vertexBuffer		= m_vertexBuffer->object();
1054
1055	m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
1056	m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
1057
1058	vk::Move<vk::VkBuffer>		indirectBuffer;
1059	de::MovePtr<vk::Allocation>	indirectAlloc;
1060
1061	{
1062		const vk::VkDeviceSize	indirectInfoSize	= m_data.commands.size() * sizeof(vk::VkDrawIndexedIndirectCommand);
1063
1064		const vk::VkBufferCreateInfo	indirectCreateInfo =
1065		{
1066			vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,	// VkStructureType		sType;
1067			DE_NULL,									// const void*			pNext;
1068			0u,											// VkBufferCreateFlags	flags;
1069			indirectInfoSize,							// VkDeviceSize			size;
1070			vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT,	// VkBufferUsageFlags	usage;
1071			vk::VK_SHARING_MODE_EXCLUSIVE,				// VkSharingMode		sharingMode;
1072			1u,											// deUint32				queueFamilyIndexCount;
1073			&queueFamilyIndex,							// const deUint32*		pQueueFamilyIndices;
1074		};
1075
1076		indirectBuffer	= createBuffer(vk, vkDevice, &indirectCreateInfo);
1077		indirectAlloc	= allocator.allocate(getBufferMemoryRequirements(vk, vkDevice, *indirectBuffer), vk::MemoryRequirement::HostVisible);
1078		VK_CHECK(vk.bindBufferMemory(vkDevice, *indirectBuffer, indirectAlloc->getMemory(), indirectAlloc->getOffset()));
1079
1080		deMemcpy(indirectAlloc->getHostPtr(), &(m_data.commands[0]), (size_t)indirectInfoSize);
1081
1082		vk::flushMappedMemoryRange(m_vk, vkDevice, indirectAlloc->getMemory(), indirectAlloc->getOffset(), indirectInfoSize);
1083	}
1084
1085	const deUint32	bufferSize = (deUint32)(m_data.indexes.size() * sizeof(deUint32));
1086
1087	vk::Move<vk::VkBuffer>			indexBuffer;
1088
1089	const vk::VkBufferCreateInfo	bufferCreateInfo =
1090	{
1091		vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,	// VkStructureType		sType;
1092		DE_NULL,									// const void*			pNext;
1093		0u,											// VkBufferCreateFlags	flags;
1094		bufferSize,									// VkDeviceSize			size;
1095		vk::VK_BUFFER_USAGE_INDEX_BUFFER_BIT,		// VkBufferUsageFlags	usage;
1096		vk::VK_SHARING_MODE_EXCLUSIVE,				// VkSharingMode		sharingMode;
1097		1u,											// deUint32				queueFamilyIndexCount;
1098		&queueFamilyIndex,							// const deUint32*		pQueueFamilyIndices;
1099	};
1100
1101	indexBuffer = createBuffer(vk, vkDevice, &bufferCreateInfo);
1102
1103	de::MovePtr<vk::Allocation>	indexAlloc;
1104
1105	indexAlloc = allocator.allocate(getBufferMemoryRequirements(vk, vkDevice, *indexBuffer), vk::MemoryRequirement::HostVisible);
1106	VK_CHECK(vk.bindBufferMemory(vkDevice, *indexBuffer, indexAlloc->getMemory(), indexAlloc->getOffset()));
1107
1108	deMemcpy(indexAlloc->getHostPtr(), &(m_data.indexes[0]), bufferSize);
1109
1110	vk::flushMappedMemoryRange(m_vk, vkDevice, indexAlloc->getMemory(), indexAlloc->getOffset(), bufferSize);
1111
1112	m_vk.cmdBindIndexBuffer(*m_cmdBuffer, *indexBuffer, 0u, m_data.indexType);
1113
1114	// If multiDrawIndirect not supported execute single calls
1115	if (m_data.commands.size() > 1 && !(features.multiDrawIndirect))
1116	{
1117		for (deUint32 cmdIdx = 0; cmdIdx < m_data.commands.size(); ++cmdIdx)
1118		{
1119			const deUint32	offset	= (deUint32)(indirectAlloc->getOffset() + cmdIdx * sizeof(vk::VkDrawIndexedIndirectCommand));
1120			m_vk.cmdDrawIndexedIndirect(*m_cmdBuffer, *indirectBuffer, offset, 1, sizeof(vk::VkDrawIndexedIndirectCommand));
1121		}
1122	}
1123	else
1124	{
1125		m_vk.cmdDrawIndexedIndirect(*m_cmdBuffer, *indirectBuffer, indirectAlloc->getOffset(), (deUint32)m_data.commands.size(), sizeof(vk::VkDrawIndexedIndirectCommand));
1126	}
1127
1128	m_vk.cmdEndRenderPass(*m_cmdBuffer);
1129	m_vk.endCommandBuffer(*m_cmdBuffer);
1130
1131	vk::VkSubmitInfo	submitInfo =
1132	{
1133		vk::VK_STRUCTURE_TYPE_SUBMIT_INFO,			// VkStructureType			sType;
1134		DE_NULL,									// const void*				pNext;
1135		0,											// deUint32					waitSemaphoreCount;
1136		DE_NULL,									// const VkSemaphore*		pWaitSemaphores;
1137		(const vk::VkPipelineStageFlags*)DE_NULL,
1138		1,											// deUint32					commandBufferCount;
1139		&m_cmdBuffer.get(),							// const VkCommandBuffer*	pCommandBuffers;
1140		0,											// deUint32					signalSemaphoreCount;
1141		DE_NULL										// const VkSemaphore*		pSignalSemaphores;
1142	};
1143	VK_CHECK(m_vk.queueSubmit(queue, 1, &submitInfo, DE_NULL));
1144
1145	// Validation
1146	tcu::TextureLevel refImage (vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5 + WIDTH), (int)(0.5 + HEIGHT));
1147	tcu::clear(refImage.getAccess(), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
1148
1149	for (std::vector<vk::VkDrawIndexedIndirectCommand>::const_iterator cmd = m_data.commands.begin(); cmd != m_data.commands.end(); ++cmd)
1150	{
1151		std::vector<tcu::Vec4>	vertices;
1152		std::vector<tcu::Vec4>	colors;
1153
1154		for (deUint32 idx = 0; idx < cmd->indexCount; ++idx)
1155		{
1156			const deUint32 vertexIndex = cmd->vertexOffset + m_data.indexes[cmd->firstIndex + idx];
1157			vertices.push_back(m_data.vertices[vertexIndex].position);
1158			colors.push_back(m_data.vertices[vertexIndex].color);
1159		}
1160		generateRefImage(refImage.getAccess(), vertices, colors);
1161	}
1162
1163	VK_CHECK(m_vk.queueWaitIdle(queue));
1164
1165	const vk::VkOffset3D zeroOffset = { 0, 0, 0 };
1166	const tcu::ConstPixelBufferAccess renderedFrame = m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(),
1167		vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
1168
1169	qpTestResult res = QP_TEST_RESULT_PASS;
1170
1171	if (!imageCompare(log, refImage.getAccess(), renderedFrame, m_data.topology))
1172		res = QP_TEST_RESULT_FAIL;
1173
1174	return tcu::TestStatus(res, qpGetTestResultName(res));
1175}
1176
1177typedef DrawTestCase<DrawParams>				DrawCase;
1178typedef DrawTestCase<DrawIndexedParams>			IndexedCase;
1179typedef DrawTestCase<DrawIndirectParams>		IndirectCase;
1180typedef DrawTestCase<DrawIndexedIndirectParams>	IndexedIndirectCase;
1181
1182struct TestCaseParams
1183{
1184	const DrawCommandType			command;
1185	const vk::VkPrimitiveTopology	topology;
1186
1187	TestCaseParams (const DrawCommandType cmd, const vk::VkPrimitiveTopology top)
1188		: command	(cmd)
1189		, topology	(top)
1190	{}
1191};
1192
1193}	// anonymous
1194
1195void populateSubGroup (tcu::TestCaseGroup* testGroup, const TestCaseParams caseParams)
1196{
1197	de::Random						rnd			(SEED ^ deStringHash(testGroup->getName()));
1198	tcu::TestContext&				testCtx		= testGroup->getTestContext();
1199	const DrawCommandType			command		= caseParams.command;
1200	const vk::VkPrimitiveTopology	topology	= caseParams.topology;
1201
1202	for (deUint32 primitiveCountIdx = 0; primitiveCountIdx < DE_LENGTH_OF_ARRAY(PRIMITIVE_COUNT); ++primitiveCountIdx)
1203	{
1204		const deUint32 primitives = PRIMITIVE_COUNT[primitiveCountIdx];
1205
1206		deUint32	multiplier	= 1;
1207		deUint32	offset		= 0;
1208		// Calculated by Vulkan 23.1
1209		switch (topology)
1210		{
1211			case vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST:													break;
1212			case vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST:						multiplier = 2;				break;
1213			case vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:													break;
1214			case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:					multiplier = 3;				break;
1215			case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:												break;
1216			case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:									offset = 1;	break;
1217			case vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY:		multiplier = 4;	offset = 1;	break;
1218			case vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY:						offset = 1;	break;
1219			case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY:	multiplier = 6;				break;
1220			case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY:	multiplier = 2;				break;
1221			default:														DE_FATAL("Unsupported topology.");
1222		}
1223
1224		const deUint32	vertexCount		= multiplier * primitives + offset;
1225		std::string		name			= de::toString(primitives);
1226
1227		switch (command)
1228		{
1229			case DRAW_COMMAND_TYPE_DRAW:
1230			{
1231				deUint32	firstPrimitive	= rnd.getInt(0, primitives);
1232				deUint32	firstVertex		= multiplier * firstPrimitive;
1233				testGroup->addChild(new DrawCase(testCtx, name.c_str(), "vkCmdDraw testcase.",
1234					DrawParams(topology, vertexCount, 1, firstVertex, 0))
1235				);
1236				break;
1237			}
1238			case DRAW_COMMAND_TYPE_DRAW_INDEXED:
1239			{
1240				deUint32	firstIndex			= rnd.getInt(0, OFFSET_LIMIT);
1241				deUint32	vertexOffset		= rnd.getInt(0, OFFSET_LIMIT);
1242				testGroup->addChild(new IndexedCase(testCtx, name.c_str(), "vkCmdDrawIndexed testcase.",
1243					DrawIndexedParams(topology, vk::VK_INDEX_TYPE_UINT32, vertexCount, 1, firstIndex, vertexOffset, 0))
1244				);
1245				break;
1246			}
1247			case DRAW_COMMAND_TYPE_DRAW_INDIRECT:
1248			{
1249				deUint32	firstVertex		= rnd.getInt(0, OFFSET_LIMIT);
1250
1251				DrawIndirectParams	params	= DrawIndirectParams(topology);
1252
1253				params.addCommand(vertexCount, 1, 0, 0);
1254				testGroup->addChild(new IndirectCase(testCtx, (name + "_single_command").c_str(), "vkCmdDrawIndirect testcase.", params));
1255
1256				params.addCommand(vertexCount, 1, firstVertex, 0);
1257				testGroup->addChild(new IndirectCase(testCtx, (name + "_multi_command").c_str(), "vkCmdDrawIndirect testcase.", params));
1258				break;
1259			}
1260			case DRAW_COMMAND_TYPE_DRAW_INDEXED_INDIRECT:
1261			{
1262				deUint32	firstIndex		= rnd.getInt(vertexCount, OFFSET_LIMIT);
1263				deUint32	vertexOffset	= rnd.getInt(vertexCount, OFFSET_LIMIT);
1264
1265				DrawIndexedIndirectParams	params	= DrawIndexedIndirectParams(topology, vk::VK_INDEX_TYPE_UINT32);
1266				params.addCommand(vertexCount, 1, 0, 0, 0);
1267				testGroup->addChild(new IndexedIndirectCase(testCtx, (name + "_single_command").c_str(), "vkCmdDrawIndexedIndirect testcase.", params));
1268
1269				params.addCommand(vertexCount, 1, firstIndex, vertexOffset, 0);
1270				testGroup->addChild(new IndexedIndirectCase(testCtx, (name + "_multi_command").c_str(), "vkCmdDrawIndexedIndirect testcase.", params));
1271				break;
1272			}
1273			default:
1274				DE_FATAL("Unsupported draw command.");
1275		}
1276	}
1277}
1278
1279void createTopologyGroups (tcu::TestCaseGroup* testGroup, const DrawCommandType cmdType)
1280{
1281	for (deUint32 idx = 0; idx != vk::VK_PRIMITIVE_TOPOLOGY_PATCH_LIST; ++idx)
1282	{
1283		const vk::VkPrimitiveTopology	topology	= vk::VkPrimitiveTopology(idx);
1284		const std::string				groupName	= de::toLower(getPrimitiveTopologyName(topology)).substr(22);
1285		addTestGroup(testGroup, groupName, "Testcases with a specific topology.", populateSubGroup, TestCaseParams(cmdType, topology));
1286	}
1287}
1288
1289void createDrawTests (tcu::TestCaseGroup* testGroup)
1290{
1291	for (deUint32 idx = 0; idx < DRAW_COMMAND_TYPE_DRAW_LAST; ++idx)
1292	{
1293		const DrawCommandType	command	= DrawCommandType(idx);
1294		addTestGroup(testGroup, getDrawCommandTypeName(command), "Group for testing a specific draw command.", createTopologyGroups, command);
1295	}
1296}
1297
1298tcu::TestCaseGroup*	createBasicDrawTests (tcu::TestContext& testCtx)
1299{
1300	return createTestGroup(testCtx, "basic_draw", "Basic drawing tests", createDrawTests);
1301}
1302
1303}	// DrawTests
1304}	// vkt
1305