Fix missing dependency on sparse binds
[platform/upstream/VK-GL-CTS.git] / modules / gles31 / functional / es31fSampleVariableTests.cpp
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 3.1 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 Sample variable tests
22  *//*--------------------------------------------------------------------*/
23
24 #include "es31fSampleVariableTests.hpp"
25 #include "es31fMultisampleShaderRenderCase.hpp"
26 #include "tcuSurface.hpp"
27 #include "tcuTestLog.hpp"
28 #include "tcuRenderTarget.hpp"
29 #include "tcuTextureUtil.hpp"
30 #include "tcuVectorUtil.hpp"
31 #include "tcuFormatUtil.hpp"
32 #include "tcuStringTemplate.hpp"
33 #include "gluContextInfo.hpp"
34 #include "gluShaderProgram.hpp"
35 #include "gluRenderContext.hpp"
36 #include "glwFunctions.hpp"
37 #include "glwEnums.hpp"
38 #include "deStringUtil.hpp"
39
40 namespace deqp
41 {
42
43 using std::map;
44 using std::string;
45
46 namespace gles31
47 {
48 namespace Functional
49 {
50 namespace
51 {
52
53 class Verifier
54 {
55 public:
56         virtual bool    verify  (const tcu::RGBA& testColor, const tcu::IVec2& position) const = 0;
57         virtual void    logInfo (tcu::TestLog& log) const = 0;
58 };
59
60 class ColorVerifier : public Verifier
61 {
62 public:
63         ColorVerifier (const tcu::Vec3& _color, int _threshold = 8)
64                 : m_color               (tcu::Vec4(_color.x(), _color.y(), _color.z(), 1.0f))
65                 , m_threshold   (tcu::IVec3(_threshold))
66         {
67         }
68
69         ColorVerifier (const tcu::Vec3& _color, tcu::IVec3 _threshold)
70                 : m_color               (tcu::Vec4(_color.x(), _color.y(), _color.z(), 1.0f))
71                 , m_threshold   (_threshold)
72         {
73         }
74
75         bool verify (const tcu::RGBA& testColor, const tcu::IVec2& position) const
76         {
77                 DE_UNREF(position);
78                 return !tcu::boolAny(tcu::greaterThan(tcu::abs(m_color.toIVec().swizzle(0, 1, 2) - testColor.toIVec().swizzle(0, 1, 2)), tcu::IVec3(m_threshold)));
79         }
80
81         void logInfo (tcu::TestLog& log) const
82         {
83                 // full threshold? print * for clarity
84                 log     << tcu::TestLog::Message
85                         << "Expecting unicolored image, color = RGB("
86                         << ((m_threshold[0] >= 255) ? ("*") : (de::toString(m_color.getRed()))) << ", "
87                         << ((m_threshold[1] >= 255) ? ("*") : (de::toString(m_color.getGreen()))) << ", "
88                         << ((m_threshold[2] >= 255) ? ("*") : (de::toString(m_color.getBlue()))) << ")"
89                         << tcu::TestLog::EndMessage;
90         }
91
92         const tcu::RGBA         m_color;
93         const tcu::IVec3        m_threshold;
94 };
95
96 class FullBlueSomeGreenVerifier : public Verifier
97 {
98 public:
99         FullBlueSomeGreenVerifier (void)
100         {
101         }
102
103         bool verify (const tcu::RGBA& testColor, const tcu::IVec2& position) const
104         {
105                 DE_UNREF(position);
106
107                 // Values from 0.0 and 1.0 are accurate
108
109                 if (testColor.getRed() != 0)
110                         return false;
111                 if (testColor.getGreen() == 0)
112                         return false;
113                 if (testColor.getBlue() != 255)
114                         return false;
115                 return true;
116         }
117
118         void logInfo (tcu::TestLog& log) const
119         {
120                 log << tcu::TestLog::Message << "Expecting color c = (0.0, x, 1.0), x > 0.0" << tcu::TestLog::EndMessage;
121         }
122 };
123
124 class NoRedVerifier : public Verifier
125 {
126 public:
127         NoRedVerifier (void)
128         {
129         }
130
131         bool verify (const tcu::RGBA& testColor, const tcu::IVec2& position) const
132         {
133                 DE_UNREF(position);
134                 return testColor.getRed() == 0;
135         }
136
137         void logInfo (tcu::TestLog& log) const
138         {
139                 log << tcu::TestLog::Message << "Expecting zero-valued red channel." << tcu::TestLog::EndMessage;
140         }
141 };
142
143 class SampleAverageVerifier : public Verifier
144 {
145 public:
146                                 SampleAverageVerifier   (int _numSamples);
147
148         bool            verify                                  (const tcu::RGBA& testColor, const tcu::IVec2& position) const;
149         void            logInfo                                 (tcu::TestLog& log) const;
150
151         const int       m_numSamples;
152         const bool      m_isStatisticallySignificant;
153         float           m_distanceThreshold;
154 };
155
156 SampleAverageVerifier::SampleAverageVerifier (int _numSamples)
157         : m_numSamples                                  (_numSamples)
158         , m_isStatisticallySignificant  (_numSamples >= 4)
159         , m_distanceThreshold                   (0.0f)
160 {
161         // approximate Bates distribution as normal
162         const float variance                    = (1.0f / (12.0f * (float)m_numSamples));
163         const float standardDeviation   = deFloatSqrt(variance);
164
165         // 95% of means of sample positions are within 2 standard deviations if
166         // they were randomly assigned. Sample patterns are expected to be more
167         // uniform than a random pattern.
168         m_distanceThreshold = 2 * standardDeviation;
169 }
170
171 bool SampleAverageVerifier::verify (const tcu::RGBA& testColor, const tcu::IVec2& position) const
172 {
173         DE_UNREF(position);
174         DE_ASSERT(m_isStatisticallySignificant);
175
176         const tcu::Vec2 avgPosition                             ((float)testColor.getGreen() / 255.0f, (float)testColor.getBlue() / 255.0f);
177         const tcu::Vec2 distanceFromCenter              = tcu::abs(avgPosition - tcu::Vec2(0.5f, 0.5f));
178
179         return distanceFromCenter.x() < m_distanceThreshold && distanceFromCenter.y() < m_distanceThreshold;
180 }
181
182 void SampleAverageVerifier::logInfo (tcu::TestLog& log) const
183 {
184         log << tcu::TestLog::Message << "Expecting average sample position to be near the pixel center. Maximum per-axis distance " << m_distanceThreshold << tcu::TestLog::EndMessage;
185 }
186
187 class PartialDiscardVerifier : public Verifier
188 {
189 public:
190         PartialDiscardVerifier (void)
191         {
192         }
193
194         bool verify (const tcu::RGBA& testColor, const tcu::IVec2& position) const
195         {
196                 DE_UNREF(position);
197
198                 return (testColor.getGreen() != 0) && (testColor.getGreen() != 255);
199         }
200
201         void logInfo (tcu::TestLog& log) const
202         {
203                 log << tcu::TestLog::Message << "Expecting color non-zero and non-saturated green channel" << tcu::TestLog::EndMessage;
204         }
205 };
206
207 static bool verifyImageWithVerifier (const tcu::Surface& resultImage, tcu::TestLog& log, const Verifier& verifier, bool logOnSuccess = true)
208 {
209         tcu::Surface    errorMask       (resultImage.getWidth(), resultImage.getHeight());
210         bool                    error           = false;
211
212         tcu::clear(errorMask.getAccess(), tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f));
213
214         if (logOnSuccess)
215         {
216                 log << tcu::TestLog::Message << "Verifying image." << tcu::TestLog::EndMessage;
217                 verifier.logInfo(log);
218         }
219
220         for (int y = 0; y < resultImage.getHeight(); ++y)
221         for (int x = 0; x < resultImage.getWidth(); ++x)
222         {
223                 const tcu::RGBA color           = resultImage.getPixel(x, y);
224
225                 // verify color value is valid for this pixel position
226                 if (!verifier.verify(color, tcu::IVec2(x,y)))
227                 {
228                         error = true;
229                         errorMask.setPixel(x, y, tcu::RGBA::red());
230                 }
231         }
232
233         if (error)
234         {
235                 // describe the verification logic if we haven't already
236                 if (!logOnSuccess)
237                         verifier.logInfo(log);
238
239                 log     << tcu::TestLog::Message << "Image verification failed." << tcu::TestLog::EndMessage
240                         << tcu::TestLog::ImageSet("Verification", "Image Verification")
241                         << tcu::TestLog::Image("Result", "Result image", resultImage.getAccess())
242                         << tcu::TestLog::Image("ErrorMask", "Error Mask", errorMask.getAccess())
243                         << tcu::TestLog::EndImageSet;
244         }
245         else if (logOnSuccess)
246         {
247                 log << tcu::TestLog::Message << "Image verification passed." << tcu::TestLog::EndMessage
248                         << tcu::TestLog::ImageSet("Verification", "Image Verification")
249                         << tcu::TestLog::Image("Result", "Result image", resultImage.getAccess())
250                         << tcu::TestLog::EndImageSet;
251         }
252
253         return !error;
254 }
255
256 class MultisampleRenderCase : public MultisampleShaderRenderUtil::MultisampleRenderCase
257 {
258 public:
259                                                 MultisampleRenderCase           (Context& context, const char* name, const char* desc, int numSamples, RenderTarget target, int renderSize, int flags = 0);
260         virtual                         ~MultisampleRenderCase          (void);
261
262         virtual void            init                                            (void);
263
264 };
265
266 MultisampleRenderCase::MultisampleRenderCase (Context& context, const char* name, const char* desc, int numSamples, RenderTarget target, int renderSize, int flags)
267         : MultisampleShaderRenderUtil::MultisampleRenderCase(context, name, desc, numSamples, target, renderSize, flags)
268 {
269         DE_ASSERT(target < TARGET_LAST);
270 }
271
272 MultisampleRenderCase::~MultisampleRenderCase (void)
273 {
274         MultisampleRenderCase::deinit();
275 }
276
277 void MultisampleRenderCase::init (void)
278 {
279         const bool supportsES32orGL45 =
280                 glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)) ||
281                 glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5));
282         if (!supportsES32orGL45 && !m_context.getContextInfo().isExtensionSupported("GL_OES_sample_variables"))
283                 TCU_THROW(NotSupportedError, "Test requires GL_OES_sample_variables extension or a context version 3.2 or higher.");
284
285         MultisampleShaderRenderUtil::MultisampleRenderCase::init();
286 }
287
288 class NumSamplesCase : public MultisampleRenderCase
289 {
290 public:
291                                         NumSamplesCase                          (Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target);
292                                         ~NumSamplesCase                         (void);
293
294         std::string             genFragmentSource                       (int numTargetSamples) const;
295         bool                    verifyImage                                     (const tcu::Surface& resultImage);
296
297 private:
298         enum
299         {
300                 RENDER_SIZE = 64
301         };
302 };
303
304 NumSamplesCase::NumSamplesCase (Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target)
305         : MultisampleRenderCase(context, name, desc, sampleCount, target, RENDER_SIZE)
306 {
307 }
308
309 NumSamplesCase::~NumSamplesCase (void)
310 {
311 }
312
313 std::string NumSamplesCase::genFragmentSource (int numTargetSamples) const
314 {
315         std::ostringstream      buf;
316         const bool supportsES32orGL45 =
317                 glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)) ||
318                 glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5));
319         map<string, string>     args;
320         args["GLSL_VERSION_DECL"]       = (supportsES32orGL45) ? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES) : getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES);
321         args["GLSL_EXTENSION"]          = (supportsES32orGL45) ? "" : "#extension GL_OES_sample_variables : require";
322
323         buf <<  "${GLSL_VERSION_DECL}\n"
324                         "${GLSL_EXTENSION}\n"
325                         "layout(location = 0) out mediump vec4 fragColor;\n"
326                         "void main (void)\n"
327                         "{\n"
328                         "       fragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
329                         "       if (gl_NumSamples == " << numTargetSamples << ")\n"
330                         "               fragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
331                         "}\n";
332
333         return tcu::StringTemplate(buf.str()).specialize(args);
334 }
335
336 bool NumSamplesCase::verifyImage (const tcu::Surface& resultImage)
337 {
338         return verifyImageWithVerifier(resultImage, m_testCtx.getLog(), NoRedVerifier());
339 }
340
341 class MaxSamplesCase : public MultisampleRenderCase
342 {
343 public:
344                                         MaxSamplesCase                          (Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target);
345                                         ~MaxSamplesCase                         (void);
346
347 private:
348         void                    preDraw                                         (void);
349         std::string             genFragmentSource                       (int numTargetSamples) const;
350         bool                    verifyImage                                     (const tcu::Surface& resultImage);
351
352         enum
353         {
354                 RENDER_SIZE = 64
355         };
356 };
357
358 MaxSamplesCase::MaxSamplesCase (Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target)
359         : MultisampleRenderCase(context, name, desc, sampleCount, target, RENDER_SIZE)
360 {
361 }
362
363 MaxSamplesCase::~MaxSamplesCase (void)
364 {
365 }
366
367 void MaxSamplesCase::preDraw (void)
368 {
369         const glw::Functions&   gl                      = m_context.getRenderContext().getFunctions();
370         deInt32                                 maxSamples      = -1;
371
372         // query samples
373         {
374                 gl.getIntegerv(GL_MAX_SAMPLES, &maxSamples);
375                 GLU_EXPECT_NO_ERROR(gl.getError(), "query GL_MAX_SAMPLES");
376
377                 m_testCtx.getLog() << tcu::TestLog::Message << "GL_MAX_SAMPLES = " << maxSamples << tcu::TestLog::EndMessage;
378         }
379
380         // set samples
381         {
382                 const int maxSampleLoc = gl.getUniformLocation(m_program->getProgram(), "u_maxSamples");
383                 if (maxSampleLoc == -1)
384                         throw tcu::TestError("Location of u_maxSamples was -1");
385
386                 gl.uniform1i(maxSampleLoc, maxSamples);
387                 GLU_EXPECT_NO_ERROR(gl.getError(), "set u_maxSamples uniform");
388
389                 m_testCtx.getLog() << tcu::TestLog::Message << "Set u_maxSamples = " << maxSamples << tcu::TestLog::EndMessage;
390         }
391 }
392
393 std::string MaxSamplesCase::genFragmentSource (int numTargetSamples) const
394 {
395         DE_UNREF(numTargetSamples);
396
397         std::ostringstream      buf;
398         const bool supportsES32orGL45 =
399                 glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)) ||
400                 glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5));
401         map<string, string>     args;
402         args["GLSL_VERSION_DECL"]       = (supportsES32orGL45) ? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES) : getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES);
403         args["GLSL_EXTENSION"]          = (supportsES32orGL45) ? "" : "#extension GL_OES_sample_variables : require";
404
405         buf <<  "${GLSL_VERSION_DECL}\n"
406                         "${GLSL_EXTENSION}\n"
407                         "layout(location = 0) out mediump vec4 fragColor;\n"
408                         "uniform mediump int u_maxSamples;\n"
409                         "void main (void)\n"
410                         "{\n"
411                         "       fragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
412                         "       if (gl_MaxSamples == u_maxSamples)\n"
413                         "               fragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
414                         "}\n";
415
416         return tcu::StringTemplate(buf.str()).specialize(args);
417 }
418
419 bool MaxSamplesCase::verifyImage (const tcu::Surface& resultImage)
420 {
421         return verifyImageWithVerifier(resultImage, m_testCtx.getLog(), NoRedVerifier());
422 }
423
424 class SampleIDCase : public MultisampleRenderCase
425 {
426 public:
427                                         SampleIDCase                            (Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target);
428                                         ~SampleIDCase                           (void);
429
430         void                    init                                            (void);
431
432 private:
433         std::string             genFragmentSource                       (int numTargetSamples) const;
434         bool                    verifyImage                                     (const tcu::Surface& resultImage);
435         bool                    verifySampleBuffers                     (const std::vector<tcu::Surface>& resultBuffers);
436
437         enum
438         {
439                 RENDER_SIZE = 64
440         };
441         enum VerificationMode
442         {
443                 VERIFY_USING_SAMPLES,
444                 VERIFY_USING_SELECTION,
445         };
446
447         const VerificationMode  m_vericationMode;
448 };
449
450 SampleIDCase::SampleIDCase (Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target)
451         : MultisampleRenderCase (context, name, desc, sampleCount, target, RENDER_SIZE, MultisampleShaderRenderUtil::MultisampleRenderCase::FLAG_VERIFY_MSAA_TEXTURE_SAMPLE_BUFFERS)
452         , m_vericationMode              ((target == TARGET_TEXTURE) ? (VERIFY_USING_SAMPLES) : (VERIFY_USING_SELECTION))
453 {
454 }
455
456 SampleIDCase::~SampleIDCase (void)
457 {
458 }
459
460 void SampleIDCase::init (void)
461 {
462         // log the test method and expectations
463         if (m_vericationMode == VERIFY_USING_SAMPLES)
464                 m_testCtx.getLog()
465                         << tcu::TestLog::Message
466                         << "Writing gl_SampleID to the green channel of the texture and verifying texture values, expecting:\n"
467                         << "    1) 0 with non-multisample targets.\n"
468                         << "    2) value N at sample index N of a multisample texture\n"
469                         << tcu::TestLog::EndMessage;
470         else if (m_vericationMode == VERIFY_USING_SELECTION)
471                 m_testCtx.getLog()
472                         << tcu::TestLog::Message
473                         << "Selecting a single sample id for each pixel and writing color only if gl_SampleID == selected.\n"
474                         << "Expecting all output pixels to be partially (multisample) or fully (singlesample) colored.\n"
475                         << tcu::TestLog::EndMessage;
476         else
477                 DE_ASSERT(false);
478
479         MultisampleRenderCase::init();
480 }
481
482 std::string SampleIDCase::genFragmentSource (int numTargetSamples) const
483 {
484         DE_ASSERT(numTargetSamples != 0);
485
486         std::ostringstream buf;
487         const bool supportsES32orGL45 =
488                 glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)) ||
489                 glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5));
490         map<string, string>     args;
491         args["GLSL_VERSION_DECL"]       = (supportsES32orGL45) ? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES) : getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES);
492         args["GLSL_EXTENSION"]          = (supportsES32orGL45) ? "" : "#extension GL_OES_sample_variables : require";
493
494         if (m_vericationMode == VERIFY_USING_SAMPLES)
495         {
496                 // encode the id to the output, and then verify it during sampling
497                 buf <<  "${GLSL_VERSION_DECL}\n"
498                                 "${GLSL_EXTENSION}\n"
499                                 "layout(location = 0) out mediump vec4 fragColor;\n"
500                                 "void main (void)\n"
501                                 "{\n"
502                                 "       highp float normalizedSample = float(gl_SampleID) / float(" << numTargetSamples << ");\n"
503                                 "       fragColor = vec4(0.0, normalizedSample, 1.0, 1.0);\n"
504                                 "}\n";
505         }
506         else if (m_vericationMode == VERIFY_USING_SELECTION)
507         {
508                 if (numTargetSamples == 1)
509                 {
510                         // single sample, just verify value is 0
511                         buf <<  "${GLSL_VERSION_DECL}\n"
512                                         "${GLSL_EXTENSION}\n"
513                                         "layout(location = 0) out mediump vec4 fragColor;\n"
514                                         "void main (void)\n"
515                                         "{\n"
516                                         "       if (gl_SampleID == 0)\n"
517                                         "               fragColor = vec4(0.0, 1.0, 1.0, 1.0);\n"
518                                         "       else\n"
519                                         "               fragColor = vec4(0.0, 0.0, 1.0, 1.0);\n"
520                                         "}\n";
521                 }
522                 else
523                 {
524                         // select only one sample per PIXEL
525                         buf <<  "${GLSL_VERSION_DECL}\n"
526                                         "${GLSL_EXTENSION}\n"
527                                         "in highp vec4 v_position;\n"
528                                         "layout(location = 0) out mediump vec4 fragColor;\n"
529                                         "void main (void)\n"
530                                         "{\n"
531                                         "       highp vec2 relPosition = (v_position.xy + vec2(1.0, 1.0)) / 2.0;\n"
532                                         "       highp ivec2 pixelPos = ivec2(floor(relPosition * " << (int)RENDER_SIZE << ".0));\n"
533                                         "       highp int selectedID = abs(pixelPos.x + 17 * pixelPos.y) % " << numTargetSamples << ";\n"
534                                         "\n"
535                                         "       if (gl_SampleID == selectedID)\n"
536                                         "               fragColor = vec4(0.0, 1.0, 1.0, 1.0);\n"
537                                         "       else\n"
538                                         "               fragColor = vec4(0.0, 0.0, 1.0, 1.0);\n"
539                                         "}\n";
540                 }
541         }
542         else
543                 DE_ASSERT(false);
544
545         return tcu::StringTemplate(buf.str()).specialize(args);
546 }
547
548 bool SampleIDCase::verifyImage (const tcu::Surface& resultImage)
549 {
550         if (m_vericationMode == VERIFY_USING_SAMPLES)
551         {
552                 // never happens
553                 DE_ASSERT(false);
554                 return false;
555         }
556         else if (m_vericationMode == VERIFY_USING_SELECTION)
557         {
558                 // should result in full blue and some green everywhere
559                 return verifyImageWithVerifier(resultImage, m_testCtx.getLog(), FullBlueSomeGreenVerifier());
560         }
561         else
562         {
563                 DE_ASSERT(false);
564                 return false;
565         }
566 }
567
568 bool SampleIDCase::verifySampleBuffers (const std::vector<tcu::Surface>& resultBuffers)
569 {
570         // Verify all sample buffers
571         bool allOk = true;
572
573         // Log layers
574         {
575                 m_testCtx.getLog() << tcu::TestLog::ImageSet("SampleBuffers", "Image sample buffers");
576                 for (int sampleNdx = 0; sampleNdx < (int)resultBuffers.size(); ++sampleNdx)
577                         m_testCtx.getLog() << tcu::TestLog::Image("Buffer" + de::toString(sampleNdx), "Sample " + de::toString(sampleNdx), resultBuffers[sampleNdx].getAccess());
578                 m_testCtx.getLog() << tcu::TestLog::EndImageSet;
579         }
580
581         m_testCtx.getLog() << tcu::TestLog::Message << "Verifying sample buffers" << tcu::TestLog::EndMessage;
582         for (int sampleNdx = 0; sampleNdx < (int)resultBuffers.size(); ++sampleNdx)
583         {
584                 // sample id should be sample index
585                 const int threshold = 255 / 4 / m_numTargetSamples + 1;
586                 const float sampleIdColor = (float)sampleNdx / (float)m_numTargetSamples;
587
588                 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying sample " << (sampleNdx+1) << "/" << (int)resultBuffers.size() << tcu::TestLog::EndMessage;
589                 allOk &= verifyImageWithVerifier(resultBuffers[sampleNdx], m_testCtx.getLog(), ColorVerifier(tcu::Vec3(0.0f, sampleIdColor, 1.0f), tcu::IVec3(1, threshold, 1)), false);
590         }
591
592         if (!allOk)
593                 m_testCtx.getLog() << tcu::TestLog::Message << "Sample buffer verification failed" << tcu::TestLog::EndMessage;
594
595         return allOk;
596 }
597
598 class SamplePosDistributionCase : public MultisampleRenderCase
599 {
600 public:
601                                         SamplePosDistributionCase       (Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target);
602                                         ~SamplePosDistributionCase      (void);
603
604         void                    init                                            (void);
605 private:
606         enum
607         {
608                 RENDER_SIZE = 64
609         };
610
611         std::string             genFragmentSource                       (int numTargetSamples) const;
612         bool                    verifyImage                                     (const tcu::Surface& resultImage);
613         bool                    verifySampleBuffers                     (const std::vector<tcu::Surface>& resultBuffers);
614 };
615
616 SamplePosDistributionCase::SamplePosDistributionCase (Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target)
617         : MultisampleRenderCase(context, name, desc, sampleCount, target, RENDER_SIZE, MultisampleShaderRenderUtil::MultisampleRenderCase::FLAG_VERIFY_MSAA_TEXTURE_SAMPLE_BUFFERS)
618 {
619 }
620
621 SamplePosDistributionCase::~SamplePosDistributionCase (void)
622 {
623 }
624
625 void SamplePosDistributionCase::init (void)
626 {
627         // log the test method and expectations
628         if (m_renderTarget == TARGET_TEXTURE)
629         {
630                 m_testCtx.getLog()
631                         << tcu::TestLog::Message
632                         << "Verifying gl_SamplePosition value:\n"
633                         << "    1) With non-multisample targets: Expect the center of the pixel.\n"
634                         << "    2) With multisample targets:\n"
635                         << "            a) Expect legal sample position.\n"
636                         << "            b) Sample position is unique within the set of all sample positions of a pixel.\n"
637                         << "            c) Sample position distribution is uniform or almost uniform.\n"
638                         << tcu::TestLog::EndMessage;
639         }
640         else
641         {
642                 m_testCtx.getLog()
643                         << tcu::TestLog::Message
644                         << "Verifying gl_SamplePosition value:\n"
645                         << "    1) With non-multisample targets: Expect the center of the pixel.\n"
646                         << "    2) With multisample targets:\n"
647                         << "            a) Expect legal sample position.\n"
648                         << "            b) Sample position distribution is uniform or almost uniform.\n"
649                         << tcu::TestLog::EndMessage;
650         }
651
652         MultisampleRenderCase::init();
653 }
654
655 std::string SamplePosDistributionCase::genFragmentSource (int numTargetSamples) const
656 {
657         DE_ASSERT(numTargetSamples != 0);
658         DE_UNREF(numTargetSamples);
659
660         const bool                      multisampleTarget       = (m_numRequestedSamples > 0) || (m_renderTarget == TARGET_DEFAULT && m_context.getRenderTarget().getNumSamples() > 1);
661         std::ostringstream      buf;
662         const bool supportsES32orGL45 =
663                 glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)) ||
664                 glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5));
665         map<string, string>     args;
666         args["GLSL_VERSION_DECL"]       = (supportsES32orGL45) ? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES) : getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES);
667         args["GLSL_EXTENSION"]          = (supportsES32orGL45) ? "\n" : "#extension GL_OES_sample_variables : require\n";
668
669         if (multisampleTarget)
670         {
671                 // encode the position to the output, use red channel as error channel
672                 buf <<  "${GLSL_VERSION_DECL}\n"
673                                 "${GLSL_EXTENSION}\n"
674                                 "layout(location = 0) out mediump vec4 fragColor;\n"
675                                 "void main (void)\n"
676                                 "{\n"
677                                 "       if (gl_SamplePosition.x < 0.0 || gl_SamplePosition.x > 1.0 || gl_SamplePosition.y < 0.0 || gl_SamplePosition.y > 1.0)\n"
678                                 "               fragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
679                                 "       else\n"
680                                 "               fragColor = vec4(0.0, gl_SamplePosition.x, gl_SamplePosition.y, 1.0);\n"
681                                 "}\n";
682         }
683         else
684         {
685                 // verify value is ok
686                 buf <<  "${GLSL_VERSION_DECL}\n"
687                                 "${GLSL_EXTENSION}\n"
688                                 "layout(location = 0) out mediump vec4 fragColor;\n"
689                                 "void main (void)\n"
690                                 "{\n"
691                                 "       if (gl_SamplePosition.x != 0.5 || gl_SamplePosition.y != 0.5)\n"
692                                 "               fragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
693                                 "       else\n"
694                                 "               fragColor = vec4(0.0, gl_SamplePosition.x, gl_SamplePosition.y, 1.0);\n"
695                                 "}\n";
696         }
697
698         return tcu::StringTemplate(buf.str()).specialize(args);
699 }
700
701 bool SamplePosDistributionCase::verifyImage (const tcu::Surface& resultImage)
702 {
703         const int                               sampleCount     = (m_renderTarget == TARGET_DEFAULT) ? (m_context.getRenderTarget().getNumSamples()) : (m_numRequestedSamples);
704         SampleAverageVerifier   verifier        (sampleCount);
705
706         // check there is nothing in the error channel
707         if (!verifyImageWithVerifier(resultImage, m_testCtx.getLog(), NoRedVerifier()))
708                 return false;
709
710         // position average should be around 0.5, 0.5
711         if (verifier.m_isStatisticallySignificant && !verifyImageWithVerifier(resultImage, m_testCtx.getLog(), verifier))
712                 throw MultisampleShaderRenderUtil::QualityWarning("Bias detected, sample positions are not uniformly distributed within the pixel");
713
714         return true;
715 }
716
717 bool SamplePosDistributionCase::verifySampleBuffers (const std::vector<tcu::Surface>& resultBuffers)
718 {
719         const int       width                           = resultBuffers[0].getWidth();
720         const int       height                          = resultBuffers[0].getHeight();
721         bool            allOk                           = true;
722         bool            distibutionError        = false;
723
724         // Check sample range, uniqueness, and distribution, log layers
725         {
726                 m_testCtx.getLog() << tcu::TestLog::ImageSet("SampleBuffers", "Image sample buffers");
727                 for (int sampleNdx = 0; sampleNdx < (int)resultBuffers.size(); ++sampleNdx)
728                         m_testCtx.getLog() << tcu::TestLog::Image("Buffer" + de::toString(sampleNdx), "Sample " + de::toString(sampleNdx), resultBuffers[sampleNdx].getAccess());
729                 m_testCtx.getLog() << tcu::TestLog::EndImageSet;
730         }
731
732         // verify range
733         {
734                 bool rangeOk = true;
735
736                 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying sample position range" << tcu::TestLog::EndMessage;
737                 for (int sampleNdx = 0; sampleNdx < (int)resultBuffers.size(); ++sampleNdx)
738                 {
739                         // shader does the check, just check the shader error output (red)
740                         m_testCtx.getLog() << tcu::TestLog::Message << "Verifying sample " << (sampleNdx+1) << "/" << (int)resultBuffers.size() << tcu::TestLog::EndMessage;
741                         rangeOk &= verifyImageWithVerifier(resultBuffers[sampleNdx], m_testCtx.getLog(), NoRedVerifier(), false);
742                 }
743
744                 if (!rangeOk)
745                 {
746                         allOk = false;
747
748                         m_testCtx.getLog() << tcu::TestLog::Message << "Sample position verification failed." << tcu::TestLog::EndMessage;
749                 }
750         }
751
752         // Verify uniqueness
753         {
754                 bool                                    uniquenessOk    = true;
755                 tcu::Surface                    errorMask               (width, height);
756                 std::vector<tcu::Vec2>  samplePositions (resultBuffers.size());
757                 int                                             printCount              = 0;
758                 const int                               printFloodLimit = 5;
759
760                 tcu::clear(errorMask.getAccess(), tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f));
761
762                 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying sample position uniqueness." << tcu::TestLog::EndMessage;
763
764                 for (int y = 0; y < height; ++y)
765                 for (int x = 0; x < width; ++x)
766                 {
767                         bool samplePosNotUnique = false;
768
769                         for (int sampleNdx = 0; sampleNdx < (int)resultBuffers.size(); ++sampleNdx)
770                         {
771                                 const tcu::RGBA color = resultBuffers[sampleNdx].getPixel(x, y);
772                                 samplePositions[sampleNdx] = tcu::Vec2((float)color.getGreen() / 255.0f, (float)color.getBlue() / 255.0f);
773                         }
774
775                         // Just check there are no two samples with same positions
776                         for (int sampleNdxA = 0;            sampleNdxA < (int)resultBuffers.size() && (!samplePosNotUnique || printCount < printFloodLimit); ++sampleNdxA)
777                         for (int sampleNdxB = sampleNdxA+1; sampleNdxB < (int)resultBuffers.size() && (!samplePosNotUnique || printCount < printFloodLimit); ++sampleNdxB)
778                         {
779                                 if (samplePositions[sampleNdxA] == samplePositions[sampleNdxB])
780                                 {
781                                         if (++printCount <= printFloodLimit)
782                                         {
783                                                 m_testCtx.getLog()
784                                                         << tcu::TestLog::Message
785                                                         << "Pixel (" << x << ", " << y << "): Samples " << sampleNdxA << " and " << sampleNdxB << " have the same position."
786                                                         << tcu::TestLog::EndMessage;
787                                         }
788
789                                         samplePosNotUnique = true;
790                                         uniquenessOk = false;
791                                         errorMask.setPixel(x, y, tcu::RGBA::red());
792                                 }
793                         }
794                 }
795
796                 // end result
797                 if (!uniquenessOk)
798                 {
799                         if (printCount > printFloodLimit)
800                                 m_testCtx.getLog()
801                                         << tcu::TestLog::Message
802                                         << "...\n"
803                                         << "Omitted " << (printCount-printFloodLimit) << " error descriptions."
804                                         << tcu::TestLog::EndMessage;
805
806                         m_testCtx.getLog()
807                                 << tcu::TestLog::Message << "Image verification failed." << tcu::TestLog::EndMessage
808                                 << tcu::TestLog::ImageSet("Verification", "Image Verification")
809                                 << tcu::TestLog::Image("ErrorMask", "Error Mask", errorMask.getAccess())
810                                 << tcu::TestLog::EndImageSet;
811
812                         allOk = false;
813                 }
814         }
815
816         // check distribution
817         {
818                 const SampleAverageVerifier verifier            (m_numTargetSamples);
819                 tcu::Surface                            errorMask               (width, height);
820                 int                                                     printCount              = 0;
821                 const int                                       printFloodLimit = 5;
822
823                 tcu::clear(errorMask.getAccess(), tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f));
824
825                 // don't bother with small sample counts
826                 if (verifier.m_isStatisticallySignificant)
827                 {
828                         m_testCtx.getLog() << tcu::TestLog::Message << "Verifying sample position distribution is (nearly) unbiased." << tcu::TestLog::EndMessage;
829                         verifier.logInfo(m_testCtx.getLog());
830
831                         for (int y = 0; y < height; ++y)
832                         for (int x = 0; x < width; ++x)
833                         {
834                                 tcu::IVec3 colorSum(0, 0, 0);
835
836                                 // color average
837
838                                 for (int sampleNdx = 0; sampleNdx < (int)resultBuffers.size(); ++sampleNdx)
839                                 {
840                                         const tcu::RGBA color = resultBuffers[sampleNdx].getPixel(x, y);
841                                         colorSum.x() += color.getRed();
842                                         colorSum.y() += color.getBlue();
843                                         colorSum.z() += color.getGreen();
844                                 }
845
846                                 colorSum.x() /= m_numTargetSamples;
847                                 colorSum.y() /= m_numTargetSamples;
848                                 colorSum.z() /= m_numTargetSamples;
849
850                                 // verify average sample position
851
852                                 if (!verifier.verify(tcu::RGBA(colorSum.x(), colorSum.y(), colorSum.z(), 0), tcu::IVec2(x, y)))
853                                 {
854                                         if (++printCount <= printFloodLimit)
855                                         {
856                                                 m_testCtx.getLog()
857                                                         << tcu::TestLog::Message
858                                                         << "Pixel (" << x << ", " << y << "): Sample distribution is biased."
859                                                         << tcu::TestLog::EndMessage;
860                                         }
861
862                                         distibutionError = true;
863                                         errorMask.setPixel(x, y, tcu::RGBA::red());
864                                 }
865                         }
866
867                         // sub-verification result
868                         if (distibutionError)
869                         {
870                                 if (printCount > printFloodLimit)
871                                         m_testCtx.getLog()
872                                                 << tcu::TestLog::Message
873                                                 << "...\n"
874                                                 << "Omitted " << (printCount-printFloodLimit) << " error descriptions."
875                                                 << tcu::TestLog::EndMessage;
876
877                                 m_testCtx.getLog()
878                                         << tcu::TestLog::Message << "Image verification failed." << tcu::TestLog::EndMessage
879                                         << tcu::TestLog::ImageSet("Verification", "Image Verification")
880                                         << tcu::TestLog::Image("ErrorMask", "Error Mask", errorMask.getAccess())
881                                         << tcu::TestLog::EndImageSet;
882                         }
883                 }
884         }
885
886         // results
887         if (!allOk)
888                 return false;
889         else if (distibutionError)
890                 throw MultisampleShaderRenderUtil::QualityWarning("Bias detected, sample positions are not uniformly distributed within the pixel");
891         else
892         {
893                 m_testCtx.getLog() << tcu::TestLog::Message << "Verification ok." << tcu::TestLog::EndMessage;
894                 return true;
895         }
896 }
897
898 class SamplePosCorrectnessCase : public MultisampleRenderCase
899 {
900 public:
901                                         SamplePosCorrectnessCase        (Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target);
902                                         ~SamplePosCorrectnessCase       (void);
903
904         void                    init                                            (void);
905 private:
906         enum
907         {
908                 RENDER_SIZE = 32
909         };
910
911         void                    preDraw                                         (void);
912         void                    postDraw                                        (void);
913
914         std::string             genVertexSource                         (int numTargetSamples) const;
915         std::string             genFragmentSource                       (int numTargetSamples) const;
916         bool                    verifyImage                                     (const tcu::Surface& resultImage);
917
918         bool                    m_useSampleQualifier;
919 };
920
921 SamplePosCorrectnessCase::SamplePosCorrectnessCase (Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target)
922         : MultisampleRenderCase (context, name, desc, sampleCount, target, RENDER_SIZE)
923         , m_useSampleQualifier  (false)
924 {
925 }
926
927 SamplePosCorrectnessCase::~SamplePosCorrectnessCase (void)
928 {
929 }
930
931 void SamplePosCorrectnessCase::init (void)
932 {
933         auto            ctxType                 = m_context.getRenderContext().getType();
934         const bool      isES32orGL45    = glu::contextSupports(ctxType, glu::ApiType::es(3, 2)) ||
935                                                                   glu::contextSupports(ctxType, glu::ApiType::core(4, 5));
936
937         // requirements: per-invocation interpolation required
938         if (!isES32orGL45 && !m_context.getContextInfo().isExtensionSupported("GL_OES_shader_multisample_interpolation") &&
939                 !m_context.getContextInfo().isExtensionSupported("GL_OES_sample_shading"))
940                 TCU_THROW(NotSupportedError, "Test requires GL_OES_shader_multisample_interpolation or GL_OES_sample_shading extension or a context version 3.2 or higher.");
941
942         // prefer to use the sample qualifier path
943         m_useSampleQualifier = m_context.getContextInfo().isExtensionSupported("GL_OES_shader_multisample_interpolation");
944
945         // log the test method and expectations
946         m_testCtx.getLog()
947                 << tcu::TestLog::Message
948                 << "Verifying gl_SamplePosition correctness:\n"
949                 << "    1) Varying values should be sampled at the sample position.\n"
950                 << "            => fract(screenSpacePosition) == gl_SamplePosition\n"
951                 << tcu::TestLog::EndMessage;
952
953         MultisampleRenderCase::init();
954 }
955
956 void SamplePosCorrectnessCase::preDraw (void)
957 {
958         if (!m_useSampleQualifier)
959         {
960                 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
961
962                 // use GL_OES_sample_shading to set per fragment sample invocation interpolation
963                 gl.enable(GL_SAMPLE_SHADING);
964                 gl.minSampleShading(1.0f);
965                 GLU_EXPECT_NO_ERROR(gl.getError(), "set ratio");
966
967                 m_testCtx.getLog() << tcu::TestLog::Message << "Enabling per-sample interpolation with GL_SAMPLE_SHADING." << tcu::TestLog::EndMessage;
968         }
969 }
970
971 void SamplePosCorrectnessCase::postDraw (void)
972 {
973         if (!m_useSampleQualifier)
974         {
975                 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
976
977                 gl.disable(GL_SAMPLE_SHADING);
978                 gl.minSampleShading(1.0f);
979                 GLU_EXPECT_NO_ERROR(gl.getError(), "set ratio");
980         }
981 }
982
983 std::string SamplePosCorrectnessCase::genVertexSource (int numTargetSamples) const
984 {
985         DE_UNREF(numTargetSamples);
986         const bool supportsES32orGL45 =
987                 glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)) ||
988                 glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5));
989
990         std::ostringstream      buf;
991         map<string, string>     args;
992         args["GLSL_VERSION_DECL"]       = supportsES32orGL45 ? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES) : getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES);
993         args["GLSL_EXTENSION"]          = supportsES32orGL45 ? "" : m_useSampleQualifier ? "#extension GL_OES_shader_multisample_interpolation : require" : "";
994
995         buf <<  "${GLSL_VERSION_DECL}\n"
996                         "${GLSL_EXTENSION}\n"
997                 <<      "in highp vec4 a_position;\n"
998                 <<      ((m_useSampleQualifier) ? ("sample ") : ("")) << "out highp vec4 v_position;\n"
999                         "void main (void)\n"
1000                         "{\n"
1001                         "       gl_Position = a_position;\n"
1002                         "       v_position = a_position;\n"
1003                         "}\n";
1004
1005         return tcu::StringTemplate(buf.str()).specialize(args);
1006 }
1007
1008 std::string SamplePosCorrectnessCase::genFragmentSource (int numTargetSamples) const
1009 {
1010         DE_UNREF(numTargetSamples);
1011
1012         std::ostringstream      buf;
1013         const bool supportsES32orGL45 =
1014                 glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)) ||
1015                 glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5));
1016         map<string, string>     args;
1017         args["GLSL_VERSION_DECL"]               = supportsES32orGL45 ? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES) : getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES);
1018         args["GLSL_SAMPLE_EXTENSION"]           = supportsES32orGL45 ? "" : "#extension GL_OES_sample_variables : require";
1019         args["GLSL_MULTISAMPLE_EXTENSION"]      = supportsES32orGL45 ? "" : m_useSampleQualifier ? "#extension GL_OES_shader_multisample_interpolation : require" : "";
1020
1021         // encode the position to the output, use red channel as error channel
1022         buf <<  "${GLSL_VERSION_DECL}\n"
1023                         "${GLSL_SAMPLE_EXTENSION}\n"
1024                         "${GLSL_MULTISAMPLE_EXTENSION}\n"
1025                 <<      ((m_useSampleQualifier) ? ("sample ") : ("")) << "in highp vec4 v_position;\n"
1026                         "layout(location = 0) out mediump vec4 fragColor;\n"
1027                         "void main (void)\n"
1028                         "{\n"
1029                         "       const highp float maxDistance = 0.15625; // 4 subpixel bits. Assume 3 accurate bits + 0.03125 for other errors\n" // 0.03125 = mediump epsilon when value = 32 (RENDER_SIZE)
1030                         "\n"
1031                         "       highp vec2 screenSpacePosition = (v_position.xy + vec2(1.0, 1.0)) / 2.0 * " << (int)RENDER_SIZE << ".0;\n"
1032                         "       highp ivec2 nearbyPixel = ivec2(floor(screenSpacePosition));\n"
1033                         "       bool allOk = false;\n"
1034                         "\n"
1035                         "       // sample at edge + inaccuaries may cause us to round to any neighboring pixel\n"
1036                         "       // check all neighbors for any match\n"
1037                         "       for (highp int dy = -1; dy <= 1; ++dy)\n"
1038                         "       for (highp int dx = -1; dx <= 1; ++dx)\n"
1039                         "       {\n"
1040                         "               highp ivec2 currentPixel = nearbyPixel + ivec2(dx, dy);\n"
1041                         "               highp vec2 candidateSamplingPos = vec2(currentPixel) + gl_SamplePosition.xy;\n"
1042                         "               highp vec2 positionDiff = abs(candidateSamplingPos - screenSpacePosition);\n"
1043                         "               if (positionDiff.x < maxDistance && positionDiff.y < maxDistance)\n"
1044                         "                       allOk = true;\n"
1045                         "       }\n"
1046                         "\n"
1047                         "       if (allOk)\n"
1048                         "               fragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
1049                         "       else\n"
1050                         "               fragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
1051                         "}\n";
1052
1053         return tcu::StringTemplate(buf.str()).specialize(args);
1054 }
1055
1056 bool SamplePosCorrectnessCase::verifyImage (const tcu::Surface& resultImage)
1057 {
1058         return verifyImageWithVerifier(resultImage, m_testCtx.getLog(), NoRedVerifier());
1059 }
1060
1061 class SampleMaskBaseCase : public MultisampleRenderCase
1062 {
1063 public:
1064         enum ShaderRunMode
1065         {
1066                 RUN_PER_PIXEL = 0,
1067                 RUN_PER_SAMPLE,
1068                 RUN_PER_TWO_SAMPLES,
1069
1070                 RUN_LAST
1071         };
1072
1073                                                 SampleMaskBaseCase                      (Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target, int renderSize, ShaderRunMode runMode, int flags = 0);
1074         virtual                         ~SampleMaskBaseCase                     (void);
1075
1076 protected:
1077         virtual void            init                                            (void);
1078         virtual void            preDraw                                         (void);
1079         virtual void            postDraw                                        (void);
1080         virtual bool            verifyImage                                     (const tcu::Surface& resultImage);
1081
1082         const ShaderRunMode     m_runMode;
1083 };
1084
1085 SampleMaskBaseCase::SampleMaskBaseCase (Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target, int renderSize, ShaderRunMode runMode, int flags)
1086         : MultisampleRenderCase (context, name, desc, sampleCount, target, renderSize, flags)
1087         , m_runMode                             (runMode)
1088 {
1089         DE_ASSERT(runMode < RUN_LAST);
1090 }
1091
1092 SampleMaskBaseCase::~SampleMaskBaseCase (void)
1093 {
1094 }
1095
1096 void SampleMaskBaseCase::init (void)
1097 {
1098         const bool supportsES32orGL45 = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)) ||
1099                 contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5));
1100         // required extra extension
1101         if (m_runMode == RUN_PER_TWO_SAMPLES && !supportsES32orGL45 && !m_context.getContextInfo().isExtensionSupported("GL_OES_sample_shading"))
1102                         TCU_THROW(NotSupportedError, "Test requires GL_OES_sample_shading extension or a context version 3.2 or higher.");
1103
1104         MultisampleRenderCase::init();
1105 }
1106
1107 void SampleMaskBaseCase::preDraw (void)
1108 {
1109         const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1110
1111         if (m_runMode == RUN_PER_TWO_SAMPLES)
1112         {
1113                 gl.enable(GL_SAMPLE_SHADING);
1114                 gl.minSampleShading(0.5f);
1115                 GLU_EXPECT_NO_ERROR(gl.getError(), "enable sample shading");
1116
1117                 m_testCtx.getLog() << tcu::TestLog::Message << "Enabled GL_SAMPLE_SHADING, value = 0.5" << tcu::TestLog::EndMessage;
1118         }
1119 }
1120
1121 void SampleMaskBaseCase::postDraw (void)
1122 {
1123         const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1124
1125         if (m_runMode == RUN_PER_TWO_SAMPLES)
1126         {
1127                 gl.disable(GL_SAMPLE_SHADING);
1128                 gl.minSampleShading(1.0f);
1129                 GLU_EXPECT_NO_ERROR(gl.getError(), "disable sample shading");
1130         }
1131 }
1132
1133 bool SampleMaskBaseCase::verifyImage (const tcu::Surface& resultImage)
1134 {
1135         // shader does the verification
1136         return verifyImageWithVerifier(resultImage, m_testCtx.getLog(), NoRedVerifier());
1137 }
1138
1139 class SampleMaskCase : public SampleMaskBaseCase
1140 {
1141 public:
1142                                                 SampleMaskCase                          (Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target);
1143                                                 ~SampleMaskCase                         (void);
1144
1145         void                            init                                            (void);
1146         void                            preDraw                                         (void);
1147         void                            postDraw                                        (void);
1148
1149 private:
1150         enum
1151         {
1152                 RENDER_SIZE = 64
1153         };
1154
1155         std::string                     genFragmentSource                       (int numTargetSamples) const;
1156 };
1157
1158 SampleMaskCase::SampleMaskCase (Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target)
1159         : SampleMaskBaseCase(context, name, desc, sampleCount, target, RENDER_SIZE, RUN_PER_PIXEL)
1160 {
1161 }
1162
1163 SampleMaskCase::~SampleMaskCase (void)
1164 {
1165 }
1166
1167 void SampleMaskCase::init (void)
1168 {
1169         // log the test method and expectations
1170         m_testCtx.getLog()
1171                 << tcu::TestLog::Message
1172                 << "Verifying gl_SampleMaskIn value with SAMPLE_MASK state. gl_SampleMaskIn does not contain any bits set that are have been killed by SAMPLE_MASK state. Expecting:\n"
1173                 << "    1) With multisample targets: gl_SampleMaskIn AND ~(SAMPLE_MASK) should be zero.\n"
1174                 << "    2) With non-multisample targets: SAMPLE_MASK state is only ANDed as a multisample operation. gl_SampleMaskIn should only have its last bit set regardless of SAMPLE_MASK state.\n"
1175                 << tcu::TestLog::EndMessage;
1176
1177         SampleMaskBaseCase::init();
1178 }
1179
1180 void SampleMaskCase::preDraw (void)
1181 {
1182         const glw::Functions&   gl                                      = m_context.getRenderContext().getFunctions();
1183         const bool                              multisampleTarget       = (m_numRequestedSamples > 0) || (m_renderTarget == TARGET_DEFAULT && m_context.getRenderTarget().getNumSamples() > 1);
1184         const deUint32                  fullMask                        = (deUint32)0xAAAAAAAAUL;
1185         const deUint32                  maskMask                        = (1U << m_numTargetSamples) - 1;
1186         const deUint32                  effectiveMask           =  fullMask & maskMask;
1187
1188         // set test mask
1189         gl.enable(GL_SAMPLE_MASK);
1190         gl.sampleMaski(0, effectiveMask);
1191         GLU_EXPECT_NO_ERROR(gl.getError(), "set mask");
1192
1193         m_testCtx.getLog() << tcu::TestLog::Message << "Setting sample mask " << tcu::Format::Hex<4>(effectiveMask) << tcu::TestLog::EndMessage;
1194
1195         // set multisample case uniforms
1196         if (multisampleTarget)
1197         {
1198                 const int maskLoc = gl.getUniformLocation(m_program->getProgram(), "u_sampleMask");
1199                 if (maskLoc == -1)
1200                         throw tcu::TestError("Location of u_mask was -1");
1201
1202                 gl.uniform1ui(maskLoc, effectiveMask);
1203                 GLU_EXPECT_NO_ERROR(gl.getError(), "set mask uniform");
1204         }
1205
1206         // base class logic
1207         SampleMaskBaseCase::preDraw();
1208 }
1209
1210 void SampleMaskCase::postDraw (void)
1211 {
1212         const glw::Functions&   gl                      = m_context.getRenderContext().getFunctions();
1213         const deUint32                  fullMask        = (1U << m_numTargetSamples) - 1;
1214
1215         gl.disable(GL_SAMPLE_MASK);
1216         gl.sampleMaski(0, fullMask);
1217         GLU_EXPECT_NO_ERROR(gl.getError(), "set mask");
1218
1219         // base class logic
1220         SampleMaskBaseCase::postDraw();
1221 }
1222
1223 std::string SampleMaskCase::genFragmentSource (int numTargetSamples) const
1224 {
1225         DE_ASSERT(numTargetSamples != 0);
1226
1227         const bool                      multisampleTarget       = (m_numRequestedSamples > 0) || (m_renderTarget == TARGET_DEFAULT && m_context.getRenderTarget().getNumSamples() > 1);
1228         std::ostringstream      buf;
1229         const bool                      supportsES32orGL45      = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)) ||
1230                                                         contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5));
1231         map<string, string>     args;
1232         args["GLSL_VERSION_DECL"]                               = supportsES32orGL45 ? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES) : getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES);
1233         args["GLSL_EXTENSION"]                                  = supportsES32orGL45 ? "" : "#extension GL_OES_sample_variables : require";
1234
1235         // test supports only one sample mask word
1236         if (numTargetSamples > 32)
1237                 TCU_THROW(NotSupportedError, "Sample count larger than 32 is not supported.");
1238
1239         if (multisampleTarget)
1240         {
1241                 buf <<  "${GLSL_VERSION_DECL}\n"
1242                                 "${GLSL_EXTENSION}\n"
1243                                 "layout(location = 0) out mediump vec4 fragColor;\n"
1244                                 "uniform highp uint u_sampleMask;\n"
1245                                 "void main (void)\n"
1246                                 "{\n"
1247                                 "       if ((uint(gl_SampleMaskIn[0]) & (~u_sampleMask)) != 0u)\n"
1248                                 "               fragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
1249                                 "       else\n"
1250                                 "               fragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
1251                                 "}\n";
1252         }
1253         else
1254         {
1255                 // non-multisample targets don't get multisample operations like ANDing with mask
1256
1257                 buf <<  "${GLSL_VERSION_DECL}\n"
1258                                 "${GLSL_EXTENSION}\n"
1259                                 "layout(location = 0) out mediump vec4 fragColor;\n"
1260                                 "uniform highp uint u_sampleMask;\n"
1261                                 "void main (void)\n"
1262                                 "{\n"
1263                                 "       if (gl_SampleMaskIn[0] != 1)\n"
1264                                 "               fragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
1265                                 "       else\n"
1266                                 "               fragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
1267                                 "}\n";
1268         }
1269
1270         return tcu::StringTemplate(buf.str()).specialize(args);
1271 }
1272
1273 class SampleMaskCountCase : public SampleMaskBaseCase
1274 {
1275 public:
1276                                                 SampleMaskCountCase                     (Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target, ShaderRunMode runMode);
1277                                                 ~SampleMaskCountCase            (void);
1278
1279         void                            init                                            (void);
1280         void                            preDraw                                         (void);
1281         void                            postDraw                                        (void);
1282
1283 private:
1284         enum
1285         {
1286                 RENDER_SIZE = 64
1287         };
1288
1289         std::string                     genFragmentSource                       (int numTargetSamples) const;
1290 };
1291
1292 SampleMaskCountCase::SampleMaskCountCase (Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target, ShaderRunMode runMode)
1293         : SampleMaskBaseCase(context, name, desc, sampleCount, target, RENDER_SIZE, runMode)
1294 {
1295         DE_ASSERT(runMode < RUN_LAST);
1296 }
1297
1298 SampleMaskCountCase::~SampleMaskCountCase (void)
1299 {
1300 }
1301
1302 void SampleMaskCountCase::init (void)
1303 {
1304         // log the test method and expectations
1305         if (m_runMode == RUN_PER_PIXEL)
1306                 m_testCtx.getLog()
1307                         << tcu::TestLog::Message
1308                         << "Verifying gl_SampleMaskIn.\n"
1309                         << "    Fragment shader may be invoked [1, numSamples] times.\n"
1310                         << "    => gl_SampleMaskIn should have the number of bits set in range [1, numSamples]\n"
1311                         << tcu::TestLog::EndMessage;
1312         else if (m_runMode == RUN_PER_SAMPLE)
1313                 m_testCtx.getLog()
1314                         << tcu::TestLog::Message
1315                         << "Verifying gl_SampleMaskIn.\n"
1316                         << "    Fragment will be invoked numSamples times.\n"
1317                         << "    => gl_SampleMaskIn should have only one bit set.\n"
1318                         << tcu::TestLog::EndMessage;
1319         else if (m_runMode == RUN_PER_TWO_SAMPLES)
1320                 m_testCtx.getLog()
1321                         << tcu::TestLog::Message
1322                         << "Verifying gl_SampleMaskIn.\n"
1323                         << "    Fragment shader may be invoked [ceil(numSamples/2), numSamples] times.\n"
1324                         << "    => gl_SampleMaskIn should have the number of bits set in range [1, numSamples - ceil(numSamples/2) + 1]:\n"
1325                         << tcu::TestLog::EndMessage;
1326         else
1327                 DE_ASSERT(false);
1328
1329         SampleMaskBaseCase::init();
1330 }
1331
1332 void SampleMaskCountCase::preDraw (void)
1333 {
1334         const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1335
1336         if (m_runMode == RUN_PER_PIXEL)
1337         {
1338                 const int maxLoc = gl.getUniformLocation(m_program->getProgram(), "u_maxBitCount");
1339                 const int minLoc = gl.getUniformLocation(m_program->getProgram(), "u_minBitCount");
1340                 const int minBitCount = 1;
1341                 const int maxBitCount = m_numTargetSamples;
1342
1343                 if (maxLoc == -1)
1344                         throw tcu::TestError("Location of u_maxBitCount was -1");
1345                 if (minLoc == -1)
1346                         throw tcu::TestError("Location of u_minBitCount was -1");
1347
1348                 gl.uniform1i(minLoc, minBitCount);
1349                 gl.uniform1i(maxLoc, maxBitCount);
1350                 GLU_EXPECT_NO_ERROR(gl.getError(), "set limits");
1351
1352                 m_testCtx.getLog() << tcu::TestLog::Message << "Setting minBitCount = " << minBitCount << ", maxBitCount = " << maxBitCount << tcu::TestLog::EndMessage;
1353         }
1354         else if (m_runMode == RUN_PER_TWO_SAMPLES)
1355         {
1356                 const int maxLoc = gl.getUniformLocation(m_program->getProgram(), "u_maxBitCount");
1357                 const int minLoc = gl.getUniformLocation(m_program->getProgram(), "u_minBitCount");
1358
1359                 // Worst case: all but one shader invocations get one sample, one shader invocation the rest of the samples
1360                 const int minInvocationCount = ((m_numTargetSamples + 1) / 2);
1361                 const int minBitCount = 1;
1362                 const int maxBitCount = m_numTargetSamples - ((minInvocationCount-1) * minBitCount);
1363
1364                 if (maxLoc == -1)
1365                         throw tcu::TestError("Location of u_maxBitCount was -1");
1366                 if (minLoc == -1)
1367                         throw tcu::TestError("Location of u_minBitCount was -1");
1368
1369                 gl.uniform1i(minLoc, minBitCount);
1370                 gl.uniform1i(maxLoc, maxBitCount);
1371                 GLU_EXPECT_NO_ERROR(gl.getError(), "set limits");
1372
1373                 m_testCtx.getLog() << tcu::TestLog::Message << "Setting minBitCount = " << minBitCount << ", maxBitCount = " << maxBitCount << tcu::TestLog::EndMessage;
1374         }
1375
1376         SampleMaskBaseCase::preDraw();
1377 }
1378
1379 void SampleMaskCountCase::postDraw (void)
1380 {
1381         SampleMaskBaseCase::postDraw();
1382 }
1383
1384 std::string SampleMaskCountCase::genFragmentSource (int numTargetSamples) const
1385 {
1386         DE_ASSERT(numTargetSamples != 0);
1387
1388         std::ostringstream      buf;
1389         const bool                      supportsES32orGL45      = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)) ||
1390                                                         contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5));
1391         map<string, string>     args;
1392         args["GLSL_VERSION_DECL"]       = supportsES32orGL45 ? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES) : getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES);
1393         args["GLSL_EXTENSION"]          = supportsES32orGL45 ? "" : "#extension GL_OES_sample_variables : require";
1394
1395         // test supports only one sample mask word
1396         if (numTargetSamples > 32)
1397                 TCU_THROW(NotSupportedError, "Sample count larger than 32 is not supported.");
1398
1399         // count the number of the bits in gl_SampleMask
1400
1401         buf <<  "${GLSL_VERSION_DECL}\n"
1402                         "${GLSL_EXTENSION}\n"
1403                         "layout(location = 0) out mediump vec4 fragColor;\n";
1404
1405         if (m_runMode != RUN_PER_SAMPLE)
1406                 buf <<  "uniform highp int u_minBitCount;\n"
1407                                 "uniform highp int u_maxBitCount;\n";
1408
1409         buf <<  "void main (void)\n"
1410                         "{\n"
1411                         "       mediump int maskBitCount = 0;\n"
1412                         "       for (int i = 0; i < 32; ++i)\n"
1413                         "               if (((gl_SampleMaskIn[0] >> i) & 0x01) == 0x01)\n"
1414                         "                       ++maskBitCount;\n"
1415                         "\n";
1416
1417         if (m_runMode == RUN_PER_SAMPLE)
1418         {
1419                 // check the validity here
1420                 buf <<  "       // force per-sample shading\n"
1421                                 "       highp float blue = float(gl_SampleID);\n"
1422                                 "\n"
1423                                 "       if (maskBitCount != 1)\n"
1424                                 "               fragColor = vec4(1.0, 0.0, blue, 1.0);\n"
1425                                 "       else\n"
1426                                 "               fragColor = vec4(0.0, 1.0, blue, 1.0);\n"
1427                                 "}\n";
1428         }
1429         else
1430         {
1431                 // check the validity here
1432                 buf <<  "       if (maskBitCount < u_minBitCount || maskBitCount > u_maxBitCount)\n"
1433                                 "               fragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
1434                                 "       else\n"
1435                                 "               fragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
1436                                 "}\n";
1437         }
1438
1439         return tcu::StringTemplate(buf.str()).specialize(args);
1440 }
1441
1442 class SampleMaskUniqueCase : public SampleMaskBaseCase
1443 {
1444 public:
1445                                                 SampleMaskUniqueCase            (Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target, ShaderRunMode runMode);
1446                                                 ~SampleMaskUniqueCase           (void);
1447
1448         void                            init                                            (void);
1449
1450 private:
1451         enum
1452         {
1453                 RENDER_SIZE = 64
1454         };
1455
1456         std::string                     genFragmentSource                       (int numTargetSamples) const;
1457         bool                            verifySampleBuffers                     (const std::vector<tcu::Surface>& resultBuffers);
1458 };
1459
1460 SampleMaskUniqueCase::SampleMaskUniqueCase (Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target, ShaderRunMode runMode)
1461         : SampleMaskBaseCase(context, name, desc, sampleCount, target, RENDER_SIZE, runMode, MultisampleShaderRenderUtil::MultisampleRenderCase::FLAG_VERIFY_MSAA_TEXTURE_SAMPLE_BUFFERS)
1462 {
1463         DE_ASSERT(runMode == RUN_PER_SAMPLE);
1464         DE_ASSERT(target == TARGET_TEXTURE);
1465 }
1466
1467 SampleMaskUniqueCase::~SampleMaskUniqueCase (void)
1468 {
1469 }
1470
1471 void SampleMaskUniqueCase::init (void)
1472 {
1473         // log the test method and expectations
1474         m_testCtx.getLog()
1475                 << tcu::TestLog::Message
1476                 << "Verifying gl_SampleMaskIn.\n"
1477                 << "    Fragment will be invoked numSamples times.\n"
1478                 << "    => gl_SampleMaskIn should have only one bit set\n"
1479                 << "    => and that bit index should be unique within other fragment shader invocations of that pixel.\n"
1480                 << "    Writing sampleMask bit index to green channel in render shader. Verifying uniqueness in sampler shader.\n"
1481                 << tcu::TestLog::EndMessage;
1482
1483         SampleMaskBaseCase::init();
1484 }
1485
1486 std::string SampleMaskUniqueCase::genFragmentSource (int numTargetSamples) const
1487 {
1488         DE_ASSERT(numTargetSamples != 0);
1489
1490         std::ostringstream      buf;
1491         const bool                      supportsES32orGL45      = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)) ||
1492                                                         contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5));
1493         map<string, string>     args;
1494         args["GLSL_VERSION_DECL"]       = supportsES32orGL45 ? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES) : getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES);
1495         args["GLSL_EXTENSION"]          = supportsES32orGL45 ? "" : "#extension GL_OES_sample_variables : require";
1496
1497         // test supports only one sample mask word
1498         if (numTargetSamples > 32)
1499                 TCU_THROW(NotSupportedError, "Sample count larger than 32 is not supported.");
1500
1501         // find our sampleID by searching for unique bit.
1502         buf <<  "${GLSL_VERSION_DECL}\n"
1503                         "${GLSL_EXTENSION}\n"
1504                         "layout(location = 0) out mediump vec4 fragColor;\n"
1505                         "void main (void)\n"
1506                         "{\n"
1507                         "       mediump int firstIndex = -1;\n"
1508                         "       for (int i = 0; i < 32; ++i)\n"
1509                         "       {\n"
1510                         "               if (((gl_SampleMaskIn[0] >> i) & 0x01) == 0x01)\n"
1511                         "               {\n"
1512                         "                       firstIndex = i;\n"
1513                         "                       break;\n"
1514                         "               }\n"
1515                         "       }\n"
1516                         "\n"
1517                         "       bool notUniqueError = false;\n"
1518                         "       for (int i = firstIndex + 1; i < 32; ++i)\n"
1519                         "               if (((gl_SampleMaskIn[0] >> i) & 0x01) == 0x01)\n"
1520                         "                       notUniqueError = true;\n"
1521                         "\n"
1522                         "       highp float encodedSampleId = float(firstIndex) / " << numTargetSamples <<".0;\n"
1523                         "\n"
1524                         "       // force per-sample shading\n"
1525                         "       highp float blue = float(gl_SampleID);\n"
1526                         "\n"
1527                         "       if (notUniqueError)\n"
1528                         "               fragColor = vec4(1.0, 0.0, blue, 1.0);\n"
1529                         "       else\n"
1530                         "               fragColor = vec4(0.0, encodedSampleId, blue, 1.0);\n"
1531                         "}\n";
1532
1533         return tcu::StringTemplate(buf.str()).specialize(args);
1534 }
1535
1536 bool SampleMaskUniqueCase::verifySampleBuffers (const std::vector<tcu::Surface>& resultBuffers)
1537 {
1538         const int       width                           = resultBuffers[0].getWidth();
1539         const int       height                          = resultBuffers[0].getHeight();
1540         bool            allOk                           = true;
1541
1542         // Log samples
1543         {
1544                 m_testCtx.getLog() << tcu::TestLog::ImageSet("SampleBuffers", "Image sample buffers");
1545                 for (int sampleNdx = 0; sampleNdx < (int)resultBuffers.size(); ++sampleNdx)
1546                         m_testCtx.getLog() << tcu::TestLog::Image("Buffer" + de::toString(sampleNdx), "Sample " + de::toString(sampleNdx), resultBuffers[sampleNdx].getAccess());
1547                 m_testCtx.getLog() << tcu::TestLog::EndImageSet;
1548         }
1549
1550         // check for earlier errors (in fragment shader)
1551         {
1552                 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying fragment shader invocation found only one set sample mask bit." << tcu::TestLog::EndMessage;
1553
1554                 for (int sampleNdx = 0; sampleNdx < (int)resultBuffers.size(); ++sampleNdx)
1555                 {
1556                         // shader does the check, just check the shader error output (red)
1557                         m_testCtx.getLog() << tcu::TestLog::Message << "Verifying sample " << (sampleNdx+1) << "/" << (int)resultBuffers.size() << tcu::TestLog::EndMessage;
1558                         allOk &= verifyImageWithVerifier(resultBuffers[sampleNdx], m_testCtx.getLog(), NoRedVerifier(), false);
1559                 }
1560
1561                 if (!allOk)
1562                 {
1563                         // can't check the uniqueness if the masks don't work at all
1564                         m_testCtx.getLog() << tcu::TestLog::Message << "Could not get mask information from the rendered image, cannot continue verification." << tcu::TestLog::EndMessage;
1565                         return false;
1566                 }
1567         }
1568
1569         // verify index / index ranges
1570
1571         if (m_numRequestedSamples == 0)
1572         {
1573                 // single sample target, expect index=0
1574
1575                 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying sample mask bit index is 0." << tcu::TestLog::EndMessage;
1576
1577                 // only check the mask index
1578                 allOk &= verifyImageWithVerifier(resultBuffers[0], m_testCtx.getLog(), ColorVerifier(tcu::Vec3(0.0f, 0.0f, 0.0f), tcu::IVec3(255, 8, 255)), false);
1579         }
1580         else
1581         {
1582                 // check uniqueness
1583
1584                 tcu::Surface            errorMask               (width, height);
1585                 bool                            uniquenessOk    = true;
1586                 int                                     printCount              = 0;
1587                 const int                       printFloodLimit = 5;
1588                 std::vector<int>        maskBitIndices  (resultBuffers.size());
1589
1590                 tcu::clear(errorMask.getAccess(), tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f));
1591
1592                 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying per-invocation sample mask bit is unique." << tcu::TestLog::EndMessage;
1593
1594                 for (int y = 0; y < height; ++y)
1595                 for (int x = 0; x < width; ++x)
1596                 {
1597                         bool maskNdxNotUnique = false;
1598
1599                         // decode index
1600                         for (int sampleNdx = 0; sampleNdx < (int)resultBuffers.size(); ++sampleNdx)
1601                         {
1602                                 const tcu::RGBA color = resultBuffers[sampleNdx].getPixel(x, y);
1603                                 maskBitIndices[sampleNdx] = (int)deFloatRound((float)color.getGreen() / 255.0f * (float)m_numTargetSamples);
1604                         }
1605
1606                         // just check there are no two invocations with the same bit index
1607                         for (int sampleNdxA = 0;            sampleNdxA < (int)resultBuffers.size() && (!maskNdxNotUnique || printCount < printFloodLimit); ++sampleNdxA)
1608                         for (int sampleNdxB = sampleNdxA+1; sampleNdxB < (int)resultBuffers.size() && (!maskNdxNotUnique || printCount < printFloodLimit); ++sampleNdxB)
1609                         {
1610                                 if (maskBitIndices[sampleNdxA] == maskBitIndices[sampleNdxB])
1611                                 {
1612                                         if (++printCount <= printFloodLimit)
1613                                         {
1614                                                 m_testCtx.getLog()
1615                                                         << tcu::TestLog::Message
1616                                                         << "Pixel (" << x << ", " << y << "): Samples " << sampleNdxA << " and " << sampleNdxB << " have the same sample mask. (Single bit at index " << maskBitIndices[sampleNdxA] << ")"
1617                                                         << tcu::TestLog::EndMessage;
1618                                         }
1619
1620                                         maskNdxNotUnique = true;
1621                                         uniquenessOk = false;
1622                                         errorMask.setPixel(x, y, tcu::RGBA::red());
1623                                 }
1624                         }
1625                 }
1626
1627                 // end result
1628                 if (!uniquenessOk)
1629                 {
1630                         if (printCount > printFloodLimit)
1631                                 m_testCtx.getLog()
1632                                         << tcu::TestLog::Message
1633                                         << "...\n"
1634                                         << "Omitted " << (printCount-printFloodLimit) << " error descriptions."
1635                                         << tcu::TestLog::EndMessage;
1636
1637                         m_testCtx.getLog()
1638                                 << tcu::TestLog::Message << "Image verification failed." << tcu::TestLog::EndMessage
1639                                 << tcu::TestLog::ImageSet("Verification", "Image Verification")
1640                                 << tcu::TestLog::Image("ErrorMask", "Error Mask", errorMask.getAccess())
1641                                 << tcu::TestLog::EndImageSet;
1642
1643                         allOk = false;
1644                 }
1645         }
1646
1647         return allOk;
1648 }
1649
1650 class SampleMaskUniqueSetCase : public SampleMaskBaseCase
1651 {
1652 public:
1653                                                                         SampleMaskUniqueSetCase         (Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target, ShaderRunMode runMode);
1654                                                                         ~SampleMaskUniqueSetCase        (void);
1655
1656         void                                                    init                                            (void);
1657         void                                                    deinit                                          (void);
1658
1659 private:
1660         enum
1661         {
1662                 RENDER_SIZE = 64
1663         };
1664
1665         void                                                    preDraw                                         (void);
1666         void                                                    postDraw                                        (void);
1667         std::string                                             genFragmentSource                       (int numTargetSamples) const;
1668         bool                                                    verifySampleBuffers                     (const std::vector<tcu::Surface>& resultBuffers);
1669         std::string                                             getIterationDescription         (int iteration) const;
1670
1671         void                                                    preTest                                         (void);
1672         void                                                    postTest                                        (void);
1673
1674         std::vector<tcu::Surface>               m_iterationSampleBuffers;
1675 };
1676
1677 SampleMaskUniqueSetCase::SampleMaskUniqueSetCase (Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target, ShaderRunMode runMode)
1678         : SampleMaskBaseCase(context, name, desc, sampleCount, target, RENDER_SIZE, runMode, MultisampleShaderRenderUtil::MultisampleRenderCase::FLAG_VERIFY_MSAA_TEXTURE_SAMPLE_BUFFERS)
1679 {
1680         DE_ASSERT(runMode == RUN_PER_TWO_SAMPLES);
1681         DE_ASSERT(target == TARGET_TEXTURE);
1682
1683         // high and low bits
1684         m_numIterations = 2;
1685 }
1686
1687 SampleMaskUniqueSetCase::~SampleMaskUniqueSetCase (void)
1688 {
1689 }
1690
1691 void SampleMaskUniqueSetCase::init (void)
1692 {
1693         // log the test method and expectations
1694         m_testCtx.getLog()
1695                 << tcu::TestLog::Message
1696                 << "Verifying gl_SampleMaskIn.\n"
1697                 << "    Fragment shader may be invoked [ceil(numSamples/2), numSamples] times.\n"
1698                 << "    => Each invocation should have unique bit set\n"
1699                 << "    Writing highest and lowest bit index to color channels in render shader. Verifying:\n"
1700                 << "            1) no other invocation contains these bits in sampler shader.\n"
1701                 << "            2) number of invocations is at least ceil(numSamples/2).\n"
1702                 << tcu::TestLog::EndMessage;
1703
1704         SampleMaskBaseCase::init();
1705 }
1706
1707 void SampleMaskUniqueSetCase::deinit (void)
1708 {
1709         m_iterationSampleBuffers.clear();
1710 }
1711
1712 void SampleMaskUniqueSetCase::preDraw (void)
1713 {
1714         const glw::Functions&   gl                      = m_context.getRenderContext().getFunctions();
1715         const int                               selectorLoc     = gl.getUniformLocation(m_program->getProgram(), "u_bitSelector");
1716
1717         gl.uniform1ui(selectorLoc, (deUint32)m_iteration);
1718         GLU_EXPECT_NO_ERROR(gl.getError(), "set u_bitSelector");
1719
1720         m_testCtx.getLog() << tcu::TestLog::Message << "Setting u_bitSelector = " << m_iteration << tcu::TestLog::EndMessage;
1721
1722         SampleMaskBaseCase::preDraw();
1723 }
1724
1725 void SampleMaskUniqueSetCase::postDraw (void)
1726 {
1727         SampleMaskBaseCase::postDraw();
1728 }
1729
1730 std::string SampleMaskUniqueSetCase::genFragmentSource (int numTargetSamples) const
1731 {
1732         DE_ASSERT(numTargetSamples != 0);
1733
1734         std::ostringstream      buf;
1735         const bool                      supportsES32orGL45      = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)) ||
1736                                                         contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5));
1737         map<string, string>     args;
1738         args["GLSL_VERSION_DECL"]       = supportsES32orGL45 ? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES) : getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES);
1739         args["GLSL_EXTENSION"]          = supportsES32orGL45 ? "" : "#extension GL_OES_sample_variables : require";
1740
1741         // test supports only one sample mask word
1742         if (numTargetSamples > 32)
1743                 TCU_THROW(NotSupportedError, "Sample count larger than 32 is not supported.");
1744
1745         // output min and max sample id
1746         buf <<  "${GLSL_VERSION_DECL}\n"
1747                         "${GLSL_EXTENSION}\n"
1748                         "uniform highp uint u_bitSelector;\n"
1749                         "layout(location = 0) out mediump vec4 fragColor;\n"
1750                         "void main (void)\n"
1751                         "{\n"
1752                         "       highp int selectedBits;\n"
1753                         "       if (u_bitSelector == 0u)\n"
1754                         "               selectedBits = (gl_SampleMaskIn[0] & 0xFFFF);\n"
1755                         "       else\n"
1756                         "               selectedBits = ((gl_SampleMaskIn[0] >> 16) & 0xFFFF);\n"
1757                         "\n"
1758                         "       // encode bits to color\n"
1759                         "       highp int redBits = selectedBits & 31;\n"
1760                         "       highp int greenBits = (selectedBits >> 5) & 63;\n"
1761                         "       highp int blueBits = (selectedBits >> 11) & 31;\n"
1762                         "\n"
1763                         "       fragColor = vec4(float(redBits) / float(31), float(greenBits) / float(63), float(blueBits) / float(31), 1.0);\n"
1764                         "}\n";
1765
1766         return tcu::StringTemplate(buf.str()).specialize(args);
1767 }
1768
1769 bool SampleMaskUniqueSetCase::verifySampleBuffers (const std::vector<tcu::Surface>& resultBuffers)
1770 {
1771         // we need results from all passes to do verification. Store results and verify later (at postTest).
1772
1773         DE_ASSERT(m_numTargetSamples == (int)resultBuffers.size());
1774         for (int ndx = 0; ndx < m_numTargetSamples; ++ndx)
1775                 m_iterationSampleBuffers[m_iteration * m_numTargetSamples + ndx] = resultBuffers[ndx];
1776
1777         return true;
1778 }
1779
1780 std::string SampleMaskUniqueSetCase::getIterationDescription (int iteration) const
1781 {
1782         if (iteration == 0)
1783                 return "Reading low bits";
1784         else if (iteration == 1)
1785                 return "Reading high bits";
1786         else
1787                 DE_ASSERT(false);
1788         return "";
1789 }
1790
1791 void SampleMaskUniqueSetCase::preTest (void)
1792 {
1793         m_iterationSampleBuffers.resize(m_numTargetSamples * 2);
1794 }
1795
1796 void SampleMaskUniqueSetCase::postTest (void)
1797 {
1798         DE_ASSERT((m_iterationSampleBuffers.size() % 2) == 0);
1799         DE_ASSERT((int)m_iterationSampleBuffers.size() / 2 == m_numTargetSamples);
1800
1801         const int                                               width                   = m_iterationSampleBuffers[0].getWidth();
1802         const int                                               height                  = m_iterationSampleBuffers[0].getHeight();
1803         bool                                                    allOk                   = true;
1804         std::vector<tcu::TextureLevel>  sampleCoverage  (m_numTargetSamples);
1805         const tcu::ScopedLogSection             section                 (m_testCtx.getLog(), "Verify", "Verify masks");
1806
1807         // convert color layers to 32 bit coverage masks, 2 passes per coverage
1808
1809         for (int sampleNdx = 0; sampleNdx < (int)sampleCoverage.size(); ++sampleNdx)
1810         {
1811                 sampleCoverage[sampleNdx].setStorage(tcu::TextureFormat(tcu::TextureFormat::R, tcu::TextureFormat::UNSIGNED_INT32), width, height);
1812
1813                 for (int y = 0; y < height; ++y)
1814                 for (int x = 0; x < width; ++x)
1815                 {
1816                         const tcu::RGBA         lowColor        = m_iterationSampleBuffers[sampleNdx].getPixel(x, y);
1817                         const tcu::RGBA         highColor       = m_iterationSampleBuffers[sampleNdx + (int)sampleCoverage.size()].getPixel(x, y);
1818                         deUint16                        low;
1819                         deUint16                        high;
1820
1821                         {
1822                                 int redBits             = (int)deFloatRound((float)lowColor.getRed() / 255.0f * 31);
1823                                 int greenBits   = (int)deFloatRound((float)lowColor.getGreen() / 255.0f * 63);
1824                                 int blueBits    = (int)deFloatRound((float)lowColor.getBlue() / 255.0f * 31);
1825
1826                                 low = (deUint16)(redBits | (greenBits << 5) | (blueBits << 11));
1827                         }
1828                         {
1829                                 int redBits             = (int)deFloatRound((float)highColor.getRed() / 255.0f * 31);
1830                                 int greenBits   = (int)deFloatRound((float)highColor.getGreen() / 255.0f * 63);
1831                                 int blueBits    = (int)deFloatRound((float)highColor.getBlue() / 255.0f * 31);
1832
1833                                 high = (deUint16)(redBits | (greenBits << 5) | (blueBits << 11));
1834                         }
1835
1836                         sampleCoverage[sampleNdx].getAccess().setPixel(tcu::UVec4((((deUint32)high) << 16) | low, 0, 0, 0), x, y);
1837                 }
1838         }
1839
1840         // verify masks
1841
1842         if (m_numRequestedSamples == 0)
1843         {
1844                 // single sample target, expect mask = 0x01
1845                 const int       printFloodLimit = 5;
1846                 int                     printCount              = 0;
1847
1848                 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying sample mask is 0x00000001." << tcu::TestLog::EndMessage;
1849
1850                 for (int y = 0; y < height; ++y)
1851                 for (int x = 0; x < width; ++x)
1852                 {
1853                         deUint32 mask = sampleCoverage[0].getAccess().getPixelUint(x, y).x();
1854                         if (mask != 0x01)
1855                         {
1856                                 allOk = false;
1857
1858                                 if (++printCount <= printFloodLimit)
1859                                 {
1860                                         m_testCtx.getLog()
1861                                                 << tcu::TestLog::Message
1862                                                 << "Pixel (" << x << ", " << y << "): Invalid mask, got " << tcu::Format::Hex<8>(mask) << ", expected " << tcu::Format::Hex<8>(0x01) << "\n"
1863                                                 << tcu::TestLog::EndMessage;
1864                                 }
1865                         }
1866                 }
1867
1868                 if (!allOk && printCount > printFloodLimit)
1869                 {
1870                         m_testCtx.getLog()
1871                                 << tcu::TestLog::Message
1872                                 << "...\n"
1873                                 << "Omitted " << (printCount-printFloodLimit) << " error descriptions."
1874                                 << tcu::TestLog::EndMessage;
1875                 }
1876         }
1877         else
1878         {
1879                 // check uniqueness
1880                 {
1881                         bool            uniquenessOk    = true;
1882                         int                     printCount              = 0;
1883                         const int       printFloodLimit = 5;
1884
1885                         m_testCtx.getLog() << tcu::TestLog::Message << "Verifying invocation sample masks do not share bits." << tcu::TestLog::EndMessage;
1886
1887                         for (int y = 0; y < height; ++y)
1888                         for (int x = 0; x < width; ++x)
1889                         {
1890                                 bool maskBitsNotUnique = false;
1891
1892                                 for (int sampleNdxA = 0;            sampleNdxA < m_numTargetSamples && (!maskBitsNotUnique || printCount < printFloodLimit); ++sampleNdxA)
1893                                 for (int sampleNdxB = sampleNdxA+1; sampleNdxB < m_numTargetSamples && (!maskBitsNotUnique || printCount < printFloodLimit); ++sampleNdxB)
1894                                 {
1895                                         const deUint32 maskA = sampleCoverage[sampleNdxA].getAccess().getPixelUint(x, y).x();
1896                                         const deUint32 maskB = sampleCoverage[sampleNdxB].getAccess().getPixelUint(x, y).x();
1897
1898                                         // equal mask == emitted by the same invocation
1899                                         if (maskA != maskB)
1900                                         {
1901                                                 // shares samples?
1902                                                 if (maskA & maskB)
1903                                                 {
1904                                                         maskBitsNotUnique = true;
1905                                                         uniquenessOk = false;
1906
1907                                                         if (++printCount <= printFloodLimit)
1908                                                         {
1909                                                                 m_testCtx.getLog()
1910                                                                         << tcu::TestLog::Message
1911                                                                         << "Pixel (" << x << ", " << y << "):\n"
1912                                                                         << "\tSamples " << sampleNdxA << " and " << sampleNdxB << " share mask bits\n"
1913                                                                         << "\tMask" << sampleNdxA << " = " << tcu::Format::Hex<8>(maskA) << "\n"
1914                                                                         << "\tMask" << sampleNdxB << " = " << tcu::Format::Hex<8>(maskB) << "\n"
1915                                                                         << tcu::TestLog::EndMessage;
1916                                                         }
1917                                                 }
1918                                         }
1919                                 }
1920                         }
1921
1922                         if (!uniquenessOk)
1923                         {
1924                                 allOk = false;
1925
1926                                 if (printCount > printFloodLimit)
1927                                         m_testCtx.getLog()
1928                                                 << tcu::TestLog::Message
1929                                                 << "...\n"
1930                                                 << "Omitted " << (printCount-printFloodLimit) << " error descriptions."
1931                                                 << tcu::TestLog::EndMessage;
1932                         }
1933                 }
1934
1935                 // check number of sample mask bit groups is valid ( == number of invocations )
1936                 {
1937                         const deUint32                  minNumInvocations       = (deUint32)de::max(1, (m_numTargetSamples+1)/2);
1938                         bool                                    countOk                         = true;
1939                         int                                             printCount                      = 0;
1940                         const int                               printFloodLimit         = 5;
1941
1942                         m_testCtx.getLog() << tcu::TestLog::Message << "Verifying cardinality of separate sample mask bit sets. Expecting equal to the number of invocations, (greater or equal to " << minNumInvocations << ")" << tcu::TestLog::EndMessage;
1943
1944                         for (int y = 0; y < height; ++y)
1945                         for (int x = 0; x < width; ++x)
1946                         {
1947                                 std::set<deUint32> masks;
1948
1949                                 for (int maskNdx = 0; maskNdx < m_numTargetSamples; ++maskNdx)
1950                                 {
1951                                         const deUint32 mask = sampleCoverage[maskNdx].getAccess().getPixelUint(x, y).x();
1952                                         masks.insert(mask);
1953                                 }
1954
1955                                 if ((int)masks.size() < (int)minNumInvocations)
1956                                 {
1957                                         if (++printCount <= printFloodLimit)
1958                                         {
1959                                                 m_testCtx.getLog()
1960                                                         << tcu::TestLog::Message
1961                                                         << "Pixel (" << x << ", " << y << "): Pixel invocations had only " << (int)masks.size() << " separate mask sets. Expected " << minNumInvocations << " or more. Found masks:"
1962                                                         << tcu::TestLog::EndMessage;
1963
1964                                                 for (std::set<deUint32>::iterator it = masks.begin(); it != masks.end(); ++it)
1965                                                         m_testCtx.getLog()
1966                                                         << tcu::TestLog::Message
1967                                                         << "\tMask: " << tcu::Format::Hex<8>(*it) << "\n"
1968                                                         << tcu::TestLog::EndMessage;
1969                                         }
1970
1971                                         countOk = false;
1972                                 }
1973                         }
1974
1975                         if (!countOk)
1976                         {
1977                                 allOk = false;
1978
1979                                 if (printCount > printFloodLimit)
1980                                         m_testCtx.getLog()
1981                                                 << tcu::TestLog::Message
1982                                                 << "...\n"
1983                                                 << "Omitted " << (printCount-printFloodLimit) << " error descriptions."
1984                                                 << tcu::TestLog::EndMessage;
1985                         }
1986                 }
1987         }
1988
1989         if (!allOk)
1990                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
1991 }
1992
1993 class SampleMaskWriteCase : public SampleMaskBaseCase
1994 {
1995 public:
1996         enum TestMode
1997         {
1998                 TEST_DISCARD = 0,
1999                 TEST_INVERSE,
2000
2001                 TEST_LAST
2002         };
2003                                                 SampleMaskWriteCase                     (Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target, ShaderRunMode runMode, TestMode testMode);
2004                                                 ~SampleMaskWriteCase            (void);
2005
2006         void                            init                                            (void);
2007         void                            preDraw                                         (void);
2008         void                            postDraw                                        (void);
2009
2010 private:
2011         enum
2012         {
2013                 RENDER_SIZE = 64
2014         };
2015
2016         std::string                     genFragmentSource                       (int numTargetSamples) const;
2017         bool                            verifyImage                                     (const tcu::Surface& resultImage);
2018
2019         const TestMode          m_testMode;
2020 };
2021
2022 SampleMaskWriteCase::SampleMaskWriteCase (Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target, ShaderRunMode runMode, TestMode testMode)
2023         : SampleMaskBaseCase    (context, name, desc, sampleCount, target, RENDER_SIZE, runMode)
2024         , m_testMode                    (testMode)
2025 {
2026         DE_ASSERT(testMode < TEST_LAST);
2027 }
2028
2029 SampleMaskWriteCase::~SampleMaskWriteCase (void)
2030 {
2031 }
2032
2033 void SampleMaskWriteCase::init (void)
2034 {
2035         // log the test method and expectations
2036         if (m_testMode == TEST_DISCARD)
2037                 m_testCtx.getLog()
2038                         << tcu::TestLog::Message
2039                         << "Discarding half of the samples using gl_SampleMask, expecting:\n"
2040                         << "    1) half intensity on multisample targets (numSamples > 1)\n"
2041                         << "    2) full discard on multisample targets (numSamples == 1)\n"
2042                         << "    3) full intensity (no discard) on singlesample targets. (Mask is only applied as a multisample operation.)\n"
2043                         << tcu::TestLog::EndMessage;
2044         else if (m_testMode == TEST_INVERSE)
2045                 m_testCtx.getLog()
2046                         << tcu::TestLog::Message
2047                         << "Discarding half of the samples using GL_SAMPLE_MASK, setting inverse mask in fragment shader using gl_SampleMask, expecting:\n"
2048                         << "    1) full discard on multisample targets (mask & modifiedCoverge == 0)\n"
2049                         << "    2) full intensity (no discard) on singlesample targets. (Mask and coverage is only applied as a multisample operation.)\n"
2050                         << tcu::TestLog::EndMessage;
2051         else
2052                 DE_ASSERT(false);
2053
2054         SampleMaskBaseCase::init();
2055 }
2056
2057 void SampleMaskWriteCase::preDraw (void)
2058 {
2059         const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2060
2061         if (m_testMode == TEST_INVERSE)
2062         {
2063                 // set mask to 0xAAAA.., set inverse mask bit coverage in shader
2064
2065                 const int               maskLoc = gl.getUniformLocation(m_program->getProgram(), "u_mask");
2066                 const deUint32  mask    = (deUint32)0xAAAAAAAAUL;
2067
2068                 if (maskLoc == -1)
2069                         throw tcu::TestError("Location of u_mask was -1");
2070
2071                 gl.enable(GL_SAMPLE_MASK);
2072                 gl.sampleMaski(0, mask);
2073                 GLU_EXPECT_NO_ERROR(gl.getError(), "set mask");
2074
2075                 gl.uniform1ui(maskLoc, mask);
2076                 GLU_EXPECT_NO_ERROR(gl.getError(), "set mask uniform");
2077
2078                 m_testCtx.getLog() << tcu::TestLog::Message << "Setting sample mask " << tcu::Format::Hex<4>(mask) << tcu::TestLog::EndMessage;
2079         }
2080
2081         SampleMaskBaseCase::preDraw();
2082 }
2083
2084 void SampleMaskWriteCase::postDraw (void)
2085 {
2086         const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2087
2088         if (m_testMode == TEST_INVERSE)
2089         {
2090                 const deUint32 fullMask = (1U << m_numTargetSamples) - 1;
2091
2092                 gl.disable(GL_SAMPLE_MASK);
2093                 gl.sampleMaski(0, fullMask);
2094                 GLU_EXPECT_NO_ERROR(gl.getError(), "set mask");
2095         }
2096
2097         SampleMaskBaseCase::postDraw();
2098 }
2099
2100 std::string SampleMaskWriteCase::genFragmentSource (int numTargetSamples) const
2101 {
2102         DE_ASSERT(numTargetSamples != 0);
2103         DE_UNREF(numTargetSamples);
2104
2105         std::ostringstream      buf;
2106         const bool                      supportsES32orGL45      = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)) ||
2107                                                         contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5));
2108         map<string, string>     args;
2109         args["GLSL_VERSION_DECL"]       = supportsES32orGL45 ? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES) : getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES);
2110         args["GLSL_EXTENSION"]          = supportsES32orGL45 ? "" : "#extension GL_OES_sample_variables : require";
2111
2112         if (m_testMode == TEST_DISCARD)
2113         {
2114                 // mask out every other coverage bit
2115
2116                 buf <<  "${GLSL_VERSION_DECL}\n"
2117                                 "${GLSL_EXTENSION}\n"
2118                                 "layout(location = 0) out mediump vec4 fragColor;\n"
2119                                 "void main (void)\n"
2120                                 "{\n"
2121                                 "       for (int i = 0; i < gl_SampleMask.length(); ++i)\n"
2122                                 "               gl_SampleMask[i] = int(0xAAAAAAAA);\n"
2123                                 "\n";
2124
2125                 if (m_runMode == RUN_PER_SAMPLE)
2126                         buf <<  "       // force per-sample shading\n"
2127                                         "       highp float blue = float(gl_SampleID);\n"
2128                                         "\n"
2129                                         "       fragColor = vec4(0.0, 1.0, blue, 1.0);\n"
2130                                         "}\n";
2131                 else
2132                         buf <<  "       fragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
2133                                         "}\n";
2134         }
2135         else if (m_testMode == TEST_INVERSE)
2136         {
2137                 // inverse every coverage bit
2138
2139                 buf <<  "${GLSL_VERSION_DECL}\n"
2140                                 "${GLSL_EXTENSION}\n"
2141                                 "layout(location = 0) out mediump vec4 fragColor;\n"
2142                                 "uniform highp uint u_mask;\n"
2143                                 "void main (void)\n"
2144                                 "{\n"
2145                                 "       gl_SampleMask[0] = int(~u_mask);\n"
2146                                 "\n";
2147
2148                 if (m_runMode == RUN_PER_SAMPLE)
2149                         buf <<  "       // force per-sample shading\n"
2150                                         "       highp float blue = float(gl_SampleID);\n"
2151                                         "\n"
2152                                         "       fragColor = vec4(0.0, 1.0, blue, 1.0);\n"
2153                                         "}\n";
2154                 else
2155                         buf <<  "       fragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
2156                                         "}\n";
2157         }
2158         else
2159                 DE_ASSERT(false);
2160
2161         return tcu::StringTemplate(buf.str()).specialize(args);
2162 }
2163
2164 bool SampleMaskWriteCase::verifyImage (const tcu::Surface& resultImage)
2165 {
2166         const bool singleSampleTarget = m_numRequestedSamples == 0 && !(m_renderTarget == TARGET_DEFAULT && m_context.getRenderTarget().getNumSamples() > 1);
2167
2168         if (m_testMode == TEST_DISCARD)
2169         {
2170                 if (singleSampleTarget)
2171                 {
2172                         // single sample case => multisample operations are not effective => don't discard anything
2173                         // expect green
2174                         return verifyImageWithVerifier(resultImage, m_testCtx.getLog(), ColorVerifier(tcu::Vec3(0.0f, 1.0f, 0.0f)));
2175                 }
2176                 else if (m_numTargetSamples == 1)
2177                 {
2178                         // total discard, expect black
2179                         return verifyImageWithVerifier(resultImage, m_testCtx.getLog(), ColorVerifier(tcu::Vec3(0.0f, 0.0f, 0.0f)));
2180                 }
2181                 else
2182                 {
2183                         // partial discard, expect something between black and green
2184                         return verifyImageWithVerifier(resultImage, m_testCtx.getLog(), PartialDiscardVerifier());
2185                 }
2186         }
2187         else if (m_testMode == TEST_INVERSE)
2188         {
2189                 if (singleSampleTarget)
2190                 {
2191                         // single sample case => multisample operations are not effective => don't discard anything
2192                         // expect green
2193                         return verifyImageWithVerifier(resultImage, m_testCtx.getLog(), ColorVerifier(tcu::Vec3(0.0f, 1.0f, 0.0f)));
2194                 }
2195                 else
2196                 {
2197                         // total discard, expect black
2198                         return verifyImageWithVerifier(resultImage, m_testCtx.getLog(), ColorVerifier(tcu::Vec3(0.0f, 0.0f, 0.0f)));
2199                 }
2200         }
2201         else
2202         {
2203                 DE_ASSERT(false);
2204                 return false;
2205         }
2206 }
2207
2208 } // anonymous
2209
2210 SampleVariableTests::SampleVariableTests (Context& context)
2211         : TestCaseGroup(context, "sample_variables", "Test sample variables")
2212 {
2213 }
2214
2215 SampleVariableTests::~SampleVariableTests (void)
2216 {
2217 }
2218
2219 void SampleVariableTests::init (void)
2220 {
2221         tcu::TestCaseGroup* const numSampleGroup        = new tcu::TestCaseGroup(m_testCtx,     "num_samples",          "Test NumSamples");
2222         tcu::TestCaseGroup* const maxSampleGroup        = new tcu::TestCaseGroup(m_testCtx,     "max_samples",          "Test MaxSamples");
2223         tcu::TestCaseGroup* const sampleIDGroup         = new tcu::TestCaseGroup(m_testCtx,     "sample_id",            "Test SampleID");
2224         tcu::TestCaseGroup* const samplePosGroup        = new tcu::TestCaseGroup(m_testCtx,     "sample_pos",           "Test SamplePosition");
2225         tcu::TestCaseGroup* const sampleMaskInGroup     = new tcu::TestCaseGroup(m_testCtx,     "sample_mask_in",       "Test SampleMaskIn");
2226         tcu::TestCaseGroup* const sampleMaskGroup       = new tcu::TestCaseGroup(m_testCtx,     "sample_mask",          "Test SampleMask");
2227
2228         addChild(numSampleGroup);
2229         addChild(maxSampleGroup);
2230         addChild(sampleIDGroup);
2231         addChild(samplePosGroup);
2232         addChild(sampleMaskInGroup);
2233         addChild(sampleMaskGroup);
2234
2235         static const struct RenderTarget
2236         {
2237                 const char*                                                     name;
2238                 const char*                                                     desc;
2239                 int                                                                     numSamples;
2240                 MultisampleRenderCase::RenderTarget     target;
2241         } targets[] =
2242         {
2243                 { "default_framebuffer",                "Test with default framebuffer",        0,      MultisampleRenderCase::TARGET_DEFAULT           },
2244                 { "singlesample_texture",               "Test with singlesample texture",       0,      MultisampleRenderCase::TARGET_TEXTURE           },
2245                 { "multisample_texture_1",              "Test with multisample texture",        1,      MultisampleRenderCase::TARGET_TEXTURE           },
2246                 { "multisample_texture_2",              "Test with multisample texture",        2,      MultisampleRenderCase::TARGET_TEXTURE           },
2247                 { "multisample_texture_4",              "Test with multisample texture",        4,      MultisampleRenderCase::TARGET_TEXTURE           },
2248                 { "multisample_texture_8",              "Test with multisample texture",        8,      MultisampleRenderCase::TARGET_TEXTURE           },
2249                 { "multisample_texture_16",             "Test with multisample texture",        16,     MultisampleRenderCase::TARGET_TEXTURE           },
2250                 { "singlesample_rbo",                   "Test with singlesample rbo",           0,      MultisampleRenderCase::TARGET_RENDERBUFFER      },
2251                 { "multisample_rbo_1",                  "Test with multisample rbo",            1,      MultisampleRenderCase::TARGET_RENDERBUFFER      },
2252                 { "multisample_rbo_2",                  "Test with multisample rbo",            2,      MultisampleRenderCase::TARGET_RENDERBUFFER      },
2253                 { "multisample_rbo_4",                  "Test with multisample rbo",            4,      MultisampleRenderCase::TARGET_RENDERBUFFER      },
2254                 { "multisample_rbo_8",                  "Test with multisample rbo",            8,      MultisampleRenderCase::TARGET_RENDERBUFFER      },
2255                 { "multisample_rbo_16",                 "Test with multisample rbo",            16,     MultisampleRenderCase::TARGET_RENDERBUFFER      },
2256         };
2257
2258         // .num_samples
2259         {
2260                 for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx)
2261                         numSampleGroup->addChild(new NumSamplesCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target));
2262         }
2263
2264         // .max_samples
2265         {
2266                 for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx)
2267                         maxSampleGroup->addChild(new MaxSamplesCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target));
2268         }
2269
2270         // .sample_ID
2271         {
2272                 for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx)
2273                         sampleIDGroup->addChild(new SampleIDCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target));
2274         }
2275
2276         // .sample_pos
2277         {
2278                 {
2279                         tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx,     "correctness", "Test SamplePos correctness");
2280                         samplePosGroup->addChild(group);
2281
2282                         for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx)
2283                                 group->addChild(new SamplePosCorrectnessCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target));
2284                 }
2285
2286                 {
2287                         tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx,     "distribution", "Test SamplePos distribution");
2288                         samplePosGroup->addChild(group);
2289
2290                         for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx)
2291                                 group->addChild(new SamplePosDistributionCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target));
2292                 }
2293         }
2294
2295         // .sample_mask_in
2296         {
2297                 // .sample_mask
2298                 {
2299                         tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx,     "sample_mask", "Test with GL_SAMPLE_MASK");
2300                         sampleMaskInGroup->addChild(group);
2301
2302                         for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx)
2303                                 group->addChild(new SampleMaskCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target));
2304                 }
2305                 // .bit_count_per_pixel
2306                 {
2307                         tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx,     "bit_count_per_pixel", "Test number of coverage bits");
2308                         sampleMaskInGroup->addChild(group);
2309
2310                         for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx)
2311                                 group->addChild(new SampleMaskCountCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target, SampleMaskCountCase::RUN_PER_PIXEL));
2312                 }
2313                 // .bit_count_per_sample
2314                 {
2315                         tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx,     "bit_count_per_sample", "Test number of coverage bits");
2316                         sampleMaskInGroup->addChild(group);
2317
2318                         for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx)
2319                                 group->addChild(new SampleMaskCountCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target, SampleMaskCountCase::RUN_PER_SAMPLE));
2320                 }
2321                 // .bit_count_per_two_samples
2322                 {
2323                         tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx,     "bit_count_per_two_samples", "Test number of coverage bits");
2324                         sampleMaskInGroup->addChild(group);
2325
2326                         for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx)
2327                                 group->addChild(new SampleMaskCountCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target, SampleMaskCountCase::RUN_PER_TWO_SAMPLES));
2328                 }
2329                 // .bits_unique_per_sample
2330                 {
2331                         tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx,     "bits_unique_per_sample", "Test coverage bits");
2332                         sampleMaskInGroup->addChild(group);
2333
2334                         for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx)
2335                                 if (targets[targetNdx].target == MultisampleRenderCase::TARGET_TEXTURE)
2336                                         group->addChild(new SampleMaskUniqueCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target, SampleMaskUniqueCase::RUN_PER_SAMPLE));
2337                 }
2338                 // .bits_unique_per_two_samples
2339                 {
2340                         tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx,     "bits_unique_per_two_samples", "Test coverage bits");
2341                         sampleMaskInGroup->addChild(group);
2342
2343                         for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx)
2344                                 if (targets[targetNdx].target == MultisampleRenderCase::TARGET_TEXTURE)
2345                                         group->addChild(new SampleMaskUniqueSetCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target, SampleMaskUniqueCase::RUN_PER_TWO_SAMPLES));
2346                 }
2347         }
2348
2349         // .sample_mask
2350         {
2351                 // .discard_half_per_pixel
2352                 {
2353                         tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx,     "discard_half_per_pixel", "Test coverage bits");
2354                         sampleMaskGroup->addChild(group);
2355
2356                         for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx)
2357                                 group->addChild(new SampleMaskWriteCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target, SampleMaskWriteCase::RUN_PER_PIXEL, SampleMaskWriteCase::TEST_DISCARD));
2358                 }
2359                 // .discard_half_per_sample
2360                 {
2361                         tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx,     "discard_half_per_sample", "Test coverage bits");
2362                         sampleMaskGroup->addChild(group);
2363
2364                         for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx)
2365                                 group->addChild(new SampleMaskWriteCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target, SampleMaskWriteCase::RUN_PER_SAMPLE, SampleMaskWriteCase::TEST_DISCARD));
2366                 }
2367                 // .discard_half_per_two_samples
2368                 {
2369                         tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx,     "discard_half_per_two_samples", "Test coverage bits");
2370                         sampleMaskGroup->addChild(group);
2371
2372                         for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx)
2373                                 group->addChild(new SampleMaskWriteCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target, SampleMaskWriteCase::RUN_PER_TWO_SAMPLES, SampleMaskWriteCase::TEST_DISCARD));
2374                 }
2375
2376                 // .discard_half_per_two_samples
2377                 {
2378                         tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx,     "inverse_per_pixel", "Test coverage bits");
2379                         sampleMaskGroup->addChild(group);
2380
2381                         for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx)
2382                                 group->addChild(new SampleMaskWriteCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target, SampleMaskWriteCase::RUN_PER_PIXEL, SampleMaskWriteCase::TEST_INVERSE));
2383                 }
2384                 // .inverse_per_sample
2385                 {
2386                         tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx,     "inverse_per_sample", "Test coverage bits");
2387                         sampleMaskGroup->addChild(group);
2388
2389                         for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx)
2390                                 group->addChild(new SampleMaskWriteCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target, SampleMaskWriteCase::RUN_PER_SAMPLE, SampleMaskWriteCase::TEST_INVERSE));
2391                 }
2392                 // .inverse_per_two_samples
2393                 {
2394                         tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx,     "inverse_per_two_samples", "Test coverage bits");
2395                         sampleMaskGroup->addChild(group);
2396
2397                         for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx)
2398                                 group->addChild(new SampleMaskWriteCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target, SampleMaskWriteCase::RUN_PER_TWO_SAMPLES, SampleMaskWriteCase::TEST_INVERSE));
2399                 }
2400         }
2401 }
2402
2403 } // Functional
2404 } // gles31
2405 } // deqp