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