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