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