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