1/*-------------------------------------------------------------------------
2 * OpenGL Conformance Test Suite
3 * -----------------------------
4 *
5 * Copyright (c) 2014-2016 The Khronos Group Inc.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 *      http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 */ /*!
20 * \file
21 * \brief
22 */ /*-------------------------------------------------------------------*/
23
24#include "glcShaderMultisampleInterpolationTests.hpp"
25#include "deMath.h"
26#include "deRandom.hpp"
27#include "deStringUtil.hpp"
28#include "gluContextInfo.hpp"
29#include "gluDrawUtil.hpp"
30#include "gluPixelTransfer.hpp"
31#include "gluShaderProgram.hpp"
32#include "glw.h"
33#include "glwFunctions.hpp"
34#include "tcuCommandLine.hpp"
35#include "tcuStringTemplate.hpp"
36#include "tcuSurface.hpp"
37#include "tcuTestLog.hpp"
38
39namespace tcu
40{
41static bool operator<(tcu::Vec4 const& k1, tcu::Vec4 const& k2)
42{
43	if (k1.y() < k2.y())
44	{
45		return true;
46	}
47	else if (k1.y() == k2.y())
48	{
49		return k1.x() < k2.x();
50	}
51	else
52	{
53		return false;
54	}
55}
56}
57
58namespace deqp
59{
60
61using tcu::TestLog;
62using std::string;
63using std::vector;
64
65static std::string specializeVersion(std::string const& source, glu::GLSLVersion version,
66									 std::string const& sampler = "", std::string const& outType = "",
67									 std::string const& qualifier = "", std::string const& assignment = "",
68									 std::string const& condition = "")
69{
70	DE_ASSERT(version == glu::GLSL_VERSION_310_ES || version >= glu::GLSL_VERSION_440);
71	std::map<std::string, std::string> args;
72	args["VERSION_DECL"] = glu::getGLSLVersionDeclaration(version);
73	args["SAMPLER"]		 = sampler;
74	args["OUT_TYPE"]	 = outType;
75	args["QUALIFIER"]	= qualifier;
76	args["ASSIGNMENT"]   = assignment;
77	args["CONDITION"]	= condition;
78	if (version == glu::GLSL_VERSION_310_ES)
79	{
80		args["OES_SMI_EN"] = "#extension GL_OES_shader_multisample_interpolation : enable\n";
81		args["OES_SMI_RQ"] = "#extension GL_OES_shader_multisample_interpolation : require\n";
82		args["OES_SMI_CH"] = "#if !GL_OES_shader_multisample_interpolation\n"
83							 "    this is broken\n"
84							 "#endif\n";
85		args["OES_SV_EN"] = "#extension GL_OES_sample_variables : enable\n";
86	}
87	else
88	{
89		args["OES_SMI_EN"] = "";
90		args["OES_SMI_RQ"] = "";
91		args["OES_SMI_CH"] = "";
92		args["OES_SV_EN"]  = "";
93	}
94	return tcu::StringTemplate(source.c_str()).specialize(args);
95}
96
97class ShaderMultisampleInterpolationApiCase : public TestCase
98{
99public:
100	ShaderMultisampleInterpolationApiCase(Context& context, const char* name, const char* description,
101										  glu::GLSLVersion glslVersion);
102	~ShaderMultisampleInterpolationApiCase();
103
104	IterateResult iterate();
105
106protected:
107	glu::GLSLVersion m_glslVersion;
108};
109
110ShaderMultisampleInterpolationApiCase::ShaderMultisampleInterpolationApiCase(Context& context, const char* name,
111																			 const char*	  description,
112																			 glu::GLSLVersion glslVersion)
113	: TestCase(context, name, description), m_glslVersion(glslVersion)
114{
115	DE_ASSERT(glslVersion == glu::GLSL_VERSION_310_ES || glslVersion >= glu::GLSL_VERSION_440);
116}
117
118ShaderMultisampleInterpolationApiCase::~ShaderMultisampleInterpolationApiCase()
119{
120}
121
122ShaderMultisampleInterpolationApiCase::IterateResult ShaderMultisampleInterpolationApiCase::iterate()
123{
124	TestLog&			  log  = m_testCtx.getLog();
125	const glw::Functions& gl   = m_context.getRenderContext().getFunctions();
126	bool				  isOk = true;
127
128	if (m_glslVersion == glu::GLSL_VERSION_310_ES &&
129		!m_context.getContextInfo().isExtensionSupported("GL_OES_shader_multisample_interpolation"))
130	{
131		m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "GL_OES_shader_multisample_interpolation");
132		return STOP;
133	}
134
135	static char const* vss = "${VERSION_DECL}\n"
136							 "${OES_SMI_RQ}"
137							 "in highp vec4 a_position;\n"
138							 "in highp vec4 a_color;\n"
139							 "sample out highp vec4 v_color;\n"
140							 "void main()\n"
141							 "{\n"
142							 "    gl_Position = a_position;\n"
143							 "}\n";
144
145	{
146		static char const* fss = "${VERSION_DECL}\n"
147								 "${OES_SMI_RQ}"
148								 "sample in highp vec4 v_color;\n"
149								 "out highp vec4 o_color;\n"
150								 "void main()\n"
151								 "{\n"
152								 "    o_color = v_color;\n"
153								 "}\n";
154
155		glu::ShaderProgram program(m_context.getRenderContext(),
156								   glu::makeVtxFragSources(specializeVersion(vss, m_glslVersion).c_str(),
157														   specializeVersion(fss, m_glslVersion).c_str()));
158		log << program;
159		if (!program.isOk())
160		{
161			TCU_FAIL("Compile failed");
162		}
163	}
164
165	{
166		static char const* fss = "${VERSION_DECL}\n"
167								 "${OES_SMI_EN}"
168								 "sample in highp vec4 v_color;\n"
169								 "out highp vec4 o_color;\n"
170								 "void main()\n"
171								 "{\n"
172								 "${OES_SMI_CH}"
173								 "    o_color = v_color;\n"
174								 "}\n";
175
176		glu::ShaderProgram program(m_context.getRenderContext(),
177								   glu::makeVtxFragSources(specializeVersion(vss, m_glslVersion).c_str(),
178														   specializeVersion(fss, m_glslVersion).c_str()));
179		log << program;
180		if (!program.isOk())
181		{
182			TCU_FAIL("Compile failed");
183		}
184	}
185
186	GLfloat minFragmentInterpolationOffset = 0.0f;
187	gl.getFloatv(GL_MIN_FRAGMENT_INTERPOLATION_OFFSET, &minFragmentInterpolationOffset);
188	if (minFragmentInterpolationOffset > -0.5f)
189	{
190		isOk = false;
191	}
192
193	GLint fragmentInterpolationOffsetBits = 0;
194	gl.getIntegerv(GL_FRAGMENT_INTERPOLATION_OFFSET_BITS, &fragmentInterpolationOffsetBits);
195	if (fragmentInterpolationOffsetBits < 4)
196	{
197		isOk = false;
198	}
199	GLfloat ULP = 1.0f / powf(2, static_cast<float>(fragmentInterpolationOffsetBits));
200
201	GLfloat maxFragmentInterpolationOffset = 0.0f;
202	gl.getFloatv(GL_MAX_FRAGMENT_INTERPOLATION_OFFSET, &maxFragmentInterpolationOffset);
203	if (maxFragmentInterpolationOffset < 0.5f - ULP)
204	{
205		isOk = false;
206	}
207
208	m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, isOk ? "Pass" : "Fail");
209	return STOP;
210}
211
212class ShaderMultisampleInterpolationBaseCase : public TestCase
213{
214public:
215	ShaderMultisampleInterpolationBaseCase(Context& context, const char* name, const char* description,
216										   glu::GLSLVersion glslVersion, char const* qualifier, char const* assignment,
217										   char const* condition, bool unique, GLenum internalFormat,
218										   tcu::TextureFormat const& texFormat, const char* m_sampler,
219										   const char* m_outType, GLfloat min, GLfloat max, GLint samples);
220	~ShaderMultisampleInterpolationBaseCase();
221
222	IterateResult iterate();
223
224protected:
225	glu::GLSLVersion   m_glslVersion;
226	std::string		   m_qualifier;
227	std::string		   m_assignment;
228	std::string		   m_condition;
229	bool			   m_unique;
230	GLenum			   m_internalFormat;
231	tcu::TextureFormat m_texFormat;
232	std::string		   m_sampler;
233	std::string		   m_outType;
234	GLfloat			   m_min;
235	GLfloat			   m_max;
236	GLint			   m_samples;
237
238	enum
239	{
240		WIDTH  = 8,
241		HEIGHT = 8,
242	};
243
244	int countUniquePixels(tcu::ConstPixelBufferAccess const& pixels);
245	int countUniquePixels(const std::vector<tcu::Vec4>& pixels);
246};
247
248ShaderMultisampleInterpolationBaseCase::ShaderMultisampleInterpolationBaseCase(
249	Context& context, const char* name, const char* description, glu::GLSLVersion glslVersion, char const* qualifier,
250	char const* assignment, char const* condition, bool unique, GLenum internalFormat,
251	tcu::TextureFormat const& texFormat, const char* sampler, const char* outType, GLfloat min, GLfloat max,
252	GLint samples)
253	: TestCase(context, name, description)
254	, m_glslVersion(glslVersion)
255	, m_qualifier(qualifier)
256	, m_assignment(assignment)
257	, m_condition(condition)
258	, m_unique(unique)
259	, m_internalFormat(internalFormat)
260	, m_texFormat(texFormat)
261	, m_sampler(sampler)
262	, m_outType(outType)
263	, m_min(min)
264	, m_max(max)
265	, m_samples(samples)
266{
267	DE_ASSERT(glslVersion == glu::GLSL_VERSION_310_ES || glslVersion >= glu::GLSL_VERSION_440);
268}
269
270ShaderMultisampleInterpolationBaseCase::~ShaderMultisampleInterpolationBaseCase()
271{
272}
273
274ShaderMultisampleInterpolationBaseCase::IterateResult ShaderMultisampleInterpolationBaseCase::iterate()
275{
276	TestLog&			  log			  = m_testCtx.getLog();
277	const glw::Functions& gl			  = m_context.getRenderContext().getFunctions();
278	bool				  isOk			  = true;
279	bool				  supportsRgba32f = false;
280
281	if (m_glslVersion == glu::GLSL_VERSION_310_ES &&
282		!m_context.getContextInfo().isExtensionSupported("GL_OES_shader_multisample_interpolation"))
283	{
284		m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "GL_OES_shader_multisample_interpolation");
285		return STOP;
286	}
287
288	supportsRgba32f = isContextTypeGLCore(m_context.getRenderContext().getType()) ?
289						  true :
290						  (m_context.getContextInfo().isExtensionSupported("GL_EXT_color_buffer_float") ||
291						   m_context.getContextInfo().isExtensionSupported("GL_ARB_color_buffer_float"));
292
293	if (m_internalFormat == GL_RGBA32F && !supportsRgba32f)
294	{
295		m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Internalformat rgba32f not supported");
296		return STOP;
297	}
298
299	GLint maxSamples;
300	if (((m_texFormat.type == tcu::TextureFormat::FLOAT) && (m_texFormat.order == tcu::TextureFormat::RGBA)) ||
301		((m_texFormat.type == tcu::TextureFormat::FLOAT) && (m_texFormat.order == tcu::TextureFormat::RG)) ||
302		((m_texFormat.type == tcu::TextureFormat::FLOAT) && (m_texFormat.order == tcu::TextureFormat::R)) ||
303		((m_texFormat.type == tcu::TextureFormat::HALF_FLOAT) && (m_texFormat.order == tcu::TextureFormat::RGBA)))
304	{
305		gl.getInternalformativ(GL_TEXTURE_2D_MULTISAMPLE, m_internalFormat, GL_SAMPLES, 1, &maxSamples);
306		if (m_samples > maxSamples)
307		{
308			m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED,
309									"Test sample count greater than samples that the format supports");
310			return STOP;
311		}
312	}
313	else if (m_texFormat.type == tcu::TextureFormat::SIGNED_INT8 ||
314			 m_texFormat.type == tcu::TextureFormat::UNSIGNED_INT8)
315	{
316		gl.getIntegerv(GL_MAX_INTEGER_SAMPLES, &maxSamples);
317		if (m_samples > maxSamples)
318		{
319			m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Test sample count greater than MAX_INTEGER_SAMPLES");
320			return STOP;
321		}
322	}
323	else
324	{
325		gl.getIntegerv(GL_MAX_SAMPLES, &maxSamples);
326		if (m_samples > maxSamples)
327		{
328			m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Test sample count greater than MAX_SAMPLES");
329			return STOP;
330		}
331	}
332
333	// Create a multisample texture, or a regular texture if samples is zero.
334	GLuint tex;
335	gl.genTextures(1, &tex);
336	gl.bindTexture(GL_TEXTURE_2D_MULTISAMPLE, tex);
337	gl.texStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_samples, m_internalFormat, WIDTH, HEIGHT, GL_FALSE);
338
339	// Create a framebuffer with the texture attached.
340	GLuint fboMs;
341	gl.genFramebuffers(1, &fboMs);
342	gl.bindFramebuffer(GL_FRAMEBUFFER, fboMs);
343	gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, tex, 0);
344	gl.viewport(0, 0, WIDTH, HEIGHT);
345
346	static deUint16 const quadIndices[] = { 0, 1, 2, 2, 1, 3 };
347
348	{
349		// Draw with one of the fragment input qualifiers and with one of the
350		// interpolate functions. Cross-check the result in the shader and
351		// output the final interpolated value.
352
353		static char const* vss = "${VERSION_DECL}\n"
354								 "${OES_SMI_RQ}"
355								 "layout(location = 0) in highp vec2 a_position;\n"
356								 "layout(location = 1) in highp vec4 a_color;\n"
357								 "out highp vec4 v_colorBase;\n"
358								 "${QUALIFIER} out highp vec4 v_color;\n"
359								 "void main()\n"
360								 "{\n"
361								 "    v_colorBase = a_color;\n"
362								 "    v_color = a_color;\n"
363								 "    gl_Position = vec4(a_position, 0.0, 1.0);\n"
364								 "}\n";
365
366		static char const* fss = "${VERSION_DECL}\n"
367								 "${OES_SMI_RQ}"
368								 "${OES_SV_EN}"
369								 "in highp vec4 v_colorBase;\n"
370								 "${QUALIFIER} in highp vec4 v_color;\n"
371								 "layout(location = 0) out highp ${OUT_TYPE} o_color;\n"
372								 "void main()\n"
373								 "{\n"
374								 "    highp vec4 temp = ${ASSIGNMENT};\n"
375								 "    bool condition = ${CONDITION};\n"
376								 "    o_color = ${OUT_TYPE}(temp.x, temp.y, condition, 1);\n"
377								 "}\n";
378
379		glu::ShaderProgram program(
380			m_context.getRenderContext(),
381			glu::makeVtxFragSources(
382				specializeVersion(vss, m_glslVersion, m_sampler, m_outType, m_qualifier, m_assignment, m_condition)
383					.c_str(),
384				specializeVersion(fss, m_glslVersion, m_sampler, m_outType, m_qualifier, m_assignment, m_condition)
385					.c_str()));
386		log << program;
387		if (!program.isOk())
388		{
389			TCU_FAIL("Compile failed");
390		}
391
392		static float const position[] = {
393			-1.0f, -1.0f, -1.0f, +1.0f, +1.0f, -1.0f, +1.0f, +1.0f,
394		};
395
396		const float color[] = {
397			m_min, m_min, 0.0f, 1.0f, m_min, m_max, 0.0f, 1.0f, m_max, m_min, 0.0f, 1.0f, m_max, m_max, 0.0f, 1.0f,
398		};
399
400		gl.useProgram(program.getProgram());
401
402		glu::VertexArrayBinding vertexArrays[] = {
403			glu::va::Float("a_position", 2, 4, 0, &position[0]), glu::va::Float("a_color", 4, 4, 0, &color[0]),
404		};
405		glu::draw(m_context.getRenderContext(), program.getProgram(), DE_LENGTH_OF_ARRAY(vertexArrays),
406				  &vertexArrays[0], glu::pr::TriangleStrip(DE_LENGTH_OF_ARRAY(quadIndices), &quadIndices[0]));
407
408		GLU_EXPECT_NO_ERROR(gl.getError(), "Draw quad");
409	}
410
411	gl.bindFramebuffer(GL_FRAMEBUFFER, m_context.getRenderContext().getDefaultFramebuffer());
412	gl.deleteFramebuffers(1, &fboMs);
413
414	GLsizei width = WIDTH * m_samples;
415
416	GLuint rbo;
417	gl.genRenderbuffers(1, &rbo);
418	gl.bindRenderbuffer(GL_RENDERBUFFER, rbo);
419	gl.renderbufferStorage(GL_RENDERBUFFER, m_internalFormat, width, HEIGHT);
420
421	GLuint fbo;
422	gl.genFramebuffers(1, &fbo);
423	gl.bindFramebuffer(GL_FRAMEBUFFER, fbo);
424	gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo);
425	gl.viewport(0, 0, width, HEIGHT);
426
427	{
428		// Resolve the mutli-sample texture into a render-buffer sized such that
429		// the width can hold all samples of a pixel.
430
431		static char const* vss = "${VERSION_DECL}\n"
432								 "in highp vec2 a_position;\n"
433								 "void main(void)\n"
434								 "{\n"
435								 "   gl_Position = vec4(a_position, 0.0, 1.0);\n"
436								 "}\n";
437
438		static char const* fss = "${VERSION_DECL}\n"
439								 "uniform highp ${SAMPLER}MS u_texMS;\n"
440								 "uniform int u_samples;\n"
441								 "layout(location = 0) out highp ${OUT_TYPE} o_color;\n"
442								 "void main(void)\n"
443								 "{\n"
444								 "    ivec2 coord = ivec2(int(gl_FragCoord.x) / u_samples, gl_FragCoord.y);\n"
445								 "    int sampleId = int(gl_FragCoord.x) % u_samples;\n"
446								 "    o_color = texelFetch(u_texMS, coord, sampleId);\n"
447								 "}\n";
448
449		glu::ShaderProgram program(
450			m_context.getRenderContext(),
451			glu::makeVtxFragSources(specializeVersion(vss, m_glslVersion, m_sampler, m_outType).c_str(),
452									specializeVersion(fss, m_glslVersion, m_sampler, m_outType).c_str()));
453		log << program;
454		if (!program.isOk())
455		{
456			TCU_FAIL("Compile failed");
457		}
458
459		static float const position[] = {
460			-1.0f, -1.0f, -1.0f, +1.0f, +1.0f, -1.0f, +1.0f, +1.0f,
461		};
462
463		gl.useProgram(program.getProgram());
464		gl.uniform1i(gl.getUniformLocation(program.getProgram(), "u_samples"), m_samples);
465		gl.uniform1i(gl.getUniformLocation(program.getProgram(), "u_texMS"), 0);
466
467		glu::VertexArrayBinding vertexArrays[] = {
468			glu::va::Float("a_position", 2, 4, 0, &position[0]),
469		};
470		glu::draw(m_context.getRenderContext(), program.getProgram(), DE_LENGTH_OF_ARRAY(vertexArrays),
471				  &vertexArrays[0], glu::pr::TriangleStrip(DE_LENGTH_OF_ARRAY(quadIndices), &quadIndices[0]));
472
473		GLU_EXPECT_NO_ERROR(gl.getError(), "Draw quad");
474	}
475
476	// Verify the results.
477	tcu::TextureLevel	  results(m_texFormat, width, HEIGHT);
478	tcu::PixelBufferAccess pixels = results.getAccess();
479	std::vector<tcu::Vec4> result(pixels.getHeight() * pixels.getWidth());
480	int					   uniquePixels;
481
482	if (pixels.getFormat().type == tcu::TextureFormat::SIGNED_INT8)
483	{
484		std::vector<GLint> data(pixels.getHeight() * pixels.getWidth() * 4);
485		gl.readPixels(0, 0, pixels.getWidth(), pixels.getHeight(), GL_RGBA_INTEGER, GL_INT, &data[0]);
486		for (unsigned int i = 0; i < data.size(); i += 4)
487		{
488			result[i / 4] =
489				tcu::Vec4((GLfloat)data[i], (GLfloat)data[i + 1], (GLfloat)data[i + 2], (GLfloat)data[i + 3]);
490		}
491		uniquePixels = countUniquePixels(result);
492	}
493	else if (pixels.getFormat().type == tcu::TextureFormat::UNSIGNED_INT8)
494	{
495		std::vector<GLuint> data(pixels.getHeight() * pixels.getWidth() * 4);
496		gl.readPixels(0, 0, pixels.getWidth(), pixels.getHeight(), GL_RGBA_INTEGER, GL_UNSIGNED_INT, &data[0]);
497		for (unsigned int i = 0; i < data.size(); i += 4)
498		{
499			result[i / 4] =
500				tcu::Vec4((GLfloat)data[i], (GLfloat)data[i + 1], (GLfloat)data[i + 2], (GLfloat)data[i + 3]);
501		}
502		uniquePixels = countUniquePixels(result);
503	}
504	else
505	{
506		glu::readPixels(m_context.getRenderContext(), 0, 0, pixels);
507		uniquePixels = countUniquePixels(pixels);
508	}
509
510	int expectedUnique = WIDTH * HEIGHT * ((m_unique) ? m_samples : 1);
511	if (uniquePixels < expectedUnique)
512	{
513		// There are duplicate pixel values meaning interpolation didn't work as expected.
514		isOk = false;
515	}
516	for (int y = 0; y < pixels.getHeight(); ++y)
517	{
518		for (int x = 0; x < pixels.getWidth(); ++x)
519		{
520			tcu::Vec4 pixel;
521			if (pixels.getFormat().type == tcu::TextureFormat::SIGNED_INT8 ||
522				pixels.getFormat().type == tcu::TextureFormat::UNSIGNED_INT8)
523			{
524				pixel = result[y * WIDTH + x];
525			}
526			else
527			{
528				pixel = pixels.getPixel(x, y);
529			}
530			if (pixel.z() != 1)
531			{
532				// The ${CONDITION} check in the shader failed.
533				isOk = false;
534			}
535		}
536	}
537
538	gl.bindFramebuffer(GL_FRAMEBUFFER, m_context.getRenderContext().getDefaultFramebuffer());
539	gl.deleteFramebuffers(1, &fbo);
540
541	gl.bindRenderbuffer(GL_RENDERBUFFER, 0);
542	gl.deleteRenderbuffers(1, &rbo);
543
544	gl.bindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0);
545	gl.deleteTextures(1, &tex);
546
547	m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, isOk ? "Pass" : "Fail");
548	return STOP;
549}
550
551int ShaderMultisampleInterpolationBaseCase::countUniquePixels(tcu::ConstPixelBufferAccess const& pixels)
552{
553	std::set<tcu::Vec4> uniquePixels;
554
555	for (int y = 0; y < pixels.getHeight(); ++y)
556	{
557		for (int x = 0; x < pixels.getWidth(); ++x)
558		{
559			uniquePixels.insert(pixels.getPixel(x, y));
560		}
561	}
562
563	return (int)uniquePixels.size();
564}
565
566int ShaderMultisampleInterpolationBaseCase::countUniquePixels(const std::vector<tcu::Vec4>& pixels)
567{
568	std::set<tcu::Vec4> uniquePixels;
569
570	for (unsigned int i = 0; i < pixels.size(); ++i)
571	{
572		uniquePixels.insert(pixels[i]);
573	}
574
575	return (int)uniquePixels.size();
576}
577
578ShaderMultisampleInterpolationTests::ShaderMultisampleInterpolationTests(Context& context, glu::GLSLVersion glslVersion)
579	: TestCaseGroup(context, "shader_multisample_interpolation", "Shader Multisample Interpolation tests")
580	, m_glslVersion(glslVersion)
581{
582}
583
584ShaderMultisampleInterpolationTests::~ShaderMultisampleInterpolationTests()
585{
586}
587
588void ShaderMultisampleInterpolationTests::init()
589{
590	struct Sample
591	{
592		char const* name;
593		GLint		samples;
594	} samples[] = {
595		{ "samples_1", 1 }, { "samples_2", 2 }, { "samples_4", 4 },
596	};
597
598	// shader_multisample_interpolation.api
599	tcu::TestCaseGroup* apiGroup = new tcu::TestCaseGroup(m_testCtx, "api", "API verification");
600	apiGroup->addChild(new ShaderMultisampleInterpolationApiCase(m_context, "api", "API verification", m_glslVersion));
601	addChild(apiGroup);
602
603	struct Case
604	{
605		char const* name;
606		char const* qualifier;
607		char const* assignment;
608		char const* condition;
609		bool		unique;
610	} cases[] = {
611		{ "base", "", "v_color", "true", false },
612		{ "sample", "sample", "v_color", "true", true },
613		{ "centroid", "centroid", "v_color", "true", false },
614		{ "interpolate_at_sample", "", "interpolateAtSample(v_colorBase, gl_SampleID)", "true", true },
615		{ "interpolate_at_sample_check", "sample", "interpolateAtSample(v_colorBase, gl_SampleID)", "temp == v_color",
616		  true },
617		{ "interpolate_at_centroid", "", "interpolateAtCentroid(v_colorBase)", "true", false },
618		{ "interpolate_at_centroid_check", "centroid", "interpolateAtCentroid(v_colorBase)", "temp == v_color", false },
619		{ "interpolate_at_offset", "", "interpolateAtOffset(v_colorBase, gl_SamplePosition - 0.5)", "true", true },
620		{ "interpolate_at_offset_check", "sample", "interpolateAtOffset(v_colorBase, gl_SamplePosition - 0.5)",
621		  "temp == v_color", true },
622	};
623
624	// shader_multisample_interpolation.render
625	tcu::TestCaseGroup* renderGroup = new tcu::TestCaseGroup(m_testCtx, "render", "Rendering tests");
626	addChild(renderGroup);
627	for (int caseId = 0; caseId < DE_LENGTH_OF_ARRAY(cases); ++caseId)
628	{
629		tcu::TestCaseGroup* group = new tcu::TestCaseGroup(m_testCtx, cases[caseId].name, "");
630		renderGroup->addChild(group);
631		struct Format
632		{
633			char const*		   name;
634			GLenum			   internalFormat;
635			tcu::TextureFormat textureFormat;
636			char const*		   sampler;
637			char const*		   outType;
638			GLfloat			   min;
639			GLfloat			   max;
640		} formats[] = {
641			{ "rgba8", GL_RGBA8, tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8),
642			  "sampler2D", "vec4", 0.0f, 1.0f },
643			{ "rgba8i", GL_RGBA8I, tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::SIGNED_INT8),
644			  "isampler2D", "ivec4", -128.0f, 127.0f },
645			{ "rgba8ui", GL_RGBA8UI, tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNSIGNED_INT8),
646			  "usampler2D", "uvec4", 0.0f, 255.0f },
647			{ "rgba32f", GL_RGBA32F, tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::FLOAT),
648			  "sampler2D", "vec4", 0.0f, 1.0f },
649		};
650		for (int format = 0; format < DE_LENGTH_OF_ARRAY(formats); ++format)
651		{
652			tcu::TestCaseGroup* formatGroup = new tcu::TestCaseGroup(m_testCtx, formats[format].name, "");
653			group->addChild(formatGroup);
654
655			for (int sample = 0; sample < DE_LENGTH_OF_ARRAY(samples); ++sample)
656			{
657				formatGroup->addChild(new ShaderMultisampleInterpolationBaseCase(
658					m_context, samples[sample].name, "", m_glslVersion, cases[caseId].qualifier,
659					cases[caseId].assignment, cases[caseId].condition, cases[caseId].unique,
660					formats[format].internalFormat, formats[format].textureFormat, formats[format].sampler,
661					formats[format].outType, formats[format].min, formats[format].max, samples[sample].samples));
662			}
663		}
664	}
665}
666
667} // glcts
668