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