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 Clipping tests.
     22  *//*--------------------------------------------------------------------*/
     23 
     24 #include "es2fClippingTests.hpp"
     25 #include "tcuRenderTarget.hpp"
     26 #include "tcuTextureUtil.hpp"
     27 #include "tcuImageCompare.hpp"
     28 #include "tcuVectorUtil.hpp"
     29 #include "deStringUtil.hpp"
     30 #include "deRandom.hpp"
     31 
     32 #include "sglrReferenceContext.hpp"
     33 #include "sglrGLContext.hpp"
     34 
     35 #include "glwEnums.hpp"
     36 #include "glwDefs.hpp"
     37 #include "glwFunctions.hpp"
     38 
     39 using namespace glw; // GLint and other GL types
     40 
     41 namespace deqp
     42 {
     43 namespace gles2
     44 {
     45 namespace Functional
     46 {
     47 namespace
     48 {
     49 
     50 using tcu::PixelBufferAccess;
     51 using tcu::ConstPixelBufferAccess;
     52 using tcu::TestLog;
     53 
     54 static const tcu::Vec4	MASK_COLOR_OK			 = tcu::Vec4(0.0f, 0.1f, 0.0f, 1.0f);
     55 static const tcu::Vec4	MASK_COLOR_DEV			 = tcu::Vec4(0.8f, 0.5f, 0.0f, 1.0f);
     56 static const tcu::Vec4	MASK_COLOR_FAIL			 = tcu::Vec4(1.0f, 0.0f, 1.0f, 1.0f);
     57 
     58 const int					TEST_CANVAS_SIZE  = 200;
     59 const rr::WindowRectangle	VIEWPORT_WHOLE		(0,						0,					TEST_CANVAS_SIZE,		TEST_CANVAS_SIZE);
     60 const rr::WindowRectangle	VIEWPORT_CENTER		(TEST_CANVAS_SIZE/4,	TEST_CANVAS_SIZE/4,	TEST_CANVAS_SIZE/2,		TEST_CANVAS_SIZE/2);
     61 const rr::WindowRectangle	VIEWPORT_CORNER		(TEST_CANVAS_SIZE/2,	TEST_CANVAS_SIZE/2,	TEST_CANVAS_SIZE/2,		TEST_CANVAS_SIZE/2);
     62 
     63 
     64 const char* shaderSourceVertex =	"attribute highp vec4 a_position;\n"
     65 									"attribute highp vec4 a_color;\n"
     66 									"attribute highp float a_pointSize;\n"
     67 									"varying mediump vec4 varFragColor;\n"
     68 									"void main (void)\n"
     69 									"{\n"
     70 									"	gl_Position = a_position;\n"
     71 									"	gl_PointSize = a_pointSize;\n"
     72 									"	varFragColor = a_color;\n"
     73 									"}\n";
     74 const char* shaderSourceFragment =	"varying mediump vec4 varFragColor;\n"
     75 									"void main (void)\n"
     76 									"{\n"
     77 									"	gl_FragColor = varFragColor;\n"
     78 									"}\n";
     79 
     80 inline bool isBlack (const tcu::IVec4& a)
     81 {
     82 	return a.x() == 0 && a.y() == 0 && a.z() == 0;
     83 }
     84 
     85 inline bool isHalfFilled (const tcu::IVec4& a)
     86 {
     87 	const tcu::IVec4 halfFilled	(127, 0, 0, 0);
     88 	const tcu::IVec4 threshold	(20, 256, 256, 256);
     89 
     90 	return tcu::boolAll(tcu::lessThanEqual(tcu::abs(a - halfFilled), threshold));
     91 }
     92 
     93 inline bool isLessThanHalfFilled (const tcu::IVec4& a)
     94 {
     95 	const int halfFilled = 127;
     96 	const int threshold	 = 20;
     97 
     98 	return a.x() + threshold < halfFilled;
     99 }
    100 
    101 inline bool compareBlackNonBlackPixels (const tcu::IVec4& a, const tcu::IVec4& b)
    102 {
    103 	return isBlack(a) == isBlack(b);
    104 }
    105 
    106 inline bool compareColoredPixels (const tcu::IVec4& a, const tcu::IVec4& b)
    107 {
    108 	const bool aIsBlack = isBlack(a);
    109 	const bool bIsBlack = isBlack(b);
    110 	const tcu::IVec4 threshold(20, 20, 20, 0);
    111 
    112 	if (aIsBlack && bIsBlack)
    113 		return true;
    114 	if (aIsBlack != bIsBlack)
    115 		return false;
    116 
    117 	return tcu::boolAll(tcu::lessThanEqual(tcu::abs(a - b), threshold));
    118 }
    119 
    120 void blitImageOnBlackSurface(const ConstPixelBufferAccess& src, const PixelBufferAccess& dst)
    121 {
    122 	const int			height	= src.getHeight();
    123 	const int			width	= src.getWidth();
    124 
    125 	for (int y = 0; y < height; y++)
    126 	for (int x = 0; x < width; x++)
    127 	{
    128 		const tcu::IVec4 cSrc = src.getPixelInt(x, y);
    129 		const tcu::IVec4 cDst = tcu::IVec4(cSrc.x(), cSrc.y(), cSrc.z(), 255);
    130 
    131 		dst.setPixel(cDst, x, y);
    132 	}
    133 }
    134 
    135 /*--------------------------------------------------------------------*//*!
    136  * \brief Pixelwise comparison of two images.
    137  * \note copied & modified from glsRasterizationTests
    138  *
    139  * Kernel radius defines maximum allowed distance. If radius is 0, only
    140  * perfect match is allowed. Radius of 1 gives a 3x3 kernel. Pixels are
    141  * equal if pixelCmp returns true..
    142  *
    143  * Return values:  -1 = Perfect match
    144  *					0 = Deviation within kernel
    145  *				   >0 = Number of faulty pixels
    146  *//*--------------------------------------------------------------------*/
    147 inline int compareImages (tcu::TestLog& log, const ConstPixelBufferAccess& test, const ConstPixelBufferAccess& ref, const PixelBufferAccess& diffMask, int kernelRadius, bool (*pixelCmp)(const tcu::IVec4& a, const tcu::IVec4& b))
    148 {
    149 	const int			height				= test.getHeight();
    150 	const int			width				= test.getWidth();
    151 	int					deviatingPixels		= 0;
    152 	int					faultyPixels		= 0;
    153 	int					compareFailed		= -1;
    154 
    155 	tcu::clear(diffMask, MASK_COLOR_OK);
    156 
    157 	for (int y = 0; y < height; y++)
    158 	{
    159 		for (int x = 0; x < width; x++)
    160 		{
    161 			const tcu::IVec4 cRef	= ref.getPixelInt(x, y);
    162 			const tcu::IVec4 cTest	= test.getPixelInt(x, y);
    163 
    164 			// Pixelwise match, no deviation or fault
    165 			if ((*pixelCmp)(cRef, cTest))
    166 				continue;
    167 
    168 			// Deviation
    169 			{
    170 				const int radius	= kernelRadius;
    171 				bool foundRef		= false;
    172 				bool foundTest		= false;
    173 
    174 				// edges are considered a "deviation" too. The suitable pixel could be "behind" the edge
    175 				if (y < radius || x < radius || y + radius >= height || x + radius >= width)
    176 				{
    177 					foundRef	= true;
    178 					foundTest	= true;
    179 				}
    180 				else
    181 				{
    182 					// find ref
    183 					for (int kY = y - radius; kY <= y + radius; kY++)
    184 					for (int kX = x - radius; kX <= x + radius; kX++)
    185 					{
    186 						if ((*pixelCmp)(cRef, test.getPixelInt(kX, kY)))
    187 						{
    188 							foundRef = true;
    189 							break;
    190 						}
    191 					}
    192 
    193 					// find result
    194 					for (int kY = y - radius; kY <= y + radius; kY++)
    195 					for (int kX = x - radius; kX <= x + radius; kX++)
    196 					{
    197 						if ((*pixelCmp)(cTest, ref.getPixelInt(kX, kY)))
    198 						{
    199 							foundTest = true;
    200 							break;
    201 						}
    202 					}
    203 				}
    204 
    205 				// A pixel is deviating if the reference color is found inside the kernel and (~= every pixel reference draws must be drawn by the gl too)
    206 				// the result color is found in the reference image inside the kernel         (~= every pixel gl draws must be drawn by the reference too)
    207 				if (foundRef && foundTest)
    208 				{
    209 					diffMask.setPixel(MASK_COLOR_DEV, x, y);
    210 					if (compareFailed == -1)
    211 						compareFailed = 0;
    212 					deviatingPixels++;
    213 					continue;
    214 				}
    215 			}
    216 
    217 			diffMask.setPixel(MASK_COLOR_FAIL, x, y);
    218 			faultyPixels++;									// The pixel is faulty if the color is not found
    219 			compareFailed = 1;
    220 		}
    221 	}
    222 
    223 	log << TestLog::Message << deviatingPixels	<< " deviating pixel(s) found." << TestLog::EndMessage;
    224 	log << TestLog::Message << faultyPixels		<< " faulty pixel(s) found." << TestLog::EndMessage;
    225 
    226 	return (compareFailed == 1 ? faultyPixels : compareFailed);
    227 }
    228 
    229 /*--------------------------------------------------------------------*//*!
    230  * \brief Pixelwise comparison of two images.
    231  *
    232  * Kernel radius defines maximum allowed distance. If radius is 0, only
    233  * perfect match is allowed. Radius of 1 gives a 3x3 kernel. Pixels are
    234  * equal if they both are black, or both are non-black.
    235  *
    236  * Return values:  -1 = Perfect match
    237  *					0 = Deviation within kernel
    238  *				   >0 = Number of faulty pixels
    239  *//*--------------------------------------------------------------------*/
    240 int compareBlackNonBlackImages (tcu::TestLog& log, const ConstPixelBufferAccess& test, const ConstPixelBufferAccess& ref, const PixelBufferAccess& diffMask, int kernelRadius)
    241 {
    242 	return compareImages(log, test, ref, diffMask, kernelRadius, compareBlackNonBlackPixels);
    243 }
    244 
    245 /*--------------------------------------------------------------------*//*!
    246  * \brief Pixelwise comparison of two images.
    247  *
    248  * Kernel radius defines maximum allowed distance. If radius is 0, only
    249  * perfect match is allowed. Radius of 1 gives a 3x3 kernel. Pixels are
    250  * equal if they both are black, or both are non-black with color values
    251  * close to each other.
    252  *
    253  * Return values:  -1 = Perfect match
    254  *					0 = Deviation within kernel
    255  *				   >0 = Number of faulty pixels
    256  *//*--------------------------------------------------------------------*/
    257 int compareColoredImages (tcu::TestLog& log, const ConstPixelBufferAccess& test, const ConstPixelBufferAccess& ref, const PixelBufferAccess& diffMask, int kernelRadius)
    258 {
    259 	return compareImages(log, test, ref, diffMask, kernelRadius, compareColoredPixels);
    260 }
    261 
    262 /*--------------------------------------------------------------------*//*!
    263  * \brief Overdraw check verification
    264  *
    265  * Check that image does not have at any point a
    266  * pixel with red component value > 0.5
    267  *
    268  * Return values:  false = area not filled, or leaking
    269  *//*--------------------------------------------------------------------*/
    270 bool checkHalfFilledImageOverdraw (tcu::TestLog& log, const tcu::RenderTarget& m_renderTarget, const ConstPixelBufferAccess& image, const PixelBufferAccess& output)
    271 {
    272 	const int			height				= image.getHeight();
    273 	const int			width				= image.getWidth();
    274 
    275 	bool				faulty				= false;
    276 
    277 	tcu::clear(output, MASK_COLOR_OK);
    278 
    279 	for (int y = 0; y < height; y++)
    280 	{
    281 		for (int x = 0; x < width; x++)
    282 		{
    283 			const tcu::IVec4	cTest	= image.getPixelInt(x, y);
    284 
    285 			const bool pixelValid = isBlack(cTest) || isHalfFilled(cTest) || (m_renderTarget.getNumSamples() > 1 && isLessThanHalfFilled(cTest));
    286 
    287 			if (!pixelValid)
    288 			{
    289 				output.setPixel(MASK_COLOR_FAIL, x, y);
    290 				faulty = true;
    291 			}
    292 		}
    293 	}
    294 
    295 	if (faulty)
    296 		log << TestLog::Message << "Faulty pixel(s) found." << TestLog::EndMessage;
    297 
    298 	return !faulty;
    299 }
    300 
    301 void checkPointSize (const glw::Functions& gl, float pointSize)
    302 {
    303 	GLfloat pointSizeRange[2] = {0,0};
    304 	gl.getFloatv(GL_ALIASED_POINT_SIZE_RANGE, pointSizeRange);
    305 	if (pointSizeRange[1] < pointSize)
    306 		throw tcu::NotSupportedError("Maximum point size is too low for this test");
    307 }
    308 
    309 void checkLineWidth (const glw::Functions& gl, float lineWidth)
    310 {
    311 	GLfloat lineWidthRange[2] = {0,0};
    312 	gl.getFloatv(GL_ALIASED_LINE_WIDTH_RANGE, lineWidthRange);
    313 	if (lineWidthRange[1] < lineWidth)
    314 		throw tcu::NotSupportedError("Maximum line width is too low for this test");
    315 }
    316 
    317 tcu::Vec3 IVec3ToVec3 (const tcu::IVec3& v)
    318 {
    319 	return tcu::Vec3((float)v.x(), (float)v.y(), (float)v.z());
    320 }
    321 
    322 bool pointOnTriangle (const tcu::IVec3& p, const tcu::IVec3& t0, const tcu::IVec3& t1, const tcu::IVec3& t2)
    323 {
    324 	// Must be on the plane
    325 	const tcu::IVec3 n = tcu::cross(t1 - t0, t2 - t0);
    326 	const tcu::IVec3 d = (p - t0);
    327 
    328 	if (tcu::dot(n, d))
    329 		return false;
    330 
    331 	// Must be within the triangle area
    332 	if (deSign32(tcu::dot(n, tcu::cross(t1 - t0, p - t0))) == deSign32(tcu::dot(n, tcu::cross(t2 - t0, p - t0))))
    333 		return false;
    334 	if (deSign32(tcu::dot(n, tcu::cross(t2 - t1, p - t1))) == deSign32(tcu::dot(n, tcu::cross(t0 - t1, p - t1))))
    335 		return false;
    336 	if (deSign32(tcu::dot(n, tcu::cross(t0 - t2, p - t2))) == deSign32(tcu::dot(n, tcu::cross(t1 - t2, p - t2))))
    337 		return false;
    338 
    339 	return true;
    340 }
    341 
    342 bool pointsOnLine (const tcu::IVec2& t0, const tcu::IVec2& t1, const tcu::IVec2& t2)
    343 {
    344 	return (t1 - t0).x() * (t2 - t0).y() - (t2 - t0).x() * (t1 - t0).y() == 0;
    345 }
    346 
    347 // returns true for cases where polygon is (almost) along xz or yz planes (normal.z < 0.1)
    348 // \note[jarkko] Doesn't have to be accurate, just to detect some obviously bad cases
    349 bool twoPointClippedTriangleInvisible(const tcu::Vec3& p, const tcu::IVec3& dir1, const tcu::IVec3& dir2)
    350 {
    351 	// fixed-point-like coords
    352 	const deInt64					fixedScale	= 64;
    353 	const deInt64					farValue	= 1024;
    354 	const tcu::Vector<deInt64, 3>	d1			= tcu::Vector<deInt64, 3>(dir1.x(), dir1.y(), dir1.z());
    355 	const tcu::Vector<deInt64, 3>	d2			= tcu::Vector<deInt64, 3>(dir2.x(), dir2.y(), dir2.z());
    356 	const tcu::Vector<deInt64, 3>	pfixed		= tcu::Vector<deInt64, 3>(deFloorFloatToInt32(p.x() * fixedScale), deFloorFloatToInt32(p.y() * fixedScale), deFloorFloatToInt32(p.z() * fixedScale));
    357 	const tcu::Vector<deInt64, 3>	normalDir	= tcu::cross(d1*farValue - pfixed, d2*farValue - pfixed);
    358 	const deInt64					normalLen2	= tcu::lengthSquared(normalDir);
    359 
    360 	return (normalDir.z() * normalDir.z() - normalLen2/100) < 0;
    361 }
    362 
    363 std::string genClippingPointInfoString(const tcu::Vec4& p)
    364 {
    365 	std::ostringstream msg;
    366 
    367 	if (p.x() < -p.w())		msg << "\t(-X clip)";
    368 	if (p.x() >  p.w())		msg << "\t(+X clip)";
    369 	if (p.y() < -p.w())		msg << "\t(-Y clip)";
    370 	if (p.y() >  p.w())		msg << "\t(+Y clip)";
    371 	if (p.z() < -p.w())		msg << "\t(-Z clip)";
    372 	if (p.z() >  p.w())		msg << "\t(+Z clip)";
    373 
    374 	return msg.str();
    375 }
    376 
    377 std::string genColorString(const tcu::Vec4& p)
    378 {
    379 	const tcu::Vec4 white	(1.0f, 1.0f, 1.0f, 1.0f);
    380 	const tcu::Vec4 red		(1.0f, 0.0f, 0.0f, 1.0f);
    381 	const tcu::Vec4 yellow	(1.0f, 1.0f, 0.0f, 1.0f);
    382 	const tcu::Vec4 blue	(0.0f, 0.0f, 1.0f, 1.0f);
    383 
    384 	if (p == white)		return "(white)";
    385 	if (p == red)		return "(red)";
    386 	if (p == yellow)	return "(yellow)";
    387 	if (p == blue)		return "(blue)";
    388 	return "";
    389 }
    390 
    391 class PositionColorShader : public sglr::ShaderProgram
    392 {
    393 public:
    394 	enum
    395 	{
    396 		VARYINGLOC_COLOR = 0
    397 	};
    398 
    399 			PositionColorShader (void);
    400 
    401 	void	shadeVertices		(const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const;
    402 	void	shadeFragments		(rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const;
    403 };
    404 
    405 PositionColorShader::PositionColorShader (void)
    406 	: sglr::ShaderProgram(sglr::pdec::ShaderProgramDeclaration()
    407 							<< sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT)
    408 							<< sglr::pdec::VertexAttribute("a_color", rr::GENERICVECTYPE_FLOAT)
    409 							<< sglr::pdec::VertexAttribute("a_pointSize", rr::GENERICVECTYPE_FLOAT)
    410 							<< sglr::pdec::VertexToFragmentVarying(rr::GENERICVECTYPE_FLOAT)
    411 							<< sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT)
    412 							<< sglr::pdec::VertexSource(shaderSourceVertex)
    413 							<< sglr::pdec::FragmentSource(shaderSourceFragment))
    414 {
    415 }
    416 
    417 void PositionColorShader::shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
    418 {
    419 	for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
    420 	{
    421 		const int positionAttrLoc = 0;
    422 		const int colorAttrLoc = 1;
    423 		const int pointSizeAttrLoc = 2;
    424 
    425 		rr::VertexPacket& packet = *packets[packetNdx];
    426 
    427 		// Transform to position
    428 		packet.position = rr::readVertexAttribFloat(inputs[positionAttrLoc], packet.instanceNdx, packet.vertexNdx);
    429 
    430 		// output point size
    431 		packet.pointSize = rr::readVertexAttribFloat(inputs[pointSizeAttrLoc], packet.instanceNdx, packet.vertexNdx).x();
    432 
    433 		// Pass color to FS
    434 		packet.outputs[VARYINGLOC_COLOR] = rr::readVertexAttribFloat(inputs[colorAttrLoc], packet.instanceNdx, packet.vertexNdx);
    435 	}
    436 }
    437 
    438 void PositionColorShader::shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
    439 {
    440 	for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
    441 	{
    442 		rr::FragmentPacket& packet = packets[packetNdx];
    443 
    444 		for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
    445 			rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, rr::readVarying<float>(packet, context, VARYINGLOC_COLOR, fragNdx));
    446 	}
    447 }
    448 
    449 class RenderTestCase : public TestCase
    450 {
    451 public:
    452 					RenderTestCase	(Context& context, const char* name, const char* description);
    453 
    454 	virtual void	testRender		(void) = DE_NULL;
    455 	virtual void	init			(void) { }
    456 
    457 	IterateResult	iterate			(void);
    458 };
    459 
    460 RenderTestCase::RenderTestCase (Context& context, const char* name, const char* description)
    461 	: TestCase	(context, name, description)
    462 {
    463 }
    464 
    465 RenderTestCase::IterateResult RenderTestCase::iterate (void)
    466 {
    467 	const int width	 = m_context.getRenderTarget().getWidth();
    468 	const int height = m_context.getRenderTarget().getHeight();
    469 
    470 	m_testCtx.getLog() << TestLog::Message << "Render target size: " << width << "x" << height << TestLog::EndMessage;
    471 	if (width < TEST_CANVAS_SIZE || height < TEST_CANVAS_SIZE)
    472 		throw tcu::NotSupportedError(std::string("Render target size must be at least ") + de::toString(TEST_CANVAS_SIZE) + "x" + de::toString(TEST_CANVAS_SIZE));
    473 
    474 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); // success by default
    475 	testRender();
    476 
    477 	return STOP;
    478 }
    479 
    480 class PointCase : public RenderTestCase
    481 {
    482 public:
    483 									PointCase	(Context& context, const char* name, const char* description, const tcu::Vec4* pointsBegin, const tcu::Vec4* pointsEnd, float pointSize, const rr::WindowRectangle& viewport);
    484 
    485 	void							init		(void);
    486 	void							testRender	(void);
    487 
    488 private:
    489 	const std::vector<tcu::Vec4>	m_points;
    490 	const float						m_pointSize;
    491 	const rr::WindowRectangle		m_viewport;
    492 };
    493 
    494 PointCase::PointCase (Context& context, const char* name, const char* description, const tcu::Vec4* pointsBegin, const tcu::Vec4* pointsEnd, float pointSize, const rr::WindowRectangle& viewport)
    495 	: RenderTestCase(context, name, description)
    496 	, m_points		(pointsBegin, pointsEnd)
    497 	, m_pointSize	(pointSize)
    498 	, m_viewport	(viewport)
    499 {
    500 }
    501 
    502 void PointCase::init (void)
    503 {
    504 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
    505 	checkPointSize (gl, m_pointSize);
    506 }
    507 
    508 void PointCase::testRender (void)
    509 {
    510 	using tcu::TestLog;
    511 
    512 	const int numSamples			= de::max(m_context.getRenderTarget().getNumSamples(), 1);
    513 
    514 	tcu::TestLog&					log			= m_testCtx.getLog();
    515 	sglr::GLContext					glesContext	(m_context.getRenderContext(), log, 0, tcu::IVec4(0, 0, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE));
    516 	sglr::ReferenceContextLimits	limits;
    517 	sglr::ReferenceContextBuffers	buffers		(m_context.getRenderTarget().getPixelFormat(), m_context.getRenderTarget().getDepthBits(), 0, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE, numSamples);
    518 	sglr::ReferenceContext			refContext	(limits, buffers.getColorbuffer(), buffers.getDepthbuffer(), buffers.getStencilbuffer());
    519 	PositionColorShader				program;
    520 	tcu::Surface					testSurface	(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
    521 	tcu::Surface					refSurface	(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
    522 	sglr::Context*					contexts[2] = {&glesContext, &refContext};
    523 	tcu::Surface*					surfaces[2] = {&testSurface, &refSurface};
    524 
    525 	// log the purpose of the test
    526 	log << TestLog::Message << "Viewport: left=" << m_viewport.left << "\tbottom=" << m_viewport.bottom << "\twidth=" << m_viewport.width << "\theight=" << m_viewport.height << TestLog::EndMessage;
    527 	log << TestLog::Message << "Rendering points with point size " << m_pointSize << ". Coordinates:" << TestLog::EndMessage;
    528 	for (size_t ndx = 0; ndx < m_points.size(); ++ndx)
    529 		log << TestLog::Message
    530 				<< "\tx=" << m_points[ndx].x()
    531 				<< "\ty=" << m_points[ndx].y()
    532 				<< "\tz=" << m_points[ndx].z()
    533 				<< "\tw=" << m_points[ndx].w()
    534 				<< "\t" << genClippingPointInfoString(m_points[ndx])
    535 				<< TestLog::EndMessage;
    536 
    537 	for (int contextNdx = 0; contextNdx < 2; ++contextNdx)
    538 	{
    539 		sglr::Context&	ctx				= *contexts[contextNdx];
    540 		tcu::Surface&	dstSurface		= *surfaces[contextNdx];
    541 		const deUint32	programId		= ctx.createProgram(&program);
    542 		const GLint		positionLoc		= ctx.getAttribLocation(programId, "a_position");
    543 		const GLint		pointSizeLoc	= ctx.getAttribLocation(programId, "a_pointSize");
    544 		const GLint		colorLoc		= ctx.getAttribLocation(programId, "a_color");
    545 
    546 		ctx.clearColor					(0, 0, 0, 1);
    547 		ctx.clearDepthf					(1.0f);
    548 		ctx.clear						(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    549 		ctx.viewport					(m_viewport.left, m_viewport.bottom, m_viewport.width, m_viewport.height);
    550 		ctx.useProgram					(programId);
    551 		ctx.enableVertexAttribArray		(positionLoc);
    552 		ctx.vertexAttribPointer			(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, &m_points[0]);
    553 		ctx.vertexAttrib1f				(pointSizeLoc, m_pointSize);
    554 		ctx.vertexAttrib4f				(colorLoc, 1.0f, 1.0f, 1.0f, 1.0f);
    555 		ctx.drawArrays					(GL_POINTS, 0, (glw::GLsizei)m_points.size());
    556 		ctx.disableVertexAttribArray	(positionLoc);
    557 		ctx.useProgram					(0);
    558 		ctx.deleteProgram				(programId);
    559 		ctx.finish						();
    560 
    561 		ctx.readPixels(dstSurface, 0, 0, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
    562 	}
    563 
    564 	// do the comparison
    565 	{
    566 		tcu::Surface		diffMask		(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
    567 		const int			kernelRadius	= 1;
    568 		int					faultyPixels;
    569 
    570 		log << TestLog::Message << "Comparing images... " << TestLog::EndMessage;
    571 		log << TestLog::Message << "Deviation within radius of " << kernelRadius << " is allowed." << TestLog::EndMessage;
    572 
    573 		faultyPixels = compareBlackNonBlackImages(log, testSurface.getAccess(), refSurface.getAccess(), diffMask.getAccess(), kernelRadius);
    574 
    575 		if (faultyPixels > 0)
    576 		{
    577 			log << TestLog::ImageSet("Images", "Image comparison")
    578 				<< TestLog::Image("TestImage", "Test image", testSurface.getAccess())
    579 				<< TestLog::Image("ReferenceImage", "Reference image", refSurface.getAccess())
    580 				<< TestLog::Image("DifferenceMask", "Difference mask", diffMask.getAccess())
    581 				<< TestLog::EndImageSet
    582 				<< tcu::TestLog::Message << "Got " << faultyPixels << " faulty pixel(s)." << tcu::TestLog::EndMessage;
    583 
    584 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got faulty pixels");
    585 		}
    586 	}
    587 }
    588 
    589 class LineRenderTestCase : public RenderTestCase
    590 {
    591 public:
    592 	struct ColoredLineData
    593 	{
    594 		tcu::Vec4 p0;
    595 		tcu::Vec4 c0;
    596 		tcu::Vec4 p1;
    597 		tcu::Vec4 c1;
    598 	};
    599 
    600 	struct ColorlessLineData
    601 	{
    602 		tcu::Vec4 p0;
    603 		tcu::Vec4 p1;
    604 	};
    605 										LineRenderTestCase		(Context& context, const char* name, const char* description, const ColoredLineData*   linesBegin, const ColoredLineData*   linesEnd, float lineWidth, const rr::WindowRectangle& viewport);
    606 										LineRenderTestCase		(Context& context, const char* name, const char* description, const ColorlessLineData* linesBegin, const ColorlessLineData* linesEnd, float lineWidth, const rr::WindowRectangle& viewport);
    607 
    608 	virtual void						verifyImage				(const tcu::ConstPixelBufferAccess& testImageAccess, const tcu::ConstPixelBufferAccess& referenceImageAccess) = DE_NULL;
    609 	void								init					(void);
    610 	void								testRender				(void);
    611 
    612 protected:
    613 	const float							m_lineWidth;
    614 
    615 private:
    616 	std::vector<ColoredLineData>		convertToColoredLines	(const ColorlessLineData* linesBegin, const ColorlessLineData* linesEnd);
    617 
    618 	const std::vector<ColoredLineData>	m_lines;
    619 	const rr::WindowRectangle			m_viewport;
    620 };
    621 
    622 LineRenderTestCase::LineRenderTestCase (Context& context, const char* name, const char* description, const ColoredLineData* linesBegin, const ColoredLineData* linesEnd, float lineWidth, const rr::WindowRectangle& viewport)
    623 	: RenderTestCase	(context, name, description)
    624 	, m_lineWidth		(lineWidth)
    625 	, m_lines			(linesBegin, linesEnd)
    626 	, m_viewport		(viewport)
    627 {
    628 }
    629 
    630 LineRenderTestCase::LineRenderTestCase (Context& context, const char* name, const char* description, const ColorlessLineData* linesBegin, const ColorlessLineData* linesEnd, float lineWidth, const rr::WindowRectangle& viewport)
    631 	: RenderTestCase	(context, name, description)
    632 	, m_lineWidth		(lineWidth)
    633 	, m_lines			(convertToColoredLines(linesBegin, linesEnd))
    634 	, m_viewport		(viewport)
    635 {
    636 }
    637 
    638 void LineRenderTestCase::init (void)
    639 {
    640 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
    641 	checkLineWidth (gl, m_lineWidth);
    642 }
    643 
    644 void LineRenderTestCase::testRender (void)
    645 {
    646 	using tcu::TestLog;
    647 
    648 	const int numSamples			= de::max(m_context.getRenderTarget().getNumSamples(), 1);
    649 	const int verticesPerLine		= 2;
    650 
    651 	tcu::TestLog&					log			= m_testCtx.getLog();
    652 	sglr::GLContext					glesContext	(m_context.getRenderContext(), log, 0, tcu::IVec4(0, 0, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE));
    653 	sglr::ReferenceContextLimits	limits;
    654 	sglr::ReferenceContextBuffers	buffers		(m_context.getRenderTarget().getPixelFormat(), m_context.getRenderTarget().getDepthBits(), 0, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE, numSamples);
    655 	sglr::ReferenceContext			refContext	(limits, buffers.getColorbuffer(), buffers.getDepthbuffer(), buffers.getStencilbuffer());
    656 	PositionColorShader				program;
    657 	tcu::Surface					testSurface	(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
    658 	tcu::Surface					refSurface	(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
    659 	sglr::Context*					contexts[2] = {&glesContext, &refContext};
    660 	tcu::Surface*					surfaces[2] = {&testSurface, &refSurface};
    661 
    662 	// log the purpose of the test
    663 	log << TestLog::Message << "Viewport: left=" << m_viewport.left << "\tbottom=" << m_viewport.bottom << "\twidth=" << m_viewport.width << "\theight=" << m_viewport.height << TestLog::EndMessage;
    664 	log << TestLog::Message << "Rendering lines with line width " << m_lineWidth << ". Coordinates:" << TestLog::EndMessage;
    665 	for (size_t ndx = 0; ndx < m_lines.size(); ++ndx)
    666 	{
    667 		const std::string fromProperties = genClippingPointInfoString(m_lines[ndx].p0);
    668 		const std::string toProperties   = genClippingPointInfoString(m_lines[ndx].p1);
    669 
    670 		log << TestLog::Message << "\tfrom (x=" << m_lines[ndx].p0.x() << "\ty=" << m_lines[ndx].p0.y() << "\tz=" << m_lines[ndx].p0.z() << "\tw=" << m_lines[ndx].p0.w() << ")\t" << fromProperties << TestLog::EndMessage;
    671 		log << TestLog::Message << "\tto   (x=" << m_lines[ndx].p1.x() << "\ty=" << m_lines[ndx].p1.y() << "\tz=" << m_lines[ndx].p1.z() << "\tw=" << m_lines[ndx].p1.w() << ")\t" << toProperties   << TestLog::EndMessage;
    672 		log << TestLog::Message << TestLog::EndMessage;
    673 	}
    674 
    675 	// render test image
    676 	for (int contextNdx = 0; contextNdx < 2; ++contextNdx)
    677 	{
    678 		sglr::Context&	ctx				= *contexts[contextNdx];
    679 		tcu::Surface&	dstSurface		= *surfaces[contextNdx];
    680 		const deUint32	programId		= ctx.createProgram(&program);
    681 		const GLint		positionLoc		= ctx.getAttribLocation(programId, "a_position");
    682 		const GLint		colorLoc		= ctx.getAttribLocation(programId, "a_color");
    683 
    684 		ctx.clearColor					(0, 0, 0, 1);
    685 		ctx.clearDepthf					(1.0f);
    686 		ctx.clear						(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    687 		ctx.viewport					(m_viewport.left, m_viewport.bottom, m_viewport.width, m_viewport.height);
    688 		ctx.useProgram					(programId);
    689 		ctx.enableVertexAttribArray		(positionLoc);
    690 		ctx.enableVertexAttribArray		(colorLoc);
    691 		ctx.vertexAttribPointer			(positionLoc,	4, GL_FLOAT, GL_FALSE, sizeof(GLfloat[8]), &m_lines[0].p0);
    692 		ctx.vertexAttribPointer			(colorLoc,		4, GL_FLOAT, GL_FALSE, sizeof(GLfloat[8]), &m_lines[0].c0);
    693 		ctx.lineWidth					(m_lineWidth);
    694 		ctx.drawArrays					(GL_LINES, 0, verticesPerLine * (glw::GLsizei)m_lines.size());
    695 		ctx.disableVertexAttribArray	(positionLoc);
    696 		ctx.disableVertexAttribArray	(colorLoc);
    697 		ctx.useProgram					(0);
    698 		ctx.deleteProgram				(programId);
    699 		ctx.finish						();
    700 
    701 		ctx.readPixels(dstSurface, 0, 0, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
    702 	}
    703 
    704 	// compare
    705 	verifyImage(testSurface.getAccess(), refSurface.getAccess());
    706 }
    707 
    708 std::vector<LineRenderTestCase::ColoredLineData> LineRenderTestCase::convertToColoredLines(const ColorlessLineData* linesBegin, const ColorlessLineData* linesEnd)
    709 {
    710 	std::vector<ColoredLineData> ret;
    711 
    712 	for (const ColorlessLineData* it = linesBegin; it != linesEnd; ++it)
    713 	{
    714 		ColoredLineData r;
    715 
    716 		r.p0 = (*it).p0;
    717 		r.c0 = tcu::Vec4(1, 1, 1, 1);
    718 		r.p1 = (*it).p1;
    719 		r.c1 = tcu::Vec4(1, 1, 1, 1);
    720 
    721 		ret.push_back(r);
    722 	}
    723 
    724 	return ret;
    725 }
    726 
    727 class LineCase : public LineRenderTestCase
    728 {
    729 public:
    730 				LineCase			(Context& context, const char* name, const char* description, const LineRenderTestCase::ColorlessLineData* linesBegin, const LineRenderTestCase::ColorlessLineData* linesEnd, float lineWidth, const rr::WindowRectangle& viewport, int searchKernelSize = 1);
    731 
    732 	void		verifyImage			(const tcu::ConstPixelBufferAccess& testImageAccess, const tcu::ConstPixelBufferAccess& referenceImageAccess);
    733 
    734 private:
    735 	const int	m_searchKernelSize;
    736 };
    737 
    738 LineCase::LineCase (Context& context, const char* name, const char* description, const LineRenderTestCase::ColorlessLineData* linesBegin, const LineRenderTestCase::ColorlessLineData* linesEnd, float lineWidth, const rr::WindowRectangle& viewport, int searchKernelSize)
    739 	: LineRenderTestCase	(context, name, description, linesBegin, linesEnd, lineWidth, viewport)
    740 	, m_searchKernelSize	(searchKernelSize)
    741 {
    742 }
    743 
    744 void LineCase::verifyImage (const tcu::ConstPixelBufferAccess& testImageAccess, const tcu::ConstPixelBufferAccess& referenceImageAccess)
    745 {
    746 	const int		faultyLimit		= 6;
    747 	int				faultyPixels;
    748 
    749 	const bool		isMsaa			= m_context.getRenderTarget().getNumSamples() > 1;
    750 	tcu::TestLog&	log				= m_testCtx.getLog();
    751 	tcu::Surface	diffMask		(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
    752 
    753 	log << TestLog::Message << "Comparing images... " << TestLog::EndMessage;
    754 	log << TestLog::Message << "Deviation within radius of " << m_searchKernelSize << " is allowed." << TestLog::EndMessage;
    755 	log << TestLog::Message << faultyLimit << " faulty pixels are allowed." << TestLog::EndMessage;
    756 
    757 	faultyPixels = compareBlackNonBlackImages(log, testImageAccess, referenceImageAccess, diffMask.getAccess(), m_searchKernelSize);
    758 
    759 	if (faultyPixels > faultyLimit)
    760 	{
    761 		log << TestLog::ImageSet("Images", "Image comparison")
    762 			<< TestLog::Image("TestImage", "Test image", testImageAccess)
    763 			<< TestLog::Image("ReferenceImage", "Reference image", referenceImageAccess)
    764 			<< TestLog::Image("DifferenceMask", "Difference mask", diffMask.getAccess())
    765 			<< TestLog::EndImageSet
    766 			<< tcu::TestLog::Message << "Got " << faultyPixels << " faulty pixel(s)." << tcu::TestLog::EndMessage;
    767 
    768 		if (m_lineWidth != 1.0f && isMsaa)
    769 		{
    770 			log << TestLog::Message << "Wide line support is optional, reporting compatibility warning." << TestLog::EndMessage;
    771 			m_testCtx.setTestResult(QP_TEST_RESULT_COMPATIBILITY_WARNING, "Wide line clipping failed");
    772 		}
    773 		else
    774 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got faulty pixels");
    775 	}
    776 }
    777 
    778 class ColoredLineCase : public LineRenderTestCase
    779 {
    780 public:
    781 	ColoredLineCase (Context& context, const char* name, const char* description, const LineRenderTestCase::ColoredLineData* linesBegin, const LineRenderTestCase::ColoredLineData* linesEnd, float lineWidth, const rr::WindowRectangle& viewport);
    782 
    783 	void verifyImage (const tcu::ConstPixelBufferAccess& testImageAccess, const tcu::ConstPixelBufferAccess& referenceImageAccess);
    784 };
    785 
    786 ColoredLineCase::ColoredLineCase (Context& context, const char* name, const char* description, const LineRenderTestCase::ColoredLineData* linesBegin, const LineRenderTestCase::ColoredLineData* linesEnd, float lineWidth, const rr::WindowRectangle& viewport)
    787 	: LineRenderTestCase (context, name, description, linesBegin, linesEnd, lineWidth, viewport)
    788 {
    789 }
    790 
    791 void ColoredLineCase::verifyImage (const tcu::ConstPixelBufferAccess& testImageAccess, const tcu::ConstPixelBufferAccess& referenceImageAccess)
    792 {
    793 	const bool		msaa	= m_context.getRenderTarget().getNumSamples() > 1;
    794 	tcu::TestLog&	log		= m_testCtx.getLog();
    795 
    796 	if (!msaa)
    797 	{
    798 		const int		kernelRadius	= 1;
    799 		const int		faultyLimit		= 6;
    800 		int				faultyPixels;
    801 		tcu::Surface	diffMask		(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
    802 
    803 		log << TestLog::Message << "Comparing images... " << TestLog::EndMessage;
    804 		log << TestLog::Message << "Deviation within radius of " << kernelRadius << " is allowed." << TestLog::EndMessage;
    805 		log << TestLog::Message << faultyLimit << " faulty pixels are allowed." << TestLog::EndMessage;
    806 
    807 		faultyPixels = compareColoredImages(log, testImageAccess, referenceImageAccess, diffMask.getAccess(), kernelRadius);
    808 
    809 		if (faultyPixels > faultyLimit)
    810 		{
    811 			log << TestLog::ImageSet("Images", "Image comparison")
    812 				<< TestLog::Image("TestImage", "Test image", testImageAccess)
    813 				<< TestLog::Image("ReferenceImage", "Reference image", referenceImageAccess)
    814 				<< TestLog::Image("DifferenceMask", "Difference mask", diffMask.getAccess())
    815 				<< TestLog::EndImageSet
    816 				<< tcu::TestLog::Message << "Got " << faultyPixels << " faulty pixel(s)." << tcu::TestLog::EndMessage;
    817 
    818 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got faulty pixels");
    819 		}
    820 	}
    821 	else
    822 	{
    823 		const float threshold = 0.3f;
    824 		if (!tcu::fuzzyCompare(log, "Images", "", referenceImageAccess, testImageAccess, threshold, tcu::COMPARE_LOG_ON_ERROR))
    825 		{
    826 			if (m_lineWidth != 1.0f)
    827 			{
    828 				log << TestLog::Message << "Wide line support is optional, reporting compatibility warning." << TestLog::EndMessage;
    829 				m_testCtx.setTestResult(QP_TEST_RESULT_COMPATIBILITY_WARNING, "Wide line clipping failed");
    830 			}
    831 			else
    832 				m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got faulty pixels");
    833 		}
    834 	}
    835 }
    836 
    837 class TriangleCaseBase : public RenderTestCase
    838 {
    839 public:
    840 	struct TriangleData
    841 	{
    842 		tcu::Vec4 p0;
    843 		tcu::Vec4 c0;
    844 		tcu::Vec4 p1;
    845 		tcu::Vec4 c1;
    846 		tcu::Vec4 p2;
    847 		tcu::Vec4 c2;
    848 	};
    849 
    850 										TriangleCaseBase	(Context& context, const char* name, const char* description, const TriangleData* polysBegin, const TriangleData* polysEnd, const rr::WindowRectangle& viewport);
    851 
    852 	virtual void						verifyImage			(const tcu::ConstPixelBufferAccess& testImageAccess, const tcu::ConstPixelBufferAccess& referenceImageAccess) = DE_NULL;
    853 	void								testRender			(void);
    854 
    855 private:
    856 	const std::vector<TriangleData>		m_polys;
    857 	const rr::WindowRectangle			m_viewport;
    858 };
    859 
    860 TriangleCaseBase::TriangleCaseBase (Context& context, const char* name, const char* description, const TriangleData* polysBegin, const TriangleData* polysEnd, const rr::WindowRectangle& viewport)
    861 	: RenderTestCase(context, name, description)
    862 	, m_polys		(polysBegin, polysEnd)
    863 	, m_viewport	(viewport)
    864 {
    865 }
    866 
    867 void TriangleCaseBase::testRender (void)
    868 {
    869 	using tcu::TestLog;
    870 
    871 	const int numSamples			= de::max(m_context.getRenderTarget().getNumSamples(), 1);
    872 	const int verticesPerTriangle	= 3;
    873 
    874 	tcu::TestLog&					log			= m_testCtx.getLog();
    875 	sglr::GLContext					glesContext	(m_context.getRenderContext(), log, 0, tcu::IVec4(0, 0, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE));
    876 	sglr::ReferenceContextLimits	limits;
    877 	sglr::ReferenceContextBuffers	buffers		(m_context.getRenderTarget().getPixelFormat(), m_context.getRenderTarget().getDepthBits(), 0, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE, numSamples);
    878 	sglr::ReferenceContext			refContext	(limits, buffers.getColorbuffer(), buffers.getDepthbuffer(), buffers.getStencilbuffer());
    879 	PositionColorShader				program;
    880 	tcu::Surface					testSurface	(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
    881 	tcu::Surface					refSurface	(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
    882 	sglr::Context*					contexts[2] = {&glesContext, &refContext};
    883 	tcu::Surface*					surfaces[2] = {&testSurface, &refSurface};
    884 
    885 	// log the purpose of the test
    886 	log << TestLog::Message << "Viewport: left=" << m_viewport.left << "\tbottom=" << m_viewport.bottom << "\twidth=" << m_viewport.width << "\theight=" << m_viewport.height << TestLog::EndMessage;
    887 	log << TestLog::Message << "Rendering triangles. Coordinates:" << TestLog::EndMessage;
    888 	for (size_t ndx = 0; ndx < m_polys.size(); ++ndx)
    889 	{
    890 		const std::string v0Properties = genClippingPointInfoString(m_polys[ndx].p0);
    891 		const std::string v1Properties = genClippingPointInfoString(m_polys[ndx].p1);
    892 		const std::string v2Properties = genClippingPointInfoString(m_polys[ndx].p2);
    893 		const std::string c0Properties = genColorString(m_polys[ndx].c0);
    894 		const std::string c1Properties = genColorString(m_polys[ndx].c1);
    895 		const std::string c2Properties = genColorString(m_polys[ndx].c2);
    896 
    897 		log << TestLog::Message << "\tv0 (x=" << m_polys[ndx].p0.x() << "\ty=" << m_polys[ndx].p0.y() << "\tz=" << m_polys[ndx].p0.z() << "\tw=" << m_polys[ndx].p0.w() << ")\t" << v0Properties << "\t" << c0Properties << TestLog::EndMessage;
    898 		log << TestLog::Message << "\tv1 (x=" << m_polys[ndx].p1.x() << "\ty=" << m_polys[ndx].p1.y() << "\tz=" << m_polys[ndx].p1.z() << "\tw=" << m_polys[ndx].p1.w() << ")\t" << v1Properties << "\t" << c1Properties << TestLog::EndMessage;
    899 		log << TestLog::Message << "\tv2 (x=" << m_polys[ndx].p2.x() << "\ty=" << m_polys[ndx].p2.y() << "\tz=" << m_polys[ndx].p2.z() << "\tw=" << m_polys[ndx].p2.w() << ")\t" << v2Properties << "\t" << c2Properties << TestLog::EndMessage;
    900 		log << TestLog::Message << TestLog::EndMessage;
    901 	}
    902 
    903 	// render test image
    904 	for (int contextNdx = 0; contextNdx < 2; ++contextNdx)
    905 	{
    906 		sglr::Context&	ctx				= *contexts[contextNdx];
    907 		tcu::Surface&	dstSurface		= *surfaces[contextNdx];
    908 		const deUint32	programId		= ctx.createProgram(&program);
    909 		const GLint		positionLoc		= ctx.getAttribLocation(programId, "a_position");
    910 		const GLint		colorLoc		= ctx.getAttribLocation(programId, "a_color");
    911 
    912 		ctx.clearColor					(0, 0, 0, 1);
    913 		ctx.clearDepthf					(1.0f);
    914 		ctx.clear						(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    915 		ctx.viewport					(m_viewport.left, m_viewport.bottom, m_viewport.width, m_viewport.height);
    916 		ctx.useProgram					(programId);
    917 		ctx.enableVertexAttribArray		(positionLoc);
    918 		ctx.enableVertexAttribArray		(colorLoc);
    919 		ctx.vertexAttribPointer			(positionLoc,	4, GL_FLOAT, GL_FALSE, sizeof(GLfloat[8]), &m_polys[0].p0);
    920 		ctx.vertexAttribPointer			(colorLoc,		4, GL_FLOAT, GL_FALSE, sizeof(GLfloat[8]), &m_polys[0].c0);
    921 		ctx.drawArrays					(GL_TRIANGLES, 0, verticesPerTriangle * (glw::GLsizei)m_polys.size());
    922 		ctx.disableVertexAttribArray	(positionLoc);
    923 		ctx.disableVertexAttribArray	(colorLoc);
    924 		ctx.useProgram					(0);
    925 		ctx.deleteProgram				(programId);
    926 		ctx.finish						();
    927 
    928 		ctx.readPixels(dstSurface, 0, 0, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
    929 	}
    930 
    931 	verifyImage(testSurface.getAccess(), refSurface.getAccess());
    932 }
    933 
    934 class TriangleCase : public TriangleCaseBase
    935 {
    936 public:
    937 			TriangleCase	(Context& context, const char* name, const char* description, const TriangleData* polysBegin, const TriangleData* polysEnd, const rr::WindowRectangle& viewport);
    938 
    939 	void	verifyImage		(const tcu::ConstPixelBufferAccess& testImageAccess, const tcu::ConstPixelBufferAccess& referenceImageAccess);
    940 };
    941 
    942 TriangleCase::TriangleCase (Context& context, const char* name, const char* description, const TriangleData* polysBegin, const TriangleData* polysEnd, const rr::WindowRectangle& viewport)
    943 	: TriangleCaseBase(context, name, description, polysBegin, polysEnd, viewport)
    944 {
    945 }
    946 
    947 void TriangleCase::verifyImage (const tcu::ConstPixelBufferAccess& testImageAccess, const tcu::ConstPixelBufferAccess& referenceImageAccess)
    948 {
    949 	const int			kernelRadius	= 1;
    950 	const int			faultyLimit		= 6;
    951 	tcu::TestLog&		log				= m_testCtx.getLog();
    952 	tcu::Surface		diffMask		(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
    953 	int					faultyPixels;
    954 
    955 	log << TestLog::Message << "Comparing images... " << TestLog::EndMessage;
    956 	log << TestLog::Message << "Deviation within radius of " << kernelRadius << " is allowed." << TestLog::EndMessage;
    957 	log << TestLog::Message << faultyLimit << " faulty pixels are allowed." << TestLog::EndMessage;
    958 
    959 	faultyPixels = compareBlackNonBlackImages(log, testImageAccess, referenceImageAccess, diffMask.getAccess(), kernelRadius);
    960 
    961 	if (faultyPixels > faultyLimit)
    962 	{
    963 		log << TestLog::ImageSet("Images", "Image comparison")
    964 			<< TestLog::Image("TestImage", "Test image", testImageAccess)
    965 			<< TestLog::Image("ReferenceImage", "Reference image", referenceImageAccess)
    966 			<< TestLog::Image("DifferenceMask", "Difference mask", diffMask.getAccess())
    967 			<< TestLog::EndImageSet
    968 			<< tcu::TestLog::Message << "Got " << faultyPixels << " faulty pixel(s)." << tcu::TestLog::EndMessage;
    969 
    970 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got faulty pixels");
    971 	}
    972 }
    973 
    974 class TriangleAttributeCase : public TriangleCaseBase
    975 {
    976 public:
    977 			TriangleAttributeCase	(Context& context, const char* name, const char* description, const TriangleData* polysBegin, const TriangleData* polysEnd, const rr::WindowRectangle& viewport);
    978 
    979 	void	verifyImage				(const tcu::ConstPixelBufferAccess& testImageAccess, const tcu::ConstPixelBufferAccess& referenceImageAccess);
    980 };
    981 
    982 TriangleAttributeCase::TriangleAttributeCase (Context& context, const char* name, const char* description, const TriangleData* polysBegin, const TriangleData* polysEnd, const rr::WindowRectangle& viewport)
    983 	: TriangleCaseBase(context, name, description, polysBegin, polysEnd, viewport)
    984 {
    985 }
    986 
    987 void TriangleAttributeCase::verifyImage (const tcu::ConstPixelBufferAccess& testImageAccess, const tcu::ConstPixelBufferAccess& referenceImageAccess)
    988 {
    989 	const bool		msaa	= m_context.getRenderTarget().getNumSamples() > 1;
    990 	tcu::TestLog&	log		= m_testCtx.getLog();
    991 
    992 	if (!msaa)
    993 	{
    994 		const int		kernelRadius	= 1;
    995 		const int		faultyLimit		= 6;
    996 		int				faultyPixels;
    997 		tcu::Surface	diffMask		(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
    998 
    999 		log << TestLog::Message << "Comparing images... " << TestLog::EndMessage;
   1000 		log << TestLog::Message << "Deviation within radius of " << kernelRadius << " is allowed." << TestLog::EndMessage;
   1001 		log << TestLog::Message << faultyLimit << " faulty pixels are allowed." << TestLog::EndMessage;
   1002 		faultyPixels = compareColoredImages(log, testImageAccess, referenceImageAccess, diffMask.getAccess(), kernelRadius);
   1003 
   1004 		if (faultyPixels > faultyLimit)
   1005 		{
   1006 			log << TestLog::ImageSet("Images", "Image comparison")
   1007 				<< TestLog::Image("TestImage", "Test image", testImageAccess)
   1008 				<< TestLog::Image("ReferenceImage", "Reference image", referenceImageAccess)
   1009 				<< TestLog::Image("DifferenceMask", "Difference mask", diffMask.getAccess())
   1010 				<< TestLog::EndImageSet
   1011 				<< tcu::TestLog::Message << "Got " << faultyPixels << " faulty pixel(s)." << tcu::TestLog::EndMessage;
   1012 
   1013 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got faulty pixels");
   1014 		}
   1015 	}
   1016 	else
   1017 	{
   1018 		const float threshold = 0.3f;
   1019 		if (!tcu::fuzzyCompare(log, "Images", "", referenceImageAccess, testImageAccess, threshold, tcu::COMPARE_LOG_ON_ERROR))
   1020 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got faulty pixels");
   1021 	}
   1022 }
   1023 
   1024 class FillTest : public RenderTestCase
   1025 {
   1026 public:
   1027 								FillTest	(Context& context, const char* name, const char* description, const rr::WindowRectangle& viewport);
   1028 
   1029 	virtual void				render		(sglr::Context& ctx) = DE_NULL;
   1030 	void						testRender	(void);
   1031 
   1032 protected:
   1033 	const rr::WindowRectangle	m_viewport;
   1034 };
   1035 
   1036 FillTest::FillTest (Context& context, const char* name, const char* description, const rr::WindowRectangle& viewport)
   1037 	: RenderTestCase(context, name, description)
   1038 	, m_viewport	(viewport)
   1039 {
   1040 }
   1041 
   1042 void FillTest::testRender (void)
   1043 {
   1044 	using tcu::TestLog;
   1045 
   1046 	const int						numSamples	= 1;
   1047 
   1048 	tcu::TestLog&					log			= m_testCtx.getLog();
   1049 	sglr::GLContext					glesContext	(m_context.getRenderContext(), log, 0, tcu::IVec4(0, 0, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE));
   1050 	sglr::ReferenceContextLimits	limits;
   1051 	sglr::ReferenceContextBuffers	buffers		(m_context.getRenderTarget().getPixelFormat(), m_context.getRenderTarget().getDepthBits(), 0, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE, numSamples);
   1052 	sglr::ReferenceContext			refContext	(limits, buffers.getColorbuffer(), buffers.getDepthbuffer(), buffers.getStencilbuffer());
   1053 	tcu::Surface					testSurface	(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
   1054 	tcu::Surface					refSurface	(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
   1055 
   1056 	render(glesContext);
   1057 	glesContext.readPixels(testSurface, 0, 0, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
   1058 
   1059 	render(refContext);
   1060 	refContext.readPixels(refSurface, 0, 0, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
   1061 
   1062 	// check overdraw
   1063 	{
   1064 		bool				overdrawOk;
   1065 		tcu::Surface		outputImage(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
   1066 
   1067 		log << TestLog::Message << "Checking for overdraw " << TestLog::EndMessage;
   1068 		overdrawOk = checkHalfFilledImageOverdraw(log, m_context.getRenderTarget(), testSurface.getAccess(), outputImage.getAccess());
   1069 
   1070 		if (!overdrawOk)
   1071 		{
   1072 			log << TestLog::ImageSet("Images", "Image comparison")
   1073 				<< TestLog::Image("TestImage", "Test image", testSurface.getAccess())
   1074 				<< TestLog::Image("InvalidPixels", "Invalid pixels", outputImage.getAccess())
   1075 				<< TestLog::EndImageSet
   1076 				<< tcu::TestLog::Message << "Got overdraw." << tcu::TestLog::EndMessage;
   1077 
   1078 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got overdraw");
   1079 		}
   1080 	}
   1081 
   1082 	// compare & check missing pixels
   1083 	{
   1084 		const int			kernelRadius	= 1;
   1085 		tcu::Surface		diffMask		(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
   1086 		int					faultyPixels;
   1087 
   1088 		log << TestLog::Message << "Comparing images... " << TestLog::EndMessage;
   1089 		log << TestLog::Message << "Deviation within radius of " << kernelRadius << " is allowed." << TestLog::EndMessage;
   1090 
   1091 		blitImageOnBlackSurface(refSurface.getAccess(), refSurface.getAccess()); // makes images look right in Candy
   1092 
   1093 		faultyPixels = compareBlackNonBlackImages(log, testSurface.getAccess(), refSurface.getAccess(), diffMask.getAccess(), kernelRadius);
   1094 
   1095 		if (faultyPixels > 0)
   1096 		{
   1097 			log << TestLog::ImageSet("Images", "Image comparison")
   1098 				<< TestLog::Image("TestImage", "Test image", testSurface.getAccess())
   1099 				<< TestLog::Image("ReferenceImage", "Reference image", refSurface.getAccess())
   1100 				<< TestLog::Image("DifferenceMask", "Difference mask", diffMask.getAccess())
   1101 				<< TestLog::EndImageSet
   1102 				<< tcu::TestLog::Message << "Got " << faultyPixels << " faulty pixel(s)." << tcu::TestLog::EndMessage;
   1103 
   1104 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got faulty pixels");
   1105 		}
   1106 	}
   1107 }
   1108 
   1109 class TriangleFillTest : public FillTest
   1110 {
   1111 public:
   1112 	struct FillTriangle
   1113 	{
   1114 		tcu::Vec4 v0;
   1115 		tcu::Vec4 c0;
   1116 		tcu::Vec4 v1;
   1117 		tcu::Vec4 c1;
   1118 		tcu::Vec4 v2;
   1119 		tcu::Vec4 c2;
   1120 	};
   1121 
   1122 								TriangleFillTest	(Context& context, const char* name, const char* description, const rr::WindowRectangle& viewport);
   1123 
   1124 	void						render				(sglr::Context& ctx);
   1125 
   1126 protected:
   1127 	std::vector<FillTriangle>	m_triangles;
   1128 };
   1129 
   1130 TriangleFillTest::TriangleFillTest (Context& context, const char* name, const char* description, const rr::WindowRectangle& viewport)
   1131 	: FillTest(context, name, description, viewport)
   1132 {
   1133 }
   1134 
   1135 void TriangleFillTest::render (sglr::Context& ctx)
   1136 {
   1137 	const int			verticesPerTriangle		= 3;
   1138 	PositionColorShader program;
   1139 	const deUint32		programId				= ctx.createProgram(&program);
   1140 	const GLint			positionLoc				= ctx.getAttribLocation(programId, "a_position");
   1141 	const GLint			colorLoc				= ctx.getAttribLocation(programId, "a_color");
   1142 	tcu::TestLog&		log						= m_testCtx.getLog();
   1143 
   1144 	// log the purpose of the test
   1145 	log << TestLog::Message << "Viewport: left=" << m_viewport.left << "\tbottom=" << m_viewport.bottom << "\twidth=" << m_viewport.width << "\theight=" << m_viewport.height << TestLog::EndMessage;
   1146 	log << TestLog::Message << "Rendering triangles. Coordinates:" << TestLog::EndMessage;
   1147 	for (size_t ndx = 0; ndx < m_triangles.size(); ++ndx)
   1148 	{
   1149 		const std::string v0Properties = genClippingPointInfoString(m_triangles[ndx].v0);
   1150 		const std::string v1Properties = genClippingPointInfoString(m_triangles[ndx].v1);
   1151 		const std::string v2Properties = genClippingPointInfoString(m_triangles[ndx].v2);
   1152 
   1153 		log << TestLog::Message << "\tv0 (x=" << m_triangles[ndx].v0.x() << "\ty=" << m_triangles[ndx].v0.y() << "\tz=" << m_triangles[ndx].v0.z() << "\tw=" << m_triangles[ndx].v0.w() << ")\t" << v0Properties << TestLog::EndMessage;
   1154 		log << TestLog::Message << "\tv1 (x=" << m_triangles[ndx].v1.x() << "\ty=" << m_triangles[ndx].v1.y() << "\tz=" << m_triangles[ndx].v1.z() << "\tw=" << m_triangles[ndx].v1.w() << ")\t" << v1Properties << TestLog::EndMessage;
   1155 		log << TestLog::Message << "\tv2 (x=" << m_triangles[ndx].v2.x() << "\ty=" << m_triangles[ndx].v2.y() << "\tz=" << m_triangles[ndx].v2.z() << "\tw=" << m_triangles[ndx].v2.w() << ")\t" << v2Properties << TestLog::EndMessage;
   1156 		log << TestLog::Message << TestLog::EndMessage;
   1157 	}
   1158 
   1159 	ctx.clearColor					(0, 0, 0, 1);
   1160 	ctx.clearDepthf					(1.0f);
   1161 	ctx.clear						(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
   1162 	ctx.viewport					(m_viewport.left, m_viewport.bottom, m_viewport.width, m_viewport.height);
   1163 	ctx.useProgram					(programId);
   1164 	ctx.blendFunc					(GL_ONE, GL_ONE);
   1165 	ctx.enable						(GL_BLEND);
   1166 	ctx.enableVertexAttribArray		(positionLoc);
   1167 	ctx.enableVertexAttribArray		(colorLoc);
   1168 	ctx.vertexAttribPointer			(positionLoc,	4, GL_FLOAT, GL_FALSE, sizeof(GLfloat[8]), &m_triangles[0].v0);
   1169 	ctx.vertexAttribPointer			(colorLoc,		4, GL_FLOAT, GL_FALSE, sizeof(GLfloat[8]), &m_triangles[0].c0);
   1170 	ctx.drawArrays					(GL_TRIANGLES, 0, verticesPerTriangle * (glw::GLsizei)m_triangles.size());
   1171 	ctx.disableVertexAttribArray	(positionLoc);
   1172 	ctx.disableVertexAttribArray	(colorLoc);
   1173 	ctx.useProgram					(0);
   1174 	ctx.deleteProgram				(programId);
   1175 	ctx.finish						();
   1176 }
   1177 
   1178 class QuadFillTest : public TriangleFillTest
   1179 {
   1180 public:
   1181 	QuadFillTest (Context& context, const char* name, const char* description, const rr::WindowRectangle& viewport, const tcu::Vec3& d1, const tcu::Vec3& d2, const tcu::Vec3& center_ = tcu::Vec3(0, 0, 0));
   1182 };
   1183 
   1184 QuadFillTest::QuadFillTest (Context& context, const char* name, const char* description, const rr::WindowRectangle& viewport, const tcu::Vec3& d1, const tcu::Vec3& d2, const tcu::Vec3& center_)
   1185 	: TriangleFillTest(context, name, description, viewport)
   1186 {
   1187 	const float		radius		= 40000.0f;
   1188 	const tcu::Vec4 center		= tcu::Vec4(center_.x(), center_.y(), center_.z(), 1.0f);
   1189 	const tcu::Vec4 halfWhite	= tcu::Vec4(0.5f, 0.5f, 0.5f, 0.5f);
   1190 	const tcu::Vec4 halfRed		= tcu::Vec4(0.5f, 0.0f, 0.0f, 0.5f);
   1191 	const tcu::Vec4	e1			= radius * tcu::Vec4(d1.x(), d1.y(), d1.z(), 0.0f);
   1192 	const tcu::Vec4	e2			= radius * tcu::Vec4(d2.x(), d2.y(), d2.z(), 0.0f);
   1193 
   1194 	FillTriangle triangle1;
   1195 	FillTriangle triangle2;
   1196 
   1197 	triangle1.c0 = halfWhite;
   1198 	triangle1.c1 = halfWhite;
   1199 	triangle1.c2 = halfWhite;
   1200 	triangle1.v0 = center + e1 + e2;
   1201 	triangle1.v1 = center + e1 - e2;
   1202 	triangle1.v2 = center - e1 - e2;
   1203 	m_triangles.push_back(triangle1);
   1204 
   1205 	triangle2.c0 = halfRed;
   1206 	triangle2.c1 = halfRed;
   1207 	triangle2.c2 = halfRed;
   1208 	triangle2.v0 = center + e1 + e2;
   1209 	triangle2.v1 = center - e1 - e2;
   1210 	triangle2.v2 = center - e1 + e2;
   1211 	m_triangles.push_back(triangle2);
   1212 }
   1213 
   1214 class TriangleFanFillTest : public TriangleFillTest
   1215 {
   1216 public:
   1217 	TriangleFanFillTest (Context& context, const char* name, const char* description, const rr::WindowRectangle& viewport);
   1218 };
   1219 
   1220 TriangleFanFillTest::TriangleFanFillTest (Context& context, const char* name, const char* description, const rr::WindowRectangle& viewport)
   1221 	: TriangleFillTest(context, name, description, viewport)
   1222 {
   1223 	const float		radius				= 70000.0f;
   1224 	const int		trianglesPerVisit	= 40;
   1225 	const tcu::Vec4 center				= tcu::Vec4(0, 0, 0, 1.0f);
   1226 	const tcu::Vec4 halfWhite			= tcu::Vec4(0.5f, 0.5f, 0.5f, 0.5f);
   1227 	const tcu::Vec4 oddSliceColor		= tcu::Vec4(0.0f, 0.0f, 0.5f, 0.0f);
   1228 
   1229 	// create a continuous surface that goes through all 6 clip planes
   1230 
   1231 	/*
   1232 		*   /           /
   1233 		*  /_ _ _ _ _  /x
   1234 		* |           |  |
   1235 		* |           | /
   1236 		* |       / --xe /
   1237 		* |      |    | /
   1238 		* |_ _ _ e _ _|/
   1239 		*
   1240 		* e = enter
   1241 		* x = exit
   1242 		*/
   1243 	const struct ClipPlaneVisit
   1244 	{
   1245 		const tcu::Vec3 corner;
   1246 		const tcu::Vec3 entryPoint;
   1247 		const tcu::Vec3 exitPoint;
   1248 	} visits[] =
   1249 	{
   1250 		{ tcu::Vec3( 1, 1, 1),	tcu::Vec3( 0, 1, 1),	tcu::Vec3( 1, 0, 1) },
   1251 		{ tcu::Vec3( 1,-1, 1),	tcu::Vec3( 1, 0, 1),	tcu::Vec3( 1,-1, 0) },
   1252 		{ tcu::Vec3( 1,-1,-1),	tcu::Vec3( 1,-1, 0),	tcu::Vec3( 0,-1,-1) },
   1253 		{ tcu::Vec3(-1,-1,-1),	tcu::Vec3( 0,-1,-1),	tcu::Vec3(-1, 0,-1) },
   1254 		{ tcu::Vec3(-1, 1,-1),	tcu::Vec3(-1, 0,-1),	tcu::Vec3(-1, 1, 0) },
   1255 		{ tcu::Vec3(-1, 1, 1),	tcu::Vec3(-1, 1, 0),	tcu::Vec3( 0, 1, 1) },
   1256 	};
   1257 
   1258 	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(visits); ++ndx)
   1259 	{
   1260 		const ClipPlaneVisit& visit = visits[ndx];
   1261 
   1262 		for (int tri = 0; tri < trianglesPerVisit; ++tri)
   1263 		{
   1264 			tcu::Vec3 vertex0;
   1265 			tcu::Vec3 vertex1;
   1266 
   1267 			if (tri == 0) // first vertex is magic
   1268 			{
   1269 				vertex0 = visit.entryPoint;
   1270 			}
   1271 			else
   1272 			{
   1273 				const tcu::Vec3 v1 = visit.entryPoint - visit.corner;
   1274 				const tcu::Vec3 v2 = visit.exitPoint  - visit.corner;
   1275 
   1276 				vertex0 = visit.corner + tcu::normalize(tcu::mix(v1, v2, tcu::Vec3(float(tri)/trianglesPerVisit)));
   1277 			}
   1278 
   1279 			if (tri == trianglesPerVisit-1) // last vertex is magic
   1280 			{
   1281 				vertex1 = visit.exitPoint;
   1282 			}
   1283 			else
   1284 			{
   1285 				const tcu::Vec3 v1 = visit.entryPoint - visit.corner;
   1286 				const tcu::Vec3 v2 = visit.exitPoint  - visit.corner;
   1287 
   1288 				vertex1 = visit.corner + tcu::normalize(tcu::mix(v1, v2, tcu::Vec3(float(tri+1)/trianglesPerVisit)));
   1289 			}
   1290 
   1291 			// write vec out
   1292 			{
   1293 				FillTriangle triangle;
   1294 
   1295 				triangle.c0 = (tri % 2) ? halfWhite : halfWhite + oddSliceColor;
   1296 				triangle.c1 = (tri % 2) ? halfWhite : halfWhite + oddSliceColor;
   1297 				triangle.c2 = (tri % 2) ? halfWhite : halfWhite + oddSliceColor;
   1298 				triangle.v0 = center;
   1299 				triangle.v1 = tcu::Vec4(vertex0.x() * radius, vertex0.y() * radius, vertex0.z() * radius, 1.0f);
   1300 				triangle.v2 = tcu::Vec4(vertex1.x() * radius, vertex1.y() * radius, vertex1.z() * radius, 1.0f);
   1301 
   1302 				m_triangles.push_back(triangle);
   1303 			}
   1304 
   1305 		}
   1306 	}
   1307 }
   1308 
   1309 class PointsTestGroup : public TestCaseGroup
   1310 {
   1311 public:
   1312 			PointsTestGroup	(Context& context);
   1313 
   1314 	void	init			(void);
   1315 };
   1316 
   1317 PointsTestGroup::PointsTestGroup (Context& context)
   1318 	: TestCaseGroup(context, "point", "Point clipping tests")
   1319 {
   1320 }
   1321 
   1322 void PointsTestGroup::init (void)
   1323 {
   1324 	const float littleOverViewport = 1.0f + (2.0f / (TEST_CANVAS_SIZE)); // one pixel over the viewport edge in VIEWPORT_WHOLE, half pixels over in the reduced viewport.
   1325 
   1326 	const tcu::Vec4 viewportTestPoints[] =
   1327 	{
   1328 		// in clip volume
   1329 		tcu::Vec4( 0.0f,  0.0f,  0.0f,  1.0f),
   1330 		tcu::Vec4( 0.1f,  0.1f,  0.1f,  1.0f),
   1331 		tcu::Vec4(-0.1f,  0.1f, -0.1f,  1.0f),
   1332 		tcu::Vec4(-0.1f, -0.1f,  0.1f,  1.0f),
   1333 		tcu::Vec4( 0.1f, -0.1f, -0.1f,  1.0f),
   1334 
   1335 		// in clip volume with w != 1
   1336 		tcu::Vec4( 2.0f,  2.0f,  2.0f,  3.0f),
   1337 		tcu::Vec4(-2.0f, -2.0f,  2.0f,  3.0f),
   1338 		tcu::Vec4( 0.5f, -0.5f,  0.5f,  0.7f),
   1339 		tcu::Vec4(-0.5f,  0.5f, -0.5f,  0.7f),
   1340 
   1341 		// near the edge
   1342 		tcu::Vec4(-2.0f, -2.0f,  0.0f,  2.2f),
   1343 		tcu::Vec4( 1.0f, -1.0f,  0.0f,  1.1f),
   1344 		tcu::Vec4(-1.0f,  1.0f,  0.0f,  1.1f),
   1345 
   1346 		// not in the volume but still between near and far planes
   1347 		tcu::Vec4( 1.3f,  0.0f,  0.0f,  1.0f),
   1348 		tcu::Vec4(-1.3f,  0.0f,  0.0f,  1.0f),
   1349 		tcu::Vec4( 0.0f,  1.3f,  0.0f,  1.0f),
   1350 		tcu::Vec4( 0.0f, -1.3f,  0.0f,  1.0f),
   1351 
   1352 		tcu::Vec4(-1.3f, -1.3f,  0.0f,  1.0f),
   1353 		tcu::Vec4(-1.3f,  1.3f,  0.0f,  1.0f),
   1354 		tcu::Vec4( 1.3f,  1.3f,  0.0f,  1.0f),
   1355 		tcu::Vec4( 1.3f, -1.3f,  0.0f,  1.0f),
   1356 
   1357 		// outside the viewport, wide points have fragments in the viewport
   1358 		tcu::Vec4( littleOverViewport,  littleOverViewport,  0.0f,  1.0f),
   1359 		tcu::Vec4(               0.0f,  littleOverViewport,  0.0f,  1.0f),
   1360 		tcu::Vec4( littleOverViewport,                0.0f,  0.0f,  1.0f),
   1361 	};
   1362 	const tcu::Vec4 depthTestPoints[] =
   1363 	{
   1364 		// in clip volume
   1365 		tcu::Vec4( 0.0f,  0.0f,  0.0f,  1.0f),
   1366 		tcu::Vec4( 0.1f,  0.1f,  0.1f,  1.0f),
   1367 		tcu::Vec4(-0.1f,  0.1f, -0.1f,  1.0f),
   1368 		tcu::Vec4(-0.1f, -0.1f,  0.1f,  1.0f),
   1369 		tcu::Vec4( 0.1f, -0.1f, -0.1f,  1.0f),
   1370 
   1371 		// not between the near and the far planes. These should be clipped
   1372 		tcu::Vec4( 0.1f,  0.0f,  1.1f,  1.0f),
   1373 		tcu::Vec4(-0.1f,  0.0f, -1.1f,  1.0f),
   1374 		tcu::Vec4(-0.0f, -0.1f,  1.1f,  1.0f),
   1375 		tcu::Vec4( 0.0f,  0.1f, -1.1f,  1.0f)
   1376 	};
   1377 
   1378 	addChild(new PointCase(m_context, "point_z_clip",						"point z clipping",				DE_ARRAY_BEGIN(depthTestPoints),	DE_ARRAY_END(depthTestPoints),		1.0f,	VIEWPORT_WHOLE));
   1379 	addChild(new PointCase(m_context, "point_z_clip_viewport_center",		"point z clipping",				DE_ARRAY_BEGIN(depthTestPoints),	DE_ARRAY_END(depthTestPoints),		1.0f,	VIEWPORT_CENTER));
   1380 	addChild(new PointCase(m_context, "point_z_clip_viewport_corner",		"point z clipping",				DE_ARRAY_BEGIN(depthTestPoints),	DE_ARRAY_END(depthTestPoints),		1.0f,	VIEWPORT_CORNER));
   1381 
   1382 	addChild(new PointCase(m_context, "point_clip_viewport_center",			"point viewport clipping",		DE_ARRAY_BEGIN(viewportTestPoints), DE_ARRAY_END(viewportTestPoints),	1.0f,	VIEWPORT_CENTER));
   1383 	addChild(new PointCase(m_context, "point_clip_viewport_corner",			"point viewport clipping",		DE_ARRAY_BEGIN(viewportTestPoints), DE_ARRAY_END(viewportTestPoints),	1.0f,	VIEWPORT_CORNER));
   1384 
   1385 	addChild(new PointCase(m_context, "wide_point_z_clip",					"point z clipping",				DE_ARRAY_BEGIN(depthTestPoints),	DE_ARRAY_END(depthTestPoints),		5.0f,	VIEWPORT_WHOLE));
   1386 	addChild(new PointCase(m_context, "wide_point_z_clip_viewport_center",	"point z clipping",				DE_ARRAY_BEGIN(depthTestPoints),	DE_ARRAY_END(depthTestPoints),		5.0f,	VIEWPORT_CENTER));
   1387 	addChild(new PointCase(m_context, "wide_point_z_clip_viewport_corner",	"point z clipping",				DE_ARRAY_BEGIN(depthTestPoints),	DE_ARRAY_END(depthTestPoints),		5.0f,	VIEWPORT_CORNER));
   1388 
   1389 	addChild(new PointCase(m_context, "wide_point_clip",					"point viewport clipping",		DE_ARRAY_BEGIN(viewportTestPoints), DE_ARRAY_END(viewportTestPoints),	5.0f,	VIEWPORT_WHOLE));
   1390 	addChild(new PointCase(m_context, "wide_point_clip_viewport_center",	"point viewport clipping",		DE_ARRAY_BEGIN(viewportTestPoints), DE_ARRAY_END(viewportTestPoints),	5.0f,	VIEWPORT_CENTER));
   1391 	addChild(new PointCase(m_context, "wide_point_clip_viewport_corner",	"point viewport clipping",		DE_ARRAY_BEGIN(viewportTestPoints), DE_ARRAY_END(viewportTestPoints),	5.0f,	VIEWPORT_CORNER));
   1392 }
   1393 
   1394 class LinesTestGroup : public TestCaseGroup
   1395 {
   1396 public:
   1397 			LinesTestGroup	(Context& context);
   1398 
   1399 	void	init			(void);
   1400 };
   1401 
   1402 LinesTestGroup::LinesTestGroup (Context& context)
   1403 	: TestCaseGroup(context, "line", "Line clipping tests")
   1404 {
   1405 }
   1406 
   1407 void LinesTestGroup::init (void)
   1408 {
   1409 	const float littleOverViewport = 1.0f + (2.0f / (TEST_CANVAS_SIZE)); // one pixel over the viewport edge in VIEWPORT_WHOLE, half pixels over in the reduced viewport.
   1410 
   1411 	// lines
   1412 	const LineRenderTestCase::ColorlessLineData viewportTestLines[] =
   1413 	{
   1414 		// from center to outside of viewport
   1415 		{tcu::Vec4( 0.0f,  0.0f,  0.0f,  1.0f),		tcu::Vec4( 0.0f,  1.5f,  0.0f,  1.0f)},
   1416 		{tcu::Vec4( 0.0f,  0.0f,  0.0f,  1.0f),		tcu::Vec4(-1.5f,  1.0f,  0.0f,  1.0f)},
   1417 		{tcu::Vec4( 0.0f,  0.0f,  0.0f,  1.0f),		tcu::Vec4(-1.5f,  0.0f,  0.0f,  1.0f)},
   1418 		{tcu::Vec4( 0.0f,  0.0f,  0.0f,  1.0f),		tcu::Vec4( 0.2f,  0.4f,  1.5f,  1.0f)},
   1419 		{tcu::Vec4( 0.0f,  0.0f,  0.0f,  1.0f),		tcu::Vec4(-2.0f, -1.0f,  0.0f,  1.0f)},
   1420 		{tcu::Vec4( 0.0f,  0.0f,  0.0f,  1.0f),		tcu::Vec4( 1.0f,  0.1f,  0.0f,  0.6f)},
   1421 
   1422 		// from outside to inside of viewport
   1423 		{tcu::Vec4( 1.5f,  0.0f,  0.0f,  1.0f),		tcu::Vec4( 0.8f, -0.2f,  0.0f,  1.0f)},
   1424 		{tcu::Vec4( 0.0f, -1.5f,  0.0f,  1.0f),		tcu::Vec4( 0.9f, -0.7f,  0.0f,  1.0f)},
   1425 
   1426 		// from outside to outside
   1427 		{tcu::Vec4( 0.0f, -1.3f,  0.0f,  1.0f),		tcu::Vec4( 1.3f,  0.0f,  0.0f,  1.0f)},
   1428 
   1429 		// outside the viewport, wide lines have fragments in the viewport
   1430 		{tcu::Vec4(-0.8f,                      -littleOverViewport,  0.0f,  1.0f),	tcu::Vec4( 0.0f, -littleOverViewport,         0.0f,  1.0f)},
   1431 		{tcu::Vec4(-littleOverViewport - 1.0f,  0.0f,                0.0f,  1.0f),	tcu::Vec4( 0.0f, -littleOverViewport - 1.0f,  0.0f,  1.0f)},
   1432 	};
   1433 	const LineRenderTestCase::ColorlessLineData depthTestLines[] =
   1434 	{
   1435 		{tcu::Vec4( 0.0f,  0.0f,  0.0f,  1.0f),		tcu::Vec4( 1.3f,  1.0f,  2.0f,  1.0f)},
   1436 		{tcu::Vec4( 0.0f,  0.0f,  0.0f,  1.0f),		tcu::Vec4( 1.3f, -1.0f,  2.0f,  1.0f)},
   1437 		{tcu::Vec4( 0.0f,  0.0f,  0.0f,  1.0f),		tcu::Vec4(-1.0f, -1.1f, -2.0f,  1.0f)},
   1438 		{tcu::Vec4( 0.0f,  0.0f,  0.0f,  1.0f),		tcu::Vec4(-1.0f,  1.1f, -2.0f,  1.0f)},
   1439 		{tcu::Vec4( 0.0f,  0.0f,  0.0f,  1.0f),		tcu::Vec4( 1.0f,  0.1f,  2.0f,  0.6f)},
   1440 	};
   1441 	const LineRenderTestCase::ColorlessLineData longTestLines[] =
   1442 	{
   1443 		{tcu::Vec4( -41000.0f,		-40000.0f,		-1000000.0f,	1.0f),	tcu::Vec4( 41000.0f,		40000.0f,		1000000.0f,	1.0f)},
   1444 		{tcu::Vec4(  41000.0f,		-40000.0f,		 1000000.0f,	1.0f),	tcu::Vec4(-41000.0f,		40000.0f,	   -1000000.0f,	1.0f)},
   1445 		{tcu::Vec4(  0.5f,			-40000.0f,		 100000.0f,		1.0f),	tcu::Vec4( 0.5f,			40000.0f,	   -100000.0f,	1.0f)},
   1446 		{tcu::Vec4( -0.5f,			 40000.0f,		 100000.0f,		1.0f),	tcu::Vec4(-0.5f,		   -40000.0f,	   -100000.0f,	1.0f)},
   1447 	};
   1448 
   1449 	// line attribute clipping
   1450 	const tcu::Vec4 red			(1.0f, 0.0f, 0.0f, 1.0f);
   1451 	const tcu::Vec4 yellow		(1.0f, 1.0f, 0.0f, 1.0f);
   1452 	const tcu::Vec4 lightBlue	(0.3f, 0.3f, 1.0f, 1.0f);
   1453 	const LineRenderTestCase::ColoredLineData colorTestLines[] =
   1454 	{
   1455 		{tcu::Vec4( 0.0f,  0.0f,  0.0f,  1.0f),	red,	tcu::Vec4( 1.3f,  1.0f,  2.0f,  1.0f),	yellow		},
   1456 		{tcu::Vec4( 0.0f,  0.0f,  0.0f,  1.0f),	red,	tcu::Vec4( 1.3f, -1.0f,  2.0f,  1.0f),	lightBlue	},
   1457 		{tcu::Vec4( 0.0f,  0.0f,  0.0f,  1.0f),	red,	tcu::Vec4(-1.0f, -1.0f, -2.0f,  1.0f),	yellow		},
   1458 		{tcu::Vec4( 0.0f,  0.0f,  0.0f,  1.0f),	red,	tcu::Vec4(-1.0f,  1.0f, -2.0f,  1.0f),	lightBlue	},
   1459 	};
   1460 
   1461 	// line clipping
   1462 	addChild(new LineCase(m_context, "line_z_clip",							"line z clipping",				DE_ARRAY_BEGIN(depthTestLines),		DE_ARRAY_END(depthTestLines),		1.0f,	VIEWPORT_WHOLE));
   1463 	addChild(new LineCase(m_context, "line_z_clip_viewport_center",			"line z clipping",				DE_ARRAY_BEGIN(depthTestLines),		DE_ARRAY_END(depthTestLines),		1.0f,	VIEWPORT_CENTER));
   1464 	addChild(new LineCase(m_context, "line_z_clip_viewport_corner",			"line z clipping",				DE_ARRAY_BEGIN(depthTestLines),		DE_ARRAY_END(depthTestLines),		1.0f,	VIEWPORT_CORNER));
   1465 
   1466 	addChild(new LineCase(m_context, "line_clip_viewport_center",			"line viewport clipping",		DE_ARRAY_BEGIN(viewportTestLines),	DE_ARRAY_END(viewportTestLines),	1.0f,	VIEWPORT_CENTER));
   1467 	addChild(new LineCase(m_context, "line_clip_viewport_corner",			"line viewport clipping",		DE_ARRAY_BEGIN(viewportTestLines),	DE_ARRAY_END(viewportTestLines),	1.0f,	VIEWPORT_CORNER));
   1468 
   1469 	addChild(new LineCase(m_context, "wide_line_z_clip",					"line z clipping",				DE_ARRAY_BEGIN(depthTestLines),		DE_ARRAY_END(depthTestLines),		5.0f,	VIEWPORT_WHOLE));
   1470 	addChild(new LineCase(m_context, "wide_line_z_clip_viewport_center",	"line z clipping",				DE_ARRAY_BEGIN(depthTestLines),		DE_ARRAY_END(depthTestLines),		5.0f,	VIEWPORT_CENTER));
   1471 	addChild(new LineCase(m_context, "wide_line_z_clip_viewport_corner",	"line z clipping",				DE_ARRAY_BEGIN(depthTestLines),		DE_ARRAY_END(depthTestLines),		5.0f,	VIEWPORT_CORNER));
   1472 
   1473 	addChild(new LineCase(m_context, "wide_line_clip",						"line viewport clipping",		DE_ARRAY_BEGIN(viewportTestLines),	DE_ARRAY_END(viewportTestLines),	5.0f,	VIEWPORT_WHOLE));
   1474 	addChild(new LineCase(m_context, "wide_line_clip_viewport_center",		"line viewport clipping",		DE_ARRAY_BEGIN(viewportTestLines),	DE_ARRAY_END(viewportTestLines),	5.0f,	VIEWPORT_CENTER));
   1475 	addChild(new LineCase(m_context, "wide_line_clip_viewport_corner",		"line viewport clipping",		DE_ARRAY_BEGIN(viewportTestLines),	DE_ARRAY_END(viewportTestLines),	5.0f,	VIEWPORT_CORNER));
   1476 
   1477 	addChild(new LineCase(m_context, "long_line_clip",						"line viewport clipping",		DE_ARRAY_BEGIN(longTestLines),		DE_ARRAY_END(longTestLines),		1.0f,	VIEWPORT_WHOLE, 2));
   1478 	addChild(new LineCase(m_context, "long_wide_line_clip",					"line viewport clipping",		DE_ARRAY_BEGIN(longTestLines),		DE_ARRAY_END(longTestLines),		5.0f,	VIEWPORT_WHOLE, 2));
   1479 
   1480 	// line attribute clipping
   1481 	addChild(new ColoredLineCase(m_context, "line_attrib_clip",				"line attribute clipping",		DE_ARRAY_BEGIN(colorTestLines),		DE_ARRAY_END(colorTestLines),		1.0f,	VIEWPORT_WHOLE));
   1482 	addChild(new ColoredLineCase(m_context, "wide_line_attrib_clip",		"line attribute clipping",		DE_ARRAY_BEGIN(colorTestLines),		DE_ARRAY_END(colorTestLines),		5.0f,	VIEWPORT_WHOLE));
   1483 }
   1484 
   1485 class PolysTestGroup : public TestCaseGroup
   1486 {
   1487 public:
   1488 			PolysTestGroup	(Context& context);
   1489 
   1490 	void	init			(void);
   1491 };
   1492 
   1493 PolysTestGroup::PolysTestGroup (Context& context)
   1494 	: TestCaseGroup(context, "polygon", "Polygon clipping tests")
   1495 {
   1496 }
   1497 
   1498 void PolysTestGroup::init (void)
   1499 {
   1500 	const float		large = 100000.0f;
   1501 	const float		offset = 0.9f;
   1502 	const tcu::Vec4 white	(1.0f, 1.0f, 1.0f, 1.0f);
   1503 	const tcu::Vec4 red		(1.0f, 0.0f, 0.0f, 1.0f);
   1504 	const tcu::Vec4 yellow	(1.0f, 1.0f, 0.0f, 1.0f);
   1505 	const tcu::Vec4 blue	(0.0f, 0.0f, 1.0f, 1.0f);
   1506 
   1507 	// basic cases
   1508 	{
   1509 		const TriangleCase::TriangleData viewportPolys[] =
   1510 		{
   1511 			// one vertex clipped
   1512 			{tcu::Vec4(-0.8f, -0.2f,  0.0f,  1.0f), white, tcu::Vec4(-0.8f,  0.2f,  0.0f,  1.0f), white, tcu::Vec4(-1.3f,  0.05f,  0.0f,  1.0f), white},
   1513 
   1514 			// two vertices clipped
   1515 			{tcu::Vec4(-0.6f, -1.2f,  0.0f,  1.0f), white, tcu::Vec4(-1.2f, -0.6f,  0.0f,  1.0f), white, tcu::Vec4(-0.6f, -0.6f,  0.0f,  1.0f), white},
   1516 
   1517 			// three vertices clipped
   1518 			{tcu::Vec4(-1.1f,  0.6f,  0.0f,  1.0f), white, tcu::Vec4(-1.1f,  1.1f,  0.0f,  1.0f), white, tcu::Vec4(-0.6f,  1.1f,  0.0f,  1.0f), white},
   1519 			{tcu::Vec4( 0.8f,  1.1f,  0.0f,  1.0f), white, tcu::Vec4( 0.95f,-1.1f,  0.0f,  1.0f), white, tcu::Vec4( 3.0f,  0.0f,  0.0f,  1.0f), white},
   1520 		};
   1521 		const TriangleCase::TriangleData depthPolys[] =
   1522 		{
   1523 			// one vertex clipped to Z+
   1524 			{tcu::Vec4(-0.2f,  0.7f,  0.0f,  1.0f), white, tcu::Vec4( 0.2f,  0.7f,  0.0f,  1.0f), white, tcu::Vec4( 0.0f,  0.9f,  2.0f,  1.0f), white},
   1525 
   1526 			// two vertices clipped to Z-
   1527 			{tcu::Vec4( 0.9f, 0.4f,  -1.5f,  1.0f), white, tcu::Vec4( 0.9f, -0.4f, -1.5f,  1.0f), white, tcu::Vec4( 0.6f,  0.0f,  0.0f,  1.0f), white},
   1528 
   1529 			// three vertices clipped
   1530 			{tcu::Vec4(-0.9f, 0.6f,  -2.0f,  1.0f), white, tcu::Vec4(-0.9f, -0.6f, -2.0f,  1.0f), white, tcu::Vec4(-0.4f,  0.0f,  2.0f,  1.0f), white},
   1531 
   1532 			// three vertices clipped by X, Y and Z
   1533 			{tcu::Vec4( 0.0f, -1.2f,  0.0f,  1.0f), white, tcu::Vec4( 0.0f,  0.5f,  -1.5f, 1.0f), white, tcu::Vec4( 1.2f, -0.9f,  0.0f,  1.0f), white},
   1534 		};
   1535 		const TriangleCase::TriangleData largePolys[] =
   1536 		{
   1537 			// one vertex clipped
   1538 			{tcu::Vec4(-0.2f,  -0.3f,  0.0f,  1.0f), white, tcu::Vec4( 0.2f, -0.3f,  0.0f,  1.0f), white, tcu::Vec4( 0.0f, -large,  2.0f,  1.0f), white},
   1539 
   1540 			// two vertices clipped
   1541 			{tcu::Vec4( 0.5f, 0.5f,  0.0f,  1.0f), white, tcu::Vec4( large, 0.5f, 0.0f,  1.0f), white, tcu::Vec4( 0.5f,  large,  0.0f,  1.0f), white},
   1542 
   1543 			// three vertices clipped
   1544 			{tcu::Vec4(-0.9f, -large, 0.0f,  1.0f), white, tcu::Vec4(-1.1f, -large, 0.0f,  1.0f), white, tcu::Vec4(-0.9f,  large,  0.0f,  1.0f), white},
   1545 		};
   1546 		const TriangleCase::TriangleData largeDepthPolys[] =
   1547 		{
   1548 			// one vertex clipped
   1549 			{tcu::Vec4(-0.2f,  -0.3f,  0.0f,  1.0f), white, tcu::Vec4( 0.2f, -0.3f,  0.0f,  1.0f), white, tcu::Vec4( 0.0f, -large, large,  1.0f), white},
   1550 
   1551 			// two vertices clipped
   1552 			{tcu::Vec4( 0.5f, 0.5f,  0.0f,  1.0f), white, tcu::Vec4( 0.9f, large/2, -large,  1.0f), white, tcu::Vec4( large/4, 0.0f, -large,  1.0f), white},
   1553 
   1554 			// three vertices clipped
   1555 			{tcu::Vec4(-0.9f, large/4, large,  1.0f), white, tcu::Vec4(-0.5f, -large/4, -large,  1.0f), white, tcu::Vec4(-0.2f, large/4, large,  1.0f), white},
   1556 		};
   1557 		const TriangleCase::TriangleData attribPolys[] =
   1558 		{
   1559 			// one vertex clipped to edge, large
   1560 			{tcu::Vec4(-0.2f,  -0.3f,  0.0f,  1.0f), red, tcu::Vec4( 0.2f, -0.3f,  0.0f,  1.0f), yellow, tcu::Vec4( 0.0f, -large,  2.0f,  1.0f), blue},
   1561 
   1562 			// two vertices clipped to edges
   1563 			{tcu::Vec4( 0.6f,  1.2f,  0.0f,  1.0f), red, tcu::Vec4( 1.2f,  0.6f,  0.0f,  1.0f), yellow, tcu::Vec4( 0.6f,  0.6f,  0.0f,  1.0f), blue},
   1564 
   1565 			// two vertices clipped to edges, with non-uniform w
   1566 			{tcu::Vec4( 0.6f, -1.2f,  0.0f,  1.0f), red, tcu::Vec4( 1.2f, -0.6f,  0.0f,  1.0f), yellow, 16.0f*tcu::Vec4( 0.6f, -0.6f,  0.0f,  1.0f), blue},
   1567 
   1568 			// three vertices clipped, large, Z
   1569 			{tcu::Vec4(-0.9f, large/4, large,  1.0f), red, tcu::Vec4(-0.5f, -large/4, -large,  1.0f), yellow, tcu::Vec4(-0.2f, large/4, large,  1.0f), blue},
   1570 		};
   1571 
   1572 		addChild(new TriangleCase(m_context, "poly_clip_viewport_center",			"polygon viewport clipping",	DE_ARRAY_BEGIN(viewportPolys),		DE_ARRAY_END(viewportPolys),	VIEWPORT_CENTER));
   1573 		addChild(new TriangleCase(m_context, "poly_clip_viewport_corner",			"polygon viewport clipping",	DE_ARRAY_BEGIN(viewportPolys),		DE_ARRAY_END(viewportPolys),	VIEWPORT_CORNER));
   1574 
   1575 		addChild(new TriangleCase(m_context, "poly_z_clip",							"polygon z clipping",			DE_ARRAY_BEGIN(depthPolys),			DE_ARRAY_END(depthPolys),		VIEWPORT_WHOLE));
   1576 		addChild(new TriangleCase(m_context, "poly_z_clip_viewport_center",			"polygon z clipping",			DE_ARRAY_BEGIN(depthPolys),			DE_ARRAY_END(depthPolys),		VIEWPORT_CENTER));
   1577 		addChild(new TriangleCase(m_context, "poly_z_clip_viewport_corner",			"polygon z clipping",			DE_ARRAY_BEGIN(depthPolys),			DE_ARRAY_END(depthPolys),		VIEWPORT_CORNER));
   1578 
   1579 		addChild(new TriangleCase(m_context, "large_poly_clip_viewport_center",		"polygon viewport clipping",	DE_ARRAY_BEGIN(largePolys),			DE_ARRAY_END(largePolys),		VIEWPORT_CENTER));
   1580 		addChild(new TriangleCase(m_context, "large_poly_clip_viewport_corner",		"polygon viewport clipping",	DE_ARRAY_BEGIN(largePolys),			DE_ARRAY_END(largePolys),		VIEWPORT_CORNER));
   1581 
   1582 		addChild(new TriangleCase(m_context, "large_poly_z_clip",					"polygon z clipping",			DE_ARRAY_BEGIN(largeDepthPolys),	DE_ARRAY_END(largeDepthPolys),	VIEWPORT_WHOLE));
   1583 		addChild(new TriangleCase(m_context, "large_poly_z_clip_viewport_center",	"polygon z clipping",			DE_ARRAY_BEGIN(largeDepthPolys),	DE_ARRAY_END(largeDepthPolys),	VIEWPORT_CENTER));
   1584 		addChild(new TriangleCase(m_context, "large_poly_z_clip_viewport_corner",	"polygon z clipping",			DE_ARRAY_BEGIN(largeDepthPolys),	DE_ARRAY_END(largeDepthPolys),	VIEWPORT_CORNER));
   1585 
   1586 		addChild(new TriangleAttributeCase(m_context, "poly_attrib_clip",					"polygon clipping",		DE_ARRAY_BEGIN(attribPolys),		DE_ARRAY_END(attribPolys),		VIEWPORT_WHOLE));
   1587 		addChild(new TriangleAttributeCase(m_context, "poly_attrib_clip_viewport_center",	"polygon clipping",		DE_ARRAY_BEGIN(attribPolys),		DE_ARRAY_END(attribPolys),		VIEWPORT_CENTER));
   1588 		addChild(new TriangleAttributeCase(m_context, "poly_attrib_clip_viewport_corner",	"polygon clipping",		DE_ARRAY_BEGIN(attribPolys),		DE_ARRAY_END(attribPolys),		VIEWPORT_CORNER));
   1589 	}
   1590 
   1591 	// multiple polygons
   1592 	{
   1593 		{
   1594 			const TriangleAttributeCase::TriangleData polys[] =
   1595 			{
   1596 				// one vertex clipped to edge
   1597 				{tcu::Vec4(-0.2f,  -0.3f,  0.0f,  1.0f), red, tcu::Vec4( 0.2f, -0.3f,  0.0f,  1.0f), yellow, tcu::Vec4( 0.0f, -offset,  2.0f,  1.0f), blue},
   1598 
   1599 				// two vertices clipped to edges
   1600 				{tcu::Vec4( 0.6f,  1.2f,  0.0f,  1.0f), red, tcu::Vec4( 1.2f,  0.6f,  0.0f,  1.0f), yellow, tcu::Vec4( 0.6f,  0.6f,  0.0f,  1.0f), blue},
   1601 
   1602 				// two vertices clipped to edges, with non-uniform w
   1603 				{tcu::Vec4( 0.6f, -1.2f,  0.0f,  1.0f), red, tcu::Vec4( 1.2f, -0.6f,  0.0f,  1.0f), yellow, 16.0f*tcu::Vec4( 0.6f, -0.6f,  0.0f,  1.0f), blue},
   1604 				{tcu::Vec4( 0.6f,  1.2f,  0.0f,  1.0f), red, tcu::Vec4( 1.2f,  0.6f,  0.0f,  1.0f), yellow, 16.0f*tcu::Vec4( 0.6f,  0.6f,  0.0f,  1.0f), blue},
   1605 				{tcu::Vec4(-0.6f,  1.2f,  0.0f,  1.0f), red, tcu::Vec4(-1.2f,  0.6f,  0.0f,  1.0f), yellow, 16.0f*tcu::Vec4(-0.6f,  0.6f,  0.0f,  1.0f), blue},
   1606 				{tcu::Vec4(-0.6f, -1.2f,  0.0f,  1.0f), red, tcu::Vec4(-1.2f, -0.6f,  0.0f,  1.0f), yellow, 16.0f*tcu::Vec4(-0.6f, -0.6f,  0.0f,  1.0f), blue},
   1607 
   1608 				// three vertices clipped, Z
   1609 				{tcu::Vec4(-0.9f, offset/4, offset,  1.0f), red, tcu::Vec4(-0.5f, -offset/4, -offset,  1.0f), yellow, tcu::Vec4(-0.2f, offset/4, offset,  1.0f), blue},
   1610 			};
   1611 
   1612 			addChild(new TriangleAttributeCase(m_context, "multiple_0",					"polygon clipping",		DE_ARRAY_BEGIN(polys),		DE_ARRAY_END(polys),		VIEWPORT_WHOLE));
   1613 			addChild(new TriangleAttributeCase(m_context, "multiple_0_viewport_center",	"polygon clipping",		DE_ARRAY_BEGIN(polys),		DE_ARRAY_END(polys),		VIEWPORT_CENTER));
   1614 			addChild(new TriangleAttributeCase(m_context, "multiple_0_viewport_corner",	"polygon clipping",		DE_ARRAY_BEGIN(polys),		DE_ARRAY_END(polys),		VIEWPORT_CORNER));
   1615 		}
   1616 
   1617 		{
   1618 			const TriangleAttributeCase::TriangleData polys[] =
   1619 			{
   1620 				// one vertex clipped to z
   1621 				{tcu::Vec4(-0.2f,  -0.3f,  0.0f,  1.0f), red, tcu::Vec4( 0.2f, -0.3f,  0.0f,  1.0f), yellow, tcu::Vec4( 0.0f, -offset,  2.0f,  1.0f), blue},
   1622 
   1623 				// two vertices clipped to edges
   1624 				{tcu::Vec4( 0.6f,  1.2f,  0.0f,  1.0f), red, tcu::Vec4( 1.2f,  0.6f,  0.0f,  1.0f), yellow, tcu::Vec4( 0.6f,  0.6f,  0.0f,  1.0f), blue},
   1625 
   1626 				// two vertices clipped to edges, with non-uniform w
   1627 				{tcu::Vec4( 0.6f, -1.2f,  0.0f,  1.0f), red, tcu::Vec4( 1.2f, -0.6f,  0.0f,  1.0f), yellow, 16.0f*tcu::Vec4( 0.6f, -0.6f,  0.0f,  1.0f), blue},
   1628 				{tcu::Vec4( 0.6f,  1.2f,  0.0f,  1.0f), red, tcu::Vec4( 1.2f,  0.6f,  0.0f,  1.0f), yellow, 16.0f*tcu::Vec4( 0.6f,  0.6f,  0.0f,  1.0f), blue},
   1629 				{tcu::Vec4(-0.6f,  1.2f,  0.0f,  1.0f), red, tcu::Vec4(-1.2f,  0.6f,  0.0f,  1.0f), yellow, 16.0f*tcu::Vec4(-0.6f,  0.6f,  0.0f,  1.0f), blue},
   1630 				{tcu::Vec4(-0.6f, -1.2f,  0.0f,  1.0f), red, tcu::Vec4(-1.2f, -0.6f,  0.0f,  1.0f), yellow, 16.0f*tcu::Vec4(-0.6f, -0.6f,  0.0f,  1.0f), blue},
   1631 			};
   1632 
   1633 			addChild(new TriangleAttributeCase(m_context, "multiple_1",					"polygon clipping",		DE_ARRAY_BEGIN(polys),		DE_ARRAY_END(polys),		VIEWPORT_WHOLE));
   1634 			addChild(new TriangleAttributeCase(m_context, "multiple_1_viewport_center",	"polygon clipping",		DE_ARRAY_BEGIN(polys),		DE_ARRAY_END(polys),		VIEWPORT_CENTER));
   1635 			addChild(new TriangleAttributeCase(m_context, "multiple_1_viewport_corner",	"polygon clipping",		DE_ARRAY_BEGIN(polys),		DE_ARRAY_END(polys),		VIEWPORT_CORNER));
   1636 		}
   1637 
   1638 		{
   1639 			const TriangleAttributeCase::TriangleData polys[] =
   1640 			{
   1641 				// one vertex clipped to z
   1642 				{tcu::Vec4(-0.2f,  -0.3f,  0.0f,  1.0f), red, tcu::Vec4( 0.2f, -0.3f,  0.0f,  1.0f), yellow, tcu::Vec4( 0.0f, -offset,  2.0f,  1.0f), blue},
   1643 
   1644 				// two vertices clipped to edges
   1645 				{tcu::Vec4( 0.6f,  1.2f,  0.0f,  1.0f), red, tcu::Vec4( 1.2f,  0.6f,  0.0f,  1.0f), yellow, tcu::Vec4( 0.6f,  0.6f,  0.0f,  1.0f), blue},
   1646 
   1647 				// two vertices clipped to edges
   1648 				{tcu::Vec4( 0.6f, -1.2f,  0.0f,  1.0f), red, tcu::Vec4( 1.2f, -0.6f,  0.0f,  1.0f), yellow, tcu::Vec4( 0.6f, -0.6f,  0.0f,  1.0f), blue},
   1649 				{tcu::Vec4( 0.6f,  1.2f,  0.0f,  1.0f), red, tcu::Vec4( 1.2f,  0.6f,  0.0f,  1.0f), yellow, tcu::Vec4( 0.6f,  0.6f,  0.0f,  1.0f), blue},
   1650 				{tcu::Vec4(-0.6f,  1.2f,  0.0f,  1.0f), red, tcu::Vec4(-1.2f,  0.6f,  0.0f,  1.0f), yellow, tcu::Vec4(-0.6f,  0.6f,  0.0f,  1.0f), blue},
   1651 				{tcu::Vec4(-0.6f, -1.2f,  0.0f,  1.0f), red, tcu::Vec4(-1.2f, -0.6f,  0.0f,  1.0f), yellow, tcu::Vec4(-0.6f, -0.6f,  0.0f,  1.0f), blue},
   1652 			};
   1653 
   1654 			addChild(new TriangleAttributeCase(m_context, "multiple_2",					"polygon clipping",		DE_ARRAY_BEGIN(polys),		DE_ARRAY_END(polys),		VIEWPORT_WHOLE));
   1655 			addChild(new TriangleAttributeCase(m_context, "multiple_2_viewport_center",	"polygon clipping",		DE_ARRAY_BEGIN(polys),		DE_ARRAY_END(polys),		VIEWPORT_CENTER));
   1656 			addChild(new TriangleAttributeCase(m_context, "multiple_2_viewport_corner",	"polygon clipping",		DE_ARRAY_BEGIN(polys),		DE_ARRAY_END(polys),		VIEWPORT_CORNER));
   1657 		}
   1658 
   1659 		{
   1660 			const TriangleAttributeCase::TriangleData polys[] =
   1661 			{
   1662 				// one vertex clipped to z
   1663 				{tcu::Vec4(-0.2f,  -0.3f,  0.0f,  1.0f), red, tcu::Vec4( 0.2f, -0.3f,  0.0f,  1.0f), yellow, tcu::Vec4( 0.0f, -offset, -2.0f,  1.0f), blue},
   1664 
   1665 				// two vertices clipped to edges
   1666 				{tcu::Vec4( 0.6f, -1.2f,  0.0f,  1.0f), red, tcu::Vec4( 1.2f, -0.6f,  0.0f,  1.0f), yellow, tcu::Vec4( 0.6f, -0.6f,  0.0f,  1.0f), blue},
   1667 				{tcu::Vec4( 0.6f,  1.2f,  0.0f,  1.0f), red, tcu::Vec4( 1.2f,  0.6f,  0.0f,  1.0f), yellow, tcu::Vec4( 0.6f,  0.6f,  0.0f,  1.0f), blue},
   1668 				{tcu::Vec4(-0.6f,  1.2f,  0.0f,  1.0f), red, tcu::Vec4(-1.2f,  0.6f,  0.0f,  1.0f), yellow, tcu::Vec4(-0.6f,  0.6f,  0.0f,  1.0f), blue},
   1669 				{tcu::Vec4(-0.6f, -1.2f,  0.0f,  1.0f), red, tcu::Vec4(-1.2f, -0.6f,  0.0f,  1.0f), yellow, tcu::Vec4(-0.6f, -0.6f,  0.0f,  1.0f), blue},
   1670 			};
   1671 
   1672 			addChild(new TriangleAttributeCase(m_context, "multiple_3",					"polygon clipping",		DE_ARRAY_BEGIN(polys),		DE_ARRAY_END(polys),		VIEWPORT_WHOLE));
   1673 			addChild(new TriangleAttributeCase(m_context, "multiple_3_viewport_center",	"polygon clipping",		DE_ARRAY_BEGIN(polys),		DE_ARRAY_END(polys),		VIEWPORT_CENTER));
   1674 			addChild(new TriangleAttributeCase(m_context, "multiple_3_viewport_corner",	"polygon clipping",		DE_ARRAY_BEGIN(polys),		DE_ARRAY_END(polys),		VIEWPORT_CORNER));
   1675 		}
   1676 
   1677 		{
   1678 			const TriangleAttributeCase::TriangleData polys[] =
   1679 			{
   1680 				// one vertex clipped to z
   1681 				{tcu::Vec4(0.3f,  0.2f,  0.0f,  1.0f), red, tcu::Vec4( 0.3f, -0.2f,  0.0f,  1.0f), yellow, tcu::Vec4( offset, 0.0f,  2.0f,  1.0f), blue},
   1682 
   1683 				// two vertices clipped to edges
   1684 				{tcu::Vec4( 0.6f, -1.2f,  0.0f,  1.0f), red, tcu::Vec4( 1.2f, -0.6f,  0.0f,  1.0f), yellow, tcu::Vec4( 0.6f, -0.6f,  0.0f,  1.0f), blue},
   1685 				{tcu::Vec4( 0.6f,  1.2f,  0.0f,  1.0f), red, tcu::Vec4( 1.2f,  0.6f,  0.0f,  1.0f), yellow, tcu::Vec4( 0.6f,  0.6f,  0.0f,  1.0f), blue},
   1686 				{tcu::Vec4(-0.6f,  1.2f,  0.0f,  1.0f), red, tcu::Vec4(-1.2f,  0.6f,  0.0f,  1.0f), yellow, tcu::Vec4(-0.6f,  0.6f,  0.0f,  1.0f), blue},
   1687 				{tcu::Vec4(-0.6f, -1.2f,  0.0f,  1.0f), red, tcu::Vec4(-1.2f, -0.6f,  0.0f,  1.0f), yellow, tcu::Vec4(-0.6f, -0.6f,  0.0f,  1.0f), blue},
   1688 			};
   1689 
   1690 			addChild(new TriangleAttributeCase(m_context, "multiple_4",					"polygon clipping",		DE_ARRAY_BEGIN(polys),		DE_ARRAY_END(polys),		VIEWPORT_WHOLE));
   1691 			addChild(new TriangleAttributeCase(m_context, "multiple_4_viewport_center",	"polygon clipping",		DE_ARRAY_BEGIN(polys),		DE_ARRAY_END(polys),		VIEWPORT_CENTER));
   1692 			addChild(new TriangleAttributeCase(m_context, "multiple_4_viewport_corner",	"polygon clipping",		DE_ARRAY_BEGIN(polys),		DE_ARRAY_END(polys),		VIEWPORT_CORNER));
   1693 		}
   1694 
   1695 		{
   1696 			const TriangleAttributeCase::TriangleData polys[] =
   1697 			{
   1698 				// one vertex clipped to z
   1699 				{tcu::Vec4(-0.3f,  0.2f,  0.0f,  1.0f), red, tcu::Vec4(-0.3f, -0.2f,  0.0f,  1.0f), yellow, tcu::Vec4(-offset, 0.0f,  2.0f,  1.0f), blue},
   1700 
   1701 				// two vertices clipped to edges
   1702 				{tcu::Vec4( 0.6f, -1.2f,  0.0f,  1.0f), red, tcu::Vec4( 1.2f, -0.6f,  0.0f,  1.0f), yellow, tcu::Vec4( 0.6f, -0.6f,  0.0f,  1.0f), blue},
   1703 				{tcu::Vec4( 0.6f,  1.2f,  0.0f,  1.0f), red, tcu::Vec4( 1.2f,  0.6f,  0.0f,  1.0f), yellow, tcu::Vec4( 0.6f,  0.6f,  0.0f,  1.0f), blue},
   1704 				{tcu::Vec4(-0.6f,  1.2f,  0.0f,  1.0f), red, tcu::Vec4(-1.2f,  0.6f,  0.0f,  1.0f), yellow, tcu::Vec4(-0.6f,  0.6f,  0.0f,  1.0f), blue},
   1705 				{tcu::Vec4(-0.6f, -1.2f,  0.0f,  1.0f), red, tcu::Vec4(-1.2f, -0.6f,  0.0f,  1.0f), yellow, tcu::Vec4(-0.6f, -0.6f,  0.0f,  1.0f), blue},
   1706 			};
   1707 
   1708 			addChild(new TriangleAttributeCase(m_context, "multiple_5",					"polygon clipping",		DE_ARRAY_BEGIN(polys),		DE_ARRAY_END(polys),		VIEWPORT_WHOLE));
   1709 			addChild(new TriangleAttributeCase(m_context, "multiple_5_viewport_center",	"polygon clipping",		DE_ARRAY_BEGIN(polys),		DE_ARRAY_END(polys),		VIEWPORT_CENTER));
   1710 			addChild(new TriangleAttributeCase(m_context, "multiple_5_viewport_corner",	"polygon clipping",		DE_ARRAY_BEGIN(polys),		DE_ARRAY_END(polys),		VIEWPORT_CORNER));
   1711 		}
   1712 
   1713 		{
   1714 			const TriangleAttributeCase::TriangleData polys[] =
   1715 			{
   1716 				// one vertex clipped to z
   1717 				{tcu::Vec4(-0.2f,  0.3f,  0.0f,  1.0f), red, tcu::Vec4( 0.2f, 0.3f,  0.0f,  1.0f), yellow, tcu::Vec4( 0.0f, offset,  2.0f,  1.0f), blue},
   1718 
   1719 				// two vertices clipped to edges
   1720 				{tcu::Vec4( 0.6f, -1.2f,  0.0f,  1.0f), red, tcu::Vec4( 1.2f, -0.6f,  0.0f,  1.0f), yellow, tcu::Vec4( 0.6f, -0.6f,  0.0f,  1.0f), blue},
   1721 				{tcu::Vec4( 0.6f,  1.2f,  0.0f,  1.0f), red, tcu::Vec4( 1.2f,  0.6f,  0.0f,  1.0f), yellow, tcu::Vec4( 0.6f,  0.6f,  0.0f,  1.0f), blue},
   1722 				{tcu::Vec4(-0.6f,  1.2f,  0.0f,  1.0f), red, tcu::Vec4(-1.2f,  0.6f,  0.0f,  1.0f), yellow, tcu::Vec4(-0.6f,  0.6f,  0.0f,  1.0f), blue},
   1723 				{tcu::Vec4(-0.6f, -1.2f,  0.0f,  1.0f), red, tcu::Vec4(-1.2f, -0.6f,  0.0f,  1.0f), yellow, tcu::Vec4(-0.6f, -0.6f,  0.0f,  1.0f), blue},
   1724 			};
   1725 
   1726 			addChild(new TriangleAttributeCase(m_context, "multiple_6",					"polygon clipping",		DE_ARRAY_BEGIN(polys),		DE_ARRAY_END(polys),		VIEWPORT_WHOLE));
   1727 			addChild(new TriangleAttributeCase(m_context, "multiple_6_viewport_center",	"polygon clipping",		DE_ARRAY_BEGIN(polys),		DE_ARRAY_END(polys),		VIEWPORT_CENTER));
   1728 			addChild(new TriangleAttributeCase(m_context, "multiple_6_viewport_corner",	"polygon clipping",		DE_ARRAY_BEGIN(polys),		DE_ARRAY_END(polys),		VIEWPORT_CORNER));
   1729 		}
   1730 
   1731 		{
   1732 			const TriangleAttributeCase::TriangleData polys[] =
   1733 			{
   1734 				// two vertices clipped to edges
   1735 				{tcu::Vec4( 0.6f,  1.2f,  0.0f,  1.0f), red, tcu::Vec4( 1.2f,  0.6f,  0.0f,  1.0f), yellow, tcu::Vec4( 0.6f,  0.6f,  0.0f,  1.0f), blue},
   1736 
   1737 				// two vertices clipped to edges
   1738 				{tcu::Vec4( 0.6f, -1.2f,  0.0f,  1.0f), red, tcu::Vec4( 1.2f, -0.6f,  0.0f,  1.0f), yellow, tcu::Vec4( 0.6f, -0.6f,  0.0f,  1.0f), blue},
   1739 				{tcu::Vec4( 0.6f,  1.2f,  0.0f,  1.0f), red, tcu::Vec4( 1.2f,  0.6f,  0.0f,  1.0f), yellow, tcu::Vec4( 0.6f,  0.6f,  0.0f,  1.0f), blue},
   1740 				{tcu::Vec4(-0.6f,  1.2f,  0.0f,  1.0f), red, tcu::Vec4(-1.2f,  0.6f,  0.0f,  1.0f), yellow, tcu::Vec4(-0.6f,  0.6f,  0.0f,  1.0f), blue},
   1741 				{tcu::Vec4(-0.6f, -1.2f,  0.0f,  1.0f), red, tcu::Vec4(-1.2f, -0.6f,  0.0f,  1.0f), yellow, tcu::Vec4(-0.6f, -0.6f,  0.0f,  1.0f), blue},
   1742 			};
   1743 
   1744 			addChild(new TriangleAttributeCase(m_context, "multiple_7",					"polygon clipping",		DE_ARRAY_BEGIN(polys),		DE_ARRAY_END(polys),		VIEWPORT_WHOLE));
   1745 			addChild(new TriangleAttributeCase(m_context, "multiple_7_viewport_center",	"polygon clipping",		DE_ARRAY_BEGIN(polys),		DE_ARRAY_END(polys),		VIEWPORT_CENTER));
   1746 			addChild(new TriangleAttributeCase(m_context, "multiple_7_viewport_corner",	"polygon clipping",		DE_ARRAY_BEGIN(polys),		DE_ARRAY_END(polys),		VIEWPORT_CORNER));
   1747 		}
   1748 
   1749 		{
   1750 			const TriangleAttributeCase::TriangleData polys[] =
   1751 			{
   1752 				// one vertex clipped to z
   1753 				{tcu::Vec4(-0.2f,  -0.3f,  0.0f,  1.0f), red, tcu::Vec4( 0.2f, -0.3f,  0.0f,  1.0f), yellow, tcu::Vec4( 0.0f, -offset,  2.0f,  1.0f), blue},
   1754 
   1755 				// fill
   1756 				{tcu::Vec4( -1.0f, -1.0f,  0.0f,  1.0f), white, tcu::Vec4( 1.0f, -1.0f,  0.0f,  1.0f), white, tcu::Vec4( -1.0f, 1.0f,  0.0f,  1.0f), white},
   1757 				{tcu::Vec4( -1.0f,  1.0f,  0.0f,  1.0f), blue,	tcu::Vec4( 1.0f, -1.0f,  0.0f,  1.0f), blue, tcu::Vec4(  1.0f, 1.0f,  0.0f,  1.0f), blue},
   1758 			};
   1759 
   1760 			addChild(new TriangleAttributeCase(m_context, "multiple_8",					"polygon clipping",		DE_ARRAY_BEGIN(polys),		DE_ARRAY_END(polys),		VIEWPORT_WHOLE));
   1761 			addChild(new TriangleAttributeCase(m_context, "multiple_8_viewport_center",	"polygon clipping",		DE_ARRAY_BEGIN(polys),		DE_ARRAY_END(polys),		VIEWPORT_CENTER));
   1762 			addChild(new TriangleAttributeCase(m_context, "multiple_8_viewport_corner",	"polygon clipping",		DE_ARRAY_BEGIN(polys),		DE_ARRAY_END(polys),		VIEWPORT_CORNER));
   1763 		}
   1764 
   1765 		{
   1766 			const TriangleAttributeCase::TriangleData polys[] =
   1767 			{
   1768 				// one vertex clipped to z
   1769 				{tcu::Vec4(-0.2f,  -0.3f,  0.0f,  1.0f), red, tcu::Vec4( 0.2f, -0.3f,  0.0f,  1.0f), yellow, tcu::Vec4( 0.0f, -offset,  2.0f,  1.0f), blue},
   1770 
   1771 				// fill
   1772 				{tcu::Vec4( -1.0f,  1.0f,  0.0f,  1.0f), red,  tcu::Vec4( 1.0f, -1.0f,  0.0f,  1.0f), red,  tcu::Vec4(  1.0f, 1.0f,  0.0f,  1.0f), red},
   1773 				{tcu::Vec4( -1.0f, -1.0f,  0.0f,  1.0f), blue, tcu::Vec4( 1.0f, -1.0f,  0.0f,  1.0f), blue, tcu::Vec4( -1.0f, 1.0f,  0.0f,  1.0f), blue},
   1774 			};
   1775 
   1776 			addChild(new TriangleAttributeCase(m_context, "multiple_9",					"polygon clipping",		DE_ARRAY_BEGIN(polys),		DE_ARRAY_END(polys),		VIEWPORT_WHOLE));
   1777 			addChild(new TriangleAttributeCase(m_context, "multiple_9_viewport_center",	"polygon clipping",		DE_ARRAY_BEGIN(polys),		DE_ARRAY_END(polys),		VIEWPORT_CENTER));
   1778 			addChild(new TriangleAttributeCase(m_context, "multiple_9_viewport_corner",	"polygon clipping",		DE_ARRAY_BEGIN(polys),		DE_ARRAY_END(polys),		VIEWPORT_CORNER));
   1779 		}
   1780 
   1781 		{
   1782 			const TriangleAttributeCase::TriangleData polys[] =
   1783 			{
   1784 				// one vertex clipped to z
   1785 				{tcu::Vec4(-0.2f,  -0.3f,  0.0f,  1.0f), red, tcu::Vec4( 0.2f, -0.3f,  0.0f,  1.0f), yellow, tcu::Vec4( 0.0f, -offset,  2.0f,  1.0f), blue},
   1786 
   1787 				// fill
   1788 				{tcu::Vec4( -1.0f, -1.0f,  0.0f,  1.0f), white, tcu::Vec4( 1.0f, -1.0f,  0.0f,  1.0f), white, tcu::Vec4( -1.0f, 1.0f,  0.0f,  1.0f), white},
   1789 				{tcu::Vec4( -1.0f,  1.0f,  0.0f,  1.0f), red,   tcu::Vec4( 1.0f, -1.0f,  0.0f,  1.0f), red,   tcu::Vec4(  1.0f, 1.0f,  0.0f,  1.0f), red},
   1790 				{tcu::Vec4( -1.0f, -1.0f,  0.0f,  1.0f), blue,  tcu::Vec4( 1.0f, -1.0f,  0.0f,  1.0f), blue,  tcu::Vec4( -1.0f, 1.0f,  0.0f,  1.0f), blue},
   1791 			};
   1792 
   1793 			addChild(new TriangleAttributeCase(m_context, "multiple_10",					"polygon clipping",		DE_ARRAY_BEGIN(polys),		DE_ARRAY_END(polys),		VIEWPORT_WHOLE));
   1794 			addChild(new TriangleAttributeCase(m_context, "multiple_10_viewport_center",	"polygon clipping",		DE_ARRAY_BEGIN(polys),		DE_ARRAY_END(polys),		VIEWPORT_CENTER));
   1795 			addChild(new TriangleAttributeCase(m_context, "multiple_10_viewport_corner",	"polygon clipping",		DE_ARRAY_BEGIN(polys),		DE_ARRAY_END(polys),		VIEWPORT_CORNER));
   1796 		}
   1797 
   1798 		{
   1799 			const TriangleAttributeCase::TriangleData polys[] =
   1800 			{
   1801 				// one vertex clipped to z
   1802 				{tcu::Vec4(-0.2f,  -0.3f,  0.0f,  1.0f), red, tcu::Vec4( 0.2f, -0.3f,  0.0f,  1.0f), yellow, tcu::Vec4( 0.0f, -offset,  2.0f,  1.0f), blue},
   1803 
   1804 				// fill
   1805 				{tcu::Vec4( -1.0f, -1.0f,  0.0f,  1.0f), white,  tcu::Vec4( 1.0f, -1.0f,  0.0f,  1.0f), white,  tcu::Vec4( -1.0f, 1.0f,  0.0f,  1.0f), white},
   1806 				{tcu::Vec4( -1.0f,  1.0f,  0.0f,  1.0f), red,    tcu::Vec4( 1.0f, -1.0f,  0.0f,  1.0f), red,    tcu::Vec4(  1.0f, 1.0f,  0.0f,  1.0f), red},
   1807 				{tcu::Vec4( -1.0f, -1.0f,  0.0f,  1.0f), blue,   tcu::Vec4( 1.0f, -1.0f,  0.0f,  1.0f), blue,   tcu::Vec4( -1.0f, 1.0f,  0.0f,  1.0f), blue},
   1808 				{tcu::Vec4( -1.0f,  1.0f,  0.0f,  1.0f), yellow, tcu::Vec4( 1.0f, -1.0f,  0.0f,  1.0f), yellow, tcu::Vec4(  1.0f, 1.0f,  0.0f,  1.0f), yellow},
   1809 			};
   1810 
   1811 			addChild(new TriangleAttributeCase(m_context, "multiple_11",					"polygon clipping",		DE_ARRAY_BEGIN(polys),		DE_ARRAY_END(polys),		VIEWPORT_WHOLE));
   1812 			addChild(new TriangleAttributeCase(m_context, "multiple_11_viewport_center",	"polygon clipping",		DE_ARRAY_BEGIN(polys),		DE_ARRAY_END(polys),		VIEWPORT_CENTER));
   1813 			addChild(new TriangleAttributeCase(m_context, "multiple_11_viewport_corner",	"polygon clipping",		DE_ARRAY_BEGIN(polys),		DE_ARRAY_END(polys),		VIEWPORT_CORNER));
   1814 		}
   1815 	}
   1816 }
   1817 
   1818 class PolyEdgesTestGroup : public TestCaseGroup
   1819 {
   1820 public:
   1821 			PolyEdgesTestGroup	(Context& context);
   1822 
   1823 	void	init				(void);
   1824 };
   1825 
   1826 PolyEdgesTestGroup::PolyEdgesTestGroup (Context& context)
   1827 	: TestCaseGroup(context, "polygon_edge", "Polygon clipping edge tests")
   1828 {
   1829 }
   1830 
   1831 void PolyEdgesTestGroup::init (void)
   1832 {
   1833 	// Quads via origin
   1834 	const struct Quad
   1835 	{
   1836 		tcu::Vec3 d1; // tangent
   1837 		tcu::Vec3 d2; // bi-tangent
   1838 	} quads[] =
   1839 	{
   1840 		{ tcu::Vec3( 1, 1, 1),	tcu::Vec3( 1,   -1, 1) },
   1841 		{ tcu::Vec3( 1, 1, 1),	tcu::Vec3(-1, 1.1f, 1) },
   1842 		{ tcu::Vec3( 1, 1, 0),	tcu::Vec3(-1,    1, 0) },
   1843 		{ tcu::Vec3( 0, 1, 0),	tcu::Vec3( 1,    0, 0) },
   1844 		{ tcu::Vec3( 0, 1, 0),	tcu::Vec3( 1, 0.1f, 0) },
   1845 	};
   1846 
   1847 	// Quad near edge
   1848 	const struct EdgeQuad
   1849 	{
   1850 		tcu::Vec3 d1;		// tangent
   1851 		tcu::Vec3 d2;		// bi-tangent
   1852 		tcu::Vec3 center;	// center
   1853 	} edgeQuads[] =
   1854 	{
   1855 		{ tcu::Vec3( 1,     0.01f, 0    ),	tcu::Vec3( 0,      0.01f,  0),  tcu::Vec3( 0,     0.99f, 0    ) }, // edge near x-plane
   1856 		{ tcu::Vec3( 0.01f, 1,     0    ),	tcu::Vec3( 0.01f,  0,      0),  tcu::Vec3( 0.99f, 0,     0    ) }, // edge near y-plane
   1857 		{ tcu::Vec3( 1,     1,     0.01f),	tcu::Vec3( 0.01f,  -0.01f, 0),  tcu::Vec3( 0,     0,     0.99f) }, // edge near z-plane
   1858 	};
   1859 
   1860 	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(quads); ++ndx)
   1861 		addChild(new QuadFillTest(m_context, (std::string("quad_at_origin_") + de::toString(ndx)).c_str(), "polygon edge clipping", VIEWPORT_CENTER, quads[ndx].d1, quads[ndx].d2));
   1862 	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(edgeQuads); ++ndx)
   1863 		addChild(new QuadFillTest(m_context, (std::string("quad_near_edge_") + de::toString(ndx)).c_str(), "polygon edge clipping", VIEWPORT_CENTER, edgeQuads[ndx].d1, edgeQuads[ndx].d2, edgeQuads[ndx].center));
   1864 
   1865 	// Polyfan
   1866 	addChild(new TriangleFanFillTest(m_context, "poly_fan", "polygon edge clipping", VIEWPORT_CENTER));
   1867 }
   1868 
   1869 class PolyVertexClipTestGroup : public TestCaseGroup
   1870 {
   1871 public:
   1872 			PolyVertexClipTestGroup	(Context& context);
   1873 
   1874 	void	init					(void);
   1875 };
   1876 
   1877 PolyVertexClipTestGroup::PolyVertexClipTestGroup (Context& context)
   1878 	: TestCaseGroup(context, "triangle_vertex", "Clip n vertices")
   1879 {
   1880 }
   1881 
   1882 void PolyVertexClipTestGroup::init (void)
   1883 {
   1884 	const float far = 30000.0f;
   1885 	const tcu::IVec3 outside[] =
   1886 	{
   1887 		// outside one clipping plane
   1888 		tcu::IVec3(-1,  0,  0),
   1889 		tcu::IVec3( 1,  0,  0),
   1890 		tcu::IVec3( 0,  1,  0),
   1891 		tcu::IVec3( 0, -1,  0),
   1892 		tcu::IVec3( 0,  0,  1),
   1893 		tcu::IVec3( 0,  0, -1),
   1894 
   1895 		// outside two clipping planes
   1896 		tcu::IVec3(-1, -1,  0),
   1897 		tcu::IVec3( 1, -1,  0),
   1898 		tcu::IVec3( 1,  1,  0),
   1899 		tcu::IVec3(-1,  1,  0),
   1900 
   1901 		tcu::IVec3(-1,  0, -1),
   1902 		tcu::IVec3( 1,  0, -1),
   1903 		tcu::IVec3( 1,  0,  1),
   1904 		tcu::IVec3(-1,  0,  1),
   1905 
   1906 		tcu::IVec3( 0, -1, -1),
   1907 		tcu::IVec3( 0,  1, -1),
   1908 		tcu::IVec3( 0,  1,  1),
   1909 		tcu::IVec3( 0, -1,  1),
   1910 
   1911 		// outside three clipping planes
   1912 		tcu::IVec3(-1, -1,  1),
   1913 		tcu::IVec3( 1, -1,  1),
   1914 		tcu::IVec3( 1,  1,  1),
   1915 		tcu::IVec3(-1,  1,  1),
   1916 
   1917 		tcu::IVec3(-1, -1, -1),
   1918 		tcu::IVec3( 1, -1, -1),
   1919 		tcu::IVec3( 1,  1, -1),
   1920 		tcu::IVec3(-1,  1, -1),
   1921 	};
   1922 
   1923 	de::Random rnd(0xabcdef);
   1924 
   1925 	TestCaseGroup* clipOne		= new TestCaseGroup(m_context, "clip_one",		"Clip one vertex");
   1926 	TestCaseGroup* clipTwo		= new TestCaseGroup(m_context, "clip_two",		"Clip two vertices");
   1927 	TestCaseGroup* clipThree	= new TestCaseGroup(m_context, "clip_three",	"Clip three vertices");
   1928 
   1929 	addChild(clipOne);
   1930 	addChild(clipTwo);
   1931 	addChild(clipThree);
   1932 
   1933 	// Test 1 point clipped
   1934 	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(outside); ++ndx)
   1935 	{
   1936 		const float		w0		= rnd.getFloat(0.2f, 16.0f);
   1937 		const float		w1		= rnd.getFloat(0.2f, 16.0f);
   1938 		const float		w2		= rnd.getFloat(0.2f, 16.0f);
   1939 		const tcu::Vec4 white	= tcu::Vec4(    1,	    1,	1,	1);
   1940 		const tcu::Vec3 r0		= tcu::Vec3( 0.2f,	 0.3f,	0);
   1941 		const tcu::Vec3 r1		= tcu::Vec3(-0.3f,	-0.4f,	0);
   1942 		const tcu::Vec3 r2		= IVec3ToVec3(outside[ndx]) * far;
   1943 		const tcu::Vec4 p0		= tcu::Vec4(r0.x() * w0, r0.y() * w0, r0.z() * w0, w0);
   1944 		const tcu::Vec4 p1		= tcu::Vec4(r1.x() * w1, r1.y() * w1, r1.z() * w1, w1);
   1945 		const tcu::Vec4 p2		= tcu::Vec4(r2.x() * w2, r2.y() * w2, r2.z() * w2, w2);
   1946 
   1947 		const std::string name	= std::string("clip") +
   1948 			(outside[ndx].x() > 0 ? "_pos_x" : (outside[ndx].x() < 0 ? "_neg_x" : "")) +
   1949 			(outside[ndx].y() > 0 ? "_pos_y" : (outside[ndx].y() < 0 ? "_neg_y" : "")) +
   1950 			(outside[ndx].z() > 0 ? "_pos_z" : (outside[ndx].z() < 0 ? "_neg_z" : ""));
   1951 
   1952 		const TriangleCase::TriangleData triangle =	{p0, white, p1, white, p2, white};
   1953 
   1954 		// don't try to test with degenerate (or almost degenerate) triangles
   1955 		if (outside[ndx].x() == 0 && outside[ndx].y() == 0)
   1956 			continue;
   1957 
   1958 		clipOne->addChild(new TriangleCase(m_context, name.c_str(), "clip one vertex", &triangle, &triangle + 1, VIEWPORT_CENTER));
   1959 	}
   1960 
   1961 	// Special triangles for "clip_z" cases, default triangles is not good, since it has very small visible area => problems with MSAA
   1962 	{
   1963 		const tcu::Vec4 white = tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f);
   1964 
   1965 		const TriangleCase::TriangleData posZTriangle =
   1966 		{
   1967 			tcu::Vec4( 0.0f, -0.7f, -0.9f, 1.0f), white,
   1968 			tcu::Vec4( 0.8f,  0.0f, -0.7f, 1.0f), white,
   1969 			tcu::Vec4(-0.9f,  0.9f,  3.0f, 1.0f), white
   1970 		};
   1971 		const TriangleCase::TriangleData negZTriangle =
   1972 		{
   1973 			tcu::Vec4( 0.0f, -0.7f,  0.9f, 1.0f), white,
   1974 			tcu::Vec4( 0.4f,  0.0f,  0.7f, 1.0f), white,
   1975 			tcu::Vec4(-0.9f,  0.9f, -3.0f, 1.0f), white
   1976 		};
   1977 
   1978 		clipOne->addChild(new TriangleCase(m_context, "clip_pos_z", "clip one vertex", &posZTriangle, &posZTriangle + 1, VIEWPORT_CENTER));
   1979 		clipOne->addChild(new TriangleCase(m_context, "clip_neg_z", "clip one vertex", &negZTriangle, &negZTriangle + 1, VIEWPORT_CENTER));
   1980 	}
   1981 
   1982 	// Test 2 points clipped
   1983 	for (int ndx1 = 0; ndx1 < DE_LENGTH_OF_ARRAY(outside); ++ndx1)
   1984 	for (int ndx2 = ndx1 + 1; ndx2 < DE_LENGTH_OF_ARRAY(outside); ++ndx2)
   1985 	{
   1986 		const float		w0		= rnd.getFloat(0.2f, 16.0f);
   1987 		const float		w1		= rnd.getFloat(0.2f, 16.0f);
   1988 		const float		w2		= rnd.getFloat(0.2f, 16.0f);
   1989 		const tcu::Vec4 white	= tcu::Vec4(    1,	    1,	1,	1);
   1990 		const tcu::Vec3 r0		= tcu::Vec3( 0.2f,	 0.3f,	0);
   1991 		const tcu::IVec3 r1		= outside[ndx1];
   1992 		const tcu::IVec3 r2		= outside[ndx2];
   1993 		const tcu::Vec4 p0		= tcu::Vec4(r0.x() * w0, r0.y() * w0, r0.z() * w0, w0);
   1994 		const tcu::Vec4 p1		= tcu::Vec4(r1.x() * far * w1, r1.y() * far * w1, r1.z() * far * w1, w1);
   1995 		const tcu::Vec4 p2		= tcu::Vec4(r2.x() * far * w2, r2.y() * far * w2, r2.z() * far * w2, w2);
   1996 
   1997 		const std::string name	= std::string("clip") +
   1998 			(outside[ndx1].x() > 0 ? "_pos_x" : (outside[ndx1].x() < 0 ? "_neg_x" : "")) +
   1999 			(outside[ndx1].y() > 0 ? "_pos_y" : (outside[ndx1].y() < 0 ? "_neg_y" : "")) +
   2000 			(outside[ndx1].z() > 0 ? "_pos_z" : (outside[ndx1].z() < 0 ? "_neg_z" : "")) +
   2001 			"_and" +
   2002 			(outside[ndx2].x() > 0 ? "_pos_x" : (outside[ndx2].x() < 0 ? "_neg_x" : "")) +
   2003 			(outside[ndx2].y() > 0 ? "_pos_y" : (outside[ndx2].y() < 0 ? "_neg_y" : "")) +
   2004 			(outside[ndx2].z() > 0 ? "_pos_z" : (outside[ndx2].z() < 0 ? "_neg_z" : ""));
   2005 
   2006 		const TriangleCase::TriangleData triangle =	{p0, white, p1, white, p2, white};
   2007 
   2008 		if (twoPointClippedTriangleInvisible(r0, r1, r2))
   2009 			continue;
   2010 
   2011 		clipTwo->addChild(new TriangleCase(m_context, name.c_str(), "clip two vertices", &triangle, &triangle + 1, VIEWPORT_CENTER));
   2012 	}
   2013 
   2014 	// Test 3 points clipped
   2015 	for (int ndx1 = 0; ndx1 < DE_LENGTH_OF_ARRAY(outside); ++ndx1)
   2016 	for (int ndx2 = ndx1 + 1; ndx2 < DE_LENGTH_OF_ARRAY(outside); ++ndx2)
   2017 	for (int ndx3 = ndx2 + 1; ndx3 < DE_LENGTH_OF_ARRAY(outside); ++ndx3)
   2018 	{
   2019 		const float		w0		= rnd.getFloat(0.2f, 16.0f);
   2020 		const float		w1		= rnd.getFloat(0.2f, 16.0f);
   2021 		const float		w2		= rnd.getFloat(0.2f, 16.0f);
   2022 		const tcu::Vec4 white	= tcu::Vec4(1, 1, 1, 1);
   2023 		const tcu::IVec3 r0		= outside[ndx1];
   2024 		const tcu::IVec3 r1		= outside[ndx2];
   2025 		const tcu::IVec3 r2		= outside[ndx3];
   2026 		const tcu::Vec4 p0		= tcu::Vec4(r0.x() * far * w0, r0.y() * far * w0, r0.z() * far * w0, w0);
   2027 		const tcu::Vec4 p1		= tcu::Vec4(r1.x() * far * w1, r1.y() * far * w1, r1.z() * far * w1, w1);
   2028 		const tcu::Vec4 p2		= tcu::Vec4(r2.x() * far * w2, r2.y() * far * w2, r2.z() * far * w2, w2);
   2029 
   2030 		// ignore cases where polygon is along xz or yz planes
   2031 		if (pointsOnLine(r0.swizzle(0, 1), r1.swizzle(0, 1), r2.swizzle(0, 1)))
   2032 			continue;
   2033 
   2034 		// triangle is visible only if it intersects the origin
   2035 		if (pointOnTriangle(tcu::IVec3(0, 0, 0), r0, r1, r2))
   2036 		{
   2037 			const TriangleCase::TriangleData triangle =	{p0, white, p1, white, p2, white};
   2038 			const std::string name	= std::string("clip") +
   2039 				(outside[ndx1].x() > 0 ? "_pos_x" : (outside[ndx1].x() < 0 ? "_neg_x" : "")) +
   2040 				(outside[ndx1].y() > 0 ? "_pos_y" : (outside[ndx1].y() < 0 ? "_neg_y" : "")) +
   2041 				(outside[ndx1].z() > 0 ? "_pos_z" : (outside[ndx1].z() < 0 ? "_neg_z" : "")) +
   2042 				"_and" +
   2043 				(outside[ndx2].x() > 0 ? "_pos_x" : (outside[ndx2].x() < 0 ? "_neg_x" : "")) +
   2044 				(outside[ndx2].y() > 0 ? "_pos_y" : (outside[ndx2].y() < 0 ? "_neg_y" : "")) +
   2045 				(outside[ndx2].z() > 0 ? "_pos_z" : (outside[ndx2].z() < 0 ? "_neg_z" : "")) +
   2046 				"_and" +
   2047 				(outside[ndx3].x() > 0 ? "_pos_x" : (outside[ndx3].x() < 0 ? "_neg_x" : "")) +
   2048 				(outside[ndx3].y() > 0 ? "_pos_y" : (outside[ndx3].y() < 0 ? "_neg_y" : "")) +
   2049 				(outside[ndx3].z() > 0 ? "_pos_z" : (outside[ndx3].z() < 0 ? "_neg_z" : ""));
   2050 
   2051 			clipThree->addChild(new TriangleCase(m_context, name.c_str(), "clip three vertices", &triangle, &triangle + 1, VIEWPORT_CENTER));
   2052 		}
   2053 	}
   2054 }
   2055 
   2056 } // anonymous
   2057 
   2058 ClippingTests::ClippingTests (Context& context)
   2059 	: TestCaseGroup(context, "clipping", "Clipping tests")
   2060 {
   2061 }
   2062 
   2063 ClippingTests::~ClippingTests (void)
   2064 {
   2065 }
   2066 
   2067 void ClippingTests::init (void)
   2068 {
   2069 	addChild(new PointsTestGroup		(m_context));
   2070 	addChild(new LinesTestGroup			(m_context));
   2071 	addChild(new PolysTestGroup			(m_context));
   2072 	addChild(new PolyEdgesTestGroup		(m_context));
   2073 	addChild(new PolyVertexClipTestGroup(m_context));
   2074 }
   2075 
   2076 } // Functional
   2077 } // gles2
   2078 } // deqp
   2079