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