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