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