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