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