1/*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2019 Advanced Micro Devices, Inc.
6 * Copyright (c) 2019 The Khronos Group Inc.
7 * Copyright (c) 2023 LunarG, Inc.
8 * Copyright (c) 2023 Nintendo
9 *
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
13 *
14 *      http://www.apache.org/licenses/LICENSE-2.0
15 *
16 * Unless required by applicable law or agreed to in writing, software
17 * distributed under the License is distributed on an "AS IS" BASIS,
18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 * See the License for the specific language governing permissions and
20 * limitations under the License.
21 *
22 *//*!
23 * \file
24 * \brief Tests for VK_AMD_shader_fragment_mask
25 *//*--------------------------------------------------------------------*/
26
27#include "vktPipelineMultisampleShaderFragmentMaskTests.hpp"
28#include "vktPipelineMakeUtil.hpp"
29#include "vktTestCase.hpp"
30#include "vktTestCaseUtil.hpp"
31#include "vktTestGroupUtil.hpp"
32#include "vktCustomInstancesDevices.hpp"
33#include "tcuCommandLine.hpp"
34
35#include "vkCmdUtil.hpp"
36#include "vkObjUtil.hpp"
37#include "vkPlatform.hpp"
38#include "vkMemUtil.hpp"
39#include "vkQueryUtil.hpp"
40#include "vkTypeUtil.hpp"
41#include "vkRefUtil.hpp"
42#include "vkBuilderUtil.hpp"
43#include "vkPrograms.hpp"
44#include "vkImageUtil.hpp"
45
46#include "deUniquePtr.hpp"
47#include "deSharedPtr.hpp"
48#include "deRandom.hpp"
49
50#include "tcuVector.hpp"
51#include "tcuTestLog.hpp"
52#include "tcuImageCompare.hpp"
53#include "tcuTestLog.hpp"
54#include "tcuTextureUtil.hpp"
55
56#include <string>
57#include <vector>
58#include <set>
59
60namespace vkt
61{
62namespace pipeline
63{
64namespace
65{
66using namespace vk;
67using de::MovePtr;
68using de::SharedPtr;
69using tcu::UVec2;
70using tcu::UVec4;
71using tcu::Vec2;
72using tcu::Vec4;
73
74typedef SharedPtr<Unique<VkImageView> >		ImageViewSp;
75
76struct PositionColor
77{
78	tcu::Vec4	        position;
79	VkClearColorValue	color;
80
81	PositionColor (const tcu::Vec4& pos, const tcu::UVec4& col) : position(pos)
82    {
83        deMemcpy(color.uint32, col.getPtr(), sizeof(color.uint32));
84    }
85
86	PositionColor (const tcu::Vec4& pos, const tcu::Vec4&  col) : position(pos)
87    {
88        deMemcpy(color.float32, col.getPtr(), sizeof(color.float32));
89    }
90
91	PositionColor (const PositionColor& rhs)
92		: position	(rhs.position)
93        , color     (rhs.color)
94	{
95	}
96};
97
98//! Make a (unused) sampler.
99Move<VkSampler> makeSampler (const DeviceInterface& vk, const VkDevice device)
100{
101	const VkSamplerCreateInfo samplerParams =
102	{
103		VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,			// VkStructureType         sType;
104		DE_NULL,										// const void*             pNext;
105		(VkSamplerCreateFlags)0,						// VkSamplerCreateFlags    flags;
106		VK_FILTER_NEAREST,								// VkFilter                magFilter;
107		VK_FILTER_NEAREST,								// VkFilter                minFilter;
108		VK_SAMPLER_MIPMAP_MODE_NEAREST,					// VkSamplerMipmapMode     mipmapMode;
109		VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,			// VkSamplerAddressMode    addressModeU;
110		VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,			// VkSamplerAddressMode    addressModeV;
111		VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,			// VkSamplerAddressMode    addressModeW;
112		0.0f,											// float                   mipLodBias;
113		VK_FALSE,										// VkBool32                anisotropyEnable;
114		1.0f,											// float                   maxAnisotropy;
115		VK_FALSE,										// VkBool32                compareEnable;
116		VK_COMPARE_OP_ALWAYS,							// VkCompareOp             compareOp;
117		0.0f,											// float                   minLod;
118		0.0f,											// float                   maxLod;
119		VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK,		// VkBorderColor           borderColor;
120		VK_FALSE,										// VkBool32                unnormalizedCoordinates;
121	};
122	return createSampler(vk, device, &samplerParams);
123}
124
125Move<VkImage> makeImage (const DeviceInterface&			vk,
126						 const VkDevice					device,
127						 const VkFormat					format,
128						 const UVec2&					size,
129						 const deUint32					layers,
130						 const VkSampleCountFlagBits	samples,
131						 const VkImageUsageFlags		usage)
132{
133	const VkImageCreateInfo imageParams =
134	{
135		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,			// VkStructureType			sType;
136		DE_NULL,										// const void*				pNext;
137		(VkImageCreateFlags)0,							// VkImageCreateFlags		flags;
138		VK_IMAGE_TYPE_2D,								// VkImageType				imageType;
139		format,											// VkFormat					format;
140		makeExtent3D(size.x(), size.y(), 1),			// VkExtent3D				extent;
141		1u,												// deUint32					mipLevels;
142		layers,											// deUint32					arrayLayers;
143		samples,										// VkSampleCountFlagBits	samples;
144		VK_IMAGE_TILING_OPTIMAL,						// VkImageTiling			tiling;
145		usage,											// VkImageUsageFlags		usage;
146		VK_SHARING_MODE_EXCLUSIVE,						// VkSharingMode			sharingMode;
147		0u,												// deUint32					queueFamilyIndexCount;
148		DE_NULL,										// const deUint32*			pQueueFamilyIndices;
149		VK_IMAGE_LAYOUT_UNDEFINED,						// VkImageLayout			initialLayout;
150	};
151	return createImage(vk, device, &imageParams);
152}
153
154std::vector<PositionColor> genShapes (const VkFormat colorFormat)
155{
156	std::vector<PositionColor> vertices;
157
158	if (colorFormat == VK_FORMAT_R8G8B8A8_UNORM)
159	{
160		vertices.push_back(PositionColor(Vec4( 0.0f,  -0.75f, 0.0f, 1.0f), Vec4(0.5f, 0.5f, 0.5f, 1.0f)));
161		vertices.push_back(PositionColor(Vec4(-0.75f,  0.75f, 0.0f, 1.0f), Vec4(1.0f, 0.5f, 0.5f, 1.0f)));
162		vertices.push_back(PositionColor(Vec4( 0.75f,  0.65f, 0.0f, 1.0f), Vec4(0.0f, 0.5f, 1.0f, 1.0f)));
163	}
164	else
165	{
166		vertices.push_back(PositionColor(Vec4( 0.0f,  -0.75f, 0.0f, 1.0f), UVec4(0xabcdu, 0u, 0u, 0u)));
167		vertices.push_back(PositionColor(Vec4(-0.75f,  0.75f, 0.0f, 1.0f), UVec4(0xbcdeu, 0u, 0u, 0u)));
168		vertices.push_back(PositionColor(Vec4( 0.75f,  0.65f, 0.0f, 1.0f), UVec4(0xcdefu, 0u, 0u, 0u)));
169	}
170
171	return vertices;
172}
173
174//! Map color image format to a convenient format used in vertex attributes
175VkFormat getVertexInputColorFormat (const VkFormat colorImageFormat)
176{
177	switch (tcu::getTextureChannelClass(mapVkFormat(colorImageFormat).type))
178	{
179		case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
180		case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
181		case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
182			return VK_FORMAT_R32G32B32A32_SFLOAT;
183
184		case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
185			return VK_FORMAT_R32G32B32A32_SINT;
186
187		case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
188			return VK_FORMAT_R32G32B32A32_UINT;
189
190		default:
191			DE_ASSERT(0);
192			return VK_FORMAT_UNDEFINED;
193	}
194}
195
196enum SampleSource
197{
198	SAMPLE_SOURCE_IMAGE,			//!< texel fetch from an image
199	SAMPLE_SOURCE_SUBPASS_INPUT,	//!< texel fetch from an input attachment
200};
201
202// Class to wrap a singleton device for use in fragment mask tests,
203// which require the VK_AMD_shader_fragment extension.
204class SingletonDevice
205{
206	SingletonDevice(Context& context)
207		: m_context(context)
208		, m_logicalDevice()
209	{
210		const float	queuePriority					= 1.0;
211		const VkDeviceQueueCreateInfo	queues[]	=
212		{
213			{
214				VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
215				DE_NULL,
216				(VkDeviceQueueCreateFlags)0,
217				m_context.getUniversalQueueFamilyIndex(),
218				1u,									// queueCount
219				&queuePriority,						// pQueuePriorities
220			}
221		};
222
223		const auto&					vkp					= m_context.getPlatformInterface();
224		const auto&					vki					= m_context.getInstanceInterface();
225		const auto					instance			= m_context.getInstance();
226		const auto					physicalDevice		= m_context.getPhysicalDevice();
227		std::vector<const char*>	creationExtensions	= m_context.getDeviceCreationExtensions();
228
229		VkPhysicalDeviceFeatures2							features2						= initVulkanStructure();
230		VkPhysicalDeviceDescriptorBufferFeaturesEXT			descriptorBufferFeatures		= initVulkanStructure();
231		VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT	graphicsPipelineLibraryFeatures	= initVulkanStructure();
232		VkPhysicalDeviceDynamicRenderingFeaturesKHR			dynamicRenderingFeatures		= initVulkanStructure();
233		VkPhysicalDeviceShaderObjectFeaturesEXT				shaderObjectFeatures			= initVulkanStructure(&dynamicRenderingFeatures);
234
235		m_context.requireInstanceFunctionality("VK_KHR_get_physical_device_properties2");
236		const auto addFeatures = makeStructChainAdder(&features2);
237
238		if (m_context.isDeviceFunctionalitySupported("VK_EXT_descriptor_buffer"))
239			addFeatures(&descriptorBufferFeatures);
240
241		if (m_context.isDeviceFunctionalitySupported("VK_EXT_graphics_pipeline_library"))
242			addFeatures(&graphicsPipelineLibraryFeatures);
243
244		if (m_context.isDeviceFunctionalitySupported("VK_EXT_shader_object"))
245			addFeatures(&shaderObjectFeatures);
246
247		vki.getPhysicalDeviceFeatures2(physicalDevice, &features2);
248		descriptorBufferFeatures.descriptorBuffer	= VK_FALSE;
249		features2.features.robustBufferAccess		= VK_FALSE; // Disable robustness features.
250		creationExtensions.push_back("VK_AMD_shader_fragment_mask");
251
252		VkDeviceCreateInfo createInfo		= initVulkanStructure(&features2);
253		createInfo.flags					= 0u;
254		createInfo.queueCreateInfoCount		= de::arrayLength(queues);
255		createInfo.pQueueCreateInfos		= queues;
256		createInfo.enabledLayerCount		= 0u;
257		createInfo.ppEnabledLayerNames		= nullptr;
258		createInfo.enabledExtensionCount	= de::sizeU32(creationExtensions);
259		createInfo.ppEnabledExtensionNames	= de::dataOrNull(creationExtensions);
260		createInfo.pEnabledFeatures			= nullptr;
261
262		m_logicalDevice = createCustomDevice(
263			m_context.getTestContext().getCommandLine().isValidationEnabled(),
264			vkp,
265			instance,
266			vki,
267			physicalDevice,
268			&createInfo,
269			nullptr);
270
271		m_deviceDriver = de::MovePtr<DeviceDriver>(new DeviceDriver(vkp, instance, *m_logicalDevice, m_context.getUsedApiVersion()));
272	}
273
274public:
275	~SingletonDevice()
276	{
277	}
278
279	static VkDevice getDevice(Context& context)
280	{
281		if (!m_singletonDevice)
282			m_singletonDevice = SharedPtr<SingletonDevice>(new SingletonDevice(context));
283		DE_ASSERT(m_singletonDevice);
284		return m_singletonDevice->m_logicalDevice.get();
285	}
286
287	static VkQueue getUniversalQueue(Context& context)
288	{
289		return getDeviceQueue(getDeviceInterface(context), getDevice(context), context.getUniversalQueueFamilyIndex(), 0);
290	}
291
292	static const DeviceInterface& getDeviceInterface(Context& context)
293	{
294		if (!m_singletonDevice)
295			m_singletonDevice = SharedPtr<SingletonDevice>(new SingletonDevice(context));
296		DE_ASSERT(m_singletonDevice);
297		return *(m_singletonDevice->m_deviceDriver.get());
298	}
299
300	static void destroy()
301	{
302		m_singletonDevice.clear();
303	}
304
305private:
306	const Context&						m_context;
307	Move<vk::VkDevice>					m_logicalDevice;
308	de::MovePtr<vk::DeviceDriver>		m_deviceDriver;
309	static SharedPtr<SingletonDevice>	m_singletonDevice;
310};
311
312SharedPtr<SingletonDevice>		SingletonDevice::m_singletonDevice;
313
314//! The parameters that define a test case
315struct TestParams
316{
317	PipelineConstructionType	pipelineConstructionType;
318	UVec2						renderSize;
319	deUint32					numLayers;			//!< 1 or N for layered image
320	SampleSource				sampleSource;		//!< source of texel fetch
321	VkSampleCountFlagBits		numColorSamples;
322	VkFormat					colorFormat;		//!< Color attachment format
323
324	TestParams (void)
325		: numLayers			()
326		, sampleSource		(SAMPLE_SOURCE_IMAGE)
327		, numColorSamples	()
328		, colorFormat		()
329	{
330	}
331};
332
333void checkRequirements (Context& context, TestParams params)
334{
335	const auto&	vki				= context.getInstanceInterface();
336	const auto	physicalDevice	= context.getPhysicalDevice();
337
338	const auto& supportedExtensions = enumerateCachedDeviceExtensionProperties(vki, physicalDevice);
339	if (!isExtensionStructSupported(supportedExtensions, RequiredExtension("VK_AMD_shader_fragment_mask")))
340		TCU_THROW(NotSupportedError, "VK_AMD_shader_fragment_mask not supported");
341
342	const auto& limits = context.getDeviceProperties().limits;
343
344	if ((limits.framebufferColorSampleCounts & params.numColorSamples) == 0u)
345		TCU_THROW(NotSupportedError, "framebufferColorSampleCounts: sample count not supported");
346
347	if ((isIntFormat(params.colorFormat) || isUintFormat(params.colorFormat)))
348	{
349		if ((limits.sampledImageIntegerSampleCounts & params.numColorSamples) == 0u)
350			TCU_THROW(NotSupportedError, "sampledImageIntegerSampleCounts: sample count not supported");
351	}
352	else
353	{
354		if ((limits.sampledImageColorSampleCounts & params.numColorSamples) == 0u)
355			TCU_THROW(NotSupportedError, "sampledImageColorSampleCounts: sample count not supported");
356	}
357
358	// In the subpass input case we have to store fetch results into a buffer for subsequent verification in a compute shader.
359	const bool requireFragmentStores = (params.sampleSource == SAMPLE_SOURCE_SUBPASS_INPUT);
360
361	if (requireFragmentStores)
362	{
363		if (!context.getDeviceFeatures().fragmentStoresAndAtomics)
364			TCU_THROW(NotSupportedError, "fragmentStoresAndAtomics: feature not supported");
365	}
366
367	checkPipelineConstructionRequirements(vki, physicalDevice, params.pipelineConstructionType);
368}
369
370//! Common data used by the test
371struct WorkingData
372{
373	deUint32						numVertices;				//!< Number of vertices defined in the vertex buffer
374	Move<VkBuffer>					vertexBuffer;
375	MovePtr<Allocation>				vertexBufferAlloc;
376	Move<VkImage>					colorImage;					//!< Color image
377	MovePtr<Allocation>				colorImageAlloc;
378	Move<VkImageView>				colorImageView;				//!< Color image view spanning all layers
379	Move<VkBuffer>					colorBuffer;				//!< Buffer used to copy image data
380	MovePtr<Allocation>				colorBufferAlloc;
381	VkDeviceSize					colorBufferSize;
382	Move<VkSampler>					defaultSampler;				//!< Unused sampler, we are using texel fetches
383
384	WorkingData (void)
385		: numVertices		()
386		, colorBufferSize	()
387	{
388	}
389};
390
391void initPrograms (SourceCollections& programCollection, const TestParams params)
392{
393	std::string	colorType;					//!< color pixel type used by image functions
394	std::string	colorBufferType;			//!< packed pixel type as stored in a ssbo
395	std::string colorBufferPack;			//!< a cast or a function call when writing back color format to the ssbo
396	std::string	colorFragInQualifier;		//!< fragment shader color input qualifier
397	std::string samplerPrefix;				//!< u, i, or empty
398
399	switch (params.colorFormat)
400	{
401		case VK_FORMAT_R8G8B8A8_UNORM:
402			colorType				= "vec4";
403			colorBufferType			= "uint";
404			colorBufferPack			= "packUnorm4x8";
405			break;
406
407		case VK_FORMAT_R32_UINT:
408			colorType				= "uint";
409			colorBufferType			= "uint";
410			colorBufferPack			= colorBufferType;
411			colorFragInQualifier	= "flat";
412			samplerPrefix			= "u";
413			break;
414
415		case VK_FORMAT_R32_SINT:
416			colorType				= "int";
417			colorBufferType			= "int";
418			colorBufferPack			= colorBufferType;
419			colorFragInQualifier	= "flat";
420			samplerPrefix			= "i";
421			break;
422
423		default:
424			DE_FATAL("initPrograms not handled for this color format");
425			break;
426	}
427
428	// Vertex shader - position and color
429	{
430		std::ostringstream src;
431		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
432			<< "\n"
433			<< "layout(location = 0) in  vec4 in_position;\n"
434			<< "layout(location = 1) in  " << colorType << " in_color;\n"
435			<< "layout(location = 0) out " << colorType << " o_color;\n"
436			<< "\n"
437			<< "out gl_PerVertex {\n"
438			<< "    vec4 gl_Position;\n"
439			<< "};\n"
440			<< "\n"
441			<< "void main(void)\n"
442			<< "{\n"
443			// Introduce a variance in geometry per instance index which maps to the image layer
444			<< "    float a   = 0.25 * float(gl_InstanceIndex);\n"
445			<< "    mat3 rm   = mat3( cos(a), sin(a), 0.0,\n"
446			<< "                     -sin(a), cos(a), 0.0,\n"
447			<< "                         0.0,    0.0, 1.0);\n"
448			<< "    vec2 rpos = (rm * vec3(in_position.xy, 1.0)).xy;\n"
449			<< "\n"
450			<< "    gl_Position = vec4(rpos, in_position.zw);\n"
451			<< "    o_color     = in_color;\n"
452			<< "}\n";
453
454		programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
455	}
456
457	// Vertex shader - no vertex data, fill viewport with one primitive
458	{
459		std::ostringstream src;
460		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
461			<< "\n"
462			<< "out gl_PerVertex {\n"
463			<< "    vec4 gl_Position;\n"
464			<< "};\n"
465			<< "\n"
466			<< "void main(void)\n"
467			<< "{\n"
468			// Specify an oversized triangle covering the whole viewport.
469			<< "    switch (gl_VertexIndex)\n"
470			<< "    {\n"
471			<< "        case 0:\n"
472			<< "            gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n"
473			<< "            break;\n"
474			<< "        case 1:\n"
475			<< "            gl_Position = vec4(-1.0,  3.0, 0.0, 1.0);\n"
476			<< "            break;\n"
477			<< "        case 2:\n"
478			<< "            gl_Position = vec4( 3.0, -1.0, 0.0, 1.0);\n"
479			<< "            break;\n"
480			<< "    }\n"
481			<< "}\n";
482
483		programCollection.glslSources.add("vert_full") << glu::VertexSource(src.str());
484	}
485
486	// Fragment shader - output color from VS
487	{
488		std::ostringstream src;
489		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
490			<< "\n"
491			<< "layout(location = 0) in " << colorFragInQualifier << " " << colorType << " in_color;\n"
492			<< "layout(location = 0) out " << colorType << " o_color;\n"
493			<< "\n"
494			<< "void main(void)\n"
495			<< "{\n"
496			<< "    o_color = in_color;\n"
497			<< "}\n";
498
499		programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
500	}
501
502	// Fragment shader - FMASK fetch from an input attachment
503	if (params.sampleSource == SAMPLE_SOURCE_SUBPASS_INPUT)
504	{
505		std::ostringstream src;
506		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
507			<< "#extension GL_AMD_shader_fragment_mask : enable\n"
508			<< "\n"
509			<< "layout(set = 0, binding = 0) uniform " << samplerPrefix << "sampler2DMS" << (params.numLayers > 1 ? "Array" : "") << " u_image;\n"
510			<< "layout(set = 0, binding = 1, std430) writeonly buffer ColorOutput {\n"
511			<< "    " << colorBufferType << " color[];\n"
512			<< "} sb_out;\n"
513			<< "layout(input_attachment_index = 0, set = 0, binding = 2) uniform " << samplerPrefix << "subpassInputMS" << " input_attach;\n"
514			<< "\n"
515			<< "void main(void)\n"
516			<< "{\n"
517			<< "    ivec2 p            = ivec2(gl_FragCoord.xy);\n"
518			<< "    int   width        = " << params.renderSize.x() << ";\n"
519			<< "    int   numSamples   = " << static_cast<deUint32>(params.numColorSamples) << ";\n"
520			<< "    int   colorOutNdx  = numSamples * (p.x + width * p.y);\n"
521			<< "\n"
522			<< "    uint mask = fragmentMaskFetchAMD(input_attach);\n"
523			<< "    for (int sampleNdx = 0; sampleNdx < numSamples; ++sampleNdx)\n"
524			<< "    {\n"
525			<< "        int fragNdx = int((mask >> (4 * sampleNdx)) & 0xf);\n"
526			<< "        " << samplerPrefix << "vec4 color = fragmentFetchAMD(input_attach, fragNdx);\n"
527			<< "        sb_out.color[colorOutNdx + sampleNdx] = " << colorBufferPack << "(color);\n"
528			<< "    }\n"
529			<< "}\n";
530
531		programCollection.glslSources.add("frag_fmask_fetch") << glu::FragmentSource(src.str());
532	}
533
534	// Generate compute shaders
535	const struct ComputeShaderParams
536	{
537		const char*		name;
538		bool			isFmaskFetch;
539		bool			enabled;
540	} computeShaders[] =
541	{
542		// name					// FMASK?	// enabled?
543		{ "comp_fetch",			false,		true,													},
544		{ "comp_fmask_fetch",	true,		(params.sampleSource != SAMPLE_SOURCE_SUBPASS_INPUT)	},
545	};
546
547	for (const ComputeShaderParams* pShaderParams = computeShaders; pShaderParams != DE_ARRAY_END(computeShaders); ++pShaderParams)
548	if (pShaderParams->enabled)
549	{
550		const std::string samplingPos = (params.numLayers == 1 ? "ivec2(gl_WorkGroupID.xy)"
551															   : "ivec3(gl_WorkGroupID)");
552		std::ostringstream src;
553		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
554			<< (pShaderParams->isFmaskFetch ? "#extension GL_AMD_shader_fragment_mask : enable\n" : "")
555			<< "#define NUM_SAMPLES " << static_cast<deUint32>(params.numColorSamples) << "\n"
556			<< "\n"
557			<< "layout(local_size_x = NUM_SAMPLES) in;\n"	// one work group per pixel, each sample gets a local invocation
558			<< "\n"
559			<< "layout(set = 0, binding = 0) uniform " << samplerPrefix << "sampler2DMS" << (params.numLayers > 1 ? "Array" : "") << " u_image;\n"
560			<< "layout(set = 0, binding = 1, std430) writeonly buffer ColorOutput {\n"
561			<< "    " << colorBufferType << " color[];\n"
562			<< "} sb_out;\n"
563			<< "\n"
564			<< "void main(void)\n"
565			<< "{\n"
566			<< "    int sampleNdx   = int(gl_LocalInvocationID.x);\n"
567			<< "    int colorOutNdx = NUM_SAMPLES * int(gl_WorkGroupID.x +\n"
568			<< "                                        gl_WorkGroupID.y * gl_NumWorkGroups.x +\n"
569			<< "                                        gl_WorkGroupID.z * gl_NumWorkGroups.x * gl_NumWorkGroups.y);\n"
570			<< "\n";
571		if (pShaderParams->isFmaskFetch)
572		{
573			src << "    uint  mask    = fragmentMaskFetchAMD(u_image, " << samplingPos << ");\n"
574				<< "    int   fragNdx = int((mask >> (4 * sampleNdx)) & 0xf);\n"
575				<< "    " << samplerPrefix << "vec4 color = fragmentFetchAMD(u_image, " << samplingPos << ", fragNdx);\n"
576				<< "    sb_out.color[colorOutNdx + sampleNdx] = " << colorBufferPack << "(color);\n";
577		}
578		else
579		{
580			src << "    " << samplerPrefix << "vec4 color = texelFetch(u_image, " << samplingPos << ", sampleNdx);\n"
581				<< "    sb_out.color[colorOutNdx + sampleNdx] = " << colorBufferPack << "(color);\n";
582		}
583		src << "}\n";
584
585		programCollection.glslSources.add(pShaderParams->name) << glu::ComputeSource(src.str());
586	}
587}
588
589std::vector<VkClearValue> genClearValues (const VkFormat format, const deUint32 count)
590{
591	std::vector<VkClearValue>	clearValues;
592	de::Random					rng (332);
593
594	switch (format)
595	{
596		case VK_FORMAT_R8G8B8A8_UNORM:
597			for (deUint32 i = 0u; i < count; ++i)
598				clearValues.push_back(makeClearValueColorF32(rng.getFloat(), rng.getFloat(), rng.getFloat(), 1.0f));
599			break;
600
601		case VK_FORMAT_R32_UINT:
602		case VK_FORMAT_R32_SINT:
603			for (deUint32 i = 0u; i < count; ++i)
604				clearValues.push_back(makeClearValueColorU32(rng.getUint32(), 0u, 0u, 0u));
605			break;
606
607		default:
608			DE_FATAL("Clear color not defined for this format");
609			break;
610	}
611
612	return clearValues;
613}
614
615//! For subpass load case draw and fetch must happen within the same render pass.
616void drawAndSampleInputAttachment (Context& context, const TestParams& params, WorkingData& wd)
617{
618	DE_ASSERT(params.numLayers == 1u);	// subpass load with single-layer image
619
620	const InstanceInterface&	vki				= context.getInstanceInterface();
621	const DeviceInterface&		vk				= SingletonDevice::getDeviceInterface(context);
622	const VkPhysicalDevice		physicalDevice	= context.getPhysicalDevice();
623	const VkDevice				device			= SingletonDevice::getDevice(context);
624
625	RenderPassWrapper		renderPass;
626
627	// Create descriptor set
628	const Unique<VkDescriptorSetLayout> descriptorSetLayout (DescriptorSetLayoutBuilder()
629		.addSingleSamplerBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,	VK_SHADER_STAGE_FRAGMENT_BIT, &wd.defaultSampler.get())
630		.addSingleBinding		(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,			VK_SHADER_STAGE_FRAGMENT_BIT)
631		.addSingleBinding		(VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,		VK_SHADER_STAGE_FRAGMENT_BIT)
632		.build(vk, device));
633
634	const Unique<VkDescriptorPool> descriptorPool (DescriptorPoolBuilder()
635		.addType(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
636		.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
637		.addType(VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT)
638		.build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
639
640	const Unique<VkDescriptorSet> descriptorSet (makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
641
642	{
643		const VkDescriptorImageInfo		colorImageInfo	= makeDescriptorImageInfo(DE_NULL, *wd.colorImageView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
644		const VkDescriptorBufferInfo	bufferInfo		= makeDescriptorBufferInfo(*wd.colorBuffer, 0u, wd.colorBufferSize);
645
646		DescriptorSetUpdateBuilder	builder;
647
648		builder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &colorImageInfo);
649		builder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,		 &bufferInfo);
650
651		if (params.sampleSource == SAMPLE_SOURCE_SUBPASS_INPUT)
652			builder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(2u), VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, &colorImageInfo);
653
654		builder.update(vk, device);
655	}
656
657	// Create a render pass and a framebuffer
658	{
659		std::vector<VkSubpassDescription>		subpasses;
660		std::vector<VkSubpassDependency>		subpassDependencies;
661		std::vector<VkImage>					images;
662		std::vector<VkImageView>				attachments;
663		std::vector<VkAttachmentDescription>	attachmentDescriptions;
664		std::vector<VkAttachmentReference>		attachmentReferences;
665
666		// Reserve capacity to avoid invalidating pointers to elements
667		attachmentReferences.reserve(2);	// color image + input attachment
668
669		// Create a MS draw subpass
670		{
671			images.push_back(*wd.colorImage);
672			attachments.push_back(*wd.colorImageView);
673
674			attachmentDescriptions.push_back(makeAttachmentDescription(
675				(VkAttachmentDescriptionFlags)0,								// VkAttachmentDescriptionFlags		flags;
676				params.colorFormat,												// VkFormat							format;
677				params.numColorSamples,											// VkSampleCountFlagBits			samples;
678				VK_ATTACHMENT_LOAD_OP_CLEAR,									// VkAttachmentLoadOp				loadOp;
679				VK_ATTACHMENT_STORE_OP_STORE,									// VkAttachmentStoreOp				storeOp;
680				VK_ATTACHMENT_LOAD_OP_DONT_CARE,								// VkAttachmentLoadOp				stencilLoadOp;
681				VK_ATTACHMENT_STORE_OP_DONT_CARE,								// VkAttachmentStoreOp				stencilStoreOp;
682				VK_IMAGE_LAYOUT_UNDEFINED,										// VkImageLayout					initialLayout;
683				VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL						// VkImageLayout					finalLayout;
684			));
685
686			attachmentReferences.push_back(makeAttachmentReference(static_cast<deUint32>(attachmentReferences.size()),	VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL));
687			const VkAttachmentReference* colorRef = &attachmentReferences.back();
688
689			const VkSubpassDescription subpassDescription =
690			{
691				(VkSubpassDescriptionFlags)0,						// VkSubpassDescriptionFlags       flags;
692				VK_PIPELINE_BIND_POINT_GRAPHICS,					// VkPipelineBindPoint             pipelineBindPoint;
693				0u,													// uint32_t                        inputAttachmentCount;
694				DE_NULL,											// const VkAttachmentReference*    pInputAttachments;
695				1u,													// uint32_t                        colorAttachmentCount;
696				colorRef,											// const VkAttachmentReference*    pColorAttachments;
697				DE_NULL,											// const VkAttachmentReference*    pResolveAttachments;
698				DE_NULL,											// const VkAttachmentReference*    pDepthStencilAttachment;
699				0u,													// uint32_t                        preserveAttachmentCount;
700				DE_NULL,											// const uint32_t*                 pPreserveAttachments;
701			};
702
703			subpasses.push_back(subpassDescription);
704		}
705
706		// Create a sampling subpass
707		{
708			attachmentReferences.push_back(makeAttachmentReference(0u, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL));
709			const VkAttachmentReference* inputRef = &attachmentReferences.back();
710
711			// No color attachment, side effects only
712			VkSubpassDescription subpassDescription =
713			{
714				(VkSubpassDescriptionFlags)0,						// VkSubpassDescriptionFlags       flags;
715				VK_PIPELINE_BIND_POINT_GRAPHICS,					// VkPipelineBindPoint             pipelineBindPoint;
716				1u,													// uint32_t                        inputAttachmentCount;
717				inputRef,											// const VkAttachmentReference*    pInputAttachments;
718				0u,													// uint32_t                        colorAttachmentCount;
719				DE_NULL,											// const VkAttachmentReference*    pColorAttachments;
720				DE_NULL,											// const VkAttachmentReference*    pResolveAttachments;
721				DE_NULL,											// const VkAttachmentReference*    pDepthStencilAttachment;
722				0u,													// uint32_t                        preserveAttachmentCount;
723				DE_NULL,											// const uint32_t*                 pPreserveAttachments;
724			};
725
726			subpasses.push_back(subpassDescription);
727		}
728
729		// Serialize the subpasses
730		{
731			const VkAccessFlags	dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT
732											  | VK_ACCESS_INPUT_ATTACHMENT_READ_BIT
733											  | VK_ACCESS_SHADER_WRITE_BIT;
734			const VkSubpassDependency	dependency	=
735			{
736				0u,																							// uint32_t                srcSubpass;
737				1u,																							// uint32_t                dstSubpass;
738				VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,		// VkPipelineStageFlags    srcStageMask;
739				VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,		// VkPipelineStageFlags    dstStageMask;
740				VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,														// VkAccessFlags           srcAccessMask;
741				dstAccessMask,																				// VkAccessFlags           dstAccessMask;
742				VK_DEPENDENCY_BY_REGION_BIT,																// VkDependencyFlags       dependencyFlags;
743			};
744			subpassDependencies.push_back(dependency);
745		}
746
747		VkRenderPassCreateInfo renderPassInfo =
748		{
749			VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,				// VkStructureType					sType;
750			DE_NULL,												// const void*						pNext;
751			(VkRenderPassCreateFlags)0,								// VkRenderPassCreateFlags			flags;
752			static_cast<deUint32>(attachmentDescriptions.size()),	// deUint32							attachmentCount;
753			dataOrNullPtr(attachmentDescriptions),					// const VkAttachmentDescription*	pAttachments;
754			static_cast<deUint32>(subpasses.size()),				// deUint32							subpassCount;
755			dataOrNullPtr(subpasses),								// const VkSubpassDescription*		pSubpasses;
756			static_cast<deUint32>(subpassDependencies.size()),		// deUint32							dependencyCount;
757			dataOrNullPtr(subpassDependencies),						// const VkSubpassDependency*		pDependencies;
758		};
759
760		renderPass  = RenderPassWrapper(params.pipelineConstructionType, vk, device, &renderPassInfo);
761		renderPass.createFramebuffer(vk, device, static_cast<deUint32>(attachments.size()), dataOrNullPtr(images), dataOrNullPtr(attachments), params.renderSize.x(), params.renderSize.y());
762	}
763
764	const std::vector<VkViewport>	viewports	{ makeViewport(params.renderSize) };
765	const std::vector<VkRect2D>		scissors	{ makeRect2D(params.renderSize) };
766
767	VkPipelineMultisampleStateCreateInfo multisampleStateInfo
768	{
769		VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,		// VkStructureType							sType;
770		DE_NULL,														// const void*								pNext;
771		(VkPipelineMultisampleStateCreateFlags)0,						// VkPipelineMultisampleStateCreateFlags	flags;
772		params.numColorSamples,											// VkSampleCountFlagBits					rasterizationSamples;
773		VK_FALSE,														// VkBool32									sampleShadingEnable;
774		1.0f,															// float									minSampleShading;
775		DE_NULL,														// const VkSampleMask*						pSampleMask;
776		VK_FALSE,														// VkBool32									alphaToCoverageEnable;
777		VK_FALSE														// VkBool32									alphaToOneEnable;
778	};
779
780	const VkPipelineColorBlendAttachmentState defaultBlendAttachmentState
781	{
782		VK_FALSE,														// VkBool32					blendEnable;
783		VK_BLEND_FACTOR_ONE,											// VkBlendFactor			srcColorBlendFactor;
784		VK_BLEND_FACTOR_ZERO,											// VkBlendFactor			dstColorBlendFactor;
785		VK_BLEND_OP_ADD,												// VkBlendOp				colorBlendOp;
786		VK_BLEND_FACTOR_ONE,											// VkBlendFactor			srcAlphaBlendFactor;
787		VK_BLEND_FACTOR_ZERO,											// VkBlendFactor			dstAlphaBlendFactor;
788		VK_BLEND_OP_ADD,												// VkBlendOp				alphaBlendOp;
789		0xf,															// VkColorComponentFlags	colorWriteMask;
790	};
791
792	VkPipelineColorBlendStateCreateInfo colorBlendStateInfo
793	{
794		VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,		// VkStructureType								sType;
795		DE_NULL,														// const void*									pNext;
796		(VkPipelineColorBlendStateCreateFlags)0,						// VkPipelineColorBlendStateCreateFlags			flags;
797		VK_FALSE,														// VkBool32										logicOpEnable;
798		VK_LOGIC_OP_COPY,												// VkLogicOp									logicOp;
799		1u,																// deUint32										attachmentCount;
800		&defaultBlendAttachmentState,									// const VkPipelineColorBlendAttachmentState*	pAttachments;
801		{ 0.0f, 0.0f, 0.0f, 0.0f },										// float										blendConstants[4];
802	};
803
804	const ShaderWrapper				vertexModuleDraw	(ShaderWrapper(vk, device, context.getBinaryCollection().get("vert"), 0u));
805	const ShaderWrapper				fragmentModuleDraw	(ShaderWrapper(vk, device, context.getBinaryCollection().get("frag"), 0u));
806
807	// Create pipelines for MS draw
808	const PipelineLayoutWrapper		pipelineLayout		(params.pipelineConstructionType, vk, device, *descriptorSetLayout);
809	GraphicsPipelineWrapper			pipelineDraw		(vki, vk, physicalDevice, device, context.getDeviceExtensions(), params.pipelineConstructionType);
810	{
811		// Vertex attributes: position and color
812		VkVertexInputBindingDescription					vertexInputBindingDescriptions = makeVertexInputBindingDescription(0u, sizeof(PositionColor), VK_VERTEX_INPUT_RATE_VERTEX);
813		std::vector<VkVertexInputAttributeDescription>	vertexInputAttributeDescriptions
814		{
815			makeVertexInputAttributeDescription(0u, 0u, VK_FORMAT_R32G32B32A32_SFLOAT, 0u),
816			makeVertexInputAttributeDescription(1u, 0u, getVertexInputColorFormat(params.colorFormat), sizeof(Vec4))
817		};
818
819		const VkPipelineVertexInputStateCreateInfo vertexInputStateInfo
820		{
821			VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,		// VkStructureType							sType;
822			DE_NULL,														// const void*								pNext;
823			(VkPipelineVertexInputStateCreateFlags)0,						// VkPipelineVertexInputStateCreateFlags	flags;
824			1u,																// uint32_t									vertexBindingDescriptionCount;
825			&vertexInputBindingDescriptions,								// const VkVertexInputBindingDescription*	pVertexBindingDescriptions;
826			static_cast<deUint32>(vertexInputAttributeDescriptions.size()),	// uint32_t									vertexAttributeDescriptionCount;
827			vertexInputAttributeDescriptions.data(),						// const VkVertexInputAttributeDescription*	pVertexAttributeDescriptions;
828		};
829
830		pipelineDraw.setDefaultRasterizationState()
831					.setDefaultDepthStencilState()
832					.setupVertexInputState(&vertexInputStateInfo)
833					.setupPreRasterizationShaderState(viewports,
834									scissors,
835									pipelineLayout,
836									*renderPass,
837									0u,
838									vertexModuleDraw)
839					.setupFragmentShaderState(pipelineLayout, *renderPass, 0u, fragmentModuleDraw, DE_NULL, &multisampleStateInfo)
840					.setupFragmentOutputState(*renderPass, 0u, &colorBlendStateInfo, &multisampleStateInfo)
841					.setMonolithicPipelineLayout(pipelineLayout)
842					.buildPipeline();
843	}
844
845	// Sampling pass is single-sampled, output to storage buffer
846	const ShaderWrapper		vertexModuleSample		(ShaderWrapper(vk, device, context.getBinaryCollection().get("vert_full"), 0u));
847	const ShaderWrapper		fragmentModuleSample	(ShaderWrapper(vk, device, context.getBinaryCollection().get("frag_fmask_fetch"), 0u));
848
849	// Sampling pipeline
850	GraphicsPipelineWrapper pipelineSample(vki, vk, physicalDevice, device, context.getDeviceExtensions(), params.pipelineConstructionType);
851	{
852		VkPipelineVertexInputStateCreateInfo vertexInputStateInfo;
853		deMemset(&vertexInputStateInfo, 0, sizeof(vertexInputStateInfo));
854		vertexInputStateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
855
856		multisampleStateInfo.rasterizationSamples	= VK_SAMPLE_COUNT_1_BIT;
857		colorBlendStateInfo.attachmentCount			= 0u;
858
859		pipelineSample.setDefaultRasterizationState()
860					  .setDefaultDepthStencilState()
861					  .setupVertexInputState(&vertexInputStateInfo)
862					  .setupPreRasterizationShaderState(viewports,
863									scissors,
864									pipelineLayout,
865									*renderPass,
866									1u,
867									vertexModuleSample)
868					  .setupFragmentShaderState(pipelineLayout, *renderPass, 1u, fragmentModuleSample, DE_NULL, &multisampleStateInfo)
869					  .setupFragmentOutputState(*renderPass, 1u, &colorBlendStateInfo, &multisampleStateInfo)
870					  .setMonolithicPipelineLayout(pipelineLayout)
871					  .buildPipeline();
872	}
873
874	const Unique<VkCommandPool>		cmdPool		(createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, context.getUniversalQueueFamilyIndex()));
875	const Unique<VkCommandBuffer>	cmdBuffer	(makeCommandBuffer(vk, device, *cmdPool));
876
877	beginCommandBuffer(vk, *cmdBuffer);
878
879	{
880		// Generate clear values
881		std::vector<VkClearValue> clearValues = genClearValues(params.colorFormat, params.numLayers);
882
883		const VkRect2D renderArea =
884		{
885			{ 0u, 0u },
886			{ params.renderSize.x(), params.renderSize.y() }
887		};
888		renderPass.begin(vk, *cmdBuffer, renderArea, static_cast<deUint32>(clearValues.size()), dataOrNullPtr(clearValues));
889	}
890
891	vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u, &descriptorSet.get(), 0u, DE_NULL);
892
893	{
894		const VkDeviceSize vertexBufferOffset = 0ull;
895		vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &wd.vertexBuffer.get(), &vertexBufferOffset);
896	}
897
898	pipelineDraw.bind(*cmdBuffer);
899	vk.cmdDraw(*cmdBuffer, wd.numVertices, 1u, 0u, 0u);
900
901	renderPass.nextSubpass(vk, *cmdBuffer, VK_SUBPASS_CONTENTS_INLINE);
902
903	pipelineSample.bind(*cmdBuffer);
904	vk.cmdDraw(*cmdBuffer, 3u, 1u, 0u, 0u);	// fill the framebuffer, geometry defined in the VS
905
906	renderPass.end(vk, *cmdBuffer);
907
908	// Buffer write barrier
909	{
910		const VkBufferMemoryBarrier barrier =
911		{
912			VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,		// VkStructureType    sType;
913			DE_NULL,										// const void*        pNext;
914			VK_ACCESS_SHADER_WRITE_BIT,						// VkAccessFlags      srcAccessMask;
915			VK_ACCESS_HOST_READ_BIT,						// VkAccessFlags      dstAccessMask;
916			VK_QUEUE_FAMILY_IGNORED,						// uint32_t           srcQueueFamilyIndex;
917			VK_QUEUE_FAMILY_IGNORED,						// uint32_t           dstQueueFamilyIndex;
918			*wd.colorBuffer,								// VkBuffer           buffer;
919			0ull,											// VkDeviceSize       offset;
920			VK_WHOLE_SIZE,									// VkDeviceSize       size;
921		};
922
923		vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_HOST_BIT, (VkDependencyFlags)0, 0u, DE_NULL, 1u, &barrier, DE_NULL, 0u);
924	}
925
926	VK_CHECK(vk.endCommandBuffer(*cmdBuffer));
927	submitCommandsAndWait(vk, device, SingletonDevice::getUniversalQueue(context), *cmdBuffer);
928
929	invalidateMappedMemoryRange(vk, device, wd.colorBufferAlloc->getMemory(), wd.colorBufferAlloc->getOffset(), VK_WHOLE_SIZE);
930}
931
932//! Only draw a multisampled image
933void draw (Context& context, const TestParams& params, WorkingData& wd)
934{
935	const InstanceInterface & vki = context.getInstanceInterface();
936	const DeviceInterface&		vk				= SingletonDevice::getDeviceInterface(context);
937	const VkPhysicalDevice		physicalDevice = context.getPhysicalDevice();
938	const VkDevice				device			= SingletonDevice::getDevice(context);
939
940	std::vector<ImageViewSp>	imageViews;
941	RenderPassWrapper			renderPass;
942
943	// Create color attachments
944	for (deUint32 layerNdx = 0u; layerNdx < params.numLayers; ++layerNdx)
945	{
946		imageViews.push_back(ImageViewSp(new Unique<VkImageView>(
947			makeImageView(vk, device, *wd.colorImage, VK_IMAGE_VIEW_TYPE_2D, params.colorFormat, makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, layerNdx, 1u)))));
948	}
949
950	// Create a render pass and a framebuffer
951	{
952		std::vector<VkSubpassDescription>		subpasses;
953		std::vector<VkImage>					images;
954		std::vector<VkImageView>				attachments;
955		std::vector<VkAttachmentDescription>	attachmentDescriptions;
956		std::vector<VkAttachmentReference>		attachmentReferences;
957
958		// Reserve capacity to avoid invalidating pointers to elements
959		attachmentReferences.reserve(params.numLayers);
960
961		// Create MS draw subpasses
962		for (deUint32 layerNdx = 0u; layerNdx < params.numLayers; ++layerNdx)
963		{
964			images.push_back(*wd.colorImage);
965			attachments.push_back(**imageViews[layerNdx]);
966
967			attachmentDescriptions.push_back(makeAttachmentDescription(
968				(VkAttachmentDescriptionFlags)0,								// VkAttachmentDescriptionFlags		flags;
969				params.colorFormat,												// VkFormat							format;
970				params.numColorSamples,											// VkSampleCountFlagBits			samples;
971				VK_ATTACHMENT_LOAD_OP_CLEAR,									// VkAttachmentLoadOp				loadOp;
972				VK_ATTACHMENT_STORE_OP_STORE,									// VkAttachmentStoreOp				storeOp;
973				VK_ATTACHMENT_LOAD_OP_DONT_CARE,								// VkAttachmentLoadOp				stencilLoadOp;
974				VK_ATTACHMENT_STORE_OP_DONT_CARE,								// VkAttachmentStoreOp				stencilStoreOp;
975				VK_IMAGE_LAYOUT_UNDEFINED,										// VkImageLayout					initialLayout;
976				VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL						// VkImageLayout					finalLayout;
977			));
978
979			attachmentReferences.push_back(makeAttachmentReference(static_cast<deUint32>(attachmentReferences.size()),	VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL));
980			const VkAttachmentReference* colorRef = &attachmentReferences.back();
981
982			const VkSubpassDescription subpassDescription =
983			{
984				(VkSubpassDescriptionFlags)0,						// VkSubpassDescriptionFlags       flags;
985				VK_PIPELINE_BIND_POINT_GRAPHICS,					// VkPipelineBindPoint             pipelineBindPoint;
986				0u,													// uint32_t                        inputAttachmentCount;
987				DE_NULL,											// const VkAttachmentReference*    pInputAttachments;
988				1u,													// uint32_t                        colorAttachmentCount;
989				colorRef,											// const VkAttachmentReference*    pColorAttachments;
990				DE_NULL,											// const VkAttachmentReference*    pResolveAttachments;
991				DE_NULL,											// const VkAttachmentReference*    pDepthStencilAttachment;
992				0u,													// uint32_t                        preserveAttachmentCount;
993				DE_NULL,											// const uint32_t*                 pPreserveAttachments;
994			};
995
996			subpasses.push_back(subpassDescription);
997		}
998
999		// All MS image drawing subpasses are independent
1000		VkRenderPassCreateInfo renderPassInfo =
1001		{
1002			VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,				// VkStructureType					sType;
1003			DE_NULL,												// const void*						pNext;
1004			(VkRenderPassCreateFlags)0,								// VkRenderPassCreateFlags			flags;
1005			static_cast<deUint32>(attachmentDescriptions.size()),	// deUint32							attachmentCount;
1006			dataOrNullPtr(attachmentDescriptions),					// const VkAttachmentDescription*	pAttachments;
1007			static_cast<deUint32>(subpasses.size()),				// deUint32							subpassCount;
1008			dataOrNullPtr(subpasses),								// const VkSubpassDescription*		pSubpasses;
1009			0u,														// deUint32							dependencyCount;
1010			DE_NULL,												// const VkSubpassDependency*		pDependencies;
1011		};
1012
1013		renderPass  = RenderPassWrapper(params.pipelineConstructionType, vk, device, &renderPassInfo);
1014		renderPass.createFramebuffer(vk, device, static_cast<deUint32>(attachments.size()), dataOrNullPtr(images), dataOrNullPtr(attachments), params.renderSize.x(), params.renderSize.y());
1015	}
1016
1017	const PipelineLayoutWrapper				pipelineLayout		(params.pipelineConstructionType, vk, device);
1018	const ShaderWrapper						vertexModuleDraw	(ShaderWrapper(vk, device, context.getBinaryCollection().get("vert"), 0u));
1019	const ShaderWrapper						fragmentModuleDraw	(ShaderWrapper(vk, device, context.getBinaryCollection().get("frag"), 0u));
1020
1021	// Vertex attributes: position and color
1022	VkVertexInputBindingDescription					vertexInputBindingDescriptions = makeVertexInputBindingDescription(0u, sizeof(PositionColor), VK_VERTEX_INPUT_RATE_VERTEX);
1023	std::vector<VkVertexInputAttributeDescription>	vertexInputAttributeDescriptions
1024	{
1025		makeVertexInputAttributeDescription(0u, 0u, VK_FORMAT_R32G32B32A32_SFLOAT, 0u),
1026		makeVertexInputAttributeDescription(1u, 0u, getVertexInputColorFormat(params.colorFormat), sizeof(Vec4))
1027	};
1028
1029	const VkPipelineVertexInputStateCreateInfo vertexInputStateInfo
1030	{
1031		VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,		// VkStructureType								sType;
1032		DE_NULL,														// const void*									pNext;
1033		(VkPipelineVertexInputStateCreateFlags)0,						// VkPipelineVertexInputStateCreateFlags		flags;
1034		1u,																// uint32_t										vertexBindingDescriptionCount;
1035		&vertexInputBindingDescriptions,								// const VkVertexInputBindingDescription*		pVertexBindingDescriptions;
1036		static_cast<deUint32>(vertexInputAttributeDescriptions.size()),	// uint32_t										vertexAttributeDescriptionCount;
1037		vertexInputAttributeDescriptions.data(),						// const VkVertexInputAttributeDescription*		pVertexAttributeDescriptions;
1038	};
1039
1040	const std::vector<VkViewport>	viewports	{ makeViewport(params.renderSize) };
1041	const std::vector<VkRect2D>		scissors	{ makeRect2D(params.renderSize) };
1042
1043	const VkPipelineMultisampleStateCreateInfo multisampleStateInfo
1044	{
1045		VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,		// VkStructureType								sType;
1046		DE_NULL,														// const void*									pNext;
1047		(VkPipelineMultisampleStateCreateFlags)0,						// VkPipelineMultisampleStateCreateFlags		flags;
1048		params.numColorSamples,											// VkSampleCountFlagBits						rasterizationSamples;
1049		VK_FALSE,														// VkBool32										sampleShadingEnable;
1050		1.0f,															// float										minSampleShading;
1051		DE_NULL,														// const VkSampleMask*							pSampleMask;
1052		VK_FALSE,														// VkBool32										alphaToCoverageEnable;
1053		VK_FALSE														// VkBool32										alphaToOneEnable;
1054	};
1055
1056	const VkPipelineColorBlendAttachmentState defaultBlendAttachmentState
1057	{
1058		VK_FALSE,														// VkBool32										blendEnable;
1059		VK_BLEND_FACTOR_ONE,											// VkBlendFactor								srcColorBlendFactor;
1060		VK_BLEND_FACTOR_ZERO,											// VkBlendFactor								dstColorBlendFactor;
1061		VK_BLEND_OP_ADD,												// VkBlendOp									colorBlendOp;
1062		VK_BLEND_FACTOR_ONE,											// VkBlendFactor								srcAlphaBlendFactor;
1063		VK_BLEND_FACTOR_ZERO,											// VkBlendFactor								dstAlphaBlendFactor;
1064		VK_BLEND_OP_ADD,												// VkBlendOp									alphaBlendOp;
1065		0xf,															// VkColorComponentFlags						colorWriteMask;
1066	};
1067
1068	VkPipelineColorBlendStateCreateInfo colorBlendStateInfo
1069	{
1070		VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,		// VkStructureType								sType;
1071		DE_NULL,														// const void*									pNext;
1072		(VkPipelineColorBlendStateCreateFlags)0,						// VkPipelineColorBlendStateCreateFlags			flags;
1073		VK_FALSE,														// VkBool32										logicOpEnable;
1074		VK_LOGIC_OP_COPY,												// VkLogicOp									logicOp;
1075		1u,																// deUint32										attachmentCount;
1076		&defaultBlendAttachmentState,									// const VkPipelineColorBlendAttachmentState*	pAttachments;
1077		{ 0.0f, 0.0f, 0.0f, 0.0f },										// float										blendConstants[4];
1078	};
1079
1080	// Create pipelines for MS draw
1081	std::vector<GraphicsPipelineWrapper> pipelines;
1082	pipelines.reserve(params.numLayers);
1083	for (deUint32 layerNdx = 0u; layerNdx < params.numLayers; ++layerNdx)
1084	{
1085		pipelines.emplace_back(vki, vk, physicalDevice, device, context.getDeviceExtensions(), params.pipelineConstructionType);
1086		pipelines.back().setDefaultRasterizationState()
1087						.setDefaultColorBlendState()
1088						.setDefaultDepthStencilState()
1089						.setupVertexInputState(&vertexInputStateInfo)
1090						.setupPreRasterizationShaderState(viewports,
1091												scissors,
1092												pipelineLayout,
1093												*renderPass,
1094												layerNdx,
1095												vertexModuleDraw)
1096						.setupFragmentShaderState(pipelineLayout, *renderPass, layerNdx, fragmentModuleDraw, DE_NULL, &multisampleStateInfo)
1097						.setupFragmentOutputState(*renderPass, layerNdx, &colorBlendStateInfo, &multisampleStateInfo)
1098						.setMonolithicPipelineLayout(pipelineLayout)
1099						.buildPipeline();
1100	}
1101
1102	const Unique<VkCommandPool>		cmdPool		(createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, context.getUniversalQueueFamilyIndex()));
1103	const Unique<VkCommandBuffer>	cmdBuffer	(makeCommandBuffer(vk, device, *cmdPool));
1104
1105	beginCommandBuffer(vk, *cmdBuffer);
1106
1107	{
1108		// Generate clear values
1109		std::vector<VkClearValue> clearValues = genClearValues(params.colorFormat, params.numLayers);
1110
1111		const VkRect2D renderArea =
1112		{
1113			{ 0u, 0u },
1114			{ params.renderSize.x(), params.renderSize.y() }
1115		};
1116
1117		renderPass.begin(vk, *cmdBuffer, renderArea, static_cast<deUint32>(clearValues.size()), dataOrNullPtr(clearValues));
1118	}
1119
1120	{
1121		const VkDeviceSize vertexBufferOffset = 0ull;
1122		vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &wd.vertexBuffer.get(), &vertexBufferOffset);
1123	}
1124
1125	for (deUint32 layerNdx = 0u; layerNdx < params.numLayers; ++layerNdx)
1126	{
1127		if (layerNdx != 0u)
1128			renderPass.nextSubpass(vk, *cmdBuffer, VK_SUBPASS_CONTENTS_INLINE);
1129
1130		pipelines[layerNdx].bind(*cmdBuffer);
1131		vk.cmdDraw(*cmdBuffer, wd.numVertices, 1u, 0u, layerNdx);	// pass instance index to slightly change geometry per layer
1132	}
1133
1134	renderPass.end(vk, *cmdBuffer);
1135
1136	VK_CHECK(vk.endCommandBuffer(*cmdBuffer));
1137	submitCommandsAndWait(vk, device, SingletonDevice::getUniversalQueue(context), *cmdBuffer);
1138}
1139
1140//! Sample from an image in a compute shader, storing the result in a color buffer
1141void dispatchSampleImage (Context& context, const TestParams& params, WorkingData& wd, const std::string& shaderName)
1142{
1143	const DeviceInterface&	vk		= SingletonDevice::getDeviceInterface(context);
1144	const VkDevice			device	= SingletonDevice::getDevice(context);
1145
1146	// Create descriptor set
1147
1148	const Unique<VkDescriptorSetLayout> descriptorSetLayout(
1149		DescriptorSetLayoutBuilder()
1150		.addSingleSamplerBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,	VK_SHADER_STAGE_COMPUTE_BIT, &wd.defaultSampler.get())
1151		.addSingleBinding		(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,			VK_SHADER_STAGE_COMPUTE_BIT)
1152		.build(vk, device));
1153
1154	const Unique<VkDescriptorPool> descriptorPool(
1155		DescriptorPoolBuilder()
1156		.addType(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
1157		.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
1158		.build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
1159
1160	const Unique<VkDescriptorSet> descriptorSet(makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
1161
1162	{
1163		const VkDescriptorImageInfo		colorImageInfo		= makeDescriptorImageInfo(DE_NULL, *wd.colorImageView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
1164		const VkDescriptorBufferInfo	resultBufferInfo	= makeDescriptorBufferInfo(*wd.colorBuffer, 0ull, wd.colorBufferSize);
1165
1166		DescriptorSetUpdateBuilder	builder;
1167
1168		builder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &colorImageInfo);
1169		builder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,		  &resultBufferInfo);
1170
1171		builder.update(vk, device);
1172	}
1173
1174	// Pipeline
1175
1176	const Unique<VkShaderModule>	shaderModule	(createShaderModule(vk, device, context.getBinaryCollection().get(shaderName), 0u));
1177	const Unique<VkPipelineLayout>	pipelineLayout	(makePipelineLayout(vk, device, *descriptorSetLayout));
1178	const Unique<VkPipeline>		pipeline		(makeComputePipeline(vk, device, *pipelineLayout, *shaderModule));
1179
1180	const Unique<VkCommandPool>		cmdPool		(createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, context.getUniversalQueueFamilyIndex()));
1181	const Unique<VkCommandBuffer>	cmdBuffer	(makeCommandBuffer(vk, device, *cmdPool));
1182
1183	beginCommandBuffer(vk, *cmdBuffer);
1184
1185	vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
1186	vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &descriptorSet.get(), 0u, DE_NULL);
1187
1188	vk.cmdDispatch(*cmdBuffer, params.renderSize.x(), params.renderSize.y(), params.numLayers);
1189
1190	{
1191		const VkBufferMemoryBarrier barrier =
1192		{
1193			VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,		// VkStructureType    sType;
1194			DE_NULL,										// const void*        pNext;
1195			VK_ACCESS_SHADER_WRITE_BIT,						// VkAccessFlags      srcAccessMask;
1196			VK_ACCESS_HOST_READ_BIT,						// VkAccessFlags      dstAccessMask;
1197			VK_QUEUE_FAMILY_IGNORED,						// uint32_t           srcQueueFamilyIndex;
1198			VK_QUEUE_FAMILY_IGNORED,						// uint32_t           dstQueueFamilyIndex;
1199			*wd.colorBuffer,								// VkBuffer           buffer;
1200			0ull,											// VkDeviceSize       offset;
1201			VK_WHOLE_SIZE,									// VkDeviceSize       size;
1202		};
1203
1204		vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_HOST_BIT, (VkDependencyFlags)0, 0,
1205			(const VkMemoryBarrier*)DE_NULL, 1u, &barrier, 0u, (const VkImageMemoryBarrier*)DE_NULL);
1206	}
1207
1208	VK_CHECK(vk.endCommandBuffer(*cmdBuffer));
1209	submitCommandsAndWait(vk, device, SingletonDevice::getUniversalQueue(context), *cmdBuffer);
1210
1211	invalidateMappedMemoryRange(vk, device, wd.colorBufferAlloc->getMemory(), wd.colorBufferAlloc->getOffset(), VK_WHOLE_SIZE);
1212}
1213
1214//! Get a single-sampled image access from a multisampled color buffer with samples packed per pixel
1215tcu::ConstPixelBufferAccess getSingleSampledAccess (const void* const imageData, const TestParams& params, const deUint32 sampleNdx, const deUint32 layerNdx)
1216{
1217	const deUint32		numSamples	= static_cast<deUint32>(params.numColorSamples);
1218	const deUint32		pixelSize	= tcu::getPixelSize(mapVkFormat(params.colorFormat));
1219	const deUint32		rowSize		= pixelSize * params.renderSize.x();
1220	const deUint32		layerSize	= rowSize * params.renderSize.y();
1221	const deUint8*		src			= static_cast<const deUint8*>(imageData)
1222									+ (layerNdx * numSamples * layerSize)
1223									+ (sampleNdx * pixelSize);
1224	const tcu::IVec3	size		(params.renderSize.x(), params.renderSize.y(), 1);
1225	const tcu::IVec3	pitch		(numSamples * pixelSize,
1226									 numSamples * rowSize,
1227									 numSamples * layerSize);
1228	return tcu::ConstPixelBufferAccess(mapVkFormat(params.colorFormat), size, pitch, src);
1229}
1230
1231tcu::TestStatus test (Context& context, const TestParams params)
1232{
1233	WorkingData				wd;
1234	const DeviceInterface&	vk		  = SingletonDevice::getDeviceInterface(context);
1235	const VkDevice			device	  = SingletonDevice::getDevice(context);
1236
1237	MovePtr<Allocator>		allocator = MovePtr<Allocator>(new SimpleAllocator(vk, device, getPhysicalDeviceMemoryProperties(context.getInstanceInterface(), context.getPhysicalDevice())));
1238
1239	// Initialize resources
1240	{
1241		const VkImageUsageFlags	msImageUsage	= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
1242												| VK_IMAGE_USAGE_SAMPLED_BIT
1243												| (params.sampleSource == SAMPLE_SOURCE_SUBPASS_INPUT ? VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT : (VkImageUsageFlagBits)0);
1244		wd.colorImage		= makeImage(vk, device, params.colorFormat, params.renderSize, params.numLayers, params.numColorSamples, msImageUsage);
1245		wd.colorImageAlloc	= bindImage(vk, device, *allocator, *wd.colorImage, MemoryRequirement::Any);
1246		wd.colorImageView	= makeImageView(vk, device, *wd.colorImage, (params.numLayers == 1u ? VK_IMAGE_VIEW_TYPE_2D : VK_IMAGE_VIEW_TYPE_2D_ARRAY), params.colorFormat,
1247											makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, params.numLayers));
1248
1249		wd.defaultSampler	= makeSampler(vk, device);
1250
1251		// Color buffer is meant to hold data for all layers and all samples of the image.
1252		// Data is tightly packed layer by layer, for each pixel all samples are laid out together starting with sample 0.
1253		// E.g.: pixel(0,0)sample(0)sample(1), pixel(1,0)sample(0)sample(1), ...
1254		wd.colorBufferSize	= static_cast<VkDeviceSize>(tcu::getPixelSize(mapVkFormat(params.colorFormat))
1255														* params.renderSize.x() * params.renderSize.y() * params.numLayers * static_cast<deUint32>(params.numColorSamples));
1256		wd.colorBuffer		= makeBuffer(vk, device, wd.colorBufferSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
1257		wd.colorBufferAlloc	= bindBuffer(vk, device, *allocator, *wd.colorBuffer, MemoryRequirement::HostVisible);
1258
1259		deMemset(wd.colorBufferAlloc->getHostPtr(), 0, static_cast<std::size_t>(wd.colorBufferSize));
1260		flushMappedMemoryRange(vk, device, wd.colorBufferAlloc->getMemory(), wd.colorBufferAlloc->getOffset(), VK_WHOLE_SIZE);
1261
1262		const std::vector<PositionColor>	vertices			= genShapes(params.colorFormat);
1263		const VkDeviceSize					vertexBufferSize	= static_cast<VkDeviceSize>(sizeof(vertices[0]) * vertices.size());
1264
1265		wd.numVertices			= static_cast<deUint32>(vertices.size());
1266		wd.vertexBuffer			= makeBuffer(vk, device, vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
1267		wd.vertexBufferAlloc	= bindBuffer(vk, device, *allocator, *wd.vertexBuffer, MemoryRequirement::HostVisible);
1268
1269		deMemcpy(wd.vertexBufferAlloc->getHostPtr(), dataOrNullPtr(vertices), static_cast<std::size_t>(vertexBufferSize));
1270		flushMappedMemoryRange(vk, device, wd.vertexBufferAlloc->getMemory(), wd.vertexBufferAlloc->getOffset(), VK_WHOLE_SIZE);
1271	}
1272
1273	if (params.sampleSource == SAMPLE_SOURCE_SUBPASS_INPUT)
1274	{
1275		// Create a multisample image and sample from it
1276		drawAndSampleInputAttachment (context, params, wd);
1277	}
1278	else
1279	{
1280		// Draw the image, then sample from it in a CS
1281		draw				(context, params, wd);
1282		dispatchSampleImage (context, params, wd, "comp_fmask_fetch");
1283	}
1284
1285	// Copy the result
1286	std::vector<deUint8> fmaskFetchColorBuffer (static_cast<deUint32>(wd.colorBufferSize));
1287	deMemcpy(&fmaskFetchColorBuffer[0], wd.colorBufferAlloc->getHostPtr(), static_cast<std::size_t>(wd.colorBufferSize));
1288
1289	// Clear the color buffer, just to be sure we're getting the new data
1290	deMemset(wd.colorBufferAlloc->getHostPtr(), 0, static_cast<std::size_t>(wd.colorBufferSize));
1291	flushMappedMemoryRange(vk, device, wd.colorBufferAlloc->getMemory(), wd.colorBufferAlloc->getOffset(), VK_WHOLE_SIZE);
1292
1293	// Sample image using the standard texel fetch
1294	dispatchSampleImage (context, params, wd, "comp_fetch");
1295
1296	// Verify the images
1297	{
1298		const void* const fmaskResult	 = dataOrNullPtr(fmaskFetchColorBuffer);
1299		const void* const expectedResult = wd.colorBufferAlloc->getHostPtr();
1300
1301		DE_ASSERT(!isFloatFormat(params.colorFormat));	// we're using int compare
1302
1303		// Mismatch, do image compare to pinpoint the failure
1304		for (deUint32 layerNdx  = 0u; layerNdx  < params.numLayers;								 ++layerNdx)
1305		for (deUint32 sampleNdx = 0u; sampleNdx < static_cast<deUint32>(params.numColorSamples); ++sampleNdx)
1306		{
1307			const std::string					imageName	= "layer_" + de::toString(layerNdx) + "_sample_" + de::toString(sampleNdx);
1308			const std::string					imageDesc	= "Layer " + de::toString(layerNdx) + " Sample " + de::toString(sampleNdx);
1309			const tcu::ConstPixelBufferAccess	expected	= getSingleSampledAccess(expectedResult, params, sampleNdx, layerNdx);
1310			const tcu::ConstPixelBufferAccess	actual		= getSingleSampledAccess(fmaskResult,	 params, sampleNdx, layerNdx);
1311			const UVec4							threshold	(0);	// should match exactly
1312
1313			const bool ok = tcu::intThresholdCompare(context.getTestContext().getLog(), imageName.c_str(), imageDesc.c_str(),
1314													 expected, actual, threshold, tcu::COMPARE_LOG_RESULT);
1315
1316			if (!ok)
1317				return tcu::TestStatus::fail("Some texels were incorrect");
1318		}
1319	}
1320
1321	return tcu::TestStatus::pass("Pass");
1322}
1323
1324std::string getFormatShortString (const VkFormat format)
1325{
1326	std::string s(de::toLower(getFormatName(format)));
1327	return s.substr(10);
1328}
1329
1330void createShaderFragmentMaskTestsInGroup (tcu::TestCaseGroup* rootGroup, PipelineConstructionType pipelineConstructionType)
1331{
1332	// Per spec, the following formats must support color attachment and sampled image
1333	const VkFormat colorFormats[] =
1334	{
1335		VK_FORMAT_R8G8B8A8_UNORM,
1336		VK_FORMAT_R32_UINT,
1337		VK_FORMAT_R32_SINT,
1338	};
1339
1340	const VkSampleCountFlagBits	sampleCounts[] =
1341	{
1342		VK_SAMPLE_COUNT_2_BIT,
1343		VK_SAMPLE_COUNT_4_BIT,
1344		VK_SAMPLE_COUNT_8_BIT,
1345		VK_SAMPLE_COUNT_16_BIT,
1346	};
1347
1348	const struct SourceCase
1349	{
1350		const char*			name;
1351		deUint32			numLayers;
1352		SampleSource		sampleSource;
1353	} sourceCases[] =
1354	{
1355		{ "image_2d",		1u,	SAMPLE_SOURCE_IMAGE			},
1356		{ "image_2d_array",	3u,	SAMPLE_SOURCE_IMAGE			},
1357		{ "subpass_input",	1u,	SAMPLE_SOURCE_SUBPASS_INPUT	},
1358	};
1359
1360	// Test 1: Compare fragments fetched via FMASK and an ordinary texel fetch
1361	{
1362		for (const VkSampleCountFlagBits* pSampleCount = sampleCounts; pSampleCount != DE_ARRAY_END(sampleCounts); ++pSampleCount)
1363		{
1364			MovePtr<tcu::TestCaseGroup> sampleCountGroup (new tcu::TestCaseGroup(rootGroup->getTestContext(), ("samples_" + de::toString(*pSampleCount)).c_str()));
1365			for (const SourceCase* pSourceCase = sourceCases; pSourceCase != DE_ARRAY_END(sourceCases); ++pSourceCase)
1366			{
1367				// Input attachments cannot be used with dynamic rendering.
1368				if (pSourceCase->sampleSource == SAMPLE_SOURCE_SUBPASS_INPUT && isConstructionTypeShaderObject(pipelineConstructionType))
1369					continue;
1370
1371				MovePtr<tcu::TestCaseGroup> sourceGroup (new tcu::TestCaseGroup(rootGroup->getTestContext(), pSourceCase->name));
1372				for (const VkFormat* pColorFormat = colorFormats; pColorFormat != DE_ARRAY_END(colorFormats); ++pColorFormat)
1373				{
1374					TestParams params;
1375					params.pipelineConstructionType = pipelineConstructionType;
1376					params.renderSize				= UVec2(32, 32);
1377					params.colorFormat				= *pColorFormat;
1378					params.numColorSamples			= *pSampleCount;
1379					params.numLayers				= pSourceCase->numLayers;
1380					params.sampleSource				= pSourceCase->sampleSource;
1381
1382					addFunctionCaseWithPrograms(sourceGroup.get(), getFormatShortString(*pColorFormat), checkRequirements, initPrograms, test, params);
1383				}
1384				sampleCountGroup->addChild(sourceGroup.release());
1385			}
1386			rootGroup->addChild(sampleCountGroup.release());
1387		}
1388	}
1389}
1390
1391} // anonymous ns
1392
1393tcu::TestCaseGroup* createMultisampleShaderFragmentMaskTests (tcu::TestContext& testCtx, PipelineConstructionType pipelineConstructionType)
1394{
1395	const auto	cleanGroup	= [](tcu::TestCaseGroup*, PipelineConstructionType) { SingletonDevice::destroy(); };
1396	const char*	groupName	= "shader_fragment_mask";
1397
1398	// Access raw texel values in a compressed MSAA surface
1399	return createTestGroup(testCtx, groupName, createShaderFragmentMaskTestsInGroup, pipelineConstructionType, cleanGroup);
1400}
1401
1402} // pipeline
1403} // vkt
1404