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