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