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 vktPipelineMultisampleInterpolationTests.cpp
23* \brief Multisample Interpolation Tests
24*//*--------------------------------------------------------------------*/
25
26#include "vktPipelineMultisampleInterpolationTests.hpp"
27#include "vktPipelineMultisampleBaseResolve.hpp"
28#include "vktPipelineMultisampleTestsUtil.hpp"
29#include "vktPipelineMakeUtil.hpp"
30#include "vktAmberTestCase.hpp"
31#include "vkQueryUtil.hpp"
32#include "tcuTestLog.hpp"
33#include <vector>
34
35namespace vkt
36{
37namespace pipeline
38{
39namespace multisample
40{
41
42using namespace vk;
43
44struct VertexDataNdc
45{
46	VertexDataNdc (const tcu::Vec4& posNdc) : positionNdc(posNdc) {}
47
48	tcu::Vec4 positionNdc;
49};
50
51struct VertexDataNdcScreen
52{
53	VertexDataNdcScreen (const tcu::Vec4& posNdc, const tcu::Vec2& posScreen) : positionNdc(posNdc), positionScreen(posScreen) {}
54
55	tcu::Vec4 positionNdc;
56	tcu::Vec2 positionScreen;
57};
58
59struct VertexDataNdcBarycentric
60{
61	VertexDataNdcBarycentric (const tcu::Vec4& posNdc, const tcu::Vec3& barCoord) : positionNdc(posNdc), barycentricCoord(barCoord) {}
62
63	tcu::Vec4 positionNdc;
64	tcu::Vec3 barycentricCoord;
65};
66
67bool checkForError (const vk::VkImageCreateInfo& imageRSInfo, const tcu::ConstPixelBufferAccess& dataRS, const deUint32 errorCompNdx)
68{
69	for (deUint32 z = 0u; z < imageRSInfo.extent.depth;  ++z)
70	for (deUint32 y = 0u; y < imageRSInfo.extent.height; ++y)
71	for (deUint32 x = 0u; x < imageRSInfo.extent.width;  ++x)
72	{
73		const deUint32 errorComponent = dataRS.getPixelUint(x, y, z)[errorCompNdx];
74
75		if (errorComponent > 0)
76			return true;
77	}
78
79	return false;
80}
81
82template <typename CaseClassName>
83class MSCase : public MultisampleCaseBase
84{
85public:
86								MSCase			(tcu::TestContext&		testCtx,
87												 const std::string&		name,
88												 const ImageMSParams&	imageMSParams)
89								: MultisampleCaseBase(testCtx, name, imageMSParams) {}
90
91	void						init			(void);
92	void						initPrograms	(vk::SourceCollections& programCollection) const;
93	void						checkSupport	(Context&				context) const;
94	TestInstance*				createInstance	(Context&				context) const;
95	static MultisampleCaseBase*	createCase		(tcu::TestContext&		testCtx,
96												 const std::string&		name,
97												 const ImageMSParams&	imageMSParams);
98};
99
100template <typename CaseClassName>
101void MSCase<CaseClassName>::checkSupport (Context& context) const
102{
103	checkGraphicsPipelineLibrarySupport(context);
104
105#ifndef CTS_USES_VULKANSC
106	if (context.isDeviceFunctionalitySupported("VK_KHR_portability_subset") &&
107		!context.getPortabilitySubsetFeatures().shaderSampleRateInterpolationFunctions)
108	{
109		TCU_THROW(NotSupportedError, "VK_KHR_portability_subset: Shader sample rate interpolation functions are not supported by this implementation");
110	}
111#endif // CTS_USES_VULKANSC
112
113	context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_SAMPLE_RATE_SHADING);
114}
115
116template <typename CaseClassName>
117MultisampleCaseBase* MSCase<CaseClassName>::createCase (tcu::TestContext& testCtx, const std::string& name, const ImageMSParams& imageMSParams)
118{
119	return new MSCase<CaseClassName>(testCtx, name, imageMSParams);
120}
121
122template <typename InstanceClassName>
123class MSInstance : public MSInstanceBaseResolve
124{
125public:
126					MSInstance				(Context&							context,
127											 const ImageMSParams&				imageMSParams)
128					: MSInstanceBaseResolve(context, imageMSParams) {}
129
130	VertexDataDesc	getVertexDataDescripton	(void) const;
131	void			uploadVertexData		(const Allocation&					vertexBufferAllocation,
132											 const VertexDataDesc&				vertexDataDescripton) const;
133	tcu::TestStatus	verifyImageData			(const vk::VkImageCreateInfo&		imageRSInfo,
134											 const tcu::ConstPixelBufferAccess& dataRS) const;
135};
136
137class MSInstanceDistinctValues;
138
139template<> MultisampleInstanceBase::VertexDataDesc MSInstance<MSInstanceDistinctValues>::getVertexDataDescripton (void) const
140{
141	VertexDataDesc vertexDataDesc;
142
143	vertexDataDesc.verticesCount		= 3u;
144	vertexDataDesc.dataStride			= sizeof(VertexDataNdc);
145	vertexDataDesc.dataSize				= vertexDataDesc.verticesCount * vertexDataDesc.dataStride;
146	vertexDataDesc.primitiveTopology	= VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
147
148	const VkVertexInputAttributeDescription vertexAttribPositionNdc =
149	{
150		0u,										// deUint32	location;
151		0u,										// deUint32	binding;
152		VK_FORMAT_R32G32B32A32_SFLOAT,			// VkFormat	format;
153		DE_OFFSET_OF(VertexDataNdc, positionNdc),	// deUint32	offset;
154	};
155
156	vertexDataDesc.vertexAttribDescVec.push_back(vertexAttribPositionNdc);
157
158	return vertexDataDesc;
159}
160
161template<> void MSInstance<MSInstanceDistinctValues>::uploadVertexData (const Allocation& vertexBufferAllocation, const VertexDataDesc& vertexDataDescripton) const
162{
163	std::vector<VertexDataNdc> vertices;
164
165	vertices.push_back(VertexDataNdc(tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f)));
166	vertices.push_back(VertexDataNdc(tcu::Vec4(-1.0f,  4.0f, 0.0f, 1.0f)));
167	vertices.push_back(VertexDataNdc(tcu::Vec4( 4.0f, -1.0f, 0.0f, 1.0f)));
168
169	deMemcpy(vertexBufferAllocation.getHostPtr(), dataPointer(vertices), static_cast<std::size_t>(vertexDataDescripton.dataSize));
170}
171
172template<> tcu::TestStatus MSInstance<MSInstanceDistinctValues>::verifyImageData (const vk::VkImageCreateInfo& imageRSInfo, const tcu::ConstPixelBufferAccess& dataRS) const
173{
174	const deUint32 distinctValuesExpected = static_cast<deUint32>(m_imageMSParams.numSamples) + 1u;
175
176	std::vector<tcu::IVec4> distinctValues;
177
178	for (deUint32 z = 0u; z < imageRSInfo.extent.depth;	 ++z)
179	for (deUint32 y = 0u; y < imageRSInfo.extent.height; ++y)
180	for (deUint32 x = 0u; x < imageRSInfo.extent.width;	 ++x)
181	{
182		const tcu::IVec4 pixel = dataRS.getPixelInt(x, y, z);
183
184		if (std::find(distinctValues.begin(), distinctValues.end(), pixel) == distinctValues.end())
185			distinctValues.push_back(pixel);
186	}
187
188	if (distinctValues.size() >= distinctValuesExpected)
189		return tcu::TestStatus::pass("Passed");
190	else
191		return tcu::TestStatus::fail("Expected numSamples+1 different colors in the output image");
192}
193
194class MSCaseSampleQualifierDistinctValues;
195
196template<> void MSCase<MSCaseSampleQualifierDistinctValues>::init (void)
197{
198	m_testCtx.getLog()
199		<< tcu::TestLog::Message
200		<< "Verifying that a sample qualified varying is given different values for different samples.\n"
201		<< "	Render full screen traingle with quadratic function defining red/green color pattern division.\n"
202		<< "	=> Resulting image should contain n+1 different colors, where n = sample count.\n"
203		<< tcu::TestLog::EndMessage;
204
205	MultisampleCaseBase::init();
206}
207
208template<> void MSCase<MSCaseSampleQualifierDistinctValues>::initPrograms (vk::SourceCollections& programCollection) const
209{
210	// Create vertex shader
211	std::ostringstream vs;
212
213	vs << "#version 440\n"
214		<< "layout(location = 0) in vec4 vs_in_position_ndc;\n"
215		<< "\n"
216		<< "layout(location = 0) out vec4 vs_out_position_ndc;\n"
217		<< "\n"
218		<< "out gl_PerVertex {\n"
219		<< "	vec4  gl_Position;\n"
220		<< "};\n"
221		<< "void main (void)\n"
222		<< "{\n"
223		<< "	gl_Position			= vs_in_position_ndc;\n"
224		<< "	vs_out_position_ndc = vs_in_position_ndc;\n"
225		<< "}\n";
226
227	programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
228
229	// Create fragment shader
230	std::ostringstream fs;
231
232	fs << "#version 440\n"
233		<< "layout(location = 0) sample in vec4 fs_in_position_ndc;\n"
234		<< "\n"
235		<< "layout(location = 0) out vec4 fs_out_color;\n"
236		<< "\n"
237		<< "void main (void)\n"
238		<< "{\n"
239		<< "	if(fs_in_position_ndc.y < -2.0*pow(0.5*(fs_in_position_ndc.x + 1.0), 2.0) + 1.0)\n"
240		<< "		fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
241		<< "	else\n"
242		<< "		fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
243		<< "}\n";
244
245	programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
246}
247
248template<> void MSCase<MSCaseSampleQualifierDistinctValues>::checkSupport (Context& context) const
249{
250	checkPipelineConstructionRequirements(context.getInstanceInterface(), context.getPhysicalDevice(), m_imageMSParams.pipelineConstructionType);
251
252	context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_SAMPLE_RATE_SHADING);
253}
254
255template<> TestInstance* MSCase<MSCaseSampleQualifierDistinctValues>::createInstance (Context& context) const
256{
257	return new MSInstance<MSInstanceDistinctValues>(context, m_imageMSParams);
258}
259
260class MSCaseInterpolateAtSampleDistinctValues;
261
262template<> void MSCase<MSCaseInterpolateAtSampleDistinctValues>::init (void)
263{
264	m_testCtx.getLog()
265		<< tcu::TestLog::Message
266		<< "Verifying that a interpolateAtSample returns different values for different samples.\n"
267		<< "	Render full screen traingle with quadratic function defining red/green color pattern division.\n"
268		<< "	=> Resulting image should contain n+1 different colors, where n = sample count.\n"
269		<< tcu::TestLog::EndMessage;
270
271	MultisampleCaseBase::init();
272}
273
274template<> void MSCase<MSCaseInterpolateAtSampleDistinctValues>::initPrograms (vk::SourceCollections& programCollection) const
275{
276	// Create vertex shader
277	std::ostringstream vs;
278
279	vs << "#version 440\n"
280		<< "layout(location = 0) in vec4 vs_in_position_ndc;\n"
281		<< "\n"
282		<< "layout(location = 0) out vec4 vs_out_position_ndc;\n"
283		<< "\n"
284		<< "out gl_PerVertex {\n"
285		<< "	vec4  gl_Position;\n"
286		<< "};\n"
287		<< "void main (void)\n"
288		<< "{\n"
289		<< "	gl_Position			= vs_in_position_ndc;\n"
290		<< "	vs_out_position_ndc = vs_in_position_ndc;\n"
291		<< "}\n";
292
293	programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
294
295	// Create fragment shader
296	std::ostringstream fs;
297
298	fs << "#version 440\n"
299		<< "layout(location = 0) in vec4 fs_in_position_ndc;\n"
300		<< "\n"
301		<< "layout(location = 0) out vec4 fs_out_color;\n"
302		<< "\n"
303		<< "void main (void)\n"
304		<< "{\n"
305		<< "	const vec4 position_ndc_at_sample = interpolateAtSample(fs_in_position_ndc, gl_SampleID);\n"
306		<< "	if(position_ndc_at_sample.y < -2.0*pow(0.5*(position_ndc_at_sample.x + 1.0), 2.0) + 1.0)\n"
307		<< "		fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
308		<< "	else\n"
309		<< "		fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
310		<< "}\n";
311
312	programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
313}
314
315template<> TestInstance* MSCase<MSCaseInterpolateAtSampleDistinctValues>::createInstance (Context& context) const
316{
317	return new MSInstance<MSInstanceDistinctValues>(context, m_imageMSParams);
318}
319
320class MSInstanceInterpolateScreenPosition;
321
322template<> MSInstanceBaseResolve::VertexDataDesc MSInstance<MSInstanceInterpolateScreenPosition>::getVertexDataDescripton (void) const
323{
324	VertexDataDesc vertexDataDesc;
325
326	vertexDataDesc.verticesCount		= 4u;
327	vertexDataDesc.dataStride			= sizeof(VertexDataNdcScreen);
328	vertexDataDesc.dataSize				= vertexDataDesc.verticesCount * vertexDataDesc.dataStride;
329	vertexDataDesc.primitiveTopology	= VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
330
331	const VkVertexInputAttributeDescription vertexAttribPositionNdc =
332	{
333		0u,												// deUint32	location;
334		0u,												// deUint32	binding;
335		VK_FORMAT_R32G32B32A32_SFLOAT,					// VkFormat	format;
336		DE_OFFSET_OF(VertexDataNdcScreen, positionNdc),	// deUint32	offset;
337	};
338
339	vertexDataDesc.vertexAttribDescVec.push_back(vertexAttribPositionNdc);
340
341	const VkVertexInputAttributeDescription vertexAttribPositionScreen =
342	{
343		1u,											// deUint32	location;
344		0u,											// deUint32	binding;
345		VK_FORMAT_R32G32_SFLOAT,					// VkFormat	format;
346		DE_OFFSET_OF(VertexDataNdcScreen, positionScreen),	// deUint32	offset;
347	};
348
349	vertexDataDesc.vertexAttribDescVec.push_back(vertexAttribPositionScreen);
350
351	return vertexDataDesc;
352}
353
354template<> void MSInstance<MSInstanceInterpolateScreenPosition>::uploadVertexData (const Allocation& vertexBufferAllocation, const VertexDataDesc& vertexDataDescripton) const
355{
356	const tcu::UVec3 layerSize		= getLayerSize(IMAGE_TYPE_2D, m_imageMSParams.imageSize);
357	const float		 screenSizeX	= static_cast<float>(layerSize.x());
358	const float		 screenSizeY	= static_cast<float>(layerSize.y());
359
360	std::vector<VertexDataNdcScreen> vertices;
361
362	vertices.push_back(VertexDataNdcScreen(tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f), tcu::Vec2(0.0f, 0.0f)));
363	vertices.push_back(VertexDataNdcScreen(tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f), tcu::Vec2(screenSizeX, 0.0f)));
364	vertices.push_back(VertexDataNdcScreen(tcu::Vec4(-1.0f,  1.0f, 0.0f, 1.0f), tcu::Vec2(0.0f, screenSizeY)));
365	vertices.push_back(VertexDataNdcScreen(tcu::Vec4( 1.0f,  1.0f, 0.0f, 1.0f), tcu::Vec2(screenSizeX, screenSizeY)));
366
367	deMemcpy(vertexBufferAllocation.getHostPtr(), dataPointer(vertices), static_cast<std::size_t>(vertexDataDescripton.dataSize));
368}
369
370template<> tcu::TestStatus MSInstance<MSInstanceInterpolateScreenPosition>::verifyImageData (const vk::VkImageCreateInfo& imageRSInfo, const tcu::ConstPixelBufferAccess& dataRS) const
371{
372	if (checkForError(imageRSInfo, dataRS, 0))
373		return tcu::TestStatus::fail("Failed");
374
375	return tcu::TestStatus::pass("Passed");
376}
377
378class MSCaseInterpolateAtSampleSingleSample;
379
380template<> void MSCase<MSCaseInterpolateAtSampleSingleSample>::init (void)
381{
382	m_testCtx.getLog()
383		<< tcu::TestLog::Message
384		<< "Verifying that using interpolateAtSample with multisample buffers not available returns sample evaluated at the center of the pixel.\n"
385		<< "	Interpolate varying containing screen space location.\n"
386		<< "	=> fract(screen space location) should be (about) (0.5, 0.5)\n"
387		<< tcu::TestLog::EndMessage;
388
389	MultisampleCaseBase::init();
390}
391
392template<> void MSCase<MSCaseInterpolateAtSampleSingleSample>::initPrograms (vk::SourceCollections& programCollection) const
393{
394	// Create vertex shader
395	std::ostringstream vs;
396
397	vs << "#version 440\n"
398		<< "layout(location = 0) in vec4 vs_in_position_ndc;\n"
399		<< "layout(location = 1) in vec2 vs_in_position_screen;\n"
400		<< "\n"
401		<< "layout(location = 0) out vec2 vs_out_position_screen;\n"
402		<< "\n"
403		<< "out gl_PerVertex {\n"
404		<< "	vec4  gl_Position;\n"
405		<< "};\n"
406		<< "void main (void)\n"
407		<< "{\n"
408		<< "	gl_Position				= vs_in_position_ndc;\n"
409		<< "	vs_out_position_screen	= vs_in_position_screen;\n"
410		<< "}\n";
411
412	programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
413
414	// Create fragment shader
415	std::ostringstream fs;
416
417	fs << "#version 440\n"
418		<< "layout(location = 0) in vec2 fs_in_position_screen;\n"
419		<< "\n"
420		<< "layout(location = 0) out vec4 fs_out_color;\n"
421		<< "\n"
422		<< "void main (void)\n"
423		<< "{\n"
424		<< "	const float threshold					= 0.15625;\n"
425		<< "	const vec2  position_screen_at_sample	= interpolateAtSample(fs_in_position_screen, 0);\n"
426		<< "	const vec2  position_inside_pixel		= fract(position_screen_at_sample);\n"
427		<< "\n"
428		<< "	if (abs(position_inside_pixel.x - 0.5) <= threshold && abs(position_inside_pixel.y - 0.5) <= threshold)\n"
429		<< "		fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
430		<< "	else\n"
431		<< "		fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
432		<< "}\n";
433
434	programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
435}
436
437template<> TestInstance* MSCase<MSCaseInterpolateAtSampleSingleSample>::createInstance (Context& context) const
438{
439	return new MSInstance<MSInstanceInterpolateScreenPosition>(context, m_imageMSParams);
440}
441
442class MSCaseInterpolateAtSampleIgnoresCentroid;
443
444template<> void MSCase<MSCaseInterpolateAtSampleIgnoresCentroid>::init (void)
445{
446	m_testCtx.getLog()
447		<< tcu::TestLog::Message
448		<< "Verifying that interpolateAtSample ignores centroid qualifier.\n"
449		<< "	Interpolate varying containing screen space location with centroid and sample qualifiers.\n"
450		<< "	=> interpolateAtSample(screenSample, n) ~= interpolateAtSample(screenCentroid, n)\n"
451		<< tcu::TestLog::EndMessage;
452
453	MultisampleCaseBase::init();
454}
455
456template<> void MSCase<MSCaseInterpolateAtSampleIgnoresCentroid>::initPrograms (vk::SourceCollections& programCollection) const
457{
458	// Create vertex shader
459	std::ostringstream vs;
460
461	vs << "#version 440\n"
462		<< "layout(location = 0) in vec4 vs_in_position_ndc;\n"
463		<< "layout(location = 1) in vec2 vs_in_position_screen;\n"
464		<< "\n"
465		<< "layout(location = 0) out vec2 vs_out_pos_screen_centroid;\n"
466		<< "layout(location = 1) out vec2 vs_out_pos_screen_fragment;\n"
467		<< "\n"
468		<< "out gl_PerVertex {\n"
469		<< "	vec4  gl_Position;\n"
470		<< "};\n"
471		<< "void main (void)\n"
472		<< "{\n"
473		<< "	gl_Position					= vs_in_position_ndc;\n"
474		<< "	vs_out_pos_screen_centroid	= vs_in_position_screen;\n"
475		<< "	vs_out_pos_screen_fragment	= vs_in_position_screen;\n"
476		<< "}\n";
477
478	programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
479
480	// Create fragment shader
481	std::ostringstream fs;
482
483	fs << "#version 440\n"
484		<< "layout(location = 0) centroid in vec2 fs_in_pos_screen_centroid;\n"
485		<< "layout(location = 1)		  in vec2 fs_in_pos_screen_fragment;\n"
486		<< "\n"
487		<< "layout(location = 0) out vec4 fs_out_color;\n"
488		<< "\n"
489		<< "void main (void)\n"
490		<< "{\n"
491		<< "	const float threshold = 0.0005;\n"
492		<< "\n"
493		<< "	const vec2 position_a  = interpolateAtSample(fs_in_pos_screen_centroid, gl_SampleID);\n"
494		<< "	const vec2 position_b  = interpolateAtSample(fs_in_pos_screen_fragment, gl_SampleID);\n"
495		<< "	const bool valuesEqual = all(lessThan(abs(position_a - position_b), vec2(threshold)));\n"
496		<< "\n"
497		<< "	if (valuesEqual)\n"
498		<< "		fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
499		<< "	else\n"
500		<< "		fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
501		<< "}\n";
502
503	programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
504}
505
506template<> TestInstance* MSCase<MSCaseInterpolateAtSampleIgnoresCentroid>::createInstance (Context& context) const
507{
508	return new MSInstance<MSInstanceInterpolateScreenPosition>(context, m_imageMSParams);
509}
510
511class MSCaseInterpolateAtSampleConsistency;
512
513template<> void MSCase<MSCaseInterpolateAtSampleConsistency>::init (void)
514{
515	const std::string	indexStr = de::toString(m_imageMSParams.componentData.index);
516	std::string			componentMsg;
517
518	switch (m_imageMSParams.componentData.source)
519	{
520	case multisample::ComponentSource::CONSTANT:		componentMsg = "Using single constant component " + indexStr;			break;
521	case multisample::ComponentSource::PUSH_CONSTANT:	componentMsg = "Using single component via push constant " + indexStr;	break;
522	default: break;
523	}
524
525	m_testCtx.getLog()
526		<< tcu::TestLog::Message
527		<< "Verifying that interpolateAtSample with the sample set to the current sampleID returns consistent values.\n"
528		<< (componentMsg.empty() ? std::string() : componentMsg + "\n")
529		<< "	Interpolate varying containing screen space location with centroid and sample qualifiers.\n"
530		<< "	=> interpolateAtSample(screenCentroid, sampleID) = screenSample\n"
531		<< tcu::TestLog::EndMessage;
532
533	MultisampleCaseBase::init();
534}
535
536template<> void MSCase<MSCaseInterpolateAtSampleConsistency>::initPrograms (vk::SourceCollections& programCollection) const
537{
538	// Create vertex shader
539	std::ostringstream vs;
540
541	vs << "#version 440\n"
542		<< "layout(location = 0) in vec4 vs_in_position_ndc;\n"
543		<< "layout(location = 1) in vec2 vs_in_position_screen;\n"
544		<< "\n"
545		<< "layout(location = 0) out vec2 vs_out_pos_screen_centroid;\n"
546		<< "layout(location = 1) out vec2 vs_out_pos_screen_sample;\n"
547		<< "\n"
548		<< "out gl_PerVertex {\n"
549		<< "	vec4  gl_Position;\n"
550		<< "};\n"
551		<< "void main (void)\n"
552		<< "{\n"
553		<< "	gl_Position					= vs_in_position_ndc;\n"
554		<< "	vs_out_pos_screen_centroid	= vs_in_position_screen;\n"
555		<< "	vs_out_pos_screen_sample	= vs_in_position_screen;\n"
556		<< "}\n";
557
558	programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
559
560	// Create fragment shader
561	std::ostringstream fs;
562
563	fs	<< "#version 440\n"
564		<< "layout(location = 0) centroid in vec2 fs_in_pos_screen_centroid;\n"
565		<< "layout(location = 1) sample   in vec2 fs_in_pos_screen_sample;\n"
566		<< "\n"
567		<< "layout(location = 0) out vec4 fs_out_color;\n"
568		<< "\n";
569
570	if (m_imageMSParams.componentData.source == multisample::ComponentSource::PUSH_CONSTANT)
571	{
572		fs	<< "layout(push_constant) uniform PushConstants {\n"
573			<< "   uint component;\n"
574			<< "};\n"
575			<< "\n";
576	}
577
578	fs	<< "void main (void)\n"
579		<< "{\n"
580		<< "	const float threshold = 0.15625;\n"
581		<< "\n";
582
583	if (m_imageMSParams.componentData.source == multisample::ComponentSource::NONE)
584	{
585		fs	<< "	const vec2  pos_interpolated_at_sample = interpolateAtSample(fs_in_pos_screen_centroid, gl_SampleID);\n"
586			<< "	const bool  valuesEqual                = all(lessThan(abs(pos_interpolated_at_sample - fs_in_pos_screen_sample), vec2(threshold)));\n";
587	}
588	else if (m_imageMSParams.componentData.source == multisample::ComponentSource::CONSTANT)
589	{
590		const auto& index = m_imageMSParams.componentData.index;
591		fs	<< "	const float pos_interpolated_at_sample = interpolateAtSample(fs_in_pos_screen_centroid[" << index << "], gl_SampleID);\n"
592			<< "	const bool  valuesEqual                = (abs(pos_interpolated_at_sample - fs_in_pos_screen_sample[" << index << "]) < threshold);\n";
593	}
594	else // multisample::ComponentSource::PUSH_CONSTANT
595	{
596		fs	<< "	const float pos_interpolated_at_sample = interpolateAtSample(fs_in_pos_screen_centroid[component], gl_SampleID);\n"
597			<< "	const bool  valuesEqual                = (abs(pos_interpolated_at_sample - fs_in_pos_screen_sample[component]) < threshold);\n";
598	}
599
600	fs	<< "\n"
601		<< "	if (valuesEqual)\n"
602		<< "		fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
603		<< "	else\n"
604		<< "		fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
605		<< "}\n";
606
607	programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
608}
609
610template<> TestInstance* MSCase<MSCaseInterpolateAtSampleConsistency>::createInstance (Context& context) const
611{
612	return new MSInstance<MSInstanceInterpolateScreenPosition>(context, m_imageMSParams);
613}
614
615class MSCaseInterpolateAtCentroidConsistency;
616
617template<> void MSCase<MSCaseInterpolateAtCentroidConsistency>::init (void)
618{
619	const std::string	indexStr = de::toString(m_imageMSParams.componentData.index);
620	std::string			componentMsg;
621
622	switch (m_imageMSParams.componentData.source)
623	{
624	case multisample::ComponentSource::CONSTANT:		componentMsg = "Using single constant component " + indexStr;			break;
625	case multisample::ComponentSource::PUSH_CONSTANT:	componentMsg = "Using single component via push constant " + indexStr;	break;
626	default: break;
627	}
628
629	m_testCtx.getLog()
630		<< tcu::TestLog::Message
631		<< "Verifying that interpolateAtCentroid does not return different values than a corresponding centroid qualified varying.\n"
632		<< (componentMsg.empty() ? std::string() : componentMsg + "\n")
633		<< "	Interpolate varying containing screen space location with sample and centroid qualifiers.\n"
634		<< "	=> interpolateAtCentroid(screenSample) = screenCentroid\n"
635		<< tcu::TestLog::EndMessage;
636
637	MultisampleCaseBase::init();
638}
639
640template<> void MSCase<MSCaseInterpolateAtCentroidConsistency>::initPrograms (vk::SourceCollections& programCollection) const
641{
642	// Create vertex shader
643	std::ostringstream vs;
644
645	vs << "#version 440\n"
646		<< "layout(location = 0) in vec4 vs_in_position_ndc;\n"
647		<< "layout(location = 1) in vec2 vs_in_position_screen;\n"
648		<< "\n"
649		<< "layout(location = 0) out vec2 vs_out_pos_screen_sample[2];\n"
650		<< "layout(location = 2) out vec2 vs_out_pos_screen_centroid[2];\n"
651		<< "\n"
652		<< "out gl_PerVertex {\n"
653		<< "	vec4  gl_Position;\n"
654		<< "};\n"
655		<< "void main (void)\n"
656		<< "{\n"
657		<< "	gl_Position				      = vs_in_position_ndc;\n"
658		// Index 0 is never read, so we'll populate them with bad values
659		<< "	vs_out_pos_screen_sample[0]	  = vec2(-70.3, 42.1);\n"
660		<< "	vs_out_pos_screen_centroid[0] = vec2(7.7, -3.2);\n"
661		// Actual coordinates in index 1:
662		<< "	vs_out_pos_screen_sample[1]	  = vs_in_position_screen;\n"
663		<< "	vs_out_pos_screen_centroid[1] = vs_in_position_screen;\n"
664		<< "}\n";
665
666	programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
667
668	// Create fragment shader
669	std::ostringstream fs;
670
671	fs	<< "#version 440\n"
672		<< "layout(location = 0) sample   in vec2 fs_in_pos_screen_sample[2];\n"
673		<< "layout(location = 2) centroid in vec2 fs_in_pos_screen_centroid[2];\n"
674		<< "\n"
675		<< "layout(location = 0) out vec4 fs_out_color;\n"
676		<< "\n";
677
678	if (m_imageMSParams.componentData.source == multisample::ComponentSource::PUSH_CONSTANT)
679	{
680		fs	<< "layout(push_constant) uniform PushConstants {\n"
681			<< "   uint component;\n"
682			<< "};\n"
683			<< "\n";
684	}
685
686	fs	<< "void main (void)\n"
687		<< "{\n"
688		<< "	const float threshold = 0.0005;\n"
689		<< "\n";
690
691	if (m_imageMSParams.componentData.source == multisample::ComponentSource::NONE)
692	{
693		fs	<< "	const vec2 pos_interpolated_at_centroid = interpolateAtCentroid(fs_in_pos_screen_sample[1]);\n"
694			<< "	const bool valuesEqual                  = all(lessThan(abs(pos_interpolated_at_centroid - fs_in_pos_screen_centroid[1]), vec2(threshold)));\n";
695	}
696	else if (m_imageMSParams.componentData.source == multisample::ComponentSource::CONSTANT)
697	{
698		const auto& index = m_imageMSParams.componentData.index;
699		fs	<< "	const float pos_interpolated_at_centroid = interpolateAtCentroid(fs_in_pos_screen_sample[1][" << index << "]);\n"
700			<< "	const bool  valuesEqual                  = (abs(pos_interpolated_at_centroid - fs_in_pos_screen_centroid[1][" << index << "]) < threshold);\n";
701	}
702	else // multisample::ComponentSource::PUSH_CONSTANT
703	{
704		fs	<< "	const float pos_interpolated_at_centroid = interpolateAtCentroid(fs_in_pos_screen_sample[1][component]);\n"
705			<< "	const bool  valuesEqual                  = (abs(pos_interpolated_at_centroid - fs_in_pos_screen_centroid[1][component]) < threshold);\n";
706	}
707
708	fs	<< "\n"
709		<< "	if (valuesEqual)\n"
710		<< "		fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
711		<< "	else\n"
712		<< "		fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
713		<< "}\n";
714
715	programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
716}
717
718template<> TestInstance* MSCase<MSCaseInterpolateAtCentroidConsistency>::createInstance (Context& context) const
719{
720	return new MSInstance<MSInstanceInterpolateScreenPosition>(context, m_imageMSParams);
721}
722
723class MSCaseInterpolateAtOffsetPixelCenter;
724
725template<> void MSCase<MSCaseInterpolateAtOffsetPixelCenter>::init (void)
726{
727	m_testCtx.getLog()
728		<< tcu::TestLog::Message
729		<< "Verifying that interpolateAtOffset returns value sampled at an offset from the center of the pixel.\n"
730		<< "	Interpolate varying containing screen space location.\n"
731		<< "	=> interpolateAtOffset(screen, offset) should be \"varying value at the pixel center\" + offset"
732		<< tcu::TestLog::EndMessage;
733
734	MultisampleCaseBase::init();
735}
736
737template<> void MSCase<MSCaseInterpolateAtOffsetPixelCenter>::initPrograms (vk::SourceCollections& programCollection) const
738{
739	// Create vertex shader
740	std::ostringstream vs;
741
742	vs << "#version 440\n"
743		<< "layout(location = 0) in vec4 vs_in_position_ndc;\n"
744		<< "layout(location = 1) in vec2 vs_in_position_screen;\n"
745		<< "\n"
746		<< "layout(location = 0) out vec2 vs_out_pos_screen;\n"
747		<< "layout(location = 1) out vec2 vs_out_offset;\n"
748		<< "\n"
749		<< "out gl_PerVertex {\n"
750		<< "	vec4  gl_Position;\n"
751		<< "};\n"
752		<< "void main (void)\n"
753		<< "{\n"
754		<< "	gl_Position			= vs_in_position_ndc;\n"
755		<< "	vs_out_pos_screen	= vs_in_position_screen;\n"
756		<< "	vs_out_offset		= vs_in_position_ndc.xy * 0.5;\n"
757		<< "}\n";
758
759	programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
760
761	// Create fragment shader
762	std::ostringstream fs;
763
764	fs << "#version 440\n"
765		<< "layout(location = 0) in  vec2 fs_in_pos_screen;\n"
766		<< "layout(location = 1) in  vec2 fs_in_offset;\n"
767		<< "\n"
768		<< "layout(location = 0) out vec4 fs_out_color;\n"
769		<< "\n"
770		<< "void main (void)\n"
771		<< "{\n"
772		<< "    const vec2  frag_center = interpolateAtOffset(fs_in_pos_screen, vec2(0.0));\n"
773		<< "    const vec2  center_diff = abs(frag_center - fs_in_pos_screen);\n"
774		<< "    const float threshold   = 0.125;\n"
775		<< "    bool        valuesEqual = false;\n"
776		<< "\n"
777		<< "    if (all(lessThan(center_diff, vec2(0.5 + threshold)))) {\n"
778		<< "        const vec2 pos_interpolated_at_offset = interpolateAtOffset(fs_in_pos_screen, fs_in_offset);\n"
779		<< "        const vec2 reference_value            = frag_center + fs_in_offset;\n"
780		<< "\n"
781		<< "        valuesEqual = all(lessThan(abs(pos_interpolated_at_offset - reference_value), vec2(threshold)));\n"
782		<< "    }\n"
783		<< "\n"
784		<< "    if (valuesEqual)\n"
785		<< "        fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
786		<< "    else\n"
787		<< "        fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
788		<< "}\n";
789
790	programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
791}
792
793template<> TestInstance* MSCase<MSCaseInterpolateAtOffsetPixelCenter>::createInstance (Context& context) const
794{
795	return new MSInstance<MSInstanceInterpolateScreenPosition>(context, m_imageMSParams);
796}
797
798class MSCaseInterpolateAtOffsetSamplePosition;
799
800template<> void MSCase<MSCaseInterpolateAtOffsetSamplePosition>::init (void)
801{
802	const std::string	indexStr = de::toString(m_imageMSParams.componentData.index);
803	std::string			componentMsg;
804
805	switch (m_imageMSParams.componentData.source)
806	{
807	case multisample::ComponentSource::CONSTANT:		componentMsg = "Using single constant component " + indexStr;			break;
808	case multisample::ComponentSource::PUSH_CONSTANT:	componentMsg = "Using single component via push constant " + indexStr;	break;
809	default: break;
810	}
811
812	m_testCtx.getLog()
813		<< tcu::TestLog::Message
814		<< "Verifying that interpolateAtOffset of screen position with the offset of current sample position returns value "
815		<< "similar to screen position interpolated at sample.\n"
816		<< (componentMsg.empty() ? std::string() : componentMsg + "\n")
817		<< "	Interpolate varying containing screen space location with and without sample qualifier.\n"
818		<< "	=> interpolateAtOffset(screenFragment, samplePosition - (0.5,0.5)) = screenSample"
819		<< tcu::TestLog::EndMessage;
820
821	MultisampleCaseBase::init();
822}
823
824template<> void MSCase<MSCaseInterpolateAtOffsetSamplePosition>::initPrograms (vk::SourceCollections& programCollection) const
825{
826	// Create vertex shader
827	std::ostringstream vs;
828
829	vs << "#version 440\n"
830		<< "layout(location = 0) in vec4 vs_in_position_ndc;\n"
831		<< "layout(location = 1) in vec2 vs_in_position_screen;\n"
832		<< "\n"
833		<< "layout(location = 0) out vec2 vs_out_pos_screen_fragment;\n"
834		<< "layout(location = 1) out vec2 vs_out_pos_screen_sample;\n"
835		<< "\n"
836		<< "out gl_PerVertex {\n"
837		<< "	vec4  gl_Position;\n"
838		<< "};\n"
839		<< "void main (void)\n"
840		<< "{\n"
841		<< "	gl_Position					= vs_in_position_ndc;\n"
842		<< "	vs_out_pos_screen_fragment	= vs_in_position_screen;\n"
843		<< "	vs_out_pos_screen_sample	= vs_in_position_screen;\n"
844		<< "}\n";
845
846	programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
847
848	// Create fragment shader
849	std::ostringstream fs;
850
851	fs	<< "#version 440\n"
852		<< "layout(location = 0)		in vec2 fs_in_pos_screen_fragment;\n"
853		<< "layout(location = 1) sample in vec2 fs_in_pos_screen_sample;\n"
854		<< "\n"
855		<< "layout(location = 0) out vec4 fs_out_color;\n"
856		<< "\n";
857
858	if (m_imageMSParams.componentData.source == multisample::ComponentSource::PUSH_CONSTANT)
859	{
860		fs	<< "layout(push_constant) uniform PushConstants {\n"
861			<< "   uint component;\n"
862			<< "};\n"
863			<< "\n";
864	}
865
866	fs	<< "void main (void)\n"
867		<< "{\n"
868		<< "	const float threshold = 0.15625;\n"
869		<< "\n"
870		<< "	const vec2 offset                     = gl_SamplePosition - vec2(0.5, 0.5);\n";
871
872	if (m_imageMSParams.componentData.source == multisample::ComponentSource::NONE)
873	{
874		fs	<< "	const vec2 pos_interpolated_at_offset = interpolateAtOffset(fs_in_pos_screen_fragment, offset);\n"
875			<< "	const bool valuesEqual                = all(lessThan(abs(pos_interpolated_at_offset - fs_in_pos_screen_sample), vec2(threshold)));\n";
876	}
877	else if (m_imageMSParams.componentData.source == multisample::ComponentSource::CONSTANT)
878	{
879		const auto& index = m_imageMSParams.componentData.index;
880		fs	<< "	const float pos_interpolated_at_offset = interpolateAtOffset(fs_in_pos_screen_fragment[" << index << "], offset);\n"
881			<< "	const bool valuesEqual                 = (abs(pos_interpolated_at_offset - fs_in_pos_screen_sample[" << index << "]) < threshold);\n";
882	}
883	else // multisample::ComponentSource::PUSH_CONSTANT
884	{
885		fs	<< "	const float pos_interpolated_at_offset = interpolateAtOffset(fs_in_pos_screen_fragment[component], offset);\n"
886			<< "	const bool valuesEqual                 = (abs(pos_interpolated_at_offset - fs_in_pos_screen_sample[component]) < threshold);\n";
887	}
888
889	fs	<< "\n"
890		<< "	if (valuesEqual)\n"
891		<< "		fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
892		<< "	else\n"
893		<< "		fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
894		<< "}\n";
895
896	programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
897}
898
899template<> TestInstance* MSCase<MSCaseInterpolateAtOffsetSamplePosition>::createInstance (Context& context) const
900{
901	return new MSInstance<MSInstanceInterpolateScreenPosition>(context, m_imageMSParams);
902}
903
904class MSInstanceInterpolateBarycentricCoordinates;
905
906template<> MSInstanceBaseResolve::VertexDataDesc MSInstance<MSInstanceInterpolateBarycentricCoordinates>::getVertexDataDescripton (void) const
907{
908	VertexDataDesc vertexDataDesc;
909
910	vertexDataDesc.verticesCount		= 3u;
911	vertexDataDesc.dataStride			= sizeof(VertexDataNdcBarycentric);
912	vertexDataDesc.dataSize				= vertexDataDesc.verticesCount * vertexDataDesc.dataStride;
913	vertexDataDesc.primitiveTopology	= VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
914
915	const VkVertexInputAttributeDescription vertexAttribPositionNdc =
916	{
917		0u,															// deUint32	location;
918		0u,															// deUint32	binding;
919		VK_FORMAT_R32G32B32A32_SFLOAT,								// VkFormat	format;
920		DE_OFFSET_OF(VertexDataNdcBarycentric, positionNdc),		// deUint32	offset;
921	};
922
923	vertexDataDesc.vertexAttribDescVec.push_back(vertexAttribPositionNdc);
924
925	const VkVertexInputAttributeDescription vertexAttrBarCoord =
926	{
927		1u,															// deUint32	location;
928		0u,															// deUint32	binding;
929		VK_FORMAT_R32G32B32_SFLOAT,									// VkFormat	format;
930		DE_OFFSET_OF(VertexDataNdcBarycentric, barycentricCoord),	// deUint32	offset;
931	};
932
933	vertexDataDesc.vertexAttribDescVec.push_back(vertexAttrBarCoord);
934
935	return vertexDataDesc;
936}
937
938template<> void MSInstance<MSInstanceInterpolateBarycentricCoordinates>::uploadVertexData (const Allocation& vertexBufferAllocation, const VertexDataDesc& vertexDataDescripton) const
939{
940	// Create buffer storing vertex data
941	std::vector<VertexDataNdcBarycentric> vertices;
942
943	vertices.push_back(VertexDataNdcBarycentric(tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f), tcu::Vec3(0.0f, 0.0f, 1.0f)));
944	vertices.push_back(VertexDataNdcBarycentric(tcu::Vec4(-1.0f,  1.0f, 0.0f, 1.0f), tcu::Vec3(1.0f, 0.0f, 0.0f)));
945	vertices.push_back(VertexDataNdcBarycentric(tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f), tcu::Vec3(0.0f, 1.0f, 0.0f)));
946
947	deMemcpy(vertexBufferAllocation.getHostPtr(), dataPointer(vertices), static_cast<std::size_t>(vertexDataDescripton.dataSize));
948}
949
950template<> tcu::TestStatus MSInstance<MSInstanceInterpolateBarycentricCoordinates>::verifyImageData (const vk::VkImageCreateInfo& imageRSInfo, const tcu::ConstPixelBufferAccess& dataRS) const
951{
952	if (checkForError(imageRSInfo, dataRS, 0))
953		return tcu::TestStatus::fail("Failed");
954
955	return tcu::TestStatus::pass("Passed");
956}
957
958class MSCaseCentroidQualifierInsidePrimitive;
959
960template<> void MSCase<MSCaseCentroidQualifierInsidePrimitive>::init (void)
961{
962	m_testCtx.getLog()
963		<< tcu::TestLog::Message
964		<< "Verifying that varying qualified with centroid is interpolated at location inside both the pixel and the primitive being processed.\n"
965		<< "	Interpolate triangle's barycentric coordinates with centroid qualifier.\n"
966		<< "	=> After interpolation we expect barycentric.xyz >= 0.0 && barycentric.xyz <= 1.0\n"
967		<< tcu::TestLog::EndMessage;
968
969	MultisampleCaseBase::init();
970}
971
972template<> void MSCase<MSCaseCentroidQualifierInsidePrimitive>::initPrograms (vk::SourceCollections& programCollection) const
973{
974	// Create vertex shader
975	std::ostringstream vs;
976
977	vs << "#version 440\n"
978		<< "layout(location = 0) in vec4 vs_in_position_ndc;\n"
979		<< "layout(location = 1) in vec3 vs_in_barCoord;\n"
980		<< "\n"
981		<< "layout(location = 0) out vec3 vs_out_barCoord;\n"
982		<< "\n"
983		<< "out gl_PerVertex {\n"
984		<< "	vec4  gl_Position;\n"
985		<< "};\n"
986		<< "void main (void)\n"
987		<< "{\n"
988		<< "	gl_Position		= vs_in_position_ndc;\n"
989		<< "	vs_out_barCoord = vs_in_barCoord;\n"
990		<< "}\n";
991
992	programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
993
994	// Create fragment shader
995	std::ostringstream fs;
996
997	fs << "#version 440\n"
998		<< "layout(location = 0) centroid in vec3 fs_in_barCoord;\n"
999		<< "\n"
1000		<< "layout(location = 0) out vec4 fs_out_color;\n"
1001		<< "\n"
1002		<< "void main (void)\n"
1003		<< "{\n"
1004		<< "	if( all(greaterThanEqual(fs_in_barCoord, vec3(0.0))) && all(lessThanEqual(fs_in_barCoord, vec3(1.0))) )\n"
1005		<< "			fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
1006		<< "	else\n"
1007		<< "			fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
1008		<< "}\n";
1009
1010	programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
1011}
1012
1013template<> void MSCase<MSCaseCentroidQualifierInsidePrimitive>::checkSupport (Context& context) const
1014{
1015	checkPipelineConstructionRequirements(context.getInstanceInterface(), context.getPhysicalDevice(), m_imageMSParams.pipelineConstructionType);
1016}
1017
1018template<> TestInstance* MSCase<MSCaseCentroidQualifierInsidePrimitive>::createInstance (Context& context) const
1019{
1020	return new MSInstance<MSInstanceInterpolateBarycentricCoordinates>(context, m_imageMSParams);
1021}
1022
1023} // multisample
1024
1025tcu::TestCaseGroup* createMultisampleInterpolationTests (tcu::TestContext& testCtx, vk::PipelineConstructionType pipelineConstructionType)
1026{
1027	de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "multisample_interpolation"));
1028
1029	const tcu::UVec3 imageSizes[] =
1030	{
1031		tcu::UVec3(128u, 128u, 1u),
1032		tcu::UVec3(137u, 191u, 1u),
1033	};
1034
1035	const deUint32 sizesElemCount = static_cast<deUint32>(sizeof(imageSizes) / sizeof(tcu::UVec3));
1036
1037	const vk::VkSampleCountFlagBits imageSamples[] =
1038	{
1039		vk::VK_SAMPLE_COUNT_2_BIT,
1040		vk::VK_SAMPLE_COUNT_4_BIT,
1041		vk::VK_SAMPLE_COUNT_8_BIT,
1042		vk::VK_SAMPLE_COUNT_16_BIT,
1043		vk::VK_SAMPLE_COUNT_32_BIT,
1044		vk::VK_SAMPLE_COUNT_64_BIT,
1045	};
1046
1047	const deUint32 samplesElemCount = static_cast<deUint32>(sizeof(imageSamples) / sizeof(vk::VkSampleCountFlagBits));
1048
1049	de::MovePtr<tcu::TestCaseGroup> caseGroup(new tcu::TestCaseGroup(testCtx, "sample_interpolate_at_single_sample"));
1050
1051	for (deUint32 imageSizeNdx = 0u; imageSizeNdx < sizesElemCount; ++imageSizeNdx)
1052	{
1053		const tcu::UVec3	imageSize = imageSizes[imageSizeNdx];
1054		std::ostringstream	imageSizeStream;
1055
1056		imageSizeStream << imageSize.x() << "_" << imageSize.y() << "_" << imageSize.z();
1057
1058		de::MovePtr<tcu::TestCaseGroup> sizeGroup(new tcu::TestCaseGroup(testCtx, imageSizeStream.str().c_str()));
1059
1060		multisample::ImageMSParams imageParams
1061		{
1062			pipelineConstructionType,
1063			vk::VK_SAMPLE_COUNT_1_BIT,
1064			imageSize,
1065			multisample::ComponentData{},
1066			1.0f,
1067		};
1068		sizeGroup->addChild(multisample::MSCase<multisample::MSCaseInterpolateAtSampleSingleSample>::createCase(testCtx, "samples_" + de::toString(1), imageParams));
1069
1070		caseGroup->addChild(sizeGroup.release());
1071	}
1072
1073	testGroup->addChild(caseGroup.release());
1074
1075	testGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseInterpolateAtSampleDistinctValues> >	(testCtx, "sample_interpolate_at_distinct_values", pipelineConstructionType, imageSizes, sizesElemCount, imageSamples, samplesElemCount));
1076	testGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseInterpolateAtSampleIgnoresCentroid> >(testCtx, "sample_interpolate_at_ignores_centroid", pipelineConstructionType, imageSizes, sizesElemCount, imageSamples, samplesElemCount));
1077
1078	// Test consistency in sample interpolation function
1079	de::MovePtr<tcu::TestCaseGroup> sampleGroup(new tcu::TestCaseGroup(testCtx, "sample_interpolation_consistency"));
1080	sampleGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseInterpolateAtSampleConsistency> >	(testCtx, "all_components",		pipelineConstructionType, imageSizes, sizesElemCount, imageSamples, samplesElemCount));
1081	sampleGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseInterpolateAtSampleConsistency> >	(testCtx, "component_0",		pipelineConstructionType, imageSizes, sizesElemCount, imageSamples, samplesElemCount, multisample::ComponentData{multisample::ComponentSource::CONSTANT, 0u}));
1082	sampleGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseInterpolateAtSampleConsistency> >	(testCtx, "component_1",		pipelineConstructionType, imageSizes, sizesElemCount, imageSamples, samplesElemCount, multisample::ComponentData{multisample::ComponentSource::CONSTANT, 1u}));
1083	sampleGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseInterpolateAtSampleConsistency> >	(testCtx, "pushc_component_0",	pipelineConstructionType, imageSizes, sizesElemCount, imageSamples, samplesElemCount, multisample::ComponentData{multisample::ComponentSource::PUSH_CONSTANT, 0u}));
1084	sampleGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseInterpolateAtSampleConsistency> >	(testCtx, "pushc_component_1",	pipelineConstructionType, imageSizes, sizesElemCount, imageSamples, samplesElemCount, multisample::ComponentData{multisample::ComponentSource::PUSH_CONSTANT, 1u}));
1085	testGroup->addChild(sampleGroup.release());
1086
1087	testGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseSampleQualifierDistinctValues> >		(testCtx, "sample_qualifier_distinct_values", pipelineConstructionType, imageSizes, sizesElemCount, imageSamples, samplesElemCount));
1088
1089	de::MovePtr<tcu::TestCaseGroup> centroidGroup(new tcu::TestCaseGroup(testCtx, "centroid_interpolation_consistency", "Test consistency in centroid interpolation function"));
1090	centroidGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseInterpolateAtCentroidConsistency> >	(testCtx, "all_components",		pipelineConstructionType, imageSizes, sizesElemCount, imageSamples, samplesElemCount));
1091	centroidGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseInterpolateAtCentroidConsistency> >	(testCtx, "component_0",		pipelineConstructionType, imageSizes, sizesElemCount, imageSamples, samplesElemCount, multisample::ComponentData{multisample::ComponentSource::CONSTANT, 0u}));
1092	centroidGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseInterpolateAtCentroidConsistency> >	(testCtx, "component_1",		pipelineConstructionType, imageSizes, sizesElemCount, imageSamples, samplesElemCount, multisample::ComponentData{multisample::ComponentSource::CONSTANT, 1u}));
1093	centroidGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseInterpolateAtCentroidConsistency> >	(testCtx, "pushc_component_0",	pipelineConstructionType, imageSizes, sizesElemCount, imageSamples, samplesElemCount, multisample::ComponentData{multisample::ComponentSource::PUSH_CONSTANT, 0u}));
1094	centroidGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseInterpolateAtCentroidConsistency> >	(testCtx, "pushc_component_1",	pipelineConstructionType, imageSizes, sizesElemCount, imageSamples, samplesElemCount, multisample::ComponentData{multisample::ComponentSource::PUSH_CONSTANT, 1u}));
1095	testGroup->addChild(centroidGroup.release());
1096
1097#ifndef CTS_USES_VULKANSC
1098	// there is no support for pipelineConstructionType in amber
1099	if (pipelineConstructionType == vk::PIPELINE_CONSTRUCTION_TYPE_MONOLITHIC)
1100	{
1101		de::MovePtr<tcu::TestCaseGroup> reInterpolationGroup(new tcu::TestCaseGroup(testCtx, "reinterpolation_consistency", "Test consistency in reinterpolation"));
1102		std::vector<std::string> requirements;
1103		requirements.push_back("Features.sampleRateShading");
1104		reInterpolationGroup->addChild(cts_amber::createAmberTestCase(testCtx, "interpolate_at_centroid", "", "pipeline", "reinterpolate_at_centroid.amber", requirements));
1105		reInterpolationGroup->addChild(cts_amber::createAmberTestCase(testCtx, "interpolate_at_sample", "", "pipeline", "reinterpolate_at_sample.amber", requirements));
1106		testGroup->addChild(reInterpolationGroup.release());
1107
1108		de::MovePtr<tcu::TestCaseGroup> nonuniformInterpolantIndexingGroup(new tcu::TestCaseGroup(testCtx, "nonuniform_interpolant_indexing", "Test nonuniform interpolant indexing"));
1109		std::vector<std::string> requirementsNonuniformIntepolantIndexing;
1110		requirementsNonuniformIntepolantIndexing.push_back("Features.sampleRateShading");
1111		nonuniformInterpolantIndexingGroup->addChild(cts_amber::createAmberTestCase(testCtx, "centroid",  "pipeline/nonuniform_interpolant_indexing", "centroid.amber", requirementsNonuniformIntepolantIndexing));
1112		nonuniformInterpolantIndexingGroup->addChild(cts_amber::createAmberTestCase(testCtx, "sample",  "pipeline/nonuniform_interpolant_indexing", "sample.amber", requirementsNonuniformIntepolantIndexing));
1113		nonuniformInterpolantIndexingGroup->addChild(cts_amber::createAmberTestCase(testCtx, "offset",  "pipeline/nonuniform_interpolant_indexing", "offset.amber", requirementsNonuniformIntepolantIndexing));
1114		testGroup->addChild(nonuniformInterpolantIndexingGroup.release());
1115	}
1116
1117	testGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseCentroidQualifierInsidePrimitive> >	(testCtx, "centroid_qualifier_inside_primitive",	pipelineConstructionType, imageSizes, sizesElemCount, imageSamples, samplesElemCount));
1118#endif // CTS_USES_VULKANSC
1119	testGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseInterpolateAtOffsetPixelCenter> >	(testCtx, "offset_interpolate_at_pixel_center",		pipelineConstructionType, imageSizes, sizesElemCount, imageSamples, samplesElemCount));
1120
1121	de::MovePtr<tcu::TestCaseGroup> offsetGroup(new tcu::TestCaseGroup(testCtx, "offset_interpolation_at_sample_position", "Test interpolation at offset function works for sample positions"));
1122	offsetGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseInterpolateAtOffsetSamplePosition> >	(testCtx, "all_components",		pipelineConstructionType, imageSizes, sizesElemCount, imageSamples, samplesElemCount));
1123	offsetGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseInterpolateAtOffsetSamplePosition> >	(testCtx, "component_0",		pipelineConstructionType, imageSizes, sizesElemCount, imageSamples, samplesElemCount, multisample::ComponentData{multisample::ComponentSource::CONSTANT, 0u}));
1124	offsetGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseInterpolateAtOffsetSamplePosition> >	(testCtx, "component_1",		pipelineConstructionType, imageSizes, sizesElemCount, imageSamples, samplesElemCount, multisample::ComponentData{multisample::ComponentSource::CONSTANT, 1u}));
1125	offsetGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseInterpolateAtOffsetSamplePosition> >	(testCtx, "pushc_component_0",	pipelineConstructionType, imageSizes, sizesElemCount, imageSamples, samplesElemCount, multisample::ComponentData{multisample::ComponentSource::PUSH_CONSTANT, 0u}));
1126	offsetGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseInterpolateAtOffsetSamplePosition> >	(testCtx, "pushc_component_1",	pipelineConstructionType, imageSizes, sizesElemCount, imageSamples, samplesElemCount, multisample::ComponentData{multisample::ComponentSource::PUSH_CONSTANT, 1u}));
1127	testGroup->addChild(offsetGroup.release());
1128
1129	return testGroup.release();
1130}
1131
1132} // pipeline
1133} // vkt
1134