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