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