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