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