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