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