• 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 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 
45 namespace vkt
46 {
47 namespace Draw
48 {
49 namespace
50 {
51 static const deUint32 SEED			= 0xc2a39fu;
52 static const deUint32 INDEX_LIMIT	= 10000;
53 // To avoid too big and mostly empty structures
54 static const deUint32 OFFSET_LIMIT	= 1000;
55 // Number of primitives to draw
56 static const deUint32 PRIMITIVE_COUNT[] = {1, 3, 17, 45};
57 
58 enum 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 
getDrawCommandTypeName(DrawCommandType command)68 const 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 
mapVkPrimitiveTopology(vk::VkPrimitiveTopology primitiveTopology)81 rr::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 
101 struct DrawParamsBase
102 {
103 	std::vector<PositionColorVertex>	vertices;
104 	vk::VkPrimitiveTopology				topology;
105 
DrawParamsBasevkt::Draw::__anon18afd7b30111::DrawParamsBase106 	DrawParamsBase ()
107 	{}
108 
DrawParamsBasevkt::Draw::__anon18afd7b30111::DrawParamsBase109 	DrawParamsBase (const vk::VkPrimitiveTopology top)
110 		: topology	(top)
111 	{}
112 };
113 
114 struct IndexedParamsBase
115 {
116 	std::vector<deUint32>	indexes;
117 	const vk::VkIndexType	indexType;
118 
IndexedParamsBasevkt::Draw::__anon18afd7b30111::IndexedParamsBase119 	IndexedParamsBase (const vk::VkIndexType indexT)
120 		: indexType	(indexT)
121 	{}
122 };
123 
124 // Structs to store draw parameters
125 struct DrawParams : DrawParamsBase
126 {
127 	// vkCmdDraw parameters is like a single VkDrawIndirectCommand
128 	vk::VkDrawIndirectCommand	params;
129 
DrawParamsvkt::Draw::__anon18afd7b30111::DrawParams130 	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 
140 struct DrawIndexedParams : DrawParamsBase, IndexedParamsBase
141 {
142 	// vkCmdDrawIndexed parameters is like a single VkDrawIndexedIndirectCommand
143 	vk::VkDrawIndexedIndirectCommand	params;
144 
DrawIndexedParamsvkt::Draw::__anon18afd7b30111::DrawIndexedParams145 	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 
157 struct DrawIndirectParams : DrawParamsBase
158 {
159 	std::vector<vk::VkDrawIndirectCommand>	commands;
160 
DrawIndirectParamsvkt::Draw::__anon18afd7b30111::DrawIndirectParams161 	DrawIndirectParams (const vk::VkPrimitiveTopology top)
162 		: DrawParamsBase	(top)
163 	{}
164 
addCommandvkt::Draw::__anon18afd7b30111::DrawIndirectParams165 	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 
177 struct DrawIndexedIndirectParams : DrawParamsBase, IndexedParamsBase
178 {
179 	std::vector<vk::VkDrawIndexedIndirectCommand>	commands;
180 
DrawIndexedIndirectParamsvkt::Draw::__anon18afd7b30111::DrawIndexedIndirectParams181 	DrawIndexedIndirectParams (const vk::VkPrimitiveTopology top, const vk::VkIndexType indexT)
182 		: DrawParamsBase	(top)
183 		, IndexedParamsBase	(indexT)
184 	{}
185 
addCommandvkt::Draw::__anon18afd7b30111::DrawIndexedIndirectParams186 	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
200 class PassthruVertShader : public rr::VertexShader
201 {
202 public:
PassthruVertShader(void)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 
shadeVertices(const rr::VertexAttrib * inputs,rr::VertexPacket * const * packets,const int numPackets) const211 	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 
228 class PassthruFragShader : public rr::FragmentShader
229 {
230 public:
PassthruFragShader(void)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 
shadeFragments(rr::FragmentPacket * packets,const int numPackets,const rr::FragmentShadingContext & context) const238 	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 
imageCompare(tcu::TestLog & log,const tcu::ConstPixelBufferAccess & reference,const tcu::ConstPixelBufferAccess & result,const vk::VkPrimitiveTopology topology)252 inline 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 
267 class DrawTestInstanceBase : public TestInstance
268 {
269 public:
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;
278 protected:
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 
DrawTestInstanceBase(Context & context)304 DrawTestInstanceBase::DrawTestInstanceBase (Context& context)
305 	: vkt::TestInstance			(context)
306 	, m_vk						(context.getDeviceInterface())
307 	, m_colorAttachmentFormat	(vk::VK_FORMAT_R8G8B8A8_UNORM)
308 {
309 }
310 
~DrawTestInstanceBase(void)311 DrawTestInstanceBase::~DrawTestInstanceBase (void)
312 {
313 }
314 
initialize(const DrawParamsBase & data)315 void 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 
initPipeline(const vk::VkDevice device)427 void 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 
beginRenderPass(void)462 void 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 
generateRefImage(const tcu::PixelBufferAccess & access,const std::vector<tcu::Vec4> & vertices,const std::vector<tcu::Vec4> & colors) const493 void 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 
517 template<typename T>
518 class DrawTestInstance : public DrawTestInstanceBase
519 {
520 public:
521 							DrawTestInstance		(Context& context, const T& data);
522 	virtual					~DrawTestInstance		(void);
523 	virtual void			generateDrawData		(void);
524 	virtual tcu::TestStatus	iterate					(void);
525 private:
526 	T						m_data;
527 };
528 
529 template<typename T>
DrawTestInstance(Context & context,const T & data)530 DrawTestInstance<T>::DrawTestInstance (Context& context, const T& data)
531 	: DrawTestInstanceBase	(context)
532 	, m_data				(data)
533 {
534 	generateDrawData();
535 	initialize(m_data);
536 }
537 
538 template<typename T>
~DrawTestInstance(void)539 DrawTestInstance<T>::~DrawTestInstance (void)
540 {
541 }
542 
543 template<typename T>
generateDrawData(void)544 void DrawTestInstance<T>::generateDrawData (void)
545 {
546 	DE_FATAL("Using the general case of this function is forbidden!");
547 }
548 
549 template<typename T>
iterate(void)550 tcu::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 
556 template<typename T>
557 class 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 
566 private:
567 	T													m_data;
568 	std::string											m_vertShaderSource;
569 	std::string											m_fragShaderSource;
570 };
571 
572 template<typename T>
DrawTestCase(tcu::TestContext & context,const char * name,const char * desc,const T data)573 DrawTestCase<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 
580 template<typename T>
~DrawTestCase(void)581 DrawTestCase<T>::~DrawTestCase	(void)
582 {
583 }
584 
585 template<typename T>
initPrograms(vk::SourceCollections & programCollection) const586 void 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 
592 template<typename T>
initShaderSources(void)593 void 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 
625 template<typename T>
createInstance(Context & context) const626 TestInstance* DrawTestCase<T>::createInstance (Context& context) const
627 {
628 	return new DrawTestInstance<T>(context, m_data);
629 }
630 
631 // Specialized cases
632 template<>
generateDrawData(void)633 void 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 
651 template<>
iterate(void)652 tcu::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 
710 template<>
generateDrawData(void)711 void 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 
746 template<>
iterate(void)747 tcu::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 
839 template<>
generateDrawData(void)840 void 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 
874 template<>
iterate(void)875 tcu::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 
985 template<>
generateDrawData(void)986 void 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 
1039 template<>
iterate(void)1040 tcu::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 
1177 typedef DrawTestCase<DrawParams>				DrawCase;
1178 typedef DrawTestCase<DrawIndexedParams>			IndexedCase;
1179 typedef DrawTestCase<DrawIndirectParams>		IndirectCase;
1180 typedef DrawTestCase<DrawIndexedIndirectParams>	IndexedIndirectCase;
1181 
1182 struct TestCaseParams
1183 {
1184 	const DrawCommandType			command;
1185 	const vk::VkPrimitiveTopology	topology;
1186 
TestCaseParamsvkt::Draw::__anon18afd7b30111::TestCaseParams1187 	TestCaseParams (const DrawCommandType cmd, const vk::VkPrimitiveTopology top)
1188 		: command	(cmd)
1189 		, topology	(top)
1190 	{}
1191 };
1192 
1193 }	// anonymous
1194 
populateSubGroup(tcu::TestCaseGroup * testGroup,const TestCaseParams caseParams)1195 void 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 
createTopologyGroups(tcu::TestCaseGroup * testGroup,const DrawCommandType cmdType)1279 void 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 
createDrawTests(tcu::TestCaseGroup * testGroup)1289 void 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 
createBasicDrawTests(tcu::TestContext & testCtx)1298 tcu::TestCaseGroup*	createBasicDrawTests (tcu::TestContext& testCtx)
1299 {
1300 	return createTestGroup(testCtx, "basic_draw", "Basic drawing tests", createDrawTests);
1301 }
1302 
1303 }	// DrawTests
1304 }	// vkt
1305