1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 2.0 Module
3  * -------------------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
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 Multisampling tests.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "es2fMultisampleTests.hpp"
25 #include "gluPixelTransfer.hpp"
26 #include "gluShaderProgram.hpp"
27 #include "tcuSurface.hpp"
28 #include "tcuImageCompare.hpp"
29 #include "tcuRenderTarget.hpp"
30 #include "tcuTestLog.hpp"
31 #include "tcuTextureUtil.hpp"
32 #include "tcuCommandLine.hpp"
33 #include "deStringUtil.hpp"
34 #include "deRandom.hpp"
35 #include "deMath.h"
36 #include "deString.h"
37 
38 #include "glw.h"
39 
40 #include <string>
41 #include <vector>
42 
43 namespace deqp
44 {
45 namespace gles2
46 {
47 namespace Functional
48 {
49 
50 using tcu::Vec2;
51 using tcu::Vec3;
52 using tcu::Vec4;
53 using tcu::IVec2;
54 using tcu::IVec4;
55 using tcu::TestLog;
56 using std::vector;
57 
58 static const float SQRT_HALF = 0.707107f;
59 
60 namespace
61 {
62 
63 struct QuadCorners
64 {
65 	Vec2 p0;
66 	Vec2 p1;
67 	Vec2 p2;
68 	Vec2 p3;
69 
QuadCornersdeqp::gles2::Functional::__anona88560210111::QuadCorners70 	QuadCorners(const Vec2& p0_, const Vec2& p1_, const Vec2& p2_, const Vec2& p3_) : p0(p0_), p1(p1_), p2(p2_), p3(p3_) {}
71 };
72 
73 } // anonymous
74 
getIterationCount(const tcu::TestContext & ctx,int defaultCount)75 static inline int getIterationCount (const tcu::TestContext& ctx, int defaultCount)
76 {
77 	int cmdLineValue = ctx.getCommandLine().getTestIterationCount();
78 	return cmdLineValue > 0 ? cmdLineValue : defaultCount;
79 }
80 
getGLInteger(GLenum name)81 static inline int getGLInteger (GLenum name)
82 {
83 	int result;
84 	GLU_CHECK_CALL(glGetIntegerv(name, &result));
85 	return result;
86 }
87 
88 template<typename T>
min4(T a,T b,T c,T d)89 static inline T min4 (T a, T b, T c, T d)
90 {
91 	return de::min(de::min(de::min(a, b), c), d);
92 }
93 
94 template<typename T>
max4(T a,T b,T c,T d)95 static inline T max4 (T a, T b, T c, T d)
96 {
97 	return de::max(de::max(de::max(a, b), c), d);
98 }
99 
isInsideQuad(const IVec2 & point,const IVec2 & p0,const IVec2 & p1,const IVec2 & p2,const IVec2 & p3)100 static inline bool isInsideQuad (const IVec2& point, const IVec2& p0, const IVec2& p1, const IVec2& p2, const IVec2& p3)
101 {
102 	int dot0 = (point.x()-p0.x()) * (p1.y()-p0.y()) + (point.y()-p0.y()) * (p0.x()-p1.x());
103 	int dot1 = (point.x()-p1.x()) * (p2.y()-p1.y()) + (point.y()-p1.y()) * (p1.x()-p2.x());
104 	int dot2 = (point.x()-p2.x()) * (p3.y()-p2.y()) + (point.y()-p2.y()) * (p2.x()-p3.x());
105 	int dot3 = (point.x()-p3.x()) * (p0.y()-p3.y()) + (point.y()-p3.y()) * (p3.x()-p0.x());
106 
107 	return (dot0 > 0) == (dot1 > 0) && (dot1 > 0) == (dot2 > 0) && (dot2 > 0) == (dot3 > 0);
108 }
109 
110 /*--------------------------------------------------------------------*//*!
111  * \brief Check if a region in an image is unicolored.
112  *
113  * Checks if the pixels in img inside the convex quadilateral defined by
114  * p0, p1, p2 and p3 are all (approximately) of the same color.
115  *//*--------------------------------------------------------------------*/
isPixelRegionUnicolored(const tcu::Surface & img,const IVec2 & p0,const IVec2 & p1,const IVec2 & p2,const IVec2 & p3)116 static bool isPixelRegionUnicolored (const tcu::Surface& img, const IVec2& p0, const IVec2& p1, const IVec2& p2, const IVec2& p3)
117 {
118 	int			xMin				= de::clamp(min4(p0.x(), p1.x(), p2.x(), p3.x()), 0, img.getWidth()-1);
119 	int			yMin				= de::clamp(min4(p0.y(), p1.y(), p2.y(), p3.y()), 0, img.getHeight()-1);
120 	int			xMax				= de::clamp(max4(p0.x(), p1.x(), p2.x(), p3.x()), 0, img.getWidth()-1);
121 	int			yMax				= de::clamp(max4(p0.y(), p1.y(), p2.y(), p3.y()), 0, img.getHeight()-1);
122 	bool		insideEncountered	= false;	//!< Whether we have already seen at least one pixel inside the region.
123 	tcu::RGBA	insideColor;					//!< Color of the first pixel inside the region.
124 
125 	for (int y = yMin; y <= yMax; y++)
126 	for (int x = xMin; x <= xMax; x++)
127 	{
128 		if (isInsideQuad(IVec2(x, y), p0, p1, p2, p3))
129 		{
130 			tcu::RGBA pixColor = img.getPixel(x, y);
131 
132 			if (insideEncountered)
133 			{
134 				if (!tcu::compareThreshold(pixColor, insideColor, tcu::RGBA(3, 3, 3, 3))) // Pixel color differs from already-detected color inside same region - region not unicolored.
135 					return false;
136 			}
137 			else
138 			{
139 				insideEncountered = true;
140 				insideColor = pixColor;
141 			}
142 		}
143 	}
144 
145 	return true;
146 }
147 
drawUnicolorTestErrors(tcu::Surface & img,const tcu::PixelBufferAccess & errorImg,const IVec2 & p0,const IVec2 & p1,const IVec2 & p2,const IVec2 & p3)148 static bool drawUnicolorTestErrors (tcu::Surface& img, const tcu::PixelBufferAccess& errorImg, const IVec2& p0, const IVec2& p1, const IVec2& p2, const IVec2& p3)
149 {
150 	int			xMin		= de::clamp(min4(p0.x(), p1.x(), p2.x(), p3.x()), 0, img.getWidth()-1);
151 	int			yMin		= de::clamp(min4(p0.y(), p1.y(), p2.y(), p3.y()), 0, img.getHeight()-1);
152 	int			xMax		= de::clamp(max4(p0.x(), p1.x(), p2.x(), p3.x()), 0, img.getWidth()-1);
153 	int			yMax		= de::clamp(max4(p0.y(), p1.y(), p2.y(), p3.y()), 0, img.getHeight()-1);
154 	tcu::RGBA	refColor	= img.getPixel((xMin + xMax) / 2, (yMin + yMax) / 2);
155 
156 	for (int y = yMin; y <= yMax; y++)
157 	for (int x = xMin; x <= xMax; x++)
158 	{
159 		if (isInsideQuad(IVec2(x, y), p0, p1, p2, p3))
160 		{
161 			if (!tcu::compareThreshold(img.getPixel(x, y), refColor, tcu::RGBA(3, 3, 3, 3)))
162 			{
163 				img.setPixel(x, y, tcu::RGBA::red());
164 				errorImg.setPixel(Vec4(1.0f, 0.0f, 0.0f, 1.0f), x, y);
165 			}
166 		}
167 	}
168 
169 	return true;
170 }
171 
172 /*--------------------------------------------------------------------*//*!
173  * \brief Abstract base class handling common stuff for multisample cases.
174  *//*--------------------------------------------------------------------*/
175 class MultisampleCase : public TestCase
176 {
177 public:
178 						MultisampleCase			(Context& context, const char* name, const char* desc);
179 	virtual				~MultisampleCase		(void);
180 
181 	virtual void		init					(void);
182 	virtual void		deinit					(void);
183 
184 protected:
185 	virtual int			getDesiredViewportSize	(void) const = 0;
186 
187 	void				renderTriangle			(const Vec3& p0, const Vec3& p1, const Vec3& p2, const Vec4& c0, const Vec4& c1, const Vec4& c2) const;
188 	void				renderTriangle			(const Vec3& p0, const Vec3& p1, const Vec3& p2, const Vec4& color) const;
189 	void				renderTriangle			(const Vec2& p0, const Vec2& p1, const Vec2& p2, const Vec4& c0, const Vec4& c1, const Vec4& c2) const;
190 	void				renderTriangle			(const Vec2& p0, const Vec2& p1, const Vec2& p2, const Vec4& color) const;
191 	void				renderQuad				(const Vec2& p0, const Vec2& p1, const Vec2& p2, const Vec2& p3, const Vec4& c0, const Vec4& c1, const Vec4& c2, const Vec4& c3) const;
192 	void				renderQuad				(const Vec2& p0, const Vec2& p1, const Vec2& p2, const Vec2& p3, const Vec4& color) const;
193 	void				renderLine				(const Vec2& p0, const Vec2& p1, const Vec4& color) const;
194 
195 	void				randomizeViewport		(void);
196 	void				readImage				(tcu::Surface& dst) const;
197 
198 	int					m_numSamples;
199 
200 	int					m_viewportSize;
201 
202 private:
203 						MultisampleCase			(const MultisampleCase& other);
204 	MultisampleCase&	operator=				(const MultisampleCase& other);
205 
206 	glu::ShaderProgram*	m_program;
207 	int					m_attrPositionLoc;
208 	int					m_attrColorLoc;
209 
210 	int					m_viewportX;
211 	int					m_viewportY;
212 	de::Random			m_rnd;
213 };
214 
MultisampleCase(Context & context,const char * name,const char * desc)215 MultisampleCase::MultisampleCase (Context& context, const char* name, const char* desc)
216 	: TestCase			(context, name, desc)
217 	, m_numSamples		(0)
218 	, m_viewportSize	(0)
219 	, m_program			(DE_NULL)
220 	, m_attrPositionLoc	(-1)
221 	, m_attrColorLoc	(-1)
222 	, m_viewportX		(0)
223 	, m_viewportY		(0)
224 	, m_rnd				(deStringHash(name))
225 {
226 }
227 
renderTriangle(const Vec3 & p0,const Vec3 & p1,const Vec3 & p2,const Vec4 & c0,const Vec4 & c1,const Vec4 & c2) const228 void MultisampleCase::renderTriangle (const Vec3& p0, const Vec3& p1, const Vec3& p2, const Vec4& c0, const Vec4& c1, const Vec4& c2) const
229 {
230 	float vertexPositions[] =
231 	{
232 		p0.x(), p0.y(), p0.z(), 1.0f,
233 		p1.x(), p1.y(), p1.z(), 1.0f,
234 		p2.x(), p2.y(), p2.z(), 1.0f
235 	};
236 	float vertexColors[] =
237 	{
238 		c0.x(), c0.y(), c0.z(), c0.w(),
239 		c1.x(), c1.y(), c1.z(), c1.w(),
240 		c2.x(), c2.y(), c2.z(), c2.w(),
241 	};
242 
243 	GLU_CHECK_CALL(glEnableVertexAttribArray(m_attrPositionLoc));
244 	GLU_CHECK_CALL(glVertexAttribPointer(m_attrPositionLoc, 4, GL_FLOAT, false, 0, &vertexPositions[0]));
245 
246 	GLU_CHECK_CALL(glEnableVertexAttribArray(m_attrColorLoc));
247 	GLU_CHECK_CALL(glVertexAttribPointer(m_attrColorLoc, 4, GL_FLOAT, false, 0, &vertexColors[0]));
248 
249 	GLU_CHECK_CALL(glUseProgram(m_program->getProgram()));
250 	GLU_CHECK_CALL(glDrawArrays(GL_TRIANGLES, 0, 3));
251 }
252 
renderTriangle(const Vec3 & p0,const Vec3 & p1,const Vec3 & p2,const Vec4 & color) const253 void MultisampleCase::renderTriangle (const Vec3& p0, const Vec3& p1, const Vec3& p2, const Vec4& color) const
254 {
255 	renderTriangle(p0, p1, p2, color, color, color);
256 }
257 
renderTriangle(const Vec2 & p0,const Vec2 & p1,const Vec2 & p2,const Vec4 & c0,const Vec4 & c1,const Vec4 & c2) const258 void MultisampleCase::renderTriangle (const Vec2& p0, const Vec2& p1, const Vec2& p2, const Vec4& c0, const Vec4& c1, const Vec4& c2) const
259 {
260 	renderTriangle(Vec3(p0.x(), p0.y(), 0.0f),
261 				   Vec3(p1.x(), p1.y(), 0.0f),
262 				   Vec3(p2.x(), p2.y(), 0.0f),
263 				   c0, c1, c2);
264 }
265 
renderTriangle(const Vec2 & p0,const Vec2 & p1,const Vec2 & p2,const Vec4 & color) const266 void MultisampleCase::renderTriangle (const Vec2& p0, const Vec2& p1, const Vec2& p2, const Vec4& color) const
267 {
268 	renderTriangle(p0, p1, p2, color, color, color);
269 }
270 
renderQuad(const Vec2 & p0,const Vec2 & p1,const Vec2 & p2,const Vec2 & p3,const Vec4 & c0,const Vec4 & c1,const Vec4 & c2,const Vec4 & c3) const271 void MultisampleCase::renderQuad (const Vec2& p0, const Vec2& p1, const Vec2& p2, const Vec2& p3, const Vec4& c0, const Vec4& c1, const Vec4& c2, const Vec4& c3) const
272 {
273 	renderTriangle(p0, p1, p2, c0, c1, c2);
274 	renderTriangle(p2, p1, p3, c2, c1, c3);
275 }
276 
renderQuad(const Vec2 & p0,const Vec2 & p1,const Vec2 & p2,const Vec2 & p3,const Vec4 & color) const277 void MultisampleCase::renderQuad (const Vec2& p0, const Vec2& p1, const Vec2& p2, const Vec2& p3, const Vec4& color) const
278 {
279 	renderQuad(p0, p1, p2, p3, color, color, color, color);
280 }
281 
renderLine(const Vec2 & p0,const Vec2 & p1,const Vec4 & color) const282 void MultisampleCase::renderLine (const Vec2& p0, const Vec2& p1, const Vec4& color) const
283 {
284 	float vertexPositions[] =
285 	{
286 		p0.x(), p0.y(), 0.0f, 1.0f,
287 		p1.x(), p1.y(), 0.0f, 1.0f
288 	};
289 	float vertexColors[] =
290 	{
291 		color.x(), color.y(), color.z(), color.w(),
292 		color.x(), color.y(), color.z(), color.w()
293 	};
294 
295 	GLU_CHECK_CALL(glEnableVertexAttribArray(m_attrPositionLoc));
296 	GLU_CHECK_CALL(glVertexAttribPointer(m_attrPositionLoc, 4, GL_FLOAT, false, 0, &vertexPositions[0]));
297 
298 	GLU_CHECK_CALL(glEnableVertexAttribArray(m_attrColorLoc));
299 	GLU_CHECK_CALL(glVertexAttribPointer(m_attrColorLoc, 4, GL_FLOAT, false, 0, &vertexColors[0]));
300 
301 	GLU_CHECK_CALL(glUseProgram(m_program->getProgram()));
302 	GLU_CHECK_CALL(glDrawArrays(GL_LINES, 0, 2));
303 }
304 
randomizeViewport(void)305 void MultisampleCase::randomizeViewport (void)
306 {
307 	m_viewportX = m_rnd.getInt(0, m_context.getRenderTarget().getWidth() - m_viewportSize);
308 	m_viewportY = m_rnd.getInt(0, m_context.getRenderTarget().getHeight() - m_viewportSize);
309 
310 	GLU_CHECK_CALL(glViewport(m_viewportX, m_viewportY, m_viewportSize, m_viewportSize));
311 }
312 
readImage(tcu::Surface & dst) const313 void MultisampleCase::readImage (tcu::Surface& dst) const
314 {
315 	glu::readPixels(m_context.getRenderContext(), m_viewportX, m_viewportY, dst.getAccess());
316 }
317 
init(void)318 void MultisampleCase::init (void)
319 {
320 	static const char* vertShaderSource =
321 		"attribute highp vec4 a_position;\n"
322 		"attribute mediump vec4 a_color;\n"
323 		"varying mediump vec4 v_color;\n"
324 		"void main()\n"
325 		"{\n"
326 		"	gl_Position = a_position;\n"
327 		"	v_color = a_color;\n"
328 		"}\n";
329 
330 	static const char* fragShaderSource =
331 		"varying mediump vec4 v_color;\n"
332 		"void main()\n"
333 		"{\n"
334 		"	gl_FragColor = v_color;\n"
335 		"}\n";
336 
337 	// Check multisample support.
338 
339 	if (m_context.getRenderTarget().getNumSamples() <= 1)
340 		throw tcu::NotSupportedError("No multisample buffers");
341 
342 	// Prepare program.
343 
344 	DE_ASSERT(!m_program);
345 
346 	m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(vertShaderSource, fragShaderSource));
347 	if (!m_program->isOk())
348 		throw tcu::TestError("Failed to compile program", DE_NULL, __FILE__, __LINE__);
349 
350 	GLU_CHECK_CALL(m_attrPositionLoc	= glGetAttribLocation(m_program->getProgram(), "a_position"));
351 	GLU_CHECK_CALL(m_attrColorLoc		= glGetAttribLocation(m_program->getProgram(), "a_color"));
352 
353 	if (m_attrPositionLoc < 0 || m_attrColorLoc < 0)
354 	{
355 		delete m_program;
356 		throw tcu::TestError("Invalid attribute locations", DE_NULL, __FILE__, __LINE__);
357 	}
358 
359 	// Get suitable viewport size.
360 
361 	m_viewportSize = de::min<int>(getDesiredViewportSize(), de::min(m_context.getRenderTarget().getWidth(), m_context.getRenderTarget().getHeight()));
362 	randomizeViewport();
363 
364 	// Query and log number of samples per pixel.
365 
366 	m_numSamples = getGLInteger(GL_SAMPLES);
367 	m_testCtx.getLog() << TestLog::Message << "GL_SAMPLES = " << m_numSamples << TestLog::EndMessage;
368 }
369 
~MultisampleCase(void)370 MultisampleCase::~MultisampleCase (void)
371 {
372 	delete m_program;
373 }
374 
deinit(void)375 void MultisampleCase::deinit (void)
376 {
377 	delete m_program;
378 
379 	m_program = DE_NULL;
380 }
381 
382 /*--------------------------------------------------------------------*//*!
383  * \brief Base class for cases testing the value of GL_SAMPLES.
384  *
385  * Draws a test pattern (defined by renderPattern() of an inheriting class)
386  * and counts the number of distinct colors in the resulting image. That
387  * number should be at least the value of GL_SAMPLES plus one. This is
388  * repeated with increased values of m_currentIteration until this correct
389  * number of colors is detected or m_currentIteration reaches
390  * m_maxNumIterations.
391  *//*--------------------------------------------------------------------*/
392 class NumSamplesCase : public MultisampleCase
393 {
394 public:
395 						NumSamplesCase			(Context& context, const char* name, const char* description);
~NumSamplesCase(void)396 						~NumSamplesCase			(void) {}
397 
398 	IterateResult		iterate					(void);
399 
400 protected:
getDesiredViewportSize(void) const401 	int					getDesiredViewportSize	(void) const { return 256; }
402 	virtual void		renderPattern			(void) const = 0;
403 
404 	int					m_currentIteration;
405 
406 private:
407 	enum { DEFAULT_MAX_NUM_ITERATIONS = 16 };
408 
409 	const int			m_maxNumIterations;
410 	vector<tcu::RGBA>	m_detectedColors;
411 };
412 
NumSamplesCase(Context & context,const char * name,const char * description)413 NumSamplesCase::NumSamplesCase (Context& context, const char* name, const char* description)
414 	: MultisampleCase		(context, name, description)
415 	, m_currentIteration	(0)
416 	, m_maxNumIterations	(getIterationCount(m_testCtx, DEFAULT_MAX_NUM_ITERATIONS))
417 {
418 }
419 
iterate(void)420 NumSamplesCase::IterateResult NumSamplesCase::iterate (void)
421 {
422 	TestLog&		log				= m_testCtx.getLog();
423 	tcu::Surface	renderedImg		(m_viewportSize, m_viewportSize);
424 
425 	randomizeViewport();
426 
427 	GLU_CHECK_CALL(glClearColor(0.0f, 0.0f, 0.0f, 1.0f));
428 	GLU_CHECK_CALL(glClear(GL_COLOR_BUFFER_BIT));
429 
430 	renderPattern();
431 
432 	// Read and log rendered image.
433 
434 	readImage(renderedImg);
435 
436 	log << TestLog::Image("RenderedImage", "Rendered image", renderedImg, QP_IMAGE_COMPRESSION_MODE_PNG);
437 
438 	// Detect new, previously unseen colors from image.
439 
440 	int requiredNumDistinctColors = m_numSamples + 1;
441 
442 	for (int y = 0; y < renderedImg.getHeight() && (int)m_detectedColors.size() < requiredNumDistinctColors; y++)
443 	for (int x = 0; x < renderedImg.getWidth() && (int)m_detectedColors.size() < requiredNumDistinctColors; x++)
444 	{
445 		tcu::RGBA color = renderedImg.getPixel(x, y);
446 
447 		int i;
448 		for (i = 0; i < (int)m_detectedColors.size(); i++)
449 		{
450 			if (tcu::compareThreshold(color, m_detectedColors[i], tcu::RGBA(3, 3, 3, 3)))
451 				break;
452 		}
453 
454 		if (i == (int)m_detectedColors.size())
455 			m_detectedColors.push_back(color); // Color not previously detected.
456 	}
457 
458 	// Log results.
459 
460 	log << TestLog::Message
461 		<< "Number of distinct colors detected so far: "
462 		<< ((int)m_detectedColors.size() >= requiredNumDistinctColors ? "at least " : "")
463 		<< de::toString(m_detectedColors.size())
464 		<< TestLog::EndMessage;
465 
466 	if ((int)m_detectedColors.size() < requiredNumDistinctColors)
467 	{
468 		// Haven't detected enough different colors yet.
469 
470 		m_currentIteration++;
471 
472 		if (m_currentIteration >= m_maxNumIterations)
473 		{
474 			log << TestLog::Message << "Failure: Number of distinct colors detected is lower than GL_SAMPLES+1" << TestLog::EndMessage;
475 			m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Failed");
476 			return STOP;
477 		}
478 		else
479 		{
480 			log << TestLog::Message << "The number of distinct colors detected is lower than GL_SAMPLES+1 - trying again with a slightly altered pattern" << TestLog::EndMessage;
481 			return CONTINUE;
482 		}
483 	}
484 	else
485 	{
486 		log << TestLog::Message << "Success: The number of distinct colors detected is at least GL_SAMPLES+1" << TestLog::EndMessage;
487 		m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Passed");
488 		return STOP;
489 	}
490 }
491 
492 class PolygonNumSamplesCase : public NumSamplesCase
493 {
494 public:
495 			PolygonNumSamplesCase	(Context& context, const char* name, const char* description);
~PolygonNumSamplesCase(void)496 			~PolygonNumSamplesCase	(void) {}
497 
498 protected:
499 	void	renderPattern			(void) const;
500 };
501 
PolygonNumSamplesCase(Context & context,const char * name,const char * description)502 PolygonNumSamplesCase::PolygonNumSamplesCase (Context& context, const char* name, const char* description)
503 	: NumSamplesCase(context, name, description)
504 {
505 }
506 
renderPattern(void) const507 void PolygonNumSamplesCase::renderPattern (void) const
508 {
509 	// The test pattern consists of several triangles with edges at different angles.
510 
511 	const int numTriangles = 25;
512 	for (int i = 0; i < numTriangles; i++)
513 	{
514 		float angle0 = 2.0f*DE_PI * (float)i			/ (float)numTriangles + 0.001f*(float)m_currentIteration;
515 		float angle1 = 2.0f*DE_PI * ((float)i + 0.5f)	/ (float)numTriangles + 0.001f*(float)m_currentIteration;
516 
517 		renderTriangle(Vec2(0.0f, 0.0f),
518 					   Vec2(deFloatCos(angle0)*0.95f, deFloatSin(angle0)*0.95f),
519 					   Vec2(deFloatCos(angle1)*0.95f, deFloatSin(angle1)*0.95f),
520 					   Vec4(1.0f));
521 	}
522 }
523 
524 class LineNumSamplesCase : public NumSamplesCase
525 {
526 public:
527 			LineNumSamplesCase		(Context& context, const char* name, const char* description);
~LineNumSamplesCase(void)528 			~LineNumSamplesCase		(void) {}
529 
530 protected:
531 	void	renderPattern			(void) const;
532 };
533 
LineNumSamplesCase(Context & context,const char * name,const char * description)534 LineNumSamplesCase::LineNumSamplesCase (Context& context, const char* name, const char* description)
535 	: NumSamplesCase (context, name, description)
536 {
537 }
538 
renderPattern(void) const539 void LineNumSamplesCase::renderPattern (void) const
540 {
541 	// The test pattern consists of several lines at different angles.
542 
543 	// We scale the number of lines based on the viewport size. This is because a gl line's thickness is
544 	// constant in pixel units, i.e. they get relatively thicker as viewport size decreases. Thus we must
545 	// decrease the number of lines in order to decrease the extent of overlap among the lines in the
546 	// center of the pattern.
547 	const int numLines = (int)(100.0f * deFloatSqrt((float)m_viewportSize / 256.0f));
548 
549 	for (int i = 0; i < numLines; i++)
550 	{
551 		float angle = 2.0f*DE_PI * (float)i / (float)numLines + 0.001f*(float)m_currentIteration;
552 		renderLine(Vec2(0.0f, 0.0f), Vec2(deFloatCos(angle)*0.95f, deFloatSin(angle)*0.95f), Vec4(1.0f));
553 	}
554 }
555 
556 /*--------------------------------------------------------------------*//*!
557  * \brief Case testing behaviour of common edges when multisampling.
558  *
559  * Draws a number of test patterns, each with a number of quads, each made
560  * of two triangles, rotated at different angles. The inner edge inside the
561  * quad (i.e. the common edge of the two triangles) still should not be
562  * visible, despite multisampling - i.e. the two triangles forming the quad
563  * should never get any common coverage bits in any pixel.
564  *//*--------------------------------------------------------------------*/
565 class CommonEdgeCase : public MultisampleCase
566 {
567 public:
568 	enum CaseType
569 	{
570 		CASETYPE_SMALL_QUADS = 0,				//!< Draw several small quads per iteration.
571 		CASETYPE_BIGGER_THAN_VIEWPORT_QUAD,		//!< Draw one bigger-than-viewport quad per iteration.
572 		CASETYPE_FIT_VIEWPORT_QUAD,				//!< Draw one exactly viewport-sized, axis aligned quad per iteration.
573 
574 		CASETYPE_LAST
575 	};
576 
577 					CommonEdgeCase			(Context& context, const char* name, const char* description, CaseType caseType);
~CommonEdgeCase(void)578 					~CommonEdgeCase			(void) {}
579 
580 	void			init					(void);
581 
582 	IterateResult	iterate					(void);
583 
584 protected:
getDesiredViewportSize(void) const585 	int				getDesiredViewportSize	(void) const { return m_caseType == CASETYPE_SMALL_QUADS ? 128 : 32; }
586 
587 private:
588 	enum
589 	{
590 		DEFAULT_SMALL_QUADS_ITERATIONS					= 16,
591 		DEFAULT_BIGGER_THAN_VIEWPORT_QUAD_ITERATIONS	= 8*8
592 		// \note With CASETYPE_FIT_VIEWPORT_QUAD, we don't do rotations other than multiples of 90 deg -> constant number of iterations.
593 	};
594 
595 	const CaseType	m_caseType;
596 
597 	const int		m_numIterations;
598 	int				m_currentIteration;
599 };
600 
CommonEdgeCase(Context & context,const char * name,const char * description,CaseType caseType)601 CommonEdgeCase::CommonEdgeCase (Context& context, const char* name, const char* description, CaseType caseType)
602 	: MultisampleCase		(context, name, description)
603 	, m_caseType			(caseType)
604 	, m_numIterations		(caseType == CASETYPE_SMALL_QUADS					? getIterationCount(m_testCtx, DEFAULT_SMALL_QUADS_ITERATIONS)
605 							: caseType == CASETYPE_BIGGER_THAN_VIEWPORT_QUAD	? getIterationCount(m_testCtx, DEFAULT_BIGGER_THAN_VIEWPORT_QUAD_ITERATIONS)
606 							: 8)
607 	, m_currentIteration	(0)
608 {
609 }
610 
init(void)611 void CommonEdgeCase::init (void)
612 {
613 	MultisampleCase::init();
614 
615 	if (m_caseType == CASETYPE_SMALL_QUADS)
616 	{
617 		// Check for a big enough viewport. With too small viewports the test case can't analyze the resulting image well enough.
618 
619 		const int minViewportSize = 32;
620 
621 		DE_ASSERT(minViewportSize <= getDesiredViewportSize());
622 
623 		if (m_viewportSize < minViewportSize)
624 			throw tcu::InternalError("Render target width or height too low (is " + de::toString(m_viewportSize) + ", should be at least " + de::toString(minViewportSize) + ")");
625 	}
626 
627 	GLU_CHECK_CALL(glEnable(GL_BLEND));
628 	GLU_CHECK_CALL(glBlendEquation(GL_FUNC_ADD));
629 	GLU_CHECK_CALL(glBlendFunc(GL_ONE, GL_ONE));
630 
631 	m_testCtx.getLog() << TestLog::Message << "Additive blending enabled in order to detect (erroneously) overlapping samples" << TestLog::EndMessage;
632 }
633 
iterate(void)634 CommonEdgeCase::IterateResult CommonEdgeCase::iterate (void)
635 {
636 	TestLog&		log				= m_testCtx.getLog();
637 	tcu::Surface	renderedImg		(m_viewportSize, m_viewportSize);
638 	tcu::Surface	errorImg		(m_viewportSize, m_viewportSize);
639 
640 	randomizeViewport();
641 
642 	GLU_CHECK_CALL(glClearColor(0.0f, 0.0f, 0.0f, 1.0f));
643 	GLU_CHECK_CALL(glClear(GL_COLOR_BUFFER_BIT));
644 
645 	// Draw test pattern. Test patterns consist of quads formed with two triangles.
646 	// After drawing the pattern, we check that the interior pixels of each quad are
647 	// all the same color - this is meant to verify that there are no artifacts on the inner edge.
648 
649 	vector<QuadCorners> unicoloredRegions;
650 
651 	if (m_caseType == CASETYPE_SMALL_QUADS)
652 	{
653 		// Draw several quads, rotated at different angles.
654 
655 		const float		quadDiagLen = 2.0f / 3.0f * 0.9f; // \note Fit 3 quads in both x and y directions.
656 		float			angleCos;
657 		float			angleSin;
658 
659 		// \note First and second iteration get exact 0 (and 90, 180, 270) and 45 (and 135, 225, 315) angle quads, as they are kind of a special case.
660 
661 		if (m_currentIteration == 0)
662 		{
663 			angleCos = 1.0f;
664 			angleSin = 0.0f;
665 		}
666 		else if (m_currentIteration == 1)
667 		{
668 			angleCos = SQRT_HALF;
669 			angleSin = SQRT_HALF;
670 		}
671 		else
672 		{
673 			float angle = 0.5f * DE_PI * (float)(m_currentIteration-1) / (float)(m_numIterations-1);
674 			angleCos = deFloatCos(angle);
675 			angleSin = deFloatSin(angle);
676 		}
677 
678 		Vec2 corners[4] =
679 		{
680 			0.5f * quadDiagLen * Vec2( angleCos,  angleSin),
681 			0.5f * quadDiagLen * Vec2(-angleSin,  angleCos),
682 			0.5f * quadDiagLen * Vec2(-angleCos, -angleSin),
683 			0.5f * quadDiagLen * Vec2( angleSin, -angleCos)
684 		};
685 
686 		unicoloredRegions.reserve(8);
687 
688 		// Draw 8 quads.
689 		// First four are rotated at angles angle+0, angle+90, angle+180 and angle+270.
690 		// Last four are rotated the same angles as the first four, but the ordering of the last triangle's vertices is reversed.
691 
692 		for (int quadNdx = 0; quadNdx < 8; quadNdx++)
693 		{
694 			Vec2 center = (2.0f-quadDiagLen) * Vec2((float)(quadNdx%3), (float)(quadNdx/3)) / 2.0f - 0.5f*(2.0f-quadDiagLen);
695 
696 			renderTriangle(corners[(0+quadNdx) % 4] + center,
697 						   corners[(1+quadNdx) % 4] + center,
698 						   corners[(2+quadNdx) % 4] + center,
699 						   Vec4(0.5f, 0.5f, 0.5f, 1.0f));
700 
701 			if (quadNdx >= 4)
702 			{
703 				renderTriangle(corners[(3+quadNdx) % 4] + center,
704 							   corners[(2+quadNdx) % 4] + center,
705 							   corners[(0+quadNdx) % 4] + center,
706 							   Vec4(0.5f, 0.5f, 0.5f, 1.0f));
707 			}
708 			else
709 			{
710 				renderTriangle(corners[(0+quadNdx) % 4] + center,
711 							   corners[(2+quadNdx) % 4] + center,
712 							   corners[(3+quadNdx) % 4] + center,
713 							   Vec4(0.5f, 0.5f, 0.5f, 1.0f));
714 			}
715 
716 			// The size of the "interior" of a quad is assumed to be approximately unicolorRegionScale*<actual size of quad>.
717 			// By "interior" we here mean the region of non-boundary pixels of the rendered quad for which we can safely assume
718 			// that it has all coverage bits set to 1, for every pixel.
719 			float unicolorRegionScale = 1.0f - 6.0f*2.0f / (float)m_viewportSize / quadDiagLen;
720 			unicoloredRegions.push_back(QuadCorners((center + corners[0]*unicolorRegionScale),
721 													(center + corners[1]*unicolorRegionScale),
722 													(center + corners[2]*unicolorRegionScale),
723 													(center + corners[3]*unicolorRegionScale)));
724 		}
725 	}
726 	else if (m_caseType == CASETYPE_BIGGER_THAN_VIEWPORT_QUAD)
727 	{
728 		// Draw a bigger-than-viewport quad, rotated at an angle depending on m_currentIteration.
729 
730 		int				quadBaseAngleNdx		= m_currentIteration / 8;
731 		int				quadSubAngleNdx			= m_currentIteration % 8;
732 		float			angleCos;
733 		float			angleSin;
734 
735 		if (quadBaseAngleNdx == 0)
736 		{
737 			angleCos = 1.0f;
738 			angleSin = 0.0f;
739 		}
740 		else if (quadBaseAngleNdx == 1)
741 		{
742 			angleCos = SQRT_HALF;
743 			angleSin = SQRT_HALF;
744 		}
745 		else
746 		{
747 			float angle = 0.5f * DE_PI * (float)(m_currentIteration-1) / (float)(m_numIterations-1);
748 			angleCos = deFloatCos(angle);
749 			angleSin = deFloatSin(angle);
750 		}
751 
752 		float quadDiagLen = 2.5f / de::max(angleCos, angleSin);
753 
754 		Vec2 corners[4] =
755 		{
756 			0.5f * quadDiagLen * Vec2( angleCos,  angleSin),
757 			0.5f * quadDiagLen * Vec2(-angleSin,  angleCos),
758 			0.5f * quadDiagLen * Vec2(-angleCos, -angleSin),
759 			0.5f * quadDiagLen * Vec2( angleSin, -angleCos)
760 		};
761 
762 		renderTriangle(corners[(0+quadSubAngleNdx) % 4],
763 					   corners[(1+quadSubAngleNdx) % 4],
764 					   corners[(2+quadSubAngleNdx) % 4],
765 					   Vec4(0.5f, 0.5f, 0.5f, 1.0f));
766 
767 		if (quadSubAngleNdx >= 4)
768 		{
769 			renderTriangle(corners[(3+quadSubAngleNdx) % 4],
770 						   corners[(2+quadSubAngleNdx) % 4],
771 						   corners[(0+quadSubAngleNdx) % 4],
772 						   Vec4(0.5f, 0.5f, 0.5f, 1.0f));
773 		}
774 		else
775 		{
776 			renderTriangle(corners[(0+quadSubAngleNdx) % 4],
777 						   corners[(2+quadSubAngleNdx) % 4],
778 						   corners[(3+quadSubAngleNdx) % 4],
779 						   Vec4(0.5f, 0.5f, 0.5f, 1.0f));
780 		}
781 
782 		float unicolorRegionScale = 1.0f - 6.0f*2.0f / (float)m_viewportSize / quadDiagLen;
783 		unicoloredRegions.push_back(QuadCorners((corners[0]*unicolorRegionScale),
784 												(corners[1]*unicolorRegionScale),
785 												(corners[2]*unicolorRegionScale),
786 												(corners[3]*unicolorRegionScale)));
787 	}
788 	else if (m_caseType == CASETYPE_FIT_VIEWPORT_QUAD)
789 	{
790 		// Draw an exactly viewport-sized quad, rotated by multiples of 90 degrees angle depending on m_currentIteration.
791 
792 		int quadSubAngleNdx = m_currentIteration % 8;
793 
794 		Vec2 corners[4] =
795 		{
796 			Vec2( 1.0f,  1.0f),
797 			Vec2(-1.0f,  1.0f),
798 			Vec2(-1.0f, -1.0f),
799 			Vec2( 1.0f, -1.0f)
800 		};
801 
802 		renderTriangle(corners[(0+quadSubAngleNdx) % 4],
803 					   corners[(1+quadSubAngleNdx) % 4],
804 					   corners[(2+quadSubAngleNdx) % 4],
805 					   Vec4(0.5f, 0.5f, 0.5f, 1.0f));
806 
807 		if (quadSubAngleNdx >= 4)
808 		{
809 			renderTriangle(corners[(3+quadSubAngleNdx) % 4],
810 						   corners[(2+quadSubAngleNdx) % 4],
811 						   corners[(0+quadSubAngleNdx) % 4],
812 						   Vec4(0.5f, 0.5f, 0.5f, 1.0f));
813 		}
814 		else
815 		{
816 			renderTriangle(corners[(0+quadSubAngleNdx) % 4],
817 						   corners[(2+quadSubAngleNdx) % 4],
818 						   corners[(3+quadSubAngleNdx) % 4],
819 						   Vec4(0.5f, 0.5f, 0.5f, 1.0f));
820 		}
821 
822 		unicoloredRegions.push_back(QuadCorners(corners[0], corners[1], corners[2], corners[3]));
823 	}
824 	else
825 		DE_ASSERT(false);
826 
827 	// Read pixels and check unicolored regions.
828 
829 	readImage(renderedImg);
830 
831 	tcu::clear(errorImg.getAccess(), Vec4(0.0f, 1.0f, 0.0f, 1.0f));
832 
833 	log << TestLog::Image("RenderedImage", "Rendered image", renderedImg, QP_IMAGE_COMPRESSION_MODE_PNG);
834 
835 	bool errorsDetected = false;
836 	for (int i = 0; i < (int)unicoloredRegions.size(); i++)
837 	{
838 		const QuadCorners&	region					= unicoloredRegions[i];
839 		IVec2				p0Win					= ((region.p0+1.0f) * 0.5f * (float)(m_viewportSize-1) + 0.5f).asInt();
840 		IVec2				p1Win					= ((region.p1+1.0f) * 0.5f * (float)(m_viewportSize-1) + 0.5f).asInt();
841 		IVec2				p2Win					= ((region.p2+1.0f) * 0.5f * (float)(m_viewportSize-1) + 0.5f).asInt();
842 		IVec2				p3Win					= ((region.p3+1.0f) * 0.5f * (float)(m_viewportSize-1) + 0.5f).asInt();
843 		bool				errorsInCurrentRegion	= !isPixelRegionUnicolored(renderedImg, p0Win, p1Win, p2Win, p3Win);
844 
845 		if (errorsInCurrentRegion)
846 			drawUnicolorTestErrors(renderedImg, errorImg.getAccess(), p0Win, p1Win, p2Win, p3Win);
847 
848 		errorsDetected = errorsDetected || errorsInCurrentRegion;
849 	}
850 
851 	m_currentIteration++;
852 
853 	if (errorsDetected)
854 	{
855 		log << TestLog::Message << "Failure: Not all quad interiors seem unicolored - common-edge artifacts?" << TestLog::EndMessage;
856 		log << TestLog::Message << "Erroneous pixels are drawn red in the following image" << TestLog::EndMessage;
857 		log << TestLog::Image("RenderedImageWithErrors",	"Rendered image with errors marked",	renderedImg,	QP_IMAGE_COMPRESSION_MODE_PNG);
858 		log << TestLog::Image("ErrorsOnly",					"Image with error pixels only",			errorImg,		QP_IMAGE_COMPRESSION_MODE_PNG);
859 		m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Failed");
860 		return STOP;
861 	}
862 	else if (m_currentIteration < m_numIterations)
863 	{
864 		log << TestLog::Message << "Quads seem OK - moving on to next pattern" << TestLog::EndMessage;
865 		return CONTINUE;
866 	}
867 	else
868 	{
869 		log << TestLog::Message << "Success: All quad interiors seem unicolored (no common-edge artifacts)" << TestLog::EndMessage;
870 		m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Passed");
871 		return STOP;
872 	}
873 }
874 
875 /*--------------------------------------------------------------------*//*!
876  * \brief Test that depth values are per-sample.
877  *
878  * Draws intersecting, differently-colored polygons and checks that there
879  * are at least GL_SAMPLES+1 distinct colors present, due to some of the
880  * samples at the intersection line belonging to one and some to another
881  * polygon.
882  *//*--------------------------------------------------------------------*/
883 class SampleDepthCase : public NumSamplesCase
884 {
885 public:
886 						SampleDepthCase			(Context& context, const char* name, const char* description);
~SampleDepthCase(void)887 						~SampleDepthCase		(void) {}
888 
889 	void				init					(void);
890 
891 protected:
892 	void				renderPattern			(void) const;
893 };
894 
SampleDepthCase(Context & context,const char * name,const char * description)895 SampleDepthCase::SampleDepthCase (Context& context, const char* name, const char* description)
896 	: NumSamplesCase (context, name, description)
897 {
898 }
899 
init(void)900 void SampleDepthCase::init (void)
901 {
902 	TestLog& log = m_testCtx.getLog();
903 
904 	if (m_context.getRenderTarget().getDepthBits() == 0)
905 		TCU_THROW(NotSupportedError, "Test requires depth buffer");
906 
907 	MultisampleCase::init();
908 
909 	GLU_CHECK_CALL(glEnable(GL_DEPTH_TEST));
910 	GLU_CHECK_CALL(glDepthFunc(GL_LESS));
911 
912 	log << TestLog::Message << "Depth test enabled, depth func is GL_LESS" << TestLog::EndMessage;
913 	log << TestLog::Message << "Drawing several bigger-than-viewport black or white polygons intersecting each other" << TestLog::EndMessage;
914 }
915 
renderPattern(void) const916 void SampleDepthCase::renderPattern (void) const
917 {
918 	GLU_CHECK_CALL(glClearColor(0.0f, 0.0f, 0.0f, 0.0f));
919 	GLU_CHECK_CALL(glClearDepthf(1.0f));
920 	GLU_CHECK_CALL(glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT));
921 
922 	{
923 		const int numPolygons = 50;
924 
925 		for (int i = 0; i < numPolygons; i++)
926 		{
927 			Vec4	color	= i % 2 == 0 ? Vec4(1.0f, 1.0f, 1.0f, 1.0f) : Vec4(0.0f, 0.0f, 0.0f, 1.0f);
928 			float	angle	= 2.0f * DE_PI * (float)i / (float)numPolygons + 0.001f*(float)m_currentIteration;
929 			Vec3	pt0		(3.0f*deFloatCos(angle + 2.0f*DE_PI*0.0f/3.0f), 3.0f*deFloatSin(angle + 2.0f*DE_PI*0.0f/3.0f), 1.0f);
930 			Vec3	pt1		(3.0f*deFloatCos(angle + 2.0f*DE_PI*1.0f/3.0f), 3.0f*deFloatSin(angle + 2.0f*DE_PI*1.0f/3.0f), 0.0f);
931 			Vec3	pt2		(3.0f*deFloatCos(angle + 2.0f*DE_PI*2.0f/3.0f), 3.0f*deFloatSin(angle + 2.0f*DE_PI*2.0f/3.0f), 0.0f);
932 
933 			renderTriangle(pt0, pt1, pt2, color);
934 		}
935 	}
936 }
937 
938 /*--------------------------------------------------------------------*//*!
939  * \brief Test that stencil buffer values are per-sample.
940  *
941  * Draws a unicolored pattern and marks drawn samples in stencil buffer;
942  * then clears and draws a viewport-size quad with that color and with
943  * proper stencil test such that the resulting image should be exactly the
944  * same as after the pattern was first drawn.
945  *//*--------------------------------------------------------------------*/
946 class SampleStencilCase : public MultisampleCase
947 {
948 public:
949 						SampleStencilCase		(Context& context, const char* name, const char* description);
~SampleStencilCase(void)950 						~SampleStencilCase		(void) {}
951 
952 	void				init					(void);
953 	IterateResult		iterate					(void);
954 
955 protected:
getDesiredViewportSize(void) const956 	int					getDesiredViewportSize	(void) const { return 256; }
957 };
958 
SampleStencilCase(Context & context,const char * name,const char * description)959 SampleStencilCase::SampleStencilCase (Context& context, const char* name, const char* description)
960 	: MultisampleCase (context, name, description)
961 {
962 }
963 
init(void)964 void SampleStencilCase::init (void)
965 {
966 	if (m_context.getRenderTarget().getStencilBits() == 0)
967 		TCU_THROW(NotSupportedError, "Test requires stencil buffer");
968 
969 	MultisampleCase::init();
970 }
971 
iterate(void)972 SampleStencilCase::IterateResult SampleStencilCase::iterate (void)
973 {
974 	TestLog&		log					= m_testCtx.getLog();
975 	tcu::Surface	renderedImgFirst	(m_viewportSize, m_viewportSize);
976 	tcu::Surface	renderedImgSecond	(m_viewportSize, m_viewportSize);
977 
978 	randomizeViewport();
979 
980 	GLU_CHECK_CALL(glClearColor(0.0f, 0.0f, 0.0f, 1.0f));
981 	GLU_CHECK_CALL(glClearStencil(0));
982 	GLU_CHECK_CALL(glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT));
983 	GLU_CHECK_CALL(glEnable(GL_STENCIL_TEST));
984 	GLU_CHECK_CALL(glStencilFunc(GL_ALWAYS, 1, 1));
985 	GLU_CHECK_CALL(glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE));
986 
987 	log << TestLog::Message << "Drawing a pattern with glStencilFunc(GL_ALWAYS, 1, 1) and glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE)" << TestLog::EndMessage;
988 
989 	{
990 		const int numTriangles = 25;
991 		for (int i = 0; i < numTriangles; i++)
992 		{
993 			float angle0 = 2.0f*DE_PI * (float)i			/ (float)numTriangles;
994 			float angle1 = 2.0f*DE_PI * ((float)i + 0.5f)	/ (float)numTriangles;
995 
996 			renderTriangle(Vec2(0.0f, 0.0f),
997 						   Vec2(deFloatCos(angle0)*0.95f, deFloatSin(angle0)*0.95f),
998 						   Vec2(deFloatCos(angle1)*0.95f, deFloatSin(angle1)*0.95f),
999 						   Vec4(1.0f));
1000 		}
1001 	}
1002 
1003 	readImage(renderedImgFirst);
1004 	log << TestLog::Image("RenderedImgFirst", "First image rendered", renderedImgFirst, QP_IMAGE_COMPRESSION_MODE_PNG);
1005 
1006 	log << TestLog::Message << "Clearing color buffer to black" << TestLog::EndMessage;
1007 
1008 	GLU_CHECK_CALL(glClear(GL_COLOR_BUFFER_BIT));
1009 	GLU_CHECK_CALL(glStencilFunc(GL_EQUAL, 1, 1));
1010 	GLU_CHECK_CALL(glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP));
1011 
1012 	{
1013 		log << TestLog::Message << "Checking that color buffer was actually cleared to black" << TestLog::EndMessage;
1014 
1015 		tcu::Surface clearedImg(m_viewportSize, m_viewportSize);
1016 		readImage(clearedImg);
1017 
1018 		for (int y = 0; y < clearedImg.getHeight(); y++)
1019 		for (int x = 0; x < clearedImg.getWidth(); x++)
1020 		{
1021 			const tcu::RGBA& clr = clearedImg.getPixel(x, y);
1022 			if (clr != tcu::RGBA::black())
1023 			{
1024 				log << TestLog::Message << "Failure: first non-black pixel, color " << clr << ", detected at coordinates (" << x << ", " << y << ")" << TestLog::EndMessage;
1025 				log << TestLog::Image("ClearedImg", "Image after clearing, erroneously non-black", clearedImg);
1026 				m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Failed");
1027 				return STOP;
1028 			}
1029 		}
1030 	}
1031 
1032 	log << TestLog::Message << "Drawing a viewport-sized quad with glStencilFunc(GL_EQUAL, 1, 1) and glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP) - should result in same image as the first" << TestLog::EndMessage;
1033 
1034 	renderQuad(Vec2(-1.0f, -1.0f),
1035 			   Vec2( 1.0f, -1.0f),
1036 			   Vec2(-1.0f,  1.0f),
1037 			   Vec2( 1.0f,  1.0f),
1038 			   Vec4(1.0f));
1039 
1040 	readImage(renderedImgSecond);
1041 	log << TestLog::Image("RenderedImgSecond", "Second image rendered", renderedImgSecond, QP_IMAGE_COMPRESSION_MODE_PNG);
1042 
1043 	bool passed = tcu::pixelThresholdCompare(log,
1044 											 "ImageCompare",
1045 											 "Image comparison",
1046 											 renderedImgFirst,
1047 											 renderedImgSecond,
1048 											 tcu::RGBA(0),
1049 											 tcu::COMPARE_LOG_ON_ERROR);
1050 
1051 	if (passed)
1052 		log << TestLog::Message << "Success: The two images rendered are identical" << TestLog::EndMessage;
1053 
1054 	m_context.getTestContext().setTestResult(passed ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
1055 											 passed ? "Passed"				: "Failed");
1056 
1057 	return STOP;
1058 }
1059 
1060 /*--------------------------------------------------------------------*//*!
1061  * \brief Tests coverage mask generation proportionality property.
1062  *
1063  * Tests that the number of coverage bits in a coverage mask created by
1064  * GL_SAMPLE_ALPHA_TO_COVERAGE or GL_SAMPLE_COVERAGE is, on average,
1065  * proportional to the alpha or coverage value, respectively. Draws
1066  * multiple frames, each time increasing the alpha or coverage value used,
1067  * and checks that the average color is changing appropriately.
1068  *//*--------------------------------------------------------------------*/
1069 class MaskProportionalityCase : public MultisampleCase
1070 {
1071 public:
1072 	enum CaseType
1073 	{
1074 		CASETYPE_ALPHA_TO_COVERAGE = 0,
1075 		CASETYPE_SAMPLE_COVERAGE,
1076 		CASETYPE_SAMPLE_COVERAGE_INVERTED,
1077 
1078 		CASETYPE_LAST
1079 	};
1080 
1081 					MaskProportionalityCase				(Context& context, const char* name, const char* description, CaseType type);
~MaskProportionalityCase(void)1082 					~MaskProportionalityCase			(void) {}
1083 
1084 	void			init								(void);
1085 
1086 	IterateResult	iterate								(void);
1087 
1088 protected:
getDesiredViewportSize(void) const1089 	int				getDesiredViewportSize				(void) const { return 32; }
1090 
1091 private:
1092 	const CaseType	m_type;
1093 
1094 	int				m_numIterations;
1095 	int				m_currentIteration;
1096 
1097 	deInt32			m_previousIterationColorSum;
1098 };
1099 
MaskProportionalityCase(Context & context,const char * name,const char * description,CaseType type)1100 MaskProportionalityCase::MaskProportionalityCase (Context& context, const char* name, const char* description, CaseType type)
1101 	: MultisampleCase				(context, name, description)
1102 	, m_type						(type)
1103 	, m_currentIteration			(0)
1104 	, m_previousIterationColorSum	(-1)
1105 {
1106 }
1107 
init(void)1108 void MaskProportionalityCase::init (void)
1109 {
1110 	TestLog& log = m_testCtx.getLog();
1111 
1112 	MultisampleCase::init();
1113 
1114 	if (m_type == CASETYPE_ALPHA_TO_COVERAGE)
1115 	{
1116 		GLU_CHECK_CALL(glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE));
1117 		log << TestLog::Message << "GL_SAMPLE_ALPHA_TO_COVERAGE is enabled" << TestLog::EndMessage;
1118 	}
1119 	else
1120 	{
1121 		DE_ASSERT(m_type == CASETYPE_SAMPLE_COVERAGE || m_type == CASETYPE_SAMPLE_COVERAGE_INVERTED);
1122 
1123 		GLU_CHECK_CALL(glEnable(GL_SAMPLE_COVERAGE));
1124 		log << TestLog::Message << "GL_SAMPLE_COVERAGE is enabled" << TestLog::EndMessage;
1125 	}
1126 
1127 	m_numIterations = de::max(2, getIterationCount(m_testCtx, m_numSamples * 5));
1128 
1129 	randomizeViewport(); // \note Using the same viewport for every iteration since coverage mask may depend on window-relative pixel coordinate.
1130 }
1131 
iterate(void)1132 MaskProportionalityCase::IterateResult MaskProportionalityCase::iterate (void)
1133 {
1134 	TestLog&		log				= m_testCtx.getLog();
1135 	tcu::Surface	renderedImg		(m_viewportSize, m_viewportSize);
1136 	deInt32			numPixels		= (deInt32)renderedImg.getWidth()*(deInt32)renderedImg.getHeight();
1137 
1138 	log << TestLog::Message << "Clearing color to black" << TestLog::EndMessage;
1139 	GLU_CHECK_CALL(glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
1140 	GLU_CHECK_CALL(glClearColor(0.0f, 0.0f, 0.0f, 1.0f));
1141 	GLU_CHECK_CALL(glClear(GL_COLOR_BUFFER_BIT));
1142 
1143 	if (m_type == CASETYPE_ALPHA_TO_COVERAGE)
1144 	{
1145 		GLU_CHECK_CALL(glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE));
1146 		log << TestLog::Message << "Using color mask TRUE, TRUE, TRUE, FALSE" << TestLog::EndMessage;
1147 	}
1148 
1149 	// Draw quad.
1150 
1151 	{
1152 		const Vec2		pt0						(-1.0f, -1.0f);
1153 		const Vec2		pt1						( 1.0f, -1.0f);
1154 		const Vec2		pt2						(-1.0f,  1.0f);
1155 		const Vec2		pt3						( 1.0f,  1.0f);
1156 		Vec4			quadColor				(1.0f, 0.0f, 0.0f, 1.0f);
1157 		float			alphaOrCoverageValue	= (float)m_currentIteration / (float)(m_numIterations-1);
1158 
1159 		if (m_type == CASETYPE_ALPHA_TO_COVERAGE)
1160 		{
1161 			log << TestLog::Message << "Drawing a red quad using alpha value " + de::floatToString(alphaOrCoverageValue, 2) << TestLog::EndMessage;
1162 			quadColor.w() = alphaOrCoverageValue;
1163 		}
1164 		else
1165 		{
1166 			DE_ASSERT(m_type == CASETYPE_SAMPLE_COVERAGE || m_type == CASETYPE_SAMPLE_COVERAGE_INVERTED);
1167 
1168 			bool	isInverted		= m_type == CASETYPE_SAMPLE_COVERAGE_INVERTED;
1169 			float	coverageValue	= isInverted ? 1.0f - alphaOrCoverageValue : alphaOrCoverageValue;
1170 			log << TestLog::Message << "Drawing a red quad using sample coverage value " + de::floatToString(coverageValue, 2) << (isInverted ? " (inverted)" : "") << TestLog::EndMessage;
1171 			GLU_CHECK_CALL(glSampleCoverage(coverageValue, isInverted ? GL_TRUE : GL_FALSE));
1172 		}
1173 
1174 		renderQuad(pt0, pt1, pt2, pt3, quadColor);
1175 	}
1176 
1177 	// Read ang log image.
1178 
1179 	readImage(renderedImg);
1180 
1181 	log << TestLog::Image("RenderedImage", "Rendered image", renderedImg, QP_IMAGE_COMPRESSION_MODE_PNG);
1182 
1183 	// Compute average red component in rendered image.
1184 
1185 	deInt32 sumRed = 0;
1186 
1187 	for (int y = 0; y < renderedImg.getHeight(); y++)
1188 	for (int x = 0; x < renderedImg.getWidth(); x++)
1189 		sumRed += renderedImg.getPixel(x, y).getRed();
1190 
1191 	log << TestLog::Message << "Average red color component: " << de::floatToString((float)sumRed / 255.0f / (float)numPixels, 2) << TestLog::EndMessage;
1192 
1193 	// Check if average color has decreased from previous frame's color.
1194 
1195 	if (sumRed < m_previousIterationColorSum)
1196 	{
1197 		log << TestLog::Message << "Failure: Current average red color component is lower than previous" << TestLog::EndMessage;
1198 		m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Failed");
1199 		return STOP;
1200 	}
1201 
1202 	// Check if coverage mask is not all-zeros if alpha or coverage value is 0 (or 1, if inverted).
1203 
1204 	if (m_currentIteration == 0 && sumRed != 0)
1205 	{
1206 		log << TestLog::Message << "Failure: Image should be completely black" << TestLog::EndMessage;
1207 		m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Failed");
1208 		return STOP;
1209 	}
1210 
1211 	if (m_currentIteration == m_numIterations-1 && sumRed != 0xff*numPixels)
1212 	{
1213 		log << TestLog::Message << "Failure: Image should be completely red" << TestLog::EndMessage;
1214 
1215 		m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Failed");
1216 		return STOP;
1217 	}
1218 
1219 	m_previousIterationColorSum = sumRed;
1220 
1221 	m_currentIteration++;
1222 
1223 	if (m_currentIteration >= m_numIterations)
1224 	{
1225 		log << TestLog::Message
1226 			<< "Success: Number of coverage mask bits set appears to be, on average, proportional to "
1227 			<< (m_type == CASETYPE_ALPHA_TO_COVERAGE ? "alpha" : m_type == CASETYPE_SAMPLE_COVERAGE ? "sample coverage value" : "inverted sample coverage value")
1228 			<< TestLog::EndMessage;
1229 
1230 		m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Passed");
1231 		return STOP;
1232 	}
1233 	else
1234 		return CONTINUE;
1235 }
1236 
1237 /*--------------------------------------------------------------------*//*!
1238  * \brief Tests coverage mask generation constancy property.
1239  *
1240  * Tests that the coverage mask created by GL_SAMPLE_ALPHA_TO_COVERAGE or
1241  * GL_SAMPLE_COVERAGE is constant at given pixel coordinates, with a given
1242  * alpha component or coverage value, respectively. Draws two quads, with
1243  * the second one fully overlapping the first one such that at any given
1244  * pixel, both quads have the same alpha or coverage value. This way, if
1245  * the constancy property is fulfilled, only the second quad should be
1246  * visible.
1247  *//*--------------------------------------------------------------------*/
1248 class MaskConstancyCase : public MultisampleCase
1249 {
1250 public:
1251 	enum CaseType
1252 	{
1253 		CASETYPE_ALPHA_TO_COVERAGE = 0,		//!< Use only alpha-to-coverage.
1254 		CASETYPE_SAMPLE_COVERAGE,			//!< Use only sample coverage.
1255 		CASETYPE_SAMPLE_COVERAGE_INVERTED,	//!< Use only inverted sample coverage.
1256 		CASETYPE_BOTH,						//!< Use both alpha-to-coverage and sample coverage.
1257 		CASETYPE_BOTH_INVERTED,				//!< Use both alpha-to-coverage and inverted sample coverage.
1258 
1259 		CASETYPE_LAST
1260 	};
1261 
1262 					MaskConstancyCase			(Context& context, const char* name, const char* description, CaseType type);
~MaskConstancyCase(void)1263 					~MaskConstancyCase			(void) {}
1264 
1265 	IterateResult	iterate						(void);
1266 
1267 protected:
getDesiredViewportSize(void) const1268 	int				getDesiredViewportSize		(void) const { return 256; }
1269 
1270 private:
1271 	const bool		m_isAlphaToCoverageCase;
1272 	const bool		m_isSampleCoverageCase;
1273 	const bool		m_isInvertedSampleCoverageCase;
1274 };
1275 
MaskConstancyCase(Context & context,const char * name,const char * description,CaseType type)1276 MaskConstancyCase::MaskConstancyCase (Context& context, const char* name, const char* description, CaseType type)
1277 	: MultisampleCase					(context, name, description)
1278 	, m_isAlphaToCoverageCase			(type == CASETYPE_ALPHA_TO_COVERAGE			|| type == CASETYPE_BOTH						|| type == CASETYPE_BOTH_INVERTED)
1279 	, m_isSampleCoverageCase			(type == CASETYPE_SAMPLE_COVERAGE			|| type == CASETYPE_SAMPLE_COVERAGE_INVERTED	|| type == CASETYPE_BOTH			|| type == CASETYPE_BOTH_INVERTED)
1280 	, m_isInvertedSampleCoverageCase	(type == CASETYPE_SAMPLE_COVERAGE_INVERTED	|| type == CASETYPE_BOTH_INVERTED)
1281 {
1282 }
1283 
iterate(void)1284 MaskConstancyCase::IterateResult MaskConstancyCase::iterate (void)
1285 {
1286 	TestLog&		log				= m_testCtx.getLog();
1287 	tcu::Surface	renderedImg		(m_viewportSize, m_viewportSize);
1288 
1289 	randomizeViewport();
1290 
1291 	log << TestLog::Message << "Clearing color to black" << TestLog::EndMessage;
1292 	GLU_CHECK_CALL(glClearColor(0.0f, 0.0f, 0.0f, 1.0f));
1293 	GLU_CHECK_CALL(glClear(GL_COLOR_BUFFER_BIT));
1294 
1295 	if (m_isAlphaToCoverageCase)
1296 	{
1297 		GLU_CHECK_CALL(glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE));
1298 		GLU_CHECK_CALL(glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE));
1299 		log << TestLog::Message << "GL_SAMPLE_ALPHA_TO_COVERAGE is enabled" << TestLog::EndMessage;
1300 		log << TestLog::Message << "Color mask is TRUE, TRUE, TRUE, FALSE" << TestLog::EndMessage;
1301 	}
1302 
1303 	if (m_isSampleCoverageCase)
1304 	{
1305 		GLU_CHECK_CALL(glEnable(GL_SAMPLE_COVERAGE));
1306 		log << TestLog::Message << "GL_SAMPLE_COVERAGE is enabled" << TestLog::EndMessage;
1307 	}
1308 
1309 	log << TestLog::Message
1310 		<< "Drawing several green quads, each fully overlapped by a red quad with the same "
1311 		<< (m_isAlphaToCoverageCase ? "alpha" : "")
1312 		<< (m_isAlphaToCoverageCase && m_isSampleCoverageCase ? " and " : "")
1313 		<< (m_isInvertedSampleCoverageCase ? "inverted " : "")
1314 		<< (m_isSampleCoverageCase ? "sample coverage" : "")
1315 		<< " values"
1316 		<< TestLog::EndMessage;
1317 
1318 	const int numQuadRowsCols = m_numSamples*4;
1319 
1320 	for (int row = 0; row < numQuadRowsCols; row++)
1321 	{
1322 		for (int col = 0; col < numQuadRowsCols; col++)
1323 		{
1324 			float		x0			= (float)(col+0) / (float)numQuadRowsCols * 2.0f - 1.0f;
1325 			float		x1			= (float)(col+1) / (float)numQuadRowsCols * 2.0f - 1.0f;
1326 			float		y0			= (float)(row+0) / (float)numQuadRowsCols * 2.0f - 1.0f;
1327 			float		y1			= (float)(row+1) / (float)numQuadRowsCols * 2.0f - 1.0f;
1328 			const Vec4	baseGreen	(0.0f, 1.0f, 0.0f, 0.0f);
1329 			const Vec4	baseRed		(1.0f, 0.0f, 0.0f, 0.0f);
1330 			Vec4		alpha0		(0.0f, 0.0f, 0.0f, m_isAlphaToCoverageCase ? (float)col / (float)(numQuadRowsCols-1) : 1.0f);
1331 			Vec4		alpha1		(0.0f, 0.0f, 0.0f, m_isAlphaToCoverageCase ? (float)row / (float)(numQuadRowsCols-1) : 1.0f);
1332 
1333 			if (m_isSampleCoverageCase)
1334 			{
1335 				float value = (float)(row*numQuadRowsCols + col) / (float)(numQuadRowsCols*numQuadRowsCols-1);
1336 				GLU_CHECK_CALL(glSampleCoverage(m_isInvertedSampleCoverageCase ? 1.0f - value : value, m_isInvertedSampleCoverageCase ? GL_TRUE : GL_FALSE));
1337 			}
1338 
1339 			renderQuad(Vec2(x0, y0), Vec2(x1, y0), Vec2(x0, y1), Vec2(x1, y1), baseGreen + alpha0,	baseGreen + alpha1,	baseGreen + alpha0,	baseGreen + alpha1);
1340 			renderQuad(Vec2(x0, y0), Vec2(x1, y0), Vec2(x0, y1), Vec2(x1, y1), baseRed + alpha0,	baseRed + alpha1,	baseRed + alpha0,	baseRed + alpha1);
1341 		}
1342 	}
1343 
1344 	readImage(renderedImg);
1345 
1346 	log << TestLog::Image("RenderedImage", "Rendered image", renderedImg, QP_IMAGE_COMPRESSION_MODE_PNG);
1347 
1348 	for (int y = 0; y < renderedImg.getHeight(); y++)
1349 	for (int x = 0; x < renderedImg.getWidth(); x++)
1350 	{
1351 		if (renderedImg.getPixel(x, y).getGreen() > 0)
1352 		{
1353 			log << TestLog::Message << "Failure: Non-zero green color component detected - should have been completely overwritten by red quad" << TestLog::EndMessage;
1354 			m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Failed");
1355 			return STOP;
1356 		}
1357 	}
1358 
1359 	log << TestLog::Message
1360 		<< "Success: Coverage mask appears to be constant at a given pixel coordinate with a given "
1361 		<< (m_isAlphaToCoverageCase ? "alpha" : "")
1362 		<< (m_isAlphaToCoverageCase && m_isSampleCoverageCase ? " and " : "")
1363 		<< (m_isSampleCoverageCase ? "coverage value" : "")
1364 		<< TestLog::EndMessage;
1365 
1366 	m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Passed");
1367 
1368 	return STOP;
1369 }
1370 
1371 /*--------------------------------------------------------------------*//*!
1372  * \brief Tests coverage mask inversion validity.
1373  *
1374  * Tests that the coverage masks obtained by glSampleCoverage(..., GL_TRUE)
1375  * and glSampleCoverage(..., GL_FALSE) are indeed each others' inverses.
1376  * This is done by drawing a pattern, with varying coverage values,
1377  * overlapped by a pattern that has inverted masks and is otherwise
1378  * identical. The resulting image is compared to one obtained by drawing
1379  * the same pattern but with all-ones coverage masks.
1380  *//*--------------------------------------------------------------------*/
1381 class CoverageMaskInvertCase : public MultisampleCase
1382 {
1383 public:
1384 					CoverageMaskInvertCase		(Context& context, const char* name, const char* description);
~CoverageMaskInvertCase(void)1385 					~CoverageMaskInvertCase		(void) {}
1386 
1387 	IterateResult	iterate						(void);
1388 
1389 protected:
getDesiredViewportSize(void) const1390 	int				getDesiredViewportSize		(void) const { return 256; }
1391 
1392 private:
1393 	void			drawPattern					(bool invertSampleCoverage) const;
1394 };
1395 
CoverageMaskInvertCase(Context & context,const char * name,const char * description)1396 CoverageMaskInvertCase::CoverageMaskInvertCase (Context& context, const char* name, const char* description)
1397 	: MultisampleCase (context, name, description)
1398 {
1399 }
1400 
drawPattern(bool invertSampleCoverage) const1401 void CoverageMaskInvertCase::drawPattern (bool invertSampleCoverage) const
1402 {
1403 	const int numTriangles = 25;
1404 	for (int i = 0; i < numTriangles; i++)
1405 	{
1406 		GLU_CHECK_CALL(glSampleCoverage((float)i / (float)(numTriangles-1), invertSampleCoverage ? GL_TRUE : GL_FALSE));
1407 
1408 		float angle0 = 2.0f*DE_PI * (float)i			/ (float)numTriangles;
1409 		float angle1 = 2.0f*DE_PI * ((float)i + 0.5f)	/ (float)numTriangles;
1410 
1411 		renderTriangle(Vec2(0.0f, 0.0f),
1412 					   Vec2(deFloatCos(angle0)*0.95f, deFloatSin(angle0)*0.95f),
1413 					   Vec2(deFloatCos(angle1)*0.95f, deFloatSin(angle1)*0.95f),
1414 					   Vec4(0.4f + (float)i/(float)numTriangles*0.6f,
1415 							0.5f + (float)i/(float)numTriangles*0.3f,
1416 							0.6f - (float)i/(float)numTriangles*0.5f,
1417 							0.7f - (float)i/(float)numTriangles*0.7f));
1418 	}
1419 }
1420 
iterate(void)1421 CoverageMaskInvertCase::IterateResult CoverageMaskInvertCase::iterate (void)
1422 {
1423 	TestLog&		log								= m_testCtx.getLog();
1424 	tcu::Surface	renderedImgNoSampleCoverage		(m_viewportSize, m_viewportSize);
1425 	tcu::Surface	renderedImgSampleCoverage		(m_viewportSize, m_viewportSize);
1426 
1427 	randomizeViewport();
1428 
1429 	GLU_CHECK_CALL(glEnable(GL_BLEND));
1430 	GLU_CHECK_CALL(glBlendEquation(GL_FUNC_ADD));
1431 	GLU_CHECK_CALL(glBlendFunc(GL_ONE, GL_ONE));
1432 	log << TestLog::Message << "Additive blending enabled in order to detect (erroneously) overlapping samples" << TestLog::EndMessage;
1433 
1434 	log << TestLog::Message << "Clearing color to all-zeros" << TestLog::EndMessage;
1435 	GLU_CHECK_CALL(glClearColor(0.0f, 0.0f, 0.0f, 0.0f));
1436 	GLU_CHECK_CALL(glClear(GL_COLOR_BUFFER_BIT));
1437 	log << TestLog::Message << "Drawing the pattern with GL_SAMPLE_COVERAGE disabled" << TestLog::EndMessage;
1438 	drawPattern(false);
1439 	readImage(renderedImgNoSampleCoverage);
1440 
1441 	log << TestLog::Image("RenderedImageNoSampleCoverage", "Rendered image with GL_SAMPLE_COVERAGE disabled", renderedImgNoSampleCoverage, QP_IMAGE_COMPRESSION_MODE_PNG);
1442 
1443 	log << TestLog::Message << "Clearing color to all-zeros" << TestLog::EndMessage;
1444 	GLU_CHECK_CALL(glClear(GL_COLOR_BUFFER_BIT));
1445 	GLU_CHECK_CALL(glEnable(GL_SAMPLE_COVERAGE));
1446 	log << TestLog::Message << "Drawing the pattern with GL_SAMPLE_COVERAGE enabled, using non-inverted masks" << TestLog::EndMessage;
1447 	drawPattern(false);
1448 	log << TestLog::Message << "Drawing the pattern with GL_SAMPLE_COVERAGE enabled, using same sample coverage values but inverted masks" << TestLog::EndMessage;
1449 	drawPattern(true);
1450 	readImage(renderedImgSampleCoverage);
1451 
1452 	log << TestLog::Image("RenderedImageSampleCoverage", "Rendered image with GL_SAMPLE_COVERAGE enabled", renderedImgSampleCoverage, QP_IMAGE_COMPRESSION_MODE_PNG);
1453 
1454 	bool passed = tcu::pixelThresholdCompare(log,
1455 											 "CoverageVsNoCoverage",
1456 											 "Comparison of same pattern with GL_SAMPLE_COVERAGE disabled and enabled",
1457 											 renderedImgNoSampleCoverage,
1458 											 renderedImgSampleCoverage,
1459 											 tcu::RGBA(0),
1460 											 tcu::COMPARE_LOG_ON_ERROR);
1461 
1462 	if (passed)
1463 		log << TestLog::Message << "Success: The two images rendered are identical" << TestLog::EndMessage;
1464 
1465 	m_context.getTestContext().setTestResult(passed ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
1466 											 passed ? "Passed"				: "Failed");
1467 
1468 	return STOP;
1469 }
1470 
MultisampleTests(Context & context)1471 MultisampleTests::MultisampleTests (Context& context)
1472 	: TestCaseGroup(context, "multisample", "Multisampling tests")
1473 {
1474 }
1475 
~MultisampleTests(void)1476 MultisampleTests::~MultisampleTests (void)
1477 {
1478 }
1479 
init(void)1480 void MultisampleTests::init (void)
1481 {
1482 	addChild(new PolygonNumSamplesCase		(m_context, "num_samples_polygon",			"Test sanity of the value of GL_SAMPLES, with polygons"));
1483 	addChild(new LineNumSamplesCase			(m_context, "num_samples_line",				"Test sanity of the value of GL_SAMPLES, with lines"));
1484 	addChild(new CommonEdgeCase				(m_context, "common_edge_small_quads",		"Test polygons' common edges with small quads",						CommonEdgeCase::CASETYPE_SMALL_QUADS));
1485 	addChild(new CommonEdgeCase				(m_context, "common_edge_big_quad",			"Test polygons' common edges with bigger-than-viewport quads",		CommonEdgeCase::CASETYPE_BIGGER_THAN_VIEWPORT_QUAD));
1486 	addChild(new CommonEdgeCase				(m_context, "common_edge_viewport_quad",	"Test polygons' common edges with exactly viewport-sized quads",	CommonEdgeCase::CASETYPE_FIT_VIEWPORT_QUAD));
1487 	addChild(new SampleDepthCase			(m_context, "depth",						"Test that depth values are per-sample"));
1488 	addChild(new SampleStencilCase			(m_context, "stencil",						"Test that stencil values are per-sample"));
1489 	addChild(new CoverageMaskInvertCase		(m_context, "sample_coverage_invert",		"Test that non-inverted and inverted sample coverage masks are each other's negations"));
1490 
1491 	addChild(new MaskProportionalityCase(m_context, "proportionality_alpha_to_coverage",			"Test the proportionality property of GL_SAMPLE_ALPHA_TO_COVERAGE",			MaskProportionalityCase::CASETYPE_ALPHA_TO_COVERAGE));
1492 	addChild(new MaskProportionalityCase(m_context, "proportionality_sample_coverage",				"Test the proportionality property of GL_SAMPLE_COVERAGE",					MaskProportionalityCase::CASETYPE_SAMPLE_COVERAGE));
1493 	addChild(new MaskProportionalityCase(m_context, "proportionality_sample_coverage_inverted",		"Test the proportionality property of inverted-mask GL_SAMPLE_COVERAGE",	MaskProportionalityCase::CASETYPE_SAMPLE_COVERAGE_INVERTED));
1494 
1495 	addChild(new MaskConstancyCase(m_context, "constancy_alpha_to_coverage",			"Test that coverage mask is constant at given coordinates with a given alpha or coverage value, using GL_SAMPLE_ALPHA_TO_COVERAGE",											MaskConstancyCase::CASETYPE_ALPHA_TO_COVERAGE));
1496 	addChild(new MaskConstancyCase(m_context, "constancy_sample_coverage",				"Test that coverage mask is constant at given coordinates with a given alpha or coverage value, using GL_SAMPLE_COVERAGE",													MaskConstancyCase::CASETYPE_SAMPLE_COVERAGE));
1497 	addChild(new MaskConstancyCase(m_context, "constancy_sample_coverage_inverted",		"Test that coverage mask is constant at given coordinates with a given alpha or coverage value, using inverted-mask GL_SAMPLE_COVERAGE",									MaskConstancyCase::CASETYPE_SAMPLE_COVERAGE_INVERTED));
1498 	addChild(new MaskConstancyCase(m_context, "constancy_both",							"Test that coverage mask is constant at given coordinates with a given alpha or coverage value, using GL_SAMPLE_ALPHA_TO_COVERAGE and GL_SAMPLE_COVERAGE",					MaskConstancyCase::CASETYPE_BOTH));
1499 	addChild(new MaskConstancyCase(m_context, "constancy_both_inverted",				"Test that coverage mask is constant at given coordinates with a given alpha or coverage value, using GL_SAMPLE_ALPHA_TO_COVERAGE and inverted-mask GL_SAMPLE_COVERAGE",	MaskConstancyCase::CASETYPE_BOTH_INVERTED));
1500 }
1501 
1502 } // Functional
1503 } // gles2
1504 } // deqp
1505