Home | History | Annotate | Download | only in functional
      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 
     70 	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 
     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 
     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>
     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>
     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 
    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  *//*--------------------------------------------------------------------*/
    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 
    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 
    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 
    228 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 
    253 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 
    258 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 
    266 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 
    271 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 
    277 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 
    282 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 
    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 
    313 void MultisampleCase::readImage (tcu::Surface& dst) const
    314 {
    315 	glu::readPixels(m_context.getRenderContext(), m_viewportX, m_viewportY, dst.getAccess());
    316 }
    317 
    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 
    370 MultisampleCase::~MultisampleCase (void)
    371 {
    372 	delete m_program;
    373 }
    374 
    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);
    396 						~NumSamplesCase			(void) {}
    397 
    398 	IterateResult		iterate					(void);
    399 
    400 protected:
    401 	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 
    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 
    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);
    496 			~PolygonNumSamplesCase	(void) {}
    497 
    498 protected:
    499 	void	renderPattern			(void) const;
    500 };
    501 
    502 PolygonNumSamplesCase::PolygonNumSamplesCase (Context& context, const char* name, const char* description)
    503 	: NumSamplesCase(context, name, description)
    504 {
    505 }
    506 
    507 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);
    528 			~LineNumSamplesCase		(void) {}
    529 
    530 protected:
    531 	void	renderPattern			(void) const;
    532 };
    533 
    534 LineNumSamplesCase::LineNumSamplesCase (Context& context, const char* name, const char* description)
    535 	: NumSamplesCase (context, name, description)
    536 {
    537 }
    538 
    539 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);
    578 					~CommonEdgeCase			(void) {}
    579 
    580 	void			init					(void);
    581 
    582 	IterateResult	iterate					(void);
    583 
    584 protected:
    585 	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 
    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 
    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 
    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);
    887 						~SampleDepthCase		(void) {}
    888 
    889 	void				init					(void);
    890 
    891 protected:
    892 	void				renderPattern			(void) const;
    893 };
    894 
    895 SampleDepthCase::SampleDepthCase (Context& context, const char* name, const char* description)
    896 	: NumSamplesCase (context, name, description)
    897 {
    898 }
    899 
    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 
    916 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);
    950 						~SampleStencilCase		(void) {}
    951 
    952 	void				init					(void);
    953 	IterateResult		iterate					(void);
    954 
    955 protected:
    956 	int					getDesiredViewportSize	(void) const { return 256; }
    957 };
    958 
    959 SampleStencilCase::SampleStencilCase (Context& context, const char* name, const char* description)
    960 	: MultisampleCase (context, name, description)
    961 {
    962 }
    963 
    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 
    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);
   1082 					~MaskProportionalityCase			(void) {}
   1083 
   1084 	void			init								(void);
   1085 
   1086 	IterateResult	iterate								(void);
   1087 
   1088 protected:
   1089 	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 
   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 
   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 
   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);
   1263 					~MaskConstancyCase			(void) {}
   1264 
   1265 	IterateResult	iterate						(void);
   1266 
   1267 protected:
   1268 	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 
   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 
   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);
   1385 					~CoverageMaskInvertCase		(void) {}
   1386 
   1387 	IterateResult	iterate						(void);
   1388 
   1389 protected:
   1390 	int				getDesiredViewportSize		(void) const { return 256; }
   1391 
   1392 private:
   1393 	void			drawPattern					(bool invertSampleCoverage) const;
   1394 };
   1395 
   1396 CoverageMaskInvertCase::CoverageMaskInvertCase (Context& context, const char* name, const char* description)
   1397 	: MultisampleCase (context, name, description)
   1398 {
   1399 }
   1400 
   1401 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 
   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 
   1471 MultisampleTests::MultisampleTests (Context& context)
   1472 	: TestCaseGroup(context, "multisample", "Multisampling tests")
   1473 {
   1474 }
   1475 
   1476 MultisampleTests::~MultisampleTests (void)
   1477 {
   1478 }
   1479 
   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