• 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 	bool								useMaintenance5;
109 	GroupParams							groupParams;	// we can't use SharedGroupParams here
110 
DrawParamsBasevkt::Draw::__anon114e94f30111::DrawParamsBase111 	DrawParamsBase ()
112 	{}
113 
DrawParamsBasevkt::Draw::__anon114e94f30111::DrawParamsBase114 	DrawParamsBase (const vk::VkPrimitiveTopology top, const SharedGroupParams gParams)
115 		: topology			(top)
116 		, useMaintenance5	(false)
117 		, groupParams
118 		{
119 			gParams->useDynamicRendering,
120 			gParams->useSecondaryCmdBuffer,
121 			gParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass
122 		}
123 	{}
124 };
125 
126 struct IndexedParamsBase
127 {
128 	std::vector<deUint32>	indexes;
129 	const vk::VkIndexType	indexType;
130 
IndexedParamsBasevkt::Draw::__anon114e94f30111::IndexedParamsBase131 	IndexedParamsBase (const vk::VkIndexType indexT)
132 		: indexType	(indexT)
133 	{}
134 };
135 
136 // Structs to store draw parameters
137 struct DrawParams : DrawParamsBase
138 {
139 	// vkCmdDraw parameters is like a single VkDrawIndirectCommand
140 	vk::VkDrawIndirectCommand	params;
141 
DrawParamsvkt::Draw::__anon114e94f30111::DrawParams142 	DrawParams (const vk::VkPrimitiveTopology top, const SharedGroupParams gParams, const deUint32 vertexC, const deUint32 instanceC, const deUint32 firstV, const deUint32 firstI)
143 		: DrawParamsBase	(top, gParams)
144 	{
145 		params.vertexCount		= vertexC;
146 		params.instanceCount	= instanceC;
147 		params.firstVertex		= firstV;
148 		params.firstInstance	= firstI;
149 	}
150 };
151 
152 struct DrawIndexedParams : DrawParamsBase, IndexedParamsBase
153 {
154 	// vkCmdDrawIndexed parameters is like a single VkDrawIndexedIndirectCommand
155 	vk::VkDrawIndexedIndirectCommand	params;
156 
DrawIndexedParamsvkt::Draw::__anon114e94f30111::DrawIndexedParams157 	DrawIndexedParams (const vk::VkPrimitiveTopology top, const SharedGroupParams gParams, const vk::VkIndexType indexT, const deUint32 indexC, const deUint32 instanceC, const deUint32 firstIdx, const deInt32 vertexO, const deUint32 firstIns)
158 		: DrawParamsBase	(top, gParams)
159 		, IndexedParamsBase	(indexT)
160 	{
161 		params.indexCount		= indexC;
162 		params.instanceCount	= instanceC;
163 		params.firstIndex		= firstIdx;
164 		params.vertexOffset		= vertexO;
165 		params.firstInstance	= firstIns;
166 	}
167 };
168 
169 struct DrawIndirectParams : DrawParamsBase
170 {
171 	std::vector<vk::VkDrawIndirectCommand>	commands;
172 
DrawIndirectParamsvkt::Draw::__anon114e94f30111::DrawIndirectParams173 	DrawIndirectParams (const vk::VkPrimitiveTopology top, const SharedGroupParams gParams)
174 		: DrawParamsBase	(top, gParams)
175 	{}
176 
addCommandvkt::Draw::__anon114e94f30111::DrawIndirectParams177 	void addCommand (const deUint32 vertexC, const deUint32 instanceC, const deUint32 firstV, const deUint32 firstI)
178 	{
179 		vk::VkDrawIndirectCommand	cmd;
180 		cmd.vertexCount				= vertexC;
181 		cmd.instanceCount			= instanceC;
182 		cmd.firstVertex				= firstV;
183 		cmd.firstInstance			= firstI;
184 
185 		commands.push_back(cmd);
186 	}
187 };
188 
189 struct DrawIndexedIndirectParams : DrawParamsBase, IndexedParamsBase
190 {
191 	std::vector<vk::VkDrawIndexedIndirectCommand>	commands;
192 
DrawIndexedIndirectParamsvkt::Draw::__anon114e94f30111::DrawIndexedIndirectParams193 	DrawIndexedIndirectParams (const vk::VkPrimitiveTopology top, const SharedGroupParams gParams, const vk::VkIndexType indexT)
194 		: DrawParamsBase	(top, gParams)
195 		, IndexedParamsBase	(indexT)
196 	{}
197 
addCommandvkt::Draw::__anon114e94f30111::DrawIndexedIndirectParams198 	void addCommand (const deUint32 indexC, const deUint32 instanceC, const deUint32 firstIdx, const deInt32 vertexO, const deUint32 firstIns)
199 	{
200 		vk::VkDrawIndexedIndirectCommand	cmd;
201 		cmd.indexCount						= indexC;
202 		cmd.instanceCount					= instanceC;
203 		cmd.firstIndex						= firstIdx;
204 		cmd.vertexOffset					= vertexO;
205 		cmd.firstInstance					= firstIns;
206 
207 		commands.push_back(cmd);
208 	}
209 };
210 
211 // Reference renderer shaders
212 class PassthruVertShader : public rr::VertexShader
213 {
214 public:
PassthruVertShader(void)215 	PassthruVertShader (void)
216 	: rr::VertexShader (2, 1)
217 	{
218 		m_inputs[0].type	= rr::GENERICVECTYPE_FLOAT;
219 		m_inputs[1].type	= rr::GENERICVECTYPE_FLOAT;
220 		m_outputs[0].type	= rr::GENERICVECTYPE_FLOAT;
221 	}
222 
shadeVertices(const rr::VertexAttrib * inputs,rr::VertexPacket * const * packets,const int numPackets) const223 	void shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
224 	{
225 		for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
226 		{
227 			packets[packetNdx]->position = rr::readVertexAttribFloat(inputs[0],
228 																	 packets[packetNdx]->instanceNdx,
229 																	 packets[packetNdx]->vertexNdx);
230 
231 			tcu::Vec4 color = rr::readVertexAttribFloat(inputs[1],
232 														packets[packetNdx]->instanceNdx,
233 														packets[packetNdx]->vertexNdx);
234 
235 			packets[packetNdx]->outputs[0] = color;
236 		}
237 	}
238 };
239 
240 class PassthruFragShader : public rr::FragmentShader
241 {
242 public:
PassthruFragShader(void)243 	PassthruFragShader (void)
244 		: rr::FragmentShader(1, 1)
245 	{
246 		m_inputs[0].type	= rr::GENERICVECTYPE_FLOAT;
247 		m_outputs[0].type	= rr::GENERICVECTYPE_FLOAT;
248 	}
249 
shadeFragments(rr::FragmentPacket * packets,const int numPackets,const rr::FragmentShadingContext & context) const250 	void shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
251 	{
252 		for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
253 		{
254 			rr::FragmentPacket& packet = packets[packetNdx];
255 			for (deUint32 fragNdx = 0; fragNdx < rr::NUM_FRAGMENTS_PER_PACKET; ++fragNdx)
256 			{
257 				tcu::Vec4 color = rr::readVarying<float>(packet, context, 0, fragNdx);
258 				rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, color);
259 			}
260 		}
261 	}
262 };
263 
imageCompare(tcu::TestLog & log,const tcu::ConstPixelBufferAccess & reference,const tcu::ConstPixelBufferAccess & result,const vk::VkPrimitiveTopology topology)264 inline bool imageCompare (tcu::TestLog& log, const tcu::ConstPixelBufferAccess& reference, const tcu::ConstPixelBufferAccess& result, const vk::VkPrimitiveTopology topology)
265 {
266 	if (topology == vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST)
267 	{
268 		return tcu::intThresholdPositionDeviationCompare(
269 			log, "Result", "Image comparison result", reference, result,
270 			tcu::UVec4(4u),					// color threshold
271 			tcu::IVec3(1, 1, 0),			// position deviation tolerance
272 			true,							// don't check the pixels at the boundary
273 			tcu::COMPARE_LOG_RESULT);
274 	}
275 	else
276 		return tcu::fuzzyCompare(log, "Result", "Image comparison result", reference, result, 0.053f, tcu::COMPARE_LOG_RESULT);
277 }
278 
279 class DrawTestInstanceBase : public TestInstance
280 {
281 public:
282 									DrawTestInstanceBase	(Context& context);
283 	virtual							~DrawTestInstanceBase	(void) = 0;
284 	void							initialize				(const DrawParamsBase& data);
285 	void							initPipeline			(const vk::VkDevice device);
286 	void							preRenderBarriers		(void);
287 	void							beginRenderPass			(vk::VkCommandBuffer cmdBuffer);
288 	void							endRenderPass			(vk::VkCommandBuffer cmdBuffer);
289 
290 #ifndef CTS_USES_VULKANSC
291 	void							beginSecondaryCmdBuffer	(const vk::DeviceInterface& vk, vk::VkRenderingFlagsKHR renderingFlags = 0u);
292 	void							beginDynamicRender		(vk::VkCommandBuffer cmdBuffer, vk::VkRenderingFlagsKHR renderingFlags = 0u);
293 	void							endDynamicRender		(vk::VkCommandBuffer cmdBuffer);
294 #endif // CTS_USES_VULKANSC
295 
296 	// Specialize this function for each type
297 	virtual tcu::TestStatus			iterate					(void) = 0;
298 protected:
299 	// Specialize this function for each type
300 	virtual void					generateDrawData		(void) = 0;
301 	void							generateRefImage		(const tcu::PixelBufferAccess& access, const std::vector<tcu::Vec4>& vertices, const std::vector<tcu::Vec4>& colors) const;
302 
303 	DrawParamsBase											m_data;
304 	const vk::DeviceInterface&								m_vk;
305 	vk::Move<vk::VkPipeline>								m_pipeline;
306 	vk::Move<vk::VkPipelineLayout>							m_pipelineLayout;
307 	vk::VkFormat											m_colorAttachmentFormat;
308 	de::SharedPtr<Image>									m_colorTargetImage;
309 	vk::Move<vk::VkImageView>								m_colorTargetView;
310 	vk::Move<vk::VkRenderPass>								m_renderPass;
311 	vk::Move<vk::VkFramebuffer>								m_framebuffer;
312 	PipelineCreateInfo::VertexInputState					m_vertexInputState;
313 	de::SharedPtr<Buffer>									m_vertexBuffer;
314 	vk::Move<vk::VkCommandPool>								m_cmdPool;
315 	vk::Move<vk::VkCommandBuffer>							m_cmdBuffer;
316 	vk::Move<vk::VkCommandBuffer>							m_secCmdBuffer;
317 
318 	enum
319 	{
320 		WIDTH = 256,
321 		HEIGHT = 256
322 	};
323 };
324 
DrawTestInstanceBase(Context & context)325 DrawTestInstanceBase::DrawTestInstanceBase (Context& context)
326 	: vkt::TestInstance			(context)
327 	, m_vk						(context.getDeviceInterface())
328 	, m_colorAttachmentFormat	(vk::VK_FORMAT_R8G8B8A8_UNORM)
329 {
330 }
331 
~DrawTestInstanceBase(void)332 DrawTestInstanceBase::~DrawTestInstanceBase (void)
333 {
334 }
335 
initialize(const DrawParamsBase & data)336 void DrawTestInstanceBase::initialize (const DrawParamsBase& data)
337 {
338 	m_data = data;
339 
340 	const vk::VkDevice	device				= m_context.getDevice();
341 	const deUint32		queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
342 
343 	const PipelineLayoutCreateInfo pipelineLayoutCreateInfo;
344 	m_pipelineLayout						= vk::createPipelineLayout(m_vk, device, &pipelineLayoutCreateInfo);
345 
346 	const vk::VkExtent3D targetImageExtent	= { WIDTH, HEIGHT, 1 };
347 	const ImageCreateInfo targetImageCreateInfo(vk::VK_IMAGE_TYPE_2D, m_colorAttachmentFormat, targetImageExtent, 1, 1, vk::VK_SAMPLE_COUNT_1_BIT,
348 		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);
349 
350 	m_colorTargetImage						= Image::createAndAlloc(m_vk, device, targetImageCreateInfo, m_context.getDefaultAllocator(), m_context.getUniversalQueueFamilyIndex());
351 
352 	const ImageViewCreateInfo colorTargetViewInfo(m_colorTargetImage->object(), vk::VK_IMAGE_VIEW_TYPE_2D, m_colorAttachmentFormat);
353 	m_colorTargetView						= vk::createImageView(m_vk, device, &colorTargetViewInfo);
354 
355 	// create render pass only when we are not using dynamic rendering
356 	if (!m_data.groupParams.useDynamicRendering)
357 	{
358 		RenderPassCreateInfo renderPassCreateInfo;
359 		renderPassCreateInfo.addAttachment(AttachmentDescription(m_colorAttachmentFormat,
360 																 vk::VK_SAMPLE_COUNT_1_BIT,
361 																 vk::VK_ATTACHMENT_LOAD_OP_LOAD,
362 																 vk::VK_ATTACHMENT_STORE_OP_STORE,
363 																 vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE,
364 																 vk::VK_ATTACHMENT_STORE_OP_STORE,
365 																 vk::VK_IMAGE_LAYOUT_GENERAL,
366 																 vk::VK_IMAGE_LAYOUT_GENERAL));
367 
368 		const vk::VkAttachmentReference colorAttachmentReference
369 		{
370 			0,
371 			vk::VK_IMAGE_LAYOUT_GENERAL
372 		};
373 
374 		renderPassCreateInfo.addSubpass(SubpassDescription(vk::VK_PIPELINE_BIND_POINT_GRAPHICS,
375 														   0,
376 														   0,
377 														   DE_NULL,
378 														   1,
379 														   &colorAttachmentReference,
380 														   DE_NULL,
381 														   AttachmentReference(),
382 														   0,
383 														   DE_NULL));
384 
385 		m_renderPass = vk::createRenderPass(m_vk, device, &renderPassCreateInfo);
386 
387 		// create framebuffer
388 		std::vector<vk::VkImageView>	colorAttachments		{ *m_colorTargetView };
389 		const FramebufferCreateInfo		framebufferCreateInfo	(*m_renderPass, colorAttachments, WIDTH, HEIGHT, 1);
390 		m_framebuffer = vk::createFramebuffer(m_vk, device, &framebufferCreateInfo);
391 	}
392 
393 	const vk::VkVertexInputBindingDescription vertexInputBindingDescription =
394 	{
395 		0,
396 		(deUint32)sizeof(tcu::Vec4) * 2,
397 		vk::VK_VERTEX_INPUT_RATE_VERTEX,
398 	};
399 
400 	const vk::VkVertexInputAttributeDescription vertexInputAttributeDescriptions[2] =
401 	{
402 		{
403 			0u,
404 			0u,
405 			vk::VK_FORMAT_R32G32B32A32_SFLOAT,
406 			0u
407 		},
408 		{
409 			1u,
410 			0u,
411 			vk::VK_FORMAT_R32G32B32A32_SFLOAT,
412 			(deUint32)(sizeof(float)* 4),
413 		}
414 	};
415 
416 	m_vertexInputState = PipelineCreateInfo::VertexInputState(1,
417 															  &vertexInputBindingDescription,
418 															  2,
419 															  vertexInputAttributeDescriptions);
420 
421 	const vk::VkDeviceSize dataSize = m_data.vertices.size() * sizeof(PositionColorVertex);
422 	BufferCreateInfo createInfo(dataSize, vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
423 
424 #ifndef CTS_USES_VULKANSC
425 	vk::VkBufferUsageFlags2CreateInfoKHR bufferUsageFlags2 = vk::initVulkanStructure();
426 	if (m_data.useMaintenance5)
427 	{
428 		bufferUsageFlags2.usage = vk::VK_BUFFER_USAGE_2_VERTEX_BUFFER_BIT_KHR;
429 		createInfo.pNext = &bufferUsageFlags2;
430 		createInfo.usage = 0xBAD00000;
431 	}
432 #endif // CTS_USES_VULKANSC
433 
434 	m_vertexBuffer = Buffer::createAndAlloc(m_vk, device, createInfo,
435 		m_context.getDefaultAllocator(), vk::MemoryRequirement::HostVisible);
436 
437 	deUint8* ptr = reinterpret_cast<deUint8*>(m_vertexBuffer->getBoundMemory().getHostPtr());
438 	deMemcpy(ptr, &(m_data.vertices[0]), static_cast<size_t>(dataSize));
439 
440 	vk::flushAlloc(m_vk, device, m_vertexBuffer->getBoundMemory());
441 
442 	const CmdPoolCreateInfo cmdPoolCreateInfo(queueFamilyIndex);
443 	m_cmdPool	= vk::createCommandPool(m_vk, device, &cmdPoolCreateInfo);
444 	m_cmdBuffer	= vk::allocateCommandBuffer(m_vk, device, *m_cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY);
445 
446 	if (m_data.groupParams.useSecondaryCmdBuffer)
447 		m_secCmdBuffer = vk::allocateCommandBuffer(m_vk, device, *m_cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_SECONDARY);
448 
449 	initPipeline(device);
450 }
451 
initPipeline(const vk::VkDevice device)452 void DrawTestInstanceBase::initPipeline (const vk::VkDevice device)
453 {
454 	const vk::Unique<vk::VkShaderModule>	vs(createShaderModule(m_vk, device, m_context.getBinaryCollection().get("vert"), 0));
455 	const vk::Unique<vk::VkShaderModule>	fs(createShaderModule(m_vk, device, m_context.getBinaryCollection().get("frag"), 0));
456 
457 	const PipelineCreateInfo::ColorBlendState::Attachment vkCbAttachmentState;
458 
459 	vk::VkViewport viewport	= vk::makeViewport(WIDTH, HEIGHT);
460 	vk::VkRect2D scissor	= vk::makeRect2D(WIDTH, HEIGHT);
461 
462 	// when dynamic_rendering is tested then renderPass won't be created and VK_NULL_HANDLE will be used here
463 	PipelineCreateInfo pipelineCreateInfo(*m_pipelineLayout, *m_renderPass, 0, 0);
464 	pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*vs, "main", vk::VK_SHADER_STAGE_VERTEX_BIT));
465 	pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*fs, "main", vk::VK_SHADER_STAGE_FRAGMENT_BIT));
466 	pipelineCreateInfo.addState(PipelineCreateInfo::VertexInputState(m_vertexInputState));
467 	pipelineCreateInfo.addState(PipelineCreateInfo::InputAssemblerState(m_data.topology));
468 	pipelineCreateInfo.addState(PipelineCreateInfo::ColorBlendState(1, &vkCbAttachmentState));
469 	pipelineCreateInfo.addState(PipelineCreateInfo::ViewportState(1, std::vector<vk::VkViewport>(1, viewport), std::vector<vk::VkRect2D>(1, scissor)));
470 	pipelineCreateInfo.addState(PipelineCreateInfo::DepthStencilState());
471 	pipelineCreateInfo.addState(PipelineCreateInfo::RasterizerState());
472 	pipelineCreateInfo.addState(PipelineCreateInfo::MultiSampleState());
473 
474 #ifndef CTS_USES_VULKANSC
475 	vk::VkPipelineRenderingCreateInfoKHR renderingCreateInfo
476 	{
477 		vk::VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR,
478 		DE_NULL,
479 		0u,
480 		1u,
481 		&m_colorAttachmentFormat,
482 		vk::VK_FORMAT_UNDEFINED,
483 		vk::VK_FORMAT_UNDEFINED
484 	};
485 
486 	if (m_data.groupParams.useDynamicRendering)
487 		pipelineCreateInfo.pNext = &renderingCreateInfo;
488 
489 	vk::VkPipelineCreateFlags2CreateInfoKHR pipelineFlags2CreateInfo
490 	{
491 		vk::VK_STRUCTURE_TYPE_PIPELINE_CREATE_FLAGS_2_CREATE_INFO_KHR,
492 		pipelineCreateInfo.pNext,
493 		vk::VK_PIPELINE_CREATE_2_ALLOW_DERIVATIVES_BIT_KHR
494 	};
495 	if (m_data.useMaintenance5)
496 	{
497 		pipelineCreateInfo.flags = 0xBAD00000;
498 		pipelineCreateInfo.pNext = &pipelineFlags2CreateInfo;
499 	}
500 #endif // CTS_USES_VULKANSC
501 
502 	m_pipeline = vk::createGraphicsPipeline(m_vk, device, DE_NULL, &pipelineCreateInfo);
503 }
504 
preRenderBarriers(void)505 void DrawTestInstanceBase::preRenderBarriers (void)
506 {
507 	const vk::VkClearValue clearColor { { { 0.0f, 0.0f, 0.0f, 1.0f } } };
508 
509 	initialTransitionColor2DImage(m_vk, *m_cmdBuffer, m_colorTargetImage->object(), vk::VK_IMAGE_LAYOUT_GENERAL,
510 								  vk::VK_ACCESS_TRANSFER_WRITE_BIT, vk::VK_PIPELINE_STAGE_TRANSFER_BIT);
511 
512 	const ImageSubresourceRange subresourceRange(vk::VK_IMAGE_ASPECT_COLOR_BIT);
513 	m_vk.cmdClearColorImage(*m_cmdBuffer, m_colorTargetImage->object(),
514 		vk::VK_IMAGE_LAYOUT_GENERAL, &clearColor.color, 1, &subresourceRange);
515 
516 	const vk::VkMemoryBarrier memBarrier
517 	{
518 		vk::VK_STRUCTURE_TYPE_MEMORY_BARRIER,
519 		DE_NULL,
520 		vk::VK_ACCESS_TRANSFER_WRITE_BIT,
521 		vk::VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT
522 	};
523 
524 	m_vk.cmdPipelineBarrier(*m_cmdBuffer, vk::VK_PIPELINE_STAGE_TRANSFER_BIT,
525 		vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
526 		0, 1, &memBarrier, 0, DE_NULL, 0, DE_NULL);
527 }
528 
beginRenderPass(vk::VkCommandBuffer cmdBuffer)529 void DrawTestInstanceBase::beginRenderPass (vk::VkCommandBuffer cmdBuffer)
530 {
531 	const vk::VkClearValue	clearColor	{ { { 0.0f, 0.0f, 0.0f, 1.0f } } };
532 	const vk::VkRect2D		renderArea	= vk::makeRect2D(WIDTH, HEIGHT);
533 
534 	vk::beginRenderPass(m_vk, cmdBuffer, *m_renderPass, *m_framebuffer, renderArea, 1u, &clearColor);
535 }
536 
endRenderPass(vk::VkCommandBuffer cmdBuffer)537 void DrawTestInstanceBase::endRenderPass (vk::VkCommandBuffer cmdBuffer)
538 {
539 	vk::endRenderPass(m_vk, cmdBuffer);
540 }
541 
542 #ifndef CTS_USES_VULKANSC
beginSecondaryCmdBuffer(const vk::DeviceInterface & vk,vk::VkRenderingFlagsKHR renderingFlags)543 void DrawTestInstanceBase::beginSecondaryCmdBuffer(const vk::DeviceInterface& vk, vk::VkRenderingFlagsKHR renderingFlags)
544 {
545 	const vk::VkCommandBufferInheritanceRenderingInfoKHR inheritanceRenderingInfo
546 	{
547 		vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO_KHR,	// VkStructureType					sType;
548 		DE_NULL,																// const void*						pNext;
549 		renderingFlags,															// VkRenderingFlagsKHR				flags;
550 		0u,																		// uint32_t							viewMask;
551 		1u,																		// uint32_t							colorAttachmentCount;
552 		&m_colorAttachmentFormat,												// const VkFormat*					pColorAttachmentFormats;
553 		vk::VK_FORMAT_UNDEFINED,												// VkFormat							depthAttachmentFormat;
554 		vk::VK_FORMAT_UNDEFINED,												// VkFormat							stencilAttachmentFormat;
555 		vk::VK_SAMPLE_COUNT_1_BIT,												// VkSampleCountFlagBits			rasterizationSamples;
556 	};
557 
558 	const vk::VkCommandBufferInheritanceInfo bufferInheritanceInfo
559 	{
560 		vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO,					// VkStructureType					sType;
561 		&inheritanceRenderingInfo,												// const void*						pNext;
562 		DE_NULL,																// VkRenderPass						renderPass;
563 		0u,																		// deUint32							subpass;
564 		DE_NULL,																// VkFramebuffer					framebuffer;
565 		VK_FALSE,																// VkBool32							occlusionQueryEnable;
566 		(vk::VkQueryControlFlags)0u,											// VkQueryControlFlags				queryFlags;
567 		(vk::VkQueryPipelineStatisticFlags)0u									// VkQueryPipelineStatisticFlags	pipelineStatistics;
568 	};
569 
570 	vk::VkCommandBufferUsageFlags usageFlags = vk::VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
571 	if (!m_data.groupParams.secondaryCmdBufferCompletelyContainsDynamicRenderpass)
572 		usageFlags |= vk::VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT;
573 
574 	const vk::VkCommandBufferBeginInfo commandBufBeginParams
575 	{
576 		vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,						// VkStructureType					sType;
577 		DE_NULL,																// const void*						pNext;
578 		usageFlags,																// VkCommandBufferUsageFlags		flags;
579 		&bufferInheritanceInfo
580 	};
581 
582 	VK_CHECK(vk.beginCommandBuffer(*m_secCmdBuffer, &commandBufBeginParams));
583 }
584 
beginDynamicRender(vk::VkCommandBuffer cmdBuffer,vk::VkRenderingFlagsKHR renderingFlags)585 void DrawTestInstanceBase::beginDynamicRender(vk::VkCommandBuffer cmdBuffer, vk::VkRenderingFlagsKHR renderingFlags)
586 {
587 	const vk::VkClearValue	clearColor{ { { 0.0f, 0.0f, 0.0f, 1.0f } } };
588 	const vk::VkRect2D		renderArea = vk::makeRect2D(WIDTH, HEIGHT);
589 
590 	vk::beginRendering(m_vk, cmdBuffer, *m_colorTargetView, renderArea, clearColor, vk::VK_IMAGE_LAYOUT_GENERAL, vk::VK_ATTACHMENT_LOAD_OP_LOAD, renderingFlags);
591 }
592 
endDynamicRender(vk::VkCommandBuffer cmdBuffer)593 void DrawTestInstanceBase::endDynamicRender(vk::VkCommandBuffer cmdBuffer)
594 {
595 	vk::endRendering(m_vk, cmdBuffer);
596 }
597 #endif // CTS_USES_VULKANSC
598 
generateRefImage(const tcu::PixelBufferAccess & access,const std::vector<tcu::Vec4> & vertices,const std::vector<tcu::Vec4> & colors) const599 void DrawTestInstanceBase::generateRefImage (const tcu::PixelBufferAccess& access, const std::vector<tcu::Vec4>& vertices, const std::vector<tcu::Vec4>& colors) const
600 {
601 	const PassthruVertShader				vertShader;
602 	const PassthruFragShader				fragShader;
603 	const rr::Program						program			(&vertShader, &fragShader);
604 	const rr::MultisamplePixelBufferAccess	colorBuffer		= rr::MultisamplePixelBufferAccess::fromSinglesampleAccess(access);
605 	const rr::RenderTarget					renderTarget	(colorBuffer);
606 	const rr::RenderState					renderState		((rr::ViewportState(colorBuffer)), m_context.getDeviceProperties().limits.subPixelPrecisionBits);
607 	const rr::Renderer						renderer;
608 
609 	const rr::VertexAttrib	vertexAttribs[] =
610 	{
611 		rr::VertexAttrib(rr::VERTEXATTRIBTYPE_FLOAT, 4, sizeof(tcu::Vec4), 0, &vertices[0]),
612 		rr::VertexAttrib(rr::VERTEXATTRIBTYPE_FLOAT, 4, sizeof(tcu::Vec4), 0, &colors[0])
613 	};
614 
615 	renderer.draw(rr::DrawCommand(renderState,
616 								  renderTarget,
617 								  program,
618 								  DE_LENGTH_OF_ARRAY(vertexAttribs),
619 								  &vertexAttribs[0],
620 								  rr::PrimitiveList(mapVkPrimitiveTopology(m_data.topology), (deUint32)vertices.size(), 0)));
621 }
622 
623 template<typename T>
624 class DrawTestInstance : public DrawTestInstanceBase
625 {
626 public:
627 							DrawTestInstance		(Context& context, const T& data);
628 	virtual					~DrawTestInstance		(void);
629 	virtual void			generateDrawData		(void);
630 	virtual void			draw					(vk::VkCommandBuffer cmdBuffer, vk::VkBuffer indirectBuffer = DE_NULL, vk::VkDeviceSize indirectOffset = 0ul);
631 	virtual tcu::TestStatus	iterate					(void);
632 private:
633 	T						m_data;
634 };
635 
636 template<typename T>
DrawTestInstance(Context & context,const T & data)637 DrawTestInstance<T>::DrawTestInstance (Context& context, const T& data)
638 	: DrawTestInstanceBase	(context)
639 	, m_data(data)
640 {
641 	generateDrawData();
642 	initialize(m_data);
643 }
644 
645 template<typename T>
~DrawTestInstance(void)646 DrawTestInstance<T>::~DrawTestInstance (void)
647 {
648 }
649 
650 template<typename T>
generateDrawData(void)651 void DrawTestInstance<T>::generateDrawData (void)
652 {
653 	DE_FATAL("Using the general case of this function is forbidden!");
654 }
655 
656 template<typename T>
draw(vk::VkCommandBuffer,vk::VkBuffer,vk::VkDeviceSize)657 void DrawTestInstance<T>::draw(vk::VkCommandBuffer, vk::VkBuffer, vk::VkDeviceSize)
658 {
659 	DE_FATAL("Using the general case of this function is forbidden!");
660 }
661 
662 template<typename T>
iterate(void)663 tcu::TestStatus DrawTestInstance<T>::iterate (void)
664 {
665 	DE_FATAL("Using the general case of this function is forbidden!");
666 	return tcu::TestStatus::fail("");
667 }
668 
669 template<typename T>
670 class DrawTestCase : public TestCase
671 {
672 	public:
673 									DrawTestCase		(tcu::TestContext& context, const char* name, const T data);
674 									~DrawTestCase		(void);
675 	virtual	void					initPrograms		(vk::SourceCollections& programCollection) const;
676 	virtual void					initShaderSources	(void);
677 	virtual void					checkSupport		(Context& context) const;
678 	virtual TestInstance*			createInstance		(Context& context) const;
679 
680 private:
681 	T													m_data;
682 	std::string											m_vertShaderSource;
683 	std::string											m_fragShaderSource;
684 };
685 
686 template<typename T>
DrawTestCase(tcu::TestContext & context,const char * name,const T data)687 DrawTestCase<T>::DrawTestCase (tcu::TestContext& context, const char* name, const T data)
688 	: vkt::TestCase	(context, name)
689 	, m_data		(data)
690 {
691 	initShaderSources();
692 }
693 
694 template<typename T>
~DrawTestCase(void)695 DrawTestCase<T>::~DrawTestCase	(void)
696 {
697 }
698 
699 template<typename T>
initPrograms(vk::SourceCollections & programCollection) const700 void DrawTestCase<T>::initPrograms (vk::SourceCollections& programCollection) const
701 {
702 	programCollection.glslSources.add("vert") << glu::VertexSource(m_vertShaderSource);
703 	programCollection.glslSources.add("frag") << glu::FragmentSource(m_fragShaderSource);
704 }
705 
706 template<typename T>
checkSupport(Context & context) const707 void DrawTestCase<T>::checkSupport (Context& context) const
708 {
709 	if (m_data.topology == vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY ||
710 		m_data.topology == vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY ||
711 		m_data.topology == vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY ||
712 		m_data.topology == vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY)
713 	{
714 		context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_GEOMETRY_SHADER);
715 	}
716 
717 #ifndef CTS_USES_VULKANSC
718 	if (m_data.useMaintenance5)
719 		context.requireDeviceFunctionality("VK_KHR_maintenance5");
720 
721 	if (m_data.groupParams.useDynamicRendering)
722 		context.requireDeviceFunctionality("VK_KHR_dynamic_rendering");
723 
724 	if (m_data.topology == vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN &&
725 		context.isDeviceFunctionalitySupported("VK_KHR_portability_subset") &&
726 		!context.getPortabilitySubsetFeatures().triangleFans)
727 	{
728 		TCU_THROW(NotSupportedError, "VK_KHR_portability_subset: Triangle fans are not supported by this implementation");
729 	}
730 #endif // CTS_USES_VULKANSC
731 }
732 
733 template<typename T>
initShaderSources(void)734 void DrawTestCase<T>::initShaderSources (void)
735 {
736 	std::stringstream vertShader;
737 	vertShader	<< "#version 430\n"
738 				<< "layout(location = 0) in vec4 in_position;\n"
739 				<< "layout(location = 1) in vec4 in_color;\n"
740 				<< "layout(location = 0) out vec4 out_color;\n"
741 
742 				<< "out gl_PerVertex {\n"
743 				<< "    vec4  gl_Position;\n"
744 				<< "    float gl_PointSize;\n"
745 				<< "};\n"
746 				<< "void main() {\n"
747 				<< "    gl_PointSize = 1.0;\n"
748 				<< "    gl_Position  = in_position;\n"
749 				<< "    out_color    = in_color;\n"
750 				<< "}\n";
751 
752 	m_vertShaderSource = vertShader.str();
753 
754 	std::stringstream fragShader;
755 	fragShader	<< "#version 430\n"
756 				<< "layout(location = 0) in vec4 in_color;\n"
757 				<< "layout(location = 0) out vec4 out_color;\n"
758 				<< "void main()\n"
759 				<< "{\n"
760 				<< "    out_color = in_color;\n"
761 				<< "}\n";
762 
763 	m_fragShaderSource = fragShader.str();
764 }
765 
766 template<typename T>
createInstance(Context & context) const767 TestInstance* DrawTestCase<T>::createInstance (Context& context) const
768 {
769 	return new DrawTestInstance<T>(context, m_data);
770 }
771 
772 // Specialized cases
773 template<>
generateDrawData(void)774 void DrawTestInstance<DrawParams>::generateDrawData (void)
775 {
776 	de::Random		rnd			(SEED ^ m_data.params.firstVertex ^ m_data.params.vertexCount);
777 
778 	const deUint32	vectorSize	= m_data.params.firstVertex + m_data.params.vertexCount;
779 
780 	// Initialize the vector
781 	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)));
782 
783 	// Fill only the used indexes
784 	for (deUint32 vertexIdx = m_data.params.firstVertex; vertexIdx < vectorSize; ++vertexIdx)
785 	{
786 		const float f0 = rnd.getFloat(-1.0f, 1.0f);
787 		const float f1 = rnd.getFloat(-1.0f, 1.0f);
788 
789 		m_data.vertices[vertexIdx] = PositionColorVertex(
790 			tcu::Vec4(f0, f1, 1.0f, 1.0f),	// Coord
791 			tcu::randomVec4(rnd));			// Color
792 	}
793 }
794 
795 template<>
draw(vk::VkCommandBuffer cmdBuffer,vk::VkBuffer,vk::VkDeviceSize)796 void DrawTestInstance<DrawParams>::draw(vk::VkCommandBuffer cmdBuffer, vk::VkBuffer, vk::VkDeviceSize)
797 {
798 	m_vk.cmdDraw(cmdBuffer, m_data.params.vertexCount, m_data.params.instanceCount, m_data.params.firstVertex, m_data.params.firstInstance);
799 }
800 
801 template<>
iterate(void)802 tcu::TestStatus DrawTestInstance<DrawParams>::iterate (void)
803 {
804 	tcu::TestLog			&log				= m_context.getTestContext().getLog();
805 	const vk::VkQueue		queue				= m_context.getUniversalQueue();
806 	const vk::VkDevice		device				= m_context.getDevice();
807 	const vk::VkDeviceSize	vertexBufferOffset	= 0;
808 	const vk::VkBuffer		vertexBuffer		= m_vertexBuffer->object();
809 
810 #ifndef CTS_USES_VULKANSC
811 	if (m_data.groupParams.useSecondaryCmdBuffer)
812 	{
813 		// record secondary command buffer
814 		if (m_data.groupParams.secondaryCmdBufferCompletelyContainsDynamicRenderpass)
815 		{
816 			beginSecondaryCmdBuffer(m_vk, vk::VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT);
817 			beginDynamicRender(*m_secCmdBuffer);
818 		}
819 		else
820 			beginSecondaryCmdBuffer(m_vk);
821 
822 		m_vk.cmdBindVertexBuffers(*m_secCmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
823 		m_vk.cmdBindPipeline(*m_secCmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
824 		draw(*m_secCmdBuffer);
825 
826 		if (m_data.groupParams.secondaryCmdBufferCompletelyContainsDynamicRenderpass)
827 			endDynamicRender(*m_secCmdBuffer);
828 
829 		endCommandBuffer(m_vk, *m_secCmdBuffer);
830 
831 		// record primary command buffer
832 		beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
833 
834 		preRenderBarriers();
835 
836 		if (!m_data.groupParams.secondaryCmdBufferCompletelyContainsDynamicRenderpass)
837 			beginDynamicRender(*m_cmdBuffer, vk::VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT);
838 
839 		m_vk.cmdExecuteCommands(*m_cmdBuffer, 1u, &*m_secCmdBuffer);
840 
841 		if (!m_data.groupParams.secondaryCmdBufferCompletelyContainsDynamicRenderpass)
842 			endDynamicRender(*m_cmdBuffer);
843 
844 		endCommandBuffer(m_vk, *m_cmdBuffer);
845 	}
846 	else if(m_data.groupParams.useDynamicRendering)
847 	{
848 		beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
849 		preRenderBarriers();
850 		beginDynamicRender(*m_cmdBuffer);
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 		draw(*m_cmdBuffer);
855 
856 		endDynamicRender(*m_cmdBuffer);
857 		endCommandBuffer(m_vk, *m_cmdBuffer);
858 	}
859 #endif // CTS_USES_VULKANSC
860 
861 	if (!m_data.groupParams.useDynamicRendering)
862 	{
863 		beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
864 		preRenderBarriers();
865 		beginRenderPass(*m_cmdBuffer);
866 
867 		m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
868 		m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
869 		draw(*m_cmdBuffer);
870 
871 		endRenderPass(*m_cmdBuffer);
872 		endCommandBuffer(m_vk, *m_cmdBuffer);
873 	}
874 
875 	submitCommandsAndWait(m_vk, device, queue, m_cmdBuffer.get());
876 
877 	// Validation
878 	tcu::TextureLevel refImage (vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5f + static_cast<float>(WIDTH)), (int)(0.5f + static_cast<float>(HEIGHT)));
879 	tcu::clear(refImage.getAccess(), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
880 
881 	std::vector<tcu::Vec4>	vertices;
882 	std::vector<tcu::Vec4>	colors;
883 
884 	for (std::vector<PositionColorVertex>::const_iterator vertex = m_data.vertices.begin() + m_data.params.firstVertex; vertex != m_data.vertices.end(); ++vertex)
885 	{
886 		vertices.push_back(vertex->position);
887 		colors.push_back(vertex->color);
888 	}
889 	generateRefImage(refImage.getAccess(), vertices, colors);
890 
891 	const vk::VkOffset3D zeroOffset = { 0, 0, 0 };
892 	const tcu::ConstPixelBufferAccess renderedFrame = m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(),
893 		vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
894 
895 	qpTestResult res = QP_TEST_RESULT_PASS;
896 
897 	if (!imageCompare(log, refImage.getAccess(), renderedFrame, m_data.topology))
898 		res = QP_TEST_RESULT_FAIL;
899 
900 	return tcu::TestStatus(res, qpGetTestResultName(res));
901 }
902 
903 template<>
generateDrawData(void)904 void DrawTestInstance<DrawIndexedParams>::generateDrawData (void)
905 {
906 	de::Random		rnd			(SEED ^ m_data.params.firstIndex ^ m_data.params.indexCount);
907 	const deUint32	indexSize	= m_data.params.firstIndex + m_data.params.indexCount;
908 
909 	// Initialize the vector with zeros
910 	m_data.indexes = std::vector<deUint32>(indexSize, 0);
911 
912 	deUint32		highestIndex	= 0;	// Store to highest index to calculate the vertices size
913 	// Fill the indexes from firstIndex
914 	for (deUint32 idx = 0; idx < m_data.params.indexCount; ++idx)
915 	{
916 		deUint32	vertexIdx	= rnd.getInt(m_data.params.vertexOffset, INDEX_LIMIT);
917 		highestIndex = (vertexIdx > highestIndex) ? vertexIdx : highestIndex;
918 
919 		m_data.indexes[m_data.params.firstIndex + idx]	= vertexIdx;
920 	}
921 
922 	// Fill up the vertex coordinates with zeros until the highestIndex including the vertexOffset
923 	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)));
924 
925 	// Generate random vertex only where you have index pointing at
926 	for (std::vector<deUint32>::const_iterator indexIt = m_data.indexes.begin() + m_data.params.firstIndex; indexIt != m_data.indexes.end(); ++indexIt)
927 	{
928 		// Get iterator to the vertex position  with the vertexOffset
929 		std::vector<PositionColorVertex>::iterator vertexIt = m_data.vertices.begin() + m_data.params.vertexOffset + *indexIt;
930 
931 		tcu::VecAccess<float, 4, 4>	positionAccess = vertexIt->position.xyzw();
932 		const float f0 = rnd.getFloat(-1.0f, 1.0f);
933 		const float f1 = rnd.getFloat(-1.0f, 1.0f);
934 		positionAccess = tcu::Vec4(f0, f1, 1.0f, 1.0f);
935 
936 		tcu::VecAccess<float, 4, 4>	colorAccess = vertexIt->color.xyzw();
937 		colorAccess = tcu::randomVec4(rnd);
938 	}
939 }
940 
941 template<>
draw(vk::VkCommandBuffer cmdBuffer,vk::VkBuffer,vk::VkDeviceSize)942 void DrawTestInstance<DrawIndexedParams>::draw(vk::VkCommandBuffer cmdBuffer, vk::VkBuffer, vk::VkDeviceSize)
943 {
944 	m_vk.cmdDrawIndexed(cmdBuffer, m_data.params.indexCount, m_data.params.instanceCount, m_data.params.firstIndex, m_data.params.vertexOffset, m_data.params.firstInstance);
945 }
946 
947 template<>
iterate(void)948 tcu::TestStatus DrawTestInstance<DrawIndexedParams>::iterate (void)
949 {
950 	tcu::TestLog				&log				= m_context.getTestContext().getLog();
951 	const vk::DeviceInterface&	vk					= m_context.getDeviceInterface();
952 	const vk::VkDevice			vkDevice			= m_context.getDevice();
953 	const deUint32				queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
954 	const vk::VkQueue			queue				= m_context.getUniversalQueue();
955 	vk::Allocator&				allocator			= m_context.getDefaultAllocator();
956 	const vk::VkDeviceSize		vertexBufferOffset	= 0;
957 	const vk::VkBuffer			vertexBuffer		= m_vertexBuffer->object();
958 	const deUint32				bufferSize			= (deUint32)(m_data.indexes.size() * sizeof(deUint32));
959 
960 	const vk::VkBufferCreateInfo	bufferCreateInfo =
961 	{
962 		vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,	// VkStructureType		sType;
963 		DE_NULL,									// const void*			pNext;
964 		0u,											// VkBufferCreateFlags	flags;
965 		bufferSize,									// VkDeviceSize			size;
966 		vk::VK_BUFFER_USAGE_INDEX_BUFFER_BIT,		// VkBufferUsageFlags	usage;
967 		vk::VK_SHARING_MODE_EXCLUSIVE,				// VkSharingMode		sharingMode;
968 		1u,											// deUint32				queueFamilyIndexCount;
969 		&queueFamilyIndex,							// const deUint32*		pQueueFamilyIndices;
970 	};
971 
972 	vk::Move<vk::VkBuffer>			indexBuffer = createBuffer(vk, vkDevice, &bufferCreateInfo);
973 	de::MovePtr<vk::Allocation>		indexAlloc;
974 
975 	indexAlloc = allocator.allocate(getBufferMemoryRequirements(vk, vkDevice, *indexBuffer), vk::MemoryRequirement::HostVisible);
976 	VK_CHECK(vk.bindBufferMemory(vkDevice, *indexBuffer, indexAlloc->getMemory(), indexAlloc->getOffset()));
977 
978 	deMemcpy(indexAlloc->getHostPtr(), &(m_data.indexes[0]), bufferSize);
979 
980 	vk::flushAlloc(m_vk, vkDevice, *indexAlloc);
981 
982 #ifndef CTS_USES_VULKANSC
983 	if (m_data.groupParams.useSecondaryCmdBuffer)
984 	{
985 		// record secondary command buffer
986 		if (m_data.groupParams.secondaryCmdBufferCompletelyContainsDynamicRenderpass)
987 		{
988 			beginSecondaryCmdBuffer(m_vk, vk::VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT);
989 			beginDynamicRender(*m_secCmdBuffer);
990 		}
991 		else
992 			beginSecondaryCmdBuffer(m_vk);
993 
994 		m_vk.cmdBindPipeline(*m_secCmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
995 		m_vk.cmdBindVertexBuffers(*m_secCmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
996 		m_vk.cmdBindIndexBuffer(*m_secCmdBuffer, *indexBuffer, 0u, m_data.indexType);
997 		draw(*m_secCmdBuffer);
998 
999 		if (m_data.groupParams.secondaryCmdBufferCompletelyContainsDynamicRenderpass)
1000 			endDynamicRender(*m_secCmdBuffer);
1001 
1002 		endCommandBuffer(m_vk, *m_secCmdBuffer);
1003 
1004 		// record primary command buffer
1005 		beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
1006 
1007 		preRenderBarriers();
1008 
1009 		if (!m_data.groupParams.secondaryCmdBufferCompletelyContainsDynamicRenderpass)
1010 			beginDynamicRender(*m_cmdBuffer, vk::VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT);
1011 
1012 		m_vk.cmdExecuteCommands(*m_cmdBuffer, 1u, &*m_secCmdBuffer);
1013 
1014 		if (!m_data.groupParams.secondaryCmdBufferCompletelyContainsDynamicRenderpass)
1015 			endDynamicRender(*m_cmdBuffer);
1016 
1017 		endCommandBuffer(m_vk, *m_cmdBuffer);
1018 	}
1019 	else if (m_data.groupParams.useDynamicRendering)
1020 	{
1021 		beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
1022 		preRenderBarriers();
1023 		beginDynamicRender(*m_cmdBuffer);
1024 
1025 		m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
1026 		m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
1027 		m_vk.cmdBindIndexBuffer(*m_cmdBuffer, *indexBuffer, 0u, m_data.indexType);
1028 		draw(*m_cmdBuffer);
1029 
1030 		endDynamicRender(*m_cmdBuffer);
1031 		endCommandBuffer(m_vk, *m_cmdBuffer);
1032 	}
1033 #endif // CTS_USES_VULKANSC
1034 
1035 	if (!m_data.groupParams.useDynamicRendering)
1036 	{
1037 		beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
1038 		preRenderBarriers();
1039 		beginRenderPass(*m_cmdBuffer);
1040 
1041 		m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
1042 		m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
1043 		m_vk.cmdBindIndexBuffer(*m_cmdBuffer, *indexBuffer, 0u, m_data.indexType);
1044 		draw(*m_cmdBuffer);
1045 
1046 		endRenderPass(*m_cmdBuffer);
1047 		endCommandBuffer(m_vk, *m_cmdBuffer);
1048 	}
1049 
1050 	submitCommandsAndWait(m_vk, vkDevice, queue, m_cmdBuffer.get());
1051 
1052 	// Validation
1053 	tcu::TextureLevel	refImage	(vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5f + static_cast<float>(WIDTH)), (int)(0.5f + static_cast<float>(HEIGHT)));
1054 	tcu::clear(refImage.getAccess(), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
1055 
1056 	std::vector<tcu::Vec4>	vertices;
1057 	std::vector<tcu::Vec4>	colors;
1058 
1059 	for (std::vector<deUint32>::const_iterator it = m_data.indexes.begin() + m_data.params.firstIndex; it != m_data.indexes.end(); ++it)
1060 	{
1061 		deUint32 idx = m_data.params.vertexOffset + *it;
1062 		vertices.push_back(m_data.vertices[idx].position);
1063 		colors.push_back(m_data.vertices[idx].color);
1064 	}
1065 	generateRefImage(refImage.getAccess(), vertices, colors);
1066 
1067 	const vk::VkOffset3D zeroOffset = { 0, 0, 0 };
1068 	const tcu::ConstPixelBufferAccess renderedFrame = m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(),
1069 		vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
1070 
1071 	qpTestResult res = QP_TEST_RESULT_PASS;
1072 
1073 	if (!imageCompare(log, refImage.getAccess(), renderedFrame, m_data.topology))
1074 		res = QP_TEST_RESULT_FAIL;
1075 
1076 	return tcu::TestStatus(res, qpGetTestResultName(res));
1077 }
1078 
1079 template<>
generateDrawData(void)1080 void DrawTestInstance<DrawIndirectParams>::generateDrawData (void)
1081 {
1082 	de::Random	rnd(SEED ^ m_data.commands[0].vertexCount ^ m_data.commands[0].firstVertex);
1083 
1084 	deUint32 lastIndex	= 0;
1085 
1086 	// Find the interval which will be used
1087 	for (std::vector<vk::VkDrawIndirectCommand>::const_iterator it = m_data.commands.begin(); it != m_data.commands.end(); ++it)
1088 	{
1089 		const deUint32	index = it->firstVertex + it->vertexCount;
1090 		lastIndex	= (index > lastIndex) ? index : lastIndex;
1091 	}
1092 
1093 	// Initialize with zeros
1094 	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)));
1095 
1096 	// Generate random vertices only where necessary
1097 	for (std::vector<vk::VkDrawIndirectCommand>::const_iterator it = m_data.commands.begin(); it != m_data.commands.end(); ++it)
1098 	{
1099 		std::vector<PositionColorVertex>::iterator vertexStart = m_data.vertices.begin() + it->firstVertex;
1100 
1101 		for (deUint32 idx = 0; idx < it->vertexCount; ++idx)
1102 		{
1103 			std::vector<PositionColorVertex>::iterator vertexIt = vertexStart + idx;
1104 
1105 			tcu::VecAccess<float, 4, 4> positionAccess = vertexIt->position.xyzw();
1106 			const float f0 = rnd.getFloat(-1.0f, 1.0f);
1107 			const float f1 = rnd.getFloat(-1.0f, 1.0f);
1108 			positionAccess = tcu::Vec4(f0, f1, 1.0f, 1.0f);
1109 
1110 			tcu::VecAccess<float, 4, 4> colorAccess = vertexIt->color.xyzw();
1111 			colorAccess = tcu::randomVec4(rnd);
1112 		}
1113 	}
1114 }
1115 
1116 template<>
draw(vk::VkCommandBuffer cmdBuffer,vk::VkBuffer indirectBuffer,vk::VkDeviceSize indirectOffset)1117 void DrawTestInstance<DrawIndirectParams>::draw(vk::VkCommandBuffer cmdBuffer, vk::VkBuffer indirectBuffer, vk::VkDeviceSize indirectOffset)
1118 {
1119 	const vk::VkPhysicalDeviceFeatures features = m_context.getDeviceFeatures();
1120 
1121 	// If multiDrawIndirect not supported execute single calls
1122 	if (m_data.commands.size() > 1 && !(features.multiDrawIndirect))
1123 	{
1124 		for (deUint32 cmdIdx = 0; cmdIdx < m_data.commands.size(); ++cmdIdx)
1125 		{
1126 			const deUint32	offset = (deUint32)(indirectOffset + cmdIdx * sizeof(vk::VkDrawIndirectCommand));
1127 			m_vk.cmdDrawIndirect(cmdBuffer, indirectBuffer, offset, 1, sizeof(vk::VkDrawIndirectCommand));
1128 		}
1129 	}
1130 	else
1131 	{
1132 		m_vk.cmdDrawIndirect(cmdBuffer, indirectBuffer, indirectOffset, (deUint32)m_data.commands.size(), sizeof(vk::VkDrawIndirectCommand));
1133 	}
1134 }
1135 
1136 template<>
iterate(void)1137 tcu::TestStatus DrawTestInstance<DrawIndirectParams>::iterate (void)
1138 {
1139 	tcu::TestLog						&log				= m_context.getTestContext().getLog();
1140 	const vk::DeviceInterface&			vk					= m_context.getDeviceInterface();
1141 	const vk::VkDevice					vkDevice			= m_context.getDevice();
1142 	vk::Allocator&						allocator			= m_context.getDefaultAllocator();
1143 	const vk::VkQueue					queue				= m_context.getUniversalQueue();
1144 	const deUint32						queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
1145 	const vk::VkDeviceSize				vertexBufferOffset	= 0;
1146 	const vk::VkBuffer					vertexBuffer		= m_vertexBuffer->object();
1147 	vk::Move<vk::VkBuffer>				indirectBuffer;
1148 	de::MovePtr<vk::Allocation>			indirectAlloc;
1149 
1150 	{
1151 		const vk::VkDeviceSize	indirectInfoSize	= m_data.commands.size() * sizeof(vk::VkDrawIndirectCommand);
1152 
1153 		const vk::VkBufferCreateInfo	indirectCreateInfo =
1154 		{
1155 			vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,	// VkStructureType		sType;
1156 			DE_NULL,									// const void*			pNext;
1157 			0u,											// VkBufferCreateFlags	flags;
1158 			indirectInfoSize,							// VkDeviceSize			size;
1159 			vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT,	// VkBufferUsageFlags	usage;
1160 			vk::VK_SHARING_MODE_EXCLUSIVE,				// VkSharingMode		sharingMode;
1161 			1u,											// deUint32				queueFamilyIndexCount;
1162 			&queueFamilyIndex,							// const deUint32*		pQueueFamilyIndices;
1163 		};
1164 
1165 		indirectBuffer	= createBuffer(vk, vkDevice, &indirectCreateInfo);
1166 		indirectAlloc	= allocator.allocate(getBufferMemoryRequirements(vk, vkDevice, *indirectBuffer), vk::MemoryRequirement::HostVisible);
1167 		VK_CHECK(vk.bindBufferMemory(vkDevice, *indirectBuffer, indirectAlloc->getMemory(), indirectAlloc->getOffset()));
1168 
1169 		deMemcpy(indirectAlloc->getHostPtr(), &(m_data.commands[0]), (size_t)indirectInfoSize);
1170 
1171 		vk::flushAlloc(m_vk, vkDevice, *indirectAlloc);
1172 	}
1173 
1174 #ifndef CTS_USES_VULKANSC
1175 	if (m_data.groupParams.useSecondaryCmdBuffer)
1176 	{
1177 		// record secondary command buffer
1178 		if (m_data.groupParams.secondaryCmdBufferCompletelyContainsDynamicRenderpass)
1179 		{
1180 			beginSecondaryCmdBuffer(m_vk, vk::VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT);
1181 			beginDynamicRender(*m_secCmdBuffer);
1182 		}
1183 		else
1184 			beginSecondaryCmdBuffer(m_vk);
1185 
1186 		m_vk.cmdBindVertexBuffers(*m_secCmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
1187 		m_vk.cmdBindPipeline(*m_secCmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
1188 		draw(*m_secCmdBuffer, *indirectBuffer, indirectAlloc->getOffset());
1189 
1190 		if (m_data.groupParams.secondaryCmdBufferCompletelyContainsDynamicRenderpass)
1191 			endDynamicRender(*m_secCmdBuffer);
1192 
1193 		endCommandBuffer(m_vk, *m_secCmdBuffer);
1194 
1195 		// record primary command buffer
1196 		beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
1197 
1198 		preRenderBarriers();
1199 
1200 		if (!m_data.groupParams.secondaryCmdBufferCompletelyContainsDynamicRenderpass)
1201 			beginDynamicRender(*m_cmdBuffer, vk::VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT);
1202 
1203 		m_vk.cmdExecuteCommands(*m_cmdBuffer, 1u, &*m_secCmdBuffer);
1204 
1205 		if (!m_data.groupParams.secondaryCmdBufferCompletelyContainsDynamicRenderpass)
1206 			endDynamicRender(*m_cmdBuffer);
1207 
1208 		endCommandBuffer(m_vk, *m_cmdBuffer);
1209 	}
1210 	else if (m_data.groupParams.useDynamicRendering)
1211 	{
1212 		beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
1213 		preRenderBarriers();
1214 		beginDynamicRender(*m_cmdBuffer);
1215 
1216 		m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
1217 		m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
1218 		draw(*m_cmdBuffer, *indirectBuffer, indirectAlloc->getOffset());
1219 
1220 		endDynamicRender(*m_cmdBuffer);
1221 		endCommandBuffer(m_vk, *m_cmdBuffer);
1222 	}
1223 #endif // CTS_USES_VULKANSC
1224 
1225 	if (!m_data.groupParams.useDynamicRendering)
1226 	{
1227 		beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
1228 		preRenderBarriers();
1229 		beginRenderPass(*m_cmdBuffer);
1230 
1231 		m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
1232 		m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
1233 		draw(*m_cmdBuffer, *indirectBuffer, indirectAlloc->getOffset());
1234 
1235 		endRenderPass(*m_cmdBuffer);
1236 		endCommandBuffer(m_vk, *m_cmdBuffer);
1237 	}
1238 
1239 	submitCommandsAndWait(m_vk, vkDevice, queue, m_cmdBuffer.get());
1240 
1241 	// Validation
1242 	tcu::TextureLevel refImage (vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5f + static_cast<float>(WIDTH)), (int)(0.5f + static_cast<float>(HEIGHT)));
1243 	tcu::clear(refImage.getAccess(), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
1244 
1245 	for (std::vector<vk::VkDrawIndirectCommand>::const_iterator it = m_data.commands.begin(); it != m_data.commands.end(); ++it)
1246 	{
1247 		std::vector<tcu::Vec4>	vertices;
1248 		std::vector<tcu::Vec4>	colors;
1249 
1250 		std::vector<PositionColorVertex>::const_iterator	firstIt	= m_data.vertices.begin() + it->firstVertex;
1251 		std::vector<PositionColorVertex>::const_iterator	lastIt	= firstIt + it->vertexCount;
1252 
1253 		for (std::vector<PositionColorVertex>::const_iterator vertex = firstIt; vertex != lastIt; ++vertex)
1254 		{
1255 			vertices.push_back(vertex->position);
1256 			colors.push_back(vertex->color);
1257 		}
1258 		generateRefImage(refImage.getAccess(), vertices, colors);
1259 	}
1260 
1261 	const vk::VkOffset3D zeroOffset = { 0, 0, 0 };
1262 	const tcu::ConstPixelBufferAccess renderedFrame = m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(),
1263 		vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
1264 
1265 	qpTestResult res = QP_TEST_RESULT_PASS;
1266 
1267 	if (!imageCompare(log, refImage.getAccess(), renderedFrame, m_data.topology))
1268 		res = QP_TEST_RESULT_FAIL;
1269 
1270 	return tcu::TestStatus(res, qpGetTestResultName(res));
1271 }
1272 
1273 template<>
generateDrawData(void)1274 void DrawTestInstance<DrawIndexedIndirectParams>::generateDrawData (void)
1275 {
1276 	de::Random		rnd			(SEED ^ m_data.commands[0].firstIndex ^ m_data.commands[0].indexCount);
1277 
1278 	deUint32		lastIndex	= 0;
1279 
1280 	// Get the maximum range of indexes
1281 	for (std::vector<vk::VkDrawIndexedIndirectCommand>::const_iterator it = m_data.commands.begin(); it != m_data.commands.end(); ++it)
1282 	{
1283 		const deUint32	index		= it->firstIndex + it->indexCount;
1284 						lastIndex	= (index > lastIndex) ? index : lastIndex;
1285 	}
1286 
1287 	// Initialize the vector with zeros
1288 	m_data.indexes = std::vector<deUint32>(lastIndex, 0);
1289 
1290 	deUint32	highestIndex	= 0;
1291 
1292 	// Generate random indexes for the ranges
1293 	for (std::vector<vk::VkDrawIndexedIndirectCommand>::const_iterator it = m_data.commands.begin(); it != m_data.commands.end(); ++it)
1294 	{
1295 		for (deUint32 idx = 0; idx < it->indexCount; ++idx)
1296 		{
1297 			const deUint32	vertexIdx	= rnd.getInt(it->vertexOffset, INDEX_LIMIT);
1298 			const deUint32	maxIndex	= vertexIdx + it->vertexOffset;
1299 
1300 			highestIndex = (maxIndex > highestIndex) ? maxIndex : highestIndex;
1301 			m_data.indexes[it->firstIndex + idx] = vertexIdx;
1302 		}
1303 	}
1304 
1305 	// Initialize the vertex vector
1306 	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)));
1307 
1308 	// Generate random vertices in the used locations
1309 	for (std::vector<vk::VkDrawIndexedIndirectCommand>::const_iterator cmdIt = m_data.commands.begin(); cmdIt != m_data.commands.end(); ++cmdIt)
1310 	{
1311 		deUint32	firstIdx	= cmdIt->firstIndex;
1312 		deUint32	lastIdx		= firstIdx + cmdIt->indexCount;
1313 
1314 		for (deUint32 idx = firstIdx; idx < lastIdx; ++idx)
1315 		{
1316 			std::vector<PositionColorVertex>::iterator	vertexIt = m_data.vertices.begin() + cmdIt->vertexOffset + m_data.indexes[idx];
1317 
1318 			tcu::VecAccess<float, 4, 4> positionAccess = vertexIt->position.xyzw();
1319 			const float f0 = rnd.getFloat(-1.0f, 1.0f);
1320 			const float f1 = rnd.getFloat(-1.0f, 1.0f);
1321 			positionAccess = tcu::Vec4(f0, f1, 1.0f, 1.0f);
1322 
1323 			tcu::VecAccess<float, 4, 4> colorAccess = vertexIt->color.xyzw();
1324 			colorAccess = tcu::randomVec4(rnd);
1325 		}
1326 	}
1327 }
1328 
1329 template<>
draw(vk::VkCommandBuffer cmdBuffer,vk::VkBuffer indirectBuffer,vk::VkDeviceSize indirectOffset)1330 void DrawTestInstance<DrawIndexedIndirectParams>::draw(vk::VkCommandBuffer cmdBuffer, vk::VkBuffer indirectBuffer, vk::VkDeviceSize indirectOffset)
1331 {
1332 	const vk::VkPhysicalDeviceFeatures features = m_context.getDeviceFeatures();
1333 
1334 	// If multiDrawIndirect not supported execute single calls
1335 	if (m_data.commands.size() > 1 && !(features.multiDrawIndirect))
1336 	{
1337 		for (deUint32 cmdIdx = 0; cmdIdx < m_data.commands.size(); ++cmdIdx)
1338 		{
1339 			const deUint32	offset = (deUint32)(indirectOffset + cmdIdx * sizeof(vk::VkDrawIndexedIndirectCommand));
1340 			m_vk.cmdDrawIndexedIndirect(cmdBuffer, indirectBuffer, offset, 1, sizeof(vk::VkDrawIndexedIndirectCommand));
1341 		}
1342 	}
1343 	else
1344 	{
1345 		m_vk.cmdDrawIndexedIndirect(cmdBuffer, indirectBuffer, indirectOffset, (deUint32)m_data.commands.size(), sizeof(vk::VkDrawIndexedIndirectCommand));
1346 	}
1347 }
1348 
1349 template<>
iterate(void)1350 tcu::TestStatus DrawTestInstance<DrawIndexedIndirectParams>::iterate (void)
1351 {
1352 	tcu::TestLog						&log				= m_context.getTestContext().getLog();
1353 	const vk::DeviceInterface&			vk					= m_context.getDeviceInterface();
1354 	const vk::VkDevice					vkDevice			= m_context.getDevice();
1355 	const deUint32						queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
1356 	const vk::VkQueue					queue				= m_context.getUniversalQueue();
1357 	vk::Allocator&						allocator			= m_context.getDefaultAllocator();
1358 	const vk::VkDeviceSize				vertexBufferOffset	= 0;
1359 	const vk::VkBuffer					vertexBuffer		= m_vertexBuffer->object();
1360 	vk::Move<vk::VkBuffer>				indirectBuffer;
1361 	de::MovePtr<vk::Allocation>			indirectAlloc;
1362 
1363 	{
1364 		const vk::VkDeviceSize	indirectInfoSize	= m_data.commands.size() * sizeof(vk::VkDrawIndexedIndirectCommand);
1365 
1366 		vk::VkBufferCreateInfo	indirectCreateInfo
1367 		{
1368 			vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,	// VkStructureType		sType;
1369 			DE_NULL,									// const void*			pNext;
1370 			0u,											// VkBufferCreateFlags	flags;
1371 			indirectInfoSize,							// VkDeviceSize			size;
1372 			vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT,	// VkBufferUsageFlags	usage;
1373 			vk::VK_SHARING_MODE_EXCLUSIVE,				// VkSharingMode		sharingMode;
1374 			1u,											// deUint32				queueFamilyIndexCount;
1375 			&queueFamilyIndex,							// const deUint32*		pQueueFamilyIndices;
1376 		};
1377 
1378 #ifndef CTS_USES_VULKANSC
1379 		vk::VkBufferUsageFlags2CreateInfoKHR bufferUsageFlags2 = vk::initVulkanStructure();
1380 		if (m_data.useMaintenance5)
1381 		{
1382 			bufferUsageFlags2.usage = vk::VK_BUFFER_USAGE_2_INDIRECT_BUFFER_BIT_KHR;
1383 			indirectCreateInfo.pNext = &bufferUsageFlags2;
1384 			indirectCreateInfo.usage = 0xBAD00000;
1385 		}
1386 #endif // CTS_USES_VULKANSC
1387 
1388 		indirectBuffer	= createBuffer(vk, vkDevice, &indirectCreateInfo);
1389 		indirectAlloc	= allocator.allocate(getBufferMemoryRequirements(vk, vkDevice, *indirectBuffer), vk::MemoryRequirement::HostVisible);
1390 		VK_CHECK(vk.bindBufferMemory(vkDevice, *indirectBuffer, indirectAlloc->getMemory(), indirectAlloc->getOffset()));
1391 
1392 		deMemcpy(indirectAlloc->getHostPtr(), &(m_data.commands[0]), (size_t)indirectInfoSize);
1393 
1394 		vk::flushAlloc(m_vk, vkDevice, *indirectAlloc);
1395 	}
1396 
1397 	const deUint32	bufferSize = (deUint32)(m_data.indexes.size() * sizeof(deUint32));
1398 
1399 	vk::Move<vk::VkBuffer>			indexBuffer;
1400 
1401 	vk::VkBufferCreateInfo	bufferCreateInfo
1402 	{
1403 		vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,	// VkStructureType		sType;
1404 		DE_NULL,									// const void*			pNext;
1405 		0u,											// VkBufferCreateFlags	flags;
1406 		bufferSize,									// VkDeviceSize			size;
1407 		vk::VK_BUFFER_USAGE_INDEX_BUFFER_BIT,		// VkBufferUsageFlags	usage;
1408 		vk::VK_SHARING_MODE_EXCLUSIVE,				// VkSharingMode		sharingMode;
1409 		1u,											// deUint32				queueFamilyIndexCount;
1410 		&queueFamilyIndex,							// const deUint32*		pQueueFamilyIndices;
1411 	};
1412 
1413 #ifndef CTS_USES_VULKANSC
1414 	vk::VkBufferUsageFlags2CreateInfoKHR bufferUsageFlags2 = vk::initVulkanStructure();
1415 	if (m_data.useMaintenance5)
1416 	{
1417 		bufferUsageFlags2.usage = vk::VK_BUFFER_USAGE_2_INDEX_BUFFER_BIT_KHR;
1418 		bufferCreateInfo.pNext = &bufferUsageFlags2;
1419 		bufferCreateInfo.usage = 0xBAD00000;
1420 	}
1421 #endif // CTS_USES_VULKANSC
1422 
1423 	indexBuffer = createBuffer(vk, vkDevice, &bufferCreateInfo);
1424 
1425 	de::MovePtr<vk::Allocation>	indexAlloc;
1426 
1427 	indexAlloc = allocator.allocate(getBufferMemoryRequirements(vk, vkDevice, *indexBuffer), vk::MemoryRequirement::HostVisible);
1428 	VK_CHECK(vk.bindBufferMemory(vkDevice, *indexBuffer, indexAlloc->getMemory(), indexAlloc->getOffset()));
1429 
1430 	deMemcpy(indexAlloc->getHostPtr(), &(m_data.indexes[0]), bufferSize);
1431 
1432 	vk::flushAlloc(m_vk, vkDevice, *indexAlloc);
1433 
1434 #ifndef CTS_USES_VULKANSC
1435 	if (m_data.groupParams.useSecondaryCmdBuffer)
1436 	{
1437 		// record secondary command buffer
1438 		if (m_data.groupParams.secondaryCmdBufferCompletelyContainsDynamicRenderpass)
1439 		{
1440 			beginSecondaryCmdBuffer(m_vk, vk::VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT);
1441 			beginDynamicRender(*m_secCmdBuffer);
1442 		}
1443 		else
1444 			beginSecondaryCmdBuffer(m_vk);
1445 
1446 		m_vk.cmdBindPipeline(*m_secCmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
1447 		m_vk.cmdBindVertexBuffers(*m_secCmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
1448 		m_vk.cmdBindIndexBuffer(*m_secCmdBuffer, *indexBuffer, 0u, m_data.indexType);
1449 		draw(*m_secCmdBuffer, *indirectBuffer, indirectAlloc->getOffset());
1450 
1451 		if (m_data.groupParams.secondaryCmdBufferCompletelyContainsDynamicRenderpass)
1452 			endDynamicRender(*m_secCmdBuffer);
1453 
1454 		endCommandBuffer(m_vk, *m_secCmdBuffer);
1455 
1456 		// record primary command buffer
1457 		beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
1458 
1459 		preRenderBarriers();
1460 
1461 		if (!m_data.groupParams.secondaryCmdBufferCompletelyContainsDynamicRenderpass)
1462 			beginDynamicRender(*m_cmdBuffer, vk::VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT);
1463 
1464 		m_vk.cmdExecuteCommands(*m_cmdBuffer, 1u, &*m_secCmdBuffer);
1465 
1466 		if (!m_data.groupParams.secondaryCmdBufferCompletelyContainsDynamicRenderpass)
1467 			endDynamicRender(*m_cmdBuffer);
1468 
1469 		endCommandBuffer(m_vk, *m_cmdBuffer);
1470 	}
1471 	else if (m_data.groupParams.useDynamicRendering)
1472 	{
1473 		beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
1474 		preRenderBarriers();
1475 		beginDynamicRender(*m_cmdBuffer);
1476 
1477 		m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
1478 		m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
1479 		m_vk.cmdBindIndexBuffer(*m_cmdBuffer, *indexBuffer, 0u, m_data.indexType);
1480 		draw(*m_cmdBuffer, *indirectBuffer, indirectAlloc->getOffset());
1481 
1482 		endDynamicRender(*m_cmdBuffer);
1483 		endCommandBuffer(m_vk, *m_cmdBuffer);
1484 	}
1485 #endif // CTS_USES_VULKANSC
1486 
1487 	if (!m_data.groupParams.useDynamicRendering)
1488 	{
1489 		beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
1490 		preRenderBarriers();
1491 		beginRenderPass(*m_cmdBuffer);
1492 
1493 		m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
1494 		m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
1495 		m_vk.cmdBindIndexBuffer(*m_cmdBuffer, *indexBuffer, 0u, m_data.indexType);
1496 		draw(*m_cmdBuffer, *indirectBuffer, indirectAlloc->getOffset());
1497 
1498 		endRenderPass(*m_cmdBuffer);
1499 		endCommandBuffer(m_vk, *m_cmdBuffer);
1500 	}
1501 
1502 	submitCommandsAndWait(m_vk, vkDevice, queue, m_cmdBuffer.get());
1503 
1504 	// Validation
1505 	tcu::TextureLevel refImage (vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5f + static_cast<float>(WIDTH)), (int)(0.5f + static_cast<float>(HEIGHT)));
1506 	tcu::clear(refImage.getAccess(), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
1507 
1508 	for (std::vector<vk::VkDrawIndexedIndirectCommand>::const_iterator cmd = m_data.commands.begin(); cmd != m_data.commands.end(); ++cmd)
1509 	{
1510 		std::vector<tcu::Vec4>	vertices;
1511 		std::vector<tcu::Vec4>	colors;
1512 
1513 		for (deUint32 idx = 0; idx < cmd->indexCount; ++idx)
1514 		{
1515 			const deUint32 vertexIndex = cmd->vertexOffset + m_data.indexes[cmd->firstIndex + idx];
1516 			vertices.push_back(m_data.vertices[vertexIndex].position);
1517 			colors.push_back(m_data.vertices[vertexIndex].color);
1518 		}
1519 		generateRefImage(refImage.getAccess(), vertices, colors);
1520 	}
1521 
1522 	const vk::VkOffset3D zeroOffset = { 0, 0, 0 };
1523 	const tcu::ConstPixelBufferAccess renderedFrame = m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(),
1524 		vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
1525 
1526 	qpTestResult res = QP_TEST_RESULT_PASS;
1527 
1528 	if (!imageCompare(log, refImage.getAccess(), renderedFrame, m_data.topology))
1529 		res = QP_TEST_RESULT_FAIL;
1530 
1531 	return tcu::TestStatus(res, qpGetTestResultName(res));
1532 }
1533 
1534 typedef DrawTestCase<DrawParams>				DrawCase;
1535 typedef DrawTestCase<DrawIndexedParams>			IndexedCase;
1536 typedef DrawTestCase<DrawIndirectParams>		IndirectCase;
1537 typedef DrawTestCase<DrawIndexedIndirectParams>	IndexedIndirectCase;
1538 
1539 struct TestCaseParams
1540 {
1541 	const DrawCommandType			command;
1542 	const vk::VkPrimitiveTopology	topology;
1543 	const SharedGroupParams			groupParams;
1544 
TestCaseParamsvkt::Draw::__anon114e94f30111::TestCaseParams1545 	TestCaseParams (const DrawCommandType cmd, const vk::VkPrimitiveTopology top, const SharedGroupParams gParams)
1546 		: command		(cmd)
1547 		, topology		(top)
1548 		, groupParams	(gParams)
1549 	{}
1550 };
1551 
1552 }	// anonymous
1553 
populateSubGroup(tcu::TestCaseGroup * testGroup,const TestCaseParams caseParams)1554 void populateSubGroup (tcu::TestCaseGroup* testGroup, const TestCaseParams caseParams)
1555 {
1556 	de::Random						rnd						(SEED ^ deStringHash(testGroup->getName()));
1557 	tcu::TestContext&				testCtx					= testGroup->getTestContext();
1558 	const DrawCommandType			command					= caseParams.command;
1559 	const vk::VkPrimitiveTopology	topology				= caseParams.topology;
1560 	const SharedGroupParams			groupParams				= caseParams.groupParams;
1561 	const deUint32					primitiveCountArrLength = DE_LENGTH_OF_ARRAY(PRIMITIVE_COUNT);
1562 
1563 	for (deUint32 primitiveCountIdx = 0; primitiveCountIdx < primitiveCountArrLength; ++primitiveCountIdx)
1564 	{
1565 		const deUint32 primitives = PRIMITIVE_COUNT[primitiveCountIdx];
1566 
1567 		// when testing VK_KHR_dynamic_rendering there is no need to duplicate tests for all primitive counts; use just 1 and 45
1568 		if (groupParams->useDynamicRendering && (primitiveCountIdx != 0) && (primitiveCountIdx != primitiveCountArrLength-1))
1569 			continue;
1570 
1571 		deUint32	multiplier	= 1;
1572 		deUint32	offset		= 0;
1573 		// Calculated by Vulkan 23.1
1574 		switch (topology)
1575 		{
1576 			case vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST:													break;
1577 			case vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST:						multiplier = 2;				break;
1578 			case vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:													break;
1579 			case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:					multiplier = 3;				break;
1580 			case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:												break;
1581 			case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:									offset = 1;	break;
1582 			case vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY:		multiplier = 4;	offset = 1;	break;
1583 			case vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY:						offset = 1;	break;
1584 			case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY:	multiplier = 6;				break;
1585 			case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY:	multiplier = 2;				break;
1586 			default:														DE_FATAL("Unsupported topology.");
1587 		}
1588 
1589 		const deUint32	vertexCount		= multiplier * primitives + offset;
1590 		std::string		name			= de::toString(primitives);
1591 
1592 		switch (command)
1593 		{
1594 			case DRAW_COMMAND_TYPE_DRAW:
1595 			{
1596 				deUint32	firstPrimitive	= rnd.getInt(0, primitives);
1597 				deUint32	firstVertex		= multiplier * firstPrimitive;
1598 				testGroup->addChild(new DrawCase(testCtx, name.c_str(),
1599 					DrawParams(topology, groupParams, vertexCount, 1, firstVertex, 0))
1600 				);
1601 				break;
1602 			}
1603 			case DRAW_COMMAND_TYPE_DRAW_INDEXED:
1604 			{
1605 				deUint32	firstIndex			= rnd.getInt(0, OFFSET_LIMIT);
1606 				deUint32	vertexOffset		= rnd.getInt(0, OFFSET_LIMIT);
1607 				testGroup->addChild(new IndexedCase(testCtx, name.c_str(),
1608 					DrawIndexedParams(topology, groupParams, vk::VK_INDEX_TYPE_UINT32, vertexCount, 1, firstIndex, vertexOffset, 0))
1609 				);
1610 				break;
1611 			}
1612 			case DRAW_COMMAND_TYPE_DRAW_INDIRECT:
1613 			{
1614 				deUint32	firstVertex		= rnd.getInt(0, OFFSET_LIMIT);
1615 
1616 				DrawIndirectParams	params	= DrawIndirectParams(topology, groupParams);
1617 
1618 				params.addCommand(vertexCount, 1, 0, 0);
1619 				testGroup->addChild(new IndirectCase(testCtx, (name + "_single_command").c_str(), params));
1620 
1621 				params.addCommand(vertexCount, 1, firstVertex, 0);
1622 				testGroup->addChild(new IndirectCase(testCtx, (name + "_multi_command").c_str(), params));
1623 				break;
1624 			}
1625 			case DRAW_COMMAND_TYPE_DRAW_INDEXED_INDIRECT:
1626 			{
1627 				deUint32	firstIndex		= rnd.getInt(vertexCount, OFFSET_LIMIT);
1628 				deUint32	vertexOffset	= rnd.getInt(vertexCount, OFFSET_LIMIT);
1629 
1630 				DrawIndexedIndirectParams	params	= DrawIndexedIndirectParams(topology, groupParams, vk::VK_INDEX_TYPE_UINT32);
1631 				params.addCommand(vertexCount, 1, 0, 0, 0);
1632 				testGroup->addChild(new IndexedIndirectCase(testCtx, (name + "_single_command").c_str(), params));
1633 
1634 				params.addCommand(vertexCount, 1, firstIndex, vertexOffset, 0);
1635 				testGroup->addChild(new IndexedIndirectCase(testCtx, (name + "_multi_command").c_str(), params));
1636 				break;
1637 			}
1638 			default:
1639 				DE_FATAL("Unsupported draw command.");
1640 		}
1641 	}
1642 }
1643 
createDrawTests(tcu::TestCaseGroup * testGroup,const SharedGroupParams groupParams)1644 void createDrawTests(tcu::TestCaseGroup* testGroup, const SharedGroupParams groupParams)
1645 {
1646 	for (deUint32 drawTypeIndex = 0; drawTypeIndex < DRAW_COMMAND_TYPE_DRAW_LAST; ++drawTypeIndex)
1647 	{
1648 		const DrawCommandType			command			(static_cast<DrawCommandType>(drawTypeIndex));
1649 		de::MovePtr<tcu::TestCaseGroup>	topologyGroup	(new tcu::TestCaseGroup(testGroup->getTestContext(), getDrawCommandTypeName(command)));
1650 
1651 		for (deUint32 topologyIdx = 0; topologyIdx != vk::VK_PRIMITIVE_TOPOLOGY_PATCH_LIST; ++topologyIdx)
1652 		{
1653 			const vk::VkPrimitiveTopology	topology	(static_cast<vk::VkPrimitiveTopology>(topologyIdx));
1654 			const std::string				groupName	(de::toLower(getPrimitiveTopologyName(topology)).substr(22));
1655 
1656 			// reduce number of tests for dynamic rendering cases where secondary command buffer is used
1657 			if (groupParams->useSecondaryCmdBuffer && (topologyIdx % 2u))
1658 				continue;
1659 
1660 			// Testcases with a specific topology.
1661 			addTestGroup(topologyGroup.get(), groupName, populateSubGroup, TestCaseParams(command, topology, groupParams));
1662 		}
1663 
1664 		testGroup->addChild(topologyGroup.release());
1665 	}
1666 
1667 #ifndef CTS_USES_VULKANSC
1668 	de::MovePtr<tcu::TestCaseGroup> miscGroup(new tcu::TestCaseGroup(testGroup->getTestContext(), "misc"));
1669 	if (groupParams->useDynamicRendering == false)
1670 	{
1671 		DrawIndexedIndirectParams params(vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, groupParams, vk::VK_INDEX_TYPE_UINT32);
1672 		params.addCommand(4, 1, 0, 0, 0);
1673 		params.useMaintenance5 = true;
1674 		miscGroup->addChild(new IndexedIndirectCase(testGroup->getTestContext(), "maintenance5", params));
1675 	}
1676 	testGroup->addChild(miscGroup.release());
1677 #endif // CTS_USES_VULKANSC
1678 }
1679 
createBasicDrawTests(tcu::TestContext & testCtx,const SharedGroupParams groupParams)1680 tcu::TestCaseGroup*	createBasicDrawTests (tcu::TestContext& testCtx, const SharedGroupParams groupParams)
1681 {
1682 	return createTestGroup(testCtx, "basic_draw", createDrawTests, groupParams);
1683 }
1684 
1685 }	// DrawTests
1686 }	// vkt
1687