1/*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2016 The Khronos Group Inc.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 *      http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief Multisample image Tests
22 *//*--------------------------------------------------------------------*/
23
24#include "vktPipelineMultisampleImageTests.hpp"
25#include "vktPipelineMakeUtil.hpp"
26#include "vktTestCase.hpp"
27#include "vktTestCaseUtil.hpp"
28#include "vktPipelineVertexUtil.hpp"
29#include "vktTestGroupUtil.hpp"
30
31#include "vkMemUtil.hpp"
32#include "vkQueryUtil.hpp"
33#include "vkTypeUtil.hpp"
34#include "vkRefUtil.hpp"
35#include "vkBuilderUtil.hpp"
36#include "vkPrograms.hpp"
37#include "vkImageUtil.hpp"
38
39#include "tcuTextureUtil.hpp"
40
41#include "deUniquePtr.hpp"
42#include "deSharedPtr.hpp"
43
44#include <string>
45
46namespace vkt
47{
48namespace pipeline
49{
50namespace
51{
52using namespace vk;
53using de::UniquePtr;
54using de::MovePtr;
55using de::SharedPtr;
56using tcu::IVec2;
57using tcu::Vec4;
58
59typedef SharedPtr<Unique<VkImageView> >	ImageViewSp;
60typedef SharedPtr<Unique<VkPipeline> >	PipelineSp;
61
62//! Test case parameters
63struct CaseDef
64{
65	IVec2					renderSize;
66	int						numLayers;
67	VkFormat				colorFormat;
68	VkSampleCountFlagBits	numSamples;
69};
70
71template<typename T>
72inline SharedPtr<Unique<T> > makeSharedPtr (Move<T> move)
73{
74	return SharedPtr<Unique<T> >(new Unique<T>(move));
75}
76
77template<typename T>
78inline VkDeviceSize sizeInBytes(const std::vector<T>& vec)
79{
80	return vec.size() * sizeof(vec[0]);
81}
82
83//! Create a vector of derived pipelines, each with an increasing subpass index
84std::vector<PipelineSp> makeGraphicsPipelines (const DeviceInterface&		vk,
85											   const VkDevice				device,
86											   const deUint32				numSubpasses,
87											   const VkPipelineLayout		pipelineLayout,
88											   const VkRenderPass			renderPass,
89											   const VkShaderModule			vertexModule,
90											   const VkShaderModule			fragmentModule,
91											   const IVec2					renderSize,
92											   const VkSampleCountFlagBits	numSamples,
93											   const VkPrimitiveTopology	topology)
94{
95	const VkVertexInputBindingDescription vertexInputBindingDescription =
96	{
97		0u,								// uint32_t				binding;
98		sizeof(Vertex4RGBA),			// uint32_t				stride;
99		VK_VERTEX_INPUT_RATE_VERTEX,	// VkVertexInputRate	inputRate;
100	};
101
102	const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[] =
103	{
104		{
105			0u,									// uint32_t			location;
106			0u,									// uint32_t			binding;
107			VK_FORMAT_R32G32B32A32_SFLOAT,		// VkFormat			format;
108			0u,									// uint32_t			offset;
109		},
110		{
111			1u,									// uint32_t			location;
112			0u,									// uint32_t			binding;
113			VK_FORMAT_R32G32B32A32_SFLOAT,		// VkFormat			format;
114			sizeof(Vec4),						// uint32_t			offset;
115		},
116	};
117
118	const VkPipelineVertexInputStateCreateInfo vertexInputStateInfo =
119	{
120		VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,		// VkStructureType                             sType;
121		DE_NULL,														// const void*                                 pNext;
122		(VkPipelineVertexInputStateCreateFlags)0,						// VkPipelineVertexInputStateCreateFlags       flags;
123		1u,																// uint32_t                                    vertexBindingDescriptionCount;
124		&vertexInputBindingDescription,									// const VkVertexInputBindingDescription*      pVertexBindingDescriptions;
125		DE_LENGTH_OF_ARRAY(vertexInputAttributeDescriptions),			// uint32_t                                    vertexAttributeDescriptionCount;
126		vertexInputAttributeDescriptions,								// const VkVertexInputAttributeDescription*    pVertexAttributeDescriptions;
127	};
128
129	const VkPipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateInfo =
130	{
131		VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,	// VkStructureType                             sType;
132		DE_NULL,														// const void*                                 pNext;
133		(VkPipelineInputAssemblyStateCreateFlags)0,						// VkPipelineInputAssemblyStateCreateFlags     flags;
134		topology,														// VkPrimitiveTopology                         topology;
135		VK_FALSE,														// VkBool32                                    primitiveRestartEnable;
136	};
137
138	const VkViewport viewport = makeViewport(
139		0.0f, 0.0f,
140		static_cast<float>(renderSize.x()), static_cast<float>(renderSize.y()),
141		0.0f, 1.0f);
142
143	const VkRect2D scissor = {
144		makeOffset2D(0, 0),
145		makeExtent2D(renderSize.x(), renderSize.y()),
146	};
147
148	const VkPipelineViewportStateCreateInfo pipelineViewportStateInfo =
149	{
150		VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,			// VkStructureType                             sType;
151		DE_NULL,														// const void*                                 pNext;
152		(VkPipelineViewportStateCreateFlags)0,							// VkPipelineViewportStateCreateFlags          flags;
153		1u,																// uint32_t                                    viewportCount;
154		&viewport,														// const VkViewport*                           pViewports;
155		1u,																// uint32_t                                    scissorCount;
156		&scissor,														// const VkRect2D*                             pScissors;
157	};
158
159	const VkPipelineRasterizationStateCreateInfo pipelineRasterizationStateInfo =
160	{
161		VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,		// VkStructureType                          sType;
162		DE_NULL,														// const void*                              pNext;
163		(VkPipelineRasterizationStateCreateFlags)0,						// VkPipelineRasterizationStateCreateFlags  flags;
164		VK_FALSE,														// VkBool32                                 depthClampEnable;
165		VK_FALSE,														// VkBool32                                 rasterizerDiscardEnable;
166		VK_POLYGON_MODE_FILL,											// VkPolygonMode							polygonMode;
167		VK_CULL_MODE_NONE,												// VkCullModeFlags							cullMode;
168		VK_FRONT_FACE_COUNTER_CLOCKWISE,								// VkFrontFace								frontFace;
169		VK_FALSE,														// VkBool32									depthBiasEnable;
170		0.0f,															// float									depthBiasConstantFactor;
171		0.0f,															// float									depthBiasClamp;
172		0.0f,															// float									depthBiasSlopeFactor;
173		1.0f,															// float									lineWidth;
174	};
175
176	const VkPipelineMultisampleStateCreateInfo pipelineMultisampleStateInfo =
177	{
178		VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,		// VkStructureType							sType;
179		DE_NULL,														// const void*								pNext;
180		(VkPipelineMultisampleStateCreateFlags)0,						// VkPipelineMultisampleStateCreateFlags	flags;
181		numSamples,														// VkSampleCountFlagBits					rasterizationSamples;
182		VK_FALSE,														// VkBool32									sampleShadingEnable;
183		0.0f,															// float									minSampleShading;
184		DE_NULL,														// const VkSampleMask*						pSampleMask;
185		VK_FALSE,														// VkBool32									alphaToCoverageEnable;
186		VK_FALSE														// VkBool32									alphaToOneEnable;
187	};
188
189	const VkStencilOpState stencilOpState = makeStencilOpState(
190		VK_STENCIL_OP_KEEP,				// stencil fail
191		VK_STENCIL_OP_KEEP,				// depth & stencil pass
192		VK_STENCIL_OP_KEEP,				// depth only fail
193		VK_COMPARE_OP_ALWAYS,			// compare op
194		0u,								// compare mask
195		0u,								// write mask
196		0u);							// reference
197
198	VkPipelineDepthStencilStateCreateInfo pipelineDepthStencilStateInfo =
199	{
200		VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,		// VkStructureType							sType;
201		DE_NULL,														// const void*								pNext;
202		(VkPipelineDepthStencilStateCreateFlags)0,						// VkPipelineDepthStencilStateCreateFlags	flags;
203		VK_FALSE,														// VkBool32									depthTestEnable;
204		VK_FALSE,														// VkBool32									depthWriteEnable;
205		VK_COMPARE_OP_LESS,												// VkCompareOp								depthCompareOp;
206		VK_FALSE,														// VkBool32									depthBoundsTestEnable;
207		VK_FALSE,														// VkBool32									stencilTestEnable;
208		stencilOpState,													// VkStencilOpState							front;
209		stencilOpState,													// VkStencilOpState							back;
210		0.0f,															// float									minDepthBounds;
211		1.0f,															// float									maxDepthBounds;
212	};
213
214	const VkColorComponentFlags colorComponentsAll = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
215	// Number of blend attachments must equal the number of color attachments during any subpass.
216	const VkPipelineColorBlendAttachmentState pipelineColorBlendAttachmentState =
217	{
218		VK_FALSE,						// VkBool32					blendEnable;
219		VK_BLEND_FACTOR_ONE,			// VkBlendFactor			srcColorBlendFactor;
220		VK_BLEND_FACTOR_ZERO,			// VkBlendFactor			dstColorBlendFactor;
221		VK_BLEND_OP_ADD,				// VkBlendOp				colorBlendOp;
222		VK_BLEND_FACTOR_ONE,			// VkBlendFactor			srcAlphaBlendFactor;
223		VK_BLEND_FACTOR_ZERO,			// VkBlendFactor			dstAlphaBlendFactor;
224		VK_BLEND_OP_ADD,				// VkBlendOp				alphaBlendOp;
225		colorComponentsAll,				// VkColorComponentFlags	colorWriteMask;
226	};
227
228	const VkPipelineColorBlendStateCreateInfo pipelineColorBlendStateInfo =
229	{
230		VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,		// VkStructureType								sType;
231		DE_NULL,														// const void*									pNext;
232		(VkPipelineColorBlendStateCreateFlags)0,						// VkPipelineColorBlendStateCreateFlags			flags;
233		VK_FALSE,														// VkBool32										logicOpEnable;
234		VK_LOGIC_OP_COPY,												// VkLogicOp									logicOp;
235		1u,																// deUint32										attachmentCount;
236		&pipelineColorBlendAttachmentState,								// const VkPipelineColorBlendAttachmentState*	pAttachments;
237		{ 0.0f, 0.0f, 0.0f, 0.0f },										// float										blendConstants[4];
238	};
239
240	const VkPipelineShaderStageCreateInfo pShaderStages[] =
241	{
242		{
243			VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,		// VkStructureType						sType;
244			DE_NULL,													// const void*							pNext;
245			(VkPipelineShaderStageCreateFlags)0,						// VkPipelineShaderStageCreateFlags		flags;
246			VK_SHADER_STAGE_VERTEX_BIT,									// VkShaderStageFlagBits				stage;
247			vertexModule,												// VkShaderModule						module;
248			"main",														// const char*							pName;
249			DE_NULL,													// const VkSpecializationInfo*			pSpecializationInfo;
250		},
251		{
252			VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,		// VkStructureType						sType;
253			DE_NULL,													// const void*							pNext;
254			(VkPipelineShaderStageCreateFlags)0,						// VkPipelineShaderStageCreateFlags		flags;
255			VK_SHADER_STAGE_FRAGMENT_BIT,								// VkShaderStageFlagBits				stage;
256			fragmentModule,												// VkShaderModule						module;
257			"main",														// const char*							pName;
258			DE_NULL,													// const VkSpecializationInfo*			pSpecializationInfo;
259		}
260	};
261
262	DE_ASSERT(numSubpasses > 0u);
263
264	std::vector<VkGraphicsPipelineCreateInfo>	graphicsPipelineInfos	(0);
265	std::vector<VkPipeline>						rawPipelines			(numSubpasses, DE_NULL);
266
267	{
268		const VkPipelineCreateFlags firstPipelineFlags = (numSubpasses > 1u ? VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT
269																			: (VkPipelineCreateFlagBits)0);
270
271		VkGraphicsPipelineCreateInfo createInfo =
272		{
273			VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,	// VkStructureType									sType;
274			DE_NULL,											// const void*										pNext;
275			firstPipelineFlags,									// VkPipelineCreateFlags							flags;
276			DE_LENGTH_OF_ARRAY(pShaderStages),					// deUint32											stageCount;
277			pShaderStages,										// const VkPipelineShaderStageCreateInfo*			pStages;
278			&vertexInputStateInfo,								// const VkPipelineVertexInputStateCreateInfo*		pVertexInputState;
279			&pipelineInputAssemblyStateInfo,					// const VkPipelineInputAssemblyStateCreateInfo*	pInputAssemblyState;
280			DE_NULL,											// const VkPipelineTessellationStateCreateInfo*		pTessellationState;
281			&pipelineViewportStateInfo,							// const VkPipelineViewportStateCreateInfo*			pViewportState;
282			&pipelineRasterizationStateInfo,					// const VkPipelineRasterizationStateCreateInfo*	pRasterizationState;
283			&pipelineMultisampleStateInfo,						// const VkPipelineMultisampleStateCreateInfo*		pMultisampleState;
284			&pipelineDepthStencilStateInfo,						// const VkPipelineDepthStencilStateCreateInfo*		pDepthStencilState;
285			&pipelineColorBlendStateInfo,						// const VkPipelineColorBlendStateCreateInfo*		pColorBlendState;
286			DE_NULL,											// const VkPipelineDynamicStateCreateInfo*			pDynamicState;
287			pipelineLayout,										// VkPipelineLayout									layout;
288			renderPass,											// VkRenderPass										renderPass;
289			0u,													// deUint32											subpass;
290			DE_NULL,											// VkPipeline										basePipelineHandle;
291			-1,													// deInt32											basePipelineIndex;
292		};
293
294		graphicsPipelineInfos.push_back(createInfo);
295
296		createInfo.flags				= VK_PIPELINE_CREATE_DERIVATIVE_BIT;
297		createInfo.basePipelineIndex	= 0;
298
299		for (deUint32 subpassNdx = 1u; subpassNdx < numSubpasses; ++subpassNdx)
300		{
301			createInfo.subpass = subpassNdx;
302			graphicsPipelineInfos.push_back(createInfo);
303		}
304	}
305
306	VK_CHECK(vk.createGraphicsPipelines(device, DE_NULL, static_cast<deUint32>(graphicsPipelineInfos.size()), &graphicsPipelineInfos[0], DE_NULL, &rawPipelines[0]));
307
308	std::vector<PipelineSp>	pipelines;
309
310	for (std::vector<VkPipeline>::const_iterator it = rawPipelines.begin(); it != rawPipelines.end(); ++it)
311		pipelines.push_back(makeSharedPtr(Move<VkPipeline>(check<VkPipeline>(*it), Deleter<VkPipeline>(vk, device, DE_NULL))));
312
313	return pipelines;
314}
315
316//! Make a render pass with one subpass per color attachment and one attachment per image layer.
317Move<VkRenderPass> makeMultisampleRenderPass (const DeviceInterface&		vk,
318											  const VkDevice				device,
319											  const VkFormat				colorFormat,
320											  const VkSampleCountFlagBits	numSamples,
321											  const deUint32				numLayers)
322{
323	const VkAttachmentDescription colorAttachmentDescription =
324	{
325		(VkAttachmentDescriptionFlags)0,					// VkAttachmentDescriptionFlags		flags;
326		colorFormat,										// VkFormat							format;
327		numSamples,											// VkSampleCountFlagBits			samples;
328		VK_ATTACHMENT_LOAD_OP_CLEAR,						// VkAttachmentLoadOp				loadOp;
329		VK_ATTACHMENT_STORE_OP_STORE,						// VkAttachmentStoreOp				storeOp;
330		VK_ATTACHMENT_LOAD_OP_DONT_CARE,					// VkAttachmentLoadOp				stencilLoadOp;
331		VK_ATTACHMENT_STORE_OP_DONT_CARE,					// VkAttachmentStoreOp				stencilStoreOp;
332		VK_IMAGE_LAYOUT_UNDEFINED,							// VkImageLayout					initialLayout;
333		VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,			// VkImageLayout					finalLayout;
334	};
335	const std::vector<VkAttachmentDescription> attachmentDescriptions(numLayers, colorAttachmentDescription);
336
337	// Create a subpass for each attachment (each attachement is a layer of an arrayed image).
338
339	std::vector<VkAttachmentReference>	colorAttachmentReferences(numLayers);
340	std::vector<VkSubpassDescription>	subpasses;
341
342	for (deUint32 i = 0; i < numLayers; ++i)
343	{
344		const VkAttachmentReference attachmentRef =
345		{
346			i,												// deUint32			attachment;
347			VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL		// VkImageLayout	layout;
348		};
349		colorAttachmentReferences[i] = attachmentRef;
350
351		const VkSubpassDescription subpassDescription =
352		{
353			(VkSubpassDescriptionFlags)0,					// VkSubpassDescriptionFlags		flags;
354			VK_PIPELINE_BIND_POINT_GRAPHICS,				// VkPipelineBindPoint				pipelineBindPoint;
355			0u,												// deUint32							inputAttachmentCount;
356			DE_NULL,										// const VkAttachmentReference*		pInputAttachments;
357			1u,												// deUint32							colorAttachmentCount;
358			&colorAttachmentReferences[i],					// const VkAttachmentReference*		pColorAttachments;
359			DE_NULL,										// const VkAttachmentReference*		pResolveAttachments;
360			DE_NULL,										// const VkAttachmentReference*		pDepthStencilAttachment;
361			0u,												// deUint32							preserveAttachmentCount;
362			DE_NULL											// const deUint32*					pPreserveAttachments;
363		};
364		subpasses.push_back(subpassDescription);
365	}
366
367	const VkRenderPassCreateInfo renderPassInfo =
368	{
369		VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,				// VkStructureType					sType;
370		DE_NULL,												// const void*						pNext;
371		(VkRenderPassCreateFlags)0,								// VkRenderPassCreateFlags			flags;
372		static_cast<deUint32>(attachmentDescriptions.size()),	// deUint32							attachmentCount;
373		&attachmentDescriptions[0],								// const VkAttachmentDescription*	pAttachments;
374		static_cast<deUint32>(subpasses.size()),				// deUint32							subpassCount;
375		&subpasses[0],											// const VkSubpassDescription*		pSubpasses;
376		0u,														// deUint32							dependencyCount;
377		DE_NULL													// const VkSubpassDependency*		pDependencies;
378	};
379
380	return createRenderPass(vk, device, &renderPassInfo);
381}
382
383//! A single-attachment, single-subpass render pass.
384Move<VkRenderPass> makeSimpleRenderPass (const DeviceInterface&	vk,
385									     const VkDevice			device,
386										 const VkFormat			colorFormat)
387{
388	const VkAttachmentDescription colorAttachmentDescription =
389	{
390		(VkAttachmentDescriptionFlags)0,					// VkAttachmentDescriptionFlags		flags;
391		colorFormat,										// VkFormat							format;
392		VK_SAMPLE_COUNT_1_BIT,								// VkSampleCountFlagBits			samples;
393		VK_ATTACHMENT_LOAD_OP_CLEAR,						// VkAttachmentLoadOp				loadOp;
394		VK_ATTACHMENT_STORE_OP_STORE,						// VkAttachmentStoreOp				storeOp;
395		VK_ATTACHMENT_LOAD_OP_DONT_CARE,					// VkAttachmentLoadOp				stencilLoadOp;
396		VK_ATTACHMENT_STORE_OP_DONT_CARE,					// VkAttachmentStoreOp				stencilStoreOp;
397		VK_IMAGE_LAYOUT_UNDEFINED,							// VkImageLayout					initialLayout;
398		VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,			// VkImageLayout					finalLayout;
399	};
400
401	const VkAttachmentReference colorAttachmentRef =
402	{
403		0u,													// deUint32			attachment;
404		VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL			// VkImageLayout	layout;
405	};
406
407	const VkSubpassDescription subpassDescription =
408	{
409		(VkSubpassDescriptionFlags)0,						// VkSubpassDescriptionFlags		flags;
410		VK_PIPELINE_BIND_POINT_GRAPHICS,					// VkPipelineBindPoint				pipelineBindPoint;
411		0u,													// deUint32							inputAttachmentCount;
412		DE_NULL,											// const VkAttachmentReference*		pInputAttachments;
413		1u,													// deUint32							colorAttachmentCount;
414		&colorAttachmentRef,								// const VkAttachmentReference*		pColorAttachments;
415		DE_NULL,											// const VkAttachmentReference*		pResolveAttachments;
416		DE_NULL,											// const VkAttachmentReference*		pDepthStencilAttachment;
417		0u,													// deUint32							preserveAttachmentCount;
418		DE_NULL												// const deUint32*					pPreserveAttachments;
419	};
420
421	const VkRenderPassCreateInfo renderPassInfo =
422	{
423		VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,			// VkStructureType					sType;
424		DE_NULL,											// const void*						pNext;
425		(VkRenderPassCreateFlags)0,							// VkRenderPassCreateFlags			flags;
426		1u,													// deUint32							attachmentCount;
427		&colorAttachmentDescription,						// const VkAttachmentDescription*	pAttachments;
428		1u,													// deUint32							subpassCount;
429		&subpassDescription,								// const VkSubpassDescription*		pSubpasses;
430		0u,													// deUint32							dependencyCount;
431		DE_NULL												// const VkSubpassDependency*		pDependencies;
432	};
433
434	return createRenderPass(vk, device, &renderPassInfo);
435}
436
437Move<VkImage> makeImage (const DeviceInterface& vk, const VkDevice device, const VkFormat format, const IVec2& size, const deUint32 numLayers, const VkSampleCountFlagBits samples, const VkImageUsageFlags usage)
438{
439	const VkImageCreateInfo imageParams =
440	{
441		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,			// VkStructureType			sType;
442		DE_NULL,										// const void*				pNext;
443		(VkImageCreateFlags)0,							// VkImageCreateFlags		flags;
444		VK_IMAGE_TYPE_2D,								// VkImageType				imageType;
445		format,											// VkFormat					format;
446		makeExtent3D(size.x(), size.y(), 1),			// VkExtent3D				extent;
447		1u,												// deUint32					mipLevels;
448		numLayers,										// deUint32					arrayLayers;
449		samples,										// VkSampleCountFlagBits	samples;
450		VK_IMAGE_TILING_OPTIMAL,						// VkImageTiling			tiling;
451		usage,											// VkImageUsageFlags		usage;
452		VK_SHARING_MODE_EXCLUSIVE,						// VkSharingMode			sharingMode;
453		0u,												// deUint32					queueFamilyIndexCount;
454		DE_NULL,										// const deUint32*			pQueueFamilyIndices;
455		VK_IMAGE_LAYOUT_UNDEFINED,						// VkImageLayout			initialLayout;
456	};
457	return createImage(vk, device, &imageParams);
458}
459
460//! Make a simplest sampler.
461Move<VkSampler> makeSampler (const DeviceInterface& vk, const VkDevice device)
462{
463	const VkSamplerCreateInfo samplerParams =
464	{
465		VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,			// VkStructureType         sType;
466		DE_NULL,										// const void*             pNext;
467		(VkSamplerCreateFlags)0,						// VkSamplerCreateFlags    flags;
468		VK_FILTER_NEAREST,								// VkFilter                magFilter;
469		VK_FILTER_NEAREST,								// VkFilter                minFilter;
470		VK_SAMPLER_MIPMAP_MODE_NEAREST,					// VkSamplerMipmapMode     mipmapMode;
471		VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,			// VkSamplerAddressMode    addressModeU;
472		VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,			// VkSamplerAddressMode    addressModeV;
473		VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,			// VkSamplerAddressMode    addressModeW;
474		0.0f,											// float                   mipLodBias;
475		VK_FALSE,										// VkBool32                anisotropyEnable;
476		1.0f,											// float                   maxAnisotropy;
477		VK_FALSE,										// VkBool32                compareEnable;
478		VK_COMPARE_OP_ALWAYS,							// VkCompareOp             compareOp;
479		0.0f,											// float                   minLod;
480		0.0f,											// float                   maxLod;
481		VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK,		// VkBorderColor           borderColor;
482		VK_FALSE,										// VkBool32                unnormalizedCoordinates;
483	};
484	return createSampler(vk, device, &samplerParams);
485}
486
487inline Move<VkBuffer> makeBuffer (const DeviceInterface& vk, const VkDevice device, const VkDeviceSize bufferSize, const VkBufferUsageFlags usage)
488{
489	const VkBufferCreateInfo bufferCreateInfo = makeBufferCreateInfo(bufferSize, usage);
490	return createBuffer(vk, device, &bufferCreateInfo);
491}
492
493inline VkImageSubresourceRange makeColorSubresourceRange (const int baseArrayLayer, const int layerCount)
494{
495	return makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, static_cast<deUint32>(baseArrayLayer), static_cast<deUint32>(layerCount));
496}
497
498inline VkImageSubresourceLayers makeColorSubresourceLayers (const int baseArrayLayer, const int layerCount)
499{
500	return makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, static_cast<deUint32>(baseArrayLayer), static_cast<deUint32>(layerCount));
501}
502
503void checkImageFormatRequirements (const InstanceInterface&		vki,
504								   const VkPhysicalDevice		physDevice,
505								   const VkSampleCountFlagBits	sampleCount,
506								   const VkFormat				format,
507								   const VkImageUsageFlags		usage)
508{
509	VkPhysicalDeviceFeatures	features;
510	vki.getPhysicalDeviceFeatures(physDevice, &features);
511
512	if (((usage & VK_IMAGE_USAGE_STORAGE_BIT) != 0) && !features.shaderStorageImageMultisample)
513		TCU_THROW(NotSupportedError, "Multisampled storage images are not supported");
514
515	VkImageFormatProperties		imageFormatProperties;
516	const VkResult				imageFormatResult		= vki.getPhysicalDeviceImageFormatProperties(
517		physDevice, format, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, usage, (VkImageCreateFlags)0, &imageFormatProperties);
518
519	if (imageFormatResult == VK_ERROR_FORMAT_NOT_SUPPORTED)
520		TCU_THROW(NotSupportedError, "Image format is not supported");
521
522	if ((imageFormatProperties.sampleCounts & sampleCount) != sampleCount)
523		TCU_THROW(NotSupportedError, "Requested sample count is not supported");
524}
525
526void zeroBuffer (const DeviceInterface& vk, const VkDevice device, const Allocation& alloc, const VkDeviceSize bufferSize)
527{
528	deMemset(alloc.getHostPtr(), 0, static_cast<std::size_t>(bufferSize));
529	flushMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), bufferSize);
530}
531
532//! The default foreground color.
533inline Vec4 getPrimitiveColor (void)
534{
535	return Vec4(1.0f, 0.0f, 0.0f, 1.0f);
536}
537
538//! Get a reference clear value based on color format.
539VkClearValue getClearValue (const VkFormat format)
540{
541	if (isUintFormat(format) || isIntFormat(format))
542		return makeClearValueColorU32(16, 32, 64, 96);
543	else
544		return makeClearValueColorF32(0.0f, 0.0f, 1.0f, 1.0f);
545}
546
547std::string getColorFormatStr (const int numComponents, const bool isUint, const bool isSint)
548{
549	std::ostringstream str;
550	if (numComponents == 1)
551		str << (isUint ? "uint" : isSint ? "int" : "float");
552	else
553		str << (isUint ? "u" : isSint ? "i" : "") << "vec" << numComponents;
554
555	return str.str();
556}
557
558std::string getSamplerTypeStr (const int numLayers, const bool isUint, const bool isSint)
559{
560	std::ostringstream str;
561	str << (isUint ? "u" : isSint ? "i" : "") << "sampler2DMS" << (numLayers > 1 ? "Array" : "");
562	return str.str();
563}
564
565//! Generate a gvec4 color literal.
566template<typename T>
567std::string getColorStr (const T* data, int numComponents, const bool isUint, const bool isSint)
568{
569	const int maxIndex = 3;  // 4 components max
570
571	std::ostringstream str;
572	str << (isUint ? "u" : isSint ? "i" : "") << "vec4(";
573
574	for (int i = 0; i < numComponents; ++i)
575	{
576		str << data[i]
577			<< (i < maxIndex ? ", " : "");
578	}
579
580	for (int i = numComponents; i < maxIndex + 1; ++i)
581	{
582		str << (i == maxIndex ? 1 : 0)
583			<< (i <  maxIndex ? ", " : "");
584	}
585
586	str << ")";
587	return str.str();
588}
589
590//! Clear color literal value used by the sampling shader.
591std::string getReferenceClearColorStr (const VkFormat format, const int numComponents, const bool isUint, const bool isSint)
592{
593	const VkClearColorValue clearColor = getClearValue(format).color;
594	if (isUint)
595		return getColorStr(clearColor.uint32, numComponents, isUint, isSint);
596	else if (isSint)
597		return getColorStr(clearColor.int32, numComponents, isUint, isSint);
598	else
599		return getColorStr(clearColor.float32, numComponents, isUint, isSint);
600}
601
602//! Primitive color literal value used by the sampling shader.
603std::string getReferencePrimitiveColorStr (int numComponents, const bool isUint, const bool isSint)
604{
605	const Vec4 color = getPrimitiveColor();
606	return getColorStr(color.getPtr(), numComponents, isUint, isSint);
607}
608
609inline int getNumSamples (const VkSampleCountFlagBits samples)
610{
611	return static_cast<int>(samples);	// enum bitmask actually matches the number of samples
612}
613
614//! A flat-colored shape with sharp angles to make antialiasing visible.
615std::vector<Vertex4RGBA> genTriangleVertices (void)
616{
617	static const Vertex4RGBA data[] =
618	{
619		{
620			Vec4(-1.0f, 0.0f, 0.0f, 1.0f),
621			getPrimitiveColor(),
622		},
623		{
624			Vec4(0.8f, 0.2f, 0.0f, 1.0f),
625			getPrimitiveColor(),
626		},
627		{
628			Vec4(0.8f, -0.2f, 0.0f, 1.0f),
629			getPrimitiveColor(),
630		},
631	};
632	return std::vector<Vertex4RGBA>(data, data + DE_LENGTH_OF_ARRAY(data));
633}
634
635//! A full-viewport quad. Use with TRIANGLE_STRIP topology.
636std::vector<Vertex4RGBA> genFullQuadVertices (void)
637{
638	static const Vertex4RGBA data[] =
639	{
640		{
641			Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
642			Vec4(), // unused
643		},
644		{
645			Vec4(-1.0f, 1.0f, 0.0f, 1.0f),
646			Vec4(), // unused
647		},
648		{
649			Vec4(1.0f, -1.0f, 0.0f, 1.0f),
650			Vec4(), // unused
651		},
652		{
653			Vec4(1.0f, 1.0f, 0.0f, 1.0f),
654			Vec4(), // unused
655		},
656	};
657	return std::vector<Vertex4RGBA>(data, data + DE_LENGTH_OF_ARRAY(data));
658}
659
660std::string getShaderImageFormatQualifier (const tcu::TextureFormat& format)
661{
662	const char* orderPart;
663	const char* typePart;
664
665	switch (format.order)
666	{
667		case tcu::TextureFormat::R:		orderPart = "r";	break;
668		case tcu::TextureFormat::RG:	orderPart = "rg";	break;
669		case tcu::TextureFormat::RGB:	orderPart = "rgb";	break;
670		case tcu::TextureFormat::RGBA:	orderPart = "rgba";	break;
671
672		default:
673			DE_ASSERT(false);
674			orderPart = DE_NULL;
675	}
676
677	switch (format.type)
678	{
679		case tcu::TextureFormat::FLOAT:				typePart = "32f";		break;
680		case tcu::TextureFormat::HALF_FLOAT:		typePart = "16f";		break;
681
682		case tcu::TextureFormat::UNSIGNED_INT32:	typePart = "32ui";		break;
683		case tcu::TextureFormat::UNSIGNED_INT16:	typePart = "16ui";		break;
684		case tcu::TextureFormat::UNSIGNED_INT8:		typePart = "8ui";		break;
685
686		case tcu::TextureFormat::SIGNED_INT32:		typePart = "32i";		break;
687		case tcu::TextureFormat::SIGNED_INT16:		typePart = "16i";		break;
688		case tcu::TextureFormat::SIGNED_INT8:		typePart = "8i";		break;
689
690		case tcu::TextureFormat::UNORM_INT16:		typePart = "16";		break;
691		case tcu::TextureFormat::UNORM_INT8:		typePart = "8";			break;
692
693		case tcu::TextureFormat::SNORM_INT16:		typePart = "16_snorm";	break;
694		case tcu::TextureFormat::SNORM_INT8:		typePart = "8_snorm";	break;
695
696		default:
697			DE_ASSERT(false);
698			typePart = DE_NULL;
699	}
700
701	return std::string() + orderPart + typePart;
702}
703
704std::string getShaderMultisampledImageType (const tcu::TextureFormat& format, const int numLayers)
705{
706	const std::string formatPart = tcu::getTextureChannelClass(format.type) == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER ? "u" :
707								   tcu::getTextureChannelClass(format.type) == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER   ? "i" : "";
708
709	std::ostringstream str;
710	str << formatPart << "image2DMS" << (numLayers > 1 ? "Array" : "");
711
712	return str.str();
713}
714
715void addSimpleVertexAndFragmentPrograms (SourceCollections& programCollection, const CaseDef caseDef)
716{
717	const int	numComponents	= tcu::getNumUsedChannels(mapVkFormat(caseDef.colorFormat).order);
718	const bool	isUint			= isUintFormat(caseDef.colorFormat);
719	const bool	isSint			= isIntFormat(caseDef.colorFormat);
720
721	// Vertex shader
722	{
723		std::ostringstream src;
724		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
725			<< "\n"
726			<< "layout(location = 0) in  vec4 in_position;\n"
727			<< "layout(location = 1) in  vec4 in_color;\n"
728			<< "layout(location = 0) out vec4 o_color;\n"
729			<< "\n"
730			<< "out gl_PerVertex {\n"
731			<< "    vec4 gl_Position;\n"
732			<< "};\n"
733			<< "\n"
734			<< "void main(void)\n"
735			<< "{\n"
736			<< "    gl_Position = in_position;\n"
737			<< "    o_color     = in_color;\n"
738			<< "}\n";
739
740		programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
741	}
742
743	// Fragment shader
744	{
745		const std::string colorFormat = getColorFormatStr(numComponents, isUint, isSint);
746
747		std::ostringstream src;
748		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
749			<< "\n"
750			<< "layout(location = 0) in  vec4 in_color;\n"
751			<< "layout(location = 0) out " << colorFormat << " o_color;\n"
752			<< "\n"
753			<< "void main(void)\n"
754			<< "{\n"
755			<< "    o_color = " << colorFormat << "("		// float color will be converted to int/uint here if needed
756			<< (numComponents == 1 ? "in_color.r"   :
757				numComponents == 2 ? "in_color.rg"  :
758				numComponents == 3 ? "in_color.rgb" : "in_color") << ");\n"
759			<< "}\n";
760
761		programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
762	}
763}
764
765//! Synchronously render to a multisampled color image.
766void renderMultisampledImage (Context& context, const CaseDef& caseDef, const VkImage colorImage)
767{
768	const DeviceInterface&			vk					= context.getDeviceInterface();
769	const VkDevice					device				= context.getDevice();
770	const VkQueue					queue				= context.getUniversalQueue();
771	const deUint32					queueFamilyIndex	= context.getUniversalQueueFamilyIndex();
772	Allocator&						allocator			= context.getDefaultAllocator();
773
774	const Unique<VkCommandPool>		cmdPool				(makeCommandPool  (vk, device, queueFamilyIndex));
775	const Unique<VkCommandBuffer>	cmdBuffer			(makeCommandBuffer(vk, device, *cmdPool));
776
777	const VkRect2D renderArea = {
778		makeOffset2D(0, 0),
779		makeExtent2D(caseDef.renderSize.x(), caseDef.renderSize.y()),
780	};
781
782	{
783		// Create an image view (attachment) for each layer of the image
784		std::vector<ImageViewSp>	colorAttachments;
785		std::vector<VkImageView>	attachmentHandles;
786		for (int i = 0; i < caseDef.numLayers; ++i)
787		{
788			colorAttachments.push_back(makeSharedPtr(makeImageView(
789				vk, device, colorImage, VK_IMAGE_VIEW_TYPE_2D, caseDef.colorFormat, makeColorSubresourceRange(i, 1))));
790			attachmentHandles.push_back(**colorAttachments.back());
791		}
792
793		// Vertex buffer
794		const std::vector<Vertex4RGBA>	vertices			= genTriangleVertices();
795		const VkDeviceSize				vertexBufferSize	= sizeInBytes(vertices);
796		const Unique<VkBuffer>			vertexBuffer		(makeBuffer(vk, device, vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT));
797		const UniquePtr<Allocation>		vertexBufferAlloc	(bindBuffer(vk, device, allocator, *vertexBuffer, MemoryRequirement::HostVisible));
798
799		{
800			deMemcpy(vertexBufferAlloc->getHostPtr(), &vertices[0], static_cast<std::size_t>(vertexBufferSize));
801			flushMappedMemoryRange(vk, device, vertexBufferAlloc->getMemory(), vertexBufferAlloc->getOffset(), vertexBufferSize);
802		}
803
804		const Unique<VkShaderModule>	vertexModule	(createShaderModule			(vk, device, context.getBinaryCollection().get("vert"), 0u));
805		const Unique<VkShaderModule>	fragmentModule	(createShaderModule			(vk, device, context.getBinaryCollection().get("frag"), 0u));
806		const Unique<VkRenderPass>		renderPass		(makeMultisampleRenderPass	(vk, device, caseDef.colorFormat, caseDef.numSamples, caseDef.numLayers));
807		const Unique<VkFramebuffer>		framebuffer		(makeFramebuffer			(vk, device, *renderPass, caseDef.numLayers, &attachmentHandles[0],
808																					 static_cast<deUint32>(caseDef.renderSize.x()),  static_cast<deUint32>(caseDef.renderSize.y())));
809		const Unique<VkPipelineLayout>	pipelineLayout	(makePipelineLayout			(vk, device));
810		const std::vector<PipelineSp>	pipelines		(makeGraphicsPipelines		(vk, device, caseDef.numLayers, *pipelineLayout, *renderPass, *vertexModule, *fragmentModule,
811																					 caseDef.renderSize, caseDef.numSamples, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST));
812
813		beginCommandBuffer(vk, *cmdBuffer);
814
815		const std::vector<VkClearValue> clearValues(caseDef.numLayers, getClearValue(caseDef.colorFormat));
816
817		const VkRenderPassBeginInfo renderPassBeginInfo = {
818			VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,		// VkStructureType         sType;
819			DE_NULL,										// const void*             pNext;
820			*renderPass,									// VkRenderPass            renderPass;
821			*framebuffer,									// VkFramebuffer           framebuffer;
822			renderArea,										// VkRect2D                renderArea;
823			static_cast<deUint32>(clearValues.size()),		// uint32_t                clearValueCount;
824			&clearValues[0],								// const VkClearValue*     pClearValues;
825		};
826		vk.cmdBeginRenderPass(*cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
827
828		{
829			const VkDeviceSize vertexBufferOffset = 0ull;
830			vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
831		}
832
833		for (int layerNdx = 0; layerNdx < caseDef.numLayers; ++layerNdx)
834		{
835			if (layerNdx != 0)
836				vk.cmdNextSubpass(*cmdBuffer, VK_SUBPASS_CONTENTS_INLINE);
837
838			vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, **pipelines[layerNdx]);
839
840			vk.cmdDraw(*cmdBuffer, static_cast<deUint32>(vertices.size()), 1u, 0u, 0u);
841		}
842
843		vk.cmdEndRenderPass(*cmdBuffer);
844
845		VK_CHECK(vk.endCommandBuffer(*cmdBuffer));
846		submitCommandsAndWait(vk, device, queue, *cmdBuffer);
847	}
848}
849
850namespace SampledImage
851{
852
853void initPrograms (SourceCollections& programCollection, const CaseDef caseDef)
854{
855	// Pass 1: Render to texture
856
857	addSimpleVertexAndFragmentPrograms(programCollection, caseDef);
858
859	// Pass 2: Sample texture
860
861	// Vertex shader
862	{
863		std::ostringstream src;
864		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
865			<< "\n"
866			<< "layout(location = 0) in  vec4  in_position;\n"
867			<< "\n"
868			<< "out gl_PerVertex {\n"
869			<< "    vec4 gl_Position;\n"
870			<< "};\n"
871			<< "\n"
872			<< "void main(void)\n"
873			<< "{\n"
874			<< "    gl_Position = in_position;\n"
875			<< "}\n";
876
877		programCollection.glslSources.add("sample_vert") << glu::VertexSource(src.str());
878	}
879
880	// Fragment shader
881	{
882		const int			numComponents		= tcu::getNumUsedChannels(mapVkFormat(caseDef.colorFormat).order);
883		const bool			isUint				= isUintFormat(caseDef.colorFormat);
884		const bool			isSint				= isIntFormat(caseDef.colorFormat);
885		const std::string	texelFormatStr		= (isUint ? "uvec4" : isSint ? "ivec4" : "vec4");
886		const std::string	refClearColor		= getReferenceClearColorStr(caseDef.colorFormat, numComponents, isUint, isSint);
887		const std::string	refPrimitiveColor	= getReferencePrimitiveColorStr(numComponents, isUint, isSint);
888		const std::string	samplerTypeStr		= getSamplerTypeStr(caseDef.numLayers, isUint, isSint);
889
890		std::ostringstream src;
891		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
892			<< "\n"
893			<< "layout(location = 0) out int o_status;\n"
894			<< "\n"
895			<< "layout(set = 0, binding = 0) uniform " << samplerTypeStr << " colorTexture;\n"
896			<< "\n"
897			<< "void main(void)\n"
898			<< "{\n"
899			<< "    int checksum = 0;\n"
900			<< "\n";
901
902		if (caseDef.numLayers == 1)
903			src << "    for (int sampleNdx = 0; sampleNdx < " << caseDef.numSamples << "; ++sampleNdx) {\n"
904				<< "        " << texelFormatStr << " color = texelFetch(colorTexture, ivec2(gl_FragCoord.xy), sampleNdx);\n"
905				<< "        if (color == " << refClearColor << " || color == " << refPrimitiveColor << ")\n"
906				<< "            ++checksum;\n"
907				<< "    }\n";
908		else
909			src << "    for (int layerNdx = 0; layerNdx < " << caseDef.numLayers << "; ++layerNdx)\n"
910				<< "    for (int sampleNdx = 0; sampleNdx < " << caseDef.numSamples << "; ++sampleNdx) {\n"
911				<< "        " << texelFormatStr << " color = texelFetch(colorTexture, ivec3(gl_FragCoord.xy, layerNdx), sampleNdx);\n"
912				<< "        if (color == " << refClearColor << " || color == " << refPrimitiveColor << ")\n"
913				<< "            ++checksum;\n"
914				<< "    }\n";
915
916		src << "\n"
917			<< "    o_status = checksum;\n"
918			<< "}\n";
919
920		programCollection.glslSources.add("sample_frag") << glu::FragmentSource(src.str());
921	}
922}
923
924tcu::TestStatus test (Context& context, const CaseDef caseDef)
925{
926	const DeviceInterface&		vk					= context.getDeviceInterface();
927	const InstanceInterface&	vki					= context.getInstanceInterface();
928	const VkDevice				device				= context.getDevice();
929	const VkPhysicalDevice		physDevice			= context.getPhysicalDevice();
930	const VkQueue				queue				= context.getUniversalQueue();
931	const deUint32				queueFamilyIndex	= context.getUniversalQueueFamilyIndex();
932	Allocator&					allocator			= context.getDefaultAllocator();
933
934	const VkImageUsageFlags		colorImageUsage		= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
935
936	checkImageFormatRequirements(vki, physDevice, caseDef.numSamples, caseDef.colorFormat, colorImageUsage);
937
938	{
939		tcu::TestLog& log = context.getTestContext().getLog();
940		log << tcu::LogSection("Description", "")
941			<< tcu::TestLog::Message << "Rendering to a multisampled image. Expecting all samples to be either a clear color or a primitive color." << tcu::TestLog::EndMessage
942			<< tcu::TestLog::Message << "Sampling from the texture with texelFetch (OpImageFetch)." << tcu::TestLog::EndMessage
943			<< tcu::TestLog::EndSection;
944	}
945
946	// Multisampled color image
947	const Unique<VkImage>			colorImage		(makeImage(vk, device, caseDef.colorFormat, caseDef.renderSize, caseDef.numLayers, caseDef.numSamples, colorImageUsage));
948	const UniquePtr<Allocation>		colorImageAlloc	(bindImage(vk, device, allocator, *colorImage, MemoryRequirement::Any));
949
950	const Unique<VkCommandPool>		cmdPool			(makeCommandPool  (vk, device, queueFamilyIndex));
951	const Unique<VkCommandBuffer>	cmdBuffer		(makeCommandBuffer(vk, device, *cmdPool));
952
953	const VkRect2D renderArea = {
954		makeOffset2D(0, 0),
955		makeExtent2D(caseDef.renderSize.x(), caseDef.renderSize.y()),
956	};
957
958	// Step 1: Render to texture
959	{
960		renderMultisampledImage(context, caseDef, *colorImage);
961	}
962
963	// Step 2: Sample texture
964	{
965		// Color image view
966		const VkImageViewType			colorImageViewType	= (caseDef.numLayers == 1 ? VK_IMAGE_VIEW_TYPE_2D : VK_IMAGE_VIEW_TYPE_2D_ARRAY);
967		const Unique<VkImageView>		colorImageView		(makeImageView(vk, device, *colorImage, colorImageViewType, caseDef.colorFormat, makeColorSubresourceRange(0, caseDef.numLayers)));
968		const Unique<VkSampler>			colorSampler		(makeSampler(vk, device));
969
970		// Checksum image
971		const VkFormat					checksumFormat		= VK_FORMAT_R32_SINT;
972		const Unique<VkImage>			checksumImage		(makeImage(vk, device, checksumFormat, caseDef.renderSize, 1u, VK_SAMPLE_COUNT_1_BIT,
973																	   VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT));
974		const UniquePtr<Allocation>		checksumImageAlloc	(bindImage(vk, device, allocator, *checksumImage, MemoryRequirement::Any));
975		const Unique<VkImageView>		checksumImageView	(makeImageView(vk, device, *checksumImage, VK_IMAGE_VIEW_TYPE_2D, checksumFormat, makeColorSubresourceRange(0, 1)));
976
977		// Checksum buffer (for host reading)
978		const VkDeviceSize				checksumBufferSize	= caseDef.renderSize.x() * caseDef.renderSize.y() * tcu::getPixelSize(mapVkFormat(checksumFormat));
979		const Unique<VkBuffer>			checksumBuffer		(makeBuffer(vk, device, checksumBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT));
980		const UniquePtr<Allocation>		checksumBufferAlloc	(bindBuffer(vk, device, allocator, *checksumBuffer, MemoryRequirement::HostVisible));
981
982		zeroBuffer(vk, device, *checksumBufferAlloc, checksumBufferSize);
983
984		// Vertex buffer
985		const std::vector<Vertex4RGBA>	vertices			= genFullQuadVertices();
986		const VkDeviceSize				vertexBufferSize	= sizeInBytes(vertices);
987		const Unique<VkBuffer>			vertexBuffer		(makeBuffer(vk, device, vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT));
988		const UniquePtr<Allocation>		vertexBufferAlloc	(bindBuffer(vk, device, allocator, *vertexBuffer, MemoryRequirement::HostVisible));
989
990		{
991			deMemcpy(vertexBufferAlloc->getHostPtr(), &vertices[0], static_cast<std::size_t>(vertexBufferSize));
992			flushMappedMemoryRange(vk, device, vertexBufferAlloc->getMemory(), vertexBufferAlloc->getOffset(), vertexBufferSize);
993		}
994
995		// Descriptors
996		// \note OpImageFetch doesn't use a sampler, but in GLSL texelFetch needs a sampler2D which translates to a combined image sampler in Vulkan.
997
998		const Unique<VkDescriptorSetLayout> descriptorSetLayout(DescriptorSetLayoutBuilder()
999			.addSingleSamplerBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT, &colorSampler.get())
1000			.build(vk, device));
1001
1002		const Unique<VkDescriptorPool> descriptorPool(DescriptorPoolBuilder()
1003			.addType(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
1004			.build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
1005
1006		const Unique<VkDescriptorSet>	descriptorSet		(makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
1007		const VkDescriptorImageInfo		imageDescriptorInfo	= makeDescriptorImageInfo(DE_NULL, *colorImageView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
1008
1009		DescriptorSetUpdateBuilder()
1010			.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &imageDescriptorInfo)
1011			.update(vk, device);
1012
1013		const Unique<VkShaderModule>	vertexModule	(createShaderModule		(vk, device, context.getBinaryCollection().get("sample_vert"), 0u));
1014		const Unique<VkShaderModule>	fragmentModule	(createShaderModule		(vk, device, context.getBinaryCollection().get("sample_frag"), 0u));
1015		const Unique<VkRenderPass>		renderPass		(makeSimpleRenderPass	(vk, device, checksumFormat));
1016		const Unique<VkFramebuffer>		framebuffer		(makeFramebuffer		(vk, device, *renderPass, 1u, &checksumImageView.get(),
1017																				 static_cast<deUint32>(caseDef.renderSize.x()),  static_cast<deUint32>(caseDef.renderSize.y())));
1018		const Unique<VkPipelineLayout>	pipelineLayout	(makePipelineLayout		(vk, device, *descriptorSetLayout));
1019		const std::vector<PipelineSp>	pipelines		(makeGraphicsPipelines	(vk, device, 1u, *pipelineLayout, *renderPass, *vertexModule, *fragmentModule,
1020																				 caseDef.renderSize, VK_SAMPLE_COUNT_1_BIT, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP));
1021
1022		beginCommandBuffer(vk, *cmdBuffer);
1023
1024		// Prepare for sampling in the fragment shader
1025		{
1026			const VkImageMemoryBarrier barriers[] =
1027			{
1028				{
1029					VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,						// VkStructureType			sType;
1030					DE_NULL,													// const void*				pNext;
1031					VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,						// VkAccessFlags			outputMask;
1032					VK_ACCESS_SHADER_READ_BIT,									// VkAccessFlags			inputMask;
1033					VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,					// VkImageLayout			oldLayout;
1034					VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,					// VkImageLayout			newLayout;
1035					VK_QUEUE_FAMILY_IGNORED,									// deUint32					srcQueueFamilyIndex;
1036					VK_QUEUE_FAMILY_IGNORED,									// deUint32					destQueueFamilyIndex;
1037					*colorImage,												// VkImage					image;
1038					makeColorSubresourceRange(0, caseDef.numLayers),			// VkImageSubresourceRange	subresourceRange;
1039				},
1040			};
1041
1042			vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0u,
1043				0u, DE_NULL, 0u, DE_NULL, DE_LENGTH_OF_ARRAY(barriers), barriers);
1044		}
1045
1046		const VkClearValue clearValue = makeClearValueColorU32(0u, 0u, 0u, 0u);
1047
1048		const VkRenderPassBeginInfo renderPassBeginInfo = {
1049			VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,							// VkStructureType         sType;
1050			DE_NULL,															// const void*             pNext;
1051			*renderPass,														// VkRenderPass            renderPass;
1052			*framebuffer,														// VkFramebuffer           framebuffer;
1053			renderArea,															// VkRect2D                renderArea;
1054			1u,																	// uint32_t                clearValueCount;
1055			&clearValue,														// const VkClearValue*     pClearValues;
1056		};
1057		vk.cmdBeginRenderPass(*cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
1058
1059		vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, **pipelines.back());
1060		vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u, &descriptorSet.get(), 0u, DE_NULL);
1061		{
1062			const VkDeviceSize vertexBufferOffset = 0ull;
1063			vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
1064		}
1065
1066		vk.cmdDraw(*cmdBuffer, static_cast<deUint32>(vertices.size()), 1u, 0u, 0u);
1067		vk.cmdEndRenderPass(*cmdBuffer);
1068
1069		// Prepare checksum image for copy
1070		{
1071			const VkImageMemoryBarrier barriers[] =
1072			{
1073				{
1074					VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,						// VkStructureType			sType;
1075					DE_NULL,													// const void*				pNext;
1076					VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,						// VkAccessFlags			outputMask;
1077					VK_ACCESS_TRANSFER_READ_BIT,								// VkAccessFlags			inputMask;
1078					VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,					// VkImageLayout			oldLayout;
1079					VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,						// VkImageLayout			newLayout;
1080					VK_QUEUE_FAMILY_IGNORED,									// deUint32					srcQueueFamilyIndex;
1081					VK_QUEUE_FAMILY_IGNORED,									// deUint32					destQueueFamilyIndex;
1082					*checksumImage,												// VkImage					image;
1083					makeColorSubresourceRange(0, 1),							// VkImageSubresourceRange	subresourceRange;
1084				},
1085			};
1086
1087			vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u,
1088				0u, DE_NULL, 0u, DE_NULL, DE_LENGTH_OF_ARRAY(barriers), barriers);
1089		}
1090		// Checksum image -> host buffer
1091		{
1092			const VkBufferImageCopy region =
1093			{
1094				0ull,																		// VkDeviceSize                bufferOffset;
1095				0u,																			// uint32_t                    bufferRowLength;
1096				0u,																			// uint32_t                    bufferImageHeight;
1097				makeColorSubresourceLayers(0, 1),											// VkImageSubresourceLayers    imageSubresource;
1098				makeOffset3D(0, 0, 0),														// VkOffset3D                  imageOffset;
1099				makeExtent3D(caseDef.renderSize.x(), caseDef.renderSize.y(), 1u),			// VkExtent3D                  imageExtent;
1100			};
1101
1102			vk.cmdCopyImageToBuffer(*cmdBuffer, *checksumImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *checksumBuffer, 1u, &region);
1103		}
1104		// Buffer write barrier
1105		{
1106			const VkBufferMemoryBarrier barriers[] =
1107			{
1108				{
1109					VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,		// VkStructureType    sType;
1110					DE_NULL,										// const void*        pNext;
1111					VK_ACCESS_TRANSFER_WRITE_BIT,					// VkAccessFlags      srcAccessMask;
1112					VK_ACCESS_HOST_READ_BIT,						// VkAccessFlags      dstAccessMask;
1113					VK_QUEUE_FAMILY_IGNORED,						// uint32_t           srcQueueFamilyIndex;
1114					VK_QUEUE_FAMILY_IGNORED,						// uint32_t           dstQueueFamilyIndex;
1115					*checksumBuffer,								// VkBuffer           buffer;
1116					0ull,											// VkDeviceSize       offset;
1117					checksumBufferSize,								// VkDeviceSize       size;
1118				},
1119			};
1120
1121			vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u,
1122				0u, DE_NULL, DE_LENGTH_OF_ARRAY(barriers), barriers, DE_NULL, 0u);
1123		}
1124
1125		VK_CHECK(vk.endCommandBuffer(*cmdBuffer));
1126		submitCommandsAndWait(vk, device, queue, *cmdBuffer);
1127
1128		// Verify result
1129
1130		{
1131			invalidateMappedMemoryRange(vk, device, checksumBufferAlloc->getMemory(), 0ull, checksumBufferSize);
1132
1133			const tcu::ConstPixelBufferAccess access(mapVkFormat(checksumFormat), caseDef.renderSize.x(), caseDef.renderSize.y(), 1, checksumBufferAlloc->getHostPtr());
1134			const int numExpectedChecksum = getNumSamples(caseDef.numSamples) * caseDef.numLayers;
1135
1136			for (int y = 0; y < caseDef.renderSize.y(); ++y)
1137			for (int x = 0; x < caseDef.renderSize.x(); ++x)
1138			{
1139				if (access.getPixelInt(x, y).x() != numExpectedChecksum)
1140					return tcu::TestStatus::fail("Some samples have incorrect color");
1141			}
1142		}
1143	}
1144
1145	return tcu::TestStatus::pass("OK");
1146}
1147
1148} // SampledImage ns
1149
1150namespace StorageImage
1151{
1152
1153void initPrograms (SourceCollections& programCollection, const CaseDef caseDef)
1154{
1155	// Vertex & fragment
1156
1157	addSimpleVertexAndFragmentPrograms(programCollection, caseDef);
1158
1159	// Compute
1160	{
1161		const std::string	imageTypeStr		= getShaderMultisampledImageType(mapVkFormat(caseDef.colorFormat), caseDef.numLayers);
1162		const std::string	formatQualifierStr	= getShaderImageFormatQualifier(mapVkFormat(caseDef.colorFormat));
1163		const std::string	signednessPrefix	= isUintFormat(caseDef.colorFormat) ? "u" : isIntFormat(caseDef.colorFormat) ? "i" : "";
1164		const std::string	gvec4Expr			= signednessPrefix + "vec4";
1165		const std::string	texelCoordStr		= (caseDef.numLayers == 1 ? "ivec2(gx, gy)" : "ivec3(gx, gy, gz)");
1166
1167		std::ostringstream src;
1168		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
1169			<< "layout(local_size_x = 1) in;\n"
1170			<< "layout(set = 0, binding = 0, " << formatQualifierStr << ") uniform " << imageTypeStr << " u_msImage;\n"
1171			<< "\n"
1172			<< "void main(void)\n"
1173			<< "{\n"
1174			<< "    int gx = int(gl_GlobalInvocationID.x);\n"
1175			<< "    int gy = int(gl_GlobalInvocationID.y);\n"
1176			<< "    int gz = int(gl_GlobalInvocationID.z);\n"
1177			<< "\n"
1178			<< "    " << gvec4Expr << " prevColor = imageLoad(u_msImage, " << texelCoordStr << ", 0);\n"
1179			<< "    for (int sampleNdx = 1; sampleNdx < " << caseDef.numSamples << "; ++sampleNdx) {\n"
1180			<< "        " << gvec4Expr << " color = imageLoad(u_msImage, " << texelCoordStr << ", sampleNdx);\n"
1181			<< "        imageStore(u_msImage, " << texelCoordStr <<", sampleNdx, prevColor);\n"
1182			<< "        prevColor = color;\n"
1183			<< "    }\n"
1184			<< "    imageStore(u_msImage, " << texelCoordStr <<", 0, prevColor);\n"
1185			<< "}\n";
1186
1187		programCollection.glslSources.add("comp") << glu::ComputeSource(src.str());
1188	}
1189}
1190
1191//! Render a MS image, resolve it, and copy result to resolveBuffer.
1192void renderAndResolve (Context& context, const CaseDef& caseDef, const VkBuffer resolveBuffer, const bool useComputePass)
1193{
1194	const DeviceInterface&		vk					= context.getDeviceInterface();
1195	const VkDevice				device				= context.getDevice();
1196	const VkQueue				queue				= context.getUniversalQueue();
1197	const deUint32				queueFamilyIndex	= context.getUniversalQueueFamilyIndex();
1198	Allocator&					allocator			= context.getDefaultAllocator();
1199
1200	// Multisampled color image
1201	const Unique<VkImage>			colorImage			(makeImage(vk, device, caseDef.colorFormat, caseDef.renderSize, caseDef.numLayers, caseDef.numSamples,
1202																   VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT));
1203	const UniquePtr<Allocation>		colorImageAlloc		(bindImage(vk, device, allocator, *colorImage, MemoryRequirement::Any));
1204
1205	const Unique<VkImage>			resolveImage		(makeImage(vk, device, caseDef.colorFormat, caseDef.renderSize, caseDef.numLayers, VK_SAMPLE_COUNT_1_BIT,
1206																   VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT));
1207	const UniquePtr<Allocation>		resolveImageAlloc	(bindImage(vk, device, allocator, *resolveImage, MemoryRequirement::Any));
1208
1209	const Unique<VkCommandPool>		cmdPool				(makeCommandPool  (vk, device, queueFamilyIndex));
1210	const Unique<VkCommandBuffer>	cmdBuffer			(makeCommandBuffer(vk, device, *cmdPool));
1211
1212	// Working image barrier, we change it based on which rendering stages were executed so far.
1213	VkImageMemoryBarrier colorImageBarrier =
1214	{
1215		VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,						// VkStructureType			sType;
1216		DE_NULL,													// const void*				pNext;
1217		(VkAccessFlags)0,											// VkAccessFlags			outputMask;
1218		(VkAccessFlags)0,											// VkAccessFlags			inputMask;
1219		VK_IMAGE_LAYOUT_UNDEFINED,									// VkImageLayout			oldLayout;
1220		VK_IMAGE_LAYOUT_UNDEFINED,									// VkImageLayout			newLayout;
1221		VK_QUEUE_FAMILY_IGNORED,									// deUint32					srcQueueFamilyIndex;
1222		VK_QUEUE_FAMILY_IGNORED,									// deUint32					destQueueFamilyIndex;
1223		*colorImage,												// VkImage					image;
1224		makeColorSubresourceRange(0, caseDef.numLayers),			// VkImageSubresourceRange	subresourceRange;
1225	};
1226
1227	// Pass 1: Render an image
1228	{
1229		renderMultisampledImage(context, caseDef, *colorImage);
1230
1231		colorImageBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
1232		colorImageBarrier.oldLayout		= VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
1233	}
1234
1235	// Pass 2: Compute shader
1236	if (useComputePass)
1237	{
1238		// Descriptors
1239
1240		Unique<VkDescriptorSetLayout> descriptorSetLayout(DescriptorSetLayoutBuilder()
1241			.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT)
1242			.build(vk, device));
1243
1244		Unique<VkDescriptorPool> descriptorPool(DescriptorPoolBuilder()
1245			.addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1u)
1246			.build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
1247
1248		const Unique<VkImageView>		colorImageView		(makeImageView(vk, device, *colorImage,
1249																			(caseDef.numLayers == 1 ? VK_IMAGE_VIEW_TYPE_2D : VK_IMAGE_VIEW_TYPE_2D_ARRAY),
1250																			caseDef.colorFormat, makeColorSubresourceRange(0, caseDef.numLayers)));
1251		const Unique<VkDescriptorSet>	descriptorSet		(makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
1252		const VkDescriptorImageInfo		descriptorImageInfo	= makeDescriptorImageInfo(DE_NULL, *colorImageView, VK_IMAGE_LAYOUT_GENERAL);
1253
1254		DescriptorSetUpdateBuilder()
1255			.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &descriptorImageInfo)
1256			.update(vk, device);
1257
1258		const Unique<VkPipelineLayout>	pipelineLayout	(makePipelineLayout	(vk, device, *descriptorSetLayout));
1259		const Unique<VkShaderModule>	shaderModule	(createShaderModule	(vk, device, context.getBinaryCollection().get("comp"), 0));
1260		const Unique<VkPipeline>		pipeline		(makeComputePipeline(vk, device, *pipelineLayout, *shaderModule, DE_NULL));
1261
1262		beginCommandBuffer(vk, *cmdBuffer);
1263
1264		// Image layout for load/stores
1265		{
1266			colorImageBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
1267			colorImageBarrier.newLayout		= VK_IMAGE_LAYOUT_GENERAL;
1268
1269			vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0u,
1270				0u, DE_NULL, 0u, DE_NULL, 1u, &colorImageBarrier);
1271
1272			colorImageBarrier.srcAccessMask = colorImageBarrier.dstAccessMask;
1273			colorImageBarrier.oldLayout		= colorImageBarrier.newLayout;
1274		}
1275		// Dispatch
1276		{
1277			vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
1278			vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &descriptorSet.get(), 0u, DE_NULL);
1279			vk.cmdDispatch(*cmdBuffer, caseDef.renderSize.x(), caseDef.renderSize.y(), caseDef.numLayers);
1280		}
1281
1282		VK_CHECK(vk.endCommandBuffer(*cmdBuffer));
1283		submitCommandsAndWait(vk, device, queue, *cmdBuffer);
1284	}
1285
1286	// Resolve and verify the image
1287	{
1288		beginCommandBuffer(vk, *cmdBuffer);
1289
1290		// Prepare for resolve
1291		{
1292			colorImageBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
1293			colorImageBarrier.newLayout		= VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
1294
1295			const VkImageMemoryBarrier barriers[] =
1296			{
1297				colorImageBarrier,
1298				{
1299					VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,						// VkStructureType			sType;
1300					DE_NULL,													// const void*				pNext;
1301					(VkAccessFlags)0,											// VkAccessFlags			outputMask;
1302					VK_ACCESS_TRANSFER_WRITE_BIT,								// VkAccessFlags			inputMask;
1303					VK_IMAGE_LAYOUT_UNDEFINED,									// VkImageLayout			oldLayout;
1304					VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,						// VkImageLayout			newLayout;
1305					VK_QUEUE_FAMILY_IGNORED,									// deUint32					srcQueueFamilyIndex;
1306					VK_QUEUE_FAMILY_IGNORED,									// deUint32					destQueueFamilyIndex;
1307					*resolveImage,												// VkImage					image;
1308					makeColorSubresourceRange(0, caseDef.numLayers),			// VkImageSubresourceRange	subresourceRange;
1309				},
1310			};
1311
1312			vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u,
1313				0u, DE_NULL, 0u, DE_NULL, DE_LENGTH_OF_ARRAY(barriers), barriers);
1314
1315			colorImageBarrier.srcAccessMask = colorImageBarrier.dstAccessMask;
1316			colorImageBarrier.oldLayout		= colorImageBarrier.newLayout;
1317		}
1318		// Resolve the image
1319		{
1320			const VkImageResolve resolveRegion =
1321			{
1322				makeColorSubresourceLayers(0, caseDef.numLayers),					// VkImageSubresourceLayers    srcSubresource;
1323				makeOffset3D(0, 0, 0),												// VkOffset3D                  srcOffset;
1324				makeColorSubresourceLayers(0, caseDef.numLayers),					// VkImageSubresourceLayers    dstSubresource;
1325				makeOffset3D(0, 0, 0),												// VkOffset3D                  dstOffset;
1326				makeExtent3D(caseDef.renderSize.x(), caseDef.renderSize.y(), 1u),	// VkExtent3D                  extent;
1327			};
1328
1329			vk.cmdResolveImage(*cmdBuffer, *colorImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *resolveImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1u, &resolveRegion);
1330		}
1331		// Prepare resolve image for copy
1332		{
1333			const VkImageMemoryBarrier barriers[] =
1334			{
1335				{
1336					VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,						// VkStructureType			sType;
1337					DE_NULL,													// const void*				pNext;
1338					VK_ACCESS_TRANSFER_WRITE_BIT,								// VkAccessFlags			outputMask;
1339					VK_ACCESS_TRANSFER_READ_BIT,								// VkAccessFlags			inputMask;
1340					VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,						// VkImageLayout			oldLayout;
1341					VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,						// VkImageLayout			newLayout;
1342					VK_QUEUE_FAMILY_IGNORED,									// deUint32					srcQueueFamilyIndex;
1343					VK_QUEUE_FAMILY_IGNORED,									// deUint32					destQueueFamilyIndex;
1344					*resolveImage,												// VkImage					image;
1345					makeColorSubresourceRange(0, caseDef.numLayers),			// VkImageSubresourceRange	subresourceRange;
1346				},
1347			};
1348
1349			vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u,
1350				0u, DE_NULL, 0u, DE_NULL, DE_LENGTH_OF_ARRAY(barriers), barriers);
1351		}
1352		// Copy resolved image to host-readable buffer
1353		{
1354			const VkBufferImageCopy copyRegion =
1355			{
1356				0ull,																// VkDeviceSize                bufferOffset;
1357				0u,																	// uint32_t                    bufferRowLength;
1358				0u,																	// uint32_t                    bufferImageHeight;
1359				makeColorSubresourceLayers(0, caseDef.numLayers),					// VkImageSubresourceLayers    imageSubresource;
1360				makeOffset3D(0, 0, 0),												// VkOffset3D                  imageOffset;
1361				makeExtent3D(caseDef.renderSize.x(), caseDef.renderSize.y(), 1u),	// VkExtent3D                  imageExtent;
1362			};
1363
1364			vk.cmdCopyImageToBuffer(*cmdBuffer, *resolveImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, resolveBuffer, 1u, &copyRegion);
1365		}
1366
1367		VK_CHECK(vk.endCommandBuffer(*cmdBuffer));
1368		submitCommandsAndWait(vk, device, queue, *cmdBuffer);
1369	}
1370}
1371
1372//! Exact image compare, but allow for some error when color format is integer.
1373bool compareImages (tcu::TestLog& log, const CaseDef& caseDef, const tcu::ConstPixelBufferAccess layeredReferenceImage, const tcu::ConstPixelBufferAccess layeredActualImage)
1374{
1375	DE_ASSERT(caseDef.numSamples > 1);
1376
1377	const Vec4	goodColor			= Vec4(0.0f, 1.0f, 0.0f, 1.0f);
1378	const Vec4	badColor			= Vec4(1.0f, 0.0f, 0.0f, 1.0f);
1379	const bool	isAnyIntFormat		= isIntFormat(caseDef.colorFormat) || isUintFormat(caseDef.colorFormat);
1380
1381	// There should be no mismatched pixels for non-integer formats. Otherwise we may get a wrong color in a location where sample coverage isn't exactly 0 or 1.
1382	const int	badPixelTolerance	= (isAnyIntFormat ? 2 * caseDef.renderSize.x() : 0);
1383	int			goodLayers			= 0;
1384
1385	for (int layerNdx = 0; layerNdx < caseDef.numLayers; ++layerNdx)
1386	{
1387		const tcu::ConstPixelBufferAccess	referenceImage	= tcu::getSubregion(layeredReferenceImage, 0, 0, layerNdx, caseDef.renderSize.x(), caseDef.renderSize.y(), 1);
1388		const tcu::ConstPixelBufferAccess	actualImage		= tcu::getSubregion(layeredActualImage, 0, 0, layerNdx, caseDef.renderSize.x(), caseDef.renderSize.y(), 1);
1389		const std::string					imageName		= "color layer " + de::toString(layerNdx);
1390
1391		tcu::TextureLevel		errorMaskStorage	(tcu::TextureFormat(tcu::TextureFormat::RGB, tcu::TextureFormat::UNORM_INT8), caseDef.renderSize.x(), caseDef.renderSize.y());
1392		tcu::PixelBufferAccess	errorMask			= errorMaskStorage.getAccess();
1393		int						numBadPixels		= 0;
1394
1395		for (int y = 0; y < caseDef.renderSize.y(); ++y)
1396		for (int x = 0; x < caseDef.renderSize.x(); ++x)
1397		{
1398			if (isAnyIntFormat && (referenceImage.getPixelInt(x, y) == actualImage.getPixelInt(x, y)))
1399				errorMask.setPixel(goodColor, x, y);
1400			else if (referenceImage.getPixel(x, y) == actualImage.getPixel(x, y))
1401				errorMask.setPixel(goodColor, x, y);
1402			else
1403			{
1404				++numBadPixels;
1405				errorMask.setPixel(badColor, x, y);
1406			}
1407		}
1408
1409		if (numBadPixels <= badPixelTolerance)
1410		{
1411			++goodLayers;
1412
1413			log << tcu::TestLog::ImageSet(imageName, imageName)
1414				<< tcu::TestLog::Image("Result",	"Result",		actualImage)
1415				<< tcu::TestLog::EndImageSet;
1416		}
1417		else
1418		{
1419			log << tcu::TestLog::ImageSet(imageName, imageName)
1420				<< tcu::TestLog::Image("Result",	"Result",		actualImage)
1421				<< tcu::TestLog::Image("Reference",	"Reference",	referenceImage)
1422				<< tcu::TestLog::Image("ErrorMask",	"Error mask",	errorMask)
1423				<< tcu::TestLog::EndImageSet;
1424		}
1425	}
1426
1427	if (goodLayers == caseDef.numLayers)
1428	{
1429		log << tcu::TestLog::Message << "All rendered images are correct." << tcu::TestLog::EndMessage;
1430		return true;
1431	}
1432	else
1433	{
1434		log << tcu::TestLog::Message << "FAILED: Some rendered images were incorrect." << tcu::TestLog::EndMessage;
1435		return false;
1436	}
1437}
1438
1439tcu::TestStatus test (Context& context, const CaseDef caseDef)
1440{
1441	const DeviceInterface&		vk					= context.getDeviceInterface();
1442	const InstanceInterface&	vki					= context.getInstanceInterface();
1443	const VkDevice				device				= context.getDevice();
1444	const VkPhysicalDevice		physDevice			= context.getPhysicalDevice();
1445	Allocator&					allocator			= context.getDefaultAllocator();
1446
1447	checkImageFormatRequirements(vki, physDevice, caseDef.numSamples, caseDef.colorFormat, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_STORAGE_BIT);
1448
1449	{
1450		tcu::TestLog& log = context.getTestContext().getLog();
1451		log << tcu::LogSection("Description", "")
1452			<< tcu::TestLog::Message << "Rendering to a multisampled image. Image will be processed with a compute shader using OpImageRead and OpImageWrite." << tcu::TestLog::EndMessage
1453			<< tcu::TestLog::Message << "Expecting the processed image to be roughly the same as the input image (deviation may occur for integer formats)." << tcu::TestLog::EndMessage
1454			<< tcu::TestLog::EndSection;
1455	}
1456
1457	// Host-readable buffer
1458	const VkDeviceSize				resolveBufferSize			= caseDef.renderSize.x() * caseDef.renderSize.y() * caseDef.numLayers * tcu::getPixelSize(mapVkFormat(caseDef.colorFormat));
1459	const Unique<VkBuffer>			resolveImageOneBuffer		(makeBuffer(vk, device, resolveBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT));
1460	const UniquePtr<Allocation>		resolveImageOneBufferAlloc	(bindBuffer(vk, device, allocator, *resolveImageOneBuffer, MemoryRequirement::HostVisible));
1461	const Unique<VkBuffer>			resolveImageTwoBuffer		(makeBuffer(vk, device, resolveBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT));
1462	const UniquePtr<Allocation>		resolveImageTwoBufferAlloc	(bindBuffer(vk, device, allocator, *resolveImageTwoBuffer, MemoryRequirement::HostVisible));
1463
1464	zeroBuffer(vk, device, *resolveImageOneBufferAlloc, resolveBufferSize);
1465	zeroBuffer(vk, device, *resolveImageTwoBufferAlloc, resolveBufferSize);
1466
1467	// Render: repeat the same rendering twice to avoid non-essential API calls and layout transitions (e.g. copy).
1468	{
1469		renderAndResolve(context, caseDef, *resolveImageOneBuffer, false);	// Pass 1: render a basic multisampled image
1470		renderAndResolve(context, caseDef, *resolveImageTwoBuffer, true);	// Pass 2: the same but altered with a compute shader
1471	}
1472
1473	// Verify
1474	{
1475		invalidateMappedMemoryRange(vk, device, resolveImageOneBufferAlloc->getMemory(), resolveImageOneBufferAlloc->getOffset(), resolveBufferSize);
1476		invalidateMappedMemoryRange(vk, device, resolveImageTwoBufferAlloc->getMemory(), resolveImageTwoBufferAlloc->getOffset(), resolveBufferSize);
1477
1478		const tcu::PixelBufferAccess		layeredImageOne	(mapVkFormat(caseDef.colorFormat), caseDef.renderSize.x(), caseDef.renderSize.y(), caseDef.numLayers, resolveImageOneBufferAlloc->getHostPtr());
1479		const tcu::ConstPixelBufferAccess	layeredImageTwo	(mapVkFormat(caseDef.colorFormat), caseDef.renderSize.x(), caseDef.renderSize.y(), caseDef.numLayers, resolveImageTwoBufferAlloc->getHostPtr());
1480
1481		// Check all layers
1482		if (!compareImages(context.getTestContext().getLog(), caseDef, layeredImageOne, layeredImageTwo))
1483			return tcu::TestStatus::fail("Rendered images are not correct");
1484	}
1485
1486	return tcu::TestStatus::pass("OK");
1487}
1488
1489} // StorageImage ns
1490
1491std::string getSizeLayerString (const IVec2& size, const int numLayers)
1492{
1493	std::ostringstream str;
1494	str << size.x() << "x" << size.y() << "_" << numLayers;
1495	return str.str();
1496}
1497
1498std::string getFormatString (const VkFormat format)
1499{
1500	std::string name(getFormatName(format));
1501	return de::toLower(name.substr(10));
1502}
1503
1504void addTestCasesWithFunctions (tcu::TestCaseGroup*						group,
1505								FunctionPrograms1<CaseDef>::Function	initPrograms,
1506								FunctionInstance1<CaseDef>::Function	testFunc)
1507{
1508	const IVec2 size[] =
1509	{
1510		IVec2(64, 64),
1511		IVec2(79, 31),
1512	};
1513	const int numLayers[] =
1514	{
1515		1, 4
1516	};
1517	const VkSampleCountFlagBits samples[] =
1518	{
1519		VK_SAMPLE_COUNT_2_BIT,
1520		VK_SAMPLE_COUNT_4_BIT,
1521		VK_SAMPLE_COUNT_8_BIT,
1522		VK_SAMPLE_COUNT_16_BIT,
1523		VK_SAMPLE_COUNT_32_BIT,
1524		VK_SAMPLE_COUNT_64_BIT,
1525	};
1526	const VkFormat format[] =
1527	{
1528		VK_FORMAT_R8G8B8A8_UNORM,
1529		VK_FORMAT_R32_UINT,
1530		VK_FORMAT_R16G16_SINT,
1531		VK_FORMAT_R32G32B32A32_SFLOAT,
1532	};
1533
1534	for (int sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(size); ++sizeNdx)
1535	for (int layerNdx = 0; layerNdx < DE_LENGTH_OF_ARRAY(numLayers); ++layerNdx)
1536	{
1537		MovePtr<tcu::TestCaseGroup>	sizeLayerGroup(new tcu::TestCaseGroup(group->getTestContext(), getSizeLayerString(size[sizeNdx], numLayers[layerNdx]).c_str(), ""));
1538		for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(format); ++formatNdx)
1539		{
1540			MovePtr<tcu::TestCaseGroup>	formatGroup(new tcu::TestCaseGroup(group->getTestContext(), getFormatString(format[formatNdx]).c_str(), ""));
1541			for (int samplesNdx = 0; samplesNdx < DE_LENGTH_OF_ARRAY(samples); ++samplesNdx)
1542			{
1543				std::ostringstream caseName;
1544				caseName << "samples_" << getNumSamples(samples[samplesNdx]);
1545
1546				const CaseDef caseDef =
1547				{
1548					size[sizeNdx],			// IVec2					renderSize;
1549					numLayers[layerNdx],	// int						numLayers;
1550					format[formatNdx],		// VkFormat					colorFormat;
1551					samples[samplesNdx],	// VkSampleCountFlagBits	numSamples;
1552				};
1553
1554				addFunctionCaseWithPrograms(formatGroup.get(), caseName.str(), "", initPrograms, testFunc, caseDef);
1555			}
1556			sizeLayerGroup->addChild(formatGroup.release());
1557		}
1558		group->addChild(sizeLayerGroup.release());
1559	}
1560}
1561
1562void createSampledImageTestsInGroup (tcu::TestCaseGroup* group)
1563{
1564	addTestCasesWithFunctions(group, SampledImage::initPrograms, SampledImage::test);
1565}
1566
1567void createStorageImageTestsInGroup (tcu::TestCaseGroup* group)
1568{
1569	addTestCasesWithFunctions(group, StorageImage::initPrograms, StorageImage::test);
1570}
1571
1572} // anonymous ns
1573
1574//! Render to a multisampled image and sample from it in a fragment shader.
1575tcu::TestCaseGroup* createMultisampleSampledImageTests (tcu::TestContext& testCtx)
1576{
1577	return createTestGroup(testCtx, "sampled_image", "Multisampled image direct sample access", createSampledImageTestsInGroup);
1578}
1579
1580//! Render to a multisampled image and access it with load/stores in a compute shader.
1581tcu::TestCaseGroup* createMultisampleStorageImageTests (tcu::TestContext& testCtx)
1582{
1583	return createTestGroup(testCtx, "storage_image", "Multisampled image draw and read/write in compute shader", createStorageImageTestsInGroup);
1584}
1585
1586} // pipeline
1587} // vkt
1588