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