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