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