Add new framebuffer fetch extension tests am: 2a609fb223
[platform/upstream/VK-GL-CTS.git] / modules / gles2 / functional / es2fRasterizationTests.cpp
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 2.0 Module
3  * -------------------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Functional rasterization tests.
22  *//*--------------------------------------------------------------------*/
23
24 #include "es2fRasterizationTests.hpp"
25 #include "tcuRasterizationVerifier.hpp"
26 #include "tcuSurface.hpp"
27 #include "tcuRenderTarget.hpp"
28 #include "tcuVectorUtil.hpp"
29 #include "tcuStringTemplate.hpp"
30 #include "tcuResultCollector.hpp"
31 #include "gluShaderProgram.hpp"
32 #include "gluRenderContext.hpp"
33 #include "gluPixelTransfer.hpp"
34 #include "gluStrUtil.hpp"
35 #include "deStringUtil.hpp"
36 #include "deRandom.hpp"
37 #include "glwFunctions.hpp"
38 #include "glwEnums.hpp"
39
40 #include <vector>
41
42 namespace deqp
43 {
44 namespace gles2
45 {
46 namespace Functional
47 {
48 namespace
49 {
50
51 using tcu::RasterizationArguments;
52 using tcu::TriangleSceneSpec;
53 using tcu::PointSceneSpec;
54 using tcu::LineSceneSpec;
55 using tcu::LineInterpolationMethod;
56
57 static const char* const s_shaderVertexTemplate =       "attribute highp vec4 a_position;\n"
58                                                                                                         "attribute highp vec4 a_color;\n"
59                                                                                                         "varying highp vec4 v_color;\n"
60                                                                                                         "uniform highp float u_pointSize;\n"
61                                                                                                         "void main ()\n"
62                                                                                                         "{\n"
63                                                                                                         "       gl_Position = a_position;\n"
64                                                                                                         "       gl_PointSize = u_pointSize;\n"
65                                                                                                         "       v_color = a_color;\n"
66                                                                                                         "}\n";
67 static const char* const s_shaderFragmentTemplate =     "varying mediump vec4 v_color;\n"
68                                                                                                         "void main ()\n"
69                                                                                                         "{\n"
70                                                                                                         "       gl_FragColor = v_color;\n"
71                                                                                                         "}\n";
72 enum InterpolationCaseFlags
73 {
74         INTERPOLATIONFLAGS_NONE = 0,
75         INTERPOLATIONFLAGS_PROJECTED = (1 << 1),
76 };
77
78 enum PrimitiveWideness
79 {
80         PRIMITIVEWIDENESS_NARROW = 0,
81         PRIMITIVEWIDENESS_WIDE,
82
83         PRIMITIVEWIDENESS_LAST
84 };
85
86 class BaseRenderingCase : public TestCase
87 {
88 public:
89                                                         BaseRenderingCase       (Context& context, const char* name, const char* desc, int renderSize = 256);
90                                                         ~BaseRenderingCase      (void);
91         virtual void                    init                            (void);
92         void                                    deinit                          (void);
93
94 protected:
95         void                                    drawPrimitives          (tcu::Surface& result, const std::vector<tcu::Vec4>& vertexData, glw::GLenum primitiveType);
96         void                                    drawPrimitives          (tcu::Surface& result, const std::vector<tcu::Vec4>& vertexData, const std::vector<tcu::Vec4>& coloDrata, glw::GLenum primitiveType);
97
98         const int                               m_renderSize;
99         int                                             m_numSamples;
100         int                                             m_subpixelBits;
101         float                                   m_pointSize;
102         float                                   m_lineWidth;
103
104 private:
105         glu::ShaderProgram*             m_shader;
106 };
107
108 BaseRenderingCase::BaseRenderingCase (Context& context, const char* name, const char* desc, int renderSize)
109         : TestCase                              (context, name, desc)
110         , m_renderSize                  (renderSize)
111         , m_numSamples                  (-1)
112         , m_subpixelBits                (-1)
113         , m_pointSize                   (1.0f)
114         , m_lineWidth                   (1.0f)
115         , m_shader                              (DE_NULL)
116 {
117 }
118
119 BaseRenderingCase::~BaseRenderingCase (void)
120 {
121         deinit();
122 }
123
124 void BaseRenderingCase::init (void)
125 {
126         const int width  = m_context.getRenderTarget().getWidth();
127         const int height = m_context.getRenderTarget().getHeight();
128
129         // Requirements
130
131         if (width < m_renderSize || height < m_renderSize)
132                 throw tcu::NotSupportedError(std::string("Render target size must be at least ") + de::toString(m_renderSize) + "x" + de::toString(m_renderSize));
133
134         if (m_lineWidth != 1.0f)
135         {
136                 float range[2] = { 0.0f, 0.0f };
137                 m_context.getRenderContext().getFunctions().getFloatv(GL_ALIASED_LINE_WIDTH_RANGE, range);
138
139                 if (m_lineWidth < range[0] || m_lineWidth > range[1])
140                         throw tcu::NotSupportedError(std::string("Support for line width ") + de::toString(m_lineWidth) + " is required.");
141
142                 m_testCtx.getLog() << tcu::TestLog::Message << "ALIASED_LINE_WIDTH_RANGE = [" << range[0] << ", " << range[1] << "]" << tcu::TestLog::EndMessage;
143         }
144
145         if (m_pointSize != 1.0f)
146         {
147                 float range[2] = { 0.0f, 0.0f };
148                 m_context.getRenderContext().getFunctions().getFloatv(GL_ALIASED_POINT_SIZE_RANGE, range);
149
150                 if (m_pointSize < range[0] || m_pointSize > range[1])
151                         throw tcu::NotSupportedError(std::string("Support for point size ") + de::toString(m_pointSize) + " is required.");
152
153                 m_testCtx.getLog() << tcu::TestLog::Message << "ALIASED_POINT_SIZE_RANGE = [" << range[0] << ", " << range[1] << "]" << tcu::TestLog::EndMessage;
154         }
155
156         // Query info
157
158         m_numSamples = m_context.getRenderTarget().getNumSamples();
159         m_context.getRenderContext().getFunctions().getIntegerv(GL_SUBPIXEL_BITS, &m_subpixelBits);
160
161         m_testCtx.getLog() << tcu::TestLog::Message << "Sample count = " << m_numSamples << tcu::TestLog::EndMessage;
162         m_testCtx.getLog() << tcu::TestLog::Message << "SUBPIXEL_BITS = " << m_subpixelBits << tcu::TestLog::EndMessage;
163
164         // Gen shader
165
166         {
167                 tcu::StringTemplate                                     vertexSource    (s_shaderVertexTemplate);
168                 tcu::StringTemplate                                     fragmentSource  (s_shaderFragmentTemplate);
169                 std::map<std::string, std::string>      params;
170
171                 m_shader = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(vertexSource.specialize(params)) << glu::FragmentSource(fragmentSource.specialize(params)));
172                 if (!m_shader->isOk())
173                         throw tcu::TestError("could not create shader");
174         }
175 }
176
177 void BaseRenderingCase::deinit (void)
178 {
179         if (m_shader)
180         {
181                 delete m_shader;
182                 m_shader = DE_NULL;
183         }
184 }
185
186 void BaseRenderingCase::drawPrimitives (tcu::Surface& result, const std::vector<tcu::Vec4>& vertexData, glw::GLenum primitiveType)
187 {
188         // default to color white
189         const std::vector<tcu::Vec4> colorData(vertexData.size(), tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f));
190
191         drawPrimitives(result, vertexData, colorData, primitiveType);
192 }
193
194 void BaseRenderingCase::drawPrimitives (tcu::Surface& result, const std::vector<tcu::Vec4>& vertexData, const std::vector<tcu::Vec4>& colorData, glw::GLenum primitiveType)
195 {
196         const glw::Functions&   gl                              = m_context.getRenderContext().getFunctions();
197         const glw::GLint                positionLoc             = gl.getAttribLocation(m_shader->getProgram(), "a_position");
198         const glw::GLint                colorLoc                = gl.getAttribLocation(m_shader->getProgram(), "a_color");
199         const glw::GLint                pointSizeLoc    = gl.getUniformLocation(m_shader->getProgram(), "u_pointSize");
200
201         gl.clearColor                                   (0, 0, 0, 1);
202         gl.clear                                                (GL_COLOR_BUFFER_BIT);
203         gl.viewport                                             (0, 0, m_renderSize, m_renderSize);
204         gl.useProgram                                   (m_shader->getProgram());
205         gl.enableVertexAttribArray              (positionLoc);
206         gl.vertexAttribPointer                  (positionLoc, 4, GL_FLOAT, GL_FALSE, 0, &vertexData[0]);
207         gl.enableVertexAttribArray              (colorLoc);
208         gl.vertexAttribPointer                  (colorLoc, 4, GL_FLOAT, GL_FALSE, 0, &colorData[0]);
209         gl.uniform1f                                    (pointSizeLoc, m_pointSize);
210         gl.lineWidth                                    (m_lineWidth);
211         gl.drawArrays                                   (primitiveType, 0, (glw::GLsizei)vertexData.size());
212         gl.disableVertexAttribArray             (colorLoc);
213         gl.disableVertexAttribArray             (positionLoc);
214         gl.useProgram                                   (0);
215         gl.finish                                               ();
216         GLU_EXPECT_NO_ERROR                             (gl.getError(), "draw primitives");
217
218         glu::readPixels(m_context.getRenderContext(), 0, 0, result.getAccess());
219 }
220
221 class BaseTriangleCase : public BaseRenderingCase
222 {
223 public:
224                                                         BaseTriangleCase        (Context& context, const char* name, const char* desc, glw::GLenum primitiveDrawType);
225                                                         ~BaseTriangleCase       (void);
226         IterateResult                   iterate                         (void);
227
228 private:
229         virtual void                    generateTriangles       (int iteration, std::vector<tcu::Vec4>& outData, std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles) = DE_NULL;
230
231         int                                             m_iteration;
232         const int                               m_iterationCount;
233         const glw::GLenum               m_primitiveDrawType;
234         bool                                    m_allIterationsPassed;
235 };
236
237 BaseTriangleCase::BaseTriangleCase (Context& context, const char* name, const char* desc, glw::GLenum primitiveDrawType)
238         : BaseRenderingCase             (context, name, desc)
239         , m_iteration                   (0)
240         , m_iterationCount              (3)
241         , m_primitiveDrawType   (primitiveDrawType)
242         , m_allIterationsPassed (true)
243 {
244 }
245
246 BaseTriangleCase::~BaseTriangleCase (void)
247 {
248 }
249
250 BaseTriangleCase::IterateResult BaseTriangleCase::iterate (void)
251 {
252         const std::string                                                               iterationDescription    = "Test iteration " + de::toString(m_iteration+1) + " / " + de::toString(m_iterationCount);
253         const tcu::ScopedLogSection                                             section                                 (m_testCtx.getLog(), iterationDescription, iterationDescription);
254         tcu::Surface                                                                    resultImage                             (m_renderSize, m_renderSize);
255         std::vector<tcu::Vec4>                                                  drawBuffer;
256         std::vector<TriangleSceneSpec::SceneTriangle>   triangles;
257
258         generateTriangles(m_iteration, drawBuffer, triangles);
259
260         // draw image
261         drawPrimitives(resultImage, drawBuffer, m_primitiveDrawType);
262
263         // compare
264         {
265                 bool                                    compareOk;
266                 RasterizationArguments  args;
267                 TriangleSceneSpec               scene;
268
269                 args.numSamples         = m_numSamples;
270                 args.subpixelBits       = m_subpixelBits;
271                 args.redBits            = m_context.getRenderTarget().getPixelFormat().redBits;
272                 args.greenBits          = m_context.getRenderTarget().getPixelFormat().greenBits;
273                 args.blueBits           = m_context.getRenderTarget().getPixelFormat().blueBits;
274
275                 scene.triangles.swap(triangles);
276
277                 compareOk = verifyTriangleGroupRasterization(resultImage, scene, args, m_testCtx.getLog());
278
279                 if (!compareOk)
280                         m_allIterationsPassed = false;
281         }
282
283         // result
284         if (++m_iteration == m_iterationCount)
285         {
286                 if (m_allIterationsPassed)
287                         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
288                 else
289                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Incorrect rasterization");
290
291                 return STOP;
292         }
293         else
294                 return CONTINUE;
295 }
296
297 class BaseLineCase : public BaseRenderingCase
298 {
299 public:
300                                                         BaseLineCase            (Context& context, const char* name, const char* desc, glw::GLenum primitiveDrawType, PrimitiveWideness wideness);
301                                                         ~BaseLineCase           (void);
302         IterateResult                   iterate                         (void);
303
304 private:
305         virtual void                    generateLines           (int iteration, std::vector<tcu::Vec4>& outData, std::vector<LineSceneSpec::SceneLine>& outLines) = DE_NULL;
306
307         int                                             m_iteration;
308         const int                               m_iterationCount;
309         const glw::GLenum               m_primitiveDrawType;
310         const PrimitiveWideness m_primitiveWideness;
311         bool                                    m_allIterationsPassed;
312         bool                                    m_multisampleRelaxationRequired;
313
314         static const float              s_wideSize;
315 };
316
317 const float BaseLineCase::s_wideSize = 5.0f;
318
319 BaseLineCase::BaseLineCase (Context& context, const char* name, const char* desc, glw::GLenum primitiveDrawType, PrimitiveWideness wideness)
320         : BaseRenderingCase                                     (context, name, desc)
321         , m_iteration                                           (0)
322         , m_iterationCount                                      (3)
323         , m_primitiveDrawType                           (primitiveDrawType)
324         , m_primitiveWideness                           (wideness)
325         , m_allIterationsPassed                         (true)
326         , m_multisampleRelaxationRequired       (false)
327 {
328         DE_ASSERT(m_primitiveWideness < PRIMITIVEWIDENESS_LAST);
329         m_lineWidth = (m_primitiveWideness == PRIMITIVEWIDENESS_WIDE) ? (s_wideSize) : (1.0f);
330 }
331
332 BaseLineCase::~BaseLineCase (void)
333 {
334 }
335
336 BaseLineCase::IterateResult BaseLineCase::iterate (void)
337 {
338         const std::string                                               iterationDescription    = "Test iteration " + de::toString(m_iteration+1) + " / " + de::toString(m_iterationCount);
339         const tcu::ScopedLogSection                             section                                 (m_testCtx.getLog(), iterationDescription, iterationDescription);
340         tcu::Surface                                                    resultImage                             (m_renderSize, m_renderSize);
341         std::vector<tcu::Vec4>                                  drawBuffer;
342         std::vector<LineSceneSpec::SceneLine>   lines;
343
344         // last iteration, max out size
345         if (m_primitiveWideness == PRIMITIVEWIDENESS_WIDE &&
346                 m_iteration+1 == m_iterationCount)
347         {
348                 float range[2] = { 0.0f, 0.0f };
349                 m_context.getRenderContext().getFunctions().getFloatv(GL_ALIASED_LINE_WIDTH_RANGE, range);
350
351                 m_lineWidth = range[1];
352         }
353
354         // gen data
355         generateLines(m_iteration, drawBuffer, lines);
356
357         // draw image
358         drawPrimitives(resultImage, drawBuffer, m_primitiveDrawType);
359
360         // compare
361         {
362                 bool                                    compareOk;
363                 RasterizationArguments  args;
364                 LineSceneSpec                   scene;
365
366                 args.numSamples         = m_numSamples;
367                 args.subpixelBits       = m_subpixelBits;
368                 args.redBits            = m_context.getRenderTarget().getPixelFormat().redBits;
369                 args.greenBits          = m_context.getRenderTarget().getPixelFormat().greenBits;
370                 args.blueBits           = m_context.getRenderTarget().getPixelFormat().blueBits;
371
372                 scene.lines.swap(lines);
373                 scene.lineWidth = m_lineWidth;
374
375                 compareOk = verifyLineGroupRasterization(resultImage, scene, args, m_testCtx.getLog());
376
377                 // multisampled wide lines might not be supported
378                 if (scene.lineWidth != 1.0f && m_numSamples > 1 && !compareOk)
379                 {
380                         m_multisampleRelaxationRequired = true;
381                         compareOk = true;
382                 }
383
384                 if (!compareOk)
385                         m_allIterationsPassed = false;
386         }
387
388         // result
389         if (++m_iteration == m_iterationCount)
390         {
391                 if (m_allIterationsPassed && m_multisampleRelaxationRequired)
392                         m_testCtx.setTestResult(QP_TEST_RESULT_COMPATIBILITY_WARNING, "Rasterization of multisampled wide lines failed");
393                 else if (m_allIterationsPassed)
394                         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
395                 else
396                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Incorrect rasterization");
397
398                 return STOP;
399         }
400         else
401                 return CONTINUE;
402 }
403
404 class PointCase : public BaseRenderingCase
405 {
406 public:
407                                                         PointCase               (Context& context, const char* name, const char* desc, PrimitiveWideness wideness);
408                                                         ~PointCase              (void);
409         IterateResult                   iterate                 (void);
410
411 private:
412         void                                    generatePoints  (int iteration, std::vector<tcu::Vec4>& outData, std::vector<PointSceneSpec::ScenePoint>& outPoints);
413
414         int                                             m_iteration;
415         const int                               m_iterationCount;
416         const PrimitiveWideness m_primitiveWideness;
417         bool                                    m_allIterationsPassed;
418
419         static const float              s_wideSize;
420 };
421
422 const float PointCase::s_wideSize = 10.0f;
423
424 PointCase::PointCase (Context& context, const char* name, const char* desc, PrimitiveWideness wideness)
425         : BaseRenderingCase             (context, name, desc)
426         , m_iteration                   (0)
427         , m_iterationCount              (3)
428         , m_primitiveWideness   (wideness)
429         , m_allIterationsPassed (true)
430 {
431         m_pointSize = (m_primitiveWideness == PRIMITIVEWIDENESS_WIDE) ? (s_wideSize) : (1.0f);
432 }
433
434 PointCase::~PointCase (void)
435 {
436 }
437
438 PointCase::IterateResult PointCase::iterate (void)
439 {
440         const std::string                                               iterationDescription    = "Test iteration " + de::toString(m_iteration+1) + " / " + de::toString(m_iterationCount);
441         const tcu::ScopedLogSection                             section                                 (m_testCtx.getLog(), iterationDescription, iterationDescription);
442         tcu::Surface                                                    resultImage                             (m_renderSize, m_renderSize);
443         std::vector<tcu::Vec4>                                  drawBuffer;
444         std::vector<PointSceneSpec::ScenePoint> points;
445
446         // last iteration, max out size
447         if (m_primitiveWideness == PRIMITIVEWIDENESS_WIDE &&
448                 m_iteration+1 == m_iterationCount)
449         {
450                 float range[2] = { 0.0f, 0.0f };
451                 m_context.getRenderContext().getFunctions().getFloatv(GL_ALIASED_POINT_SIZE_RANGE, range);
452
453                 m_pointSize = range[1];
454         }
455
456         // gen data
457         generatePoints(m_iteration, drawBuffer, points);
458
459         // draw image
460         drawPrimitives(resultImage, drawBuffer, GL_POINTS);
461
462         // compare
463         {
464                 bool                                    compareOk;
465                 RasterizationArguments  args;
466                 PointSceneSpec                  scene;
467
468                 args.numSamples         = m_numSamples;
469                 args.subpixelBits       = m_subpixelBits;
470                 args.redBits            = m_context.getRenderTarget().getPixelFormat().redBits;
471                 args.greenBits          = m_context.getRenderTarget().getPixelFormat().greenBits;
472                 args.blueBits           = m_context.getRenderTarget().getPixelFormat().blueBits;
473
474                 scene.points.swap(points);
475
476                 compareOk = verifyPointGroupRasterization(resultImage, scene, args, m_testCtx.getLog());
477
478                 if (!compareOk)
479                         m_allIterationsPassed = false;
480         }
481
482         // result
483         if (++m_iteration == m_iterationCount)
484         {
485                 if (m_allIterationsPassed)
486                         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
487                 else
488                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Incorrect rasterization");
489
490                 return STOP;
491         }
492         else
493                 return CONTINUE;
494 }
495
496 void PointCase::generatePoints  (int iteration, std::vector<tcu::Vec4>& outData, std::vector<PointSceneSpec::ScenePoint>& outPoints)
497 {
498         outData.resize(6);
499
500         switch (iteration)
501         {
502                 case 0:
503                         // \note: these values are chosen arbitrarily
504                         outData[0] = tcu::Vec4( 0.2f,  0.8f, 0.0f, 1.0f);
505                         outData[1] = tcu::Vec4( 0.5f,  0.2f, 0.0f, 1.0f);
506                         outData[2] = tcu::Vec4( 0.5f,  0.3f, 0.0f, 1.0f);
507                         outData[3] = tcu::Vec4(-0.5f,  0.2f, 0.0f, 1.0f);
508                         outData[4] = tcu::Vec4(-0.2f, -0.4f, 0.0f, 1.0f);
509                         outData[5] = tcu::Vec4(-0.4f,  0.2f, 0.0f, 1.0f);
510                         break;
511
512                 case 1:
513                         outData[0] = tcu::Vec4(-0.499f, 0.128f, 0.0f, 1.0f);
514                         outData[1] = tcu::Vec4(-0.501f,  -0.3f, 0.0f, 1.0f);
515                         outData[2] = tcu::Vec4(  0.11f,  -0.2f, 0.0f, 1.0f);
516                         outData[3] = tcu::Vec4(  0.11f,   0.2f, 0.0f, 1.0f);
517                         outData[4] = tcu::Vec4(  0.88f,   0.9f, 0.0f, 1.0f);
518                         outData[5] = tcu::Vec4(   0.4f,   1.2f, 0.0f, 1.0f);
519                         break;
520
521                 case 2:
522                         outData[0] = tcu::Vec4( -0.9f, -0.3f, 0.0f, 1.0f);
523                         outData[1] = tcu::Vec4(  0.3f, -0.9f, 0.0f, 1.0f);
524                         outData[2] = tcu::Vec4( -0.4f, -0.1f, 0.0f, 1.0f);
525                         outData[3] = tcu::Vec4(-0.11f,  0.2f, 0.0f, 1.0f);
526                         outData[4] = tcu::Vec4( 0.88f,  0.7f, 0.0f, 1.0f);
527                         outData[5] = tcu::Vec4( -0.4f,  0.4f, 0.0f, 1.0f);
528                         break;
529         }
530
531         outPoints.resize(outData.size());
532         for (int pointNdx = 0; pointNdx < (int)outPoints.size(); ++pointNdx)
533         {
534                 outPoints[pointNdx].position = outData[pointNdx];
535                 outPoints[pointNdx].pointSize = m_pointSize;
536         }
537
538         // log
539         m_testCtx.getLog() << tcu::TestLog::Message << "Rendering " << outPoints.size() << " point(s): (point size = " << m_pointSize << ")" << tcu::TestLog::EndMessage;
540         for (int pointNdx = 0; pointNdx < (int)outPoints.size(); ++pointNdx)
541                 m_testCtx.getLog() << tcu::TestLog::Message << "Point " << (pointNdx+1) << ":\t" << outPoints[pointNdx].position << tcu::TestLog::EndMessage;
542 }
543
544 class TrianglesCase : public BaseTriangleCase
545 {
546 public:
547                         TrianglesCase           (Context& context, const char* name, const char* desc);
548                         ~TrianglesCase          (void);
549
550         void    generateTriangles       (int iteration, std::vector<tcu::Vec4>& outData, std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles);
551 };
552
553 TrianglesCase::TrianglesCase (Context& context, const char* name, const char* desc)
554         : BaseTriangleCase(context, name, desc, GL_TRIANGLES)
555 {
556 }
557
558 TrianglesCase::~TrianglesCase (void)
559 {
560
561 }
562
563 void TrianglesCase::generateTriangles (int iteration, std::vector<tcu::Vec4>& outData, std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles)
564 {
565         outData.resize(6);
566
567         switch (iteration)
568         {
569                 case 0:
570                         // \note: these values are chosen arbitrarily
571                         outData[0] = tcu::Vec4( 0.2f,  0.8f, 0.0f, 1.0f);
572                         outData[1] = tcu::Vec4( 0.5f,  0.2f, 0.0f, 1.0f);
573                         outData[2] = tcu::Vec4( 0.5f,  0.3f, 0.0f, 1.0f);
574                         outData[3] = tcu::Vec4(-0.5f,  0.2f, 0.0f, 1.0f);
575                         outData[4] = tcu::Vec4(-1.5f, -0.4f, 0.0f, 1.0f);
576                         outData[5] = tcu::Vec4(-0.4f,  0.2f, 0.0f, 1.0f);
577                         break;
578
579                 case 1:
580                         outData[0] = tcu::Vec4(-0.499f, 0.128f, 0.0f, 1.0f);
581                         outData[1] = tcu::Vec4(-0.501f,  -0.3f, 0.0f, 1.0f);
582                         outData[2] = tcu::Vec4(  0.11f,  -0.2f, 0.0f, 1.0f);
583                         outData[3] = tcu::Vec4(  0.11f,   0.2f, 0.0f, 1.0f);
584                         outData[4] = tcu::Vec4(  0.88f,   0.9f, 0.0f, 1.0f);
585                         outData[5] = tcu::Vec4(   0.4f,   1.2f, 0.0f, 1.0f);
586                         break;
587
588                 case 2:
589                         outData[0] = tcu::Vec4( -0.9f, -0.3f, 0.0f, 1.0f);
590                         outData[1] = tcu::Vec4(  1.1f, -0.9f, 0.0f, 1.0f);
591                         outData[2] = tcu::Vec4( -1.1f, -0.1f, 0.0f, 1.0f);
592                         outData[3] = tcu::Vec4(-0.11f,  0.2f, 0.0f, 1.0f);
593                         outData[4] = tcu::Vec4( 0.88f,  0.7f, 0.0f, 1.0f);
594                         outData[5] = tcu::Vec4( -0.4f,  0.4f, 0.0f, 1.0f);
595                         break;
596         }
597
598         outTriangles.resize(2);
599         outTriangles[0].positions[0] = outData[0];      outTriangles[0].sharedEdge[0] = false;
600         outTriangles[0].positions[1] = outData[1];      outTriangles[0].sharedEdge[1] = false;
601         outTriangles[0].positions[2] = outData[2];      outTriangles[0].sharedEdge[2] = false;
602
603         outTriangles[1].positions[0] = outData[3];      outTriangles[1].sharedEdge[0] = false;
604         outTriangles[1].positions[1] = outData[4];      outTriangles[1].sharedEdge[1] = false;
605         outTriangles[1].positions[2] = outData[5];      outTriangles[1].sharedEdge[2] = false;
606
607         // log
608         m_testCtx.getLog() << tcu::TestLog::Message << "Rendering " << outTriangles.size() << " triangle(s):" << tcu::TestLog::EndMessage;
609         for (int triangleNdx = 0; triangleNdx < (int)outTriangles.size(); ++triangleNdx)
610         {
611                 m_testCtx.getLog()
612                         << tcu::TestLog::Message
613                         << "Triangle " << (triangleNdx+1) << ":"
614                         << "\n\t" << outTriangles[triangleNdx].positions[0]
615                         << "\n\t" << outTriangles[triangleNdx].positions[1]
616                         << "\n\t" << outTriangles[triangleNdx].positions[2]
617                         << tcu::TestLog::EndMessage;
618         }
619 }
620
621 class TriangleStripCase : public BaseTriangleCase
622 {
623 public:
624                         TriangleStripCase       (Context& context, const char* name, const char* desc);
625
626         void    generateTriangles       (int iteration, std::vector<tcu::Vec4>& outData, std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles);
627 };
628
629 TriangleStripCase::TriangleStripCase (Context& context, const char* name, const char* desc)
630         : BaseTriangleCase(context, name, desc, GL_TRIANGLE_STRIP)
631 {
632 }
633
634 void TriangleStripCase::generateTriangles (int iteration, std::vector<tcu::Vec4>& outData, std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles)
635 {
636         outData.resize(5);
637
638         switch (iteration)
639         {
640                 case 0:
641                         // \note: these values are chosen arbitrarily
642                         outData[0] = tcu::Vec4(-0.504f,  0.8f,   0.0f, 1.0f);
643                         outData[1] = tcu::Vec4(-0.2f,   -0.2f,   0.0f, 1.0f);
644                         outData[2] = tcu::Vec4(-0.2f,    0.199f, 0.0f, 1.0f);
645                         outData[3] = tcu::Vec4( 0.5f,    0.201f, 0.0f, 1.0f);
646                         outData[4] = tcu::Vec4( 1.5f,    0.4f,   0.0f, 1.0f);
647                         break;
648
649                 case 1:
650                         outData[0] = tcu::Vec4(-0.499f, 0.129f,  0.0f, 1.0f);
651                         outData[1] = tcu::Vec4(-0.501f,  -0.3f,  0.0f, 1.0f);
652                         outData[2] = tcu::Vec4(  0.11f,  -0.2f,  0.0f, 1.0f);
653                         outData[3] = tcu::Vec4(  0.11f,  -0.31f, 0.0f, 1.0f);
654                         outData[4] = tcu::Vec4(  0.88f,   0.9f,  0.0f, 1.0f);
655                         break;
656
657                 case 2:
658                         outData[0] = tcu::Vec4( -0.9f, -0.3f,  0.0f, 1.0f);
659                         outData[1] = tcu::Vec4(  1.1f, -0.9f,  0.0f, 1.0f);
660                         outData[2] = tcu::Vec4(-0.87f, -0.1f,  0.0f, 1.0f);
661                         outData[3] = tcu::Vec4(-0.11f,  0.19f, 0.0f, 1.0f);
662                         outData[4] = tcu::Vec4( 0.88f,  0.7f,  0.0f, 1.0f);
663                         break;
664         }
665
666         outTriangles.resize(3);
667         outTriangles[0].positions[0] = outData[0];      outTriangles[0].sharedEdge[0] = false;
668         outTriangles[0].positions[1] = outData[1];      outTriangles[0].sharedEdge[1] = true;
669         outTriangles[0].positions[2] = outData[2];      outTriangles[0].sharedEdge[2] = false;
670
671         outTriangles[1].positions[0] = outData[2];      outTriangles[1].sharedEdge[0] = true;
672         outTriangles[1].positions[1] = outData[1];      outTriangles[1].sharedEdge[1] = false;
673         outTriangles[1].positions[2] = outData[3];      outTriangles[1].sharedEdge[2] = true;
674
675         outTriangles[2].positions[0] = outData[2];      outTriangles[2].sharedEdge[0] = true;
676         outTriangles[2].positions[1] = outData[3];      outTriangles[2].sharedEdge[1] = false;
677         outTriangles[2].positions[2] = outData[4];      outTriangles[2].sharedEdge[2] = false;
678
679         // log
680         m_testCtx.getLog() << tcu::TestLog::Message << "Rendering triangle strip, " << outData.size() << " vertices." << tcu::TestLog::EndMessage;
681         for (int vtxNdx = 0; vtxNdx < (int)outData.size(); ++vtxNdx)
682         {
683                 m_testCtx.getLog()
684                         << tcu::TestLog::Message
685                         << "\t" << outData[vtxNdx]
686                         << tcu::TestLog::EndMessage;
687         }
688 }
689
690 class TriangleFanCase : public BaseTriangleCase
691 {
692 public:
693                         TriangleFanCase         (Context& context, const char* name, const char* desc);
694
695         void    generateTriangles       (int iteration, std::vector<tcu::Vec4>& outData, std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles);
696 };
697
698 TriangleFanCase::TriangleFanCase (Context& context, const char* name, const char* desc)
699         : BaseTriangleCase(context, name, desc, GL_TRIANGLE_FAN)
700 {
701 }
702
703 void TriangleFanCase::generateTriangles (int iteration, std::vector<tcu::Vec4>& outData, std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles)
704 {
705         outData.resize(5);
706
707         switch (iteration)
708         {
709                 case 0:
710                         // \note: these values are chosen arbitrarily
711                         outData[0] = tcu::Vec4( 0.01f,  0.0f, 0.0f, 1.0f);
712                         outData[1] = tcu::Vec4( 0.5f,   0.2f, 0.0f, 1.0f);
713                         outData[2] = tcu::Vec4( 0.46f,  0.3f, 0.0f, 1.0f);
714                         outData[3] = tcu::Vec4(-0.5f,   0.2f, 0.0f, 1.0f);
715                         outData[4] = tcu::Vec4(-1.5f,  -0.4f, 0.0f, 1.0f);
716                         break;
717
718                 case 1:
719                         outData[0] = tcu::Vec4(-0.499f, 0.128f, 0.0f, 1.0f);
720                         outData[1] = tcu::Vec4(-0.501f,  -0.3f, 0.0f, 1.0f);
721                         outData[2] = tcu::Vec4(  0.11f,  -0.2f, 0.0f, 1.0f);
722                         outData[3] = tcu::Vec4(  0.11f,   0.2f, 0.0f, 1.0f);
723                         outData[4] = tcu::Vec4(  0.88f,   0.9f, 0.0f, 1.0f);
724                         break;
725
726                 case 2:
727                         outData[0] = tcu::Vec4( -0.9f, -0.3f, 0.0f, 1.0f);
728                         outData[1] = tcu::Vec4(  1.1f, -0.9f, 0.0f, 1.0f);
729                         outData[2] = tcu::Vec4(  0.7f, -0.1f, 0.0f, 1.0f);
730                         outData[3] = tcu::Vec4( 0.11f,  0.2f, 0.0f, 1.0f);
731                         outData[4] = tcu::Vec4( 0.88f,  0.7f, 0.0f, 1.0f);
732                         break;
733         }
734
735         outTriangles.resize(3);
736         outTriangles[0].positions[0] = outData[0];      outTriangles[0].sharedEdge[0] = false;
737         outTriangles[0].positions[1] = outData[1];      outTriangles[0].sharedEdge[1] = false;
738         outTriangles[0].positions[2] = outData[2];      outTriangles[0].sharedEdge[2] = true;
739
740         outTriangles[1].positions[0] = outData[0];      outTriangles[1].sharedEdge[0] = true;
741         outTriangles[1].positions[1] = outData[2];      outTriangles[1].sharedEdge[1] = false;
742         outTriangles[1].positions[2] = outData[3];      outTriangles[1].sharedEdge[2] = true;
743
744         outTriangles[2].positions[0] = outData[0];      outTriangles[2].sharedEdge[0] = true;
745         outTriangles[2].positions[1] = outData[3];      outTriangles[2].sharedEdge[1] = false;
746         outTriangles[2].positions[2] = outData[4];      outTriangles[2].sharedEdge[2] = false;
747
748         // log
749         m_testCtx.getLog() << tcu::TestLog::Message << "Rendering triangle fan, " << outData.size() << " vertices." << tcu::TestLog::EndMessage;
750         for (int vtxNdx = 0; vtxNdx < (int)outData.size(); ++vtxNdx)
751         {
752                 m_testCtx.getLog()
753                         << tcu::TestLog::Message
754                         << "\t" << outData[vtxNdx]
755                         << tcu::TestLog::EndMessage;
756         }
757 }
758
759 class LinesCase : public BaseLineCase
760 {
761 public:
762                         LinesCase               (Context& context, const char* name, const char* desc, PrimitiveWideness wideness);
763
764         void    generateLines   (int iteration, std::vector<tcu::Vec4>& outData, std::vector<LineSceneSpec::SceneLine>& outLines);
765 };
766
767 LinesCase::LinesCase (Context& context, const char* name, const char* desc, PrimitiveWideness wideness)
768         : BaseLineCase(context, name, desc, GL_LINES, wideness)
769 {
770 }
771
772 void LinesCase::generateLines (int iteration, std::vector<tcu::Vec4>& outData, std::vector<LineSceneSpec::SceneLine>& outLines)
773 {
774         outData.resize(6);
775
776         switch (iteration)
777         {
778                 case 0:
779                         // \note: these values are chosen arbitrarily
780                         outData[0] = tcu::Vec4( 0.01f,  0.0f, 0.0f, 1.0f);
781                         outData[1] = tcu::Vec4( 0.5f,   0.2f, 0.0f, 1.0f);
782                         outData[2] = tcu::Vec4( 0.46f,  0.3f, 0.0f, 1.0f);
783                         outData[3] = tcu::Vec4(-0.3f,   0.2f, 0.0f, 1.0f);
784                         outData[4] = tcu::Vec4(-1.5f,  -0.4f, 0.0f, 1.0f);
785                         outData[5] = tcu::Vec4( 0.1f,   0.5f, 0.0f, 1.0f);
786                         break;
787
788                 case 1:
789                         outData[0] = tcu::Vec4(-0.499f, 0.128f, 0.0f, 1.0f);
790                         outData[1] = tcu::Vec4(-0.501f,  -0.3f, 0.0f, 1.0f);
791                         outData[2] = tcu::Vec4(  0.11f,  -0.2f, 0.0f, 1.0f);
792                         outData[3] = tcu::Vec4(  0.11f,   0.2f, 0.0f, 1.0f);
793                         outData[4] = tcu::Vec4(  0.88f,   0.9f, 0.0f, 1.0f);
794                         outData[5] = tcu::Vec4(  0.18f,  -0.2f, 0.0f, 1.0f);
795                         break;
796
797                 case 2:
798                         outData[0] = tcu::Vec4( -0.9f, -0.3f, 0.0f, 1.0f);
799                         outData[1] = tcu::Vec4(  1.1f, -0.9f, 0.0f, 1.0f);
800                         outData[2] = tcu::Vec4(  0.7f, -0.1f, 0.0f, 1.0f);
801                         outData[3] = tcu::Vec4( 0.11f,  0.2f, 0.0f, 1.0f);
802                         outData[4] = tcu::Vec4( 0.88f,  0.7f, 0.0f, 1.0f);
803                         outData[5] = tcu::Vec4(  0.8f, -0.7f, 0.0f, 1.0f);
804                         break;
805         }
806
807         outLines.resize(3);
808         outLines[0].positions[0] = outData[0];
809         outLines[0].positions[1] = outData[1];
810         outLines[1].positions[0] = outData[2];
811         outLines[1].positions[1] = outData[3];
812         outLines[2].positions[0] = outData[4];
813         outLines[2].positions[1] = outData[5];
814
815         // log
816         m_testCtx.getLog() << tcu::TestLog::Message << "Rendering " << outLines.size() << " lines(s): (width = " << m_lineWidth << ")" << tcu::TestLog::EndMessage;
817         for (int lineNdx = 0; lineNdx < (int)outLines.size(); ++lineNdx)
818         {
819                 m_testCtx.getLog()
820                         << tcu::TestLog::Message
821                         << "Line " << (lineNdx+1) << ":"
822                         << "\n\t" << outLines[lineNdx].positions[0]
823                         << "\n\t" << outLines[lineNdx].positions[1]
824                         << tcu::TestLog::EndMessage;
825         }
826 }
827
828 class LineStripCase : public BaseLineCase
829 {
830 public:
831                         LineStripCase   (Context& context, const char* name, const char* desc, PrimitiveWideness wideness);
832
833         void    generateLines   (int iteration, std::vector<tcu::Vec4>& outData, std::vector<LineSceneSpec::SceneLine>& outLines);
834 };
835
836 LineStripCase::LineStripCase (Context& context, const char* name, const char* desc, PrimitiveWideness wideness)
837         : BaseLineCase(context, name, desc, GL_LINE_STRIP, wideness)
838 {
839 }
840
841 void LineStripCase::generateLines (int iteration, std::vector<tcu::Vec4>& outData, std::vector<LineSceneSpec::SceneLine>& outLines)
842 {
843         outData.resize(4);
844
845         switch (iteration)
846         {
847                 case 0:
848                         // \note: these values are chosen arbitrarily
849                         outData[0] = tcu::Vec4( 0.01f,  0.0f, 0.0f, 1.0f);
850                         outData[1] = tcu::Vec4( 0.5f,   0.2f, 0.0f, 1.0f);
851                         outData[2] = tcu::Vec4( 0.46f,  0.3f, 0.0f, 1.0f);
852                         outData[3] = tcu::Vec4(-0.5f,   0.2f, 0.0f, 1.0f);
853                         break;
854
855                 case 1:
856                         outData[0] = tcu::Vec4(-0.499f, 0.128f, 0.0f, 1.0f);
857                         outData[1] = tcu::Vec4(-0.501f,  -0.3f, 0.0f, 1.0f);
858                         outData[2] = tcu::Vec4(  0.11f,  -0.2f, 0.0f, 1.0f);
859                         outData[3] = tcu::Vec4(  0.11f,   0.2f, 0.0f, 1.0f);
860                         break;
861
862                 case 2:
863                         outData[0] = tcu::Vec4( -0.9f, -0.3f, 0.0f, 1.0f);
864                         outData[1] = tcu::Vec4(  1.1f, -0.9f, 0.0f, 1.0f);
865                         outData[2] = tcu::Vec4(  0.7f, -0.1f, 0.0f, 1.0f);
866                         outData[3] = tcu::Vec4( 0.11f,  0.2f, 0.0f, 1.0f);
867                         break;
868         }
869
870         outLines.resize(3);
871         outLines[0].positions[0] = outData[0];
872         outLines[0].positions[1] = outData[1];
873         outLines[1].positions[0] = outData[1];
874         outLines[1].positions[1] = outData[2];
875         outLines[2].positions[0] = outData[2];
876         outLines[2].positions[1] = outData[3];
877
878         // log
879         m_testCtx.getLog() << tcu::TestLog::Message << "Rendering line strip, width = " << m_lineWidth << ", " << outData.size() << " vertices." << tcu::TestLog::EndMessage;
880         for (int vtxNdx = 0; vtxNdx < (int)outData.size(); ++vtxNdx)
881         {
882                 m_testCtx.getLog()
883                         << tcu::TestLog::Message
884                         << "\t" << outData[vtxNdx]
885                         << tcu::TestLog::EndMessage;
886         }
887 }
888
889 class LineLoopCase : public BaseLineCase
890 {
891 public:
892                         LineLoopCase    (Context& context, const char* name, const char* desc, PrimitiveWideness wideness);
893
894         void    generateLines   (int iteration, std::vector<tcu::Vec4>& outData, std::vector<LineSceneSpec::SceneLine>& outLines);
895 };
896
897 LineLoopCase::LineLoopCase (Context& context, const char* name, const char* desc, PrimitiveWideness wideness)
898         : BaseLineCase(context, name, desc, GL_LINE_LOOP, wideness)
899 {
900 }
901
902 void LineLoopCase::generateLines (int iteration, std::vector<tcu::Vec4>& outData, std::vector<LineSceneSpec::SceneLine>& outLines)
903 {
904         outData.resize(4);
905
906         switch (iteration)
907         {
908                 case 0:
909                         // \note: these values are chosen arbitrarily
910                         outData[0] = tcu::Vec4( 0.01f,  0.0f, 0.0f, 1.0f);
911                         outData[1] = tcu::Vec4( 0.5f,   0.2f, 0.0f, 1.0f);
912                         outData[2] = tcu::Vec4( 0.46f,  0.3f, 0.0f, 1.0f);
913                         outData[3] = tcu::Vec4(-0.5f,   0.2f, 0.0f, 1.0f);
914                         break;
915
916                 case 1:
917                         outData[0] = tcu::Vec4(-0.499f, 0.128f, 0.0f, 1.0f);
918                         outData[1] = tcu::Vec4(-0.501f,  -0.3f, 0.0f, 1.0f);
919                         outData[2] = tcu::Vec4(  0.11f,  -0.2f, 0.0f, 1.0f);
920                         outData[3] = tcu::Vec4(  0.11f,   0.2f, 0.0f, 1.0f);
921                         break;
922
923                 case 2:
924                         outData[0] = tcu::Vec4( -0.9f, -0.3f, 0.0f, 1.0f);
925                         outData[1] = tcu::Vec4(  1.1f, -0.9f, 0.0f, 1.0f);
926                         outData[2] = tcu::Vec4(  0.7f, -0.1f, 0.0f, 1.0f);
927                         outData[3] = tcu::Vec4( 0.11f,  0.2f, 0.0f, 1.0f);
928                         break;
929         }
930
931         outLines.resize(4);
932         outLines[0].positions[0] = outData[0];
933         outLines[0].positions[1] = outData[1];
934         outLines[1].positions[0] = outData[1];
935         outLines[1].positions[1] = outData[2];
936         outLines[2].positions[0] = outData[2];
937         outLines[2].positions[1] = outData[3];
938         outLines[3].positions[0] = outData[3];
939         outLines[3].positions[1] = outData[0];
940
941         // log
942         m_testCtx.getLog() << tcu::TestLog::Message << "Rendering line loop, width = " << m_lineWidth << ", " << outData.size() << " vertices." << tcu::TestLog::EndMessage;
943         for (int vtxNdx = 0; vtxNdx < (int)outData.size(); ++vtxNdx)
944         {
945                 m_testCtx.getLog()
946                         << tcu::TestLog::Message
947                         << "\t" << outData[vtxNdx]
948                         << tcu::TestLog::EndMessage;
949         }
950 }
951
952 class FillRuleCase : public BaseRenderingCase
953 {
954 public:
955         enum FillRuleCaseType
956         {
957                 FILLRULECASE_BASIC = 0,
958                 FILLRULECASE_REVERSED,
959                 FILLRULECASE_CLIPPED_FULL,
960                 FILLRULECASE_CLIPPED_PARTIAL,
961                 FILLRULECASE_PROJECTED,
962
963                 FILLRULECASE_LAST
964         };
965
966                                                         FillRuleCase            (Context& ctx, const char* name, const char* desc, FillRuleCaseType type);
967                                                         ~FillRuleCase           (void);
968         IterateResult                   iterate                         (void);
969
970 private:
971         int                                             getRenderSize           (FillRuleCase::FillRuleCaseType type) const;
972         int                                             getNumIterations        (FillRuleCase::FillRuleCaseType type) const;
973         void                                    generateTriangles       (int iteration, std::vector<tcu::Vec4>& outData) const;
974
975         const FillRuleCaseType  m_caseType;
976         int                                             m_iteration;
977         const int                               m_iterationCount;
978         bool                                    m_allIterationsPassed;
979
980 };
981
982 FillRuleCase::FillRuleCase (Context& ctx, const char* name, const char* desc, FillRuleCaseType type)
983         : BaseRenderingCase             (ctx, name, desc, getRenderSize(type))
984         , m_caseType                    (type)
985         , m_iteration                   (0)
986         , m_iterationCount              (getNumIterations(type))
987         , m_allIterationsPassed (true)
988 {
989         DE_ASSERT(type < FILLRULECASE_LAST);
990 }
991
992 FillRuleCase::~FillRuleCase (void)
993 {
994         deinit();
995 }
996
997 FillRuleCase::IterateResult FillRuleCase::iterate (void)
998 {
999         const std::string                                               iterationDescription    = "Test iteration " + de::toString(m_iteration+1) + " / " + de::toString(m_iterationCount);
1000         const tcu::ScopedLogSection                             section                                 (m_testCtx.getLog(), iterationDescription, iterationDescription);
1001         const int                                                               thresholdRed                    = 1 << (8 - m_context.getRenderTarget().getPixelFormat().redBits);
1002         const int                                                               thresholdGreen                  = 1 << (8 - m_context.getRenderTarget().getPixelFormat().greenBits);
1003         const int                                                               thresholdBlue                   = 1 << (8 - m_context.getRenderTarget().getPixelFormat().blueBits);
1004         tcu::Surface                                                    resultImage                             (m_renderSize, m_renderSize);
1005         std::vector<tcu::Vec4>                                  drawBuffer;
1006         bool                                                                    imageShown                              = false;
1007
1008         generateTriangles(m_iteration, drawBuffer);
1009
1010         // draw image
1011         {
1012                 const glw::Functions&                   gl                              = m_context.getRenderContext().getFunctions();
1013                 const std::vector<tcu::Vec4>    colorBuffer             (drawBuffer.size(), tcu::Vec4(0.5f, 0.5f, 0.5f, 1.0f));
1014
1015                 m_testCtx.getLog() << tcu::TestLog::Message << "Drawing gray triangles with shared edges.\nEnabling additive blending to detect overlapping fragments." << tcu::TestLog::EndMessage;
1016
1017                 gl.enable(GL_BLEND);
1018                 gl.blendEquation(GL_FUNC_ADD);
1019                 gl.blendFunc(GL_ONE, GL_ONE);
1020                 drawPrimitives(resultImage, drawBuffer, colorBuffer, GL_TRIANGLES);
1021         }
1022
1023         // verify no overdraw
1024         {
1025                 const tcu::RGBA triangleColor   = tcu::RGBA(127, 127, 127, 255);
1026                 bool                    overdraw                = false;
1027
1028                 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying result." << tcu::TestLog::EndMessage;
1029
1030                 for (int y = 0; y < resultImage.getHeight(); ++y)
1031                 for (int x = 0; x < resultImage.getWidth();  ++x)
1032                 {
1033                         const tcu::RGBA color = resultImage.getPixel(x, y);
1034
1035                         // color values are greater than triangle color? Allow lower values for multisampled edges and background.
1036                         if ((color.getRed()   - triangleColor.getRed())   > thresholdRed   ||
1037                                 (color.getGreen() - triangleColor.getGreen()) > thresholdGreen ||
1038                                 (color.getBlue()  - triangleColor.getBlue())  > thresholdBlue)
1039                                 overdraw = true;
1040                 }
1041
1042                 // results
1043                 if (!overdraw)
1044                         m_testCtx.getLog() << tcu::TestLog::Message << "No overlapping fragments detected." << tcu::TestLog::EndMessage;
1045                 else
1046                 {
1047                         m_testCtx.getLog()      << tcu::TestLog::Message << "Overlapping fragments detected, image is not valid." << tcu::TestLog::EndMessage;
1048                         m_testCtx.getLog()      << tcu::TestLog::ImageSet("Result of rendering", "Result of rendering")
1049                                                                 << tcu::TestLog::Image("Result", "Result", resultImage)
1050                                                                 << tcu::TestLog::EndImageSet;
1051
1052                         imageShown = true;
1053                         m_allIterationsPassed = false;
1054                 }
1055         }
1056
1057         // verify no missing fragments in the full viewport case
1058         if (m_caseType == FILLRULECASE_CLIPPED_FULL)
1059         {
1060                 bool missingFragments = false;
1061
1062                 m_testCtx.getLog() << tcu::TestLog::Message << "Searching missing fragments." << tcu::TestLog::EndMessage;
1063
1064                 for (int y = 0; y < resultImage.getHeight(); ++y)
1065                 for (int x = 0; x < resultImage.getWidth();  ++x)
1066                 {
1067                         const tcu::RGBA color = resultImage.getPixel(x, y);
1068
1069                         // black? (background)
1070                         if (color.getRed()   <= thresholdRed   ||
1071                                 color.getGreen() <= thresholdGreen ||
1072                                 color.getBlue()  <= thresholdBlue)
1073                                 missingFragments = true;
1074                 }
1075
1076                 // results
1077                 if (!missingFragments)
1078                         m_testCtx.getLog() << tcu::TestLog::Message << "No missing fragments detected." << tcu::TestLog::EndMessage;
1079                 else
1080                 {
1081                         m_testCtx.getLog()      << tcu::TestLog::Message << "Missing fragments detected, image is not valid." << tcu::TestLog::EndMessage;
1082
1083                         if (!imageShown)
1084                         {
1085                                 m_testCtx.getLog()      << tcu::TestLog::ImageSet("Result of rendering", "Result of rendering")
1086                                                                         << tcu::TestLog::Image("Result", "Result", resultImage)
1087                                                                         << tcu::TestLog::EndImageSet;
1088                         }
1089
1090                         m_allIterationsPassed = false;
1091                 }
1092         }
1093
1094         // result
1095         if (++m_iteration == m_iterationCount)
1096         {
1097                 if (m_allIterationsPassed)
1098                         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1099                 else
1100                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Found invalid pixels");
1101
1102                 return STOP;
1103         }
1104         else
1105                 return CONTINUE;
1106 }
1107
1108 int FillRuleCase::getRenderSize (FillRuleCase::FillRuleCaseType type) const
1109 {
1110         if (type == FILLRULECASE_CLIPPED_FULL || type == FILLRULECASE_CLIPPED_PARTIAL)
1111                 return 64;
1112         else
1113                 return 256;
1114 }
1115
1116 int FillRuleCase::getNumIterations (FillRuleCase::FillRuleCaseType type) const
1117 {
1118         if (type == FILLRULECASE_CLIPPED_FULL || type == FILLRULECASE_CLIPPED_PARTIAL)
1119                 return 15;
1120         else
1121                 return 2;
1122 }
1123
1124 void FillRuleCase::generateTriangles (int iteration, std::vector<tcu::Vec4>& outData) const
1125 {
1126         switch (m_caseType)
1127         {
1128                 case FILLRULECASE_BASIC:
1129                 case FILLRULECASE_REVERSED:
1130                 case FILLRULECASE_PROJECTED:
1131                 {
1132                         const int       numRows         = 4;
1133                         const int       numColumns      = 4;
1134                         const float     quadSide        = 0.15f;
1135                         de::Random      rnd                     (0xabcd);
1136
1137                         outData.resize(6 * numRows * numColumns);
1138
1139                         for (int col = 0; col < numColumns; ++col)
1140                         for (int row = 0; row < numRows;    ++row)
1141                         {
1142                                 const tcu::Vec2 center          = tcu::Vec2(((float)row + 0.5f) / (float)numRows * 2.0f - 1.0f, ((float)col + 0.5f) / (float)numColumns * 2.0f - 1.0f);
1143                                 const float             rotation        = float(iteration * numColumns * numRows + col * numRows + row) / (float)(m_iterationCount * numColumns * numRows) * DE_PI / 2.0f;
1144                                 const tcu::Vec2 sideH           = quadSide * tcu::Vec2(deFloatCos(rotation), deFloatSin(rotation));
1145                                 const tcu::Vec2 sideV           = tcu::Vec2(sideH.y(), -sideH.x());
1146                                 const tcu::Vec2 quad[4]         =
1147                                 {
1148                                         center + sideH + sideV,
1149                                         center + sideH - sideV,
1150                                         center - sideH - sideV,
1151                                         center - sideH + sideV,
1152                                 };
1153
1154                                 if (m_caseType == FILLRULECASE_BASIC)
1155                                 {
1156                                         outData[6 * (col * numRows + row) + 0] = tcu::Vec4(quad[0].x(), quad[0].y(), 0.0f, 1.0f);
1157                                         outData[6 * (col * numRows + row) + 1] = tcu::Vec4(quad[1].x(), quad[1].y(), 0.0f, 1.0f);
1158                                         outData[6 * (col * numRows + row) + 2] = tcu::Vec4(quad[2].x(), quad[2].y(), 0.0f, 1.0f);
1159                                         outData[6 * (col * numRows + row) + 3] = tcu::Vec4(quad[2].x(), quad[2].y(), 0.0f, 1.0f);
1160                                         outData[6 * (col * numRows + row) + 4] = tcu::Vec4(quad[0].x(), quad[0].y(), 0.0f, 1.0f);
1161                                         outData[6 * (col * numRows + row) + 5] = tcu::Vec4(quad[3].x(), quad[3].y(), 0.0f, 1.0f);
1162                                 }
1163                                 else if (m_caseType == FILLRULECASE_REVERSED)
1164                                 {
1165                                         outData[6 * (col * numRows + row) + 0] = tcu::Vec4(quad[0].x(), quad[0].y(), 0.0f, 1.0f);
1166                                         outData[6 * (col * numRows + row) + 1] = tcu::Vec4(quad[1].x(), quad[1].y(), 0.0f, 1.0f);
1167                                         outData[6 * (col * numRows + row) + 2] = tcu::Vec4(quad[2].x(), quad[2].y(), 0.0f, 1.0f);
1168                                         outData[6 * (col * numRows + row) + 3] = tcu::Vec4(quad[0].x(), quad[0].y(), 0.0f, 1.0f);
1169                                         outData[6 * (col * numRows + row) + 4] = tcu::Vec4(quad[2].x(), quad[2].y(), 0.0f, 1.0f);
1170                                         outData[6 * (col * numRows + row) + 5] = tcu::Vec4(quad[3].x(), quad[3].y(), 0.0f, 1.0f);
1171                                 }
1172                                 else if (m_caseType == FILLRULECASE_PROJECTED)
1173                                 {
1174                                         const float w0 = rnd.getFloat(0.1f, 4.0f);
1175                                         const float w1 = rnd.getFloat(0.1f, 4.0f);
1176                                         const float w2 = rnd.getFloat(0.1f, 4.0f);
1177                                         const float w3 = rnd.getFloat(0.1f, 4.0f);
1178
1179                                         outData[6 * (col * numRows + row) + 0] = tcu::Vec4(quad[0].x() * w0, quad[0].y() * w0, 0.0f, w0);
1180                                         outData[6 * (col * numRows + row) + 1] = tcu::Vec4(quad[1].x() * w1, quad[1].y() * w1, 0.0f, w1);
1181                                         outData[6 * (col * numRows + row) + 2] = tcu::Vec4(quad[2].x() * w2, quad[2].y() * w2, 0.0f, w2);
1182                                         outData[6 * (col * numRows + row) + 3] = tcu::Vec4(quad[2].x() * w2, quad[2].y() * w2, 0.0f, w2);
1183                                         outData[6 * (col * numRows + row) + 4] = tcu::Vec4(quad[0].x() * w0, quad[0].y() * w0, 0.0f, w0);
1184                                         outData[6 * (col * numRows + row) + 5] = tcu::Vec4(quad[3].x() * w3, quad[3].y() * w3, 0.0f, w3);
1185                                 }
1186                                 else
1187                                         DE_ASSERT(DE_FALSE);
1188                         }
1189
1190                         break;
1191                 }
1192
1193                 case FILLRULECASE_CLIPPED_PARTIAL:
1194                 case FILLRULECASE_CLIPPED_FULL:
1195                 {
1196                         const float             quadSide        = (m_caseType == FILLRULECASE_CLIPPED_PARTIAL) ? (1.0f) : (2.0f);
1197                         const tcu::Vec2 center          = (m_caseType == FILLRULECASE_CLIPPED_PARTIAL) ? (tcu::Vec2(0.5f, 0.5f)) : (tcu::Vec2(0.0f, 0.0f));
1198                         const float             rotation        = (float)(iteration) / (float)(m_iterationCount - 1) * DE_PI / 2.0f;
1199                         const tcu::Vec2 sideH           = quadSide * tcu::Vec2(deFloatCos(rotation), deFloatSin(rotation));
1200                         const tcu::Vec2 sideV           = tcu::Vec2(sideH.y(), -sideH.x());
1201                         const tcu::Vec2 quad[4]         =
1202                         {
1203                                 center + sideH + sideV,
1204                                 center + sideH - sideV,
1205                                 center - sideH - sideV,
1206                                 center - sideH + sideV,
1207                         };
1208
1209                         outData.resize(6);
1210                         outData[0] = tcu::Vec4(quad[0].x(), quad[0].y(), 0.0f, 1.0f);
1211                         outData[1] = tcu::Vec4(quad[1].x(), quad[1].y(), 0.0f, 1.0f);
1212                         outData[2] = tcu::Vec4(quad[2].x(), quad[2].y(), 0.0f, 1.0f);
1213                         outData[3] = tcu::Vec4(quad[2].x(), quad[2].y(), 0.0f, 1.0f);
1214                         outData[4] = tcu::Vec4(quad[0].x(), quad[0].y(), 0.0f, 1.0f);
1215                         outData[5] = tcu::Vec4(quad[3].x(), quad[3].y(), 0.0f, 1.0f);
1216                         break;
1217                 }
1218
1219                 default:
1220                         DE_ASSERT(DE_FALSE);
1221         }
1222 }
1223
1224 class CullingTest : public BaseRenderingCase
1225 {
1226 public:
1227                                                 CullingTest                     (Context& ctx, const char* name, const char* desc, glw::GLenum cullMode, glw::GLenum primitive, glw::GLenum faceOrder);
1228                                                 ~CullingTest            (void);
1229         IterateResult           iterate                         (void);
1230
1231 private:
1232         void                            generateVertices        (std::vector<tcu::Vec4>& outData) const;
1233         void                            extractTriangles        (std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles, const std::vector<tcu::Vec4>& vertices) const;
1234         bool                            triangleOrder           (const tcu::Vec4& v0, const tcu::Vec4& v1, const tcu::Vec4& v2) const;
1235
1236         const glw::GLenum       m_cullMode;
1237         const glw::GLenum       m_primitive;
1238         const glw::GLenum       m_faceOrder;
1239 };
1240
1241 CullingTest::CullingTest (Context& ctx, const char* name, const char* desc, glw::GLenum cullMode, glw::GLenum primitive, glw::GLenum faceOrder)
1242         : BaseRenderingCase     (ctx, name, desc)
1243         , m_cullMode            (cullMode)
1244         , m_primitive           (primitive)
1245         , m_faceOrder           (faceOrder)
1246 {
1247 }
1248
1249 CullingTest::~CullingTest (void)
1250 {
1251 }
1252
1253 CullingTest::IterateResult CullingTest::iterate (void)
1254 {
1255         tcu::Surface                                                                    resultImage(m_renderSize, m_renderSize);
1256         std::vector<tcu::Vec4>                                                  drawBuffer;
1257         std::vector<TriangleSceneSpec::SceneTriangle>   triangles;
1258
1259         // generate scene
1260         generateVertices(drawBuffer);
1261         extractTriangles(triangles, drawBuffer);
1262
1263         // draw image
1264         {
1265                 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1266
1267                 gl.enable(GL_CULL_FACE);
1268                 gl.cullFace(m_cullMode);
1269                 gl.frontFace(m_faceOrder);
1270
1271                 m_testCtx.getLog() << tcu::TestLog::Message << "Setting front face to " << glu::getWindingName(m_faceOrder) << tcu::TestLog::EndMessage;
1272                 m_testCtx.getLog() << tcu::TestLog::Message << "Setting cull face to " << glu::getFaceName(m_cullMode) << tcu::TestLog::EndMessage;
1273                 m_testCtx.getLog() << tcu::TestLog::Message << "Drawing test pattern (" << glu::getPrimitiveTypeName(m_primitive) << ")" << tcu::TestLog::EndMessage;
1274
1275                 drawPrimitives(resultImage, drawBuffer, m_primitive);
1276         }
1277
1278         // compare
1279         {
1280                 RasterizationArguments  args;
1281                 TriangleSceneSpec               scene;
1282
1283                 args.numSamples         = m_numSamples;
1284                 args.subpixelBits       = m_subpixelBits;
1285                 args.redBits            = m_context.getRenderTarget().getPixelFormat().redBits;
1286                 args.greenBits          = m_context.getRenderTarget().getPixelFormat().greenBits;
1287                 args.blueBits           = m_context.getRenderTarget().getPixelFormat().blueBits;
1288
1289                 scene.triangles.swap(triangles);
1290
1291                 if (verifyTriangleGroupRasterization(resultImage, scene, args, m_testCtx.getLog(), tcu::VERIFICATIONMODE_WEAK))
1292                         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1293                 else
1294                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Incorrect rendering");
1295         }
1296
1297         return STOP;
1298 }
1299
1300 void CullingTest::generateVertices (std::vector<tcu::Vec4>& outData) const
1301 {
1302         de::Random rnd(543210);
1303
1304         outData.resize(6);
1305         for (int vtxNdx = 0; vtxNdx < (int)outData.size(); ++vtxNdx)
1306         {
1307                 outData[vtxNdx].x() = rnd.getFloat(-0.9f, 0.9f);
1308                 outData[vtxNdx].y() = rnd.getFloat(-0.9f, 0.9f);
1309                 outData[vtxNdx].z() = 0.0f;
1310                 outData[vtxNdx].w() = 1.0f;
1311         }
1312 }
1313
1314 void CullingTest::extractTriangles (std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles, const std::vector<tcu::Vec4>& vertices) const
1315 {
1316         const bool cullDirection = (m_cullMode == GL_FRONT) ^ (m_faceOrder == GL_CCW);
1317
1318         // No triangles
1319         if (m_cullMode == GL_FRONT_AND_BACK)
1320                 return;
1321
1322         switch (m_primitive)
1323         {
1324                 case GL_TRIANGLES:
1325                 {
1326                         for (int vtxNdx = 0; vtxNdx < (int)vertices.size() - 2; vtxNdx += 3)
1327                         {
1328                                 const tcu::Vec4& v0 = vertices[vtxNdx + 0];
1329                                 const tcu::Vec4& v1 = vertices[vtxNdx + 1];
1330                                 const tcu::Vec4& v2 = vertices[vtxNdx + 2];
1331
1332                                 if (triangleOrder(v0, v1, v2) != cullDirection)
1333                                 {
1334                                         TriangleSceneSpec::SceneTriangle tri;
1335                                         tri.positions[0] = v0;  tri.sharedEdge[0] = false;
1336                                         tri.positions[1] = v1;  tri.sharedEdge[1] = false;
1337                                         tri.positions[2] = v2;  tri.sharedEdge[2] = false;
1338
1339                                         outTriangles.push_back(tri);
1340                                 }
1341                         }
1342                         break;
1343                 }
1344
1345                 case GL_TRIANGLE_STRIP:
1346                 {
1347                         for (int vtxNdx = 0; vtxNdx < (int)vertices.size() - 2; ++vtxNdx)
1348                         {
1349                                 const tcu::Vec4& v0 = vertices[vtxNdx + 0];
1350                                 const tcu::Vec4& v1 = vertices[vtxNdx + 1];
1351                                 const tcu::Vec4& v2 = vertices[vtxNdx + 2];
1352
1353                                 if (triangleOrder(v0, v1, v2) != (cullDirection ^ (vtxNdx % 2 != 0)))
1354                                 {
1355                                         TriangleSceneSpec::SceneTriangle tri;
1356                                         tri.positions[0] = v0;  tri.sharedEdge[0] = false;
1357                                         tri.positions[1] = v1;  tri.sharedEdge[1] = false;
1358                                         tri.positions[2] = v2;  tri.sharedEdge[2] = false;
1359
1360                                         outTriangles.push_back(tri);
1361                                 }
1362                         }
1363                         break;
1364                 }
1365
1366                 case GL_TRIANGLE_FAN:
1367                 {
1368                         for (int vtxNdx = 1; vtxNdx < (int)vertices.size() - 1; ++vtxNdx)
1369                         {
1370                                 const tcu::Vec4& v0 = vertices[0];
1371                                 const tcu::Vec4& v1 = vertices[vtxNdx + 0];
1372                                 const tcu::Vec4& v2 = vertices[vtxNdx + 1];
1373
1374                                 if (triangleOrder(v0, v1, v2) != cullDirection)
1375                                 {
1376                                         TriangleSceneSpec::SceneTriangle tri;
1377                                         tri.positions[0] = v0;  tri.sharedEdge[0] = false;
1378                                         tri.positions[1] = v1;  tri.sharedEdge[1] = false;
1379                                         tri.positions[2] = v2;  tri.sharedEdge[2] = false;
1380
1381                                         outTriangles.push_back(tri);
1382                                 }
1383                         }
1384                         break;
1385                 }
1386
1387                 default:
1388                         DE_ASSERT(false);
1389         }
1390 }
1391
1392 bool CullingTest::triangleOrder (const tcu::Vec4& v0, const tcu::Vec4& v1, const tcu::Vec4& v2) const
1393 {
1394         const tcu::Vec2 s0 = v0.swizzle(0, 1) / v0.w();
1395         const tcu::Vec2 s1 = v1.swizzle(0, 1) / v1.w();
1396         const tcu::Vec2 s2 = v2.swizzle(0, 1) / v2.w();
1397
1398         // cross
1399         return ((s1.x() - s0.x()) * (s2.y() - s0.y()) - (s2.x() - s0.x()) * (s1.y() - s0.y())) < 0;
1400 }
1401
1402 class TriangleInterpolationTest : public BaseRenderingCase
1403 {
1404 public:
1405                                                 TriangleInterpolationTest       (Context& ctx, const char* name, const char* desc, glw::GLenum primitive, int flags);
1406                                                 ~TriangleInterpolationTest      (void);
1407         IterateResult           iterate                                         (void);
1408
1409 private:
1410         void                            generateVertices                        (int iteration, std::vector<tcu::Vec4>& outVertices, std::vector<tcu::Vec4>& outColors) const;
1411         void                            extractTriangles                        (std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles, const std::vector<tcu::Vec4>& vertices, const std::vector<tcu::Vec4>& colors) const;
1412
1413         const glw::GLenum       m_primitive;
1414         const bool                      m_projective;
1415         const int                       m_iterationCount;
1416
1417         int                                     m_iteration;
1418         bool                            m_allIterationsPassed;
1419 };
1420
1421 TriangleInterpolationTest::TriangleInterpolationTest (Context& ctx, const char* name, const char* desc, glw::GLenum primitive, int flags)
1422         : BaseRenderingCase             (ctx, name, desc)
1423         , m_primitive                   (primitive)
1424         , m_projective                  ((flags & INTERPOLATIONFLAGS_PROJECTED) != 0)
1425         , m_iterationCount              (3)
1426         , m_iteration                   (0)
1427         , m_allIterationsPassed (true)
1428 {
1429 }
1430
1431 TriangleInterpolationTest::~TriangleInterpolationTest (void)
1432 {
1433         deinit();
1434 }
1435
1436 TriangleInterpolationTest::IterateResult TriangleInterpolationTest::iterate (void)
1437 {
1438         const std::string                                                               iterationDescription    = "Test iteration " + de::toString(m_iteration+1) + " / " + de::toString(m_iterationCount);
1439         const tcu::ScopedLogSection                                             section                                 (m_testCtx.getLog(), "Iteration" + de::toString(m_iteration+1), iterationDescription);
1440         tcu::Surface                                                                    resultImage                             (m_renderSize, m_renderSize);
1441         std::vector<tcu::Vec4>                                                  drawBuffer;
1442         std::vector<tcu::Vec4>                                                  colorBuffer;
1443         std::vector<TriangleSceneSpec::SceneTriangle>   triangles;
1444
1445         // generate scene
1446         generateVertices(m_iteration, drawBuffer, colorBuffer);
1447         extractTriangles(triangles, drawBuffer, colorBuffer);
1448
1449         // log
1450         {
1451                 m_testCtx.getLog() << tcu::TestLog::Message << "Generated vertices:" << tcu::TestLog::EndMessage;
1452                 for (int vtxNdx = 0; vtxNdx < (int)drawBuffer.size(); ++vtxNdx)
1453                         m_testCtx.getLog() << tcu::TestLog::Message << "\t" << drawBuffer[vtxNdx] << ",\tcolor= " << colorBuffer[vtxNdx] << tcu::TestLog::EndMessage;
1454         }
1455
1456         // draw image
1457         drawPrimitives(resultImage, drawBuffer, colorBuffer, m_primitive);
1458
1459         // compare
1460         {
1461                 RasterizationArguments  args;
1462                 TriangleSceneSpec               scene;
1463
1464                 args.numSamples         = m_numSamples;
1465                 args.subpixelBits       = m_subpixelBits;
1466                 args.redBits            = m_context.getRenderTarget().getPixelFormat().redBits;
1467                 args.greenBits          = m_context.getRenderTarget().getPixelFormat().greenBits;
1468                 args.blueBits           = m_context.getRenderTarget().getPixelFormat().blueBits;
1469
1470                 scene.triangles.swap(triangles);
1471
1472                 if (!verifyTriangleGroupInterpolation(resultImage, scene, args, m_testCtx.getLog()))
1473                         m_allIterationsPassed = false;
1474         }
1475
1476         // result
1477         if (++m_iteration == m_iterationCount)
1478         {
1479                 if (m_allIterationsPassed)
1480                         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1481                 else
1482                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Found invalid pixel values");
1483
1484                 return STOP;
1485         }
1486         else
1487                 return CONTINUE;
1488 }
1489
1490 void TriangleInterpolationTest::generateVertices (int iteration, std::vector<tcu::Vec4>& outVertices, std::vector<tcu::Vec4>& outColors) const
1491 {
1492         // use only red, green and blue
1493         const tcu::Vec4 colors[] =
1494         {
1495                 tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f),
1496                 tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f),
1497                 tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f),
1498         };
1499
1500         de::Random rnd(123 + iteration * 1000 + (int)m_primitive);
1501
1502         outVertices.resize(6);
1503         outColors.resize(6);
1504
1505         for (int vtxNdx = 0; vtxNdx < (int)outVertices.size(); ++vtxNdx)
1506         {
1507                 outVertices[vtxNdx].x() = rnd.getFloat(-0.9f, 0.9f);
1508                 outVertices[vtxNdx].y() = rnd.getFloat(-0.9f, 0.9f);
1509                 outVertices[vtxNdx].z() = 0.0f;
1510
1511                 if (!m_projective)
1512                         outVertices[vtxNdx].w() = 1.0f;
1513                 else
1514                 {
1515                         const float w = rnd.getFloat(0.2f, 4.0f);
1516
1517                         outVertices[vtxNdx].x() *= w;
1518                         outVertices[vtxNdx].y() *= w;
1519                         outVertices[vtxNdx].z() *= w;
1520                         outVertices[vtxNdx].w() = w;
1521                 }
1522
1523                 outColors[vtxNdx] = colors[vtxNdx % DE_LENGTH_OF_ARRAY(colors)];
1524         }
1525 }
1526
1527 void TriangleInterpolationTest::extractTriangles (std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles, const std::vector<tcu::Vec4>& vertices, const std::vector<tcu::Vec4>& colors) const
1528 {
1529         switch (m_primitive)
1530         {
1531                 case GL_TRIANGLES:
1532                 {
1533                         for (int vtxNdx = 0; vtxNdx < (int)vertices.size() - 2; vtxNdx += 3)
1534                         {
1535                                 TriangleSceneSpec::SceneTriangle tri;
1536                                 tri.positions[0]        = vertices[vtxNdx + 0];
1537                                 tri.positions[1]        = vertices[vtxNdx + 1];
1538                                 tri.positions[2]        = vertices[vtxNdx + 2];
1539                                 tri.sharedEdge[0]       = false;
1540                                 tri.sharedEdge[1]       = false;
1541                                 tri.sharedEdge[2]       = false;
1542
1543                                 tri.colors[0] = colors[vtxNdx + 0];
1544                                 tri.colors[1] = colors[vtxNdx + 1];
1545                                 tri.colors[2] = colors[vtxNdx + 2];
1546
1547                                 outTriangles.push_back(tri);
1548                         }
1549                         break;
1550                 }
1551
1552                 case GL_TRIANGLE_STRIP:
1553                 {
1554                         for (int vtxNdx = 0; vtxNdx < (int)vertices.size() - 2; ++vtxNdx)
1555                         {
1556                                 TriangleSceneSpec::SceneTriangle tri;
1557                                 tri.positions[0]        = vertices[vtxNdx + 0];
1558                                 tri.positions[1]        = vertices[vtxNdx + 1];
1559                                 tri.positions[2]        = vertices[vtxNdx + 2];
1560                                 tri.sharedEdge[0]       = false;
1561                                 tri.sharedEdge[1]       = false;
1562                                 tri.sharedEdge[2]       = false;
1563
1564                                 tri.colors[0] = colors[vtxNdx + 0];
1565                                 tri.colors[1] = colors[vtxNdx + 1];
1566                                 tri.colors[2] = colors[vtxNdx + 2];
1567
1568                                 outTriangles.push_back(tri);
1569                         }
1570                         break;
1571                 }
1572
1573                 case GL_TRIANGLE_FAN:
1574                 {
1575                         for (int vtxNdx = 1; vtxNdx < (int)vertices.size() - 1; ++vtxNdx)
1576                         {
1577                                 TriangleSceneSpec::SceneTriangle tri;
1578                                 tri.positions[0]        = vertices[0];
1579                                 tri.positions[1]        = vertices[vtxNdx + 0];
1580                                 tri.positions[2]        = vertices[vtxNdx + 1];
1581                                 tri.sharedEdge[0]       = false;
1582                                 tri.sharedEdge[1]       = false;
1583                                 tri.sharedEdge[2]       = false;
1584
1585                                 tri.colors[0] = colors[0];
1586                                 tri.colors[1] = colors[vtxNdx + 0];
1587                                 tri.colors[2] = colors[vtxNdx + 1];
1588
1589                                 outTriangles.push_back(tri);
1590                         }
1591                         break;
1592                 }
1593
1594                 default:
1595                         DE_ASSERT(false);
1596         }
1597 }
1598
1599 class LineInterpolationTest : public BaseRenderingCase
1600 {
1601 public:
1602                                                         LineInterpolationTest   (Context& ctx, const char* name, const char* desc, glw::GLenum primitive, int flags, float lineWidth);
1603                                                         ~LineInterpolationTest  (void);
1604         IterateResult                   iterate                                 (void);
1605
1606 private:
1607         void                                    generateVertices                (int iteration, std::vector<tcu::Vec4>& outVertices, std::vector<tcu::Vec4>& outColors) const;
1608         void                                    extractLines                    (std::vector<LineSceneSpec::SceneLine>& outLines, const std::vector<tcu::Vec4>& vertices, const std::vector<tcu::Vec4>& colors) const;
1609
1610         const glw::GLenum               m_primitive;
1611         const bool                              m_projective;
1612         const int                               m_iterationCount;
1613
1614         int                                             m_iteration;
1615         tcu::ResultCollector    m_result;
1616 };
1617
1618 LineInterpolationTest::LineInterpolationTest (Context& ctx, const char* name, const char* desc, glw::GLenum primitive, int flags, float lineWidth)
1619         : BaseRenderingCase             (ctx, name, desc)
1620         , m_primitive                   (primitive)
1621         , m_projective                  ((flags & INTERPOLATIONFLAGS_PROJECTED) != 0)
1622         , m_iterationCount              (3)
1623         , m_iteration                   (0)
1624 {
1625         m_lineWidth = lineWidth;
1626 }
1627
1628 LineInterpolationTest::~LineInterpolationTest (void)
1629 {
1630         deinit();
1631 }
1632
1633 LineInterpolationTest::IterateResult LineInterpolationTest::iterate (void)
1634 {
1635         const std::string                                               iterationDescription    = "Test iteration " + de::toString(m_iteration+1) + " / " + de::toString(m_iterationCount);
1636         const tcu::ScopedLogSection                             section                                 (m_testCtx.getLog(), "Iteration" + de::toString(m_iteration+1), iterationDescription);
1637         tcu::Surface                                                    resultImage                             (m_renderSize, m_renderSize);
1638         std::vector<tcu::Vec4>                                  drawBuffer;
1639         std::vector<tcu::Vec4>                                  colorBuffer;
1640         std::vector<LineSceneSpec::SceneLine>   lines;
1641
1642         // generate scene
1643         generateVertices(m_iteration, drawBuffer, colorBuffer);
1644         extractLines(lines, drawBuffer, colorBuffer);
1645
1646         // log
1647         {
1648                 m_testCtx.getLog() << tcu::TestLog::Message << "Generated vertices:" << tcu::TestLog::EndMessage;
1649                 for (int vtxNdx = 0; vtxNdx < (int)drawBuffer.size(); ++vtxNdx)
1650                         m_testCtx.getLog() << tcu::TestLog::Message << "\t" << drawBuffer[vtxNdx] << ",\tcolor= " << colorBuffer[vtxNdx] << tcu::TestLog::EndMessage;
1651         }
1652
1653         // draw image
1654         drawPrimitives(resultImage, drawBuffer, colorBuffer, m_primitive);
1655
1656         // compare
1657         {
1658                 RasterizationArguments  args;
1659                 LineSceneSpec                   scene;
1660                 LineInterpolationMethod iterationResult;
1661
1662                 args.numSamples         = m_numSamples;
1663                 args.subpixelBits       = m_subpixelBits;
1664                 args.redBits            = m_context.getRenderTarget().getPixelFormat().redBits;
1665                 args.greenBits          = m_context.getRenderTarget().getPixelFormat().greenBits;
1666                 args.blueBits           = m_context.getRenderTarget().getPixelFormat().blueBits;
1667
1668                 scene.lines.swap(lines);
1669                 scene.lineWidth = m_lineWidth;
1670
1671                 iterationResult = verifyLineGroupInterpolation(resultImage, scene, args, m_testCtx.getLog());
1672                 switch (iterationResult)
1673                 {
1674                         case tcu::LINEINTERPOLATION_STRICTLY_CORRECT:
1675                                 // line interpolation matches the specification
1676                                 m_result.addResult(QP_TEST_RESULT_PASS, "Pass");
1677                                 break;
1678
1679                         case tcu::LINEINTERPOLATION_PROJECTED:
1680                                 // line interpolation weights are otherwise correct, but they are projected onto major axis
1681                                 m_testCtx.getLog()      << tcu::TestLog::Message
1682                                                                         << "Interpolation was calculated using coordinates projected onto major axis. "
1683                                                                            "This method does not produce the same values as the non-projecting method defined in the specification."
1684                                                                         << tcu::TestLog::EndMessage;
1685                                 m_result.addResult(QP_TEST_RESULT_QUALITY_WARNING, "Interpolation was calculated using projected coordinateds");
1686                                 break;
1687
1688                         case tcu::LINEINTERPOLATION_INCORRECT:
1689                                 if (scene.lineWidth != 1.0f && m_numSamples > 1)
1690                                 {
1691                                         // multisampled wide lines might not be supported
1692                                         m_result.addResult(QP_TEST_RESULT_COMPATIBILITY_WARNING, "Interpolation of multisampled wide lines failed");
1693                                 }
1694                                 else
1695                                 {
1696                                         // line interpolation is incorrect
1697                                         m_result.addResult(QP_TEST_RESULT_FAIL, "Found invalid pixel values");
1698                                 }
1699                                 break;
1700
1701                         default:
1702                                 DE_ASSERT(false);
1703                                 break;
1704                 }
1705         }
1706
1707         // result
1708         if (++m_iteration == m_iterationCount)
1709         {
1710                 m_result.setTestContextResult(m_testCtx);
1711                 return STOP;
1712         }
1713         else
1714                 return CONTINUE;
1715 }
1716
1717 void LineInterpolationTest::generateVertices (int iteration, std::vector<tcu::Vec4>& outVertices, std::vector<tcu::Vec4>& outColors) const
1718 {
1719         // use only red, green and blue
1720         const tcu::Vec4 colors[] =
1721         {
1722                 tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f),
1723                 tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f),
1724                 tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f),
1725         };
1726
1727         de::Random rnd(123 + iteration * 1000 + (int)m_primitive);
1728
1729         outVertices.resize(6);
1730         outColors.resize(6);
1731
1732         for (int vtxNdx = 0; vtxNdx < (int)outVertices.size(); ++vtxNdx)
1733         {
1734                 outVertices[vtxNdx].x() = rnd.getFloat(-0.9f, 0.9f);
1735                 outVertices[vtxNdx].y() = rnd.getFloat(-0.9f, 0.9f);
1736                 outVertices[vtxNdx].z() = 0.0f;
1737
1738                 if (!m_projective)
1739                         outVertices[vtxNdx].w() = 1.0f;
1740                 else
1741                 {
1742                         const float w = rnd.getFloat(0.2f, 4.0f);
1743
1744                         outVertices[vtxNdx].x() *= w;
1745                         outVertices[vtxNdx].y() *= w;
1746                         outVertices[vtxNdx].z() *= w;
1747                         outVertices[vtxNdx].w() = w;
1748                 }
1749
1750                 outColors[vtxNdx] = colors[vtxNdx % DE_LENGTH_OF_ARRAY(colors)];
1751         }
1752 }
1753
1754 void LineInterpolationTest::extractLines (std::vector<LineSceneSpec::SceneLine>& outLines, const std::vector<tcu::Vec4>& vertices, const std::vector<tcu::Vec4>& colors) const
1755 {
1756         switch (m_primitive)
1757         {
1758                 case GL_LINES:
1759                 {
1760                         for (int vtxNdx = 0; vtxNdx < (int)vertices.size() - 1; vtxNdx += 2)
1761                         {
1762                                 LineSceneSpec::SceneLine line;
1763                                 line.positions[0] = vertices[vtxNdx + 0];
1764                                 line.positions[1] = vertices[vtxNdx + 1];
1765
1766                                 line.colors[0] = colors[vtxNdx + 0];
1767                                 line.colors[1] = colors[vtxNdx + 1];
1768
1769                                 outLines.push_back(line);
1770                         }
1771                         break;
1772                 }
1773
1774                 case GL_LINE_STRIP:
1775                 {
1776                         for (int vtxNdx = 0; vtxNdx < (int)vertices.size() - 1; ++vtxNdx)
1777                         {
1778                                 LineSceneSpec::SceneLine line;
1779                                 line.positions[0] = vertices[vtxNdx + 0];
1780                                 line.positions[1] = vertices[vtxNdx + 1];
1781
1782                                 line.colors[0] = colors[vtxNdx + 0];
1783                                 line.colors[1] = colors[vtxNdx + 1];
1784
1785                                 outLines.push_back(line);
1786                         }
1787                         break;
1788                 }
1789
1790                 case GL_LINE_LOOP:
1791                 {
1792                         for (int vtxNdx = 0; vtxNdx < (int)vertices.size(); ++vtxNdx)
1793                         {
1794                                 LineSceneSpec::SceneLine line;
1795                                 line.positions[0] = vertices[(vtxNdx + 0) % (int)vertices.size()];
1796                                 line.positions[1] = vertices[(vtxNdx + 1) % (int)vertices.size()];
1797
1798                                 line.colors[0] = colors[(vtxNdx + 0) % (int)vertices.size()];
1799                                 line.colors[1] = colors[(vtxNdx + 1) % (int)vertices.size()];
1800
1801                                 outLines.push_back(line);
1802                         }
1803                         break;
1804                 }
1805
1806                 default:
1807                         DE_ASSERT(false);
1808         }
1809 }
1810
1811 } // anonymous
1812
1813 RasterizationTests::RasterizationTests (Context& context)
1814         : TestCaseGroup(context, "rasterization", "Rasterization Tests")
1815 {
1816 }
1817
1818 RasterizationTests::~RasterizationTests (void)
1819 {
1820 }
1821
1822 void RasterizationTests::init (void)
1823 {
1824         // .primitives
1825         {
1826                 tcu::TestCaseGroup* const primitives = new tcu::TestCaseGroup(m_testCtx, "primitives", "Primitive rasterization");
1827
1828                 addChild(primitives);
1829
1830                 primitives->addChild(new TrianglesCase          (m_context, "triangles",                "Render primitives as GL_TRIANGLES, verify rasterization result"));
1831                 primitives->addChild(new TriangleStripCase      (m_context, "triangle_strip",   "Render primitives as GL_TRIANGLE_STRIP, verify rasterization result"));
1832                 primitives->addChild(new TriangleFanCase        (m_context, "triangle_fan",             "Render primitives as GL_TRIANGLE_FAN, verify rasterization result"));
1833                 primitives->addChild(new LinesCase                      (m_context, "lines",                    "Render primitives as GL_LINES, verify rasterization result",                                                   PRIMITIVEWIDENESS_NARROW));
1834                 primitives->addChild(new LineStripCase          (m_context, "line_strip",               "Render primitives as GL_LINE_STRIP, verify rasterization result",                                              PRIMITIVEWIDENESS_NARROW));
1835                 primitives->addChild(new LineLoopCase           (m_context, "line_loop",                "Render primitives as GL_LINE_LOOP, verify rasterization result",                                               PRIMITIVEWIDENESS_NARROW));
1836                 primitives->addChild(new LinesCase                      (m_context, "lines_wide",               "Render primitives as GL_LINES with wide lines, verify rasterization result",                   PRIMITIVEWIDENESS_WIDE));
1837                 primitives->addChild(new LineStripCase          (m_context, "line_strip_wide",  "Render primitives as GL_LINE_STRIP with wide lines, verify rasterization result",              PRIMITIVEWIDENESS_WIDE));
1838                 primitives->addChild(new LineLoopCase           (m_context, "line_loop_wide",   "Render primitives as GL_LINE_LOOP with wide lines, verify rasterization result",               PRIMITIVEWIDENESS_WIDE));
1839                 primitives->addChild(new PointCase                      (m_context, "points",                   "Render primitives as GL_POINTS, verify rasterization result",                                                  PRIMITIVEWIDENESS_WIDE));
1840         }
1841
1842         // .fill_rules
1843         {
1844                 tcu::TestCaseGroup* const fillRules = new tcu::TestCaseGroup(m_testCtx, "fill_rules", "Primitive fill rules");
1845
1846                 addChild(fillRules);
1847
1848                 fillRules->addChild(new FillRuleCase(m_context, "basic_quad",                   "Verify fill rules",    FillRuleCase::FILLRULECASE_BASIC));
1849                 fillRules->addChild(new FillRuleCase(m_context, "basic_quad_reverse",   "Verify fill rules",    FillRuleCase::FILLRULECASE_REVERSED));
1850                 fillRules->addChild(new FillRuleCase(m_context, "clipped_full",                 "Verify fill rules",    FillRuleCase::FILLRULECASE_CLIPPED_FULL));
1851                 fillRules->addChild(new FillRuleCase(m_context, "clipped_partly",               "Verify fill rules",    FillRuleCase::FILLRULECASE_CLIPPED_PARTIAL));
1852                 fillRules->addChild(new FillRuleCase(m_context, "projected",                    "Verify fill rules",    FillRuleCase::FILLRULECASE_PROJECTED));
1853         }
1854
1855         // .culling
1856         {
1857                 static const struct CullMode
1858                 {
1859                         glw::GLenum     mode;
1860                         const char*     prefix;
1861                 } cullModes[] =
1862                 {
1863                         { GL_FRONT,                             "front_"        },
1864                         { GL_BACK,                              "back_"         },
1865                         { GL_FRONT_AND_BACK,    "both_"         },
1866                 };
1867                 static const struct PrimitiveType
1868                 {
1869                         glw::GLenum     type;
1870                         const char*     name;
1871                 } primitiveTypes[] =
1872                 {
1873                         { GL_TRIANGLES,                 "triangles"                     },
1874                         { GL_TRIANGLE_STRIP,    "triangle_strip"        },
1875                         { GL_TRIANGLE_FAN,              "triangle_fan"          },
1876                 };
1877                 static const struct FrontFaceOrder
1878                 {
1879                         glw::GLenum     mode;
1880                         const char*     postfix;
1881                 } frontOrders[] =
1882                 {
1883                         { GL_CCW,       ""                      },
1884                         { GL_CW,        "_reverse"      },
1885                 };
1886
1887                 tcu::TestCaseGroup* const culling = new tcu::TestCaseGroup(m_testCtx, "culling", "Culling");
1888
1889                 addChild(culling);
1890
1891                 for (int cullModeNdx   = 0; cullModeNdx   < DE_LENGTH_OF_ARRAY(cullModes);      ++cullModeNdx)
1892                 for (int primitiveNdx  = 0; primitiveNdx  < DE_LENGTH_OF_ARRAY(primitiveTypes); ++primitiveNdx)
1893                 for (int frontOrderNdx = 0; frontOrderNdx < DE_LENGTH_OF_ARRAY(frontOrders);    ++frontOrderNdx)
1894                 {
1895                         const std::string name = std::string(cullModes[cullModeNdx].prefix) + primitiveTypes[primitiveNdx].name + frontOrders[frontOrderNdx].postfix;
1896
1897                         culling->addChild(new CullingTest(m_context, name.c_str(), "Test primitive culling.", cullModes[cullModeNdx].mode, primitiveTypes[primitiveNdx].type, frontOrders[frontOrderNdx].mode));
1898                 }
1899         }
1900
1901         // .interpolation
1902         {
1903                 tcu::TestCaseGroup* const interpolation = new tcu::TestCaseGroup(m_testCtx, "interpolation", "Test interpolation");
1904
1905                 addChild(interpolation);
1906
1907                 // .basic
1908                 {
1909                         tcu::TestCaseGroup* const basic = new tcu::TestCaseGroup(m_testCtx, "basic", "Non-projective interpolation");
1910
1911                         interpolation->addChild(basic);
1912
1913                         basic->addChild(new TriangleInterpolationTest           (m_context, "triangles",                "Verify triangle interpolation",                GL_TRIANGLES,           INTERPOLATIONFLAGS_NONE));
1914                         basic->addChild(new TriangleInterpolationTest           (m_context, "triangle_strip",   "Verify triangle strip interpolation",  GL_TRIANGLE_STRIP,      INTERPOLATIONFLAGS_NONE));
1915                         basic->addChild(new TriangleInterpolationTest           (m_context, "triangle_fan",             "Verify triangle fan interpolation",    GL_TRIANGLE_FAN,        INTERPOLATIONFLAGS_NONE));
1916                         basic->addChild(new LineInterpolationTest                       (m_context, "lines",                    "Verify line interpolation",                    GL_LINES,                       INTERPOLATIONFLAGS_NONE,        1.0f));
1917                         basic->addChild(new LineInterpolationTest                       (m_context, "line_strip",               "Verify line strip interpolation",              GL_LINE_STRIP,          INTERPOLATIONFLAGS_NONE,        1.0f));
1918                         basic->addChild(new LineInterpolationTest                       (m_context, "line_loop",                "Verify line loop interpolation",               GL_LINE_LOOP,           INTERPOLATIONFLAGS_NONE,        1.0f));
1919                         basic->addChild(new LineInterpolationTest                       (m_context, "lines_wide",               "Verify wide line interpolation",               GL_LINES,                       INTERPOLATIONFLAGS_NONE,        5.0f));
1920                         basic->addChild(new LineInterpolationTest                       (m_context, "line_strip_wide",  "Verify wide line strip interpolation", GL_LINE_STRIP,          INTERPOLATIONFLAGS_NONE,        5.0f));
1921                         basic->addChild(new LineInterpolationTest                       (m_context, "line_loop_wide",   "Verify wide line loop interpolation",  GL_LINE_LOOP,           INTERPOLATIONFLAGS_NONE,        5.0f));
1922                 }
1923
1924                 // .projected
1925                 {
1926                         tcu::TestCaseGroup* const projected = new tcu::TestCaseGroup(m_testCtx, "projected", "Projective interpolation");
1927
1928                         interpolation->addChild(projected);
1929
1930                         projected->addChild(new TriangleInterpolationTest       (m_context, "triangles",                "Verify triangle interpolation",                GL_TRIANGLES,           INTERPOLATIONFLAGS_PROJECTED));
1931                         projected->addChild(new TriangleInterpolationTest       (m_context, "triangle_strip",   "Verify triangle strip interpolation",  GL_TRIANGLE_STRIP,      INTERPOLATIONFLAGS_PROJECTED));
1932                         projected->addChild(new TriangleInterpolationTest       (m_context, "triangle_fan",             "Verify triangle fan interpolation",    GL_TRIANGLE_FAN,        INTERPOLATIONFLAGS_PROJECTED));
1933                         projected->addChild(new LineInterpolationTest           (m_context, "lines",                    "Verify line interpolation",                    GL_LINES,                       INTERPOLATIONFLAGS_PROJECTED,   1.0f));
1934                         projected->addChild(new LineInterpolationTest           (m_context, "line_strip",               "Verify line strip interpolation",              GL_LINE_STRIP,          INTERPOLATIONFLAGS_PROJECTED,   1.0f));
1935                         projected->addChild(new LineInterpolationTest           (m_context, "line_loop",                "Verify line loop interpolation",               GL_LINE_LOOP,           INTERPOLATIONFLAGS_PROJECTED,   1.0f));
1936                         projected->addChild(new LineInterpolationTest           (m_context, "lines_wide",               "Verify wide line interpolation",               GL_LINES,                       INTERPOLATIONFLAGS_PROJECTED,   5.0f));
1937                         projected->addChild(new LineInterpolationTest           (m_context, "line_strip_wide",  "Verify wide line strip interpolation", GL_LINE_STRIP,          INTERPOLATIONFLAGS_PROJECTED,   5.0f));
1938                         projected->addChild(new LineInterpolationTest           (m_context, "line_loop_wide",   "Verify wide line loop interpolation",  GL_LINE_LOOP,           INTERPOLATIONFLAGS_PROJECTED,   5.0f));
1939                 }
1940         }
1941 }
1942
1943 } // Functional
1944 } // gles2
1945 } // deqp