1/*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2016 The Khronos Group Inc.
6 * Copyright (c) 2014 The Android Open Source Project
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 Geometry shader instanced rendering tests
23 *//*--------------------------------------------------------------------*/
24
25#include "vktGeometryInstancedRenderingTests.hpp"
26#include "vktTestCase.hpp"
27#include "vktTestCaseUtil.hpp"
28#include "vktGeometryTestsUtil.hpp"
29
30#include "vkPrograms.hpp"
31#include "vkQueryUtil.hpp"
32#include "vkMemUtil.hpp"
33#include "vkRefUtil.hpp"
34#include "vkTypeUtil.hpp"
35#include "vkImageUtil.hpp"
36
37#include "tcuTextureUtil.hpp"
38#include "tcuImageCompare.hpp"
39
40#include "deRandom.hpp"
41#include "deMath.h"
42
43namespace vkt
44{
45namespace geometry
46{
47namespace
48{
49using namespace vk;
50using de::MovePtr;
51using de::UniquePtr;
52using tcu::Vec4;
53using tcu::UVec2;
54
55struct TestParams
56{
57	int	numDrawInstances;
58	int	numInvocations;
59};
60
61VkImageCreateInfo makeImageCreateInfo (const VkFormat format, const VkExtent3D size, const VkImageUsageFlags usage)
62{
63	const VkImageCreateInfo imageParams =
64	{
65		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,			// VkStructureType			sType;
66		DE_NULL,										// const void*				pNext;
67		(VkImageCreateFlags)0,							// VkImageCreateFlags		flags;
68		VK_IMAGE_TYPE_2D,								// VkImageType				imageType;
69		format,											// VkFormat					format;
70		size,											// VkExtent3D				extent;
71		1u,												// deUint32					mipLevels;
72		1u,												// deUint32					arrayLayers;
73		VK_SAMPLE_COUNT_1_BIT,							// VkSampleCountFlagBits	samples;
74		VK_IMAGE_TILING_OPTIMAL,						// VkImageTiling			tiling;
75		usage,											// VkImageUsageFlags		usage;
76		VK_SHARING_MODE_EXCLUSIVE,						// VkSharingMode			sharingMode;
77		0u,												// deUint32					queueFamilyIndexCount;
78		DE_NULL,										// const deUint32*			pQueueFamilyIndices;
79		VK_IMAGE_LAYOUT_UNDEFINED,						// VkImageLayout			initialLayout;
80	};
81	return imageParams;
82}
83
84Move<VkRenderPass> makeRenderPass (const DeviceInterface&	vk,
85								   const VkDevice			device,
86								   const VkFormat			colorFormat)
87{
88	const VkAttachmentDescription colorAttachmentDescription =
89	{
90		(VkAttachmentDescriptionFlags)0,					// VkAttachmentDescriptionFlags		flags;
91		colorFormat,										// VkFormat							format;
92		VK_SAMPLE_COUNT_1_BIT,								// VkSampleCountFlagBits			samples;
93		VK_ATTACHMENT_LOAD_OP_CLEAR,						// VkAttachmentLoadOp				loadOp;
94		VK_ATTACHMENT_STORE_OP_STORE,						// VkAttachmentStoreOp				storeOp;
95		VK_ATTACHMENT_LOAD_OP_DONT_CARE,					// VkAttachmentLoadOp				stencilLoadOp;
96		VK_ATTACHMENT_STORE_OP_DONT_CARE,					// VkAttachmentStoreOp				stencilStoreOp;
97		VK_IMAGE_LAYOUT_UNDEFINED,							// VkImageLayout					initialLayout;
98		VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,			// VkImageLayout					finalLayout;
99	};
100
101	const VkAttachmentReference colorAttachmentRef =
102	{
103		0u,													// deUint32			attachment;
104		VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL			// VkImageLayout	layout;
105	};
106
107	const VkSubpassDescription subpassDescription =
108	{
109		(VkSubpassDescriptionFlags)0,						// VkSubpassDescriptionFlags		flags;
110		VK_PIPELINE_BIND_POINT_GRAPHICS,					// VkPipelineBindPoint				pipelineBindPoint;
111		0u,													// deUint32							inputAttachmentCount;
112		DE_NULL,											// const VkAttachmentReference*		pInputAttachments;
113		1u,													// deUint32							colorAttachmentCount;
114		&colorAttachmentRef,								// const VkAttachmentReference*		pColorAttachments;
115		DE_NULL,											// const VkAttachmentReference*		pResolveAttachments;
116		DE_NULL,											// const VkAttachmentReference*		pDepthStencilAttachment;
117		0u,													// deUint32							preserveAttachmentCount;
118		DE_NULL												// const deUint32*					pPreserveAttachments;
119	};
120
121	const VkRenderPassCreateInfo renderPassInfo =
122	{
123		VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,			// VkStructureType					sType;
124		DE_NULL,											// const void*						pNext;
125		(VkRenderPassCreateFlags)0,							// VkRenderPassCreateFlags			flags;
126		1u,													// deUint32							attachmentCount;
127		&colorAttachmentDescription,						// const VkAttachmentDescription*	pAttachments;
128		1u,													// deUint32							subpassCount;
129		&subpassDescription,								// const VkSubpassDescription*		pSubpasses;
130		0u,													// deUint32							dependencyCount;
131		DE_NULL												// const VkSubpassDependency*		pDependencies;
132	};
133
134	return createRenderPass(vk, device, &renderPassInfo);
135}
136
137Move<VkPipeline> makeGraphicsPipeline (const DeviceInterface&		vk,
138									   const VkDevice				device,
139									   const VkPipelineLayout		pipelineLayout,
140									   const VkRenderPass			renderPass,
141									   const VkShaderModule			vertexModule,
142									   const VkShaderModule			geometryModule,
143									   const VkShaderModule			fragmentModule,
144									   const VkExtent2D				renderSize)
145{
146	const VkVertexInputBindingDescription vertexInputBindingDescription =
147	{
148		0u,											// uint32_t             binding;
149		sizeof(Vec4),								// uint32_t             stride;
150		VK_VERTEX_INPUT_RATE_INSTANCE,				// VkVertexInputRate    inputRate;
151	};
152
153	const VkVertexInputAttributeDescription vertexInputAttributeDescription =
154	{
155		0u,											// uint32_t    location;
156		0u,											// uint32_t    binding;
157		VK_FORMAT_R32G32B32A32_SFLOAT,				// VkFormat    format;
158		0u,											// uint32_t    offset;
159	};
160
161	const VkPipelineVertexInputStateCreateInfo vertexInputStateInfo =
162	{
163		VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,		// VkStructureType                             sType;
164		DE_NULL,														// const void*                                 pNext;
165		(VkPipelineVertexInputStateCreateFlags)0,						// VkPipelineVertexInputStateCreateFlags       flags;
166		1u,																// uint32_t                                    vertexBindingDescriptionCount;
167		&vertexInputBindingDescription,									// const VkVertexInputBindingDescription*      pVertexBindingDescriptions;
168		1u,																// uint32_t                                    vertexAttributeDescriptionCount;
169		&vertexInputAttributeDescription,								// const VkVertexInputAttributeDescription*    pVertexAttributeDescriptions;
170	};
171
172	const VkPipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateInfo =
173	{
174		VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,	// VkStructureType                             sType;
175		DE_NULL,														// const void*                                 pNext;
176		(VkPipelineInputAssemblyStateCreateFlags)0,						// VkPipelineInputAssemblyStateCreateFlags     flags;
177		VK_PRIMITIVE_TOPOLOGY_POINT_LIST,								// VkPrimitiveTopology                         topology;
178		VK_FALSE,														// VkBool32                                    primitiveRestartEnable;
179	};
180
181	const VkViewport viewport = makeViewport(
182		0.0f, 0.0f,
183		static_cast<float>(renderSize.width), static_cast<float>(renderSize.height),
184		0.0f, 1.0f);
185	const VkRect2D scissor =
186	{
187		makeOffset2D(0, 0),
188		makeExtent2D(renderSize.width, renderSize.height),
189	};
190
191	const VkPipelineViewportStateCreateInfo pipelineViewportStateInfo =
192	{
193		VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,			// VkStructureType                             sType;
194		DE_NULL,														// const void*                                 pNext;
195		(VkPipelineViewportStateCreateFlags)0,							// VkPipelineViewportStateCreateFlags          flags;
196		1u,																// uint32_t                                    viewportCount;
197		&viewport,														// const VkViewport*                           pViewports;
198		1u,																// uint32_t                                    scissorCount;
199		&scissor,														// const VkRect2D*                             pScissors;
200	};
201
202	const VkPipelineRasterizationStateCreateInfo pipelineRasterizationStateInfo =
203	{
204		VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,		// VkStructureType                          sType;
205		DE_NULL,														// const void*                              pNext;
206		(VkPipelineRasterizationStateCreateFlags)0,						// VkPipelineRasterizationStateCreateFlags  flags;
207		VK_FALSE,														// VkBool32                                 depthClampEnable;
208		VK_FALSE,														// VkBool32                                 rasterizerDiscardEnable;
209		VK_POLYGON_MODE_FILL,											// VkPolygonMode							polygonMode;
210		VK_CULL_MODE_NONE,												// VkCullModeFlags							cullMode;
211		VK_FRONT_FACE_COUNTER_CLOCKWISE,								// VkFrontFace								frontFace;
212		VK_FALSE,														// VkBool32									depthBiasEnable;
213		0.0f,															// float									depthBiasConstantFactor;
214		0.0f,															// float									depthBiasClamp;
215		0.0f,															// float									depthBiasSlopeFactor;
216		1.0f,															// float									lineWidth;
217	};
218
219	const VkPipelineMultisampleStateCreateInfo pipelineMultisampleStateInfo =
220	{
221		VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,		// VkStructureType							sType;
222		DE_NULL,														// const void*								pNext;
223		(VkPipelineMultisampleStateCreateFlags)0,						// VkPipelineMultisampleStateCreateFlags	flags;
224		VK_SAMPLE_COUNT_1_BIT,											// VkSampleCountFlagBits					rasterizationSamples;
225		VK_FALSE,														// VkBool32									sampleShadingEnable;
226		0.0f,															// float									minSampleShading;
227		DE_NULL,														// const VkSampleMask*						pSampleMask;
228		VK_FALSE,														// VkBool32									alphaToCoverageEnable;
229		VK_FALSE														// VkBool32									alphaToOneEnable;
230	};
231
232	const VkStencilOpState stencilOpState = makeStencilOpState(
233		VK_STENCIL_OP_KEEP,				// stencil fail
234		VK_STENCIL_OP_KEEP,				// depth & stencil pass
235		VK_STENCIL_OP_KEEP,				// depth only fail
236		VK_COMPARE_OP_ALWAYS,			// compare op
237		0u,								// compare mask
238		0u,								// write mask
239		0u);							// reference
240
241	VkPipelineDepthStencilStateCreateInfo pipelineDepthStencilStateInfo =
242	{
243		VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,		// VkStructureType							sType;
244		DE_NULL,														// const void*								pNext;
245		(VkPipelineDepthStencilStateCreateFlags)0,						// VkPipelineDepthStencilStateCreateFlags	flags;
246		VK_FALSE,														// VkBool32									depthTestEnable;
247		VK_FALSE,														// VkBool32									depthWriteEnable;
248		VK_COMPARE_OP_LESS,												// VkCompareOp								depthCompareOp;
249		VK_FALSE,														// VkBool32									depthBoundsTestEnable;
250		VK_FALSE,														// VkBool32									stencilTestEnable;
251		stencilOpState,													// VkStencilOpState							front;
252		stencilOpState,													// VkStencilOpState							back;
253		0.0f,															// float									minDepthBounds;
254		1.0f,															// float									maxDepthBounds;
255	};
256
257	const VkColorComponentFlags					colorComponentsAll					= VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
258	const VkPipelineColorBlendAttachmentState	pipelineColorBlendAttachmentState	=
259	{
260		VK_FALSE,						// VkBool32					blendEnable;
261		VK_BLEND_FACTOR_ONE,			// VkBlendFactor			srcColorBlendFactor;
262		VK_BLEND_FACTOR_ZERO,			// VkBlendFactor			dstColorBlendFactor;
263		VK_BLEND_OP_ADD,				// VkBlendOp				colorBlendOp;
264		VK_BLEND_FACTOR_ONE,			// VkBlendFactor			srcAlphaBlendFactor;
265		VK_BLEND_FACTOR_ZERO,			// VkBlendFactor			dstAlphaBlendFactor;
266		VK_BLEND_OP_ADD,				// VkBlendOp				alphaBlendOp;
267		colorComponentsAll,				// VkColorComponentFlags	colorWriteMask;
268	};
269
270	const VkPipelineColorBlendStateCreateInfo pipelineColorBlendStateInfo =
271	{
272		VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,		// VkStructureType								sType;
273		DE_NULL,														// const void*									pNext;
274		(VkPipelineColorBlendStateCreateFlags)0,						// VkPipelineColorBlendStateCreateFlags			flags;
275		VK_FALSE,														// VkBool32										logicOpEnable;
276		VK_LOGIC_OP_COPY,												// VkLogicOp									logicOp;
277		1u,																// deUint32										attachmentCount;
278		&pipelineColorBlendAttachmentState,								// const VkPipelineColorBlendAttachmentState*	pAttachments;
279		{ 0.0f, 0.0f, 0.0f, 0.0f },										// float										blendConstants[4];
280	};
281
282	const VkPipelineShaderStageCreateInfo pShaderStages[] =
283	{
284		{
285			VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,		// VkStructureType						sType;
286			DE_NULL,													// const void*							pNext;
287			(VkPipelineShaderStageCreateFlags)0,						// VkPipelineShaderStageCreateFlags		flags;
288			VK_SHADER_STAGE_VERTEX_BIT,									// VkShaderStageFlagBits				stage;
289			vertexModule,												// VkShaderModule						module;
290			"main",														// const char*							pName;
291			DE_NULL,													// const VkSpecializationInfo*			pSpecializationInfo;
292		},
293		{
294			VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,		// VkStructureType						sType;
295			DE_NULL,													// const void*							pNext;
296			(VkPipelineShaderStageCreateFlags)0,						// VkPipelineShaderStageCreateFlags		flags;
297			VK_SHADER_STAGE_GEOMETRY_BIT,								// VkShaderStageFlagBits				stage;
298			geometryModule,												// VkShaderModule						module;
299			"main",														// const char*							pName;
300			DE_NULL,													// const VkSpecializationInfo*			pSpecializationInfo;
301		},
302		{
303			VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,		// VkStructureType						sType;
304			DE_NULL,													// const void*							pNext;
305			(VkPipelineShaderStageCreateFlags)0,						// VkPipelineShaderStageCreateFlags		flags;
306			VK_SHADER_STAGE_FRAGMENT_BIT,								// VkShaderStageFlagBits				stage;
307			fragmentModule,												// VkShaderModule						module;
308			"main",														// const char*							pName;
309			DE_NULL,													// const VkSpecializationInfo*			pSpecializationInfo;
310		},
311	};
312
313	const VkGraphicsPipelineCreateInfo graphicsPipelineInfo =
314	{
315		VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,	// VkStructureType									sType;
316		DE_NULL,											// const void*										pNext;
317		(VkPipelineCreateFlags)0,							// VkPipelineCreateFlags							flags;
318		DE_LENGTH_OF_ARRAY(pShaderStages),					// deUint32											stageCount;
319		pShaderStages,										// const VkPipelineShaderStageCreateInfo*			pStages;
320		&vertexInputStateInfo,								// const VkPipelineVertexInputStateCreateInfo*		pVertexInputState;
321		&pipelineInputAssemblyStateInfo,					// const VkPipelineInputAssemblyStateCreateInfo*	pInputAssemblyState;
322		DE_NULL,											// const VkPipelineTessellationStateCreateInfo*		pTessellationState;
323		&pipelineViewportStateInfo,							// const VkPipelineViewportStateCreateInfo*			pViewportState;
324		&pipelineRasterizationStateInfo,					// const VkPipelineRasterizationStateCreateInfo*	pRasterizationState;
325		&pipelineMultisampleStateInfo,						// const VkPipelineMultisampleStateCreateInfo*		pMultisampleState;
326		&pipelineDepthStencilStateInfo,						// const VkPipelineDepthStencilStateCreateInfo*		pDepthStencilState;
327		&pipelineColorBlendStateInfo,						// const VkPipelineColorBlendStateCreateInfo*		pColorBlendState;
328		DE_NULL,											// const VkPipelineDynamicStateCreateInfo*			pDynamicState;
329		pipelineLayout,										// VkPipelineLayout									layout;
330		renderPass,											// VkRenderPass										renderPass;
331		0u,													// deUint32											subpass;
332		DE_NULL,											// VkPipeline										basePipelineHandle;
333		0,													// deInt32											basePipelineIndex;
334	};
335
336	return createGraphicsPipeline(vk, device, DE_NULL, &graphicsPipelineInfo);
337}
338
339void draw (Context&					context,
340		   const UVec2&				renderSize,
341		   const VkFormat			colorFormat,
342		   const Vec4&				clearColor,
343		   const VkBuffer			colorBuffer,
344		   const int				numDrawInstances,
345		   const std::vector<Vec4>& perInstanceAttribute)
346{
347	const DeviceInterface&			vk						= context.getDeviceInterface();
348	const VkDevice					device					= context.getDevice();
349	const deUint32					queueFamilyIndex		= context.getUniversalQueueFamilyIndex();
350	const VkQueue					queue					= context.getUniversalQueue();
351	Allocator&						allocator				= context.getDefaultAllocator();
352
353	const VkImageSubresourceRange	colorSubresourceRange	(makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u));
354	const VkExtent3D				colorImageExtent		(makeExtent3D(renderSize.x(), renderSize.y(), 1u));
355	const VkExtent2D				renderExtent			(makeExtent2D(renderSize.x(), renderSize.y()));
356
357	const Unique<VkImage>			colorImage				(makeImage		(vk, device, makeImageCreateInfo(colorFormat, colorImageExtent, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT)));
358	const UniquePtr<Allocation>		colorImageAlloc			(bindImage		(vk, device, allocator, *colorImage, MemoryRequirement::Any));
359	const Unique<VkImageView>		colorAttachment			(makeImageView	(vk, device, *colorImage, VK_IMAGE_VIEW_TYPE_2D, colorFormat, colorSubresourceRange));
360
361	const VkDeviceSize				vertexBufferSize		= sizeInBytes(perInstanceAttribute);
362	const Unique<VkBuffer>			vertexBuffer			(makeBuffer(vk, device, makeBufferCreateInfo(vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT)));
363	const UniquePtr<Allocation>		vertexBufferAlloc		(bindBuffer(vk, device, allocator, *vertexBuffer, MemoryRequirement::HostVisible));
364
365	const Unique<VkShaderModule>	vertexModule			(createShaderModule	(vk, device, context.getBinaryCollection().get("vert"), 0u));
366	const Unique<VkShaderModule>	geometryModule			(createShaderModule	(vk, device, context.getBinaryCollection().get("geom"), 0u));
367	const Unique<VkShaderModule>	fragmentModule			(createShaderModule	(vk, device, context.getBinaryCollection().get("frag"), 0u));
368
369	const Unique<VkRenderPass>		renderPass				(makeRenderPass			(vk, device, colorFormat));
370	const Unique<VkFramebuffer>		framebuffer				(makeFramebuffer		(vk, device, *renderPass, *colorAttachment, renderSize.x(), renderSize.y(), 1u));
371	const Unique<VkPipelineLayout>	pipelineLayout			(makePipelineLayout		(vk, device));
372	const Unique<VkPipeline>		pipeline				(makeGraphicsPipeline	(vk, device, *pipelineLayout, *renderPass, *vertexModule, *geometryModule, *fragmentModule, renderExtent));
373
374	const Unique<VkCommandPool>		cmdPool					(makeCommandPool		(vk, device, queueFamilyIndex));
375	const Unique<VkCommandBuffer>	cmdBuffer				(makeCommandBuffer		(vk, device, *cmdPool));
376
377	// Initialize vertex data
378	{
379		deMemcpy(vertexBufferAlloc->getHostPtr(), &perInstanceAttribute[0], (size_t)vertexBufferSize);
380		flushMappedMemoryRange(vk, device, vertexBufferAlloc->getMemory(), vertexBufferAlloc->getOffset(), vertexBufferSize);
381	}
382
383	beginCommandBuffer(vk, *cmdBuffer);
384
385	const VkClearValue			clearValue	= makeClearValueColor(clearColor);
386	const VkRect2D				renderArea	=
387	{
388		makeOffset2D(0, 0),
389		renderExtent,
390	};
391	const VkRenderPassBeginInfo renderPassBeginInfo =
392	{
393		VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,		// VkStructureType         sType;
394		DE_NULL,										// const void*             pNext;
395		*renderPass,									// VkRenderPass            renderPass;
396		*framebuffer,									// VkFramebuffer           framebuffer;
397		renderArea,										// VkRect2D                renderArea;
398		1u,												// uint32_t                clearValueCount;
399		&clearValue,									// const VkClearValue*     pClearValues;
400	};
401	vk.cmdBeginRenderPass(*cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
402
403	vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
404	{
405		const VkDeviceSize offset = 0ull;
406		vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffer.get(), &offset);
407	}
408	vk.cmdDraw(*cmdBuffer, 1u, static_cast<deUint32>(numDrawInstances), 0u, 0u);
409	vk.cmdEndRenderPass(*cmdBuffer);
410
411	// Prepare color image for copy
412	{
413		const VkImageMemoryBarrier barriers[] =
414		{
415			{
416				VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,		// VkStructureType			sType;
417				DE_NULL,									// const void*				pNext;
418				VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,		// VkAccessFlags			outputMask;
419				VK_ACCESS_TRANSFER_READ_BIT,				// VkAccessFlags			inputMask;
420				VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,	// VkImageLayout			oldLayout;
421				VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,		// VkImageLayout			newLayout;
422				VK_QUEUE_FAMILY_IGNORED,					// deUint32					srcQueueFamilyIndex;
423				VK_QUEUE_FAMILY_IGNORED,					// deUint32					destQueueFamilyIndex;
424				*colorImage,								// VkImage					image;
425				colorSubresourceRange,						// VkImageSubresourceRange	subresourceRange;
426			},
427		};
428
429		vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u,
430			0u, DE_NULL, 0u, DE_NULL, DE_LENGTH_OF_ARRAY(barriers), barriers);
431	}
432	// Color image -> host buffer
433	{
434		const VkBufferImageCopy region =
435		{
436			0ull,																	// VkDeviceSize                bufferOffset;
437			0u,																		// uint32_t                    bufferRowLength;
438			0u,																		// uint32_t                    bufferImageHeight;
439			makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u),		// VkImageSubresourceLayers    imageSubresource;
440			makeOffset3D(0, 0, 0),													// VkOffset3D                  imageOffset;
441			colorImageExtent,														// VkExtent3D                  imageExtent;
442		};
443
444		vk.cmdCopyImageToBuffer(*cmdBuffer, *colorImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, colorBuffer, 1u, &region);
445	}
446	// Buffer write barrier
447	{
448		const VkBufferMemoryBarrier barriers[] =
449		{
450			{
451				VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,		// VkStructureType    sType;
452				DE_NULL,										// const void*        pNext;
453				VK_ACCESS_TRANSFER_WRITE_BIT,					// VkAccessFlags      srcAccessMask;
454				VK_ACCESS_HOST_READ_BIT,						// VkAccessFlags      dstAccessMask;
455				VK_QUEUE_FAMILY_IGNORED,						// uint32_t           srcQueueFamilyIndex;
456				VK_QUEUE_FAMILY_IGNORED,						// uint32_t           dstQueueFamilyIndex;
457				colorBuffer,									// VkBuffer           buffer;
458				0ull,											// VkDeviceSize       offset;
459				VK_WHOLE_SIZE,									// VkDeviceSize       size;
460			},
461		};
462
463		vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u,
464			0u, DE_NULL, DE_LENGTH_OF_ARRAY(barriers), barriers, DE_NULL, 0u);
465	}
466
467	VK_CHECK(vk.endCommandBuffer(*cmdBuffer));
468	submitCommandsAndWait(vk, device, queue, *cmdBuffer);
469}
470
471std::vector<Vec4> generatePerInstancePosition (const int numInstances)
472{
473	de::Random			rng(1234);
474	std::vector<Vec4>	positions;
475
476	for (int i = 0; i < numInstances; ++i)
477	{
478		const float flipX	= rng.getBool() ? 1.0f : -1.0f;
479		const float flipY	= rng.getBool() ? 1.0f : -1.0f;
480		const float x		= flipX * rng.getFloat(0.1f, 0.9f);	// x mustn't be 0.0, because we are using sign() in the shader
481		const float y		= flipY * rng.getFloat(0.0f, 0.7f);
482
483		positions.push_back(Vec4(x, y, 0.0f, 1.0f));
484	}
485
486	return positions;
487}
488
489//! Get a rectangle region of an image, using NDC coordinates (i.e. [-1, 1] range).
490//! Result rect is cropped in either dimension to be inside the bounds of the image.
491tcu::PixelBufferAccess getSubregion (tcu::PixelBufferAccess image, const float x, const float y, const float size)
492{
493	const float w	= static_cast<float>(image.getWidth());
494	const float h	= static_cast<float>(image.getHeight());
495	const float x1	= w * (x + 1.0f) * 0.5f;
496	const float y1	= h * (y + 1.0f) * 0.5f;
497	const float sx	= w * size * 0.5f;
498	const float sy	= h * size * 0.5f;
499	const float x2	= x1 + sx;
500	const float y2	= y1 + sy;
501
502	// Round and clamp only after all of the above.
503	const int	ix1	= std::max(deRoundFloatToInt32(x1), 0);
504	const int	ix2	= std::min(deRoundFloatToInt32(x2), image.getWidth());
505	const int	iy1	= std::max(deRoundFloatToInt32(y1), 0);
506	const int	iy2	= std::min(deRoundFloatToInt32(y2), image.getHeight());
507
508	return tcu::getSubregion(image, ix1, iy1, ix2 - ix1, iy2 - iy1);
509}
510
511//! Must be in sync with the geometry shader code.
512void generateReferenceImage(tcu::PixelBufferAccess image, const Vec4& clearColor, const std::vector<Vec4>& perInstancePosition, const int numInvocations)
513{
514	tcu::clear(image, clearColor);
515
516	for (std::vector<Vec4>::const_iterator iterPosition = perInstancePosition.begin(); iterPosition != perInstancePosition.end(); ++iterPosition)
517	for (int invocationNdx = 0; invocationNdx < numInvocations; ++invocationNdx)
518	{
519		const float x			= iterPosition->x();
520		const float y			= iterPosition->y();
521		const float	modifier	= (numInvocations > 1 ? static_cast<float>(invocationNdx) / static_cast<float>(numInvocations - 1) : 0.0f);
522		const Vec4	color		(deFloatAbs(x), deFloatAbs(y), 0.2f + 0.8f * modifier, 1.0f);
523		const float size		= 0.05f + 0.03f * modifier;
524		const float dx			= (deFloatSign(-x) - x) / static_cast<float>(numInvocations);
525		const float xOffset		= static_cast<float>(invocationNdx) * dx;
526		const float yOffset		= 0.3f * deFloatSin(12.0f * modifier);
527
528		tcu::PixelBufferAccess rect = getSubregion(image, x + xOffset - size, y + yOffset - size, size + size);
529		tcu::clear(rect, color);
530	}
531}
532
533void initPrograms (SourceCollections& programCollection, const TestParams params)
534{
535	// Vertex shader
536	{
537		std::ostringstream src;
538		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
539			<< "\n"
540			<< "layout(location = 0) in vec4 in_position;\n"
541			<< "\n"
542			<< "out gl_PerVertex {\n"
543			<< "    vec4 gl_Position;\n"
544			<< "};\n"
545			<< "\n"
546			<< "void main(void)\n"
547			<< "{\n"
548			<< "    gl_Position = in_position;\n"
549			<< "}\n";
550
551		programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
552	}
553
554	// Geometry shader
555	{
556		// The shader must be in sync with reference image rendering routine.
557
558		std::ostringstream src;
559		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
560			<< "\n"
561			<< "layout(points, invocations = " << params.numInvocations << ") in;\n"
562			<< "layout(triangle_strip, max_vertices = 4) out;\n"
563			<< "\n"
564			<< "layout(location = 0) out vec4 out_color;\n"
565			<< "\n"
566			<< "in gl_PerVertex {\n"
567			<< "    vec4 gl_Position;\n"
568			<< "} gl_in[];\n"
569			<< "\n"
570			<< "out gl_PerVertex {\n"
571			<< "    vec4 gl_Position;\n"
572			<< "};\n"
573			<< "\n"
574			<< "void main(void)\n"
575			<< "{\n"
576			<< "    const vec4  pos       = gl_in[0].gl_Position;\n"
577			<< "    const float modifier  = " << (params.numInvocations > 1 ? "float(gl_InvocationID) / float(" + de::toString(params.numInvocations - 1) + ")" : "0.0") << ";\n"
578			<< "    const vec4  color     = vec4(abs(pos.x), abs(pos.y), 0.2 + 0.8 * modifier, 1.0);\n"
579			<< "    const float size      = 0.05 + 0.03 * modifier;\n"
580			<< "    const float dx        = (sign(-pos.x) - pos.x) / float(" << params.numInvocations << ");\n"
581			<< "    const vec4  offsetPos = pos + vec4(float(gl_InvocationID) * dx,\n"
582			<< "                                       0.3 * sin(12.0 * modifier),\n"
583			<< "                                       0.0,\n"
584			<< "                                       0.0);\n"
585			<< "\n"
586			<< "    gl_Position = offsetPos + vec4(-size, -size, 0.0, 0.0);\n"
587			<< "    out_color   = color;\n"
588			<< "    EmitVertex();\n"
589			<< "\n"
590			<< "    gl_Position = offsetPos + vec4(-size,  size, 0.0, 0.0);\n"
591			<< "    out_color   = color;\n"
592			<< "    EmitVertex();\n"
593			<< "\n"
594			<< "    gl_Position = offsetPos + vec4( size, -size, 0.0, 0.0);\n"
595			<< "    out_color   = color;\n"
596			<< "    EmitVertex();\n"
597			<< "\n"
598			<< "    gl_Position = offsetPos + vec4( size,  size, 0.0, 0.0);\n"
599			<< "    out_color   = color;\n"
600			<< "    EmitVertex();\n"
601			<<	"}\n";
602
603		programCollection.glslSources.add("geom") << glu::GeometrySource(src.str());
604	}
605
606	// Fragment shader
607	{
608		std::ostringstream src;
609		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
610			<< "\n"
611			<< "layout(location = 0) in  vec4 in_color;\n"
612			<< "layout(location = 0) out vec4 o_color;\n"
613			<< "\n"
614			<< "void main(void)\n"
615			<< "{\n"
616			<< "    o_color = in_color;\n"
617			<< "}\n";
618
619		programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
620	}
621}
622
623tcu::TestStatus test (Context& context, const TestParams params)
624{
625	const DeviceInterface&			vk					= context.getDeviceInterface();
626	const InstanceInterface&		vki					= context.getInstanceInterface();
627	const VkDevice					device				= context.getDevice();
628	const VkPhysicalDevice			physDevice			= context.getPhysicalDevice();
629	Allocator&						allocator			= context.getDefaultAllocator();
630
631	checkGeometryShaderSupport(vki, physDevice, params.numInvocations);
632
633	const UVec2						renderSize			(128u, 128u);
634	const VkFormat					colorFormat			= VK_FORMAT_R8G8B8A8_UNORM;
635	const Vec4						clearColor			= Vec4(0.0f, 0.0f, 0.0f, 1.0f);
636
637	const VkDeviceSize				colorBufferSize		= renderSize.x() * renderSize.y() * tcu::getPixelSize(mapVkFormat(colorFormat));
638	const Unique<VkBuffer>			colorBuffer			(makeBuffer(vk, device, makeBufferCreateInfo(colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT)));
639	const UniquePtr<Allocation>		colorBufferAlloc	(bindBuffer(vk, device, allocator, *colorBuffer, MemoryRequirement::HostVisible));
640
641	const std::vector<Vec4>			perInstancePosition	= generatePerInstancePosition(params.numDrawInstances);
642
643	{
644		context.getTestContext().getLog()
645			<< tcu::TestLog::Message << "Rendering " << params.numDrawInstances << " instance(s) of colorful quads." << tcu::TestLog::EndMessage
646			<< tcu::TestLog::Message << "Drawing " << params.numInvocations << " quad(s), each drawn by a geometry shader invocation." << tcu::TestLog::EndMessage;
647	}
648
649	zeroBuffer(vk, device, *colorBufferAlloc, colorBufferSize);
650	draw(context, renderSize, colorFormat, clearColor, *colorBuffer, params.numDrawInstances, perInstancePosition);
651
652	// Compare result
653	{
654		invalidateMappedMemoryRange(vk, device, colorBufferAlloc->getMemory(), colorBufferAlloc->getOffset(), colorBufferSize);
655		const tcu::ConstPixelBufferAccess result(mapVkFormat(colorFormat), renderSize.x(), renderSize.y(), 1u, colorBufferAlloc->getHostPtr());
656
657		tcu::TextureLevel reference(mapVkFormat(colorFormat), renderSize.x(), renderSize.y());
658		generateReferenceImage(reference.getAccess(), clearColor, perInstancePosition, params.numInvocations);
659
660		if (!tcu::fuzzyCompare(context.getTestContext().getLog(), "Image Compare", "Image Compare", reference.getAccess(), result, 0.01f, tcu::COMPARE_LOG_RESULT))
661			return tcu::TestStatus::fail("Rendered image is incorrect");
662		else
663			return tcu::TestStatus::pass("OK");
664	}
665}
666
667} // anonymous
668
669//! \note CTS requires shaders to be known ahead of time (some platforms use precompiled shaders), so we can't query a limit at runtime and generate
670//!       a shader based on that. This applies to number of GS invocations which can't be injected into the shader.
671tcu::TestCaseGroup* createInstancedRenderingTests (tcu::TestContext& testCtx)
672{
673	MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "instanced", "Instanced rendering tests."));
674
675	const int drawInstanceCases[]	=
676	{
677		1, 2, 4, 8,
678	};
679	const int invocationCases[]		=
680	{
681		1, 2, 8, 32,	// required by the Vulkan spec
682		64, 127,		// larger than the minimum, but perhaps some implementations support it, so we'll try
683	};
684
685	for (const int* pNumDrawInstances = drawInstanceCases; pNumDrawInstances != drawInstanceCases + DE_LENGTH_OF_ARRAY(drawInstanceCases); ++pNumDrawInstances)
686	for (const int* pNumInvocations   = invocationCases;   pNumInvocations   != invocationCases   + DE_LENGTH_OF_ARRAY(invocationCases);   ++pNumInvocations)
687	{
688		std::ostringstream caseName;
689		caseName << "draw_" << *pNumDrawInstances << "_instances_" << *pNumInvocations << "_geometry_invocations";
690
691		const TestParams params =
692		{
693			*pNumDrawInstances,
694			*pNumInvocations,
695		};
696
697		addFunctionCaseWithPrograms(group.get(), caseName.str(), "", initPrograms, test, params);
698	}
699
700	return group.release();
701}
702
703} // geometry
704} // vkt
705