1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2016 The Khronos Group Inc.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 *      http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*
20 * \file vktPipelineMultisampleInterpolationTests.cpp
21 * \brief Multisample Interpolation Tests
22 *//*--------------------------------------------------------------------*/
23 
24 #include "vktPipelineMultisampleInterpolationTests.hpp"
25 #include "vktPipelineMultisampleBaseResolve.hpp"
26 #include "vktPipelineMultisampleTestsUtil.hpp"
27 #include "vktPipelineMakeUtil.hpp"
28 #include "vkQueryUtil.hpp"
29 #include "tcuTestLog.hpp"
30 #include <vector>
31 
32 namespace vkt
33 {
34 namespace pipeline
35 {
36 namespace multisample
37 {
38 
39 using namespace vk;
40 
41 struct VertexDataNdc
42 {
VertexDataNdcvkt::pipeline::multisample::VertexDataNdc43 	VertexDataNdc (const tcu::Vec4& posNdc) : positionNdc(posNdc) {}
44 
45 	tcu::Vec4 positionNdc;
46 };
47 
48 struct VertexDataNdcScreen
49 {
VertexDataNdcScreenvkt::pipeline::multisample::VertexDataNdcScreen50 	VertexDataNdcScreen (const tcu::Vec4& posNdc, const tcu::Vec2& posScreen) : positionNdc(posNdc), positionScreen(posScreen) {}
51 
52 	tcu::Vec4 positionNdc;
53 	tcu::Vec2 positionScreen;
54 };
55 
56 struct VertexDataNdcBarycentric
57 {
VertexDataNdcBarycentricvkt::pipeline::multisample::VertexDataNdcBarycentric58 	VertexDataNdcBarycentric (const tcu::Vec4& posNdc, const tcu::Vec3& barCoord) : positionNdc(posNdc), barycentricCoord(barCoord) {}
59 
60 	tcu::Vec4 positionNdc;
61 	tcu::Vec3 barycentricCoord;
62 };
63 
checkForError(const vk::VkImageCreateInfo & imageRSInfo,const tcu::ConstPixelBufferAccess & dataRS,const deUint32 errorCompNdx)64 bool checkForError (const vk::VkImageCreateInfo& imageRSInfo, const tcu::ConstPixelBufferAccess& dataRS, const deUint32 errorCompNdx)
65 {
66 	for (deUint32 z = 0u; z < imageRSInfo.extent.depth;  ++z)
67 	for (deUint32 y = 0u; y < imageRSInfo.extent.height; ++y)
68 	for (deUint32 x = 0u; x < imageRSInfo.extent.width;  ++x)
69 	{
70 		const deUint32 errorComponent = dataRS.getPixelUint(x, y, z)[errorCompNdx];
71 
72 		if (errorComponent > 0)
73 			return true;
74 	}
75 
76 	return false;
77 }
78 
79 template <typename CaseClassName>
80 class MSCase : public MultisampleCaseBase
81 {
82 public:
MSCase(tcu::TestContext & testCtx,const std::string & name,const ImageMSParams & imageMSParams)83 								MSCase			(tcu::TestContext&		testCtx,
84 												 const std::string&		name,
85 												 const ImageMSParams&	imageMSParams)
86 								: MultisampleCaseBase(testCtx, name, imageMSParams) {}
87 
88 	void						init			(void);
89 	void						initPrograms	(vk::SourceCollections& programCollection) const;
90 	TestInstance*				createInstance	(Context&				context) const;
91 	static MultisampleCaseBase*	createCase		(tcu::TestContext&		testCtx,
92 												 const std::string&		name,
93 												 const ImageMSParams&	imageMSParams);
94 };
95 
96 template <typename CaseClassName>
createCase(tcu::TestContext & testCtx,const std::string & name,const ImageMSParams & imageMSParams)97 MultisampleCaseBase* MSCase<CaseClassName>::createCase (tcu::TestContext& testCtx, const std::string& name, const ImageMSParams& imageMSParams)
98 {
99 	return new MSCase<CaseClassName>(testCtx, name, imageMSParams);
100 }
101 
102 template <typename InstanceClassName>
103 class MSInstance : public MSInstanceBaseResolve
104 {
105 public:
MSInstance(Context & context,const ImageMSParams & imageMSParams)106 					MSInstance				(Context&							context,
107 											 const ImageMSParams&				imageMSParams)
108 					: MSInstanceBaseResolve(context, imageMSParams) {}
109 
110 	VertexDataDesc	getVertexDataDescripton	(void) const;
111 	void			uploadVertexData		(const Allocation&					vertexBufferAllocation,
112 											 const VertexDataDesc&				vertexDataDescripton) const;
113 	tcu::TestStatus	verifyImageData			(const vk::VkImageCreateInfo&		imageRSInfo,
114 											 const tcu::ConstPixelBufferAccess& dataRS) const;
115 };
116 
117 class MSInstanceDistinctValues;
118 
getVertexDataDescripton(void) const119 template<> MultisampleInstanceBase::VertexDataDesc MSInstance<MSInstanceDistinctValues>::getVertexDataDescripton (void) const
120 {
121 	VertexDataDesc vertexDataDesc;
122 
123 	vertexDataDesc.verticesCount		= 3u;
124 	vertexDataDesc.dataStride			= sizeof(VertexDataNdc);
125 	vertexDataDesc.dataSize				= vertexDataDesc.verticesCount * vertexDataDesc.dataStride;
126 	vertexDataDesc.primitiveTopology	= VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
127 
128 	const VkVertexInputAttributeDescription vertexAttribPositionNdc =
129 	{
130 		0u,										// deUint32	location;
131 		0u,										// deUint32	binding;
132 		VK_FORMAT_R32G32B32A32_SFLOAT,			// VkFormat	format;
133 		DE_OFFSET_OF(VertexDataNdc, positionNdc),	// deUint32	offset;
134 	};
135 
136 	vertexDataDesc.vertexAttribDescVec.push_back(vertexAttribPositionNdc);
137 
138 	return vertexDataDesc;
139 }
140 
uploadVertexData(const Allocation & vertexBufferAllocation,const VertexDataDesc & vertexDataDescripton) const141 template<> void MSInstance<MSInstanceDistinctValues>::uploadVertexData (const Allocation& vertexBufferAllocation, const VertexDataDesc& vertexDataDescripton) const
142 {
143 	std::vector<VertexDataNdc> vertices;
144 
145 	vertices.push_back(VertexDataNdc(tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f)));
146 	vertices.push_back(VertexDataNdc(tcu::Vec4(-1.0f,  4.0f, 0.0f, 1.0f)));
147 	vertices.push_back(VertexDataNdc(tcu::Vec4( 4.0f, -1.0f, 0.0f, 1.0f)));
148 
149 	deMemcpy(vertexBufferAllocation.getHostPtr(), dataPointer(vertices), static_cast<std::size_t>(vertexDataDescripton.dataSize));
150 }
151 
verifyImageData(const vk::VkImageCreateInfo & imageRSInfo,const tcu::ConstPixelBufferAccess & dataRS) const152 template<> tcu::TestStatus MSInstance<MSInstanceDistinctValues>::verifyImageData (const vk::VkImageCreateInfo& imageRSInfo, const tcu::ConstPixelBufferAccess& dataRS) const
153 {
154 	const deUint32 distinctValuesExpected = static_cast<deUint32>(m_imageMSParams.numSamples) + 1u;
155 
156 	std::vector<tcu::IVec4> distinctValues;
157 
158 	for (deUint32 z = 0u; z < imageRSInfo.extent.depth;	 ++z)
159 	for (deUint32 y = 0u; y < imageRSInfo.extent.height; ++y)
160 	for (deUint32 x = 0u; x < imageRSInfo.extent.width;	 ++x)
161 	{
162 		const tcu::IVec4 pixel = dataRS.getPixelInt(x, y, z);
163 
164 		if (std::find(distinctValues.begin(), distinctValues.end(), pixel) == distinctValues.end())
165 			distinctValues.push_back(pixel);
166 	}
167 
168 	if (distinctValues.size() >= distinctValuesExpected)
169 		return tcu::TestStatus::pass("Passed");
170 	else
171 		return tcu::TestStatus::fail("Expected numSamples+1 different colors in the output image");
172 }
173 
174 class MSCaseSampleQualifierDistinctValues;
175 
init(void)176 template<> void MSCase<MSCaseSampleQualifierDistinctValues>::init (void)
177 {
178 	m_testCtx.getLog()
179 		<< tcu::TestLog::Message
180 		<< "Verifying that a sample qualified varying is given different values for different samples.\n"
181 		<< "	Render full screen traingle with quadratic function defining red/green color pattern division.\n"
182 		<< "	=> Resulting image should contain n+1 different colors, where n = sample count.\n"
183 		<< tcu::TestLog::EndMessage;
184 
185 	MultisampleCaseBase::init();
186 }
187 
initPrograms(vk::SourceCollections & programCollection) const188 template<> void MSCase<MSCaseSampleQualifierDistinctValues>::initPrograms (vk::SourceCollections& programCollection) const
189 {
190 	// Create vertex shader
191 	std::ostringstream vs;
192 
193 	vs << "#version 440\n"
194 		<< "layout(location = 0) in vec4 vs_in_position_ndc;\n"
195 		<< "\n"
196 		<< "layout(location = 0) out vec4 vs_out_position_ndc;\n"
197 		<< "\n"
198 		<< "out gl_PerVertex {\n"
199 		<< "	vec4  gl_Position;\n"
200 		<< "};\n"
201 		<< "void main (void)\n"
202 		<< "{\n"
203 		<< "	gl_Position			= vs_in_position_ndc;\n"
204 		<< "	vs_out_position_ndc = vs_in_position_ndc;\n"
205 		<< "}\n";
206 
207 	programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
208 
209 	// Create fragment shader
210 	std::ostringstream fs;
211 
212 	fs << "#version 440\n"
213 		<< "layout(location = 0) sample in vec4 fs_in_position_ndc;\n"
214 		<< "\n"
215 		<< "layout(location = 0) out vec4 fs_out_color;\n"
216 		<< "\n"
217 		<< "void main (void)\n"
218 		<< "{\n"
219 		<< "	if(fs_in_position_ndc.y < -2.0*pow(0.5*(fs_in_position_ndc.x + 1.0), 2.0) + 1.0)\n"
220 		<< "		fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
221 		<< "	else\n"
222 		<< "		fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
223 		<< "}\n";
224 
225 	programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
226 }
227 
createInstance(Context & context) const228 template<> TestInstance* MSCase<MSCaseSampleQualifierDistinctValues>::createInstance (Context& context) const
229 {
230 	if (!context.getDeviceFeatures().sampleRateShading)
231 		TCU_THROW(NotSupportedError, "sampleRateShading support required");
232 	return new MSInstance<MSInstanceDistinctValues>(context, m_imageMSParams);
233 }
234 
235 class MSCaseInterpolateAtSampleDistinctValues;
236 
init(void)237 template<> void MSCase<MSCaseInterpolateAtSampleDistinctValues>::init (void)
238 {
239 	m_testCtx.getLog()
240 		<< tcu::TestLog::Message
241 		<< "Verifying that a interpolateAtSample returns different values for different samples.\n"
242 		<< "	Render full screen traingle with quadratic function defining red/green color pattern division.\n"
243 		<< "	=> Resulting image should contain n+1 different colors, where n = sample count.\n"
244 		<< tcu::TestLog::EndMessage;
245 
246 	MultisampleCaseBase::init();
247 }
248 
initPrograms(vk::SourceCollections & programCollection) const249 template<> void MSCase<MSCaseInterpolateAtSampleDistinctValues>::initPrograms (vk::SourceCollections& programCollection) const
250 {
251 	// Create vertex shader
252 	std::ostringstream vs;
253 
254 	vs << "#version 440\n"
255 		<< "layout(location = 0) in vec4 vs_in_position_ndc;\n"
256 		<< "\n"
257 		<< "layout(location = 0) out vec4 vs_out_position_ndc;\n"
258 		<< "\n"
259 		<< "out gl_PerVertex {\n"
260 		<< "	vec4  gl_Position;\n"
261 		<< "};\n"
262 		<< "void main (void)\n"
263 		<< "{\n"
264 		<< "	gl_Position			= vs_in_position_ndc;\n"
265 		<< "	vs_out_position_ndc = vs_in_position_ndc;\n"
266 		<< "}\n";
267 
268 	programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
269 
270 	// Create fragment shader
271 	std::ostringstream fs;
272 
273 	fs << "#version 440\n"
274 		<< "layout(location = 0) in vec4 fs_in_position_ndc;\n"
275 		<< "\n"
276 		<< "layout(location = 0) out vec4 fs_out_color;\n"
277 		<< "\n"
278 		<< "void main (void)\n"
279 		<< "{\n"
280 		<< "	const vec4 position_ndc_at_sample = interpolateAtSample(fs_in_position_ndc, gl_SampleID);\n"
281 		<< "	if(position_ndc_at_sample.y < -2.0*pow(0.5*(position_ndc_at_sample.x + 1.0), 2.0) + 1.0)\n"
282 		<< "		fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
283 		<< "	else\n"
284 		<< "		fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
285 		<< "}\n";
286 
287 	programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
288 }
289 
createInstance(Context & context) const290 template<> TestInstance* MSCase<MSCaseInterpolateAtSampleDistinctValues>::createInstance (Context& context) const
291 {
292 	if (!context.getDeviceFeatures().sampleRateShading)
293 		TCU_THROW(NotSupportedError, "sampleRateShading support required");
294 
295 	return new MSInstance<MSInstanceDistinctValues>(context, m_imageMSParams);
296 }
297 
298 class MSInstanceInterpolateScreenPosition;
299 
getVertexDataDescripton(void) const300 template<> MSInstanceBaseResolve::VertexDataDesc MSInstance<MSInstanceInterpolateScreenPosition>::getVertexDataDescripton (void) const
301 {
302 	VertexDataDesc vertexDataDesc;
303 
304 	vertexDataDesc.verticesCount		= 4u;
305 	vertexDataDesc.dataStride			= sizeof(VertexDataNdcScreen);
306 	vertexDataDesc.dataSize				= vertexDataDesc.verticesCount * vertexDataDesc.dataStride;
307 	vertexDataDesc.primitiveTopology	= VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
308 
309 	const VkVertexInputAttributeDescription vertexAttribPositionNdc =
310 	{
311 		0u,												// deUint32	location;
312 		0u,												// deUint32	binding;
313 		VK_FORMAT_R32G32B32A32_SFLOAT,					// VkFormat	format;
314 		DE_OFFSET_OF(VertexDataNdcScreen, positionNdc),	// deUint32	offset;
315 	};
316 
317 	vertexDataDesc.vertexAttribDescVec.push_back(vertexAttribPositionNdc);
318 
319 	const VkVertexInputAttributeDescription vertexAttribPositionScreen =
320 	{
321 		1u,											// deUint32	location;
322 		0u,											// deUint32	binding;
323 		VK_FORMAT_R32G32_SFLOAT,					// VkFormat	format;
324 		DE_OFFSET_OF(VertexDataNdcScreen, positionScreen),	// deUint32	offset;
325 	};
326 
327 	vertexDataDesc.vertexAttribDescVec.push_back(vertexAttribPositionScreen);
328 
329 	return vertexDataDesc;
330 }
331 
uploadVertexData(const Allocation & vertexBufferAllocation,const VertexDataDesc & vertexDataDescripton) const332 template<> void MSInstance<MSInstanceInterpolateScreenPosition>::uploadVertexData (const Allocation& vertexBufferAllocation, const VertexDataDesc& vertexDataDescripton) const
333 {
334 	const tcu::UVec3 layerSize		= getLayerSize(IMAGE_TYPE_2D, m_imageMSParams.imageSize);
335 	const float		 screenSizeX	= static_cast<float>(layerSize.x());
336 	const float		 screenSizeY	= static_cast<float>(layerSize.y());
337 
338 	std::vector<VertexDataNdcScreen> vertices;
339 
340 	vertices.push_back(VertexDataNdcScreen(tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f), tcu::Vec2(0.0f, 0.0f)));
341 	vertices.push_back(VertexDataNdcScreen(tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f), tcu::Vec2(screenSizeX, 0.0f)));
342 	vertices.push_back(VertexDataNdcScreen(tcu::Vec4(-1.0f,  1.0f, 0.0f, 1.0f), tcu::Vec2(0.0f, screenSizeY)));
343 	vertices.push_back(VertexDataNdcScreen(tcu::Vec4( 1.0f,  1.0f, 0.0f, 1.0f), tcu::Vec2(screenSizeX, screenSizeY)));
344 
345 	deMemcpy(vertexBufferAllocation.getHostPtr(), dataPointer(vertices), static_cast<std::size_t>(vertexDataDescripton.dataSize));
346 }
347 
verifyImageData(const vk::VkImageCreateInfo & imageRSInfo,const tcu::ConstPixelBufferAccess & dataRS) const348 template<> tcu::TestStatus MSInstance<MSInstanceInterpolateScreenPosition>::verifyImageData (const vk::VkImageCreateInfo& imageRSInfo, const tcu::ConstPixelBufferAccess& dataRS) const
349 {
350 	if (checkForError(imageRSInfo, dataRS, 0))
351 		return tcu::TestStatus::fail("Failed");
352 
353 	return tcu::TestStatus::pass("Passed");
354 }
355 
356 class MSCaseInterpolateAtSampleSingleSample;
357 
init(void)358 template<> void MSCase<MSCaseInterpolateAtSampleSingleSample>::init (void)
359 {
360 	m_testCtx.getLog()
361 		<< tcu::TestLog::Message
362 		<< "Verifying that using interpolateAtSample with multisample buffers not available returns sample evaluated at the center of the pixel.\n"
363 		<< "	Interpolate varying containing screen space location.\n"
364 		<< "	=> fract(screen space location) should be (about) (0.5, 0.5)\n"
365 		<< tcu::TestLog::EndMessage;
366 
367 	MultisampleCaseBase::init();
368 }
369 
initPrograms(vk::SourceCollections & programCollection) const370 template<> void MSCase<MSCaseInterpolateAtSampleSingleSample>::initPrograms (vk::SourceCollections& programCollection) const
371 {
372 	// Create vertex shader
373 	std::ostringstream vs;
374 
375 	vs << "#version 440\n"
376 		<< "layout(location = 0) in vec4 vs_in_position_ndc;\n"
377 		<< "layout(location = 1) in vec2 vs_in_position_screen;\n"
378 		<< "\n"
379 		<< "layout(location = 0) out vec2 vs_out_position_screen;\n"
380 		<< "\n"
381 		<< "out gl_PerVertex {\n"
382 		<< "	vec4  gl_Position;\n"
383 		<< "};\n"
384 		<< "void main (void)\n"
385 		<< "{\n"
386 		<< "	gl_Position				= vs_in_position_ndc;\n"
387 		<< "	vs_out_position_screen	= vs_in_position_screen;\n"
388 		<< "}\n";
389 
390 	programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
391 
392 	// Create fragment shader
393 	std::ostringstream fs;
394 
395 	fs << "#version 440\n"
396 		<< "layout(location = 0) in vec2 fs_in_position_screen;\n"
397 		<< "\n"
398 		<< "layout(location = 0) out vec4 fs_out_color;\n"
399 		<< "\n"
400 		<< "void main (void)\n"
401 		<< "{\n"
402 		<< "	const float threshold					= 0.15625;\n"
403 		<< "	const vec2  position_screen_at_sample	= interpolateAtSample(fs_in_position_screen, 0);\n"
404 		<< "	const vec2  position_inside_pixel		= fract(position_screen_at_sample);\n"
405 		<< "\n"
406 		<< "	if (abs(position_inside_pixel.x - 0.5) <= threshold && abs(position_inside_pixel.y - 0.5) <= threshold)\n"
407 		<< "		fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
408 		<< "	else\n"
409 		<< "		fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
410 		<< "}\n";
411 
412 	programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
413 }
414 
createInstance(Context & context) const415 template<> TestInstance* MSCase<MSCaseInterpolateAtSampleSingleSample>::createInstance (Context& context) const
416 {
417 	if (!context.getDeviceFeatures().sampleRateShading)
418 		TCU_THROW(NotSupportedError, "sampleRateShading support required");
419 
420 	return new MSInstance<MSInstanceInterpolateScreenPosition>(context, m_imageMSParams);
421 }
422 
423 class MSCaseInterpolateAtSampleIgnoresCentroid;
424 
init(void)425 template<> void MSCase<MSCaseInterpolateAtSampleIgnoresCentroid>::init (void)
426 {
427 	m_testCtx.getLog()
428 		<< tcu::TestLog::Message
429 		<< "Verifying that interpolateAtSample ignores centroid qualifier.\n"
430 		<< "	Interpolate varying containing screen space location with centroid and sample qualifiers.\n"
431 		<< "	=> interpolateAtSample(screenSample, n) ~= interpolateAtSample(screenCentroid, n)\n"
432 		<< tcu::TestLog::EndMessage;
433 
434 	MultisampleCaseBase::init();
435 }
436 
initPrograms(vk::SourceCollections & programCollection) const437 template<> void MSCase<MSCaseInterpolateAtSampleIgnoresCentroid>::initPrograms (vk::SourceCollections& programCollection) const
438 {
439 	// Create vertex shader
440 	std::ostringstream vs;
441 
442 	vs << "#version 440\n"
443 		<< "layout(location = 0) in vec4 vs_in_position_ndc;\n"
444 		<< "layout(location = 1) in vec2 vs_in_position_screen;\n"
445 		<< "\n"
446 		<< "layout(location = 0) out vec2 vs_out_pos_screen_centroid;\n"
447 		<< "layout(location = 1) out vec2 vs_out_pos_screen_fragment;\n"
448 		<< "\n"
449 		<< "out gl_PerVertex {\n"
450 		<< "	vec4  gl_Position;\n"
451 		<< "};\n"
452 		<< "void main (void)\n"
453 		<< "{\n"
454 		<< "	gl_Position					= vs_in_position_ndc;\n"
455 		<< "	vs_out_pos_screen_centroid	= vs_in_position_screen;\n"
456 		<< "	vs_out_pos_screen_fragment	= vs_in_position_screen;\n"
457 		<< "}\n";
458 
459 	programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
460 
461 	// Create fragment shader
462 	std::ostringstream fs;
463 
464 	fs << "#version 440\n"
465 		<< "layout(location = 0) centroid in vec2 fs_in_pos_screen_centroid;\n"
466 		<< "layout(location = 1)		  in vec2 fs_in_pos_screen_fragment;\n"
467 		<< "\n"
468 		<< "layout(location = 0) out vec4 fs_out_color;\n"
469 		<< "\n"
470 		<< "void main (void)\n"
471 		<< "{\n"
472 		<< "	const float threshold = 0.0005;\n"
473 		<< "\n"
474 		<< "	const vec2 position_a  = interpolateAtSample(fs_in_pos_screen_centroid, gl_SampleID);\n"
475 		<< "	const vec2 position_b  = interpolateAtSample(fs_in_pos_screen_fragment, gl_SampleID);\n"
476 		<< "	const bool valuesEqual = all(lessThan(abs(position_a - position_b), vec2(threshold)));\n"
477 		<< "\n"
478 		<< "	if (valuesEqual)\n"
479 		<< "		fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
480 		<< "	else\n"
481 		<< "		fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
482 		<< "}\n";
483 
484 	programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
485 }
486 
createInstance(Context & context) const487 template<> TestInstance* MSCase<MSCaseInterpolateAtSampleIgnoresCentroid>::createInstance (Context& context) const
488 {
489 	if (!context.getDeviceFeatures().sampleRateShading)
490 		TCU_THROW(NotSupportedError, "sampleRateShading support required");
491 
492 	return new MSInstance<MSInstanceInterpolateScreenPosition>(context, m_imageMSParams);
493 }
494 
495 class MSCaseInterpolateAtSampleConsistency;
496 
init(void)497 template<> void MSCase<MSCaseInterpolateAtSampleConsistency>::init (void)
498 {
499 	m_testCtx.getLog()
500 		<< tcu::TestLog::Message
501 		<< "Verifying that interpolateAtSample with the sample set to the current sampleID returns consistent values.\n"
502 		<< "	Interpolate varying containing screen space location with centroid and sample qualifiers.\n"
503 		<< "	=> interpolateAtSample(screenCentroid, sampleID) = screenSample\n"
504 		<< tcu::TestLog::EndMessage;
505 
506 	MultisampleCaseBase::init();
507 }
508 
initPrograms(vk::SourceCollections & programCollection) const509 template<> void MSCase<MSCaseInterpolateAtSampleConsistency>::initPrograms (vk::SourceCollections& programCollection) const
510 {
511 	// Create vertex shader
512 	std::ostringstream vs;
513 
514 	vs << "#version 440\n"
515 		<< "layout(location = 0) in vec4 vs_in_position_ndc;\n"
516 		<< "layout(location = 1) in vec2 vs_in_position_screen;\n"
517 		<< "\n"
518 		<< "layout(location = 0) out vec2 vs_out_pos_screen_centroid;\n"
519 		<< "layout(location = 1) out vec2 vs_out_pos_screen_sample;\n"
520 		<< "\n"
521 		<< "out gl_PerVertex {\n"
522 		<< "	vec4  gl_Position;\n"
523 		<< "};\n"
524 		<< "void main (void)\n"
525 		<< "{\n"
526 		<< "	gl_Position					= vs_in_position_ndc;\n"
527 		<< "	vs_out_pos_screen_centroid	= vs_in_position_screen;\n"
528 		<< "	vs_out_pos_screen_sample	= vs_in_position_screen;\n"
529 		<< "}\n";
530 
531 	programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
532 
533 	// Create fragment shader
534 	std::ostringstream fs;
535 
536 	fs << "#version 440\n"
537 		<< "layout(location = 0) centroid in vec2 fs_in_pos_screen_centroid;\n"
538 		<< "layout(location = 1) sample   in vec2 fs_in_pos_screen_sample;\n"
539 		<< "\n"
540 		<< "layout(location = 0) out vec4 fs_out_color;\n"
541 		<< "\n"
542 		<< "void main (void)\n"
543 		<< "{\n"
544 		<< "	const float threshold = 0.15625;\n"
545 		<< "\n"
546 		<< "	const vec2  pos_interpolated_at_sample = interpolateAtSample(fs_in_pos_screen_centroid, gl_SampleID);\n"
547 		<< "	const bool  valuesEqual				   = all(lessThan(abs(pos_interpolated_at_sample - fs_in_pos_screen_sample), vec2(threshold)));\n"
548 		<< "\n"
549 		<< "	if (valuesEqual)\n"
550 		<< "		fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
551 		<< "	else\n"
552 		<< "		fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
553 		<< "}\n";
554 
555 	programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
556 }
557 
createInstance(Context & context) const558 template<> TestInstance* MSCase<MSCaseInterpolateAtSampleConsistency>::createInstance (Context& context) const
559 {
560 	if (!context.getDeviceFeatures().sampleRateShading)
561 		TCU_THROW(NotSupportedError, "sampleRateShading support required");
562 
563 	return new MSInstance<MSInstanceInterpolateScreenPosition>(context, m_imageMSParams);
564 }
565 
566 class MSCaseInterpolateAtCentroidConsistency;
567 
init(void)568 template<> void MSCase<MSCaseInterpolateAtCentroidConsistency>::init (void)
569 {
570 	m_testCtx.getLog()
571 		<< tcu::TestLog::Message
572 		<< "Verifying that interpolateAtCentroid does not return different values than a corresponding centroid qualified varying.\n"
573 		<< "	Interpolate varying containing screen space location with sample and centroid qualifiers.\n"
574 		<< "	=> interpolateAtCentroid(screenSample) = screenCentroid\n"
575 		<< tcu::TestLog::EndMessage;
576 
577 	MultisampleCaseBase::init();
578 }
579 
initPrograms(vk::SourceCollections & programCollection) const580 template<> void MSCase<MSCaseInterpolateAtCentroidConsistency>::initPrograms (vk::SourceCollections& programCollection) const
581 {
582 	// Create vertex shader
583 	std::ostringstream vs;
584 
585 	vs << "#version 440\n"
586 		<< "layout(location = 0) in vec4 vs_in_position_ndc;\n"
587 		<< "layout(location = 1) in vec2 vs_in_position_screen;\n"
588 		<< "\n"
589 		<< "layout(location = 0) out vec2 vs_out_pos_screen_sample;\n"
590 		<< "layout(location = 1) out vec2 vs_out_pos_screen_centroid;\n"
591 		<< "\n"
592 		<< "out gl_PerVertex {\n"
593 		<< "	vec4  gl_Position;\n"
594 		<< "};\n"
595 		<< "void main (void)\n"
596 		<< "{\n"
597 		<< "	gl_Position					= vs_in_position_ndc;\n"
598 		<< "	vs_out_pos_screen_sample	= vs_in_position_screen;\n"
599 		<< "	vs_out_pos_screen_centroid	= vs_in_position_screen;\n"
600 		<< "}\n";
601 
602 	programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
603 
604 	// Create fragment shader
605 	std::ostringstream fs;
606 
607 	fs << "#version 440\n"
608 		<< "layout(location = 0) sample   in vec2 fs_in_pos_screen_sample;\n"
609 		<< "layout(location = 1) centroid in vec2 fs_in_pos_screen_centroid;\n"
610 		<< "\n"
611 		<< "layout(location = 0) out vec4 fs_out_color;\n"
612 		<< "\n"
613 		<< "void main (void)\n"
614 		<< "{\n"
615 		<< "	const float threshold = 0.0005;\n"
616 		<< "\n"
617 		<< "	const vec2 pos_interpolated_at_centroid = interpolateAtCentroid(fs_in_pos_screen_sample);\n"
618 		<< "	const bool valuesEqual					= all(lessThan(abs(pos_interpolated_at_centroid - fs_in_pos_screen_centroid), vec2(threshold)));\n"
619 		<< "\n"
620 		<< "	if (valuesEqual)\n"
621 		<< "		fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
622 		<< "	else\n"
623 		<< "		fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
624 		<< "}\n";
625 
626 	programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
627 }
628 
createInstance(Context & context) const629 template<> TestInstance* MSCase<MSCaseInterpolateAtCentroidConsistency>::createInstance (Context& context) const
630 {
631 	if (!context.getDeviceFeatures().sampleRateShading)
632 		TCU_THROW(NotSupportedError, "sampleRateShading support required");
633 
634 	return new MSInstance<MSInstanceInterpolateScreenPosition>(context, m_imageMSParams);
635 }
636 
637 class MSCaseInterpolateAtOffsetPixelCenter;
638 
init(void)639 template<> void MSCase<MSCaseInterpolateAtOffsetPixelCenter>::init (void)
640 {
641 	m_testCtx.getLog()
642 		<< tcu::TestLog::Message
643 		<< "Verifying that interpolateAtOffset returns value sampled at an offset from the center of the pixel.\n"
644 		<< "	Interpolate varying containing screen space location.\n"
645 		<< "	=> interpolateAtOffset(screen, offset) should be \"varying value at the pixel center\" + offset"
646 		<< tcu::TestLog::EndMessage;
647 
648 	MultisampleCaseBase::init();
649 }
650 
initPrograms(vk::SourceCollections & programCollection) const651 template<> void MSCase<MSCaseInterpolateAtOffsetPixelCenter>::initPrograms (vk::SourceCollections& programCollection) const
652 {
653 	// Create vertex shader
654 	std::ostringstream vs;
655 
656 	vs << "#version 440\n"
657 		<< "layout(location = 0) in vec4 vs_in_position_ndc;\n"
658 		<< "layout(location = 1) in vec2 vs_in_position_screen;\n"
659 		<< "\n"
660 		<< "layout(location = 0) out vec2 vs_out_pos_screen;\n"
661 		<< "layout(location = 1) out vec2 vs_out_offset;\n"
662 		<< "\n"
663 		<< "out gl_PerVertex {\n"
664 		<< "	vec4  gl_Position;\n"
665 		<< "};\n"
666 		<< "void main (void)\n"
667 		<< "{\n"
668 		<< "	gl_Position			= vs_in_position_ndc;\n"
669 		<< "	vs_out_pos_screen	= vs_in_position_screen;\n"
670 		<< "	vs_out_offset		= vs_in_position_ndc.xy * 0.5;\n"
671 		<< "}\n";
672 
673 	programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
674 
675 	// Create fragment shader
676 	std::ostringstream fs;
677 
678 	fs << "#version 440\n"
679 		<< "layout(location = 0) in  vec2 fs_in_pos_screen;\n"
680 		<< "layout(location = 1) in  vec2 fs_in_offset;\n"
681 		<< "\n"
682 		<< "layout(location = 0) out vec4 fs_out_color;\n"
683 		<< "\n"
684 		<< "void main (void)\n"
685 		<< "{\n"
686 		<< "    const vec2  frag_center = interpolateAtOffset(fs_in_pos_screen, vec2(0.0));\n"
687 		<< "    const vec2  center_diff = abs(frag_center - fs_in_pos_screen);\n"
688 		<< "    const float threshold   = 0.125;\n"
689 		<< "    bool        valuesEqual = false;\n"
690 		<< "\n"
691 		<< "    if (all(lessThan(center_diff, vec2(0.5 + threshold)))) {\n"
692 		<< "        const vec2 pos_interpolated_at_offset = interpolateAtOffset(fs_in_pos_screen, fs_in_offset);\n"
693 		<< "        const vec2 reference_value            = frag_center + fs_in_offset;\n"
694 		<< "\n"
695 		<< "        valuesEqual = all(lessThan(abs(pos_interpolated_at_offset - reference_value), vec2(threshold)));\n"
696 		<< "    }\n"
697 		<< "\n"
698 		<< "    if (valuesEqual)\n"
699 		<< "        fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
700 		<< "    else\n"
701 		<< "        fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
702 		<< "}\n";
703 
704 	programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
705 }
706 
createInstance(Context & context) const707 template<> TestInstance* MSCase<MSCaseInterpolateAtOffsetPixelCenter>::createInstance (Context& context) const
708 {
709 	if (!context.getDeviceFeatures().sampleRateShading)
710 		TCU_THROW(NotSupportedError, "sampleRateShading support required");
711 
712 	return new MSInstance<MSInstanceInterpolateScreenPosition>(context, m_imageMSParams);
713 }
714 
715 class MSCaseInterpolateAtOffsetSamplePosition;
716 
init(void)717 template<> void MSCase<MSCaseInterpolateAtOffsetSamplePosition>::init (void)
718 {
719 	m_testCtx.getLog()
720 		<< tcu::TestLog::Message
721 		<< "Verifying that interpolateAtOffset of screen position with the offset of current sample position returns value "
722 		<< "similar to screen position interpolated at sample.\n"
723 		<< "	Interpolate varying containing screen space location with and without sample qualifier.\n"
724 		<< "	=> interpolateAtOffset(screenFragment, samplePosition - (0.5,0.5)) = screenSample"
725 		<< tcu::TestLog::EndMessage;
726 
727 	MultisampleCaseBase::init();
728 }
729 
initPrograms(vk::SourceCollections & programCollection) const730 template<> void MSCase<MSCaseInterpolateAtOffsetSamplePosition>::initPrograms (vk::SourceCollections& programCollection) const
731 {
732 	// Create vertex shader
733 	std::ostringstream vs;
734 
735 	vs << "#version 440\n"
736 		<< "layout(location = 0) in vec4 vs_in_position_ndc;\n"
737 		<< "layout(location = 1) in vec2 vs_in_position_screen;\n"
738 		<< "\n"
739 		<< "layout(location = 0) out vec2 vs_out_pos_screen_fragment;\n"
740 		<< "layout(location = 1) out vec2 vs_out_pos_screen_sample;\n"
741 		<< "\n"
742 		<< "out gl_PerVertex {\n"
743 		<< "	vec4  gl_Position;\n"
744 		<< "};\n"
745 		<< "void main (void)\n"
746 		<< "{\n"
747 		<< "	gl_Position					= vs_in_position_ndc;\n"
748 		<< "	vs_out_pos_screen_fragment	= vs_in_position_screen;\n"
749 		<< "	vs_out_pos_screen_sample	= vs_in_position_screen;\n"
750 		<< "}\n";
751 
752 	programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
753 
754 	// Create fragment shader
755 	std::ostringstream fs;
756 
757 	fs << "#version 440\n"
758 		<< "layout(location = 0)		in vec2 fs_in_pos_screen_fragment;\n"
759 		<< "layout(location = 1) sample in vec2 fs_in_pos_screen_sample;\n"
760 		<< "\n"
761 		<< "layout(location = 0) out vec4 fs_out_color;\n"
762 		<< "\n"
763 		<< "void main (void)\n"
764 		<< "{\n"
765 		<< "	const float threshold = 0.15625;\n"
766 		<< "\n"
767 		<< "	const vec2 offset					  = gl_SamplePosition - vec2(0.5, 0.5);\n"
768 		<< "	const vec2 pos_interpolated_at_offset = interpolateAtOffset(fs_in_pos_screen_fragment, offset);\n"
769 		<< "	const bool valuesEqual				  = all(lessThan(abs(pos_interpolated_at_offset - fs_in_pos_screen_sample), vec2(threshold)));\n"
770 		<< "\n"
771 		<< "	if (valuesEqual)\n"
772 		<< "		fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
773 		<< "	else\n"
774 		<< "		fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
775 		<< "}\n";
776 
777 	programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
778 }
779 
createInstance(Context & context) const780 template<> TestInstance* MSCase<MSCaseInterpolateAtOffsetSamplePosition>::createInstance (Context& context) const
781 {
782 	if (!context.getDeviceFeatures().sampleRateShading)
783 		TCU_THROW(NotSupportedError, "sampleRateShading support required");
784 
785 	return new MSInstance<MSInstanceInterpolateScreenPosition>(context, m_imageMSParams);
786 }
787 
788 class MSInstanceInterpolateBarycentricCoordinates;
789 
getVertexDataDescripton(void) const790 template<> MSInstanceBaseResolve::VertexDataDesc MSInstance<MSInstanceInterpolateBarycentricCoordinates>::getVertexDataDescripton (void) const
791 {
792 	VertexDataDesc vertexDataDesc;
793 
794 	vertexDataDesc.verticesCount		= 3u;
795 	vertexDataDesc.dataStride			= sizeof(VertexDataNdcBarycentric);
796 	vertexDataDesc.dataSize				= vertexDataDesc.verticesCount * vertexDataDesc.dataStride;
797 	vertexDataDesc.primitiveTopology	= VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
798 
799 	const VkVertexInputAttributeDescription vertexAttribPositionNdc =
800 	{
801 		0u,															// deUint32	location;
802 		0u,															// deUint32	binding;
803 		VK_FORMAT_R32G32B32A32_SFLOAT,								// VkFormat	format;
804 		DE_OFFSET_OF(VertexDataNdcBarycentric, positionNdc),		// deUint32	offset;
805 	};
806 
807 	vertexDataDesc.vertexAttribDescVec.push_back(vertexAttribPositionNdc);
808 
809 	const VkVertexInputAttributeDescription vertexAttrBarCoord =
810 	{
811 		1u,															// deUint32	location;
812 		0u,															// deUint32	binding;
813 		VK_FORMAT_R32G32B32_SFLOAT,									// VkFormat	format;
814 		DE_OFFSET_OF(VertexDataNdcBarycentric, barycentricCoord),	// deUint32	offset;
815 	};
816 
817 	vertexDataDesc.vertexAttribDescVec.push_back(vertexAttrBarCoord);
818 
819 	return vertexDataDesc;
820 }
821 
uploadVertexData(const Allocation & vertexBufferAllocation,const VertexDataDesc & vertexDataDescripton) const822 template<> void MSInstance<MSInstanceInterpolateBarycentricCoordinates>::uploadVertexData (const Allocation& vertexBufferAllocation, const VertexDataDesc& vertexDataDescripton) const
823 {
824 	// Create buffer storing vertex data
825 	std::vector<VertexDataNdcBarycentric> vertices;
826 
827 	vertices.push_back(VertexDataNdcBarycentric(tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f), tcu::Vec3(0.0f, 0.0f, 1.0f)));
828 	vertices.push_back(VertexDataNdcBarycentric(tcu::Vec4(-1.0f,  1.0f, 0.0f, 1.0f), tcu::Vec3(1.0f, 0.0f, 0.0f)));
829 	vertices.push_back(VertexDataNdcBarycentric(tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f), tcu::Vec3(0.0f, 1.0f, 0.0f)));
830 
831 	deMemcpy(vertexBufferAllocation.getHostPtr(), dataPointer(vertices), static_cast<std::size_t>(vertexDataDescripton.dataSize));
832 }
833 
verifyImageData(const vk::VkImageCreateInfo & imageRSInfo,const tcu::ConstPixelBufferAccess & dataRS) const834 template<> tcu::TestStatus MSInstance<MSInstanceInterpolateBarycentricCoordinates>::verifyImageData (const vk::VkImageCreateInfo& imageRSInfo, const tcu::ConstPixelBufferAccess& dataRS) const
835 {
836 	if (checkForError(imageRSInfo, dataRS, 0))
837 		return tcu::TestStatus::fail("Failed");
838 
839 	return tcu::TestStatus::pass("Passed");
840 }
841 
842 class MSCaseCentroidQualifierInsidePrimitive;
843 
init(void)844 template<> void MSCase<MSCaseCentroidQualifierInsidePrimitive>::init (void)
845 {
846 	m_testCtx.getLog()
847 		<< tcu::TestLog::Message
848 		<< "Verifying that varying qualified with centroid is interpolated at location inside both the pixel and the primitive being processed.\n"
849 		<< "	Interpolate triangle's barycentric coordinates with centroid qualifier.\n"
850 		<< "	=> After interpolation we expect barycentric.xyz >= 0.0 && barycentric.xyz <= 1.0\n"
851 		<< tcu::TestLog::EndMessage;
852 
853 	MultisampleCaseBase::init();
854 }
855 
initPrograms(vk::SourceCollections & programCollection) const856 template<> void MSCase<MSCaseCentroidQualifierInsidePrimitive>::initPrograms (vk::SourceCollections& programCollection) const
857 {
858 	// Create vertex shader
859 	std::ostringstream vs;
860 
861 	vs << "#version 440\n"
862 		<< "layout(location = 0) in vec4 vs_in_position_ndc;\n"
863 		<< "layout(location = 1) in vec3 vs_in_barCoord;\n"
864 		<< "\n"
865 		<< "layout(location = 0) out vec3 vs_out_barCoord;\n"
866 		<< "\n"
867 		<< "out gl_PerVertex {\n"
868 		<< "	vec4  gl_Position;\n"
869 		<< "};\n"
870 		<< "void main (void)\n"
871 		<< "{\n"
872 		<< "	gl_Position		= vs_in_position_ndc;\n"
873 		<< "	vs_out_barCoord = vs_in_barCoord;\n"
874 		<< "}\n";
875 
876 	programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
877 
878 	// Create fragment shader
879 	std::ostringstream fs;
880 
881 	fs << "#version 440\n"
882 		<< "layout(location = 0) centroid in vec3 fs_in_barCoord;\n"
883 		<< "\n"
884 		<< "layout(location = 0) out vec4 fs_out_color;\n"
885 		<< "\n"
886 		<< "void main (void)\n"
887 		<< "{\n"
888 		<< "	if( all(greaterThanEqual(fs_in_barCoord, vec3(0.0))) && all(lessThanEqual(fs_in_barCoord, vec3(1.0))) )\n"
889 		<< "			fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
890 		<< "	else\n"
891 		<< "			fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
892 		<< "}\n";
893 
894 	programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
895 }
896 
createInstance(Context & context) const897 template<> TestInstance* MSCase<MSCaseCentroidQualifierInsidePrimitive>::createInstance (Context& context) const
898 {
899 	return new MSInstance<MSInstanceInterpolateBarycentricCoordinates>(context, m_imageMSParams);
900 }
901 
902 } // multisample
903 
createMultisampleInterpolationTests(tcu::TestContext & testCtx)904 tcu::TestCaseGroup* createMultisampleInterpolationTests (tcu::TestContext& testCtx)
905 {
906 	de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "multisample_interpolation", "Multisample Interpolation"));
907 
908 	const tcu::UVec3 imageSizes[] =
909 	{
910 		tcu::UVec3(128u, 128u, 1u),
911 		tcu::UVec3(137u, 191u, 1u),
912 	};
913 
914 	const deUint32 sizesElemCount = static_cast<deUint32>(sizeof(imageSizes) / sizeof(tcu::UVec3));
915 
916 	const vk::VkSampleCountFlagBits imageSamples[] =
917 	{
918 		vk::VK_SAMPLE_COUNT_2_BIT,
919 		vk::VK_SAMPLE_COUNT_4_BIT,
920 		vk::VK_SAMPLE_COUNT_8_BIT,
921 		vk::VK_SAMPLE_COUNT_16_BIT,
922 		vk::VK_SAMPLE_COUNT_32_BIT,
923 		vk::VK_SAMPLE_COUNT_64_BIT,
924 	};
925 
926 	const deUint32 samplesElemCount = static_cast<deUint32>(sizeof(imageSamples) / sizeof(vk::VkSampleCountFlagBits));
927 
928 	de::MovePtr<tcu::TestCaseGroup> caseGroup(new tcu::TestCaseGroup(testCtx, "sample_interpolate_at_single_sample", ""));
929 
930 	for (deUint32 imageSizeNdx = 0u; imageSizeNdx < sizesElemCount; ++imageSizeNdx)
931 	{
932 		const tcu::UVec3	imageSize = imageSizes[imageSizeNdx];
933 		std::ostringstream	imageSizeStream;
934 
935 		imageSizeStream << imageSize.x() << "_" << imageSize.y() << "_" << imageSize.z();
936 
937 		de::MovePtr<tcu::TestCaseGroup> sizeGroup(new tcu::TestCaseGroup(testCtx, imageSizeStream.str().c_str(), ""));
938 
939 		sizeGroup->addChild(multisample::MSCase<multisample::MSCaseInterpolateAtSampleSingleSample>::createCase(testCtx, "samples_" + de::toString(1), multisample::ImageMSParams(vk::VK_SAMPLE_COUNT_1_BIT, imageSize)));
940 
941 		caseGroup->addChild(sizeGroup.release());
942 	}
943 
944 	testGroup->addChild(caseGroup.release());
945 
946 	testGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseInterpolateAtSampleDistinctValues> >	(testCtx, "sample_interpolate_at_distinct_values",	imageSizes, sizesElemCount, imageSamples, samplesElemCount));
947 	testGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseInterpolateAtSampleIgnoresCentroid> >(testCtx, "sample_interpolate_at_ignores_centroid",	imageSizes, sizesElemCount, imageSamples, samplesElemCount));
948 	testGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseInterpolateAtSampleConsistency> >	(testCtx, "sample_interpolate_at_consistency",		imageSizes, sizesElemCount, imageSamples, samplesElemCount));
949 	testGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseSampleQualifierDistinctValues> >		(testCtx, "sample_qualifier_distinct_values",		imageSizes, sizesElemCount, imageSamples, samplesElemCount));
950 	testGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseInterpolateAtCentroidConsistency> >	(testCtx, "centroid_interpolate_at_consistency",	imageSizes, sizesElemCount, imageSamples, samplesElemCount));
951 	testGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseCentroidQualifierInsidePrimitive> >	(testCtx, "centroid_qualifier_inside_primitive",	imageSizes, sizesElemCount, imageSamples, samplesElemCount));
952 	testGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseInterpolateAtOffsetPixelCenter> >	(testCtx, "offset_interpolate_at_pixel_center",		imageSizes, sizesElemCount, imageSamples, samplesElemCount));
953 	testGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseInterpolateAtOffsetSamplePosition> >	(testCtx, "offset_interpolate_at_sample_position",	imageSizes, sizesElemCount, imageSamples, samplesElemCount));
954 
955 	return testGroup.release();
956 }
957 
958 } // pipeline
959 } // vkt
960