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