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