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