1/*------------------------------------------------------------------------
2* Vulkan Conformance Tests
3* ------------------------
4*
5* Copyright (c) 2016 The Khronos Group Inc.
6* Copyright (c) 2023 LunarG, Inc.
7* Copyright (c) 2023 Nintendo
8*
9* Licensed under the Apache License, Version 2.0 (the "License");
10* you may not use this file except in compliance with the License.
11* You may obtain a copy of the License at
12*
13*      http://www.apache.org/licenses/LICENSE-2.0
14*
15* Unless required by applicable law or agreed to in writing, software
16* distributed under the License is distributed on an "AS IS" BASIS,
17* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18* See the License for the specific language governing permissions and
19* limitations under the License.
20*
21*//*
22* \file vktPipelineMultisampleShaderBuiltInTests.cpp
23* \brief Multisample Shader BuiltIn Tests
24*//*--------------------------------------------------------------------*/
25
26#include "vktPipelineMultisampleShaderBuiltInTests.hpp"
27#include "vktPipelineMultisampleBaseResolveAndPerSampleFetch.hpp"
28#include "vktPipelineMakeUtil.hpp"
29
30#include "vkBuilderUtil.hpp"
31#include "vkQueryUtil.hpp"
32#include "vkObjUtil.hpp"
33#include "vkImageWithMemory.hpp"
34#include "vkBufferWithMemory.hpp"
35#include "vkBarrierUtil.hpp"
36#include "vkCmdUtil.hpp"
37#include "vkTypeUtil.hpp"
38
39#include "tcuVectorUtil.hpp"
40#include "tcuTestLog.hpp"
41
42#include <set>
43#include <cmath>
44
45using std::set;
46
47namespace vkt
48{
49namespace pipeline
50{
51namespace multisample
52{
53
54using namespace vk;
55
56struct VertexDataNdc
57{
58	VertexDataNdc (const tcu::Vec4& posNdc) : positionNdc(posNdc) {}
59
60	tcu::Vec4 positionNdc;
61};
62
63MultisampleInstanceBase::VertexDataDesc getVertexDataDescriptonNdc (void)
64{
65	MultisampleInstanceBase::VertexDataDesc vertexDataDesc;
66
67	vertexDataDesc.verticesCount	 = 4u;
68	vertexDataDesc.dataStride		 = sizeof(VertexDataNdc);
69	vertexDataDesc.dataSize			 = vertexDataDesc.verticesCount * vertexDataDesc.dataStride;
70	vertexDataDesc.primitiveTopology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
71
72	const VkVertexInputAttributeDescription vertexAttribPositionNdc =
73	{
74		0u,											// deUint32	location;
75		0u,											// deUint32	binding;
76		VK_FORMAT_R32G32B32A32_SFLOAT,				// VkFormat	format;
77		DE_OFFSET_OF(VertexDataNdc, positionNdc),	// deUint32	offset;
78	};
79
80	vertexDataDesc.vertexAttribDescVec.push_back(vertexAttribPositionNdc);
81
82	return vertexDataDesc;
83}
84
85void uploadVertexDataNdc (const Allocation& vertexBufferAllocation, const MultisampleInstanceBase::VertexDataDesc& vertexDataDescripton)
86{
87	std::vector<VertexDataNdc> vertices;
88
89	vertices.push_back(VertexDataNdc(tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f)));
90	vertices.push_back(VertexDataNdc(tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f)));
91	vertices.push_back(VertexDataNdc(tcu::Vec4(-1.0f,  1.0f, 0.0f, 1.0f)));
92	vertices.push_back(VertexDataNdc(tcu::Vec4( 1.0f,  1.0f, 0.0f, 1.0f)));
93
94	deMemcpy(vertexBufferAllocation.getHostPtr(), dataPointer(vertices), static_cast<std::size_t>(vertexDataDescripton.dataSize));
95}
96
97struct VertexDataNdcScreen
98{
99	VertexDataNdcScreen (const tcu::Vec4& posNdc, const tcu::Vec2& posScreen) : positionNdc(posNdc), positionScreen(posScreen) {}
100
101	tcu::Vec4 positionNdc;
102	tcu::Vec2 positionScreen;
103};
104
105MultisampleInstanceBase::VertexDataDesc getVertexDataDescriptonNdcScreen (void)
106{
107	MultisampleInstanceBase::VertexDataDesc vertexDataDesc;
108
109	vertexDataDesc.verticesCount	 = 4u;
110	vertexDataDesc.dataStride		 = sizeof(VertexDataNdcScreen);
111	vertexDataDesc.dataSize			 = vertexDataDesc.verticesCount * vertexDataDesc.dataStride;
112	vertexDataDesc.primitiveTopology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
113
114	const VkVertexInputAttributeDescription vertexAttribPositionNdc =
115	{
116		0u,													// deUint32	location;
117		0u,													// deUint32	binding;
118		VK_FORMAT_R32G32B32A32_SFLOAT,						// VkFormat	format;
119		DE_OFFSET_OF(VertexDataNdcScreen, positionNdc),		// deUint32	offset;
120	};
121
122	vertexDataDesc.vertexAttribDescVec.push_back(vertexAttribPositionNdc);
123
124	const VkVertexInputAttributeDescription vertexAttribPositionScreen =
125	{
126		1u,													// deUint32	location;
127		0u,													// deUint32	binding;
128		VK_FORMAT_R32G32_SFLOAT,							// VkFormat	format;
129		DE_OFFSET_OF(VertexDataNdcScreen, positionScreen),	// deUint32	offset;
130	};
131
132	vertexDataDesc.vertexAttribDescVec.push_back(vertexAttribPositionScreen);
133
134	return vertexDataDesc;
135}
136
137void uploadVertexDataNdcScreen (const Allocation& vertexBufferAllocation, const MultisampleInstanceBase::VertexDataDesc& vertexDataDescripton, const tcu::Vec2& screenSize)
138{
139	std::vector<VertexDataNdcScreen> vertices;
140
141	vertices.push_back(VertexDataNdcScreen(tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f), tcu::Vec2(0.0f, 0.0f)));
142	vertices.push_back(VertexDataNdcScreen(tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f), tcu::Vec2(screenSize.x(), 0.0f)));
143	vertices.push_back(VertexDataNdcScreen(tcu::Vec4(-1.0f,  1.0f, 0.0f, 1.0f), tcu::Vec2(0.0f, screenSize.y())));
144	vertices.push_back(VertexDataNdcScreen(tcu::Vec4( 1.0f,  1.0f, 0.0f, 1.0f), tcu::Vec2(screenSize.x(), screenSize.y())));
145
146	deMemcpy(vertexBufferAllocation.getHostPtr(), dataPointer(vertices), static_cast<std::size_t>(vertexDataDescripton.dataSize));
147}
148
149bool checkForErrorMS (const vk::VkImageCreateInfo& imageMSInfo, const std::vector<tcu::ConstPixelBufferAccess>& dataPerSample, const deUint32 errorCompNdx)
150{
151	const deUint32 numSamples = static_cast<deUint32>(imageMSInfo.samples);
152
153	for (deUint32 z = 0u; z < imageMSInfo.extent.depth;  ++z)
154	for (deUint32 y = 0u; y < imageMSInfo.extent.height; ++y)
155	for (deUint32 x = 0u; x < imageMSInfo.extent.width;  ++x)
156	{
157		for (deUint32 sampleNdx = 0u; sampleNdx < numSamples; ++sampleNdx)
158		{
159			const deUint32 errorComponent = dataPerSample[sampleNdx].getPixelUint(x, y, z)[errorCompNdx];
160
161			if (errorComponent > 0)
162				return true;
163		}
164	}
165
166	return false;
167}
168
169bool checkForErrorRS (const vk::VkImageCreateInfo& imageRSInfo, const tcu::ConstPixelBufferAccess& dataRS, const deUint32 errorCompNdx)
170{
171	for (deUint32 z = 0u; z < imageRSInfo.extent.depth;  ++z)
172	for (deUint32 y = 0u; y < imageRSInfo.extent.height; ++y)
173	for (deUint32 x = 0u; x < imageRSInfo.extent.width;  ++x)
174	{
175		const deUint32 errorComponent = dataRS.getPixelUint(x, y, z)[errorCompNdx];
176
177		if (errorComponent > 0)
178			return true;
179	}
180
181	return false;
182}
183
184template <typename CaseClassName>
185class MSCase : public MSCaseBaseResolveAndPerSampleFetch
186{
187public:
188								MSCase			(tcu::TestContext&		testCtx,
189												 const std::string&		name,
190												 const ImageMSParams&	imageMSParams)
191								: MSCaseBaseResolveAndPerSampleFetch(testCtx, name, imageMSParams) {}
192
193	virtual void				checkSupport	(Context& context) const;
194	void						init			(void);
195	void						initPrograms	(vk::SourceCollections& programCollection) const;
196	TestInstance*				createInstance	(Context&				context) const;
197	static MultisampleCaseBase*	createCase		(tcu::TestContext&		testCtx,
198												 const std::string&		name,
199												 const ImageMSParams&	imageMSParams);
200};
201#ifndef CTS_USES_VULKANSC
202template <typename CaseClassName>
203void MSCase<CaseClassName>::checkSupport(Context& context) const
204{
205	checkGraphicsPipelineLibrarySupport(context);
206}
207#endif // CTS_USES_VULKANSC
208
209template <typename CaseClassName>
210MultisampleCaseBase* MSCase<CaseClassName>::createCase (tcu::TestContext& testCtx, const std::string& name, const ImageMSParams& imageMSParams)
211{
212	return new MSCase<CaseClassName>(testCtx, name, imageMSParams);
213}
214
215template <typename InstanceClassName>
216class MSInstance : public MSInstanceBaseResolveAndPerSampleFetch
217{
218public:
219													MSInstance				(Context&											context,
220																			 const ImageMSParams&								imageMSParams)
221													: MSInstanceBaseResolveAndPerSampleFetch(context, imageMSParams) {}
222
223	VertexDataDesc									getVertexDataDescripton	(void) const;
224	void											uploadVertexData		(const Allocation&									vertexBufferAllocation,
225																			 const VertexDataDesc&								vertexDataDescripton) const;
226
227	tcu::TestStatus									verifyImageData			(const vk::VkImageCreateInfo&						imageMSInfo,
228																			 const vk::VkImageCreateInfo&						imageRSInfo,
229																			 const std::vector<tcu::ConstPixelBufferAccess>&	dataPerSample,
230																			 const tcu::ConstPixelBufferAccess&					dataRS) const;
231
232	virtual VkPipelineMultisampleStateCreateInfo	getMSStateCreateInfo	(const ImageMSParams&								imageMSParams) const
233	{
234		return MSInstanceBaseResolveAndPerSampleFetch::getMSStateCreateInfo(imageMSParams);
235	}
236};
237
238class MSInstanceSampleID;
239
240template<> MultisampleInstanceBase::VertexDataDesc MSInstance<MSInstanceSampleID>::getVertexDataDescripton (void) const
241{
242	return getVertexDataDescriptonNdc();
243}
244
245template<> void MSInstance<MSInstanceSampleID>::uploadVertexData (const Allocation& vertexBufferAllocation, const VertexDataDesc& vertexDataDescripton) const
246{
247	uploadVertexDataNdc(vertexBufferAllocation, vertexDataDescripton);
248}
249
250template<> tcu::TestStatus MSInstance<MSInstanceSampleID>::verifyImageData	(const vk::VkImageCreateInfo&						imageMSInfo,
251																			 const vk::VkImageCreateInfo&						imageRSInfo,
252																			 const std::vector<tcu::ConstPixelBufferAccess>&	dataPerSample,
253																			 const tcu::ConstPixelBufferAccess&					dataRS) const
254{
255	DE_UNREF(imageRSInfo);
256	DE_UNREF(dataRS);
257
258	const deUint32 numSamples = static_cast<deUint32>(imageMSInfo.samples);
259
260	for (deUint32 sampleNdx = 0u; sampleNdx < numSamples; ++sampleNdx)
261	{
262		for (deUint32 z = 0u; z < imageMSInfo.extent.depth;  ++z)
263		for (deUint32 y = 0u; y < imageMSInfo.extent.height; ++y)
264		for (deUint32 x = 0u; x < imageMSInfo.extent.width;  ++x)
265		{
266			const deUint32 sampleID = dataPerSample[sampleNdx].getPixelUint(x, y, z).x();
267
268			if (sampleID != sampleNdx)
269				return tcu::TestStatus::fail("gl_SampleID does not have correct value");
270		}
271	}
272
273	return tcu::TestStatus::pass("Passed");
274}
275
276class MSCaseSampleID;
277
278template<> void MSCase<MSCaseSampleID>::checkSupport (Context& context) const
279{
280	checkGraphicsPipelineLibrarySupport(context);
281	context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_SAMPLE_RATE_SHADING);
282}
283
284template<> void MSCase<MSCaseSampleID>::init (void)
285{
286	m_testCtx.getLog()
287		<< tcu::TestLog::Message
288		<< "Writing gl_SampleID to the red channel of the texture and verifying texture values.\n"
289		<< "Expecting value N at sample index N of a multisample texture.\n"
290		<< tcu::TestLog::EndMessage;
291
292	MultisampleCaseBase::init();
293}
294
295template<> void MSCase<MSCaseSampleID>::initPrograms (vk::SourceCollections& programCollection) const
296{
297	MSCaseBaseResolveAndPerSampleFetch::initPrograms(programCollection);
298
299	// Create vertex shader
300	std::ostringstream vs;
301
302	vs << "#version 440\n"
303		<< "layout(location = 0) in vec4 vs_in_position_ndc;\n"
304		<< "\n"
305		<< "out gl_PerVertex {\n"
306		<< "	vec4  gl_Position;\n"
307		<< "};\n"
308		<< "void main (void)\n"
309		<< "{\n"
310		<< "	gl_Position	= vs_in_position_ndc;\n"
311		<< "}\n";
312
313	programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
314
315	// Create fragment shader
316	std::ostringstream fs;
317
318	fs << "#version 440\n"
319		<< "\n"
320		<< "layout(location = 0) out vec4 fs_out_color;\n"
321		<< "\n"
322		<< "void main (void)\n"
323		<< "{\n"
324		<< "	fs_out_color = vec4(float(gl_SampleID) / float(255), 0.0, 0.0, 1.0);\n"
325		<< "}\n";
326
327	programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
328}
329
330template<> TestInstance* MSCase<MSCaseSampleID>::createInstance (Context& context) const
331{
332	return new MSInstance<MSInstanceSampleID>(context, m_imageMSParams);
333}
334
335class MSInstanceSamplePosDistribution;
336
337template<> MultisampleInstanceBase::VertexDataDesc MSInstance<MSInstanceSamplePosDistribution>::getVertexDataDescripton (void) const
338{
339	return getVertexDataDescriptonNdc();
340}
341
342template<> void MSInstance<MSInstanceSamplePosDistribution>::uploadVertexData (const Allocation& vertexBufferAllocation, const VertexDataDesc& vertexDataDescripton) const
343{
344	uploadVertexDataNdc(vertexBufferAllocation, vertexDataDescripton);
345}
346
347template<> tcu::TestStatus MSInstance<MSInstanceSamplePosDistribution>::verifyImageData	(const vk::VkImageCreateInfo&						imageMSInfo,
348																						 const vk::VkImageCreateInfo&						imageRSInfo,
349																						 const std::vector<tcu::ConstPixelBufferAccess>&	dataPerSample,
350																						 const tcu::ConstPixelBufferAccess&					dataRS) const
351{
352	const deUint32 numSamples = static_cast<deUint32>(imageMSInfo.samples);
353
354	// approximate Bates distribution as normal
355	const float variance = (1.0f / (12.0f * (float)numSamples));
356	const float standardDeviation = deFloatSqrt(variance);
357
358	// 95% of means of sample positions are within 2 standard deviations if
359	// they were randomly assigned. Sample patterns are expected to be more
360	// uniform than a random pattern.
361	const float distanceThreshold = 2.0f * standardDeviation;
362
363	for (deUint32 z = 0u; z < imageRSInfo.extent.depth;  ++z)
364	for (deUint32 y = 0u; y < imageRSInfo.extent.height; ++y)
365	for (deUint32 x = 0u; x < imageRSInfo.extent.width;  ++x)
366	{
367		const deUint32 errorComponent = dataRS.getPixelUint(x, y, z).z();
368
369		if (errorComponent > 0)
370			return tcu::TestStatus::fail("gl_SamplePosition is not within interval [0,1]");
371
372		if (numSamples >= VK_SAMPLE_COUNT_4_BIT)
373		{
374			const tcu::Vec2 averageSamplePos	= tcu::Vec2((float)dataRS.getPixelUint(x, y, z).x() / 255.0f, (float)dataRS.getPixelUint(x, y, z).y() / 255.0f);
375			const tcu::Vec2	distanceFromCenter	= tcu::abs(averageSamplePos - tcu::Vec2(0.5f, 0.5f));
376
377			if (distanceFromCenter.x() > distanceThreshold || distanceFromCenter.y() > distanceThreshold)
378				return tcu::TestStatus::fail("Sample positions are not uniformly distributed within the pixel");
379		}
380	}
381
382	for (deUint32 z = 0u; z < imageMSInfo.extent.depth;  ++z)
383	for (deUint32 y = 0u; y < imageMSInfo.extent.height; ++y)
384	for (deUint32 x = 0u; x < imageMSInfo.extent.width;  ++x)
385	{
386		std::vector<tcu::Vec2> samplePositions(numSamples);
387
388		for (deUint32 sampleNdx = 0u; sampleNdx < numSamples; ++sampleNdx)
389		{
390			const deUint32 errorComponent = dataPerSample[sampleNdx].getPixelUint(x, y, z).z();
391
392			if (errorComponent > 0)
393				return tcu::TestStatus::fail("gl_SamplePosition is not within interval [0,1]");
394
395			samplePositions[sampleNdx] = tcu::Vec2( (float)dataPerSample[sampleNdx].getPixelUint(x, y, z).x() / 255.0f,
396													(float)dataPerSample[sampleNdx].getPixelUint(x, y, z).y() / 255.0f);
397		}
398
399		for (deUint32 sampleNdxA = 0u;				sampleNdxA < numSamples; ++sampleNdxA)
400		for (deUint32 sampleNdxB = sampleNdxA + 1u; sampleNdxB < numSamples; ++sampleNdxB)
401		{
402			if (samplePositions[sampleNdxA] == samplePositions[sampleNdxB])
403				return tcu::TestStatus::fail("Two samples have the same position");
404		}
405
406		if (numSamples >= VK_SAMPLE_COUNT_4_BIT)
407		{
408			tcu::Vec2 averageSamplePos(0.0f, 0.0f);
409
410			for (deUint32 sampleNdx = 0u; sampleNdx < numSamples; ++sampleNdx)
411			{
412				averageSamplePos.x() += samplePositions[sampleNdx].x();
413				averageSamplePos.y() += samplePositions[sampleNdx].y();
414			}
415
416			averageSamplePos.x() /= (float)numSamples;
417			averageSamplePos.y() /= (float)numSamples;
418
419			const tcu::Vec2	distanceFromCenter = tcu::abs(averageSamplePos - tcu::Vec2(0.5f, 0.5f));
420
421			if (distanceFromCenter.x() > distanceThreshold || distanceFromCenter.y() > distanceThreshold)
422				return tcu::TestStatus::fail("Sample positions are not uniformly distributed within the pixel");
423		}
424	}
425
426	return tcu::TestStatus::pass("Passed");
427}
428
429class MSCaseSamplePosDistribution;
430
431template<> void MSCase<MSCaseSamplePosDistribution>::checkSupport (Context& context) const
432{
433	checkGraphicsPipelineLibrarySupport(context);
434	context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_SAMPLE_RATE_SHADING);
435}
436
437template<> void MSCase<MSCaseSamplePosDistribution>::init (void)
438{
439	m_testCtx.getLog()
440		<< tcu::TestLog::Message
441		<< "Verifying gl_SamplePosition value with multisample targets:\n"
442		<< "	a) Expect legal sample position.\n"
443		<< "	b) Sample position is unique within the set of all sample positions of a pixel.\n"
444		<< "	c) Sample position distribution is uniform or almost uniform.\n"
445		<< tcu::TestLog::EndMessage;
446
447	MultisampleCaseBase::init();
448}
449
450template<> void MSCase<MSCaseSamplePosDistribution>::initPrograms (vk::SourceCollections& programCollection) const
451{
452	MSCaseBaseResolveAndPerSampleFetch::initPrograms(programCollection);
453
454	// Create vertex shader
455	std::ostringstream vs;
456
457	vs << "#version 440\n"
458		<< "layout(location = 0) in vec4 vs_in_position_ndc;\n"
459		<< "\n"
460		<< "out gl_PerVertex {\n"
461		<< "	vec4  gl_Position;\n"
462		<< "};\n"
463		<< "void main (void)\n"
464		<< "{\n"
465		<< "	gl_Position	= vs_in_position_ndc;\n"
466		<< "}\n";
467
468	programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
469
470	// Create fragment shader
471	std::ostringstream fs;
472
473	fs << "#version 440\n"
474		<< "\n"
475		<< "layout(location = 0) out vec4 fs_out_color;\n"
476		<< "\n"
477		<< "void main (void)\n"
478		<< "{\n"
479		<< "	if (gl_SamplePosition.x < 0.0 || gl_SamplePosition.x > 1.0 || gl_SamplePosition.y < 0.0 || gl_SamplePosition.y > 1.0)\n"
480		"		fs_out_color = vec4(0.0, 0.0, 1.0, 1.0);\n"
481		"	else\n"
482		"		fs_out_color = vec4(gl_SamplePosition.x, gl_SamplePosition.y, 0.0, 1.0);\n"
483		"}\n";
484
485	programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
486}
487
488template<> TestInstance* MSCase<MSCaseSamplePosDistribution>::createInstance (Context& context) const
489{
490	return new MSInstance<MSInstanceSamplePosDistribution>(context, m_imageMSParams);
491}
492
493class MSInstanceSamplePosCorrectness;
494
495template<> MultisampleInstanceBase::VertexDataDesc MSInstance<MSInstanceSamplePosCorrectness>::getVertexDataDescripton (void) const
496{
497	return getVertexDataDescriptonNdcScreen();
498}
499
500template<> void MSInstance<MSInstanceSamplePosCorrectness>::uploadVertexData (const Allocation& vertexBufferAllocation, const VertexDataDesc& vertexDataDescripton) const
501{
502	const tcu::UVec3 layerSize = getLayerSize(IMAGE_TYPE_2D, m_imageMSParams.imageSize);
503
504	uploadVertexDataNdcScreen(vertexBufferAllocation, vertexDataDescripton, tcu::Vec2(static_cast<float>(layerSize.x()), static_cast<float>(layerSize.y())));
505}
506
507template<> tcu::TestStatus MSInstance<MSInstanceSamplePosCorrectness>::verifyImageData	(const vk::VkImageCreateInfo&						imageMSInfo,
508																						 const vk::VkImageCreateInfo&						imageRSInfo,
509																						 const std::vector<tcu::ConstPixelBufferAccess>&	dataPerSample,
510																						 const tcu::ConstPixelBufferAccess&					dataRS) const
511{
512	if (checkForErrorMS(imageMSInfo, dataPerSample, 0))
513		return tcu::TestStatus::fail("Varying values are not sampled at gl_SamplePosition");
514
515	if (checkForErrorRS(imageRSInfo, dataRS, 0))
516		return tcu::TestStatus::fail("Varying values are not sampled at gl_SamplePosition");
517
518	return tcu::TestStatus::pass("Passed");
519}
520
521class MSCaseSamplePosCorrectness;
522
523template<> void MSCase<MSCaseSamplePosCorrectness>::checkSupport (Context& context) const
524{
525	checkGraphicsPipelineLibrarySupport(context);
526	context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_SAMPLE_RATE_SHADING);
527}
528
529template<> void MSCase<MSCaseSamplePosCorrectness>::init (void)
530{
531	m_testCtx.getLog()
532		<< tcu::TestLog::Message
533		<< "Verifying gl_SamplePosition correctness:\n"
534		<< "	1) Varying values should be sampled at the sample position.\n"
535		<< "		=> fract(position_screen) == gl_SamplePosition\n"
536		<< tcu::TestLog::EndMessage;
537
538	MultisampleCaseBase::init();
539}
540
541template<> void MSCase<MSCaseSamplePosCorrectness>::initPrograms (vk::SourceCollections& programCollection) const
542{
543	MSCaseBaseResolveAndPerSampleFetch::initPrograms(programCollection);
544
545	// Create vertex shaders
546	std::ostringstream vs;
547
548	vs	<< "#version 440\n"
549		<< "layout(location = 0) in vec4 vs_in_position_ndc;\n"
550		<< "layout(location = 1) in vec2 vs_in_position_screen;\n"
551		<< "\n"
552		<< "layout(location = 0) sample out vec2 vs_out_position_screen;\n"
553		<< "\n"
554		<< "out gl_PerVertex {\n"
555		<< "	vec4  gl_Position;\n"
556		<< "};\n"
557		<< "void main (void)\n"
558		<< "{\n"
559		<< "	gl_Position				= vs_in_position_ndc;\n"
560		<< "	vs_out_position_screen	= vs_in_position_screen;\n"
561		<< "}\n";
562
563	programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
564
565	// Create fragment shader
566	std::ostringstream fs;
567
568	fs	<< "#version 440\n"
569		<< "layout(location = 0) sample in vec2 fs_in_position_screen;\n"
570		<< "\n"
571		<< "layout(location = 0) out vec4 fs_out_color;\n"
572		<< "\n"
573		<< "void main (void)\n"
574		<< "{\n"
575		<< "	const float threshold = 0.15625; // 4 subpixel bits. Assume 3 accurate bits + 0.03125 for other errors\n"
576		<< "	const ivec2 nearby_pixel = ivec2(floor(fs_in_position_screen));\n"
577		<< "	bool ok	= false;\n"
578		<< "\n"
579		<< "	// sample at edge + inaccuaries may cause us to round to any neighboring pixel\n"
580		<< "	// check all neighbors for any match\n"
581		<< "	for (int dy = -1; dy <= 1; ++dy)\n"
582		<< "	for (int dx = -1; dx <= 1; ++dx)\n"
583		<< "	{\n"
584		<< "		ivec2 current_pixel			= nearby_pixel + ivec2(dx, dy);\n"
585		<< "		vec2 position_inside_pixel	= vec2(current_pixel) + gl_SamplePosition;\n"
586		<< "		vec2 position_diff			= abs(position_inside_pixel - fs_in_position_screen);\n"
587		<< "\n"
588		<< "		if (all(lessThan(position_diff, vec2(threshold))))\n"
589		<< "			ok = true;\n"
590		<< "	}\n"
591		<< "\n"
592		<< "	if (ok)\n"
593		<< "		fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
594		<< "	else\n"
595		<< "		fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
596		<< "}\n";
597
598	programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
599}
600
601template<> TestInstance* MSCase<MSCaseSamplePosCorrectness>::createInstance (Context& context) const
602{
603	return new MSInstance<MSInstanceSamplePosCorrectness>(context, m_imageMSParams);
604}
605
606class MSInstanceSampleMaskPattern : public MSInstanceBaseResolveAndPerSampleFetch
607{
608public:
609											MSInstanceSampleMaskPattern	(Context&											context,
610																		 const ImageMSParams&								imageMSParams);
611
612	VkPipelineMultisampleStateCreateInfo	getMSStateCreateInfo		(const ImageMSParams&								imageMSParams) const;
613
614	const VkDescriptorSetLayout*			createMSPassDescSetLayout	(const ImageMSParams&								imageMSParams);
615
616	const VkDescriptorSet*					createMSPassDescSet			(const ImageMSParams&								imageMSParams,
617																		 const VkDescriptorSetLayout*						descSetLayout);
618
619	VertexDataDesc							getVertexDataDescripton		(void) const;
620
621	void									uploadVertexData			(const Allocation&									vertexBufferAllocation,
622																		 const VertexDataDesc&								vertexDataDescripton) const;
623
624	tcu::TestStatus							verifyImageData				(const vk::VkImageCreateInfo&						imageMSInfo,
625																		 const vk::VkImageCreateInfo&						imageRSInfo,
626																		 const std::vector<tcu::ConstPixelBufferAccess>&	dataPerSample,
627																		 const tcu::ConstPixelBufferAccess&					dataRS) const;
628protected:
629
630	VkSampleMask					m_sampleMask;
631	Move<VkDescriptorSetLayout>		m_descriptorSetLayout;
632	Move<VkDescriptorPool>			m_descriptorPool;
633	Move<VkDescriptorSet>			m_descriptorSet;
634	de::MovePtr<BufferWithMemory>	m_buffer;
635};
636
637MSInstanceSampleMaskPattern::MSInstanceSampleMaskPattern (Context& context, const ImageMSParams& imageMSParams) : MSInstanceBaseResolveAndPerSampleFetch(context, imageMSParams)
638{
639	m_sampleMask = 0xAAAAAAAAu & ((1u << imageMSParams.numSamples) - 1u);
640}
641
642VkPipelineMultisampleStateCreateInfo MSInstanceSampleMaskPattern::getMSStateCreateInfo (const ImageMSParams& imageMSParams) const
643{
644	const VkPipelineMultisampleStateCreateInfo multisampleStateInfo =
645	{
646		VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,		// VkStructureType							sType;
647		DE_NULL,														// const void*								pNext;
648		(VkPipelineMultisampleStateCreateFlags)0u,						// VkPipelineMultisampleStateCreateFlags	flags;
649		imageMSParams.numSamples,										// VkSampleCountFlagBits					rasterizationSamples;
650		VK_FALSE,														// VkBool32									sampleShadingEnable;
651		imageMSParams.shadingRate,										// float									minSampleShading;
652		&m_sampleMask,													// const VkSampleMask*						pSampleMask;
653		VK_FALSE,														// VkBool32									alphaToCoverageEnable;
654		VK_FALSE,														// VkBool32									alphaToOneEnable;
655	};
656
657	return multisampleStateInfo;
658}
659
660const VkDescriptorSetLayout* MSInstanceSampleMaskPattern::createMSPassDescSetLayout (const ImageMSParams& imageMSParams)
661{
662	DE_UNREF(imageMSParams);
663
664	const DeviceInterface&		deviceInterface = m_context.getDeviceInterface();
665	const VkDevice				device			= m_context.getDevice();
666
667	// Create descriptor set layout
668	m_descriptorSetLayout = DescriptorSetLayoutBuilder()
669		.addSingleBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_FRAGMENT_BIT)
670		.build(deviceInterface, device);
671
672	return &m_descriptorSetLayout.get();
673}
674
675const VkDescriptorSet* MSInstanceSampleMaskPattern::createMSPassDescSet (const ImageMSParams& imageMSParams, const VkDescriptorSetLayout* descSetLayout)
676{
677	DE_UNREF(imageMSParams);
678
679	const DeviceInterface&		deviceInterface = m_context.getDeviceInterface();
680	const VkDevice				device			= m_context.getDevice();
681	Allocator&					allocator		= m_context.getDefaultAllocator();
682
683	// Create descriptor pool
684	m_descriptorPool = DescriptorPoolBuilder()
685		.addType(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1u)
686		.build(deviceInterface, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
687
688	// Create descriptor set
689	m_descriptorSet = makeDescriptorSet(deviceInterface, device, *m_descriptorPool, *descSetLayout);
690
691	const VkBufferCreateInfo bufferSampleMaskInfo = makeBufferCreateInfo(sizeof(VkSampleMask), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
692
693	m_buffer = de::MovePtr<BufferWithMemory>(new BufferWithMemory(deviceInterface, device, allocator, bufferSampleMaskInfo, MemoryRequirement::HostVisible));
694
695	deMemcpy(m_buffer->getAllocation().getHostPtr(), &m_sampleMask, sizeof(VkSampleMask));
696
697	flushAlloc(deviceInterface, device, m_buffer->getAllocation());
698
699	const VkDescriptorBufferInfo descBufferInfo = makeDescriptorBufferInfo(**m_buffer, 0u, sizeof(VkSampleMask));
700
701	DescriptorSetUpdateBuilder()
702		.writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &descBufferInfo)
703		.update(deviceInterface, device);
704
705	return &m_descriptorSet.get();
706}
707
708MultisampleInstanceBase::VertexDataDesc MSInstanceSampleMaskPattern::getVertexDataDescripton (void) const
709{
710	return getVertexDataDescriptonNdc();
711}
712
713void MSInstanceSampleMaskPattern::uploadVertexData (const Allocation& vertexBufferAllocation, const VertexDataDesc& vertexDataDescripton) const
714{
715	uploadVertexDataNdc(vertexBufferAllocation, vertexDataDescripton);
716}
717
718tcu::TestStatus	MSInstanceSampleMaskPattern::verifyImageData	(const vk::VkImageCreateInfo&						imageMSInfo,
719																 const vk::VkImageCreateInfo&						imageRSInfo,
720																 const std::vector<tcu::ConstPixelBufferAccess>&	dataPerSample,
721																 const tcu::ConstPixelBufferAccess&					dataRS) const
722{
723	DE_UNREF(imageRSInfo);
724	DE_UNREF(dataRS);
725
726	if (checkForErrorMS(imageMSInfo, dataPerSample, 0))
727		return tcu::TestStatus::fail("gl_SampleMaskIn bits have not been killed by pSampleMask state");
728
729	return tcu::TestStatus::pass("Passed");
730}
731
732class MSCaseSampleMaskPattern;
733
734template<> void MSCase<MSCaseSampleMaskPattern>::init (void)
735{
736	m_testCtx.getLog()
737		<< tcu::TestLog::Message
738		<< "Verifying gl_SampleMaskIn value with pSampleMask state. gl_SampleMaskIn does not contain any bits set that are have been killed by pSampleMask state. Expecting:\n"
739		<< "Expected result: gl_SampleMaskIn AND ~(pSampleMask) should be zero.\n"
740		<< tcu::TestLog::EndMessage;
741
742	MultisampleCaseBase::init();
743}
744
745template<> void MSCase<MSCaseSampleMaskPattern>::initPrograms (vk::SourceCollections& programCollection) const
746{
747	MSCaseBaseResolveAndPerSampleFetch::initPrograms(programCollection);
748
749	// Create vertex shader
750	std::ostringstream vs;
751
752	vs << "#version 440\n"
753		<< "layout(location = 0) in vec4 vs_in_position_ndc;\n"
754		<< "\n"
755		<< "out gl_PerVertex {\n"
756		<< "	vec4  gl_Position;\n"
757		<< "};\n"
758		<< "void main (void)\n"
759		<< "{\n"
760		<< "	gl_Position	= vs_in_position_ndc;\n"
761		<< "}\n";
762
763	programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
764
765	// Create fragment shader
766	std::ostringstream fs;
767
768	fs << "#version 440\n"
769		<< "\n"
770		<< "layout(location = 0) out vec4 fs_out_color;\n"
771		<< "\n"
772		<< "layout(set = 0, binding = 0, std140) uniform SampleMaskBlock\n"
773		<< "{\n"
774		<< "	int sampleMaskPattern;\n"
775		<< "};"
776		<< "\n"
777		<< "void main (void)\n"
778		<< "{\n"
779		<< "	if ((gl_SampleMaskIn[0] & ~sampleMaskPattern) != 0)\n"
780		<< "		fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
781		<< "	else\n"
782		<< "		fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
783		<< "}\n";
784
785	programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
786}
787
788template<> TestInstance* MSCase<MSCaseSampleMaskPattern>::createInstance (Context& context) const
789{
790	return new MSInstanceSampleMaskPattern(context, m_imageMSParams);
791}
792
793class MSInstanceSampleMaskBitCount;
794
795template<> MultisampleInstanceBase::VertexDataDesc MSInstance<MSInstanceSampleMaskBitCount>::getVertexDataDescripton (void) const
796{
797	return getVertexDataDescriptonNdc();
798}
799
800template<> void MSInstance<MSInstanceSampleMaskBitCount>::uploadVertexData (const Allocation& vertexBufferAllocation, const VertexDataDesc& vertexDataDescripton) const
801{
802	uploadVertexDataNdc(vertexBufferAllocation, vertexDataDescripton);
803}
804
805template<> tcu::TestStatus MSInstance<MSInstanceSampleMaskBitCount>::verifyImageData	(const vk::VkImageCreateInfo&						imageMSInfo,
806																						 const vk::VkImageCreateInfo&						imageRSInfo,
807																						 const std::vector<tcu::ConstPixelBufferAccess>&	dataPerSample,
808																						 const tcu::ConstPixelBufferAccess&					dataRS) const
809{
810	DE_UNREF(imageRSInfo);
811	DE_UNREF(dataRS);
812
813	if (checkForErrorMS(imageMSInfo, dataPerSample, 0))
814		return tcu::TestStatus::fail("gl_SampleMaskIn has an illegal number of bits for some shader invocations");
815
816	return tcu::TestStatus::pass("Passed");
817}
818
819class MSCaseSampleMaskBitCount;
820
821template<> void MSCase<MSCaseSampleMaskBitCount>::checkSupport (Context& context) const
822{
823	checkGraphicsPipelineLibrarySupport(context);
824	context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_SAMPLE_RATE_SHADING);
825}
826
827template<> void MSCase<MSCaseSampleMaskBitCount>::init (void)
828{
829	m_testCtx.getLog()
830		<< tcu::TestLog::Message
831		<< "Verifying gl_SampleMaskIn.\n"
832		<< "	Fragment shader will be invoked numSamples times.\n"
833		<< "	=> gl_SampleMaskIn should have a number of bits that depends on the shading rate.\n"
834		<< tcu::TestLog::EndMessage;
835
836	MultisampleCaseBase::init();
837}
838
839template<> void MSCase<MSCaseSampleMaskBitCount>::initPrograms (vk::SourceCollections& programCollection) const
840{
841	MSCaseBaseResolveAndPerSampleFetch::initPrograms(programCollection);
842
843	// Create vertex shader
844	std::ostringstream vs;
845
846	vs << "#version 440\n"
847		<< "layout(location = 0) in vec4 vs_in_position_ndc;\n"
848		<< "\n"
849		<< "out gl_PerVertex {\n"
850		<< "	vec4  gl_Position;\n"
851		<< "};\n"
852		<< "void main (void)\n"
853		<< "{\n"
854		<< "	gl_Position	= vs_in_position_ndc;\n"
855		<< "}\n";
856
857	programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
858
859	// Create fragment shader
860	std::ostringstream fs;
861
862	// The worst case scenario would be all invocations except one covering a single sample, and then one invocation covering the rest.
863	const int minInvocations	= static_cast<int>(std::ceil(static_cast<float>(m_imageMSParams.numSamples) * m_imageMSParams.shadingRate));
864	const int minCount			= 1;
865	const int maxCount			= m_imageMSParams.numSamples - (minInvocations - 1);
866
867	fs << "#version 440\n"
868		<< "\n"
869		<< "layout(location = 0) out vec4 fs_out_color;\n"
870		<< "\n"
871		<< "void main (void)\n"
872		<< "{\n"
873		<< "	const int maskBitCount = bitCount(gl_SampleMaskIn[0]);\n"
874		<< "\n"
875		<< "	if (maskBitCount < " << minCount << " || maskBitCount > " << maxCount << ")\n"
876		<< "		fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
877		<< "	else\n"
878		<< "		fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
879		<< "}\n";
880
881	programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
882}
883
884template<> TestInstance* MSCase<MSCaseSampleMaskBitCount>::createInstance (Context& context) const
885{
886	return new MSInstance<MSInstanceSampleMaskBitCount>(context, m_imageMSParams);
887}
888
889class MSInstanceSampleMaskCorrectBit;
890
891template<> MultisampleInstanceBase::VertexDataDesc MSInstance<MSInstanceSampleMaskCorrectBit>::getVertexDataDescripton (void) const
892{
893	return getVertexDataDescriptonNdc();
894}
895
896template<> void MSInstance<MSInstanceSampleMaskCorrectBit>::uploadVertexData (const Allocation& vertexBufferAllocation, const VertexDataDesc& vertexDataDescripton) const
897{
898	uploadVertexDataNdc(vertexBufferAllocation, vertexDataDescripton);
899}
900
901template<> tcu::TestStatus MSInstance<MSInstanceSampleMaskCorrectBit>::verifyImageData	(const vk::VkImageCreateInfo&						imageMSInfo,
902																						 const vk::VkImageCreateInfo&						imageRSInfo,
903																						 const std::vector<tcu::ConstPixelBufferAccess>&	dataPerSample,
904																						 const tcu::ConstPixelBufferAccess&					dataRS) const
905{
906	DE_UNREF(imageRSInfo);
907	DE_UNREF(dataRS);
908
909	if (checkForErrorMS(imageMSInfo, dataPerSample, 0))
910		return tcu::TestStatus::fail("The bit corresponsing to current gl_SampleID is not set in gl_SampleMaskIn");
911
912	return tcu::TestStatus::pass("Passed");
913}
914
915class MSCaseSampleMaskCorrectBit;
916
917template<> void MSCase<MSCaseSampleMaskCorrectBit>::checkSupport (Context& context) const
918{
919	checkGraphicsPipelineLibrarySupport(context);
920	context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_SAMPLE_RATE_SHADING);
921}
922
923template<> void MSCase<MSCaseSampleMaskCorrectBit>::init (void)
924{
925	m_testCtx.getLog()
926		<< tcu::TestLog::Message
927		<< "Verifying gl_SampleMaskIn.\n"
928		<< "	Fragment shader will be invoked numSamples times.\n"
929		<< "	=> In each invocation gl_SampleMaskIn should have the bit set that corresponds to gl_SampleID.\n"
930		<< tcu::TestLog::EndMessage;
931
932	MultisampleCaseBase::init();
933}
934
935template<> void MSCase<MSCaseSampleMaskCorrectBit>::initPrograms (vk::SourceCollections& programCollection) const
936{
937	MSCaseBaseResolveAndPerSampleFetch::initPrograms(programCollection);
938
939	// Create vertex shader
940	std::ostringstream vs;
941
942	vs << "#version 440\n"
943		<< "layout(location = 0) in vec4 vs_in_position_ndc;\n"
944		<< "\n"
945		<< "out gl_PerVertex {\n"
946		<< "	vec4  gl_Position;\n"
947		<< "};\n"
948		<< "void main (void)\n"
949		<< "{\n"
950		<< "	gl_Position	= vs_in_position_ndc;\n"
951		<< "}\n";
952
953	programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
954
955	// Create fragment shader
956	std::ostringstream fs;
957
958	fs << "#version 440\n"
959		<< "\n"
960		<< "layout(location = 0) out vec4 fs_out_color;\n"
961		<< "\n"
962		<< "void main (void)\n"
963		<< "{\n"
964		<< "	if (((gl_SampleMaskIn[0] >> gl_SampleID) & 0x01) == 0x01)\n"
965		<< "		fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
966		<< "	else\n"
967		<< "		fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
968		<< "}\n";
969
970	programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
971}
972
973template<> TestInstance* MSCase<MSCaseSampleMaskCorrectBit>::createInstance (Context& context) const
974{
975	return new MSInstance<MSInstanceSampleMaskCorrectBit>(context, m_imageMSParams);
976}
977
978class MSInstanceSampleMaskWrite;
979
980template<> MultisampleInstanceBase::VertexDataDesc MSInstance<MSInstanceSampleMaskWrite>::getVertexDataDescripton (void) const
981{
982	return getVertexDataDescriptonNdc();
983}
984
985template<> void MSInstance<MSInstanceSampleMaskWrite>::uploadVertexData (const Allocation& vertexBufferAllocation, const VertexDataDesc& vertexDataDescripton) const
986{
987	uploadVertexDataNdc(vertexBufferAllocation, vertexDataDescripton);
988}
989
990//! Creates VkPipelineMultisampleStateCreateInfo with sample shading disabled.
991template<> VkPipelineMultisampleStateCreateInfo MSInstance<MSInstanceSampleMaskWrite>::getMSStateCreateInfo (const ImageMSParams& imageMSParams) const
992{
993	const VkPipelineMultisampleStateCreateInfo multisampleStateInfo =
994	{
995		VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,	// VkStructureType							sType;
996		DE_NULL,													// const void*								pNext;
997		(VkPipelineMultisampleStateCreateFlags)0u,					// VkPipelineMultisampleStateCreateFlags	flags;
998		imageMSParams.numSamples,									// VkSampleCountFlagBits					rasterizationSamples;
999		VK_FALSE,													// VkBool32									sampleShadingEnable;
1000		imageMSParams.shadingRate,									// float									minSampleShading;
1001		DE_NULL,													// const VkSampleMask*						pSampleMask;
1002		VK_FALSE,													// VkBool32									alphaToCoverageEnable;
1003		VK_FALSE,													// VkBool32									alphaToOneEnable;
1004	};
1005
1006	return multisampleStateInfo;
1007}
1008
1009template<> tcu::TestStatus MSInstance<MSInstanceSampleMaskWrite>::verifyImageData	(const vk::VkImageCreateInfo&						imageMSInfo,
1010																					 const vk::VkImageCreateInfo&						imageRSInfo,
1011																					 const std::vector<tcu::ConstPixelBufferAccess>&	dataPerSample,
1012																					 const tcu::ConstPixelBufferAccess&					dataRS) const
1013{
1014	const deUint32 numSamples = static_cast<deUint32>(imageMSInfo.samples);
1015
1016	for (deUint32 z = 0u; z < imageMSInfo.extent.depth;  ++z)
1017	for (deUint32 y = 0u; y < imageMSInfo.extent.height; ++y)
1018	for (deUint32 x = 0u; x < imageMSInfo.extent.width;  ++x)
1019	{
1020		for (deUint32 sampleNdx = 0u; sampleNdx < numSamples; ++sampleNdx)
1021		{
1022			const deUint32 firstComponent = dataPerSample[sampleNdx].getPixelUint(x, y, z)[0];
1023
1024			if (firstComponent != 0u && firstComponent != 255u)
1025				return tcu::TestStatus::fail("Expected color to be zero or saturated on the first channel");
1026		}
1027	}
1028
1029	for (deUint32 z = 0u; z < imageRSInfo.extent.depth;  ++z)
1030	for (deUint32 y = 0u; y < imageRSInfo.extent.height; ++y)
1031	for (deUint32 x = 0u; x < imageRSInfo.extent.width;  ++x)
1032	{
1033		const float firstComponent = dataRS.getPixel(x, y, z)[0];
1034
1035		if (deFloatAbs(firstComponent - 0.5f) > 0.02f)
1036			return tcu::TestStatus::fail("Expected resolve color to be half intensity on the first channel");
1037	}
1038
1039	return tcu::TestStatus::pass("Passed");
1040}
1041
1042class MSCaseSampleMaskWrite;
1043
1044template<> void MSCase<MSCaseSampleMaskWrite>::init (void)
1045{
1046	m_testCtx.getLog()
1047		<< tcu::TestLog::Message
1048		<< "Discarding half of the samples using gl_SampleMask."
1049		<< "Expecting half intensity on multisample targets (numSamples > 1)\n"
1050		<< tcu::TestLog::EndMessage;
1051
1052	MultisampleCaseBase::init();
1053}
1054
1055template<> void MSCase<MSCaseSampleMaskWrite>::initPrograms (vk::SourceCollections& programCollection) const
1056{
1057	MSCaseBaseResolveAndPerSampleFetch::initPrograms(programCollection);
1058
1059	// Create vertex shader
1060	std::ostringstream vs;
1061
1062	vs << "#version 440\n"
1063		<< "layout(location = 0) in vec4 vs_in_position_ndc;\n"
1064		<< "\n"
1065		<< "out gl_PerVertex {\n"
1066		<< "	vec4  gl_Position;\n"
1067		<< "};\n"
1068		<< "void main (void)\n"
1069		<< "{\n"
1070		<< "	gl_Position	= vs_in_position_ndc;\n"
1071		<< "}\n";
1072
1073	programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
1074
1075	// Create fragment shader
1076	std::ostringstream fs;
1077
1078	fs << "#version 440\n"
1079		<< "\n"
1080		<< "layout(location = 0) out vec4 fs_out_color;\n"
1081		<< "\n"
1082		<< "void main (void)\n"
1083		<< "{\n"
1084		<< "	gl_SampleMask[0] = 0xAAAAAAAA;\n"
1085		<< "\n"
1086		<< "	fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
1087		<< "}\n";
1088
1089	programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
1090}
1091
1092template<> TestInstance* MSCase<MSCaseSampleMaskWrite>::createInstance (Context& context) const
1093{
1094	return new MSInstance<MSInstanceSampleMaskWrite>(context, m_imageMSParams);
1095}
1096
1097const set<deUint32> kValidSquareSampleCounts =
1098{
1099	vk::VK_SAMPLE_COUNT_1_BIT,
1100	vk::VK_SAMPLE_COUNT_2_BIT,
1101	vk::VK_SAMPLE_COUNT_4_BIT,
1102	vk::VK_SAMPLE_COUNT_8_BIT,
1103	vk::VK_SAMPLE_COUNT_16_BIT,
1104};
1105
1106void assertSquareSampleCount (deUint32 sampleCount)
1107{
1108	DE_ASSERT(kValidSquareSampleCounts.find(sampleCount) != kValidSquareSampleCounts.end());
1109	DE_UNREF(sampleCount); // for release builds.
1110}
1111
1112// When dealing with N samples, each coordinate (x, y) will be used to decide which samples will be written to, using N/2 bits for
1113// each of the X and Y values. Take into account this returns 0 for 1 sample.
1114deUint32 bitsPerCoord (deUint32 numSamples)
1115{
1116	assertSquareSampleCount(numSamples);
1117	return (numSamples / 2u);
1118}
1119
1120// These tests will try to verify all write or mask bit combinations for the given sample count, and will verify one combination per
1121// image pixel. This means the following image sizes need to be used:
1122//		- 2 samples: 2x2
1123//		- 4 samples: 4x4
1124//		- 8 samples: 16x16
1125//		- 16 samples: 256x256
1126// In other words, images will be square with 2^(samples-1) pixels on each side.
1127vk::VkExtent2D imageSize (deUint32 sampleCount)
1128{
1129	assertSquareSampleCount(sampleCount);
1130
1131	// Special case: 2x1 image (not actually square).
1132	if (sampleCount == vk::VK_SAMPLE_COUNT_1_BIT)
1133		return vk::VkExtent2D{2u, 1u};
1134
1135	// Other cases: square image as described above.
1136	const auto dim = (1u<<(sampleCount>>1u));
1137	return vk::VkExtent2D{dim, dim};
1138}
1139
1140vk::VkExtent3D getExtent3D (deUint32 sampleCount)
1141{
1142	const auto size = imageSize(sampleCount);
1143	return vk::VkExtent3D{size.width, size.height, 1u};
1144}
1145
1146std::string getShaderDecl (const tcu::Vec4& color)
1147{
1148	std::ostringstream declaration;
1149	declaration << "vec4(" << color.x() << ", " << color.y() << ", " << color.z() << ", " << color.w() << ")";
1150	return declaration.str();
1151}
1152
1153struct WriteSampleParams
1154{
1155	vk::PipelineConstructionType	pipelineConstructionType;
1156	vk::VkSampleCountFlagBits		sampleCount;
1157};
1158
1159class WriteSampleTest : public vkt::TestCase
1160{
1161public:
1162									WriteSampleTest		(tcu::TestContext& testCtx, const std::string& name, const WriteSampleParams& params)
1163										: vkt::TestCase(testCtx, name), m_params(params)
1164										{}
1165	virtual							~WriteSampleTest	(void) {}
1166
1167	virtual void					initPrograms		(vk::SourceCollections& programCollection) const;
1168	virtual vkt::TestInstance*		createInstance		(Context& context) const;
1169	virtual void					checkSupport		(Context& context) const;
1170
1171	static const tcu::Vec4			kClearColor;
1172	static const tcu::Vec4			kBadColor;
1173	static const tcu::Vec4			kGoodColor;
1174	static const tcu::Vec4			kWriteColor;
1175
1176	static constexpr vk::VkFormat	kImageFormat		= vk::VK_FORMAT_R8G8B8A8_UNORM;
1177
1178	// Keep these two in sync.
1179	static constexpr vk::VkImageUsageFlags		kUsageFlags		= (vk::VK_IMAGE_USAGE_STORAGE_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT | vk::VK_IMAGE_USAGE_TRANSFER_DST_BIT);
1180	static constexpr vk::VkFormatFeatureFlags	kFeatureFlags	= (vk::VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT | vk::VK_FORMAT_FEATURE_TRANSFER_SRC_BIT | vk::VK_FORMAT_FEATURE_TRANSFER_DST_BIT);
1181
1182private:
1183	WriteSampleParams		m_params;
1184};
1185
1186const tcu::Vec4 WriteSampleTest::kClearColor	{0.0f, 0.0f, 0.0f, 1.0f};
1187const tcu::Vec4 WriteSampleTest::kBadColor		{1.0f, 0.0f, 0.0f, 1.0f};
1188const tcu::Vec4 WriteSampleTest::kGoodColor		{0.0f, 1.0f, 0.0f, 1.0f};
1189const tcu::Vec4 WriteSampleTest::kWriteColor	{0.0f, 0.0f, 1.0f, 1.0f};
1190
1191class WriteSampleTestInstance : public vkt::TestInstance
1192{
1193public:
1194								WriteSampleTestInstance		(vkt::Context& context, const WriteSampleParams& params)
1195									: vkt::TestInstance(context), m_params(params)
1196									{}
1197
1198	virtual						~WriteSampleTestInstance	(void) {}
1199
1200	virtual tcu::TestStatus		iterate						(void);
1201
1202private:
1203	WriteSampleParams			m_params;
1204};
1205
1206void WriteSampleTest::checkSupport (Context& context) const
1207{
1208	const auto&	vki				= context.getInstanceInterface();
1209	const auto	physicalDevice	= context.getPhysicalDevice();
1210
1211	// Check multisample storage images support.
1212	const auto features = vk::getPhysicalDeviceFeatures(vki, physicalDevice);
1213	if (!features.shaderStorageImageMultisample)
1214		TCU_THROW(NotSupportedError, "Using multisample images as storage is not supported");
1215
1216	// Check the specific image format.
1217	const auto properties = vk::getPhysicalDeviceFormatProperties(vki, physicalDevice, kImageFormat);
1218	if (!(properties.optimalTilingFeatures & kFeatureFlags))
1219		TCU_THROW(NotSupportedError, "Format does not support the required features");
1220
1221	// Check the supported sample count.
1222	const auto imgProps = vk::getPhysicalDeviceImageFormatProperties(vki, physicalDevice, kImageFormat, vk::VK_IMAGE_TYPE_2D, vk::VK_IMAGE_TILING_OPTIMAL, kUsageFlags, 0u);
1223	if (!(imgProps.sampleCounts & m_params.sampleCount))
1224		TCU_THROW(NotSupportedError, "Format does not support the required sample count");
1225
1226	checkPipelineConstructionRequirements(context.getInstanceInterface(), context.getPhysicalDevice(), m_params.pipelineConstructionType);
1227}
1228
1229void WriteSampleTest::initPrograms (vk::SourceCollections& programCollection) const
1230{
1231	std::ostringstream writeColorDecl, goodColorDecl, badColorDecl, clearColorDecl, allColorDecl;
1232
1233	writeColorDecl	<< "        vec4  wcolor   = " << getShaderDecl(kWriteColor)	<< ";\n";
1234	goodColorDecl	<< "        vec4  bcolor   = " << getShaderDecl(kBadColor)		<< ";\n";
1235	badColorDecl	<< "        vec4  gcolor   = " << getShaderDecl(kGoodColor)		<< ";\n";
1236	clearColorDecl	<< "        vec4  ccolor   = " << getShaderDecl(kClearColor)	<< ";\n";
1237	allColorDecl	<< writeColorDecl.str() << goodColorDecl.str() << badColorDecl.str() << clearColorDecl.str();
1238
1239	std::ostringstream shaderWrite;
1240
1241	const auto bpc		= de::toString(bitsPerCoord(m_params.sampleCount));
1242	const auto count	= de::toString(m_params.sampleCount);
1243
1244	shaderWrite
1245		<< "#version 450\n"
1246		<< "\n"
1247		<< "layout (rgba8, set=0, binding=0) uniform image2DMS writeImg;\n"
1248		<< "layout (rgba8, set=0, binding=1) uniform image2D   verificationImg;\n"
1249		<< "\n"
1250		<< "void main()\n"
1251		<< "{\n"
1252		<< writeColorDecl.str()
1253		<< "        uvec2 ucoords  = uvec2(gl_GlobalInvocationID.xy);\n"
1254		<< "        ivec2 icoords  = ivec2(ucoords);\n"
1255		<< "        uint writeMask = ((ucoords.x << " << bpc << ") | ucoords.y);\n"
1256		<< "        for (uint i = 0; i < " << count << "; ++i)\n"
1257		<< "        {\n"
1258		<< "                if ((writeMask & (1 << i)) != 0)\n"
1259		<< "                        imageStore(writeImg, icoords, int(i), wcolor);\n"
1260		<< "        }\n"
1261		<< "}\n"
1262		;
1263
1264	std::ostringstream shaderVerify;
1265
1266	shaderVerify
1267		<< "#version 450\n"
1268		<< "\n"
1269		<< "layout (rgba8, set=0, binding=0) uniform image2DMS writeImg;\n"
1270		<< "layout (rgba8, set=0, binding=1) uniform image2D   verificationImg;\n"
1271		<< "\n"
1272		<< "void main()\n"
1273		<< "{\n"
1274		<< allColorDecl.str()
1275		<< "        uvec2 ucoords  = uvec2(gl_GlobalInvocationID.xy);\n"
1276		<< "        ivec2 icoords  = ivec2(ucoords);\n"
1277		<< "        uint writeMask = ((ucoords.x << " << bpc << ") | ucoords.y);\n"
1278		<< "        bool ok = true;\n"
1279		<< "        for (uint i = 0; i < " << count << "; ++i)\n"
1280		<< "        {\n"
1281		<< "                bool expectWrite = ((writeMask & (1 << i)) != 0);\n"
1282		<< "                vec4 sampleColor = imageLoad(writeImg, icoords, int(i));\n"
1283		<< "                vec4 wantedColor = (expectWrite ? wcolor : ccolor);\n"
1284		<< "                ok = ok && (sampleColor == wantedColor);\n"
1285		<< "        }\n"
1286		<< "        vec4 resultColor = (ok ? gcolor : bcolor);\n"
1287		<< "        imageStore(verificationImg, icoords, resultColor);\n"
1288		<< "}\n"
1289		;
1290
1291	programCollection.glslSources.add("write")	<< glu::ComputeSource(shaderWrite.str());
1292	programCollection.glslSources.add("verify")	<< glu::ComputeSource(shaderVerify.str());
1293}
1294
1295vkt::TestInstance* WriteSampleTest::createInstance (Context& context) const
1296{
1297	return new WriteSampleTestInstance{context, m_params};
1298}
1299
1300tcu::TestStatus WriteSampleTestInstance::iterate (void)
1301{
1302	const auto&	vkd			= m_context.getDeviceInterface();
1303	const auto	device		= m_context.getDevice();
1304	auto&		allocator	= m_context.getDefaultAllocator();
1305	const auto	queue		= m_context.getUniversalQueue();
1306	const auto	queueIndex	= m_context.getUniversalQueueFamilyIndex();
1307	const auto	extent3D	= getExtent3D(m_params.sampleCount);
1308
1309	// Create storage image and verification image.
1310	const vk::VkImageCreateInfo storageImageInfo =
1311	{
1312		vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,	// VkStructureType			sType;
1313		nullptr,									// const void*				pNext;
1314		0u,											// VkImageCreateFlags		flags;
1315		vk::VK_IMAGE_TYPE_2D,						// VkImageType				imageType;
1316		WriteSampleTest::kImageFormat,				// VkFormat					format;
1317		extent3D,									// VkExtent3D				extent;
1318		1u,											// deUint32					mipLevels;
1319		1u,											// deUint32					arrayLayers;
1320		m_params.sampleCount,						// VkSampleCountFlagBits	samples;
1321		vk::VK_IMAGE_TILING_OPTIMAL,				// VkImageTiling			tiling;
1322		WriteSampleTest::kUsageFlags,				// VkImageUsageFlags		usage;
1323		vk::VK_SHARING_MODE_EXCLUSIVE,				// VkSharingMode			sharingMode;
1324		1u,											// deUint32					queueFamilyIndexCount;
1325		&queueIndex,								// const deUint32*			pQueueFamilyIndices;
1326		vk::VK_IMAGE_LAYOUT_UNDEFINED,				// VkImageLayout			initialLayout;
1327	};
1328
1329	const vk::VkImageCreateInfo verificationImageInfo =
1330	{
1331		vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,	// VkStructureType			sType;
1332		nullptr,									// const void*				pNext;
1333		0u,											// VkImageCreateFlags		flags;
1334		vk::VK_IMAGE_TYPE_2D,						// VkImageType				imageType;
1335		WriteSampleTest::kImageFormat,				// VkFormat					format;
1336		extent3D,									// VkExtent3D				extent;
1337		1u,											// deUint32					mipLevels;
1338		1u,											// deUint32					arrayLayers;
1339		vk::VK_SAMPLE_COUNT_1_BIT,					// VkSampleCountFlagBits	samples;
1340		vk::VK_IMAGE_TILING_OPTIMAL,				// VkImageTiling			tiling;
1341		WriteSampleTest::kUsageFlags,				// VkImageUsageFlags		usage;
1342		vk::VK_SHARING_MODE_EXCLUSIVE,				// VkSharingMode			sharingMode;
1343		1u,											// deUint32					queueFamilyIndexCount;
1344		&queueIndex,								// const deUint32*			pQueueFamilyIndices;
1345		vk::VK_IMAGE_LAYOUT_UNDEFINED,				// VkImageLayout			initialLayout;
1346	};
1347
1348	vk::ImageWithMemory storageImgPrt		{vkd, device, allocator, storageImageInfo, vk::MemoryRequirement::Any};
1349	vk::ImageWithMemory verificationImgPtr	{vkd, device, allocator, verificationImageInfo, vk::MemoryRequirement::Any};
1350
1351	const vk::VkImageSubresourceRange kSubresourceRange =
1352	{
1353		vk::VK_IMAGE_ASPECT_COLOR_BIT,	// VkImageAspectFlags	aspectMask;
1354		0u,								// deUint32				baseMipLevel;
1355		1u,								// deUint32				levelCount;
1356		0u,								// deUint32				baseArrayLayer;
1357		1u,								// deUint32				layerCount;
1358	};
1359
1360	auto storageImgViewPtr		= vk::makeImageView(vkd, device, storageImgPrt.get(), vk::VK_IMAGE_VIEW_TYPE_2D, WriteSampleTest::kImageFormat, kSubresourceRange);
1361	auto verificationImgViewPtr	= vk::makeImageView(vkd, device, verificationImgPtr.get(), vk::VK_IMAGE_VIEW_TYPE_2D, WriteSampleTest::kImageFormat, kSubresourceRange);
1362
1363	// Prepare a staging buffer to check verification image.
1364	const auto				tcuFormat			= vk::mapVkFormat(WriteSampleTest::kImageFormat);
1365	const VkDeviceSize		bufferSize			= extent3D.width * extent3D.height * extent3D.depth * tcu::getPixelSize(tcuFormat);
1366	const auto				stagingBufferInfo	= vk::makeBufferCreateInfo(bufferSize, vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT);
1367	vk::BufferWithMemory	stagingBuffer		{vkd, device, allocator, stagingBufferInfo, MemoryRequirement::HostVisible};
1368
1369	// Descriptor set layout.
1370	vk::DescriptorSetLayoutBuilder layoutBuilder;
1371	layoutBuilder.addSingleBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, vk::VK_SHADER_STAGE_COMPUTE_BIT);
1372	layoutBuilder.addSingleBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, vk::VK_SHADER_STAGE_COMPUTE_BIT);
1373	auto descriptorSetLayout = layoutBuilder.build(vkd, device);
1374
1375	// Descriptor pool.
1376	vk::DescriptorPoolBuilder poolBuilder;
1377	poolBuilder.addType(vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 2u);
1378	auto descriptorPool = poolBuilder.build(vkd, device, vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
1379
1380	// Descriptor set.
1381	const auto descriptorSet = vk::makeDescriptorSet(vkd, device, descriptorPool.get(), descriptorSetLayout.get());
1382
1383	// Update descriptor set using the images.
1384	const auto storageImgDescriptorInfo			= vk::makeDescriptorImageInfo(DE_NULL, storageImgViewPtr.get(), vk::VK_IMAGE_LAYOUT_GENERAL);
1385	const auto verificationImgDescriptorInfo	= vk::makeDescriptorImageInfo(DE_NULL, verificationImgViewPtr.get(), vk::VK_IMAGE_LAYOUT_GENERAL);
1386
1387	vk::DescriptorSetUpdateBuilder updateBuilder;
1388	updateBuilder.writeSingle(descriptorSet.get(), vk::DescriptorSetUpdateBuilder::Location::binding(0u), vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &storageImgDescriptorInfo);
1389	updateBuilder.writeSingle(descriptorSet.get(), vk::DescriptorSetUpdateBuilder::Location::binding(1u), vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &verificationImgDescriptorInfo);
1390	updateBuilder.update(vkd, device);
1391
1392	// Create write and verification compute pipelines.
1393	auto shaderWriteModule	= ShaderWrapper(vkd, device, m_context.getBinaryCollection().get("write"), 0u);
1394	auto shaderVerifyModule	= ShaderWrapper(vkd, device, m_context.getBinaryCollection().get("verify"), 0u);
1395	auto pipelineLayout		= vk::makePipelineLayout(vkd, device, descriptorSetLayout.get());
1396
1397	const vk::VkComputePipelineCreateInfo writePipelineCreateInfo =
1398	{
1399		vk::VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
1400		nullptr,
1401		0u,															// flags
1402		{															// compute shader
1403			vk::VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,	// VkStructureType						sType;
1404			nullptr,													// const void*							pNext;
1405			0u,															// VkPipelineShaderStageCreateFlags		flags;
1406			vk::VK_SHADER_STAGE_COMPUTE_BIT,							// VkShaderStageFlagBits				stage;
1407			shaderWriteModule.getModule(),								// VkShaderModule						module;
1408			"main",														// const char*							pName;
1409			nullptr,													// const VkSpecializationInfo*			pSpecializationInfo;
1410		},
1411		pipelineLayout.get(),										// layout
1412		DE_NULL,													// basePipelineHandle
1413		0,															// basePipelineIndex
1414	};
1415
1416	auto verificationPipelineCreateInfo = writePipelineCreateInfo;
1417	verificationPipelineCreateInfo.stage.module = shaderVerifyModule.getModule();
1418
1419	auto writePipeline			= vk::createComputePipeline(vkd, device, DE_NULL, &writePipelineCreateInfo);
1420	auto verificationPipeline	= vk::createComputePipeline(vkd, device, DE_NULL, &verificationPipelineCreateInfo);
1421
1422	// Transition images to the correct layout and buffers at different stages.
1423	auto storageImgPreClearBarrier			= vk::makeImageMemoryBarrier(0, vk::VK_ACCESS_TRANSFER_WRITE_BIT, vk::VK_IMAGE_LAYOUT_UNDEFINED, vk::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, storageImgPrt.get(), kSubresourceRange);
1424	auto storageImgPreShaderBarrier			= vk::makeImageMemoryBarrier(vk::VK_ACCESS_TRANSFER_WRITE_BIT, vk::VK_ACCESS_SHADER_WRITE_BIT, vk::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, vk::VK_IMAGE_LAYOUT_GENERAL, storageImgPrt.get(), kSubresourceRange);
1425	auto verificationImgPreShaderBarrier	= vk::makeImageMemoryBarrier(0, vk::VK_ACCESS_SHADER_WRITE_BIT, vk::VK_IMAGE_LAYOUT_UNDEFINED, vk::VK_IMAGE_LAYOUT_GENERAL, verificationImgPtr.get(), kSubresourceRange);
1426	auto storageImgPreVerificationBarrier	= vk::makeImageMemoryBarrier(vk::VK_ACCESS_SHADER_WRITE_BIT, vk::VK_ACCESS_SHADER_READ_BIT, vk::VK_IMAGE_LAYOUT_GENERAL, vk::VK_IMAGE_LAYOUT_GENERAL, storageImgPrt.get(), kSubresourceRange);
1427	auto verificationImgPostBarrier			= vk::makeImageMemoryBarrier(vk::VK_ACCESS_SHADER_WRITE_BIT, vk::VK_ACCESS_TRANSFER_READ_BIT, vk::VK_IMAGE_LAYOUT_GENERAL, vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, verificationImgPtr.get(), kSubresourceRange);
1428	auto bufferBarrier						= vk::makeBufferMemoryBarrier(vk::VK_ACCESS_TRANSFER_WRITE_BIT, vk::VK_ACCESS_HOST_READ_BIT, stagingBuffer.get(), 0ull, bufferSize);
1429
1430	// Command buffer.
1431	auto cmdPool		= vk::makeCommandPool(vkd, device, queueIndex);
1432	auto cmdBufferPtr	= vk::allocateCommandBuffer(vkd, device, cmdPool.get(), vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY);
1433	auto cmdBuffer		= cmdBufferPtr.get();
1434
1435	// Clear color for the storage image.
1436	const auto clearColor = vk::makeClearValueColor(WriteSampleTest::kClearColor);
1437
1438	const vk::VkBufferImageCopy	copyRegion =
1439	{
1440		0ull,									// VkDeviceSize				bufferOffset;
1441		extent3D.width,							// deUint32					bufferRowLength;
1442		extent3D.height,						// deUint32					bufferImageHeight;
1443		{										// VkImageSubresourceLayers	imageSubresource;
1444			vk::VK_IMAGE_ASPECT_COLOR_BIT,			// VkImageAspectFlags	aspectMask;
1445			0u,										// deUint32				mipLevel;
1446			0u,										// deUint32				baseArrayLayer;
1447			1u,										// deUint32				layerCount;
1448		},
1449		{ 0, 0, 0 },							// VkOffset3D				imageOffset;
1450		extent3D,								// VkExtent3D				imageExtent;
1451	};
1452
1453	// Record and submit commands.
1454	vk::beginCommandBuffer(vkd, cmdBuffer);
1455		// Clear storage image.
1456		vkd.cmdPipelineBarrier(cmdBuffer, vk::VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, vk::VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, nullptr, 0u, nullptr, 1u, &storageImgPreClearBarrier);
1457		vkd.cmdClearColorImage(cmdBuffer, storageImgPrt.get(), vk::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clearColor.color, 1u, &kSubresourceRange);
1458
1459		// Bind write pipeline and descriptor set.
1460		vkd.cmdBindPipeline(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, writePipeline.get());
1461		vkd.cmdBindDescriptorSets(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, pipelineLayout.get(), 0, 1u, &descriptorSet.get(), 0u, nullptr);
1462
1463		// Transition images to the appropriate layout before running the shader.
1464		vkd.cmdPipelineBarrier(cmdBuffer, vk::VK_PIPELINE_STAGE_TRANSFER_BIT, vk::VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0u, 0u, nullptr, 0u, nullptr, 1u, &storageImgPreShaderBarrier);
1465		vkd.cmdPipelineBarrier(cmdBuffer, vk::VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, vk::VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0u, 0u, nullptr, 0u, nullptr, 1u, &verificationImgPreShaderBarrier);
1466
1467		// Run shader.
1468		vkd.cmdDispatch(cmdBuffer, extent3D.width, extent3D.height, extent3D.depth);
1469
1470		// Bind verification pipeline.
1471		vkd.cmdBindPipeline(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, verificationPipeline.get());
1472
1473		// Make sure writes happen before reads in the second dispatch for the storage image.
1474		vkd.cmdPipelineBarrier(cmdBuffer, vk::VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, vk::VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0u, 0u, nullptr, 0u, nullptr, 1u, &storageImgPreVerificationBarrier);
1475
1476		// Run verification shader.
1477		vkd.cmdDispatch(cmdBuffer, extent3D.width, extent3D.height, extent3D.depth);
1478
1479		// Change verification image layout to prepare the transfer.
1480		vkd.cmdPipelineBarrier(cmdBuffer, vk::VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, vk::VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, nullptr, 0u, nullptr, 1u, &verificationImgPostBarrier);
1481
1482		// Copy verification image to staging buffer.
1483		vkd.cmdCopyImageToBuffer(cmdBuffer, verificationImgPtr.get(), vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, stagingBuffer.get(), 1u, &copyRegion);
1484		vkd.cmdPipelineBarrier(cmdBuffer, vk::VK_PIPELINE_STAGE_TRANSFER_BIT, vk::VK_PIPELINE_STAGE_HOST_BIT, 0, 0u, nullptr, 1u, &bufferBarrier, 0u, nullptr);
1485
1486	vk::endCommandBuffer(vkd, cmdBuffer);
1487
1488	// Run shaders.
1489	vk::submitCommandsAndWait(vkd, device, queue, cmdBuffer);
1490
1491	// Read buffer pixels.
1492	const auto& bufferAlloc = stagingBuffer.getAllocation();
1493	vk::invalidateAlloc(vkd, device, bufferAlloc);
1494
1495	// Copy buffer data to texture level and verify all pixels have the proper color.
1496	tcu::TextureLevel texture {tcuFormat, static_cast<int>(extent3D.width), static_cast<int>(extent3D.height), static_cast<int>(extent3D.depth)};
1497	const auto access = texture.getAccess();
1498	deMemcpy(access.getDataPtr(), reinterpret_cast<char*>(bufferAlloc.getHostPtr()) + bufferAlloc.getOffset(), static_cast<size_t>(bufferSize));
1499
1500	for (int i = 0; i < access.getWidth(); ++i)
1501	for (int j = 0; j < access.getHeight(); ++j)
1502	for (int k = 0; k < access.getDepth(); ++k)
1503	{
1504		if (access.getPixel(i, j, k) != WriteSampleTest::kGoodColor)
1505		{
1506			std::ostringstream msg;
1507			msg << "Invalid result at pixel (" << i << ", " << j << ", " << k << "); check error mask for more details";
1508			m_context.getTestContext().getLog() << tcu::TestLog::Image("ErrorMask", "Indicates which pixels have unexpected values", access);
1509			return tcu::TestStatus::fail(msg.str());
1510		}
1511	}
1512
1513	return tcu::TestStatus::pass("Pass");
1514}
1515
1516using WriteSampleMaskParams = WriteSampleParams;
1517
1518class WriteSampleMaskTestCase : public vkt::TestCase
1519{
1520public:
1521							WriteSampleMaskTestCase		(tcu::TestContext& testCtx, const std::string& name, const WriteSampleMaskParams& params);
1522	virtual					~WriteSampleMaskTestCase	(void) {}
1523
1524	virtual void			checkSupport				(Context& context) const;
1525	virtual void			initPrograms				(vk::SourceCollections& programCollection) const;
1526	virtual TestInstance*	createInstance				(Context& context) const;
1527	static deUint32			getBufferElems				(deUint32 sampleCount);
1528
1529	static const tcu::Vec4						kClearColor;
1530	static const tcu::Vec4						kWriteColor;
1531
1532	static constexpr vk::VkFormat				kImageFormat	= vk::VK_FORMAT_R8G8B8A8_UNORM;
1533	static constexpr vk::VkImageUsageFlags		kUsageFlags		= (vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT);
1534	static constexpr vk::VkFormatFeatureFlags	kFeatureFlags	= (vk::VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT);
1535
1536private:
1537	WriteSampleMaskParams	m_params;
1538};
1539
1540const tcu::Vec4 WriteSampleMaskTestCase::kClearColor	{0.0f, 0.0f, 0.0f, 1.0f};
1541const tcu::Vec4 WriteSampleMaskTestCase::kWriteColor	{0.0f, 0.0f, 1.0f, 1.0f};
1542
1543class WriteSampleMaskTestInstance : public vkt::TestInstance
1544{
1545public:
1546								WriteSampleMaskTestInstance		(Context& context, const WriteSampleMaskParams& params);
1547	virtual						~WriteSampleMaskTestInstance	(void) {}
1548
1549	virtual tcu::TestStatus		iterate							(void);
1550
1551private:
1552	WriteSampleMaskParams		m_params;
1553};
1554
1555WriteSampleMaskTestCase::WriteSampleMaskTestCase (tcu::TestContext& testCtx, const std::string& name, const WriteSampleMaskParams& params)
1556	: vkt::TestCase	(testCtx, name)
1557	, m_params		(params)
1558{}
1559
1560void WriteSampleMaskTestCase::checkSupport (Context& context) const
1561{
1562	const auto&	vki				= context.getInstanceInterface();
1563	const auto	physicalDevice	= context.getPhysicalDevice();
1564
1565	// Check if sampleRateShading is supported.
1566	if(!vk::getPhysicalDeviceFeatures(vki, physicalDevice).sampleRateShading)
1567		TCU_THROW(NotSupportedError, "Sample rate shading is not supported");
1568
1569	// Check the specific image format.
1570	const auto properties = vk::getPhysicalDeviceFormatProperties(vki, physicalDevice, kImageFormat);
1571	if (!(properties.optimalTilingFeatures & kFeatureFlags))
1572		TCU_THROW(NotSupportedError, "Format does not support the required features");
1573
1574	// Check the supported sample count.
1575	const auto imgProps = vk::getPhysicalDeviceImageFormatProperties(vki, physicalDevice, kImageFormat, vk::VK_IMAGE_TYPE_2D, vk::VK_IMAGE_TILING_OPTIMAL, kUsageFlags, 0u);
1576	if (!(imgProps.sampleCounts & m_params.sampleCount))
1577		TCU_THROW(NotSupportedError, "Format does not support the required sample count");
1578
1579	checkPipelineConstructionRequirements(context.getInstanceInterface(), context.getPhysicalDevice(), m_params.pipelineConstructionType);
1580}
1581
1582void WriteSampleMaskTestCase::initPrograms (vk::SourceCollections& programCollection) const
1583{
1584	const auto bpc			= de::toString(bitsPerCoord(m_params.sampleCount));
1585	const auto size			= imageSize(m_params.sampleCount);
1586	const auto bufferElems	= getBufferElems(m_params.sampleCount);
1587
1588	// Passthrough vertex shader.
1589	std::ostringstream vertShader;
1590
1591	vertShader
1592		<< "#version 450\n"
1593		<< "layout (location=0) in vec2 inPos;\n"
1594		<< "void main()\n"
1595		<< "{\n"
1596		<< "    gl_Position = vec4(inPos, 0.0, 1.0);\n"
1597		<< "}\n"
1598		;
1599
1600	// Fragment shader common header.
1601	std::ostringstream fragHeader;
1602
1603	fragHeader
1604		<< "#version 450\n"
1605		<< "\n"
1606		// The color attachment is useless for the second subpass but avoids having to use an empty subpass and verifying the sample
1607		// count is valid for it.
1608		<< "layout (location=0) out vec4 outColor;\n"
1609		<< "\n"
1610		<< "vec4 wcolor = " << getShaderDecl(kWriteColor) << ";\n"
1611		<< "vec4 ccolor = " << getShaderDecl(kClearColor) << ";\n"
1612		<< "\n"
1613		;
1614
1615	const auto fragHeaderStr = fragHeader.str();
1616
1617	// Fragment shader setting the sample mask and writing to the output color attachment. The sample mask will guarantee each image
1618	// pixel gets a different combination of sample bits set, allowing the fragment shader to write in that sample or not, from all
1619	// zeros in pixel (0, 0) to all ones in the opposite corner.
1620	std::ostringstream fragShaderWrite;
1621
1622	fragShaderWrite
1623		<< fragHeaderStr
1624		<< "void main()\n"
1625		<< "{\n"
1626		<< "    uvec2 ucoords    = uvec2(gl_FragCoord);\n"
1627		<< "    ivec2 icoords    = ivec2(ucoords);\n"
1628		<< "    gl_SampleMask[0] = int((ucoords.x << " << bpc << ") | ucoords.y);\n"
1629		<< "    outColor         = wcolor;\n"
1630		<< "}\n"
1631		;
1632
1633	// Fragment shader reading from the previous output color attachment and copying the state to an SSBO for verification.
1634	std::ostringstream fragShaderCheck;
1635
1636	const bool isMultiSample = (m_params.sampleCount != vk::VK_SAMPLE_COUNT_1_BIT);
1637	fragShaderCheck
1638		<< fragHeaderStr
1639		<< "layout(set=0, binding=0, input_attachment_index=0) uniform subpassInput" << (isMultiSample ? "MS" : "") << " inputAttachment;\n"
1640		<< "layout(set=0, binding=1, std430) buffer StorageBuffer {\n"
1641		<< "    int writeFlags[" << bufferElems << "];\n"
1642		<< "} sb;\n"
1643		<< "\n"
1644		<< "void main()\n"
1645		<< "{\n"
1646		<< "    uvec2 ucoords          = uvec2(gl_FragCoord);\n"
1647		<< "    ivec2 icoords          = ivec2(ucoords);\n"
1648		<< "    uint  bufferp          = ((ucoords.y * " << size.width << " + ucoords.x) * " << m_params.sampleCount << ") + uint(gl_SampleID);\n"
1649		<< "    vec4  storedc          = subpassLoad(inputAttachment" << (isMultiSample ? ", gl_SampleID" : "") << ");\n"
1650		<< "    sb.writeFlags[bufferp] = ((storedc == wcolor) ? 1 : ((storedc == ccolor) ? 0 : 2));\n"
1651		<< "    outColor               = storedc;\n"
1652		<< "}\n"
1653		;
1654
1655	programCollection.glslSources.add("vert")		<< glu::VertexSource(vertShader.str());
1656	programCollection.glslSources.add("frag_write")	<< glu::FragmentSource(fragShaderWrite.str());
1657	programCollection.glslSources.add("frag_check")	<< glu::FragmentSource(fragShaderCheck.str());
1658}
1659
1660TestInstance* WriteSampleMaskTestCase::createInstance (Context& context) const
1661{
1662	return new WriteSampleMaskTestInstance(context, m_params);
1663}
1664
1665deUint32 WriteSampleMaskTestCase::getBufferElems (deUint32 sampleCount)
1666{
1667	const auto imgSize = imageSize(sampleCount);
1668	return (imgSize.width * imgSize.height * sampleCount);
1669}
1670
1671WriteSampleMaskTestInstance::WriteSampleMaskTestInstance (Context& context, const WriteSampleMaskParams& params)
1672	: vkt::TestInstance	(context)
1673	, m_params			(params)
1674{}
1675
1676tcu::TestStatus WriteSampleMaskTestInstance::iterate (void)
1677{
1678	const auto&		vki					= m_context.getInstanceInterface();
1679	const auto&		vkd					= m_context.getDeviceInterface();
1680	const auto		physicalDevice		= m_context.getPhysicalDevice();
1681	const auto		device				= m_context.getDevice();
1682	auto&			alloc				= m_context.getDefaultAllocator();
1683	const auto		queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
1684	const auto		queue				= m_context.getUniversalQueue();
1685
1686	static constexpr auto	kImageFormat	= WriteSampleMaskTestCase::kImageFormat;
1687	static constexpr auto	kImageUsage		= WriteSampleMaskTestCase::kUsageFlags;
1688	const auto				kImageExtent	= getExtent3D(m_params.sampleCount);
1689	const auto				kBufferElems	= WriteSampleMaskTestCase::getBufferElems(m_params.sampleCount);
1690	const auto				kBufferSize		= static_cast<vk::VkDeviceSize>(kBufferElems * sizeof(deInt32));
1691
1692	// Create image.
1693	const vk::VkImageCreateInfo imageCreateInfo =
1694	{
1695		vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,	//	VkStructureType			sType;
1696		nullptr,									//	const void*				pNext;
1697		0u,											//	VkImageCreateFlags		flags;
1698		vk::VK_IMAGE_TYPE_2D,						//	VkImageType				imageType;
1699		kImageFormat,								//	VkFormat				format;
1700		kImageExtent,								//	VkExtent3D				extent;
1701		1u,											//	deUint32				mipLevels;
1702		1u,											//	deUint32				arrayLayers;
1703		m_params.sampleCount,						//	VkSampleCountFlagBits	samples;
1704		vk::VK_IMAGE_TILING_OPTIMAL,				//	VkImageTiling			tiling;
1705		kImageUsage,								//	VkImageUsageFlags		usage;
1706		vk::VK_SHARING_MODE_EXCLUSIVE,				//	VkSharingMode			sharingMode;
1707		0u,											//	deUint32				queueFamilyIndexCount;
1708		nullptr,									//	const deUint32*			pQueueFamilyIndices;
1709		vk::VK_IMAGE_LAYOUT_UNDEFINED,				//	VkImageLayout			initialLayout;
1710	};
1711
1712	const vk::ImageWithMemory colorImage	(vkd, device, alloc, imageCreateInfo, vk::MemoryRequirement::Any);
1713	const vk::ImageWithMemory auxiliarImage	(vkd, device, alloc, imageCreateInfo, vk::MemoryRequirement::Any);	// For the second subpass.
1714
1715	// Image views.
1716	const auto subresourceRange		= vk::makeImageSubresourceRange(vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
1717	const auto colorImageView		= vk::makeImageView(vkd, device, colorImage.get(), vk::VK_IMAGE_VIEW_TYPE_2D, kImageFormat, subresourceRange);
1718	const auto auxiliarImageView	= vk::makeImageView(vkd, device, auxiliarImage.get(), vk::VK_IMAGE_VIEW_TYPE_2D, kImageFormat, subresourceRange);
1719
1720	// Create storage buffer used to verify results.
1721	const vk::BufferWithMemory storageBuffer(vkd, device, alloc, vk::makeBufferCreateInfo(kBufferSize, vk::VK_BUFFER_USAGE_STORAGE_BUFFER_BIT), vk::MemoryRequirement::HostVisible);
1722
1723	// Full-screen quad.
1724	const std::vector<tcu::Vec2> quadVertices =
1725	{
1726		tcu::Vec2(-1.0f,  1.0f),	// Lower left
1727		tcu::Vec2( 1.0f,  1.0f),	// Lower right
1728		tcu::Vec2( 1.0f, -1.0f),	// Top right.
1729		tcu::Vec2(-1.0f,  1.0f),	// Lower left
1730		tcu::Vec2( 1.0f, -1.0f),	// Top right.
1731		tcu::Vec2(-1.0f, -1.0f),	// Top left.
1732	};
1733
1734	// Vertex buffer.
1735	const auto					vertexBufferSize	= static_cast<vk::VkDeviceSize>(quadVertices.size() * sizeof(decltype(quadVertices)::value_type));
1736	const vk::BufferWithMemory	vertexBuffer		(vkd, device, alloc, vk::makeBufferCreateInfo(vertexBufferSize, vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT), vk::MemoryRequirement::HostVisible);
1737	const auto&					vertexBufferAlloc	= vertexBuffer.getAllocation();
1738	void*						vertexBufferPtr		= vertexBufferAlloc.getHostPtr();
1739	const vk::VkDeviceSize		vertexBufferOffset	= 0;
1740	deMemcpy(vertexBufferPtr, quadVertices.data(), static_cast<size_t>(vertexBufferSize));
1741	vk::flushAlloc(vkd, device, vertexBufferAlloc);
1742
1743	// Descriptor set layout.
1744	vk::DescriptorSetLayoutBuilder setLayoutBuilder;
1745	setLayoutBuilder.addSingleBinding(vk::VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, vk::VK_SHADER_STAGE_FRAGMENT_BIT);
1746	setLayoutBuilder.addSingleBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, vk::VK_SHADER_STAGE_FRAGMENT_BIT);
1747	const auto descriptorSetLayout = setLayoutBuilder.build(vkd, device);
1748
1749	// Descriptor pool and set.
1750	vk::DescriptorPoolBuilder poolBuilder;
1751	poolBuilder.addType(vk::VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1u);
1752	poolBuilder.addType(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1u);
1753	const auto descriptorPool	= poolBuilder.build(vkd, device, vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
1754	const auto descriptorSet	= vk::makeDescriptorSet(vkd, device, descriptorPool.get(), descriptorSetLayout.get());
1755
1756	// Render pass.
1757	const std::vector<vk::VkAttachmentDescription> attachments =
1758	{
1759		// Main color attachment.
1760		{
1761			0u,												//	VkAttachmentDescriptionFlags	flags;
1762			kImageFormat,									//	VkFormat						format;
1763			m_params.sampleCount,							//	VkSampleCountFlagBits			samples;
1764			vk::VK_ATTACHMENT_LOAD_OP_CLEAR,				//	VkAttachmentLoadOp				loadOp;
1765			vk::VK_ATTACHMENT_STORE_OP_STORE,				//	VkAttachmentStoreOp				storeOp;
1766			vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE,			//	VkAttachmentLoadOp				stencilLoadOp;
1767			vk::VK_ATTACHMENT_STORE_OP_DONT_CARE,			//	VkAttachmentStoreOp				stencilStoreOp;
1768			vk::VK_IMAGE_LAYOUT_UNDEFINED,					//	VkImageLayout					initialLayout;
1769			vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,	//	VkImageLayout					finalLayout;
1770		},
1771		// Auxiliar color attachment for the check pass.
1772		{
1773			0u,												//	VkAttachmentDescriptionFlags	flags;
1774			kImageFormat,									//	VkFormat						format;
1775			m_params.sampleCount,							//	VkSampleCountFlagBits			samples;
1776			vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE,			//	VkAttachmentLoadOp				loadOp;
1777			vk::VK_ATTACHMENT_STORE_OP_DONT_CARE,			//	VkAttachmentStoreOp				storeOp;
1778			vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE,			//	VkAttachmentLoadOp				stencilLoadOp;
1779			vk::VK_ATTACHMENT_STORE_OP_DONT_CARE,			//	VkAttachmentStoreOp				stencilStoreOp;
1780			vk::VK_IMAGE_LAYOUT_UNDEFINED,					//	VkImageLayout					initialLayout;
1781			vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,	//	VkImageLayout					finalLayout;
1782		},
1783	};
1784
1785	const vk::VkAttachmentReference colorAttachmentReference =
1786	{
1787		0u,												//	deUint32		attachment;
1788		vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,	//	VkImageLayout	layout;
1789	};
1790
1791	const vk::VkAttachmentReference colorAsInputAttachment =
1792	{
1793		0u,												//	deUint32		attachment;
1794		vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,	//	VkImageLayout	layout;
1795	};
1796
1797	const vk::VkAttachmentReference auxiliarAttachmentReference =
1798	{
1799		1u,												//	deUint32		attachment;
1800		vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,	//	VkImageLayout	layout;
1801	};
1802
1803	const std::vector<vk::VkSubpassDescription> subpasses =
1804	{
1805		// First subpass writing to the main attachment.
1806		{
1807			0u,										//	VkSubpassDescriptionFlags		flags;
1808			vk::VK_PIPELINE_BIND_POINT_GRAPHICS,	//	VkPipelineBindPoint				pipelineBindPoint;
1809			0u,										//	deUint32						inputAttachmentCount;
1810			nullptr,								//	const VkAttachmentReference*	pInputAttachments;
1811			1u,										//	deUint32						colorAttachmentCount;
1812			&colorAttachmentReference,				//	const VkAttachmentReference*	pColorAttachments;
1813			nullptr,								//	const VkAttachmentReference*	pResolveAttachments;
1814			nullptr,								//	const VkAttachmentReference*	pDepthStencilAttachment;
1815			0u,										//	deUint32						preserveAttachmentCount;
1816			nullptr,								//	const deUint32*					pPreserveAttachments;
1817		},
1818		// Second subpass writing to the auxiliar attachment.
1819		{
1820			0u,										//	VkSubpassDescriptionFlags		flags;
1821			vk::VK_PIPELINE_BIND_POINT_GRAPHICS,	//	VkPipelineBindPoint				pipelineBindPoint;
1822			1u,										//	deUint32						inputAttachmentCount;
1823			&colorAsInputAttachment,				//	const VkAttachmentReference*	pInputAttachments;
1824			1u,										//	deUint32						colorAttachmentCount;
1825			&auxiliarAttachmentReference,			//	const VkAttachmentReference*	pColorAttachments;
1826			nullptr,								//	const VkAttachmentReference*	pResolveAttachments;
1827			nullptr,								//	const VkAttachmentReference*	pDepthStencilAttachment;
1828			0u,										//	deUint32						preserveAttachmentCount;
1829			nullptr,								//	const deUint32*					pPreserveAttachments;
1830		},
1831	};
1832
1833	const std::vector<vk::VkSubpassDependency> subpassDependencies =
1834	{
1835		// First subpass writes to the color attachment and second subpass reads it as an input attachment.
1836		{
1837			0u,													//	deUint32				srcSubpass;
1838			1u,													//	deUint32				dstSubpass;
1839			vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,	//	VkPipelineStageFlags	srcStageMask;
1840			vk::VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,			//	VkPipelineStageFlags	dstStageMask;
1841			vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,			//	VkAccessFlags			srcAccessMask;
1842			vk::VK_ACCESS_INPUT_ATTACHMENT_READ_BIT,			//	VkAccessFlags			dstAccessMask;
1843			0u,													//	VkDependencyFlags		dependencyFlags;
1844		},
1845	};
1846
1847	const vk::VkRenderPassCreateInfo renderPassInfo =
1848	{
1849		vk::VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,		//	VkStructureType					sType;
1850		nullptr,											//	const void*						pNext;
1851		0u,													//	VkRenderPassCreateFlags			flags;
1852		static_cast<deUint32>(attachments.size()),			//	deUint32						attachmentCount;
1853		attachments.data(),									//	const VkAttachmentDescription*	pAttachments;
1854		static_cast<deUint32>(subpasses.size()),			//	deUint32						subpassCount;
1855		subpasses.data(),									//	const VkSubpassDescription*		pSubpasses;
1856		static_cast<deUint32>(subpassDependencies.size()),	//	deUint32						dependencyCount;
1857		subpassDependencies.data(),							//	const VkSubpassDependency*		pDependencies;
1858	};
1859	RenderPassWrapper renderPass (m_params.pipelineConstructionType, vkd, device, &renderPassInfo);
1860
1861	// Framebuffer.
1862	const std::vector<vk::VkImage>		images		=
1863	{
1864		colorImage.get(),
1865		auxiliarImage.get(),
1866	};
1867	const std::vector<vk::VkImageView>	imageViews	=
1868	{
1869		colorImageView.get(),
1870		auxiliarImageView.get(),
1871	};
1872	renderPass.createFramebuffer(vkd, device, static_cast<deUint32>(imageViews.size()), images.data(), imageViews.data(), kImageExtent.width, kImageExtent.height);
1873
1874	// Empty pipeline layout for the first subpass.
1875	const PipelineLayoutWrapper emptyPipelineLayout (m_params.pipelineConstructionType, vkd, device);
1876
1877	// Pipeline layout for the second subpass.
1878	const PipelineLayoutWrapper checkPipelineLayout (m_params.pipelineConstructionType, vkd, device, descriptorSetLayout.get());
1879
1880	// Shader modules.
1881	const auto vertModule	= ShaderWrapper(vkd, device, m_context.getBinaryCollection().get("vert"), 0u);
1882	const auto writeModule	= ShaderWrapper(vkd, device, m_context.getBinaryCollection().get("frag_write"), 0u);
1883	const auto checkModule	= ShaderWrapper(vkd, device, m_context.getBinaryCollection().get("frag_check"), 0u);
1884
1885	const std::vector<vk::VkVertexInputBindingDescription> vertexBindings =
1886	{
1887		{
1888			0u,																	//	deUint32			binding;
1889			static_cast<deUint32>(sizeof(decltype(quadVertices)::value_type)),	//	deUint32			stride;
1890			vk::VK_VERTEX_INPUT_RATE_VERTEX,									//	VkVertexInputRate	inputRate;
1891		},
1892	};
1893
1894	const std::vector<vk::VkVertexInputAttributeDescription> vertexAttributes =
1895	{
1896		{
1897			0u,								//	deUint32	location;
1898			0u,								//	deUint32	binding;
1899			vk::VK_FORMAT_R32G32_SFLOAT,	//	VkFormat	format;
1900			0u,								//	deUint32	offset;
1901		},
1902	};
1903
1904	const vk::VkPipelineVertexInputStateCreateInfo vertexInputInfo =
1905	{
1906		vk::VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,	//	VkStructureType								sType;
1907		nullptr,														//	const void*									pNext;
1908		0u,																//	VkPipelineVertexInputStateCreateFlags		flags;
1909		static_cast<deUint32>(vertexBindings.size()),					//	deUint32									vertexBindingDescriptionCount;
1910		vertexBindings.data(),											//	const VkVertexInputBindingDescription*		pVertexBindingDescriptions;
1911		static_cast<deUint32>(vertexAttributes.size()),					//	deUint32									vertexAttributeDescriptionCount;
1912		vertexAttributes.data(),										//	const VkVertexInputAttributeDescription*	pVertexAttributeDescriptions;
1913	};
1914
1915	const vk::VkPipelineInputAssemblyStateCreateInfo inputAssemblyInfo =
1916	{
1917		vk::VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,	//	VkStructureType							sType;
1918		nullptr,															//	const void*								pNext;
1919		0u,																	//	VkPipelineInputAssemblyStateCreateFlags	flags;
1920		vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,							//	VkPrimitiveTopology						topology;
1921		VK_FALSE,															//	VkBool32								primitiveRestartEnable;
1922	};
1923
1924	const std::vector<VkViewport>	viewport	{ vk::makeViewport(kImageExtent) };
1925	const std::vector<VkRect2D>		scissor		{ vk::makeRect2D(kImageExtent) };
1926
1927	const vk::VkPipelineMultisampleStateCreateInfo multisampleInfo =
1928	{
1929		vk::VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,	//	VkStructureType							sType;
1930		nullptr,														//	const void*								pNext;
1931		0u,																//	VkPipelineMultisampleStateCreateFlags	flags;
1932		m_params.sampleCount,											//	VkSampleCountFlagBits					rasterizationSamples;
1933		VK_FALSE,														//	VkBool32								sampleShadingEnable;
1934		1.0f,															//	float									minSampleShading;
1935		nullptr,														//	const VkSampleMask*						pSampleMask;
1936		VK_FALSE,														//	VkBool32								alphaToCoverageEnable;
1937		VK_FALSE,														//	VkBool32								alphaToOneEnable;
1938	};
1939
1940	const auto stencilState = vk::makeStencilOpState(vk::VK_STENCIL_OP_KEEP, vk::VK_STENCIL_OP_KEEP, vk::VK_STENCIL_OP_KEEP, vk::VK_COMPARE_OP_ALWAYS, 0xFFu, 0xFFu, 0u);
1941
1942	const vk::VkPipelineDepthStencilStateCreateInfo depthStencilInfo =
1943	{
1944		vk::VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,	//	VkStructureType							sType;
1945		nullptr,														//	const void*								pNext;
1946		0u,																//	VkPipelineDepthStencilStateCreateFlags	flags;
1947		VK_FALSE,														//	VkBool32								depthTestEnable;
1948		VK_FALSE,														//	VkBool32								depthWriteEnable;
1949		vk::VK_COMPARE_OP_ALWAYS,										//	VkCompareOp								depthCompareOp;
1950		VK_FALSE,														//	VkBool32								depthBoundsTestEnable;
1951		VK_FALSE,														//	VkBool32								stencilTestEnable;
1952		stencilState,													//	VkStencilOpState						front;
1953		stencilState,													//	VkStencilOpState						back;
1954		0.0f,															//	float									minDepthBounds;
1955		1.0f,															//	float									maxDepthBounds;
1956	};
1957
1958	const vk::VkPipelineColorBlendAttachmentState colorBlendAttachmentState =
1959	{
1960		VK_FALSE,					//	VkBool32				blendEnable;
1961		vk::VK_BLEND_FACTOR_ZERO,	//	VkBlendFactor			srcColorBlendFactor;
1962		vk::VK_BLEND_FACTOR_ZERO,	//	VkBlendFactor			dstColorBlendFactor;
1963		vk::VK_BLEND_OP_ADD,		//	VkBlendOp				colorBlendOp;
1964		vk::VK_BLEND_FACTOR_ZERO,	//	VkBlendFactor			srcAlphaBlendFactor;
1965		vk::VK_BLEND_FACTOR_ZERO,	//	VkBlendFactor			dstAlphaBlendFactor;
1966		vk::VK_BLEND_OP_ADD,		//	VkBlendOp				alphaBlendOp;
1967		(							//	VkColorComponentFlags	colorWriteMask;
1968			vk::VK_COLOR_COMPONENT_R_BIT	|
1969			vk::VK_COLOR_COMPONENT_G_BIT	|
1970			vk::VK_COLOR_COMPONENT_B_BIT	|
1971			vk::VK_COLOR_COMPONENT_A_BIT	),
1972	};
1973
1974	const vk::VkPipelineColorBlendStateCreateInfo colorBlendInfo =
1975	{
1976		vk::VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,	//	VkStructureType								sType;
1977		nullptr,														//	const void*									pNext;
1978		0u,																//	VkPipelineColorBlendStateCreateFlags		flags;
1979		VK_FALSE,														//	VkBool32									logicOpEnable;
1980		vk::VK_LOGIC_OP_NO_OP,											//	VkLogicOp									logicOp;
1981		1u,																//	deUint32									attachmentCount;
1982		&colorBlendAttachmentState,										//	const VkPipelineColorBlendAttachmentState*	pAttachments;
1983		{ .0f, .0f, .0f, .0f },											//	float										blendConstants[4];
1984	};
1985
1986	const vk::VkPipelineDynamicStateCreateInfo dynamicStateInfo =
1987	{
1988		vk::VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,	//	VkStructureType						sType;
1989		nullptr,													//	const void*							pNext;
1990		0u,															//	VkPipelineDynamicStateCreateFlags	flags;
1991		0u,															//	deUint32							dynamicStateCount;
1992		nullptr,													//	const VkDynamicState*				pDynamicStates;
1993	};
1994
1995	// Pipeline for the first subpass.
1996	vk::GraphicsPipelineWrapper firstSubpassPipeline(vki, vkd, physicalDevice, device, m_context.getDeviceExtensions(), m_params.pipelineConstructionType);
1997	firstSubpassPipeline.setDynamicState(&dynamicStateInfo)
1998						.setDefaultRasterizationState()
1999						.setupVertexInputState(&vertexInputInfo, &inputAssemblyInfo)
2000						.setupPreRasterizationShaderState(viewport, scissor, emptyPipelineLayout, *renderPass, 0u, vertModule)
2001						.setupFragmentShaderState(emptyPipelineLayout, *renderPass, 0u, writeModule, &depthStencilInfo, &multisampleInfo)
2002						.setupFragmentOutputState(*renderPass, 0u, &colorBlendInfo, &multisampleInfo)
2003						.setMonolithicPipelineLayout(emptyPipelineLayout)
2004						.buildPipeline();
2005
2006	// Pipeline for the second subpass.
2007	vk::GraphicsPipelineWrapper secondSubpassPipeline(vki, vkd, physicalDevice, device, m_context.getDeviceExtensions(), m_params.pipelineConstructionType);
2008	secondSubpassPipeline.setDynamicState(&dynamicStateInfo)
2009						.setDefaultRasterizationState()
2010						.setupVertexInputState(&vertexInputInfo, &inputAssemblyInfo)
2011						.setupPreRasterizationShaderState(viewport, scissor, checkPipelineLayout, *renderPass, 1u, vertModule)
2012						.setupFragmentShaderState(checkPipelineLayout, *renderPass, 1u, checkModule, &depthStencilInfo, &multisampleInfo)
2013						.setupFragmentOutputState(*renderPass, 1u, &colorBlendInfo, &multisampleInfo)
2014						.setMonolithicPipelineLayout(checkPipelineLayout)
2015						.buildPipeline();
2016
2017	// Command pool and command buffer.
2018	const auto cmdPool		= vk::makeCommandPool(vkd, device, queueFamilyIndex);
2019	const auto cmdBufferPtr	= vk::allocateCommandBuffer(vkd, device, cmdPool.get(), vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY);
2020	const auto cmdBuffer	= cmdBufferPtr.get();
2021
2022	// Update descriptor set.
2023	vk::DescriptorSetUpdateBuilder updateBuilder;
2024	const auto imageInfo	= vk::makeDescriptorImageInfo(DE_NULL, colorImageView.get(), vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
2025	const auto bufferInfo	= vk::makeDescriptorBufferInfo(storageBuffer.get(), 0u, VK_WHOLE_SIZE);
2026	updateBuilder.writeSingle(descriptorSet.get(), vk::DescriptorSetUpdateBuilder::Location::binding(0u), vk::VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, &imageInfo);
2027	updateBuilder.writeSingle(descriptorSet.get(), vk::DescriptorSetUpdateBuilder::Location::binding(1u), vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &bufferInfo);
2028	updateBuilder.update(vkd, device);
2029
2030	// Output buffer pipeline barrier.
2031	const auto bufferBarrier = vk::makeBufferMemoryBarrier(vk::VK_ACCESS_SHADER_WRITE_BIT, vk::VK_ACCESS_HOST_READ_BIT, storageBuffer.get(), 0ull, VK_WHOLE_SIZE);
2032
2033	// Run pipelines.
2034	vk::beginCommandBuffer(vkd, cmdBuffer);
2035
2036	renderPass.begin(vkd, cmdBuffer, vk::makeRect2D(kImageExtent), WriteSampleMaskTestCase::kClearColor);
2037	vkd.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
2038	firstSubpassPipeline.bind(cmdBuffer);
2039	vkd.cmdDraw(cmdBuffer, static_cast<deUint32>(quadVertices.size()), 1u, 0u, 0u);
2040
2041	renderPass.nextSubpass(vkd, cmdBuffer, vk::VK_SUBPASS_CONTENTS_INLINE);
2042	secondSubpassPipeline.bind(cmdBuffer);
2043	vkd.cmdBindDescriptorSets(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, checkPipelineLayout.get(), 0u, 1u, &descriptorSet.get(), 0u, nullptr);
2044	vkd.cmdDraw(cmdBuffer, static_cast<deUint32>(quadVertices.size()), 1u, 0u, 0u);
2045
2046	renderPass.end(vkd, cmdBuffer);
2047	vkd.cmdPipelineBarrier(cmdBuffer, vk::VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, vk::VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u, nullptr, 1u, &bufferBarrier, 0u, nullptr);
2048	vk::endCommandBuffer(vkd, cmdBuffer);
2049
2050	vk::submitCommandsAndWait(vkd, device, queue, cmdBuffer);
2051
2052	// Check buffer contents.
2053	auto&					bufferAlloc		= storageBuffer.getAllocation();
2054	const void*				bufferPtr		= bufferAlloc.getHostPtr();
2055	std::vector<deInt32>	bufferContents	(kBufferElems, 0);
2056
2057	vk::invalidateAlloc(vkd, device, bufferAlloc);
2058	deMemcpy(bufferContents.data(), bufferPtr, static_cast<size_t>(kBufferSize));
2059
2060	const auto sampleCount	= static_cast<deUint32>(m_params.sampleCount);
2061	const auto bpc			= bitsPerCoord(sampleCount);
2062
2063	for (deUint32 x = 0; x < kImageExtent.width; ++x)
2064	for (deUint32 y = 0; y < kImageExtent.height; ++y)
2065	{
2066		// Samples on which we expect writes.
2067		const deUint32 sampleMask = ((x << bpc) | y);
2068
2069		// Starting location for the pixel sample values in the buffer.
2070		const deUint32 pixelOffset = (y * kImageExtent.width + x) * sampleCount;
2071
2072		for (deUint32 s = 0; s < sampleCount; ++s)
2073		{
2074			const deUint32 sampleIndex	= pixelOffset + s;
2075			const deInt32& value		= bufferContents[sampleIndex];
2076
2077			if (value != 0 && value != 1)
2078			{
2079				// Garbage!
2080				std::ostringstream msg;
2081				msg << "Found garbage value " << value << " in buffer position " << sampleIndex << " (x=" << x << ", y=" << y << ", sample=" << s << ")";
2082				return tcu::TestStatus::fail(msg.str());
2083			}
2084
2085			const deInt32 expected = (((sampleMask & (1u << s)) != 0u) ? 1 : 0);
2086			if (value != expected)
2087			{
2088				std::ostringstream msg;
2089				msg << "Read " << value << " while expecting " << expected << " in buffer position " << sampleIndex << " (x=" << x << ", y=" << y << ", sample=" << s << ")";
2090				return tcu::TestStatus::fail(msg.str());
2091			}
2092		}
2093	}
2094
2095	return tcu::TestStatus::pass("Pass");
2096}
2097
2098} // multisample
2099
2100tcu::TestCaseGroup* createMultisampleShaderBuiltInTests (tcu::TestContext& testCtx, vk::PipelineConstructionType pipelineConstructionType)
2101{
2102	de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "multisample_shader_builtin"));
2103
2104	const tcu::UVec3 imageSizes[] =
2105	{
2106		tcu::UVec3(128u, 128u, 1u),
2107		tcu::UVec3(137u, 191u, 1u),
2108	};
2109
2110	const deUint32 sizesElemCount = static_cast<deUint32>(sizeof(imageSizes) / sizeof(tcu::UVec3));
2111
2112	const vk::VkSampleCountFlagBits samplesSetFull[] =
2113	{
2114		vk::VK_SAMPLE_COUNT_2_BIT,
2115		vk::VK_SAMPLE_COUNT_4_BIT,
2116		vk::VK_SAMPLE_COUNT_8_BIT,
2117		vk::VK_SAMPLE_COUNT_16_BIT,
2118		vk::VK_SAMPLE_COUNT_32_BIT,
2119		vk::VK_SAMPLE_COUNT_64_BIT,
2120	};
2121
2122	const deUint32 samplesSetFullCount = static_cast<deUint32>(sizeof(samplesSetFull) / sizeof(vk::VkSampleCountFlagBits));
2123
2124	testGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseSampleID> >(testCtx, "sample_id", pipelineConstructionType, imageSizes, sizesElemCount, samplesSetFull, samplesSetFullCount));
2125
2126	de::MovePtr<tcu::TestCaseGroup> samplePositionGroup(new tcu::TestCaseGroup(testCtx, "sample_position"));
2127
2128	samplePositionGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseSamplePosDistribution> >(testCtx, "distribution", pipelineConstructionType, imageSizes, sizesElemCount, samplesSetFull, samplesSetFullCount));
2129	samplePositionGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseSamplePosCorrectness> > (testCtx, "correctness", pipelineConstructionType, imageSizes, sizesElemCount, samplesSetFull, samplesSetFullCount));
2130
2131	testGroup->addChild(samplePositionGroup.release());
2132
2133	const vk::VkSampleCountFlagBits samplesSetReduced[] =
2134	{
2135		vk::VK_SAMPLE_COUNT_2_BIT,
2136		vk::VK_SAMPLE_COUNT_4_BIT,
2137		vk::VK_SAMPLE_COUNT_8_BIT,
2138		vk::VK_SAMPLE_COUNT_16_BIT,
2139		vk::VK_SAMPLE_COUNT_32_BIT,
2140	};
2141
2142	const deUint32 samplesSetReducedCount = static_cast<deUint32>(DE_LENGTH_OF_ARRAY(samplesSetReduced));
2143
2144	de::MovePtr<tcu::TestCaseGroup> sampleMaskGroup(new tcu::TestCaseGroup(testCtx, "sample_mask"));
2145
2146	sampleMaskGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseSampleMaskPattern> >	(testCtx, "pattern",		pipelineConstructionType, imageSizes, sizesElemCount, samplesSetReduced, samplesSetReducedCount));
2147	sampleMaskGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseSampleMaskBitCount> >	(testCtx, "bit_count",		pipelineConstructionType, imageSizes, sizesElemCount, samplesSetReduced, samplesSetReducedCount));
2148	sampleMaskGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseSampleMaskBitCount> >	(testCtx, "bit_count_0_5",	pipelineConstructionType, imageSizes, sizesElemCount, samplesSetReduced, samplesSetReducedCount, multisample::ComponentData{}, 0.5f));
2149	sampleMaskGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseSampleMaskCorrectBit> >(testCtx, "correct_bit",	pipelineConstructionType, imageSizes, sizesElemCount, samplesSetReduced, samplesSetReducedCount));
2150	sampleMaskGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseSampleMaskWrite> >		(testCtx, "write",			pipelineConstructionType, imageSizes, sizesElemCount, samplesSetReduced, samplesSetReducedCount));
2151
2152	testGroup->addChild(sampleMaskGroup.release());
2153
2154	// Write image sample tests using a storage images (tests construct only compute pipeline).
2155	if (pipelineConstructionType == vk::PIPELINE_CONSTRUCTION_TYPE_MONOLITHIC)
2156	{
2157		// Test OpImageWrite with a sample ID
2158		de::MovePtr<tcu::TestCaseGroup> imageWriteSampleGroup(new tcu::TestCaseGroup(testCtx, "image_write_sample"));
2159
2160		for (auto count : multisample::kValidSquareSampleCounts)
2161		{
2162			if (count == vk::VK_SAMPLE_COUNT_1_BIT)
2163				continue;
2164
2165			multisample::WriteSampleParams params { pipelineConstructionType, static_cast<vk::VkSampleCountFlagBits>(count) };
2166			const auto countStr = de::toString(count);
2167			imageWriteSampleGroup->addChild(new multisample::WriteSampleTest(testCtx, countStr + "_samples", params));
2168		}
2169
2170		testGroup->addChild(imageWriteSampleGroup.release());
2171	}
2172
2173	// Write to gl_SampleMask from the fragment shader.
2174	{
2175		de::MovePtr<tcu::TestCaseGroup> writeSampleMaskGroup(new tcu::TestCaseGroup(testCtx, "write_sample_mask"));
2176
2177		for (auto count : multisample::kValidSquareSampleCounts)
2178		{
2179			multisample::WriteSampleMaskParams params { pipelineConstructionType, static_cast<vk::VkSampleCountFlagBits>(count) };
2180			const auto countStr = de::toString(count);
2181			writeSampleMaskGroup->addChild(new multisample::WriteSampleMaskTestCase(testCtx, countStr + "_samples", params));
2182		}
2183
2184		testGroup->addChild(writeSampleMaskGroup.release());
2185	}
2186
2187	return testGroup.release();
2188}
2189
2190} // pipeline
2191} // vkt
2192