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 
43 namespace vkt
44 {
45 namespace geometry
46 {
47 namespace
48 {
49 using namespace vk;
50 using de::MovePtr;
51 using de::UniquePtr;
52 using tcu::Vec4;
53 using tcu::UVec2;
54 
55 struct TestParams
56 {
57 	int	numDrawInstances;
58 	int	numInvocations;
59 };
60 
makeImageCreateInfo(const VkFormat format,const VkExtent3D size,const VkImageUsageFlags usage)61 VkImageCreateInfo 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 
makeRenderPass(const DeviceInterface & vk,const VkDevice device,const VkFormat colorFormat)84 Move<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 
makeGraphicsPipeline(const DeviceInterface & vk,const VkDevice device,const VkPipelineLayout pipelineLayout,const VkRenderPass renderPass,const VkShaderModule vertexModule,const VkShaderModule geometryModule,const VkShaderModule fragmentModule,const VkExtent2D renderSize)137 Move<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 
draw(Context & context,const UVec2 & renderSize,const VkFormat colorFormat,const Vec4 & clearColor,const VkBuffer colorBuffer,const int numDrawInstances,const std::vector<Vec4> & perInstanceAttribute)339 void 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 
generatePerInstancePosition(const int numInstances)471 std::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.
getSubregion(tcu::PixelBufferAccess image,const float x,const float y,const float size)491 tcu::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.
generateReferenceImage(tcu::PixelBufferAccess image,const Vec4 & clearColor,const std::vector<Vec4> & perInstancePosition,const int numInvocations)512 void 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 
initPrograms(SourceCollections & programCollection,const TestParams params)533 void 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 
test(Context & context,const TestParams params)623 tcu::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.
createInstancedRenderingTests(tcu::TestContext & testCtx)671 tcu::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