Add new framebuffer fetch extension tests am: 2a609fb223
[platform/upstream/VK-GL-CTS.git] / modules / gles2 / functional / es2fMultisampleTests.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 Multisampling tests.
22  *//*--------------------------------------------------------------------*/
23
24 #include "es2fMultisampleTests.hpp"
25 #include "gluPixelTransfer.hpp"
26 #include "gluShaderProgram.hpp"
27 #include "tcuSurface.hpp"
28 #include "tcuImageCompare.hpp"
29 #include "tcuRenderTarget.hpp"
30 #include "tcuTestLog.hpp"
31 #include "tcuTextureUtil.hpp"
32 #include "tcuCommandLine.hpp"
33 #include "deStringUtil.hpp"
34 #include "deRandom.hpp"
35 #include "deMath.h"
36 #include "deString.h"
37
38 #include "glw.h"
39
40 #include <string>
41 #include <vector>
42
43 namespace deqp
44 {
45 namespace gles2
46 {
47 namespace Functional
48 {
49
50 using tcu::Vec2;
51 using tcu::Vec3;
52 using tcu::Vec4;
53 using tcu::IVec2;
54 using tcu::IVec4;
55 using tcu::TestLog;
56 using std::vector;
57
58 static const float SQRT_HALF = 0.707107f;
59
60 namespace
61 {
62
63 struct QuadCorners
64 {
65         Vec2 p0;
66         Vec2 p1;
67         Vec2 p2;
68         Vec2 p3;
69
70         QuadCorners(const Vec2& p0_, const Vec2& p1_, const Vec2& p2_, const Vec2& p3_) : p0(p0_), p1(p1_), p2(p2_), p3(p3_) {}
71 };
72
73 } // anonymous
74
75 static inline int getIterationCount (const tcu::TestContext& ctx, int defaultCount)
76 {
77         int cmdLineValue = ctx.getCommandLine().getTestIterationCount();
78         return cmdLineValue > 0 ? cmdLineValue : defaultCount;
79 }
80
81 static inline int getGLInteger (GLenum name)
82 {
83         int result;
84         GLU_CHECK_CALL(glGetIntegerv(name, &result));
85         return result;
86 }
87
88 template<typename T>
89 static inline T min4 (T a, T b, T c, T d)
90 {
91         return de::min(de::min(de::min(a, b), c), d);
92 }
93
94 template<typename T>
95 static inline T max4 (T a, T b, T c, T d)
96 {
97         return de::max(de::max(de::max(a, b), c), d);
98 }
99
100 static inline bool isInsideQuad (const IVec2& point, const IVec2& p0, const IVec2& p1, const IVec2& p2, const IVec2& p3)
101 {
102         int dot0 = (point.x()-p0.x()) * (p1.y()-p0.y()) + (point.y()-p0.y()) * (p0.x()-p1.x());
103         int dot1 = (point.x()-p1.x()) * (p2.y()-p1.y()) + (point.y()-p1.y()) * (p1.x()-p2.x());
104         int dot2 = (point.x()-p2.x()) * (p3.y()-p2.y()) + (point.y()-p2.y()) * (p2.x()-p3.x());
105         int dot3 = (point.x()-p3.x()) * (p0.y()-p3.y()) + (point.y()-p3.y()) * (p3.x()-p0.x());
106
107         return (dot0 > 0) == (dot1 > 0) && (dot1 > 0) == (dot2 > 0) && (dot2 > 0) == (dot3 > 0);
108 }
109
110 /*--------------------------------------------------------------------*//*!
111  * \brief Check if a region in an image is unicolored.
112  *
113  * Checks if the pixels in img inside the convex quadilateral defined by
114  * p0, p1, p2 and p3 are all (approximately) of the same color.
115  *//*--------------------------------------------------------------------*/
116 static bool isPixelRegionUnicolored (const tcu::Surface& img, const IVec2& p0, const IVec2& p1, const IVec2& p2, const IVec2& p3)
117 {
118         int                     xMin                            = de::clamp(min4(p0.x(), p1.x(), p2.x(), p3.x()), 0, img.getWidth()-1);
119         int                     yMin                            = de::clamp(min4(p0.y(), p1.y(), p2.y(), p3.y()), 0, img.getHeight()-1);
120         int                     xMax                            = de::clamp(max4(p0.x(), p1.x(), p2.x(), p3.x()), 0, img.getWidth()-1);
121         int                     yMax                            = de::clamp(max4(p0.y(), p1.y(), p2.y(), p3.y()), 0, img.getHeight()-1);
122         bool            insideEncountered       = false;        //!< Whether we have already seen at least one pixel inside the region.
123         tcu::RGBA       insideColor;                                    //!< Color of the first pixel inside the region.
124
125         for (int y = yMin; y <= yMax; y++)
126         for (int x = xMin; x <= xMax; x++)
127         {
128                 if (isInsideQuad(IVec2(x, y), p0, p1, p2, p3))
129                 {
130                         tcu::RGBA pixColor = img.getPixel(x, y);
131
132                         if (insideEncountered)
133                         {
134                                 if (!tcu::compareThreshold(pixColor, insideColor, tcu::RGBA(3, 3, 3, 3))) // Pixel color differs from already-detected color inside same region - region not unicolored.
135                                         return false;
136                         }
137                         else
138                         {
139                                 insideEncountered = true;
140                                 insideColor = pixColor;
141                         }
142                 }
143         }
144
145         return true;
146 }
147
148 static bool drawUnicolorTestErrors (tcu::Surface& img, const tcu::PixelBufferAccess& errorImg, const IVec2& p0, const IVec2& p1, const IVec2& p2, const IVec2& p3)
149 {
150         int                     xMin            = de::clamp(min4(p0.x(), p1.x(), p2.x(), p3.x()), 0, img.getWidth()-1);
151         int                     yMin            = de::clamp(min4(p0.y(), p1.y(), p2.y(), p3.y()), 0, img.getHeight()-1);
152         int                     xMax            = de::clamp(max4(p0.x(), p1.x(), p2.x(), p3.x()), 0, img.getWidth()-1);
153         int                     yMax            = de::clamp(max4(p0.y(), p1.y(), p2.y(), p3.y()), 0, img.getHeight()-1);
154         tcu::RGBA       refColor        = img.getPixel((xMin + xMax) / 2, (yMin + yMax) / 2);
155
156         for (int y = yMin; y <= yMax; y++)
157         for (int x = xMin; x <= xMax; x++)
158         {
159                 if (isInsideQuad(IVec2(x, y), p0, p1, p2, p3))
160                 {
161                         if (!tcu::compareThreshold(img.getPixel(x, y), refColor, tcu::RGBA(3, 3, 3, 3)))
162                         {
163                                 img.setPixel(x, y, tcu::RGBA::red());
164                                 errorImg.setPixel(Vec4(1.0f, 0.0f, 0.0f, 1.0f), x, y);
165                         }
166                 }
167         }
168
169         return true;
170 }
171
172 /*--------------------------------------------------------------------*//*!
173  * \brief Abstract base class handling common stuff for multisample cases.
174  *//*--------------------------------------------------------------------*/
175 class MultisampleCase : public TestCase
176 {
177 public:
178                                                 MultisampleCase                 (Context& context, const char* name, const char* desc);
179         virtual                         ~MultisampleCase                (void);
180
181         virtual void            init                                    (void);
182         virtual void            deinit                                  (void);
183
184 protected:
185         virtual int                     getDesiredViewportSize  (void) const = 0;
186
187         void                            renderTriangle                  (const Vec3& p0, const Vec3& p1, const Vec3& p2, const Vec4& c0, const Vec4& c1, const Vec4& c2) const;
188         void                            renderTriangle                  (const Vec3& p0, const Vec3& p1, const Vec3& p2, const Vec4& color) const;
189         void                            renderTriangle                  (const Vec2& p0, const Vec2& p1, const Vec2& p2, const Vec4& c0, const Vec4& c1, const Vec4& c2) const;
190         void                            renderTriangle                  (const Vec2& p0, const Vec2& p1, const Vec2& p2, const Vec4& color) const;
191         void                            renderQuad                              (const Vec2& p0, const Vec2& p1, const Vec2& p2, const Vec2& p3, const Vec4& c0, const Vec4& c1, const Vec4& c2, const Vec4& c3) const;
192         void                            renderQuad                              (const Vec2& p0, const Vec2& p1, const Vec2& p2, const Vec2& p3, const Vec4& color) const;
193         void                            renderLine                              (const Vec2& p0, const Vec2& p1, const Vec4& color) const;
194
195         void                            randomizeViewport               (void);
196         void                            readImage                               (tcu::Surface& dst) const;
197
198         int                                     m_numSamples;
199
200         int                                     m_viewportSize;
201
202 private:
203                                                 MultisampleCase                 (const MultisampleCase& other);
204         MultisampleCase&        operator=                               (const MultisampleCase& other);
205
206         glu::ShaderProgram*     m_program;
207         int                                     m_attrPositionLoc;
208         int                                     m_attrColorLoc;
209
210         int                                     m_viewportX;
211         int                                     m_viewportY;
212         de::Random                      m_rnd;
213 };
214
215 MultisampleCase::MultisampleCase (Context& context, const char* name, const char* desc)
216         : TestCase                      (context, name, desc)
217         , m_numSamples          (0)
218         , m_viewportSize        (0)
219         , m_program                     (DE_NULL)
220         , m_attrPositionLoc     (-1)
221         , m_attrColorLoc        (-1)
222         , m_viewportX           (0)
223         , m_viewportY           (0)
224         , m_rnd                         (deStringHash(name))
225 {
226 }
227
228 void MultisampleCase::renderTriangle (const Vec3& p0, const Vec3& p1, const Vec3& p2, const Vec4& c0, const Vec4& c1, const Vec4& c2) const
229 {
230         float vertexPositions[] =
231         {
232                 p0.x(), p0.y(), p0.z(), 1.0f,
233                 p1.x(), p1.y(), p1.z(), 1.0f,
234                 p2.x(), p2.y(), p2.z(), 1.0f
235         };
236         float vertexColors[] =
237         {
238                 c0.x(), c0.y(), c0.z(), c0.w(),
239                 c1.x(), c1.y(), c1.z(), c1.w(),
240                 c2.x(), c2.y(), c2.z(), c2.w(),
241         };
242
243         GLU_CHECK_CALL(glEnableVertexAttribArray(m_attrPositionLoc));
244         GLU_CHECK_CALL(glVertexAttribPointer(m_attrPositionLoc, 4, GL_FLOAT, false, 0, &vertexPositions[0]));
245
246         GLU_CHECK_CALL(glEnableVertexAttribArray(m_attrColorLoc));
247         GLU_CHECK_CALL(glVertexAttribPointer(m_attrColorLoc, 4, GL_FLOAT, false, 0, &vertexColors[0]));
248
249         GLU_CHECK_CALL(glUseProgram(m_program->getProgram()));
250         GLU_CHECK_CALL(glDrawArrays(GL_TRIANGLES, 0, 3));
251 }
252
253 void MultisampleCase::renderTriangle (const Vec3& p0, const Vec3& p1, const Vec3& p2, const Vec4& color) const
254 {
255         renderTriangle(p0, p1, p2, color, color, color);
256 }
257
258 void MultisampleCase::renderTriangle (const Vec2& p0, const Vec2& p1, const Vec2& p2, const Vec4& c0, const Vec4& c1, const Vec4& c2) const
259 {
260         renderTriangle(Vec3(p0.x(), p0.y(), 0.0f),
261                                    Vec3(p1.x(), p1.y(), 0.0f),
262                                    Vec3(p2.x(), p2.y(), 0.0f),
263                                    c0, c1, c2);
264 }
265
266 void MultisampleCase::renderTriangle (const Vec2& p0, const Vec2& p1, const Vec2& p2, const Vec4& color) const
267 {
268         renderTriangle(p0, p1, p2, color, color, color);
269 }
270
271 void MultisampleCase::renderQuad (const Vec2& p0, const Vec2& p1, const Vec2& p2, const Vec2& p3, const Vec4& c0, const Vec4& c1, const Vec4& c2, const Vec4& c3) const
272 {
273         renderTriangle(p0, p1, p2, c0, c1, c2);
274         renderTriangle(p2, p1, p3, c2, c1, c3);
275 }
276
277 void MultisampleCase::renderQuad (const Vec2& p0, const Vec2& p1, const Vec2& p2, const Vec2& p3, const Vec4& color) const
278 {
279         renderQuad(p0, p1, p2, p3, color, color, color, color);
280 }
281
282 void MultisampleCase::renderLine (const Vec2& p0, const Vec2& p1, const Vec4& color) const
283 {
284         float vertexPositions[] =
285         {
286                 p0.x(), p0.y(), 0.0f, 1.0f,
287                 p1.x(), p1.y(), 0.0f, 1.0f
288         };
289         float vertexColors[] =
290         {
291                 color.x(), color.y(), color.z(), color.w(),
292                 color.x(), color.y(), color.z(), color.w()
293         };
294
295         GLU_CHECK_CALL(glEnableVertexAttribArray(m_attrPositionLoc));
296         GLU_CHECK_CALL(glVertexAttribPointer(m_attrPositionLoc, 4, GL_FLOAT, false, 0, &vertexPositions[0]));
297
298         GLU_CHECK_CALL(glEnableVertexAttribArray(m_attrColorLoc));
299         GLU_CHECK_CALL(glVertexAttribPointer(m_attrColorLoc, 4, GL_FLOAT, false, 0, &vertexColors[0]));
300
301         GLU_CHECK_CALL(glUseProgram(m_program->getProgram()));
302         GLU_CHECK_CALL(glDrawArrays(GL_LINES, 0, 2));
303 }
304
305 void MultisampleCase::randomizeViewport (void)
306 {
307         m_viewportX = m_rnd.getInt(0, m_context.getRenderTarget().getWidth() - m_viewportSize);
308         m_viewportY = m_rnd.getInt(0, m_context.getRenderTarget().getHeight() - m_viewportSize);
309
310         GLU_CHECK_CALL(glViewport(m_viewportX, m_viewportY, m_viewportSize, m_viewportSize));
311 }
312
313 void MultisampleCase::readImage (tcu::Surface& dst) const
314 {
315         glu::readPixels(m_context.getRenderContext(), m_viewportX, m_viewportY, dst.getAccess());
316 }
317
318 void MultisampleCase::init (void)
319 {
320         static const char* vertShaderSource =
321                 "attribute highp vec4 a_position;\n"
322                 "attribute mediump vec4 a_color;\n"
323                 "varying mediump vec4 v_color;\n"
324                 "void main()\n"
325                 "{\n"
326                 "       gl_Position = a_position;\n"
327                 "       v_color = a_color;\n"
328                 "}\n";
329
330         static const char* fragShaderSource =
331                 "varying mediump vec4 v_color;\n"
332                 "void main()\n"
333                 "{\n"
334                 "       gl_FragColor = v_color;\n"
335                 "}\n";
336
337         // Check multisample support.
338
339         if (m_context.getRenderTarget().getNumSamples() <= 1)
340                 throw tcu::NotSupportedError("No multisample buffers");
341
342         // Prepare program.
343
344         DE_ASSERT(!m_program);
345
346         m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(vertShaderSource, fragShaderSource));
347         if (!m_program->isOk())
348                 throw tcu::TestError("Failed to compile program", DE_NULL, __FILE__, __LINE__);
349
350         GLU_CHECK_CALL(m_attrPositionLoc        = glGetAttribLocation(m_program->getProgram(), "a_position"));
351         GLU_CHECK_CALL(m_attrColorLoc           = glGetAttribLocation(m_program->getProgram(), "a_color"));
352
353         if (m_attrPositionLoc < 0 || m_attrColorLoc < 0)
354         {
355                 delete m_program;
356                 throw tcu::TestError("Invalid attribute locations", DE_NULL, __FILE__, __LINE__);
357         }
358
359         // Get suitable viewport size.
360
361         m_viewportSize = de::min<int>(getDesiredViewportSize(), de::min(m_context.getRenderTarget().getWidth(), m_context.getRenderTarget().getHeight()));
362         randomizeViewport();
363
364         // Query and log number of samples per pixel.
365
366         m_numSamples = getGLInteger(GL_SAMPLES);
367         m_testCtx.getLog() << TestLog::Message << "GL_SAMPLES = " << m_numSamples << TestLog::EndMessage;
368 }
369
370 MultisampleCase::~MultisampleCase (void)
371 {
372         delete m_program;
373 }
374
375 void MultisampleCase::deinit (void)
376 {
377         delete m_program;
378
379         m_program = DE_NULL;
380 }
381
382 /*--------------------------------------------------------------------*//*!
383  * \brief Base class for cases testing the value of GL_SAMPLES.
384  *
385  * Draws a test pattern (defined by renderPattern() of an inheriting class)
386  * and counts the number of distinct colors in the resulting image. That
387  * number should be at least the value of GL_SAMPLES plus one. This is
388  * repeated with increased values of m_currentIteration until this correct
389  * number of colors is detected or m_currentIteration reaches
390  * m_maxNumIterations.
391  *//*--------------------------------------------------------------------*/
392 class NumSamplesCase : public MultisampleCase
393 {
394 public:
395                                                 NumSamplesCase                  (Context& context, const char* name, const char* description);
396                                                 ~NumSamplesCase                 (void) {}
397
398         IterateResult           iterate                                 (void);
399
400 protected:
401         int                                     getDesiredViewportSize  (void) const { return 256; }
402         virtual void            renderPattern                   (void) const = 0;
403
404         int                                     m_currentIteration;
405
406 private:
407         enum { DEFAULT_MAX_NUM_ITERATIONS = 16 };
408
409         const int                       m_maxNumIterations;
410         vector<tcu::RGBA>       m_detectedColors;
411 };
412
413 NumSamplesCase::NumSamplesCase (Context& context, const char* name, const char* description)
414         : MultisampleCase               (context, name, description)
415         , m_currentIteration    (0)
416         , m_maxNumIterations    (getIterationCount(m_testCtx, DEFAULT_MAX_NUM_ITERATIONS))
417 {
418 }
419
420 NumSamplesCase::IterateResult NumSamplesCase::iterate (void)
421 {
422         TestLog&                log                             = m_testCtx.getLog();
423         tcu::Surface    renderedImg             (m_viewportSize, m_viewportSize);
424
425         randomizeViewport();
426
427         GLU_CHECK_CALL(glClearColor(0.0f, 0.0f, 0.0f, 1.0f));
428         GLU_CHECK_CALL(glClear(GL_COLOR_BUFFER_BIT));
429
430         renderPattern();
431
432         // Read and log rendered image.
433
434         readImage(renderedImg);
435
436         log << TestLog::Image("RenderedImage", "Rendered image", renderedImg, QP_IMAGE_COMPRESSION_MODE_PNG);
437
438         // Detect new, previously unseen colors from image.
439
440         int requiredNumDistinctColors = m_numSamples + 1;
441
442         for (int y = 0; y < renderedImg.getHeight() && (int)m_detectedColors.size() < requiredNumDistinctColors; y++)
443         for (int x = 0; x < renderedImg.getWidth() && (int)m_detectedColors.size() < requiredNumDistinctColors; x++)
444         {
445                 tcu::RGBA color = renderedImg.getPixel(x, y);
446
447                 int i;
448                 for (i = 0; i < (int)m_detectedColors.size(); i++)
449                 {
450                         if (tcu::compareThreshold(color, m_detectedColors[i], tcu::RGBA(3, 3, 3, 3)))
451                                 break;
452                 }
453
454                 if (i == (int)m_detectedColors.size())
455                         m_detectedColors.push_back(color); // Color not previously detected.
456         }
457
458         // Log results.
459
460         log << TestLog::Message
461                 << "Number of distinct colors detected so far: "
462                 << ((int)m_detectedColors.size() >= requiredNumDistinctColors ? "at least " : "")
463                 << de::toString(m_detectedColors.size())
464                 << TestLog::EndMessage;
465
466         if ((int)m_detectedColors.size() < requiredNumDistinctColors)
467         {
468                 // Haven't detected enough different colors yet.
469
470                 m_currentIteration++;
471
472                 if (m_currentIteration >= m_maxNumIterations)
473                 {
474                         log << TestLog::Message << "Failure: Number of distinct colors detected is lower than GL_SAMPLES+1" << TestLog::EndMessage;
475                         m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Failed");
476                         return STOP;
477                 }
478                 else
479                 {
480                         log << TestLog::Message << "The number of distinct colors detected is lower than GL_SAMPLES+1 - trying again with a slightly altered pattern" << TestLog::EndMessage;
481                         return CONTINUE;
482                 }
483         }
484         else
485         {
486                 log << TestLog::Message << "Success: The number of distinct colors detected is at least GL_SAMPLES+1" << TestLog::EndMessage;
487                 m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Passed");
488                 return STOP;
489         }
490 }
491
492 class PolygonNumSamplesCase : public NumSamplesCase
493 {
494 public:
495                         PolygonNumSamplesCase   (Context& context, const char* name, const char* description);
496                         ~PolygonNumSamplesCase  (void) {}
497
498 protected:
499         void    renderPattern                   (void) const;
500 };
501
502 PolygonNumSamplesCase::PolygonNumSamplesCase (Context& context, const char* name, const char* description)
503         : NumSamplesCase(context, name, description)
504 {
505 }
506
507 void PolygonNumSamplesCase::renderPattern (void) const
508 {
509         // The test pattern consists of several triangles with edges at different angles.
510
511         const int numTriangles = 25;
512         for (int i = 0; i < numTriangles; i++)
513         {
514                 float angle0 = 2.0f*DE_PI * (float)i                    / (float)numTriangles + 0.001f*(float)m_currentIteration;
515                 float angle1 = 2.0f*DE_PI * ((float)i + 0.5f)   / (float)numTriangles + 0.001f*(float)m_currentIteration;
516
517                 renderTriangle(Vec2(0.0f, 0.0f),
518                                            Vec2(deFloatCos(angle0)*0.95f, deFloatSin(angle0)*0.95f),
519                                            Vec2(deFloatCos(angle1)*0.95f, deFloatSin(angle1)*0.95f),
520                                            Vec4(1.0f));
521         }
522 }
523
524 class LineNumSamplesCase : public NumSamplesCase
525 {
526 public:
527                         LineNumSamplesCase              (Context& context, const char* name, const char* description);
528                         ~LineNumSamplesCase             (void) {}
529
530 protected:
531         void    renderPattern                   (void) const;
532 };
533
534 LineNumSamplesCase::LineNumSamplesCase (Context& context, const char* name, const char* description)
535         : NumSamplesCase (context, name, description)
536 {
537 }
538
539 void LineNumSamplesCase::renderPattern (void) const
540 {
541         // The test pattern consists of several lines at different angles.
542
543         // We scale the number of lines based on the viewport size. This is because a gl line's thickness is
544         // constant in pixel units, i.e. they get relatively thicker as viewport size decreases. Thus we must
545         // decrease the number of lines in order to decrease the extent of overlap among the lines in the
546         // center of the pattern.
547         const int numLines = (int)(100.0f * deFloatSqrt((float)m_viewportSize / 256.0f));
548
549         for (int i = 0; i < numLines; i++)
550         {
551                 float angle = 2.0f*DE_PI * (float)i / (float)numLines + 0.001f*(float)m_currentIteration;
552                 renderLine(Vec2(0.0f, 0.0f), Vec2(deFloatCos(angle)*0.95f, deFloatSin(angle)*0.95f), Vec4(1.0f));
553         }
554 }
555
556 /*--------------------------------------------------------------------*//*!
557  * \brief Case testing behaviour of common edges when multisampling.
558  *
559  * Draws a number of test patterns, each with a number of quads, each made
560  * of two triangles, rotated at different angles. The inner edge inside the
561  * quad (i.e. the common edge of the two triangles) still should not be
562  * visible, despite multisampling - i.e. the two triangles forming the quad
563  * should never get any common coverage bits in any pixel.
564  *//*--------------------------------------------------------------------*/
565 class CommonEdgeCase : public MultisampleCase
566 {
567 public:
568         enum CaseType
569         {
570                 CASETYPE_SMALL_QUADS = 0,                               //!< Draw several small quads per iteration.
571                 CASETYPE_BIGGER_THAN_VIEWPORT_QUAD,             //!< Draw one bigger-than-viewport quad per iteration.
572                 CASETYPE_FIT_VIEWPORT_QUAD,                             //!< Draw one exactly viewport-sized, axis aligned quad per iteration.
573
574                 CASETYPE_LAST
575         };
576
577                                         CommonEdgeCase                  (Context& context, const char* name, const char* description, CaseType caseType);
578                                         ~CommonEdgeCase                 (void) {}
579
580         void                    init                                    (void);
581
582         IterateResult   iterate                                 (void);
583
584 protected:
585         int                             getDesiredViewportSize  (void) const { return m_caseType == CASETYPE_SMALL_QUADS ? 128 : 32; }
586
587 private:
588         enum
589         {
590                 DEFAULT_SMALL_QUADS_ITERATIONS                                  = 16,
591                 DEFAULT_BIGGER_THAN_VIEWPORT_QUAD_ITERATIONS    = 8*8
592                 // \note With CASETYPE_FIT_VIEWPORT_QUAD, we don't do rotations other than multiples of 90 deg -> constant number of iterations.
593         };
594
595         const CaseType  m_caseType;
596
597         const int               m_numIterations;
598         int                             m_currentIteration;
599 };
600
601 CommonEdgeCase::CommonEdgeCase (Context& context, const char* name, const char* description, CaseType caseType)
602         : MultisampleCase               (context, name, description)
603         , m_caseType                    (caseType)
604         , m_numIterations               (caseType == CASETYPE_SMALL_QUADS                                       ? getIterationCount(m_testCtx, DEFAULT_SMALL_QUADS_ITERATIONS)
605                                                         : caseType == CASETYPE_BIGGER_THAN_VIEWPORT_QUAD        ? getIterationCount(m_testCtx, DEFAULT_BIGGER_THAN_VIEWPORT_QUAD_ITERATIONS)
606                                                         : 8)
607         , m_currentIteration    (0)
608 {
609 }
610
611 void CommonEdgeCase::init (void)
612 {
613         MultisampleCase::init();
614
615         if (m_caseType == CASETYPE_SMALL_QUADS)
616         {
617                 // Check for a big enough viewport. With too small viewports the test case can't analyze the resulting image well enough.
618
619                 const int minViewportSize = 32;
620
621                 DE_ASSERT(minViewportSize <= getDesiredViewportSize());
622
623                 if (m_viewportSize < minViewportSize)
624                         throw tcu::InternalError("Render target width or height too low (is " + de::toString(m_viewportSize) + ", should be at least " + de::toString(minViewportSize) + ")");
625         }
626
627         GLU_CHECK_CALL(glEnable(GL_BLEND));
628         GLU_CHECK_CALL(glBlendEquation(GL_FUNC_ADD));
629         GLU_CHECK_CALL(glBlendFunc(GL_ONE, GL_ONE));
630
631         m_testCtx.getLog() << TestLog::Message << "Additive blending enabled in order to detect (erroneously) overlapping samples" << TestLog::EndMessage;
632 }
633
634 CommonEdgeCase::IterateResult CommonEdgeCase::iterate (void)
635 {
636         TestLog&                log                             = m_testCtx.getLog();
637         tcu::Surface    renderedImg             (m_viewportSize, m_viewportSize);
638         tcu::Surface    errorImg                (m_viewportSize, m_viewportSize);
639
640         randomizeViewport();
641
642         GLU_CHECK_CALL(glClearColor(0.0f, 0.0f, 0.0f, 1.0f));
643         GLU_CHECK_CALL(glClear(GL_COLOR_BUFFER_BIT));
644
645         // Draw test pattern. Test patterns consist of quads formed with two triangles.
646         // After drawing the pattern, we check that the interior pixels of each quad are
647         // all the same color - this is meant to verify that there are no artifacts on the inner edge.
648
649         vector<QuadCorners> unicoloredRegions;
650
651         if (m_caseType == CASETYPE_SMALL_QUADS)
652         {
653                 // Draw several quads, rotated at different angles.
654
655                 const float             quadDiagLen = 2.0f / 3.0f * 0.9f; // \note Fit 3 quads in both x and y directions.
656                 float                   angleCos;
657                 float                   angleSin;
658
659                 // \note First and second iteration get exact 0 (and 90, 180, 270) and 45 (and 135, 225, 315) angle quads, as they are kind of a special case.
660
661                 if (m_currentIteration == 0)
662                 {
663                         angleCos = 1.0f;
664                         angleSin = 0.0f;
665                 }
666                 else if (m_currentIteration == 1)
667                 {
668                         angleCos = SQRT_HALF;
669                         angleSin = SQRT_HALF;
670                 }
671                 else
672                 {
673                         float angle = 0.5f * DE_PI * (float)(m_currentIteration-1) / (float)(m_numIterations-1);
674                         angleCos = deFloatCos(angle);
675                         angleSin = deFloatSin(angle);
676                 }
677
678                 Vec2 corners[4] =
679                 {
680                         0.5f * quadDiagLen * Vec2( angleCos,  angleSin),
681                         0.5f * quadDiagLen * Vec2(-angleSin,  angleCos),
682                         0.5f * quadDiagLen * Vec2(-angleCos, -angleSin),
683                         0.5f * quadDiagLen * Vec2( angleSin, -angleCos)
684                 };
685
686                 unicoloredRegions.reserve(8);
687
688                 // Draw 8 quads.
689                 // First four are rotated at angles angle+0, angle+90, angle+180 and angle+270.
690                 // Last four are rotated the same angles as the first four, but the ordering of the last triangle's vertices is reversed.
691
692                 for (int quadNdx = 0; quadNdx < 8; quadNdx++)
693                 {
694                         Vec2 center = (2.0f-quadDiagLen) * Vec2((float)(quadNdx%3), (float)(quadNdx/3)) / 2.0f - 0.5f*(2.0f-quadDiagLen);
695
696                         renderTriangle(corners[(0+quadNdx) % 4] + center,
697                                                    corners[(1+quadNdx) % 4] + center,
698                                                    corners[(2+quadNdx) % 4] + center,
699                                                    Vec4(0.5f, 0.5f, 0.5f, 1.0f));
700
701                         if (quadNdx >= 4)
702                         {
703                                 renderTriangle(corners[(3+quadNdx) % 4] + center,
704                                                            corners[(2+quadNdx) % 4] + center,
705                                                            corners[(0+quadNdx) % 4] + center,
706                                                            Vec4(0.5f, 0.5f, 0.5f, 1.0f));
707                         }
708                         else
709                         {
710                                 renderTriangle(corners[(0+quadNdx) % 4] + center,
711                                                            corners[(2+quadNdx) % 4] + center,
712                                                            corners[(3+quadNdx) % 4] + center,
713                                                            Vec4(0.5f, 0.5f, 0.5f, 1.0f));
714                         }
715
716                         // The size of the "interior" of a quad is assumed to be approximately unicolorRegionScale*<actual size of quad>.
717                         // By "interior" we here mean the region of non-boundary pixels of the rendered quad for which we can safely assume
718                         // that it has all coverage bits set to 1, for every pixel.
719                         float unicolorRegionScale = 1.0f - 6.0f*2.0f / (float)m_viewportSize / quadDiagLen;
720                         unicoloredRegions.push_back(QuadCorners((center + corners[0]*unicolorRegionScale),
721                                                                                                         (center + corners[1]*unicolorRegionScale),
722                                                                                                         (center + corners[2]*unicolorRegionScale),
723                                                                                                         (center + corners[3]*unicolorRegionScale)));
724                 }
725         }
726         else if (m_caseType == CASETYPE_BIGGER_THAN_VIEWPORT_QUAD)
727         {
728                 // Draw a bigger-than-viewport quad, rotated at an angle depending on m_currentIteration.
729
730                 int                             quadBaseAngleNdx                = m_currentIteration / 8;
731                 int                             quadSubAngleNdx                 = m_currentIteration % 8;
732                 float                   angleCos;
733                 float                   angleSin;
734
735                 if (quadBaseAngleNdx == 0)
736                 {
737                         angleCos = 1.0f;
738                         angleSin = 0.0f;
739                 }
740                 else if (quadBaseAngleNdx == 1)
741                 {
742                         angleCos = SQRT_HALF;
743                         angleSin = SQRT_HALF;
744                 }
745                 else
746                 {
747                         float angle = 0.5f * DE_PI * (float)(m_currentIteration-1) / (float)(m_numIterations-1);
748                         angleCos = deFloatCos(angle);
749                         angleSin = deFloatSin(angle);
750                 }
751
752                 float quadDiagLen = 2.5f / de::max(angleCos, angleSin);
753
754                 Vec2 corners[4] =
755                 {
756                         0.5f * quadDiagLen * Vec2( angleCos,  angleSin),
757                         0.5f * quadDiagLen * Vec2(-angleSin,  angleCos),
758                         0.5f * quadDiagLen * Vec2(-angleCos, -angleSin),
759                         0.5f * quadDiagLen * Vec2( angleSin, -angleCos)
760                 };
761
762                 renderTriangle(corners[(0+quadSubAngleNdx) % 4],
763                                            corners[(1+quadSubAngleNdx) % 4],
764                                            corners[(2+quadSubAngleNdx) % 4],
765                                            Vec4(0.5f, 0.5f, 0.5f, 1.0f));
766
767                 if (quadSubAngleNdx >= 4)
768                 {
769                         renderTriangle(corners[(3+quadSubAngleNdx) % 4],
770                                                    corners[(2+quadSubAngleNdx) % 4],
771                                                    corners[(0+quadSubAngleNdx) % 4],
772                                                    Vec4(0.5f, 0.5f, 0.5f, 1.0f));
773                 }
774                 else
775                 {
776                         renderTriangle(corners[(0+quadSubAngleNdx) % 4],
777                                                    corners[(2+quadSubAngleNdx) % 4],
778                                                    corners[(3+quadSubAngleNdx) % 4],
779                                                    Vec4(0.5f, 0.5f, 0.5f, 1.0f));
780                 }
781
782                 float unicolorRegionScale = 1.0f - 6.0f*2.0f / (float)m_viewportSize / quadDiagLen;
783                 unicoloredRegions.push_back(QuadCorners((corners[0]*unicolorRegionScale),
784                                                                                                 (corners[1]*unicolorRegionScale),
785                                                                                                 (corners[2]*unicolorRegionScale),
786                                                                                                 (corners[3]*unicolorRegionScale)));
787         }
788         else if (m_caseType == CASETYPE_FIT_VIEWPORT_QUAD)
789         {
790                 // Draw an exactly viewport-sized quad, rotated by multiples of 90 degrees angle depending on m_currentIteration.
791
792                 int quadSubAngleNdx = m_currentIteration % 8;
793
794                 Vec2 corners[4] =
795                 {
796                         Vec2( 1.0f,  1.0f),
797                         Vec2(-1.0f,  1.0f),
798                         Vec2(-1.0f, -1.0f),
799                         Vec2( 1.0f, -1.0f)
800                 };
801
802                 renderTriangle(corners[(0+quadSubAngleNdx) % 4],
803                                            corners[(1+quadSubAngleNdx) % 4],
804                                            corners[(2+quadSubAngleNdx) % 4],
805                                            Vec4(0.5f, 0.5f, 0.5f, 1.0f));
806
807                 if (quadSubAngleNdx >= 4)
808                 {
809                         renderTriangle(corners[(3+quadSubAngleNdx) % 4],
810                                                    corners[(2+quadSubAngleNdx) % 4],
811                                                    corners[(0+quadSubAngleNdx) % 4],
812                                                    Vec4(0.5f, 0.5f, 0.5f, 1.0f));
813                 }
814                 else
815                 {
816                         renderTriangle(corners[(0+quadSubAngleNdx) % 4],
817                                                    corners[(2+quadSubAngleNdx) % 4],
818                                                    corners[(3+quadSubAngleNdx) % 4],
819                                                    Vec4(0.5f, 0.5f, 0.5f, 1.0f));
820                 }
821
822                 unicoloredRegions.push_back(QuadCorners(corners[0], corners[1], corners[2], corners[3]));
823         }
824         else
825                 DE_ASSERT(false);
826
827         // Read pixels and check unicolored regions.
828
829         readImage(renderedImg);
830
831         tcu::clear(errorImg.getAccess(), Vec4(0.0f, 1.0f, 0.0f, 1.0f));
832
833         log << TestLog::Image("RenderedImage", "Rendered image", renderedImg, QP_IMAGE_COMPRESSION_MODE_PNG);
834
835         bool errorsDetected = false;
836         for (int i = 0; i < (int)unicoloredRegions.size(); i++)
837         {
838                 const QuadCorners&      region                                  = unicoloredRegions[i];
839                 IVec2                           p0Win                                   = ((region.p0+1.0f) * 0.5f * (float)(m_viewportSize-1) + 0.5f).asInt();
840                 IVec2                           p1Win                                   = ((region.p1+1.0f) * 0.5f * (float)(m_viewportSize-1) + 0.5f).asInt();
841                 IVec2                           p2Win                                   = ((region.p2+1.0f) * 0.5f * (float)(m_viewportSize-1) + 0.5f).asInt();
842                 IVec2                           p3Win                                   = ((region.p3+1.0f) * 0.5f * (float)(m_viewportSize-1) + 0.5f).asInt();
843                 bool                            errorsInCurrentRegion   = !isPixelRegionUnicolored(renderedImg, p0Win, p1Win, p2Win, p3Win);
844
845                 if (errorsInCurrentRegion)
846                         drawUnicolorTestErrors(renderedImg, errorImg.getAccess(), p0Win, p1Win, p2Win, p3Win);
847
848                 errorsDetected = errorsDetected || errorsInCurrentRegion;
849         }
850
851         m_currentIteration++;
852
853         if (errorsDetected)
854         {
855                 log << TestLog::Message << "Failure: Not all quad interiors seem unicolored - common-edge artifacts?" << TestLog::EndMessage;
856                 log << TestLog::Message << "Erroneous pixels are drawn red in the following image" << TestLog::EndMessage;
857                 log << TestLog::Image("RenderedImageWithErrors",        "Rendered image with errors marked",    renderedImg,    QP_IMAGE_COMPRESSION_MODE_PNG);
858                 log << TestLog::Image("ErrorsOnly",                                     "Image with error pixels only",                 errorImg,               QP_IMAGE_COMPRESSION_MODE_PNG);
859                 m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Failed");
860                 return STOP;
861         }
862         else if (m_currentIteration < m_numIterations)
863         {
864                 log << TestLog::Message << "Quads seem OK - moving on to next pattern" << TestLog::EndMessage;
865                 return CONTINUE;
866         }
867         else
868         {
869                 log << TestLog::Message << "Success: All quad interiors seem unicolored (no common-edge artifacts)" << TestLog::EndMessage;
870                 m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Passed");
871                 return STOP;
872         }
873 }
874
875 /*--------------------------------------------------------------------*//*!
876  * \brief Test that depth values are per-sample.
877  *
878  * Draws intersecting, differently-colored polygons and checks that there
879  * are at least GL_SAMPLES+1 distinct colors present, due to some of the
880  * samples at the intersection line belonging to one and some to another
881  * polygon.
882  *//*--------------------------------------------------------------------*/
883 class SampleDepthCase : public NumSamplesCase
884 {
885 public:
886                                                 SampleDepthCase                 (Context& context, const char* name, const char* description);
887                                                 ~SampleDepthCase                (void) {}
888
889         void                            init                                    (void);
890
891 protected:
892         void                            renderPattern                   (void) const;
893 };
894
895 SampleDepthCase::SampleDepthCase (Context& context, const char* name, const char* description)
896         : NumSamplesCase (context, name, description)
897 {
898 }
899
900 void SampleDepthCase::init (void)
901 {
902         TestLog& log = m_testCtx.getLog();
903
904         if (m_context.getRenderTarget().getDepthBits() == 0)
905                 TCU_THROW(NotSupportedError, "Test requires depth buffer");
906
907         MultisampleCase::init();
908
909         GLU_CHECK_CALL(glEnable(GL_DEPTH_TEST));
910         GLU_CHECK_CALL(glDepthFunc(GL_LESS));
911
912         log << TestLog::Message << "Depth test enabled, depth func is GL_LESS" << TestLog::EndMessage;
913         log << TestLog::Message << "Drawing several bigger-than-viewport black or white polygons intersecting each other" << TestLog::EndMessage;
914 }
915
916 void SampleDepthCase::renderPattern (void) const
917 {
918         GLU_CHECK_CALL(glClearColor(0.0f, 0.0f, 0.0f, 0.0f));
919         GLU_CHECK_CALL(glClearDepthf(1.0f));
920         GLU_CHECK_CALL(glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT));
921
922         {
923                 const int numPolygons = 50;
924
925                 for (int i = 0; i < numPolygons; i++)
926                 {
927                         Vec4    color   = i % 2 == 0 ? Vec4(1.0f, 1.0f, 1.0f, 1.0f) : Vec4(0.0f, 0.0f, 0.0f, 1.0f);
928                         float   angle   = 2.0f * DE_PI * (float)i / (float)numPolygons + 0.001f*(float)m_currentIteration;
929                         Vec3    pt0             (3.0f*deFloatCos(angle + 2.0f*DE_PI*0.0f/3.0f), 3.0f*deFloatSin(angle + 2.0f*DE_PI*0.0f/3.0f), 1.0f);
930                         Vec3    pt1             (3.0f*deFloatCos(angle + 2.0f*DE_PI*1.0f/3.0f), 3.0f*deFloatSin(angle + 2.0f*DE_PI*1.0f/3.0f), 0.0f);
931                         Vec3    pt2             (3.0f*deFloatCos(angle + 2.0f*DE_PI*2.0f/3.0f), 3.0f*deFloatSin(angle + 2.0f*DE_PI*2.0f/3.0f), 0.0f);
932
933                         renderTriangle(pt0, pt1, pt2, color);
934                 }
935         }
936 }
937
938 /*--------------------------------------------------------------------*//*!
939  * \brief Test that stencil buffer values are per-sample.
940  *
941  * Draws a unicolored pattern and marks drawn samples in stencil buffer;
942  * then clears and draws a viewport-size quad with that color and with
943  * proper stencil test such that the resulting image should be exactly the
944  * same as after the pattern was first drawn.
945  *//*--------------------------------------------------------------------*/
946 class SampleStencilCase : public MultisampleCase
947 {
948 public:
949                                                 SampleStencilCase               (Context& context, const char* name, const char* description);
950                                                 ~SampleStencilCase              (void) {}
951
952         void                            init                                    (void);
953         IterateResult           iterate                                 (void);
954
955 protected:
956         int                                     getDesiredViewportSize  (void) const { return 256; }
957 };
958
959 SampleStencilCase::SampleStencilCase (Context& context, const char* name, const char* description)
960         : MultisampleCase (context, name, description)
961 {
962 }
963
964 void SampleStencilCase::init (void)
965 {
966         if (m_context.getRenderTarget().getStencilBits() == 0)
967                 TCU_THROW(NotSupportedError, "Test requires stencil buffer");
968
969         MultisampleCase::init();
970 }
971
972 SampleStencilCase::IterateResult SampleStencilCase::iterate (void)
973 {
974         TestLog&                log                                     = m_testCtx.getLog();
975         tcu::Surface    renderedImgFirst        (m_viewportSize, m_viewportSize);
976         tcu::Surface    renderedImgSecond       (m_viewportSize, m_viewportSize);
977
978         randomizeViewport();
979
980         GLU_CHECK_CALL(glClearColor(0.0f, 0.0f, 0.0f, 1.0f));
981         GLU_CHECK_CALL(glClearStencil(0));
982         GLU_CHECK_CALL(glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT));
983         GLU_CHECK_CALL(glEnable(GL_STENCIL_TEST));
984         GLU_CHECK_CALL(glStencilFunc(GL_ALWAYS, 1, 1));
985         GLU_CHECK_CALL(glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE));
986
987         log << TestLog::Message << "Drawing a pattern with glStencilFunc(GL_ALWAYS, 1, 1) and glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE)" << TestLog::EndMessage;
988
989         {
990                 const int numTriangles = 25;
991                 for (int i = 0; i < numTriangles; i++)
992                 {
993                         float angle0 = 2.0f*DE_PI * (float)i                    / (float)numTriangles;
994                         float angle1 = 2.0f*DE_PI * ((float)i + 0.5f)   / (float)numTriangles;
995
996                         renderTriangle(Vec2(0.0f, 0.0f),
997                                                    Vec2(deFloatCos(angle0)*0.95f, deFloatSin(angle0)*0.95f),
998                                                    Vec2(deFloatCos(angle1)*0.95f, deFloatSin(angle1)*0.95f),
999                                                    Vec4(1.0f));
1000                 }
1001         }
1002
1003         readImage(renderedImgFirst);
1004         log << TestLog::Image("RenderedImgFirst", "First image rendered", renderedImgFirst, QP_IMAGE_COMPRESSION_MODE_PNG);
1005
1006         log << TestLog::Message << "Clearing color buffer to black" << TestLog::EndMessage;
1007
1008         GLU_CHECK_CALL(glClear(GL_COLOR_BUFFER_BIT));
1009         GLU_CHECK_CALL(glStencilFunc(GL_EQUAL, 1, 1));
1010         GLU_CHECK_CALL(glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP));
1011
1012         {
1013                 log << TestLog::Message << "Checking that color buffer was actually cleared to black" << TestLog::EndMessage;
1014
1015                 tcu::Surface clearedImg(m_viewportSize, m_viewportSize);
1016                 readImage(clearedImg);
1017
1018                 for (int y = 0; y < clearedImg.getHeight(); y++)
1019                 for (int x = 0; x < clearedImg.getWidth(); x++)
1020                 {
1021                         const tcu::RGBA& clr = clearedImg.getPixel(x, y);
1022                         if (clr != tcu::RGBA::black())
1023                         {
1024                                 log << TestLog::Message << "Failure: first non-black pixel, color " << clr << ", detected at coordinates (" << x << ", " << y << ")" << TestLog::EndMessage;
1025                                 log << TestLog::Image("ClearedImg", "Image after clearing, erroneously non-black", clearedImg);
1026                                 m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Failed");
1027                                 return STOP;
1028                         }
1029                 }
1030         }
1031
1032         log << TestLog::Message << "Drawing a viewport-sized quad with glStencilFunc(GL_EQUAL, 1, 1) and glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP) - should result in same image as the first" << TestLog::EndMessage;
1033
1034         renderQuad(Vec2(-1.0f, -1.0f),
1035                            Vec2( 1.0f, -1.0f),
1036                            Vec2(-1.0f,  1.0f),
1037                            Vec2( 1.0f,  1.0f),
1038                            Vec4(1.0f));
1039
1040         readImage(renderedImgSecond);
1041         log << TestLog::Image("RenderedImgSecond", "Second image rendered", renderedImgSecond, QP_IMAGE_COMPRESSION_MODE_PNG);
1042
1043         bool passed = tcu::pixelThresholdCompare(log,
1044                                                                                          "ImageCompare",
1045                                                                                          "Image comparison",
1046                                                                                          renderedImgFirst,
1047                                                                                          renderedImgSecond,
1048                                                                                          tcu::RGBA(0),
1049                                                                                          tcu::COMPARE_LOG_ON_ERROR);
1050
1051         if (passed)
1052                 log << TestLog::Message << "Success: The two images rendered are identical" << TestLog::EndMessage;
1053
1054         m_context.getTestContext().setTestResult(passed ? QP_TEST_RESULT_PASS   : QP_TEST_RESULT_FAIL,
1055                                                                                          passed ? "Passed"                              : "Failed");
1056
1057         return STOP;
1058 }
1059
1060 /*--------------------------------------------------------------------*//*!
1061  * \brief Tests coverage mask generation proportionality property.
1062  *
1063  * Tests that the number of coverage bits in a coverage mask created by
1064  * GL_SAMPLE_ALPHA_TO_COVERAGE or GL_SAMPLE_COVERAGE is, on average,
1065  * proportional to the alpha or coverage value, respectively. Draws
1066  * multiple frames, each time increasing the alpha or coverage value used,
1067  * and checks that the average color is changing appropriately.
1068  *//*--------------------------------------------------------------------*/
1069 class MaskProportionalityCase : public MultisampleCase
1070 {
1071 public:
1072         enum CaseType
1073         {
1074                 CASETYPE_ALPHA_TO_COVERAGE = 0,
1075                 CASETYPE_SAMPLE_COVERAGE,
1076                 CASETYPE_SAMPLE_COVERAGE_INVERTED,
1077
1078                 CASETYPE_LAST
1079         };
1080
1081                                         MaskProportionalityCase                         (Context& context, const char* name, const char* description, CaseType type);
1082                                         ~MaskProportionalityCase                        (void) {}
1083
1084         void                    init                                                            (void);
1085
1086         IterateResult   iterate                                                         (void);
1087
1088 protected:
1089         int                             getDesiredViewportSize                          (void) const { return 32; }
1090
1091 private:
1092         const CaseType  m_type;
1093
1094         int                             m_numIterations;
1095         int                             m_currentIteration;
1096
1097         deInt32                 m_previousIterationColorSum;
1098 };
1099
1100 MaskProportionalityCase::MaskProportionalityCase (Context& context, const char* name, const char* description, CaseType type)
1101         : MultisampleCase                               (context, name, description)
1102         , m_type                                                (type)
1103         , m_currentIteration                    (0)
1104         , m_previousIterationColorSum   (-1)
1105 {
1106 }
1107
1108 void MaskProportionalityCase::init (void)
1109 {
1110         TestLog& log = m_testCtx.getLog();
1111
1112         MultisampleCase::init();
1113
1114         if (m_type == CASETYPE_ALPHA_TO_COVERAGE)
1115         {
1116                 GLU_CHECK_CALL(glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE));
1117                 log << TestLog::Message << "GL_SAMPLE_ALPHA_TO_COVERAGE is enabled" << TestLog::EndMessage;
1118         }
1119         else
1120         {
1121                 DE_ASSERT(m_type == CASETYPE_SAMPLE_COVERAGE || m_type == CASETYPE_SAMPLE_COVERAGE_INVERTED);
1122
1123                 GLU_CHECK_CALL(glEnable(GL_SAMPLE_COVERAGE));
1124                 log << TestLog::Message << "GL_SAMPLE_COVERAGE is enabled" << TestLog::EndMessage;
1125         }
1126
1127         m_numIterations = de::max(2, getIterationCount(m_testCtx, m_numSamples * 5));
1128
1129         randomizeViewport(); // \note Using the same viewport for every iteration since coverage mask may depend on window-relative pixel coordinate.
1130 }
1131
1132 MaskProportionalityCase::IterateResult MaskProportionalityCase::iterate (void)
1133 {
1134         TestLog&                log                             = m_testCtx.getLog();
1135         tcu::Surface    renderedImg             (m_viewportSize, m_viewportSize);
1136         deInt32                 numPixels               = (deInt32)renderedImg.getWidth()*(deInt32)renderedImg.getHeight();
1137
1138         log << TestLog::Message << "Clearing color to black" << TestLog::EndMessage;
1139         GLU_CHECK_CALL(glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
1140         GLU_CHECK_CALL(glClearColor(0.0f, 0.0f, 0.0f, 1.0f));
1141         GLU_CHECK_CALL(glClear(GL_COLOR_BUFFER_BIT));
1142
1143         if (m_type == CASETYPE_ALPHA_TO_COVERAGE)
1144         {
1145                 GLU_CHECK_CALL(glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE));
1146                 log << TestLog::Message << "Using color mask TRUE, TRUE, TRUE, FALSE" << TestLog::EndMessage;
1147         }
1148
1149         // Draw quad.
1150
1151         {
1152                 const Vec2              pt0                                             (-1.0f, -1.0f);
1153                 const Vec2              pt1                                             ( 1.0f, -1.0f);
1154                 const Vec2              pt2                                             (-1.0f,  1.0f);
1155                 const Vec2              pt3                                             ( 1.0f,  1.0f);
1156                 Vec4                    quadColor                               (1.0f, 0.0f, 0.0f, 1.0f);
1157                 float                   alphaOrCoverageValue    = (float)m_currentIteration / (float)(m_numIterations-1);
1158
1159                 if (m_type == CASETYPE_ALPHA_TO_COVERAGE)
1160                 {
1161                         log << TestLog::Message << "Drawing a red quad using alpha value " + de::floatToString(alphaOrCoverageValue, 2) << TestLog::EndMessage;
1162                         quadColor.w() = alphaOrCoverageValue;
1163                 }
1164                 else
1165                 {
1166                         DE_ASSERT(m_type == CASETYPE_SAMPLE_COVERAGE || m_type == CASETYPE_SAMPLE_COVERAGE_INVERTED);
1167
1168                         bool    isInverted              = m_type == CASETYPE_SAMPLE_COVERAGE_INVERTED;
1169                         float   coverageValue   = isInverted ? 1.0f - alphaOrCoverageValue : alphaOrCoverageValue;
1170                         log << TestLog::Message << "Drawing a red quad using sample coverage value " + de::floatToString(coverageValue, 2) << (isInverted ? " (inverted)" : "") << TestLog::EndMessage;
1171                         GLU_CHECK_CALL(glSampleCoverage(coverageValue, isInverted ? GL_TRUE : GL_FALSE));
1172                 }
1173
1174                 renderQuad(pt0, pt1, pt2, pt3, quadColor);
1175         }
1176
1177         // Read ang log image.
1178
1179         readImage(renderedImg);
1180
1181         log << TestLog::Image("RenderedImage", "Rendered image", renderedImg, QP_IMAGE_COMPRESSION_MODE_PNG);
1182
1183         // Compute average red component in rendered image.
1184
1185         deInt32 sumRed = 0;
1186
1187         for (int y = 0; y < renderedImg.getHeight(); y++)
1188         for (int x = 0; x < renderedImg.getWidth(); x++)
1189                 sumRed += renderedImg.getPixel(x, y).getRed();
1190
1191         log << TestLog::Message << "Average red color component: " << de::floatToString((float)sumRed / 255.0f / (float)numPixels, 2) << TestLog::EndMessage;
1192
1193         // Check if average color has decreased from previous frame's color.
1194
1195         if (sumRed < m_previousIterationColorSum)
1196         {
1197                 log << TestLog::Message << "Failure: Current average red color component is lower than previous" << TestLog::EndMessage;
1198                 m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Failed");
1199                 return STOP;
1200         }
1201
1202         // Check if coverage mask is not all-zeros if alpha or coverage value is 0 (or 1, if inverted).
1203
1204         if (m_currentIteration == 0 && sumRed != 0)
1205         {
1206                 log << TestLog::Message << "Failure: Image should be completely black" << TestLog::EndMessage;
1207                 m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Failed");
1208                 return STOP;
1209         }
1210
1211         if (m_currentIteration == m_numIterations-1 && sumRed != 0xff*numPixels)
1212         {
1213                 log << TestLog::Message << "Failure: Image should be completely red" << TestLog::EndMessage;
1214
1215                 m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Failed");
1216                 return STOP;
1217         }
1218
1219         m_previousIterationColorSum = sumRed;
1220
1221         m_currentIteration++;
1222
1223         if (m_currentIteration >= m_numIterations)
1224         {
1225                 log << TestLog::Message
1226                         << "Success: Number of coverage mask bits set appears to be, on average, proportional to "
1227                         << (m_type == CASETYPE_ALPHA_TO_COVERAGE ? "alpha" : m_type == CASETYPE_SAMPLE_COVERAGE ? "sample coverage value" : "inverted sample coverage value")
1228                         << TestLog::EndMessage;
1229
1230                 m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Passed");
1231                 return STOP;
1232         }
1233         else
1234                 return CONTINUE;
1235 }
1236
1237 /*--------------------------------------------------------------------*//*!
1238  * \brief Tests coverage mask generation constancy property.
1239  *
1240  * Tests that the coverage mask created by GL_SAMPLE_ALPHA_TO_COVERAGE or
1241  * GL_SAMPLE_COVERAGE is constant at given pixel coordinates, with a given
1242  * alpha component or coverage value, respectively. Draws two quads, with
1243  * the second one fully overlapping the first one such that at any given
1244  * pixel, both quads have the same alpha or coverage value. This way, if
1245  * the constancy property is fulfilled, only the second quad should be
1246  * visible.
1247  *//*--------------------------------------------------------------------*/
1248 class MaskConstancyCase : public MultisampleCase
1249 {
1250 public:
1251         enum CaseType
1252         {
1253                 CASETYPE_ALPHA_TO_COVERAGE = 0,         //!< Use only alpha-to-coverage.
1254                 CASETYPE_SAMPLE_COVERAGE,                       //!< Use only sample coverage.
1255                 CASETYPE_SAMPLE_COVERAGE_INVERTED,      //!< Use only inverted sample coverage.
1256                 CASETYPE_BOTH,                                          //!< Use both alpha-to-coverage and sample coverage.
1257                 CASETYPE_BOTH_INVERTED,                         //!< Use both alpha-to-coverage and inverted sample coverage.
1258
1259                 CASETYPE_LAST
1260         };
1261
1262                                         MaskConstancyCase                       (Context& context, const char* name, const char* description, CaseType type);
1263                                         ~MaskConstancyCase                      (void) {}
1264
1265         IterateResult   iterate                                         (void);
1266
1267 protected:
1268         int                             getDesiredViewportSize          (void) const { return 256; }
1269
1270 private:
1271         const bool              m_isAlphaToCoverageCase;
1272         const bool              m_isSampleCoverageCase;
1273         const bool              m_isInvertedSampleCoverageCase;
1274 };
1275
1276 MaskConstancyCase::MaskConstancyCase (Context& context, const char* name, const char* description, CaseType type)
1277         : MultisampleCase                                       (context, name, description)
1278         , m_isAlphaToCoverageCase                       (type == CASETYPE_ALPHA_TO_COVERAGE                     || type == CASETYPE_BOTH                                                || type == CASETYPE_BOTH_INVERTED)
1279         , m_isSampleCoverageCase                        (type == CASETYPE_SAMPLE_COVERAGE                       || type == CASETYPE_SAMPLE_COVERAGE_INVERTED    || type == CASETYPE_BOTH                        || type == CASETYPE_BOTH_INVERTED)
1280         , m_isInvertedSampleCoverageCase        (type == CASETYPE_SAMPLE_COVERAGE_INVERTED      || type == CASETYPE_BOTH_INVERTED)
1281 {
1282 }
1283
1284 MaskConstancyCase::IterateResult MaskConstancyCase::iterate (void)
1285 {
1286         TestLog&                log                             = m_testCtx.getLog();
1287         tcu::Surface    renderedImg             (m_viewportSize, m_viewportSize);
1288
1289         randomizeViewport();
1290
1291         log << TestLog::Message << "Clearing color to black" << TestLog::EndMessage;
1292         GLU_CHECK_CALL(glClearColor(0.0f, 0.0f, 0.0f, 1.0f));
1293         GLU_CHECK_CALL(glClear(GL_COLOR_BUFFER_BIT));
1294
1295         if (m_isAlphaToCoverageCase)
1296         {
1297                 GLU_CHECK_CALL(glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE));
1298                 GLU_CHECK_CALL(glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE));
1299                 log << TestLog::Message << "GL_SAMPLE_ALPHA_TO_COVERAGE is enabled" << TestLog::EndMessage;
1300                 log << TestLog::Message << "Color mask is TRUE, TRUE, TRUE, FALSE" << TestLog::EndMessage;
1301         }
1302
1303         if (m_isSampleCoverageCase)
1304         {
1305                 GLU_CHECK_CALL(glEnable(GL_SAMPLE_COVERAGE));
1306                 log << TestLog::Message << "GL_SAMPLE_COVERAGE is enabled" << TestLog::EndMessage;
1307         }
1308
1309         log << TestLog::Message
1310                 << "Drawing several green quads, each fully overlapped by a red quad with the same "
1311                 << (m_isAlphaToCoverageCase ? "alpha" : "")
1312                 << (m_isAlphaToCoverageCase && m_isSampleCoverageCase ? " and " : "")
1313                 << (m_isInvertedSampleCoverageCase ? "inverted " : "")
1314                 << (m_isSampleCoverageCase ? "sample coverage" : "")
1315                 << " values"
1316                 << TestLog::EndMessage;
1317
1318         const int numQuadRowsCols = m_numSamples*4;
1319
1320         for (int row = 0; row < numQuadRowsCols; row++)
1321         {
1322                 for (int col = 0; col < numQuadRowsCols; col++)
1323                 {
1324                         float           x0                      = (float)(col+0) / (float)numQuadRowsCols * 2.0f - 1.0f;
1325                         float           x1                      = (float)(col+1) / (float)numQuadRowsCols * 2.0f - 1.0f;
1326                         float           y0                      = (float)(row+0) / (float)numQuadRowsCols * 2.0f - 1.0f;
1327                         float           y1                      = (float)(row+1) / (float)numQuadRowsCols * 2.0f - 1.0f;
1328                         const Vec4      baseGreen       (0.0f, 1.0f, 0.0f, 0.0f);
1329                         const Vec4      baseRed         (1.0f, 0.0f, 0.0f, 0.0f);
1330                         Vec4            alpha0          (0.0f, 0.0f, 0.0f, m_isAlphaToCoverageCase ? (float)col / (float)(numQuadRowsCols-1) : 1.0f);
1331                         Vec4            alpha1          (0.0f, 0.0f, 0.0f, m_isAlphaToCoverageCase ? (float)row / (float)(numQuadRowsCols-1) : 1.0f);
1332
1333                         if (m_isSampleCoverageCase)
1334                         {
1335                                 float value = (float)(row*numQuadRowsCols + col) / (float)(numQuadRowsCols*numQuadRowsCols-1);
1336                                 GLU_CHECK_CALL(glSampleCoverage(m_isInvertedSampleCoverageCase ? 1.0f - value : value, m_isInvertedSampleCoverageCase ? GL_TRUE : GL_FALSE));
1337                         }
1338
1339                         renderQuad(Vec2(x0, y0), Vec2(x1, y0), Vec2(x0, y1), Vec2(x1, y1), baseGreen + alpha0,  baseGreen + alpha1,     baseGreen + alpha0,     baseGreen + alpha1);
1340                         renderQuad(Vec2(x0, y0), Vec2(x1, y0), Vec2(x0, y1), Vec2(x1, y1), baseRed + alpha0,    baseRed + alpha1,       baseRed + alpha0,       baseRed + alpha1);
1341                 }
1342         }
1343
1344         readImage(renderedImg);
1345
1346         log << TestLog::Image("RenderedImage", "Rendered image", renderedImg, QP_IMAGE_COMPRESSION_MODE_PNG);
1347
1348         for (int y = 0; y < renderedImg.getHeight(); y++)
1349         for (int x = 0; x < renderedImg.getWidth(); x++)
1350         {
1351                 if (renderedImg.getPixel(x, y).getGreen() > 0)
1352                 {
1353                         log << TestLog::Message << "Failure: Non-zero green color component detected - should have been completely overwritten by red quad" << TestLog::EndMessage;
1354                         m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Failed");
1355                         return STOP;
1356                 }
1357         }
1358
1359         log << TestLog::Message
1360                 << "Success: Coverage mask appears to be constant at a given pixel coordinate with a given "
1361                 << (m_isAlphaToCoverageCase ? "alpha" : "")
1362                 << (m_isAlphaToCoverageCase && m_isSampleCoverageCase ? " and " : "")
1363                 << (m_isSampleCoverageCase ? "coverage value" : "")
1364                 << TestLog::EndMessage;
1365
1366         m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Passed");
1367
1368         return STOP;
1369 }
1370
1371 /*--------------------------------------------------------------------*//*!
1372  * \brief Tests coverage mask inversion validity.
1373  *
1374  * Tests that the coverage masks obtained by glSampleCoverage(..., GL_TRUE)
1375  * and glSampleCoverage(..., GL_FALSE) are indeed each others' inverses.
1376  * This is done by drawing a pattern, with varying coverage values,
1377  * overlapped by a pattern that has inverted masks and is otherwise
1378  * identical. The resulting image is compared to one obtained by drawing
1379  * the same pattern but with all-ones coverage masks.
1380  *//*--------------------------------------------------------------------*/
1381 class CoverageMaskInvertCase : public MultisampleCase
1382 {
1383 public:
1384                                         CoverageMaskInvertCase          (Context& context, const char* name, const char* description);
1385                                         ~CoverageMaskInvertCase         (void) {}
1386
1387         IterateResult   iterate                                         (void);
1388
1389 protected:
1390         int                             getDesiredViewportSize          (void) const { return 256; }
1391
1392 private:
1393         void                    drawPattern                                     (bool invertSampleCoverage) const;
1394 };
1395
1396 CoverageMaskInvertCase::CoverageMaskInvertCase (Context& context, const char* name, const char* description)
1397         : MultisampleCase (context, name, description)
1398 {
1399 }
1400
1401 void CoverageMaskInvertCase::drawPattern (bool invertSampleCoverage) const
1402 {
1403         const int numTriangles = 25;
1404         for (int i = 0; i < numTriangles; i++)
1405         {
1406                 GLU_CHECK_CALL(glSampleCoverage((float)i / (float)(numTriangles-1), invertSampleCoverage ? GL_TRUE : GL_FALSE));
1407
1408                 float angle0 = 2.0f*DE_PI * (float)i                    / (float)numTriangles;
1409                 float angle1 = 2.0f*DE_PI * ((float)i + 0.5f)   / (float)numTriangles;
1410
1411                 renderTriangle(Vec2(0.0f, 0.0f),
1412                                            Vec2(deFloatCos(angle0)*0.95f, deFloatSin(angle0)*0.95f),
1413                                            Vec2(deFloatCos(angle1)*0.95f, deFloatSin(angle1)*0.95f),
1414                                            Vec4(0.4f + (float)i/(float)numTriangles*0.6f,
1415                                                         0.5f + (float)i/(float)numTriangles*0.3f,
1416                                                         0.6f - (float)i/(float)numTriangles*0.5f,
1417                                                         0.7f - (float)i/(float)numTriangles*0.7f));
1418         }
1419 }
1420
1421 CoverageMaskInvertCase::IterateResult CoverageMaskInvertCase::iterate (void)
1422 {
1423         TestLog&                log                                                             = m_testCtx.getLog();
1424         tcu::Surface    renderedImgNoSampleCoverage             (m_viewportSize, m_viewportSize);
1425         tcu::Surface    renderedImgSampleCoverage               (m_viewportSize, m_viewportSize);
1426
1427         randomizeViewport();
1428
1429         GLU_CHECK_CALL(glEnable(GL_BLEND));
1430         GLU_CHECK_CALL(glBlendEquation(GL_FUNC_ADD));
1431         GLU_CHECK_CALL(glBlendFunc(GL_ONE, GL_ONE));
1432         log << TestLog::Message << "Additive blending enabled in order to detect (erroneously) overlapping samples" << TestLog::EndMessage;
1433
1434         log << TestLog::Message << "Clearing color to all-zeros" << TestLog::EndMessage;
1435         GLU_CHECK_CALL(glClearColor(0.0f, 0.0f, 0.0f, 0.0f));
1436         GLU_CHECK_CALL(glClear(GL_COLOR_BUFFER_BIT));
1437         log << TestLog::Message << "Drawing the pattern with GL_SAMPLE_COVERAGE disabled" << TestLog::EndMessage;
1438         drawPattern(false);
1439         readImage(renderedImgNoSampleCoverage);
1440
1441         log << TestLog::Image("RenderedImageNoSampleCoverage", "Rendered image with GL_SAMPLE_COVERAGE disabled", renderedImgNoSampleCoverage, QP_IMAGE_COMPRESSION_MODE_PNG);
1442
1443         log << TestLog::Message << "Clearing color to all-zeros" << TestLog::EndMessage;
1444         GLU_CHECK_CALL(glClear(GL_COLOR_BUFFER_BIT));
1445         GLU_CHECK_CALL(glEnable(GL_SAMPLE_COVERAGE));
1446         log << TestLog::Message << "Drawing the pattern with GL_SAMPLE_COVERAGE enabled, using non-inverted masks" << TestLog::EndMessage;
1447         drawPattern(false);
1448         log << TestLog::Message << "Drawing the pattern with GL_SAMPLE_COVERAGE enabled, using same sample coverage values but inverted masks" << TestLog::EndMessage;
1449         drawPattern(true);
1450         readImage(renderedImgSampleCoverage);
1451
1452         log << TestLog::Image("RenderedImageSampleCoverage", "Rendered image with GL_SAMPLE_COVERAGE enabled", renderedImgSampleCoverage, QP_IMAGE_COMPRESSION_MODE_PNG);
1453
1454         bool passed = tcu::pixelThresholdCompare(log,
1455                                                                                          "CoverageVsNoCoverage",
1456                                                                                          "Comparison of same pattern with GL_SAMPLE_COVERAGE disabled and enabled",
1457                                                                                          renderedImgNoSampleCoverage,
1458                                                                                          renderedImgSampleCoverage,
1459                                                                                          tcu::RGBA(0),
1460                                                                                          tcu::COMPARE_LOG_ON_ERROR);
1461
1462         if (passed)
1463                 log << TestLog::Message << "Success: The two images rendered are identical" << TestLog::EndMessage;
1464
1465         m_context.getTestContext().setTestResult(passed ? QP_TEST_RESULT_PASS   : QP_TEST_RESULT_FAIL,
1466                                                                                          passed ? "Passed"                              : "Failed");
1467
1468         return STOP;
1469 }
1470
1471 MultisampleTests::MultisampleTests (Context& context)
1472         : TestCaseGroup(context, "multisample", "Multisampling tests")
1473 {
1474 }
1475
1476 MultisampleTests::~MultisampleTests (void)
1477 {
1478 }
1479
1480 void MultisampleTests::init (void)
1481 {
1482         addChild(new PolygonNumSamplesCase              (m_context, "num_samples_polygon",                      "Test sanity of the value of GL_SAMPLES, with polygons"));
1483         addChild(new LineNumSamplesCase                 (m_context, "num_samples_line",                         "Test sanity of the value of GL_SAMPLES, with lines"));
1484         addChild(new CommonEdgeCase                             (m_context, "common_edge_small_quads",          "Test polygons' common edges with small quads",                                         CommonEdgeCase::CASETYPE_SMALL_QUADS));
1485         addChild(new CommonEdgeCase                             (m_context, "common_edge_big_quad",                     "Test polygons' common edges with bigger-than-viewport quads",          CommonEdgeCase::CASETYPE_BIGGER_THAN_VIEWPORT_QUAD));
1486         addChild(new CommonEdgeCase                             (m_context, "common_edge_viewport_quad",        "Test polygons' common edges with exactly viewport-sized quads",        CommonEdgeCase::CASETYPE_FIT_VIEWPORT_QUAD));
1487         addChild(new SampleDepthCase                    (m_context, "depth",                                            "Test that depth values are per-sample"));
1488         addChild(new SampleStencilCase                  (m_context, "stencil",                                          "Test that stencil values are per-sample"));
1489         addChild(new CoverageMaskInvertCase             (m_context, "sample_coverage_invert",           "Test that non-inverted and inverted sample coverage masks are each other's negations"));
1490
1491         addChild(new MaskProportionalityCase(m_context, "proportionality_alpha_to_coverage",                    "Test the proportionality property of GL_SAMPLE_ALPHA_TO_COVERAGE",                     MaskProportionalityCase::CASETYPE_ALPHA_TO_COVERAGE));
1492         addChild(new MaskProportionalityCase(m_context, "proportionality_sample_coverage",                              "Test the proportionality property of GL_SAMPLE_COVERAGE",                                      MaskProportionalityCase::CASETYPE_SAMPLE_COVERAGE));
1493         addChild(new MaskProportionalityCase(m_context, "proportionality_sample_coverage_inverted",             "Test the proportionality property of inverted-mask GL_SAMPLE_COVERAGE",        MaskProportionalityCase::CASETYPE_SAMPLE_COVERAGE_INVERTED));
1494
1495         addChild(new MaskConstancyCase(m_context, "constancy_alpha_to_coverage",                        "Test that coverage mask is constant at given coordinates with a given alpha or coverage value, using GL_SAMPLE_ALPHA_TO_COVERAGE",                                                                                     MaskConstancyCase::CASETYPE_ALPHA_TO_COVERAGE));
1496         addChild(new MaskConstancyCase(m_context, "constancy_sample_coverage",                          "Test that coverage mask is constant at given coordinates with a given alpha or coverage value, using GL_SAMPLE_COVERAGE",                                                                                                      MaskConstancyCase::CASETYPE_SAMPLE_COVERAGE));
1497         addChild(new MaskConstancyCase(m_context, "constancy_sample_coverage_inverted",         "Test that coverage mask is constant at given coordinates with a given alpha or coverage value, using inverted-mask GL_SAMPLE_COVERAGE",                                                                        MaskConstancyCase::CASETYPE_SAMPLE_COVERAGE_INVERTED));
1498         addChild(new MaskConstancyCase(m_context, "constancy_both",                                                     "Test that coverage mask is constant at given coordinates with a given alpha or coverage value, using GL_SAMPLE_ALPHA_TO_COVERAGE and GL_SAMPLE_COVERAGE",                                      MaskConstancyCase::CASETYPE_BOTH));
1499         addChild(new MaskConstancyCase(m_context, "constancy_both_inverted",                            "Test that coverage mask is constant at given coordinates with a given alpha or coverage value, using GL_SAMPLE_ALPHA_TO_COVERAGE and inverted-mask GL_SAMPLE_COVERAGE",        MaskConstancyCase::CASETYPE_BOTH_INVERTED));
1500 }
1501
1502 } // Functional
1503 } // gles2
1504 } // deqp