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