fa3f6b9b3ce12f9a7bc4514b60061a491ae6efe9
[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         float                                   m_maxLineWidth;
514         std::vector<float>              m_lineWidths;
515 };
516
517 BaseLineCase::BaseLineCase (Context& context, const char* name, const char* desc, glw::GLenum primitiveDrawType, PrimitiveWideness wideness, BaseRenderingCase::RenderTarget renderTarget, int numSamples)
518         : BaseRenderingCase             (context, name, desc, renderTarget, numSamples, DEFAULT_RENDER_SIZE)
519         , m_iteration                   (0)
520         , m_iterationCount              (3)
521         , m_primitiveDrawType   (primitiveDrawType)
522         , m_primitiveWideness   (wideness)
523         , m_allIterationsPassed (true)
524         , m_maxLineWidth                (1.0f)
525 {
526         DE_ASSERT(m_primitiveWideness < PRIMITIVEWIDENESS_LAST);
527 }
528
529 BaseLineCase::~BaseLineCase (void)
530 {
531 }
532
533 void BaseLineCase::init (void)
534 {
535         // create line widths
536         if (m_primitiveWideness == PRIMITIVEWIDENESS_NARROW)
537         {
538                 m_lineWidths.resize(m_iterationCount, 1.0f);
539         }
540         else if (m_primitiveWideness == PRIMITIVEWIDENESS_WIDE)
541         {
542                 float range[2] = { 0.0f, 0.0f };
543                 m_context.getRenderContext().getFunctions().getFloatv(GL_ALIASED_LINE_WIDTH_RANGE, range);
544
545                 m_testCtx.getLog() << tcu::TestLog::Message << "ALIASED_LINE_WIDTH_RANGE = [" << range[0] << ", " << range[1] << "]" << tcu::TestLog::EndMessage;
546
547                 // no wide line support
548                 if (range[1] <= 1.0f)
549                         throw tcu::NotSupportedError("wide line support required");
550
551                 // set hand picked sizes
552                 m_lineWidths.push_back(5.0f);
553                 m_lineWidths.push_back(10.0f);
554                 m_lineWidths.push_back(range[1]);
555                 DE_ASSERT((int)m_lineWidths.size() == m_iterationCount);
556
557                 m_maxLineWidth = range[1];
558         }
559         else
560                 DE_ASSERT(false);
561
562         // init parent
563         BaseRenderingCase::init();
564 }
565
566 BaseLineCase::IterateResult BaseLineCase::iterate (void)
567 {
568         const std::string                                               iterationDescription    = "Test iteration " + de::toString(m_iteration+1) + " / " + de::toString(m_iterationCount);
569         const tcu::ScopedLogSection                             section                                 (m_testCtx.getLog(), iterationDescription, iterationDescription);
570         const float                                                             lineWidth                               = getLineWidth();
571         tcu::Surface                                                    resultImage                             (m_renderSize, m_renderSize);
572         std::vector<tcu::Vec4>                                  drawBuffer;
573         std::vector<LineSceneSpec::SceneLine>   lines;
574
575         // supported?
576         if (lineWidth <= m_maxLineWidth)
577         {
578                 // gen data
579                 generateLines(m_iteration, drawBuffer, lines);
580
581                 // draw image
582                 drawPrimitives(resultImage, drawBuffer, m_primitiveDrawType);
583
584                 // compare
585                 {
586                         bool                                    compareOk;
587                         RasterizationArguments  args;
588                         LineSceneSpec                   scene;
589
590                         args.numSamples         = m_numSamples;
591                         args.subpixelBits       = m_subpixelBits;
592                         args.redBits            = getPixelFormat().redBits;
593                         args.greenBits          = getPixelFormat().greenBits;
594                         args.blueBits           = getPixelFormat().blueBits;
595
596                         scene.lines.swap(lines);
597                         scene.lineWidth = lineWidth;
598
599                         compareOk = verifyLineGroupRasterization(resultImage, scene, args, m_testCtx.getLog());
600
601                         if (!compareOk)
602                                 m_allIterationsPassed = false;
603                 }
604         }
605         else
606                 m_testCtx.getLog() << tcu::TestLog::Message << "Line width " << lineWidth << " not supported, skipping iteration." << tcu::TestLog::EndMessage;
607
608         // result
609         if (++m_iteration == m_iterationCount)
610         {
611                 if (m_allIterationsPassed)
612                         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
613                 else
614                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Incorrect rasterization");
615
616                 return STOP;
617         }
618         else
619                 return CONTINUE;
620 }
621
622 float BaseLineCase::getLineWidth (void) const
623 {
624         return m_lineWidths[m_iteration];
625 }
626
627 class PointCase : public BaseRenderingCase
628 {
629 public:
630                                                         PointCase               (Context& context, const char* name, const char* desc, PrimitiveWideness wideness, BaseRenderingCase::RenderTarget renderTarget = RENDERTARGET_DEFAULT, int numSamples = -1);
631                                                         ~PointCase              (void);
632
633         void                                    init                    (void);
634         IterateResult                   iterate                 (void);
635
636 protected:
637         float                                   getPointSize    (void) const;
638
639 private:
640         void                                    generatePoints  (int iteration, std::vector<tcu::Vec4>& outData, std::vector<PointSceneSpec::ScenePoint>& outPoints);
641
642         int                                             m_iteration;
643         const int                               m_iterationCount;
644         const PrimitiveWideness m_primitiveWideness;
645         bool                                    m_allIterationsPassed;
646
647         float                                   m_maxPointSize;
648         std::vector<float>              m_pointSizes;
649 };
650
651 PointCase::PointCase (Context& context, const char* name, const char* desc, PrimitiveWideness wideness, BaseRenderingCase::RenderTarget renderTarget, int numSamples)
652         : BaseRenderingCase             (context, name, desc, renderTarget, numSamples, DEFAULT_RENDER_SIZE)
653         , m_iteration                   (0)
654         , m_iterationCount              (3)
655         , m_primitiveWideness   (wideness)
656         , m_allIterationsPassed (true)
657         , m_maxPointSize                (1.0f)
658 {
659 }
660
661 PointCase::~PointCase (void)
662 {
663 }
664
665 void PointCase::init (void)
666 {
667         // create point sizes
668         if (m_primitiveWideness == PRIMITIVEWIDENESS_NARROW)
669         {
670                 m_pointSizes.resize(m_iterationCount, 1.0f);
671         }
672         else if (m_primitiveWideness == PRIMITIVEWIDENESS_WIDE)
673         {
674                 float range[2] = { 0.0f, 0.0f };
675                 m_context.getRenderContext().getFunctions().getFloatv(GL_ALIASED_POINT_SIZE_RANGE, range);
676
677                 m_testCtx.getLog() << tcu::TestLog::Message << "GL_ALIASED_POINT_SIZE_RANGE = [" << range[0] << ", " << range[1] << "]" << tcu::TestLog::EndMessage;
678
679                 // no wide line support
680                 if (range[1] <= 1.0f)
681                         throw tcu::NotSupportedError("wide point support required");
682
683                 // set hand picked sizes
684                 m_pointSizes.push_back(10.0f);
685                 m_pointSizes.push_back(25.0f);
686                 m_pointSizes.push_back(range[1]);
687                 DE_ASSERT((int)m_pointSizes.size() == m_iterationCount);
688
689                 m_maxPointSize = range[1];
690         }
691         else
692                 DE_ASSERT(false);
693
694         // init parent
695         BaseRenderingCase::init();
696 }
697
698 PointCase::IterateResult PointCase::iterate (void)
699 {
700         const std::string                                               iterationDescription    = "Test iteration " + de::toString(m_iteration+1) + " / " + de::toString(m_iterationCount);
701         const tcu::ScopedLogSection                             section                                 (m_testCtx.getLog(), iterationDescription, iterationDescription);
702         const float                                                             pointSize                               = getPointSize();
703         tcu::Surface                                                    resultImage                             (m_renderSize, m_renderSize);
704         std::vector<tcu::Vec4>                                  drawBuffer;
705         std::vector<PointSceneSpec::ScenePoint> points;
706
707         // supported?
708         if (pointSize <= m_maxPointSize)
709         {
710                 // gen data
711                 generatePoints(m_iteration, drawBuffer, points);
712
713                 // draw image
714                 drawPrimitives(resultImage, drawBuffer, GL_POINTS);
715
716                 // compare
717                 {
718                         bool                                    compareOk;
719                         RasterizationArguments  args;
720                         PointSceneSpec                  scene;
721
722                         args.numSamples         = m_numSamples;
723                         args.subpixelBits       = m_subpixelBits;
724                         args.redBits            = getPixelFormat().redBits;
725                         args.greenBits          = getPixelFormat().greenBits;
726                         args.blueBits           = getPixelFormat().blueBits;
727
728                         scene.points.swap(points);
729
730                         compareOk = verifyPointGroupRasterization(resultImage, scene, args, m_testCtx.getLog());
731
732                         if (!compareOk)
733                                 m_allIterationsPassed = false;
734                 }
735         }
736         else
737                 m_testCtx.getLog() << tcu::TestLog::Message << "Point size " << pointSize << " not supported, skipping iteration." << tcu::TestLog::EndMessage;
738
739         // result
740         if (++m_iteration == m_iterationCount)
741         {
742                 if (m_allIterationsPassed)
743                         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
744                 else
745                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Incorrect rasterization");
746
747                 return STOP;
748         }
749         else
750                 return CONTINUE;
751 }
752
753 float PointCase::getPointSize (void) const
754 {
755         return m_pointSizes[m_iteration];
756 }
757
758 void PointCase::generatePoints (int iteration, std::vector<tcu::Vec4>& outData, std::vector<PointSceneSpec::ScenePoint>& outPoints)
759 {
760         outData.resize(6);
761
762         switch (iteration)
763         {
764                 case 0:
765                         // \note: these values are chosen arbitrarily
766                         outData[0] = tcu::Vec4( 0.2f,  0.8f, 0.0f, 1.0f);
767                         outData[1] = tcu::Vec4( 0.5f,  0.2f, 0.0f, 1.0f);
768                         outData[2] = tcu::Vec4( 0.5f,  0.3f, 0.0f, 1.0f);
769                         outData[3] = tcu::Vec4(-0.5f,  0.2f, 0.0f, 1.0f);
770                         outData[4] = tcu::Vec4(-0.2f, -0.4f, 0.0f, 1.0f);
771                         outData[5] = tcu::Vec4(-0.4f,  0.2f, 0.0f, 1.0f);
772                         break;
773
774                 case 1:
775                         outData[0] = tcu::Vec4(-0.499f, 0.128f, 0.0f, 1.0f);
776                         outData[1] = tcu::Vec4(-0.501f,  -0.3f, 0.0f, 1.0f);
777                         outData[2] = tcu::Vec4(  0.11f,  -0.2f, 0.0f, 1.0f);
778                         outData[3] = tcu::Vec4(  0.11f,   0.2f, 0.0f, 1.0f);
779                         outData[4] = tcu::Vec4(  0.88f,   0.9f, 0.0f, 1.0f);
780                         outData[5] = tcu::Vec4(   0.4f,   1.2f, 0.0f, 1.0f);
781                         break;
782
783                 case 2:
784                         outData[0] = tcu::Vec4( -0.9f, -0.3f, 0.0f, 1.0f);
785                         outData[1] = tcu::Vec4(  0.3f, -0.9f, 0.0f, 1.0f);
786                         outData[2] = tcu::Vec4( -0.4f, -0.1f, 0.0f, 1.0f);
787                         outData[3] = tcu::Vec4(-0.11f,  0.2f, 0.0f, 1.0f);
788                         outData[4] = tcu::Vec4( 0.88f,  0.7f, 0.0f, 1.0f);
789                         outData[5] = tcu::Vec4( -0.4f,  0.4f, 0.0f, 1.0f);
790                         break;
791         }
792
793         outPoints.resize(outData.size());
794         for (int pointNdx = 0; pointNdx < (int)outPoints.size(); ++pointNdx)
795         {
796                 outPoints[pointNdx].position = outData[pointNdx];
797                 outPoints[pointNdx].pointSize = getPointSize();
798         }
799
800         // log
801         m_testCtx.getLog() << tcu::TestLog::Message << "Rendering " << outPoints.size() << " point(s): (point size = " << getPointSize() << ")" << tcu::TestLog::EndMessage;
802         for (int pointNdx = 0; pointNdx < (int)outPoints.size(); ++pointNdx)
803                 m_testCtx.getLog() << tcu::TestLog::Message << "Point " << (pointNdx+1) << ":\t" << outPoints[pointNdx].position << tcu::TestLog::EndMessage;
804 }
805
806 class TrianglesCase : public BaseTriangleCase
807 {
808 public:
809         TrianglesCase           (Context& context, const char* name, const char* desc, BaseRenderingCase::RenderTarget renderTarget = RENDERTARGET_DEFAULT, int numSamples = -1);
810         ~TrianglesCase          (void);
811
812         void    generateTriangles       (int iteration, std::vector<tcu::Vec4>& outData, std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles);
813 };
814
815 TrianglesCase::TrianglesCase (Context& context, const char* name, const char* desc, BaseRenderingCase::RenderTarget renderTarget, int numSamples)
816         : BaseTriangleCase(context, name, desc, GL_TRIANGLES, renderTarget, numSamples)
817 {
818 }
819
820 TrianglesCase::~TrianglesCase (void)
821 {
822
823 }
824
825 void TrianglesCase::generateTriangles (int iteration, std::vector<tcu::Vec4>& outData, std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles)
826 {
827         outData.resize(6);
828
829         switch (iteration)
830         {
831                 case 0:
832                         // \note: these values are chosen arbitrarily
833                         outData[0] = tcu::Vec4( 0.2f,  0.8f, 0.0f, 1.0f);
834                         outData[1] = tcu::Vec4( 0.5f,  0.2f, 0.0f, 1.0f);
835                         outData[2] = tcu::Vec4( 0.5f,  0.3f, 0.0f, 1.0f);
836                         outData[3] = tcu::Vec4(-0.5f,  0.2f, 0.0f, 1.0f);
837                         outData[4] = tcu::Vec4(-1.5f, -0.4f, 0.0f, 1.0f);
838                         outData[5] = tcu::Vec4(-0.4f,  0.2f, 0.0f, 1.0f);
839                         break;
840
841                 case 1:
842                         outData[0] = tcu::Vec4(-0.499f, 0.128f, 0.0f, 1.0f);
843                         outData[1] = tcu::Vec4(-0.501f,  -0.3f, 0.0f, 1.0f);
844                         outData[2] = tcu::Vec4(  0.11f,  -0.2f, 0.0f, 1.0f);
845                         outData[3] = tcu::Vec4(  0.11f,   0.2f, 0.0f, 1.0f);
846                         outData[4] = tcu::Vec4(  0.88f,   0.9f, 0.0f, 1.0f);
847                         outData[5] = tcu::Vec4(   0.4f,   1.2f, 0.0f, 1.0f);
848                         break;
849
850                 case 2:
851                         outData[0] = tcu::Vec4( -0.9f, -0.3f, 0.0f, 1.0f);
852                         outData[1] = tcu::Vec4(  1.1f, -0.9f, 0.0f, 1.0f);
853                         outData[2] = tcu::Vec4( -1.1f, -0.1f, 0.0f, 1.0f);
854                         outData[3] = tcu::Vec4(-0.11f,  0.2f, 0.0f, 1.0f);
855                         outData[4] = tcu::Vec4( 0.88f,  0.7f, 0.0f, 1.0f);
856                         outData[5] = tcu::Vec4( -0.4f,  0.4f, 0.0f, 1.0f);
857                         break;
858         }
859
860         outTriangles.resize(2);
861         outTriangles[0].positions[0] = outData[0];      outTriangles[0].sharedEdge[0] = false;
862         outTriangles[0].positions[1] = outData[1];      outTriangles[0].sharedEdge[1] = false;
863         outTriangles[0].positions[2] = outData[2];      outTriangles[0].sharedEdge[2] = false;
864
865         outTriangles[1].positions[0] = outData[3];      outTriangles[1].sharedEdge[0] = false;
866         outTriangles[1].positions[1] = outData[4];      outTriangles[1].sharedEdge[1] = false;
867         outTriangles[1].positions[2] = outData[5];      outTriangles[1].sharedEdge[2] = false;
868
869         // log
870         m_testCtx.getLog() << tcu::TestLog::Message << "Rendering " << outTriangles.size() << " triangle(s):" << tcu::TestLog::EndMessage;
871         for (int triangleNdx = 0; triangleNdx < (int)outTriangles.size(); ++triangleNdx)
872         {
873                 m_testCtx.getLog()
874                         << tcu::TestLog::Message
875                         << "Triangle " << (triangleNdx+1) << ":"
876                         << "\n\t" << outTriangles[triangleNdx].positions[0]
877                         << "\n\t" << outTriangles[triangleNdx].positions[1]
878                         << "\n\t" << outTriangles[triangleNdx].positions[2]
879                         << tcu::TestLog::EndMessage;
880         }
881 }
882
883 class TriangleStripCase : public BaseTriangleCase
884 {
885 public:
886                         TriangleStripCase       (Context& context, const char* name, const char* desc, BaseRenderingCase::RenderTarget renderTarget = RENDERTARGET_DEFAULT, int numSamples = -1);
887
888         void    generateTriangles       (int iteration, std::vector<tcu::Vec4>& outData, std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles);
889 };
890
891 TriangleStripCase::TriangleStripCase (Context& context, const char* name, const char* desc, BaseRenderingCase::RenderTarget renderTarget, int numSamples)
892         : BaseTriangleCase(context, name, desc, GL_TRIANGLE_STRIP, renderTarget, numSamples)
893 {
894 }
895
896 void TriangleStripCase::generateTriangles (int iteration, std::vector<tcu::Vec4>& outData, std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles)
897 {
898         outData.resize(5);
899
900         switch (iteration)
901         {
902                 case 0:
903                         // \note: these values are chosen arbitrarily
904                         outData[0] = tcu::Vec4(-0.504f,  0.8f,   0.0f, 1.0f);
905                         outData[1] = tcu::Vec4(-0.2f,   -0.2f,   0.0f, 1.0f);
906                         outData[2] = tcu::Vec4(-0.2f,    0.199f, 0.0f, 1.0f);
907                         outData[3] = tcu::Vec4( 0.5f,    0.201f, 0.0f, 1.0f);
908                         outData[4] = tcu::Vec4( 1.5f,    0.4f,   0.0f, 1.0f);
909                         break;
910
911                 case 1:
912                         outData[0] = tcu::Vec4(-0.499f, 0.129f,  0.0f, 1.0f);
913                         outData[1] = tcu::Vec4(-0.501f,  -0.3f,  0.0f, 1.0f);
914                         outData[2] = tcu::Vec4(  0.11f,  -0.2f,  0.0f, 1.0f);
915                         outData[3] = tcu::Vec4(  0.11f,  -0.31f, 0.0f, 1.0f);
916                         outData[4] = tcu::Vec4(  0.88f,   0.9f,  0.0f, 1.0f);
917                         break;
918
919                 case 2:
920                         outData[0] = tcu::Vec4( -0.9f, -0.3f,  0.0f, 1.0f);
921                         outData[1] = tcu::Vec4(  1.1f, -0.9f,  0.0f, 1.0f);
922                         outData[2] = tcu::Vec4(-0.87f, -0.1f,  0.0f, 1.0f);
923                         outData[3] = tcu::Vec4(-0.11f,  0.19f, 0.0f, 1.0f);
924                         outData[4] = tcu::Vec4( 0.88f,  0.7f,  0.0f, 1.0f);
925                         break;
926         }
927
928         outTriangles.resize(3);
929         outTriangles[0].positions[0] = outData[0];      outTriangles[0].sharedEdge[0] = false;
930         outTriangles[0].positions[1] = outData[1];      outTriangles[0].sharedEdge[1] = true;
931         outTriangles[0].positions[2] = outData[2];      outTriangles[0].sharedEdge[2] = false;
932
933         outTriangles[1].positions[0] = outData[2];      outTriangles[1].sharedEdge[0] = true;
934         outTriangles[1].positions[1] = outData[1];      outTriangles[1].sharedEdge[1] = false;
935         outTriangles[1].positions[2] = outData[3];      outTriangles[1].sharedEdge[2] = true;
936
937         outTriangles[2].positions[0] = outData[2];      outTriangles[2].sharedEdge[0] = true;
938         outTriangles[2].positions[1] = outData[3];      outTriangles[2].sharedEdge[1] = false;
939         outTriangles[2].positions[2] = outData[4];      outTriangles[2].sharedEdge[2] = false;
940
941         // log
942         m_testCtx.getLog() << tcu::TestLog::Message << "Rendering triangle strip, " << outData.size() << " vertices." << tcu::TestLog::EndMessage;
943         for (int vtxNdx = 0; vtxNdx < (int)outData.size(); ++vtxNdx)
944         {
945                 m_testCtx.getLog()
946                         << tcu::TestLog::Message
947                         << "\t" << outData[vtxNdx]
948                         << tcu::TestLog::EndMessage;
949         }
950 }
951
952 class TriangleFanCase : public BaseTriangleCase
953 {
954 public:
955                         TriangleFanCase         (Context& context, const char* name, const char* desc, BaseRenderingCase::RenderTarget renderTarget = RENDERTARGET_DEFAULT, int numSamples = -1);
956
957         void    generateTriangles       (int iteration, std::vector<tcu::Vec4>& outData, std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles);
958 };
959
960 TriangleFanCase::TriangleFanCase (Context& context, const char* name, const char* desc, BaseRenderingCase::RenderTarget renderTarget, int numSamples)
961         : BaseTriangleCase(context, name, desc, GL_TRIANGLE_FAN, renderTarget, numSamples)
962 {
963 }
964
965 void TriangleFanCase::generateTriangles (int iteration, std::vector<tcu::Vec4>& outData, std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles)
966 {
967         outData.resize(5);
968
969         switch (iteration)
970         {
971                 case 0:
972                         // \note: these values are chosen arbitrarily
973                         outData[0] = tcu::Vec4( 0.01f,  0.0f, 0.0f, 1.0f);
974                         outData[1] = tcu::Vec4( 0.5f,   0.2f, 0.0f, 1.0f);
975                         outData[2] = tcu::Vec4( 0.46f,  0.3f, 0.0f, 1.0f);
976                         outData[3] = tcu::Vec4(-0.5f,   0.2f, 0.0f, 1.0f);
977                         outData[4] = tcu::Vec4(-1.5f,  -0.4f, 0.0f, 1.0f);
978                         break;
979
980                 case 1:
981                         outData[0] = tcu::Vec4(-0.499f, 0.128f, 0.0f, 1.0f);
982                         outData[1] = tcu::Vec4(-0.501f,  -0.3f, 0.0f, 1.0f);
983                         outData[2] = tcu::Vec4(  0.11f,  -0.2f, 0.0f, 1.0f);
984                         outData[3] = tcu::Vec4(  0.11f,   0.2f, 0.0f, 1.0f);
985                         outData[4] = tcu::Vec4(  0.88f,   0.9f, 0.0f, 1.0f);
986                         break;
987
988                 case 2:
989                         outData[0] = tcu::Vec4( -0.9f, -0.3f, 0.0f, 1.0f);
990                         outData[1] = tcu::Vec4(  1.1f, -0.9f, 0.0f, 1.0f);
991                         outData[2] = tcu::Vec4(  0.7f, -0.1f, 0.0f, 1.0f);
992                         outData[3] = tcu::Vec4( 0.11f,  0.2f, 0.0f, 1.0f);
993                         outData[4] = tcu::Vec4( 0.88f,  0.7f, 0.0f, 1.0f);
994                         break;
995         }
996
997         outTriangles.resize(3);
998         outTriangles[0].positions[0] = outData[0];      outTriangles[0].sharedEdge[0] = false;
999         outTriangles[0].positions[1] = outData[1];      outTriangles[0].sharedEdge[1] = false;
1000         outTriangles[0].positions[2] = outData[2];      outTriangles[0].sharedEdge[2] = true;
1001
1002         outTriangles[1].positions[0] = outData[0];      outTriangles[1].sharedEdge[0] = true;
1003         outTriangles[1].positions[1] = outData[2];      outTriangles[1].sharedEdge[1] = false;
1004         outTriangles[1].positions[2] = outData[3];      outTriangles[1].sharedEdge[2] = true;
1005
1006         outTriangles[2].positions[0] = outData[0];      outTriangles[2].sharedEdge[0] = true;
1007         outTriangles[2].positions[1] = outData[3];      outTriangles[2].sharedEdge[1] = false;
1008         outTriangles[2].positions[2] = outData[4];      outTriangles[2].sharedEdge[2] = false;
1009
1010         // log
1011         m_testCtx.getLog() << tcu::TestLog::Message << "Rendering triangle fan, " << outData.size() << " vertices." << tcu::TestLog::EndMessage;
1012         for (int vtxNdx = 0; vtxNdx < (int)outData.size(); ++vtxNdx)
1013         {
1014                 m_testCtx.getLog()
1015                         << tcu::TestLog::Message
1016                         << "\t" << outData[vtxNdx]
1017                         << tcu::TestLog::EndMessage;
1018         }
1019 }
1020
1021 class LinesCase : public BaseLineCase
1022 {
1023 public:
1024                         LinesCase               (Context& context, const char* name, const char* desc, PrimitiveWideness wideness, BaseRenderingCase::RenderTarget renderTarget = RENDERTARGET_DEFAULT, int numSamples = -1);
1025
1026         void    generateLines   (int iteration, std::vector<tcu::Vec4>& outData, std::vector<LineSceneSpec::SceneLine>& outLines);
1027 };
1028
1029 LinesCase::LinesCase (Context& context, const char* name, const char* desc, PrimitiveWideness wideness, BaseRenderingCase::RenderTarget renderTarget, int numSamples)
1030         : BaseLineCase(context, name, desc, GL_LINES, wideness, renderTarget, numSamples)
1031 {
1032 }
1033
1034 void LinesCase::generateLines (int iteration, std::vector<tcu::Vec4>& outData, std::vector<LineSceneSpec::SceneLine>& outLines)
1035 {
1036         outData.resize(6);
1037
1038         switch (iteration)
1039         {
1040                 case 0:
1041                         // \note: these values are chosen arbitrarily
1042                         outData[0] = tcu::Vec4( 0.01f,  0.0f, 0.0f, 1.0f);
1043                         outData[1] = tcu::Vec4( 0.5f,   0.2f, 0.0f, 1.0f);
1044                         outData[2] = tcu::Vec4( 0.46f,  0.3f, 0.0f, 1.0f);
1045                         outData[3] = tcu::Vec4(-0.3f,   0.2f, 0.0f, 1.0f);
1046                         outData[4] = tcu::Vec4(-1.5f,  -0.4f, 0.0f, 1.0f);
1047                         outData[5] = tcu::Vec4( 0.1f,   0.5f, 0.0f, 1.0f);
1048                         break;
1049
1050                 case 1:
1051                         outData[0] = tcu::Vec4(-0.499f, 0.128f, 0.0f, 1.0f);
1052                         outData[1] = tcu::Vec4(-0.501f,  -0.3f, 0.0f, 1.0f);
1053                         outData[2] = tcu::Vec4(  0.11f,  -0.2f, 0.0f, 1.0f);
1054                         outData[3] = tcu::Vec4(  0.11f,   0.2f, 0.0f, 1.0f);
1055                         outData[4] = tcu::Vec4(  0.88f,   0.9f, 0.0f, 1.0f);
1056                         outData[5] = tcu::Vec4(  0.18f,  -0.2f, 0.0f, 1.0f);
1057                         break;
1058
1059                 case 2:
1060                         outData[0] = tcu::Vec4( -0.9f, -0.3f, 0.0f, 1.0f);
1061                         outData[1] = tcu::Vec4(  1.1f, -0.9f, 0.0f, 1.0f);
1062                         outData[2] = tcu::Vec4(  0.7f, -0.1f, 0.0f, 1.0f);
1063                         outData[3] = tcu::Vec4( 0.11f,  0.2f, 0.0f, 1.0f);
1064                         outData[4] = tcu::Vec4( 0.88f,  0.7f, 0.0f, 1.0f);
1065                         outData[5] = tcu::Vec4(  0.8f, -0.7f, 0.0f, 1.0f);
1066                         break;
1067         }
1068
1069         outLines.resize(3);
1070         outLines[0].positions[0] = outData[0];
1071         outLines[0].positions[1] = outData[1];
1072         outLines[1].positions[0] = outData[2];
1073         outLines[1].positions[1] = outData[3];
1074         outLines[2].positions[0] = outData[4];
1075         outLines[2].positions[1] = outData[5];
1076
1077         // log
1078         m_testCtx.getLog() << tcu::TestLog::Message << "Rendering " << outLines.size() << " lines(s): (width = " << getLineWidth() << ")" << tcu::TestLog::EndMessage;
1079         for (int lineNdx = 0; lineNdx < (int)outLines.size(); ++lineNdx)
1080         {
1081                 m_testCtx.getLog()
1082                         << tcu::TestLog::Message
1083                         << "Line " << (lineNdx+1) << ":"
1084                         << "\n\t" << outLines[lineNdx].positions[0]
1085                         << "\n\t" << outLines[lineNdx].positions[1]
1086                         << tcu::TestLog::EndMessage;
1087         }
1088 }
1089
1090 class LineStripCase : public BaseLineCase
1091 {
1092 public:
1093                         LineStripCase   (Context& context, const char* name, const char* desc, PrimitiveWideness wideness, BaseRenderingCase::RenderTarget renderTarget = RENDERTARGET_DEFAULT, int numSamples = -1);
1094
1095         void    generateLines   (int iteration, std::vector<tcu::Vec4>& outData, std::vector<LineSceneSpec::SceneLine>& outLines);
1096 };
1097
1098 LineStripCase::LineStripCase (Context& context, const char* name, const char* desc, PrimitiveWideness wideness, BaseRenderingCase::RenderTarget renderTarget, int numSamples)
1099         : BaseLineCase(context, name, desc, GL_LINE_STRIP, wideness, renderTarget, numSamples)
1100 {
1101 }
1102
1103 void LineStripCase::generateLines (int iteration, std::vector<tcu::Vec4>& outData, std::vector<LineSceneSpec::SceneLine>& outLines)
1104 {
1105         outData.resize(4);
1106
1107         switch (iteration)
1108         {
1109                 case 0:
1110                         // \note: these values are chosen arbitrarily
1111                         outData[0] = tcu::Vec4( 0.01f,  0.0f, 0.0f, 1.0f);
1112                         outData[1] = tcu::Vec4( 0.5f,   0.2f, 0.0f, 1.0f);
1113                         outData[2] = tcu::Vec4( 0.46f,  0.3f, 0.0f, 1.0f);
1114                         outData[3] = tcu::Vec4(-0.5f,   0.2f, 0.0f, 1.0f);
1115                         break;
1116
1117                 case 1:
1118                         outData[0] = tcu::Vec4(-0.499f, 0.128f, 0.0f, 1.0f);
1119                         outData[1] = tcu::Vec4(-0.501f,  -0.3f, 0.0f, 1.0f);
1120                         outData[2] = tcu::Vec4(  0.11f,  -0.2f, 0.0f, 1.0f);
1121                         outData[3] = tcu::Vec4(  0.11f,   0.2f, 0.0f, 1.0f);
1122                         break;
1123
1124                 case 2:
1125                         outData[0] = tcu::Vec4( -0.9f, -0.3f, 0.0f, 1.0f);
1126                         outData[1] = tcu::Vec4(  1.1f, -0.9f, 0.0f, 1.0f);
1127                         outData[2] = tcu::Vec4(  0.7f, -0.1f, 0.0f, 1.0f);
1128                         outData[3] = tcu::Vec4( 0.11f,  0.2f, 0.0f, 1.0f);
1129                         break;
1130         }
1131
1132         outLines.resize(3);
1133         outLines[0].positions[0] = outData[0];
1134         outLines[0].positions[1] = outData[1];
1135         outLines[1].positions[0] = outData[1];
1136         outLines[1].positions[1] = outData[2];
1137         outLines[2].positions[0] = outData[2];
1138         outLines[2].positions[1] = outData[3];
1139
1140         // log
1141         m_testCtx.getLog() << tcu::TestLog::Message << "Rendering line strip, width = " << getLineWidth() << ", " << outData.size() << " vertices." << tcu::TestLog::EndMessage;
1142         for (int vtxNdx = 0; vtxNdx < (int)outData.size(); ++vtxNdx)
1143         {
1144                 m_testCtx.getLog()
1145                         << tcu::TestLog::Message
1146                         << "\t" << outData[vtxNdx]
1147                         << tcu::TestLog::EndMessage;
1148         }
1149 }
1150
1151 class LineLoopCase : public BaseLineCase
1152 {
1153 public:
1154                         LineLoopCase    (Context& context, const char* name, const char* desc, PrimitiveWideness wideness, BaseRenderingCase::RenderTarget renderTarget = RENDERTARGET_DEFAULT, int numSamples = -1);
1155
1156         void    generateLines   (int iteration, std::vector<tcu::Vec4>& outData, std::vector<LineSceneSpec::SceneLine>& outLines);
1157 };
1158
1159 LineLoopCase::LineLoopCase (Context& context, const char* name, const char* desc, PrimitiveWideness wideness, BaseRenderingCase::RenderTarget renderTarget, int numSamples)
1160         : BaseLineCase(context, name, desc, GL_LINE_LOOP, wideness, renderTarget, numSamples)
1161 {
1162 }
1163
1164 void LineLoopCase::generateLines (int iteration, std::vector<tcu::Vec4>& outData, std::vector<LineSceneSpec::SceneLine>& outLines)
1165 {
1166         outData.resize(4);
1167
1168         switch (iteration)
1169         {
1170                 case 0:
1171                         // \note: these values are chosen arbitrarily
1172                         outData[0] = tcu::Vec4( 0.01f,  0.0f, 0.0f, 1.0f);
1173                         outData[1] = tcu::Vec4( 0.5f,   0.2f, 0.0f, 1.0f);
1174                         outData[2] = tcu::Vec4( 0.46f,  0.3f, 0.0f, 1.0f);
1175                         outData[3] = tcu::Vec4(-0.5f,   0.2f, 0.0f, 1.0f);
1176                         break;
1177
1178                 case 1:
1179                         outData[0] = tcu::Vec4(-0.499f, 0.128f, 0.0f, 1.0f);
1180                         outData[1] = tcu::Vec4(-0.501f,  -0.3f, 0.0f, 1.0f);
1181                         outData[2] = tcu::Vec4(  0.11f,  -0.2f, 0.0f, 1.0f);
1182                         outData[3] = tcu::Vec4(  0.11f,   0.2f, 0.0f, 1.0f);
1183                         break;
1184
1185                 case 2:
1186                         outData[0] = tcu::Vec4( -0.9f, -0.3f, 0.0f, 1.0f);
1187                         outData[1] = tcu::Vec4(  1.1f, -0.9f, 0.0f, 1.0f);
1188                         outData[2] = tcu::Vec4(  0.7f, -0.1f, 0.0f, 1.0f);
1189                         outData[3] = tcu::Vec4( 0.11f,  0.2f, 0.0f, 1.0f);
1190                         break;
1191         }
1192
1193         outLines.resize(4);
1194         outLines[0].positions[0] = outData[0];
1195         outLines[0].positions[1] = outData[1];
1196         outLines[1].positions[0] = outData[1];
1197         outLines[1].positions[1] = outData[2];
1198         outLines[2].positions[0] = outData[2];
1199         outLines[2].positions[1] = outData[3];
1200         outLines[3].positions[0] = outData[3];
1201         outLines[3].positions[1] = outData[0];
1202
1203         // log
1204         m_testCtx.getLog() << tcu::TestLog::Message << "Rendering line loop, width = " << getLineWidth() << ", " << outData.size() << " vertices." << tcu::TestLog::EndMessage;
1205         for (int vtxNdx = 0; vtxNdx < (int)outData.size(); ++vtxNdx)
1206         {
1207                 m_testCtx.getLog()
1208                         << tcu::TestLog::Message
1209                         << "\t" << outData[vtxNdx]
1210                         << tcu::TestLog::EndMessage;
1211         }
1212 }
1213
1214 class FillRuleCase : public BaseRenderingCase
1215 {
1216 public:
1217         enum FillRuleCaseType
1218         {
1219                 FILLRULECASE_BASIC = 0,
1220                 FILLRULECASE_REVERSED,
1221                 FILLRULECASE_CLIPPED_FULL,
1222                 FILLRULECASE_CLIPPED_PARTIAL,
1223                 FILLRULECASE_PROJECTED,
1224
1225                 FILLRULECASE_LAST
1226         };
1227
1228                                                         FillRuleCase            (Context& ctx, const char* name, const char* desc, FillRuleCaseType type, RenderTarget renderTarget = RENDERTARGET_DEFAULT, int numSamples = -1);
1229                                                         ~FillRuleCase           (void);
1230         IterateResult                   iterate                         (void);
1231
1232 private:
1233         int                                             getRenderSize           (FillRuleCase::FillRuleCaseType type) const;
1234         int                                             getNumIterations        (FillRuleCase::FillRuleCaseType type) const;
1235         void                                    generateTriangles       (int iteration, std::vector<tcu::Vec4>& outData) const;
1236
1237         const FillRuleCaseType  m_caseType;
1238         int                                             m_iteration;
1239         const int                               m_iterationCount;
1240         bool                                    m_allIterationsPassed;
1241
1242 };
1243
1244 FillRuleCase::FillRuleCase (Context& ctx, const char* name, const char* desc, FillRuleCaseType type, RenderTarget renderTarget, int numSamples)
1245         : BaseRenderingCase             (ctx, name, desc, renderTarget, numSamples, getRenderSize(type))
1246         , m_caseType                    (type)
1247         , m_iteration                   (0)
1248         , m_iterationCount              (getNumIterations(type))
1249         , m_allIterationsPassed (true)
1250 {
1251         DE_ASSERT(type < FILLRULECASE_LAST);
1252 }
1253
1254 FillRuleCase::~FillRuleCase (void)
1255 {
1256         deinit();
1257 }
1258
1259 FillRuleCase::IterateResult FillRuleCase::iterate (void)
1260 {
1261         const std::string                                               iterationDescription    = "Test iteration " + de::toString(m_iteration+1) + " / " + de::toString(m_iterationCount);
1262         const tcu::ScopedLogSection                             section                                 (m_testCtx.getLog(), iterationDescription, iterationDescription);
1263         const int                                                               thresholdRed                    = 1 << (8 - getPixelFormat().redBits);
1264         const int                                                               thresholdGreen                  = 1 << (8 - getPixelFormat().greenBits);
1265         const int                                                               thresholdBlue                   = 1 << (8 - getPixelFormat().blueBits);
1266         tcu::Surface                                                    resultImage                             (m_renderSize, m_renderSize);
1267         std::vector<tcu::Vec4>                                  drawBuffer;
1268         bool                                                                    imageShown                              = false;
1269
1270         generateTriangles(m_iteration, drawBuffer);
1271
1272         // draw image
1273         {
1274                 const glw::Functions&                   gl                              = m_context.getRenderContext().getFunctions();
1275                 const std::vector<tcu::Vec4>    colorBuffer             (drawBuffer.size(), tcu::Vec4(0.5f, 0.5f, 0.5f, 1.0f));
1276
1277                 m_testCtx.getLog() << tcu::TestLog::Message << "Drawing gray triangles with shared edges.\nEnabling additive blending to detect overlapping fragments." << tcu::TestLog::EndMessage;
1278
1279                 gl.enable(GL_BLEND);
1280                 gl.blendEquation(GL_FUNC_ADD);
1281                 gl.blendFunc(GL_ONE, GL_ONE);
1282                 drawPrimitives(resultImage, drawBuffer, colorBuffer, GL_TRIANGLES);
1283         }
1284
1285         // verify no overdraw
1286         {
1287                 const tcu::RGBA triangleColor   = tcu::RGBA(127, 127, 127, 255);
1288                 bool                    overdraw                = false;
1289
1290                 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying result." << tcu::TestLog::EndMessage;
1291
1292                 for (int y = 0; y < resultImage.getHeight(); ++y)
1293                 for (int x = 0; x < resultImage.getWidth();  ++x)
1294                 {
1295                         const tcu::RGBA color = resultImage.getPixel(x, y);
1296
1297                         // color values are greater than triangle color? Allow lower values for multisampled edges and background.
1298                         if ((color.getRed()   - triangleColor.getRed())   > thresholdRed   ||
1299                                 (color.getGreen() - triangleColor.getGreen()) > thresholdGreen ||
1300                                 (color.getBlue()  - triangleColor.getBlue())  > thresholdBlue)
1301                                 overdraw = true;
1302                 }
1303
1304                 // results
1305                 if (!overdraw)
1306                         m_testCtx.getLog() << tcu::TestLog::Message << "No overlapping fragments detected." << tcu::TestLog::EndMessage;
1307                 else
1308                 {
1309                         m_testCtx.getLog()      << tcu::TestLog::Message << "Overlapping fragments detected, image is not valid." << tcu::TestLog::EndMessage;
1310                         m_testCtx.getLog()      << tcu::TestLog::ImageSet("Result of rendering", "Result of rendering")
1311                                                                 << tcu::TestLog::Image("Result", "Result", resultImage)
1312                                                                 << tcu::TestLog::EndImageSet;
1313
1314                         imageShown = true;
1315                         m_allIterationsPassed = false;
1316                 }
1317         }
1318
1319         // verify no missing fragments in the full viewport case
1320         if (m_caseType == FILLRULECASE_CLIPPED_FULL)
1321         {
1322                 bool missingFragments = false;
1323
1324                 m_testCtx.getLog() << tcu::TestLog::Message << "Searching missing fragments." << tcu::TestLog::EndMessage;
1325
1326                 for (int y = 0; y < resultImage.getHeight(); ++y)
1327                 for (int x = 0; x < resultImage.getWidth();  ++x)
1328                 {
1329                         const tcu::RGBA color = resultImage.getPixel(x, y);
1330
1331                         // black? (background)
1332                         if (color.getRed()   <= thresholdRed   ||
1333                                 color.getGreen() <= thresholdGreen ||
1334                                 color.getBlue()  <= thresholdBlue)
1335                                 missingFragments = true;
1336                 }
1337
1338                 // results
1339                 if (!missingFragments)
1340                         m_testCtx.getLog() << tcu::TestLog::Message << "No missing fragments detected." << tcu::TestLog::EndMessage;
1341                 else
1342                 {
1343                         m_testCtx.getLog()      << tcu::TestLog::Message << "Missing fragments detected, image is not valid." << tcu::TestLog::EndMessage;
1344
1345                         if (!imageShown)
1346                         {
1347                                 m_testCtx.getLog()      << tcu::TestLog::ImageSet("Result of rendering", "Result of rendering")
1348                                                                         << tcu::TestLog::Image("Result", "Result", resultImage)
1349                                                                         << tcu::TestLog::EndImageSet;
1350                         }
1351
1352                         m_allIterationsPassed = false;
1353                 }
1354         }
1355
1356         // result
1357         if (++m_iteration == m_iterationCount)
1358         {
1359                 if (m_allIterationsPassed)
1360                         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1361                 else
1362                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Found invalid pixels");
1363
1364                 return STOP;
1365         }
1366         else
1367                 return CONTINUE;
1368 }
1369
1370 int FillRuleCase::getRenderSize (FillRuleCase::FillRuleCaseType type) const
1371 {
1372         if (type == FILLRULECASE_CLIPPED_FULL || type == FILLRULECASE_CLIPPED_PARTIAL)
1373                 return DEFAULT_RENDER_SIZE / 4;
1374         else
1375                 return DEFAULT_RENDER_SIZE;
1376 }
1377
1378 int FillRuleCase::getNumIterations (FillRuleCase::FillRuleCaseType type) const
1379 {
1380         if (type == FILLRULECASE_CLIPPED_FULL || type == FILLRULECASE_CLIPPED_PARTIAL)
1381                 return 15;
1382         else
1383                 return 2;
1384 }
1385
1386 void FillRuleCase::generateTriangles (int iteration, std::vector<tcu::Vec4>& outData) const
1387 {
1388         switch (m_caseType)
1389         {
1390                 case FILLRULECASE_BASIC:
1391                 case FILLRULECASE_REVERSED:
1392                 case FILLRULECASE_PROJECTED:
1393                 {
1394                         const int       numRows         = 4;
1395                         const int       numColumns      = 4;
1396                         const float     quadSide        = 0.15f;
1397                         de::Random      rnd                     (0xabcd);
1398
1399                         outData.resize(6 * numRows * numColumns);
1400
1401                         for (int col = 0; col < numColumns; ++col)
1402                         for (int row = 0; row < numRows;    ++row)
1403                         {
1404                                 const tcu::Vec2 center          = tcu::Vec2((row + 0.5f) / numRows * 2.0f - 1.0f, (col + 0.5f) / numColumns * 2.0f - 1.0f);
1405                                 const float             rotation        = (iteration * numColumns * numRows + col * numRows + row) / (float)(m_iterationCount * numColumns * numRows) * DE_PI / 2.0f;
1406                                 const tcu::Vec2 sideH           = quadSide * tcu::Vec2(deFloatCos(rotation), deFloatSin(rotation));
1407                                 const tcu::Vec2 sideV           = tcu::Vec2(sideH.y(), -sideH.x());
1408                                 const tcu::Vec2 quad[4]         =
1409                                 {
1410                                         center + sideH + sideV,
1411                                         center + sideH - sideV,
1412                                         center - sideH - sideV,
1413                                         center - sideH + sideV,
1414                                 };
1415
1416                                 if (m_caseType == FILLRULECASE_BASIC)
1417                                 {
1418                                         outData[6 * (col * numRows + row) + 0] = tcu::Vec4(quad[0].x(), quad[0].y(), 0.0f, 1.0f);
1419                                         outData[6 * (col * numRows + row) + 1] = tcu::Vec4(quad[1].x(), quad[1].y(), 0.0f, 1.0f);
1420                                         outData[6 * (col * numRows + row) + 2] = tcu::Vec4(quad[2].x(), quad[2].y(), 0.0f, 1.0f);
1421                                         outData[6 * (col * numRows + row) + 3] = tcu::Vec4(quad[2].x(), quad[2].y(), 0.0f, 1.0f);
1422                                         outData[6 * (col * numRows + row) + 4] = tcu::Vec4(quad[0].x(), quad[0].y(), 0.0f, 1.0f);
1423                                         outData[6 * (col * numRows + row) + 5] = tcu::Vec4(quad[3].x(), quad[3].y(), 0.0f, 1.0f);
1424                                 }
1425                                 else if (m_caseType == FILLRULECASE_REVERSED)
1426                                 {
1427                                         outData[6 * (col * numRows + row) + 0] = tcu::Vec4(quad[0].x(), quad[0].y(), 0.0f, 1.0f);
1428                                         outData[6 * (col * numRows + row) + 1] = tcu::Vec4(quad[1].x(), quad[1].y(), 0.0f, 1.0f);
1429                                         outData[6 * (col * numRows + row) + 2] = tcu::Vec4(quad[2].x(), quad[2].y(), 0.0f, 1.0f);
1430                                         outData[6 * (col * numRows + row) + 3] = tcu::Vec4(quad[0].x(), quad[0].y(), 0.0f, 1.0f);
1431                                         outData[6 * (col * numRows + row) + 4] = tcu::Vec4(quad[2].x(), quad[2].y(), 0.0f, 1.0f);
1432                                         outData[6 * (col * numRows + row) + 5] = tcu::Vec4(quad[3].x(), quad[3].y(), 0.0f, 1.0f);
1433                                 }
1434                                 else if (m_caseType == FILLRULECASE_PROJECTED)
1435                                 {
1436                                         const float w0 = rnd.getFloat(0.1f, 4.0f);
1437                                         const float w1 = rnd.getFloat(0.1f, 4.0f);
1438                                         const float w2 = rnd.getFloat(0.1f, 4.0f);
1439                                         const float w3 = rnd.getFloat(0.1f, 4.0f);
1440
1441                                         outData[6 * (col * numRows + row) + 0] = tcu::Vec4(quad[0].x() * w0, quad[0].y() * w0, 0.0f, w0);
1442                                         outData[6 * (col * numRows + row) + 1] = tcu::Vec4(quad[1].x() * w1, quad[1].y() * w1, 0.0f, w1);
1443                                         outData[6 * (col * numRows + row) + 2] = tcu::Vec4(quad[2].x() * w2, quad[2].y() * w2, 0.0f, w2);
1444                                         outData[6 * (col * numRows + row) + 3] = tcu::Vec4(quad[2].x() * w2, quad[2].y() * w2, 0.0f, w2);
1445                                         outData[6 * (col * numRows + row) + 4] = tcu::Vec4(quad[0].x() * w0, quad[0].y() * w0, 0.0f, w0);
1446                                         outData[6 * (col * numRows + row) + 5] = tcu::Vec4(quad[3].x() * w3, quad[3].y() * w3, 0.0f, w3);
1447                                 }
1448                                 else
1449                                         DE_ASSERT(DE_FALSE);
1450                         }
1451
1452                         break;
1453                 }
1454
1455                 case FILLRULECASE_CLIPPED_PARTIAL:
1456                 case FILLRULECASE_CLIPPED_FULL:
1457                 {
1458                         const float             quadSide        = (m_caseType == FILLRULECASE_CLIPPED_PARTIAL) ? (1.0f) : (2.0f);
1459                         const tcu::Vec2 center          = (m_caseType == FILLRULECASE_CLIPPED_PARTIAL) ? (tcu::Vec2(0.5f, 0.5f)) : (tcu::Vec2(0.0f, 0.0f));
1460                         const float             rotation        = (iteration) / (float)(m_iterationCount - 1) * DE_PI / 2.0f;
1461                         const tcu::Vec2 sideH           = quadSide * tcu::Vec2(deFloatCos(rotation), deFloatSin(rotation));
1462                         const tcu::Vec2 sideV           = tcu::Vec2(sideH.y(), -sideH.x());
1463                         const tcu::Vec2 quad[4]         =
1464                         {
1465                                 center + sideH + sideV,
1466                                 center + sideH - sideV,
1467                                 center - sideH - sideV,
1468                                 center - sideH + sideV,
1469                         };
1470
1471                         outData.resize(6);
1472                         outData[0] = tcu::Vec4(quad[0].x(), quad[0].y(), 0.0f, 1.0f);
1473                         outData[1] = tcu::Vec4(quad[1].x(), quad[1].y(), 0.0f, 1.0f);
1474                         outData[2] = tcu::Vec4(quad[2].x(), quad[2].y(), 0.0f, 1.0f);
1475                         outData[3] = tcu::Vec4(quad[2].x(), quad[2].y(), 0.0f, 1.0f);
1476                         outData[4] = tcu::Vec4(quad[0].x(), quad[0].y(), 0.0f, 1.0f);
1477                         outData[5] = tcu::Vec4(quad[3].x(), quad[3].y(), 0.0f, 1.0f);
1478                         break;
1479                 }
1480
1481                 default:
1482                         DE_ASSERT(DE_FALSE);
1483         }
1484 }
1485
1486 class CullingTest : public BaseRenderingCase
1487 {
1488 public:
1489                                                 CullingTest                     (Context& ctx, const char* name, const char* desc, glw::GLenum cullMode, glw::GLenum primitive, glw::GLenum faceOrder);
1490                                                 ~CullingTest            (void);
1491         IterateResult           iterate                         (void);
1492
1493 private:
1494         void                            generateVertices        (std::vector<tcu::Vec4>& outData) const;
1495         void                            extractTriangles        (std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles, const std::vector<tcu::Vec4>& vertices) const;
1496         bool                            triangleOrder           (const tcu::Vec4& v0, const tcu::Vec4& v1, const tcu::Vec4& v2) const;
1497
1498         const glw::GLenum       m_cullMode;
1499         const glw::GLenum       m_primitive;
1500         const glw::GLenum       m_faceOrder;
1501 };
1502
1503 CullingTest::CullingTest (Context& ctx, const char* name, const char* desc, glw::GLenum cullMode, glw::GLenum primitive, glw::GLenum faceOrder)
1504         : BaseRenderingCase     (ctx, name, desc, RENDERTARGET_DEFAULT, -1, DEFAULT_RENDER_SIZE)
1505         , m_cullMode            (cullMode)
1506         , m_primitive           (primitive)
1507         , m_faceOrder           (faceOrder)
1508 {
1509 }
1510
1511 CullingTest::~CullingTest (void)
1512 {
1513 }
1514
1515 CullingTest::IterateResult CullingTest::iterate (void)
1516 {
1517         tcu::Surface                                                                    resultImage(m_renderSize, m_renderSize);
1518         std::vector<tcu::Vec4>                                                  drawBuffer;
1519         std::vector<TriangleSceneSpec::SceneTriangle>   triangles;
1520
1521         // generate scene
1522         generateVertices(drawBuffer);
1523         extractTriangles(triangles, drawBuffer);
1524
1525         // draw image
1526         {
1527                 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1528
1529                 gl.enable(GL_CULL_FACE);
1530                 gl.cullFace(m_cullMode);
1531                 gl.frontFace(m_faceOrder);
1532
1533                 m_testCtx.getLog() << tcu::TestLog::Message << "Setting front face to " << glu::getWindingName(m_faceOrder) << tcu::TestLog::EndMessage;
1534                 m_testCtx.getLog() << tcu::TestLog::Message << "Setting cull face to " << glu::getFaceName(m_cullMode) << tcu::TestLog::EndMessage;
1535                 m_testCtx.getLog() << tcu::TestLog::Message << "Drawing test pattern (" << glu::getPrimitiveTypeName(m_primitive) << ")" << tcu::TestLog::EndMessage;
1536
1537                 drawPrimitives(resultImage, drawBuffer, m_primitive);
1538         }
1539
1540         // compare
1541         {
1542                 RasterizationArguments  args;
1543                 TriangleSceneSpec               scene;
1544
1545                 args.numSamples         = m_numSamples;
1546                 args.subpixelBits       = m_subpixelBits;
1547                 args.redBits            = getPixelFormat().redBits;
1548                 args.greenBits          = getPixelFormat().greenBits;
1549                 args.blueBits           = getPixelFormat().blueBits;
1550
1551                 scene.triangles.swap(triangles);
1552
1553                 if (verifyTriangleGroupRasterization(resultImage, scene, args, m_testCtx.getLog(), VERIFICATIONMODE_WEAK))
1554                         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1555                 else
1556                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Incorrect rendering");
1557         }
1558
1559         return STOP;
1560 }
1561
1562 void CullingTest::generateVertices (std::vector<tcu::Vec4>& outData) const
1563 {
1564         de::Random rnd(543210);
1565
1566         outData.resize(6);
1567         for (int vtxNdx = 0; vtxNdx < (int)outData.size(); ++vtxNdx)
1568         {
1569                 outData[vtxNdx].x() = rnd.getFloat(-0.9f, 0.9f);
1570                 outData[vtxNdx].y() = rnd.getFloat(-0.9f, 0.9f);
1571                 outData[vtxNdx].z() = 0.0f;
1572                 outData[vtxNdx].w() = 1.0f;
1573         }
1574 }
1575
1576 void CullingTest::extractTriangles (std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles, const std::vector<tcu::Vec4>& vertices) const
1577 {
1578         const bool cullDirection = (m_cullMode == GL_FRONT) ^ (m_faceOrder == GL_CCW);
1579
1580         // No triangles
1581         if (m_cullMode == GL_FRONT_AND_BACK)
1582                 return;
1583
1584         switch (m_primitive)
1585         {
1586                 case GL_TRIANGLES:
1587                 {
1588                         for (int vtxNdx = 0; vtxNdx < (int)vertices.size() - 2; vtxNdx += 3)
1589                         {
1590                                 const tcu::Vec4& v0 = vertices[vtxNdx + 0];
1591                                 const tcu::Vec4& v1 = vertices[vtxNdx + 1];
1592                                 const tcu::Vec4& v2 = vertices[vtxNdx + 2];
1593
1594                                 if (triangleOrder(v0, v1, v2) != cullDirection)
1595                                 {
1596                                         TriangleSceneSpec::SceneTriangle tri;
1597                                         tri.positions[0] = v0;  tri.sharedEdge[0] = false;
1598                                         tri.positions[1] = v1;  tri.sharedEdge[1] = false;
1599                                         tri.positions[2] = v2;  tri.sharedEdge[2] = false;
1600
1601                                         outTriangles.push_back(tri);
1602                                 }
1603                         }
1604                         break;
1605                 }
1606
1607                 case GL_TRIANGLE_STRIP:
1608                 {
1609                         for (int vtxNdx = 0; vtxNdx < (int)vertices.size() - 2; ++vtxNdx)
1610                         {
1611                                 const tcu::Vec4& v0 = vertices[vtxNdx + 0];
1612                                 const tcu::Vec4& v1 = vertices[vtxNdx + 1];
1613                                 const tcu::Vec4& v2 = vertices[vtxNdx + 2];
1614
1615                                 if (triangleOrder(v0, v1, v2) != (cullDirection ^ (vtxNdx % 2 != 0)))
1616                                 {
1617                                         TriangleSceneSpec::SceneTriangle tri;
1618                                         tri.positions[0] = v0;  tri.sharedEdge[0] = false;
1619                                         tri.positions[1] = v1;  tri.sharedEdge[1] = false;
1620                                         tri.positions[2] = v2;  tri.sharedEdge[2] = false;
1621
1622                                         outTriangles.push_back(tri);
1623                                 }
1624                         }
1625                         break;
1626                 }
1627
1628                 case GL_TRIANGLE_FAN:
1629                 {
1630                         for (int vtxNdx = 1; vtxNdx < (int)vertices.size() - 1; ++vtxNdx)
1631                         {
1632                                 const tcu::Vec4& v0 = vertices[0];
1633                                 const tcu::Vec4& v1 = vertices[vtxNdx + 0];
1634                                 const tcu::Vec4& v2 = vertices[vtxNdx + 1];
1635
1636                                 if (triangleOrder(v0, v1, v2) != cullDirection)
1637                                 {
1638                                         TriangleSceneSpec::SceneTriangle tri;
1639                                         tri.positions[0] = v0;  tri.sharedEdge[0] = false;
1640                                         tri.positions[1] = v1;  tri.sharedEdge[1] = false;
1641                                         tri.positions[2] = v2;  tri.sharedEdge[2] = false;
1642
1643                                         outTriangles.push_back(tri);
1644                                 }
1645                         }
1646                         break;
1647                 }
1648
1649                 default:
1650                         DE_ASSERT(false);
1651         }
1652 }
1653
1654 bool CullingTest::triangleOrder (const tcu::Vec4& v0, const tcu::Vec4& v1, const tcu::Vec4& v2) const
1655 {
1656         const tcu::Vec2 s0 = v0.swizzle(0, 1) / v0.w();
1657         const tcu::Vec2 s1 = v1.swizzle(0, 1) / v1.w();
1658         const tcu::Vec2 s2 = v2.swizzle(0, 1) / v2.w();
1659
1660         // cross
1661         return ((s1.x() - s0.x()) * (s2.y() - s0.y()) - (s2.x() - s0.x()) * (s1.y() - s0.y())) < 0;
1662 }
1663
1664 class TriangleInterpolationTest : public BaseRenderingCase
1665 {
1666 public:
1667                                                 TriangleInterpolationTest       (Context& ctx, const char* name, const char* desc, glw::GLenum primitive, int flags, RenderTarget renderTarget = RENDERTARGET_DEFAULT, int numSamples = -1);
1668                                                 ~TriangleInterpolationTest      (void);
1669         IterateResult           iterate                                         (void);
1670
1671 private:
1672         void                            generateVertices                        (int iteration, std::vector<tcu::Vec4>& outVertices, std::vector<tcu::Vec4>& outColors) const;
1673         void                            extractTriangles                        (std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles, const std::vector<tcu::Vec4>& vertices, const std::vector<tcu::Vec4>& colors) const;
1674
1675         const glw::GLenum       m_primitive;
1676         const bool                      m_projective;
1677         const int                       m_iterationCount;
1678
1679         int                                     m_iteration;
1680         bool                            m_allIterationsPassed;
1681 };
1682
1683 TriangleInterpolationTest::TriangleInterpolationTest (Context& ctx, const char* name, const char* desc, glw::GLenum primitive, int flags, RenderTarget renderTarget, int numSamples)
1684         : BaseRenderingCase             (ctx, name, desc, renderTarget, numSamples, DEFAULT_RENDER_SIZE)
1685         , m_primitive                   (primitive)
1686         , m_projective                  ((flags & INTERPOLATIONFLAGS_PROJECTED) != 0)
1687         , m_iterationCount              (3)
1688         , m_iteration                   (0)
1689         , m_allIterationsPassed (true)
1690 {
1691         m_flatshade = ((flags & INTERPOLATIONFLAGS_FLATSHADE) != 0);
1692 }
1693
1694 TriangleInterpolationTest::~TriangleInterpolationTest (void)
1695 {
1696         deinit();
1697 }
1698
1699 TriangleInterpolationTest::IterateResult TriangleInterpolationTest::iterate (void)
1700 {
1701         const std::string                                                               iterationDescription    = "Test iteration " + de::toString(m_iteration+1) + " / " + de::toString(m_iterationCount);
1702         const tcu::ScopedLogSection                                             section                                 (m_testCtx.getLog(), "Iteration" + de::toString(m_iteration+1), iterationDescription);
1703         tcu::Surface                                                                    resultImage                             (m_renderSize, m_renderSize);
1704         std::vector<tcu::Vec4>                                                  drawBuffer;
1705         std::vector<tcu::Vec4>                                                  colorBuffer;
1706         std::vector<TriangleSceneSpec::SceneTriangle>   triangles;
1707
1708         // generate scene
1709         generateVertices(m_iteration, drawBuffer, colorBuffer);
1710         extractTriangles(triangles, drawBuffer, colorBuffer);
1711
1712         // log
1713         {
1714                 m_testCtx.getLog() << tcu::TestLog::Message << "Generated vertices:" << tcu::TestLog::EndMessage;
1715                 for (int vtxNdx = 0; vtxNdx < (int)drawBuffer.size(); ++vtxNdx)
1716                         m_testCtx.getLog() << tcu::TestLog::Message << "\t" << drawBuffer[vtxNdx] << ",\tcolor= " << colorBuffer[vtxNdx] << tcu::TestLog::EndMessage;
1717         }
1718
1719         // draw image
1720         drawPrimitives(resultImage, drawBuffer, colorBuffer, m_primitive);
1721
1722         // compare
1723         {
1724                 RasterizationArguments  args;
1725                 TriangleSceneSpec               scene;
1726
1727                 args.numSamples         = m_numSamples;
1728                 args.subpixelBits       = m_subpixelBits;
1729                 args.redBits            = getPixelFormat().redBits;
1730                 args.greenBits          = getPixelFormat().greenBits;
1731                 args.blueBits           = getPixelFormat().blueBits;
1732
1733                 scene.triangles.swap(triangles);
1734
1735                 if (!verifyTriangleGroupInterpolation(resultImage, scene, args, m_testCtx.getLog()))
1736                         m_allIterationsPassed = false;
1737         }
1738
1739         // result
1740         if (++m_iteration == m_iterationCount)
1741         {
1742                 if (m_allIterationsPassed)
1743                         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1744                 else
1745                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Found invalid pixel values");
1746
1747                 return STOP;
1748         }
1749         else
1750                 return CONTINUE;
1751 }
1752
1753 void TriangleInterpolationTest::generateVertices (int iteration, std::vector<tcu::Vec4>& outVertices, std::vector<tcu::Vec4>& outColors) const
1754 {
1755         // use only red, green and blue
1756         const tcu::Vec4 colors[] =
1757         {
1758                 tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f),
1759                 tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f),
1760                 tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f),
1761         };
1762
1763         de::Random rnd(123 + iteration * 1000 + (int)m_primitive);
1764
1765         outVertices.resize(6);
1766         outColors.resize(6);
1767
1768         for (int vtxNdx = 0; vtxNdx < (int)outVertices.size(); ++vtxNdx)
1769         {
1770                 outVertices[vtxNdx].x() = rnd.getFloat(-0.9f, 0.9f);
1771                 outVertices[vtxNdx].y() = rnd.getFloat(-0.9f, 0.9f);
1772                 outVertices[vtxNdx].z() = 0.0f;
1773
1774                 if (!m_projective)
1775                         outVertices[vtxNdx].w() = 1.0f;
1776                 else
1777                 {
1778                         const float w = rnd.getFloat(0.2f, 4.0f);
1779
1780                         outVertices[vtxNdx].x() *= w;
1781                         outVertices[vtxNdx].y() *= w;
1782                         outVertices[vtxNdx].z() *= w;
1783                         outVertices[vtxNdx].w() = w;
1784                 }
1785
1786                 outColors[vtxNdx] = colors[vtxNdx % DE_LENGTH_OF_ARRAY(colors)];
1787         }
1788 }
1789
1790 void TriangleInterpolationTest::extractTriangles (std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles, const std::vector<tcu::Vec4>& vertices, const std::vector<tcu::Vec4>& colors) const
1791 {
1792         switch (m_primitive)
1793         {
1794                 case GL_TRIANGLES:
1795                 {
1796                         for (int vtxNdx = 0; vtxNdx < (int)vertices.size() - 2; vtxNdx += 3)
1797                         {
1798                                 TriangleSceneSpec::SceneTriangle tri;
1799                                 tri.positions[0]        = vertices[vtxNdx + 0];
1800                                 tri.positions[1]        = vertices[vtxNdx + 1];
1801                                 tri.positions[2]        = vertices[vtxNdx + 2];
1802                                 tri.sharedEdge[0]       = false;
1803                                 tri.sharedEdge[1]       = false;
1804                                 tri.sharedEdge[2]       = false;
1805
1806                                 if (m_flatshade)
1807                                 {
1808                                         tri.colors[0] = colors[vtxNdx + 2];
1809                                         tri.colors[1] = colors[vtxNdx + 2];
1810                                         tri.colors[2] = colors[vtxNdx + 2];
1811                                 }
1812                                 else
1813                                 {
1814                                         tri.colors[0] = colors[vtxNdx + 0];
1815                                         tri.colors[1] = colors[vtxNdx + 1];
1816                                         tri.colors[2] = colors[vtxNdx + 2];
1817                                 }
1818
1819                                 outTriangles.push_back(tri);
1820                         }
1821                         break;
1822                 }
1823
1824                 case GL_TRIANGLE_STRIP:
1825                 {
1826                         for (int vtxNdx = 0; vtxNdx < (int)vertices.size() - 2; ++vtxNdx)
1827                         {
1828                                 TriangleSceneSpec::SceneTriangle tri;
1829                                 tri.positions[0]        = vertices[vtxNdx + 0];
1830                                 tri.positions[1]        = vertices[vtxNdx + 1];
1831                                 tri.positions[2]        = vertices[vtxNdx + 2];
1832                                 tri.sharedEdge[0]       = false;
1833                                 tri.sharedEdge[1]       = false;
1834                                 tri.sharedEdge[2]       = false;
1835
1836                                 if (m_flatshade)
1837                                 {
1838                                         tri.colors[0] = colors[vtxNdx + 2];
1839                                         tri.colors[1] = colors[vtxNdx + 2];
1840                                         tri.colors[2] = colors[vtxNdx + 2];
1841                                 }
1842                                 else
1843                                 {
1844                                         tri.colors[0] = colors[vtxNdx + 0];
1845                                         tri.colors[1] = colors[vtxNdx + 1];
1846                                         tri.colors[2] = colors[vtxNdx + 2];
1847                                 }
1848
1849                                 outTriangles.push_back(tri);
1850                         }
1851                         break;
1852                 }
1853
1854                 case GL_TRIANGLE_FAN:
1855                 {
1856                         for (int vtxNdx = 1; vtxNdx < (int)vertices.size() - 1; ++vtxNdx)
1857                         {
1858                                 TriangleSceneSpec::SceneTriangle tri;
1859                                 tri.positions[0]        = vertices[0];
1860                                 tri.positions[1]        = vertices[vtxNdx + 0];
1861                                 tri.positions[2]        = vertices[vtxNdx + 1];
1862                                 tri.sharedEdge[0]       = false;
1863                                 tri.sharedEdge[1]       = false;
1864                                 tri.sharedEdge[2]       = false;
1865
1866                                 if (m_flatshade)
1867                                 {
1868                                         tri.colors[0] = colors[vtxNdx + 1];
1869                                         tri.colors[1] = colors[vtxNdx + 1];
1870                                         tri.colors[2] = colors[vtxNdx + 1];
1871                                 }
1872                                 else
1873                                 {
1874                                         tri.colors[0] = colors[0];
1875                                         tri.colors[1] = colors[vtxNdx + 0];
1876                                         tri.colors[2] = colors[vtxNdx + 1];
1877                                 }
1878
1879                                 outTriangles.push_back(tri);
1880                         }
1881                         break;
1882                 }
1883
1884                 default:
1885                         DE_ASSERT(false);
1886         }
1887 }
1888
1889 class LineInterpolationTest : public BaseRenderingCase
1890 {
1891 public:
1892                                                         LineInterpolationTest   (Context& ctx, const char* name, const char* desc, glw::GLenum primitive, int flags, PrimitiveWideness wideness, RenderTarget renderTarget = RENDERTARGET_DEFAULT, int numSamples = -1);
1893                                                         ~LineInterpolationTest  (void);
1894
1895         void                                    init                                    (void);
1896         IterateResult                   iterate                                 (void);
1897
1898 private:
1899         void                                    generateVertices                (int iteration, std::vector<tcu::Vec4>& outVertices, std::vector<tcu::Vec4>& outColors) const;
1900         void                                    extractLines                    (std::vector<LineSceneSpec::SceneLine>& outLines, const std::vector<tcu::Vec4>& vertices, const std::vector<tcu::Vec4>& colors) const;
1901         float                                   getLineWidth                    (void) const;
1902
1903         const glw::GLenum               m_primitive;
1904         const bool                              m_projective;
1905         const int                               m_iterationCount;
1906         const PrimitiveWideness m_primitiveWideness;
1907
1908         int                                             m_iteration;
1909         tcu::ResultCollector    m_result;
1910         float                                   m_maxLineWidth;
1911         std::vector<float>              m_lineWidths;
1912 };
1913
1914 LineInterpolationTest::LineInterpolationTest (Context& ctx, const char* name, const char* desc, glw::GLenum primitive, int flags, PrimitiveWideness wideness, RenderTarget renderTarget, int numSamples)
1915         : BaseRenderingCase             (ctx, name, desc, renderTarget, numSamples, DEFAULT_RENDER_SIZE)
1916         , m_primitive                   (primitive)
1917         , m_projective                  ((flags & INTERPOLATIONFLAGS_PROJECTED) != 0)
1918         , m_iterationCount              (3)
1919         , m_primitiveWideness   (wideness)
1920         , m_iteration                   (0)
1921         , m_maxLineWidth                (1.0f)
1922 {
1923         m_flatshade = ((flags & INTERPOLATIONFLAGS_FLATSHADE) != 0);
1924 }
1925
1926 LineInterpolationTest::~LineInterpolationTest (void)
1927 {
1928         deinit();
1929 }
1930
1931 void LineInterpolationTest::init (void)
1932 {
1933         // create line widths
1934         if (m_primitiveWideness == PRIMITIVEWIDENESS_NARROW)
1935         {
1936                 m_lineWidths.resize(m_iterationCount, 1.0f);
1937         }
1938         else if (m_primitiveWideness == PRIMITIVEWIDENESS_WIDE)
1939         {
1940                 float range[2] = { 0.0f, 0.0f };
1941                 m_context.getRenderContext().getFunctions().getFloatv(GL_ALIASED_LINE_WIDTH_RANGE, range);
1942
1943                 m_testCtx.getLog() << tcu::TestLog::Message << "ALIASED_LINE_WIDTH_RANGE = [" << range[0] << ", " << range[1] << "]" << tcu::TestLog::EndMessage;
1944
1945                 // no wide line support
1946                 if (range[1] <= 1.0f)
1947                         throw tcu::NotSupportedError("wide line support required");
1948
1949                 // set hand picked sizes
1950                 m_lineWidths.push_back(5.0f);
1951                 m_lineWidths.push_back(10.0f);
1952                 m_lineWidths.push_back(range[1]);
1953                 DE_ASSERT((int)m_lineWidths.size() == m_iterationCount);
1954
1955                 m_maxLineWidth = range[1];
1956         }
1957         else
1958                 DE_ASSERT(false);
1959
1960         // init parent
1961         BaseRenderingCase::init();
1962 }
1963
1964 LineInterpolationTest::IterateResult LineInterpolationTest::iterate (void)
1965 {
1966         const std::string                                               iterationDescription    = "Test iteration " + de::toString(m_iteration+1) + " / " + de::toString(m_iterationCount);
1967         const tcu::ScopedLogSection                             section                                 (m_testCtx.getLog(), "Iteration" + de::toString(m_iteration+1), iterationDescription);
1968         const float                                                             lineWidth                               = getLineWidth();
1969         tcu::Surface                                                    resultImage                             (m_renderSize, m_renderSize);
1970         std::vector<tcu::Vec4>                                  drawBuffer;
1971         std::vector<tcu::Vec4>                                  colorBuffer;
1972         std::vector<LineSceneSpec::SceneLine>   lines;
1973
1974         // supported?
1975         if (lineWidth <= m_maxLineWidth)
1976         {
1977                 // generate scene
1978                 generateVertices(m_iteration, drawBuffer, colorBuffer);
1979                 extractLines(lines, drawBuffer, colorBuffer);
1980
1981                 // log
1982                 {
1983                         m_testCtx.getLog() << tcu::TestLog::Message << "Generated vertices:" << tcu::TestLog::EndMessage;
1984                         for (int vtxNdx = 0; vtxNdx < (int)drawBuffer.size(); ++vtxNdx)
1985                                 m_testCtx.getLog() << tcu::TestLog::Message << "\t" << drawBuffer[vtxNdx] << ",\tcolor= " << colorBuffer[vtxNdx] << tcu::TestLog::EndMessage;
1986                 }
1987
1988                 // draw image
1989                 drawPrimitives(resultImage, drawBuffer, colorBuffer, m_primitive);
1990
1991                 // compare
1992                 {
1993                         RasterizationArguments  args;
1994                         LineSceneSpec                   scene;
1995                         LineInterpolationMethod iterationResult;
1996
1997                         args.numSamples         = m_numSamples;
1998                         args.subpixelBits       = m_subpixelBits;
1999                         args.redBits            = getPixelFormat().redBits;
2000                         args.greenBits          = getPixelFormat().greenBits;
2001                         args.blueBits           = getPixelFormat().blueBits;
2002
2003                         scene.lines.swap(lines);
2004                         scene.lineWidth = getLineWidth();
2005
2006                         iterationResult = verifyLineGroupInterpolation(resultImage, scene, args, m_testCtx.getLog());
2007                         switch (iterationResult)
2008                         {
2009                                 case LINEINTERPOLATION_STRICTLY_CORRECT:
2010                                         // line interpolation matches the specification
2011                                         m_result.addResult(QP_TEST_RESULT_PASS, "Pass");
2012                                         break;
2013
2014                                 case LINEINTERPOLATION_PROJECTED:
2015                                         // line interpolation weights are otherwise correct, but they are projected onto major axis
2016                                         m_testCtx.getLog()      << tcu::TestLog::Message
2017                                                                                 << "Interpolation was calculated using coordinates projected onto major axis. "
2018                                                                                 "This method does not produce the same values as the non-projecting method defined in the specification."
2019                                                                                 << tcu::TestLog::EndMessage;
2020                                         m_result.addResult(QP_TEST_RESULT_QUALITY_WARNING, "Interpolation was calculated using projected coordinateds");
2021                                         break;
2022
2023                                 case LINEINTERPOLATION_INCORRECT:
2024                                         // line interpolation is incorrect
2025                                         m_result.addResult(QP_TEST_RESULT_FAIL, "Found invalid pixel values");
2026                                         break;
2027
2028                                 default:
2029                                         DE_ASSERT(false);
2030                                         break;
2031                         }
2032                 }
2033         }
2034         else
2035                 m_testCtx.getLog() << tcu::TestLog::Message << "Line width " << lineWidth << " not supported, skipping iteration." << tcu::TestLog::EndMessage;
2036
2037         // result
2038         if (++m_iteration == m_iterationCount)
2039         {
2040                 m_result.setTestContextResult(m_testCtx);
2041                 return STOP;
2042         }
2043         else
2044                 return CONTINUE;
2045 }
2046
2047 void LineInterpolationTest::generateVertices (int iteration, std::vector<tcu::Vec4>& outVertices, std::vector<tcu::Vec4>& outColors) const
2048 {
2049         // use only red, green and blue
2050         const tcu::Vec4 colors[] =
2051         {
2052                 tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f),
2053                 tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f),
2054                 tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f),
2055         };
2056
2057         de::Random rnd(123 + iteration * 1000 + (int)m_primitive);
2058
2059         outVertices.resize(6);
2060         outColors.resize(6);
2061
2062         for (int vtxNdx = 0; vtxNdx < (int)outVertices.size(); ++vtxNdx)
2063         {
2064                 outVertices[vtxNdx].x() = rnd.getFloat(-0.9f, 0.9f);
2065                 outVertices[vtxNdx].y() = rnd.getFloat(-0.9f, 0.9f);
2066                 outVertices[vtxNdx].z() = 0.0f;
2067
2068                 if (!m_projective)
2069                         outVertices[vtxNdx].w() = 1.0f;
2070                 else
2071                 {
2072                         const float w = rnd.getFloat(0.2f, 4.0f);
2073
2074                         outVertices[vtxNdx].x() *= w;
2075                         outVertices[vtxNdx].y() *= w;
2076                         outVertices[vtxNdx].z() *= w;
2077                         outVertices[vtxNdx].w() = w;
2078                 }
2079
2080                 outColors[vtxNdx] = colors[vtxNdx % DE_LENGTH_OF_ARRAY(colors)];
2081         }
2082 }
2083
2084 void LineInterpolationTest::extractLines (std::vector<LineSceneSpec::SceneLine>& outLines, const std::vector<tcu::Vec4>& vertices, const std::vector<tcu::Vec4>& colors) const
2085 {
2086         switch (m_primitive)
2087         {
2088                 case GL_LINES:
2089                 {
2090                         for (int vtxNdx = 0; vtxNdx < (int)vertices.size() - 1; vtxNdx += 2)
2091                         {
2092                                 LineSceneSpec::SceneLine line;
2093                                 line.positions[0] = vertices[vtxNdx + 0];
2094                                 line.positions[1] = vertices[vtxNdx + 1];
2095
2096                                 if (m_flatshade)
2097                                 {
2098                                         line.colors[0] = colors[vtxNdx + 1];
2099                                         line.colors[1] = colors[vtxNdx + 1];
2100                                 }
2101                                 else
2102                                 {
2103                                         line.colors[0] = colors[vtxNdx + 0];
2104                                         line.colors[1] = colors[vtxNdx + 1];
2105                                 }
2106
2107                                 outLines.push_back(line);
2108                         }
2109                         break;
2110                 }
2111
2112                 case GL_LINE_STRIP:
2113                 {
2114                         for (int vtxNdx = 0; vtxNdx < (int)vertices.size() - 1; ++vtxNdx)
2115                         {
2116                                 LineSceneSpec::SceneLine line;
2117                                 line.positions[0] = vertices[vtxNdx + 0];
2118                                 line.positions[1] = vertices[vtxNdx + 1];
2119
2120                                 if (m_flatshade)
2121                                 {
2122                                         line.colors[0] = colors[vtxNdx + 1];
2123                                         line.colors[1] = colors[vtxNdx + 1];
2124                                 }
2125                                 else
2126                                 {
2127                                         line.colors[0] = colors[vtxNdx + 0];
2128                                         line.colors[1] = colors[vtxNdx + 1];
2129                                 }
2130
2131                                 outLines.push_back(line);
2132                         }
2133                         break;
2134                 }
2135
2136                 case GL_LINE_LOOP:
2137                 {
2138                         for (int vtxNdx = 0; vtxNdx < (int)vertices.size(); ++vtxNdx)
2139                         {
2140                                 LineSceneSpec::SceneLine line;
2141                                 line.positions[0] = vertices[(vtxNdx + 0) % (int)vertices.size()];
2142                                 line.positions[1] = vertices[(vtxNdx + 1) % (int)vertices.size()];
2143
2144                                 if (m_flatshade)
2145                                 {
2146                                         line.colors[0] = colors[(vtxNdx + 1) % (int)vertices.size()];
2147                                         line.colors[1] = colors[(vtxNdx + 1) % (int)vertices.size()];
2148                                 }
2149                                 else
2150                                 {
2151                                         line.colors[0] = colors[(vtxNdx + 0) % (int)vertices.size()];
2152                                         line.colors[1] = colors[(vtxNdx + 1) % (int)vertices.size()];
2153                                 }
2154
2155                                 outLines.push_back(line);
2156                         }
2157                         break;
2158                 }
2159
2160                 default:
2161                         DE_ASSERT(false);
2162         }
2163 }
2164
2165 float LineInterpolationTest::getLineWidth (void) const
2166 {
2167         return m_lineWidths[m_iteration];
2168 }
2169
2170 } // anonymous
2171
2172 RasterizationTests::RasterizationTests (Context& context)
2173         : TestCaseGroup(context, "rasterization", "Rasterization Tests")
2174 {
2175 }
2176
2177 RasterizationTests::~RasterizationTests (void)
2178 {
2179 }
2180
2181 void RasterizationTests::init (void)
2182 {
2183         // .primitives
2184         {
2185                 tcu::TestCaseGroup* const primitives = new tcu::TestCaseGroup(m_testCtx, "primitives", "Primitive rasterization");
2186
2187                 addChild(primitives);
2188
2189                 primitives->addChild(new TrianglesCase          (m_context, "triangles",                "Render primitives as GL_TRIANGLES, verify rasterization result"));
2190                 primitives->addChild(new TriangleStripCase      (m_context, "triangle_strip",   "Render primitives as GL_TRIANGLE_STRIP, verify rasterization result"));
2191                 primitives->addChild(new TriangleFanCase        (m_context, "triangle_fan",             "Render primitives as GL_TRIANGLE_FAN, verify rasterization result"));
2192                 primitives->addChild(new LinesCase                      (m_context, "lines",                    "Render primitives as GL_LINES, verify rasterization result",                                                   PRIMITIVEWIDENESS_NARROW));
2193                 primitives->addChild(new LineStripCase          (m_context, "line_strip",               "Render primitives as GL_LINE_STRIP, verify rasterization result",                                              PRIMITIVEWIDENESS_NARROW));
2194                 primitives->addChild(new LineLoopCase           (m_context, "line_loop",                "Render primitives as GL_LINE_LOOP, verify rasterization result",                                               PRIMITIVEWIDENESS_NARROW));
2195                 primitives->addChild(new LinesCase                      (m_context, "lines_wide",               "Render primitives as GL_LINES with wide lines, verify rasterization result",                   PRIMITIVEWIDENESS_WIDE));
2196                 primitives->addChild(new LineStripCase          (m_context, "line_strip_wide",  "Render primitives as GL_LINE_STRIP with wide lines, verify rasterization result",              PRIMITIVEWIDENESS_WIDE));
2197                 primitives->addChild(new LineLoopCase           (m_context, "line_loop_wide",   "Render primitives as GL_LINE_LOOP with wide lines, verify rasterization result",               PRIMITIVEWIDENESS_WIDE));
2198                 primitives->addChild(new PointCase                      (m_context, "points",                   "Render primitives as GL_POINTS, verify rasterization result",                                                  PRIMITIVEWIDENESS_WIDE));
2199         }
2200
2201         // .fill_rules
2202         {
2203                 tcu::TestCaseGroup* const fillRules = new tcu::TestCaseGroup(m_testCtx, "fill_rules", "Primitive fill rules");
2204
2205                 addChild(fillRules);
2206
2207                 fillRules->addChild(new FillRuleCase(m_context, "basic_quad",                   "Verify fill rules",    FillRuleCase::FILLRULECASE_BASIC));
2208                 fillRules->addChild(new FillRuleCase(m_context, "basic_quad_reverse",   "Verify fill rules",    FillRuleCase::FILLRULECASE_REVERSED));
2209                 fillRules->addChild(new FillRuleCase(m_context, "clipped_full",                 "Verify fill rules",    FillRuleCase::FILLRULECASE_CLIPPED_FULL));
2210                 fillRules->addChild(new FillRuleCase(m_context, "clipped_partly",               "Verify fill rules",    FillRuleCase::FILLRULECASE_CLIPPED_PARTIAL));
2211                 fillRules->addChild(new FillRuleCase(m_context, "projected",                    "Verify fill rules",    FillRuleCase::FILLRULECASE_PROJECTED));
2212         }
2213
2214         // .culling
2215         {
2216                 static const struct CullMode
2217                 {
2218                         glw::GLenum     mode;
2219                         const char*     prefix;
2220                 } cullModes[] =
2221                 {
2222                         { GL_FRONT,                             "front_"        },
2223                         { GL_BACK,                              "back_"         },
2224                         { GL_FRONT_AND_BACK,    "both_"         },
2225                 };
2226                 static const struct PrimitiveType
2227                 {
2228                         glw::GLenum     type;
2229                         const char*     name;
2230                 } primitiveTypes[] =
2231                 {
2232                         { GL_TRIANGLES,                 "triangles"                     },
2233                         { GL_TRIANGLE_STRIP,    "triangle_strip"        },
2234                         { GL_TRIANGLE_FAN,              "triangle_fan"          },
2235                 };
2236                 static const struct FrontFaceOrder
2237                 {
2238                         glw::GLenum     mode;
2239                         const char*     postfix;
2240                 } frontOrders[] =
2241                 {
2242                         { GL_CCW,       ""                      },
2243                         { GL_CW,        "_reverse"      },
2244                 };
2245
2246                 tcu::TestCaseGroup* const culling = new tcu::TestCaseGroup(m_testCtx, "culling", "Culling");
2247
2248                 addChild(culling);
2249
2250                 for (int cullModeNdx   = 0; cullModeNdx   < DE_LENGTH_OF_ARRAY(cullModes);      ++cullModeNdx)
2251                 for (int primitiveNdx  = 0; primitiveNdx  < DE_LENGTH_OF_ARRAY(primitiveTypes); ++primitiveNdx)
2252                 for (int frontOrderNdx = 0; frontOrderNdx < DE_LENGTH_OF_ARRAY(frontOrders);    ++frontOrderNdx)
2253                 {
2254                         const std::string name = std::string(cullModes[cullModeNdx].prefix) + primitiveTypes[primitiveNdx].name + frontOrders[frontOrderNdx].postfix;
2255
2256                         culling->addChild(new CullingTest(m_context, name.c_str(), "Test primitive culling.", cullModes[cullModeNdx].mode, primitiveTypes[primitiveNdx].type, frontOrders[frontOrderNdx].mode));
2257                 }
2258         }
2259
2260         // .interpolation
2261         {
2262                 tcu::TestCaseGroup* const interpolation = new tcu::TestCaseGroup(m_testCtx, "interpolation", "Test interpolation");
2263
2264                 addChild(interpolation);
2265
2266                 // .basic
2267                 {
2268                         tcu::TestCaseGroup* const basic = new tcu::TestCaseGroup(m_testCtx, "basic", "Non-projective interpolation");
2269
2270                         interpolation->addChild(basic);
2271
2272                         basic->addChild(new TriangleInterpolationTest           (m_context, "triangles",                "Verify triangle interpolation",                GL_TRIANGLES,           INTERPOLATIONFLAGS_NONE));
2273                         basic->addChild(new TriangleInterpolationTest           (m_context, "triangle_strip",   "Verify triangle strip interpolation",  GL_TRIANGLE_STRIP,      INTERPOLATIONFLAGS_NONE));
2274                         basic->addChild(new TriangleInterpolationTest           (m_context, "triangle_fan",             "Verify triangle fan interpolation",    GL_TRIANGLE_FAN,        INTERPOLATIONFLAGS_NONE));
2275                         basic->addChild(new LineInterpolationTest                       (m_context, "lines",                    "Verify line interpolation",                    GL_LINES,                       INTERPOLATIONFLAGS_NONE,        PRIMITIVEWIDENESS_NARROW));
2276                         basic->addChild(new LineInterpolationTest                       (m_context, "line_strip",               "Verify line strip interpolation",              GL_LINE_STRIP,          INTERPOLATIONFLAGS_NONE,        PRIMITIVEWIDENESS_NARROW));
2277                         basic->addChild(new LineInterpolationTest                       (m_context, "line_loop",                "Verify line loop interpolation",               GL_LINE_LOOP,           INTERPOLATIONFLAGS_NONE,        PRIMITIVEWIDENESS_NARROW));
2278                         basic->addChild(new LineInterpolationTest                       (m_context, "lines_wide",               "Verify wide line interpolation",               GL_LINES,                       INTERPOLATIONFLAGS_NONE,        PRIMITIVEWIDENESS_WIDE));
2279                         basic->addChild(new LineInterpolationTest                       (m_context, "line_strip_wide",  "Verify wide line strip interpolation", GL_LINE_STRIP,          INTERPOLATIONFLAGS_NONE,        PRIMITIVEWIDENESS_WIDE));
2280                         basic->addChild(new LineInterpolationTest                       (m_context, "line_loop_wide",   "Verify wide line loop interpolation",  GL_LINE_LOOP,           INTERPOLATIONFLAGS_NONE,        PRIMITIVEWIDENESS_WIDE));
2281                 }
2282
2283                 // .projected
2284                 {
2285                         tcu::TestCaseGroup* const projected = new tcu::TestCaseGroup(m_testCtx, "projected", "Projective interpolation");
2286
2287                         interpolation->addChild(projected);
2288
2289                         projected->addChild(new TriangleInterpolationTest       (m_context, "triangles",                "Verify triangle interpolation",                GL_TRIANGLES,           INTERPOLATIONFLAGS_PROJECTED));
2290                         projected->addChild(new TriangleInterpolationTest       (m_context, "triangle_strip",   "Verify triangle strip interpolation",  GL_TRIANGLE_STRIP,      INTERPOLATIONFLAGS_PROJECTED));
2291                         projected->addChild(new TriangleInterpolationTest       (m_context, "triangle_fan",             "Verify triangle fan interpolation",    GL_TRIANGLE_FAN,        INTERPOLATIONFLAGS_PROJECTED));
2292                         projected->addChild(new LineInterpolationTest           (m_context, "lines",                    "Verify line interpolation",                    GL_LINES,                       INTERPOLATIONFLAGS_PROJECTED,   PRIMITIVEWIDENESS_NARROW));
2293                         projected->addChild(new LineInterpolationTest           (m_context, "line_strip",               "Verify line strip interpolation",              GL_LINE_STRIP,          INTERPOLATIONFLAGS_PROJECTED,   PRIMITIVEWIDENESS_NARROW));
2294                         projected->addChild(new LineInterpolationTest           (m_context, "line_loop",                "Verify line loop interpolation",               GL_LINE_LOOP,           INTERPOLATIONFLAGS_PROJECTED,   PRIMITIVEWIDENESS_NARROW));
2295                         projected->addChild(new LineInterpolationTest           (m_context, "lines_wide",               "Verify wide line interpolation",               GL_LINES,                       INTERPOLATIONFLAGS_PROJECTED,   PRIMITIVEWIDENESS_WIDE));
2296                         projected->addChild(new LineInterpolationTest           (m_context, "line_strip_wide",  "Verify wide line strip interpolation", GL_LINE_STRIP,          INTERPOLATIONFLAGS_PROJECTED,   PRIMITIVEWIDENESS_WIDE));
2297                         projected->addChild(new LineInterpolationTest           (m_context, "line_loop_wide",   "Verify wide line loop interpolation",  GL_LINE_LOOP,           INTERPOLATIONFLAGS_PROJECTED,   PRIMITIVEWIDENESS_WIDE));
2298                 }
2299         }
2300
2301         // .flatshading
2302         {
2303                 tcu::TestCaseGroup* const flatshading = new tcu::TestCaseGroup(m_testCtx, "flatshading", "Test flatshading");
2304
2305                 addChild(flatshading);
2306
2307                 flatshading->addChild(new TriangleInterpolationTest             (m_context, "triangles",                "Verify triangle flatshading",                  GL_TRIANGLES,           INTERPOLATIONFLAGS_FLATSHADE));
2308                 flatshading->addChild(new TriangleInterpolationTest             (m_context, "triangle_strip",   "Verify triangle strip flatshading",    GL_TRIANGLE_STRIP,      INTERPOLATIONFLAGS_FLATSHADE));
2309                 flatshading->addChild(new TriangleInterpolationTest             (m_context, "triangle_fan",             "Verify triangle fan flatshading",              GL_TRIANGLE_FAN,        INTERPOLATIONFLAGS_FLATSHADE));
2310                 flatshading->addChild(new LineInterpolationTest                 (m_context, "lines",                    "Verify line flatshading",                              GL_LINES,                       INTERPOLATIONFLAGS_FLATSHADE,   PRIMITIVEWIDENESS_NARROW));
2311                 flatshading->addChild(new LineInterpolationTest                 (m_context, "line_strip",               "Verify line strip flatshading",                GL_LINE_STRIP,          INTERPOLATIONFLAGS_FLATSHADE,   PRIMITIVEWIDENESS_NARROW));
2312                 flatshading->addChild(new LineInterpolationTest                 (m_context, "line_loop",                "Verify line loop flatshading",                 GL_LINE_LOOP,           INTERPOLATIONFLAGS_FLATSHADE,   PRIMITIVEWIDENESS_NARROW));
2313                 flatshading->addChild(new LineInterpolationTest                 (m_context, "lines_wide",               "Verify wide line flatshading",                 GL_LINES,                       INTERPOLATIONFLAGS_FLATSHADE,   PRIMITIVEWIDENESS_WIDE));
2314                 flatshading->addChild(new LineInterpolationTest                 (m_context, "line_strip_wide",  "Verify wide line strip flatshading",   GL_LINE_STRIP,          INTERPOLATIONFLAGS_FLATSHADE,   PRIMITIVEWIDENESS_WIDE));
2315                 flatshading->addChild(new LineInterpolationTest                 (m_context, "line_loop_wide",   "Verify wide line loop flatshading",    GL_LINE_LOOP,           INTERPOLATIONFLAGS_FLATSHADE,   PRIMITIVEWIDENESS_WIDE));
2316         }
2317
2318         // .fbo
2319         {
2320                 static const struct
2321                 {
2322                         const char*                                             name;
2323                         BaseRenderingCase::RenderTarget target;
2324                         int                                                             numSamples;
2325                 } renderTargets[] =
2326                 {
2327                         { "texture_2d",                         BaseRenderingCase::RENDERTARGET_TEXTURE_2D,                     -1                                                                      },
2328                         { "rbo_singlesample",           BaseRenderingCase::RENDERTARGET_RBO_SINGLESAMPLE,       -1                                                                      },
2329                         { "rbo_multisample_4",          BaseRenderingCase::RENDERTARGET_RBO_MULTISAMPLE,        4                                                                       },
2330                         { "rbo_multisample_max",        BaseRenderingCase::RENDERTARGET_RBO_MULTISAMPLE,        BaseRenderingCase::SAMPLE_COUNT_MAX     },
2331                 };
2332
2333                 tcu::TestCaseGroup* const fboGroup = new tcu::TestCaseGroup(m_testCtx, "fbo", "Test using framebuffer objects");
2334                 addChild(fboGroup);
2335
2336                 // .texture_2d
2337                 // .rbo_singlesample
2338                 // .rbo_multisample_4
2339                 // .rbo_multisample_max
2340                 for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(renderTargets); ++targetNdx)
2341                 {
2342                         tcu::TestCaseGroup* const colorAttachmentGroup = new tcu::TestCaseGroup(m_testCtx, renderTargets[targetNdx].name, ("Test using " + std::string(renderTargets[targetNdx].name) + " color attachment").c_str());
2343                         fboGroup->addChild(colorAttachmentGroup);
2344
2345                         // .primitives
2346                         {
2347                                 tcu::TestCaseGroup* const primitiveGroup = new tcu::TestCaseGroup(m_testCtx, "primitives", "Primitive rasterization");
2348                                 colorAttachmentGroup->addChild(primitiveGroup);
2349
2350                                 primitiveGroup->addChild(new TrianglesCase      (m_context, "triangles",        "Render primitives as GL_TRIANGLES, verify rasterization result",                                                                                       renderTargets[targetNdx].target, renderTargets[targetNdx].numSamples));
2351                                 primitiveGroup->addChild(new LinesCase          (m_context, "lines",            "Render primitives as GL_LINES, verify rasterization result",                                   PRIMITIVEWIDENESS_NARROW,       renderTargets[targetNdx].target, renderTargets[targetNdx].numSamples));
2352                                 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));
2353                                 primitiveGroup->addChild(new PointCase          (m_context, "points",           "Render primitives as GL_POINTS, verify rasterization result",                                  PRIMITIVEWIDENESS_WIDE,         renderTargets[targetNdx].target, renderTargets[targetNdx].numSamples));
2354                         }
2355
2356                         // .fill_rules
2357                         {
2358                                 tcu::TestCaseGroup* const fillRules = new tcu::TestCaseGroup(m_testCtx, "fill_rules", "Primitive fill rules");
2359
2360                                 colorAttachmentGroup->addChild(fillRules);
2361
2362                                 fillRules->addChild(new FillRuleCase(m_context, "basic_quad",                   "Verify fill rules",    FillRuleCase::FILLRULECASE_BASIC,                       renderTargets[targetNdx].target, renderTargets[targetNdx].numSamples));
2363                                 fillRules->addChild(new FillRuleCase(m_context, "basic_quad_reverse",   "Verify fill rules",    FillRuleCase::FILLRULECASE_REVERSED,            renderTargets[targetNdx].target, renderTargets[targetNdx].numSamples));
2364                                 fillRules->addChild(new FillRuleCase(m_context, "clipped_full",                 "Verify fill rules",    FillRuleCase::FILLRULECASE_CLIPPED_FULL,        renderTargets[targetNdx].target, renderTargets[targetNdx].numSamples));
2365                                 fillRules->addChild(new FillRuleCase(m_context, "clipped_partly",               "Verify fill rules",    FillRuleCase::FILLRULECASE_CLIPPED_PARTIAL,     renderTargets[targetNdx].target, renderTargets[targetNdx].numSamples));
2366                                 fillRules->addChild(new FillRuleCase(m_context, "projected",                    "Verify fill rules",    FillRuleCase::FILLRULECASE_PROJECTED,           renderTargets[targetNdx].target, renderTargets[targetNdx].numSamples));
2367                         }
2368
2369                         // .interpolation
2370                         {
2371                                 tcu::TestCaseGroup* const interpolation = new tcu::TestCaseGroup(m_testCtx, "interpolation", "Non-projective interpolation");
2372
2373                                 colorAttachmentGroup->addChild(interpolation);
2374
2375                                 interpolation->addChild(new TriangleInterpolationTest           (m_context, "triangles",                "Verify triangle interpolation",                GL_TRIANGLES,           INTERPOLATIONFLAGS_NONE,                                                                renderTargets[targetNdx].target, renderTargets[targetNdx].numSamples));
2376                                 interpolation->addChild(new LineInterpolationTest                       (m_context, "lines",                    "Verify line interpolation",                    GL_LINES,                       INTERPOLATIONFLAGS_NONE,        PRIMITIVEWIDENESS_NARROW,       renderTargets[targetNdx].target, renderTargets[targetNdx].numSamples));
2377                                 interpolation->addChild(new LineInterpolationTest                       (m_context, "lines_wide",               "Verify wide line interpolation",               GL_LINES,                       INTERPOLATIONFLAGS_NONE,        PRIMITIVEWIDENESS_WIDE,         renderTargets[targetNdx].target, renderTargets[targetNdx].numSamples));
2378                         }
2379                 }
2380         }
2381 }
2382
2383 } // Functional
2384 } // gles3
2385 } // deqp