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