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