1 /*------------------------------------------------------------------------- 2 * drawElements Quality Program OpenGL ES 3.1 Module 3 * ------------------------------------------------- 4 * 5 * Copyright 2014 The Android Open Source Project 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 * 19 *//*! 20 * \file 21 * \brief Multisample texture test 22 *//*--------------------------------------------------------------------*/ 23 24 #include "es31fTextureMultisampleTests.hpp" 25 #include "tcuTestLog.hpp" 26 #include "tcuRenderTarget.hpp" 27 #include "tcuSurface.hpp" 28 #include "tcuStringTemplate.hpp" 29 #include "tcuTextureUtil.hpp" 30 #include "glsStateQueryUtil.hpp" 31 #include "tcuRasterizationVerifier.hpp" 32 #include "gluRenderContext.hpp" 33 #include "gluCallLogWrapper.hpp" 34 #include "gluObjectWrapper.hpp" 35 #include "gluShaderProgram.hpp" 36 #include "gluPixelTransfer.hpp" 37 #include "gluStrUtil.hpp" 38 #include "gluContextInfo.hpp" 39 #include "glwEnums.hpp" 40 #include "glwFunctions.hpp" 41 #include "deStringUtil.hpp" 42 #include "deRandom.hpp" 43 44 using namespace glw; 45 46 namespace deqp 47 { 48 namespace gles31 49 { 50 namespace Functional 51 { 52 namespace 53 { 54 55 using tcu::RasterizationArguments; 56 using tcu::TriangleSceneSpec; 57 58 static std::string sampleMaskToString (const std::vector<deUint32>& bitfield, int numBits) 59 { 60 std::string result(numBits, '0'); 61 62 // move from back to front and set chars to 1 63 for (int wordNdx = 0; wordNdx < (int)bitfield.size(); ++wordNdx) 64 { 65 for (int bit = 0; bit < 32; ++bit) 66 { 67 const int targetCharNdx = numBits - (wordNdx*32+bit) - 1; 68 69 // beginning of the string reached 70 if (targetCharNdx < 0) 71 return result; 72 73 if ((bitfield[wordNdx] >> bit) & 0x01) 74 result[targetCharNdx] = '1'; 75 } 76 } 77 78 return result; 79 } 80 81 /*--------------------------------------------------------------------*//*! 82 * \brief Returns the number of words needed to represent mask of given length 83 *//*--------------------------------------------------------------------*/ 84 static int getEffectiveSampleMaskWordCount (int highestBitNdx) 85 { 86 const int wordSize = 32; 87 const int maskLen = highestBitNdx + 1; 88 89 return ((maskLen - 1) / wordSize) + 1; // round_up(mask_len / wordSize) 90 } 91 92 /*--------------------------------------------------------------------*//*! 93 * \brief Creates sample mask with all less significant bits than nthBit set 94 *//*--------------------------------------------------------------------*/ 95 static std::vector<deUint32> genAllSetToNthBitSampleMask (int nthBit) 96 { 97 const int wordSize = 32; 98 const int numWords = getEffectiveSampleMaskWordCount(nthBit - 1); 99 const deUint32 topWordBits = (deUint32)(nthBit - (numWords - 1) * wordSize); 100 std::vector<deUint32> mask (numWords); 101 102 for (int ndx = 0; ndx < numWords - 1; ++ndx) 103 mask[ndx] = 0xFFFFFFFF; 104 105 mask[numWords - 1] = (deUint32)((1ULL << topWordBits) - (deUint32)1); 106 return mask; 107 } 108 109 /*--------------------------------------------------------------------*//*! 110 * \brief Creates sample mask with nthBit set 111 *//*--------------------------------------------------------------------*/ 112 static std::vector<deUint32> genSetNthBitSampleMask (int nthBit) 113 { 114 const int wordSize = 32; 115 const int numWords = getEffectiveSampleMaskWordCount(nthBit); 116 const deUint32 topWordBits = (deUint32)(nthBit - (numWords - 1) * wordSize); 117 std::vector<deUint32> mask (numWords); 118 119 for (int ndx = 0; ndx < numWords - 1; ++ndx) 120 mask[ndx] = 0; 121 122 mask[numWords - 1] = (deUint32)(1ULL << topWordBits); 123 return mask; 124 } 125 126 class SamplePosRasterizationTest : public TestCase 127 { 128 public: 129 SamplePosRasterizationTest (Context& context, const char* name, const char* desc, int samples); 130 ~SamplePosRasterizationTest (void); 131 132 private: 133 void init (void); 134 void deinit (void); 135 IterateResult iterate (void); 136 void genMultisampleTexture (void); 137 void genSamplerProgram (void); 138 bool testMultisampleTexture (int sampleNdx); 139 void drawSample (tcu::Surface& dst, int sampleNdx); 140 void convertToSceneSpec (TriangleSceneSpec& scene, const tcu::Vec2& samplePos) const; 141 142 struct Triangle 143 { 144 tcu::Vec4 p1; 145 tcu::Vec4 p2; 146 tcu::Vec4 p3; 147 }; 148 149 const int m_samples; 150 const int m_canvasSize; 151 std::vector<Triangle> m_testTriangles; 152 153 int m_iteration; 154 bool m_allIterationsOk; 155 156 GLuint m_texID; 157 GLuint m_vaoID; 158 GLuint m_vboID; 159 std::vector<tcu::Vec2> m_samplePositions; 160 int m_subpixelBits; 161 162 const glu::ShaderProgram* m_samplerProgram; 163 GLint m_samplerProgramPosLoc; 164 GLint m_samplerProgramSamplerLoc; 165 GLint m_samplerProgramSampleNdxLoc; 166 }; 167 168 SamplePosRasterizationTest::SamplePosRasterizationTest (Context& context, const char* name, const char* desc, int samples) 169 : TestCase (context, name, desc) 170 , m_samples (samples) 171 , m_canvasSize (256) 172 , m_iteration (0) 173 , m_allIterationsOk (true) 174 , m_texID (0) 175 , m_vaoID (0) 176 , m_vboID (0) 177 , m_subpixelBits (0) 178 , m_samplerProgram (DE_NULL) 179 , m_samplerProgramPosLoc (-1) 180 , m_samplerProgramSamplerLoc (-1) 181 , m_samplerProgramSampleNdxLoc (-1) 182 { 183 } 184 185 SamplePosRasterizationTest::~SamplePosRasterizationTest (void) 186 { 187 deinit(); 188 } 189 190 void SamplePosRasterizationTest::init (void) 191 { 192 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 193 GLint maxSamples = 0; 194 195 // requirements 196 197 if (m_context.getRenderTarget().getWidth() < m_canvasSize || m_context.getRenderTarget().getHeight() < m_canvasSize) 198 throw tcu::NotSupportedError("render target size must be at least " + de::toString(m_canvasSize) + "x" + de::toString(m_canvasSize)); 199 200 gl.getIntegerv(GL_MAX_COLOR_TEXTURE_SAMPLES, &maxSamples); 201 if (m_samples > maxSamples) 202 throw tcu::NotSupportedError("Requested sample count is greater than GL_MAX_COLOR_TEXTURE_SAMPLES"); 203 204 m_testCtx.getLog() << tcu::TestLog::Message << "GL_MAX_COLOR_TEXTURE_SAMPLES = " << maxSamples << tcu::TestLog::EndMessage; 205 206 gl.getIntegerv(GL_SUBPIXEL_BITS, &m_subpixelBits); 207 m_testCtx.getLog() << tcu::TestLog::Message << "GL_SUBPIXEL_BITS = " << m_subpixelBits << tcu::TestLog::EndMessage; 208 209 // generate textures & other gl stuff 210 211 m_testCtx.getLog() << tcu::TestLog::Message << "Creating multisample texture" << tcu::TestLog::EndMessage; 212 213 gl.genTextures (1, &m_texID); 214 gl.bindTexture (GL_TEXTURE_2D_MULTISAMPLE, m_texID); 215 gl.texStorage2DMultisample (GL_TEXTURE_2D_MULTISAMPLE, m_samples, GL_RGBA8, m_canvasSize, m_canvasSize, GL_TRUE); 216 GLU_EXPECT_NO_ERROR (gl.getError(), "texStorage2DMultisample"); 217 218 gl.genVertexArrays (1, &m_vaoID); 219 gl.bindVertexArray (m_vaoID); 220 GLU_EXPECT_NO_ERROR (gl.getError(), "bindVertexArray"); 221 222 gl.genBuffers (1, &m_vboID); 223 gl.bindBuffer (GL_ARRAY_BUFFER, m_vboID); 224 GLU_EXPECT_NO_ERROR (gl.getError(), "bindBuffer"); 225 226 // generate test scene 227 for (int i = 0; i < 20; ++i) 228 { 229 // vertical spikes 230 Triangle tri; 231 tri.p1 = tcu::Vec4(((float)i + 1.0f / (float)(i + 1)) / 20.0f, 0.0f, 0.0f, 1.0f); 232 tri.p2 = tcu::Vec4(((float)i + 0.3f + 1.0f / (float)(i + 1)) / 20.0f, 0.0f, 0.0f, 1.0f); 233 tri.p3 = tcu::Vec4(((float)i + 1.0f / (float)(i + 1)) / 20.0f, -1.0f, 0.0f, 1.0f); 234 m_testTriangles.push_back(tri); 235 } 236 for (int i = 0; i < 20; ++i) 237 { 238 // horisontal spikes 239 Triangle tri; 240 tri.p1 = tcu::Vec4(-1.0f, ((float)i + 1.0f / (float)(i + 1)) / 20.0f, 0.0f, 1.0f); 241 tri.p2 = tcu::Vec4(-1.0f, ((float)i + 0.3f + 1.0f / (float)(i + 1)) / 20.0f, 0.0f, 1.0f); 242 tri.p3 = tcu::Vec4( 0.0f, ((float)i + 1.0f / (float)(i + 1)) / 20.0f, 0.0f, 1.0f); 243 m_testTriangles.push_back(tri); 244 } 245 246 for (int i = 0; i < 20; ++i) 247 { 248 // fan 249 const tcu::Vec2 p = tcu::Vec2(deFloatCos(((float)i)/20.0f*DE_PI*2) * 0.5f + 0.5f, deFloatSin(((float)i)/20.0f*DE_PI*2) * 0.5f + 0.5f); 250 const tcu::Vec2 d = tcu::Vec2(0.1f, 0.02f); 251 252 Triangle tri; 253 tri.p1 = tcu::Vec4(0.4f, 0.4f, 0.0f, 1.0f); 254 tri.p2 = tcu::Vec4(p.x(), p.y(), 0.0f, 1.0f); 255 tri.p3 = tcu::Vec4(p.x() + d.x(), p.y() + d.y(), 0.0f, 1.0f); 256 m_testTriangles.push_back(tri); 257 } 258 { 259 Triangle tri; 260 tri.p1 = tcu::Vec4(-0.202f, -0.202f, 0.0f, 1.0f); 261 tri.p2 = tcu::Vec4(-0.802f, -0.202f, 0.0f, 1.0f); 262 tri.p3 = tcu::Vec4(-0.802f, -0.802f, 0.0f, 1.0f); 263 m_testTriangles.push_back(tri); 264 } 265 266 // generate multisample texture (and query the sample positions in it) 267 genMultisampleTexture(); 268 269 // verify queried samples are in a valid range 270 for (int sampleNdx = 0; sampleNdx < m_samples; ++sampleNdx) 271 { 272 if (m_samplePositions[sampleNdx].x() < 0.0f || m_samplePositions[sampleNdx].x() > 1.0f || 273 m_samplePositions[sampleNdx].y() < 0.0f || m_samplePositions[sampleNdx].y() > 1.0f) 274 { 275 m_testCtx.getLog() << tcu::TestLog::Message << "// ERROR: Sample position of sample " << sampleNdx << " should be in range ([0, 1], [0, 1]). Got " << m_samplePositions[sampleNdx] << tcu::TestLog::EndMessage; 276 throw tcu::TestError("invalid sample position"); 277 } 278 } 279 280 // generate sampler program 281 genSamplerProgram(); 282 } 283 284 void SamplePosRasterizationTest::deinit (void) 285 { 286 if (m_vboID) 287 { 288 m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_vboID); 289 m_vboID = 0; 290 } 291 292 if (m_vaoID) 293 { 294 m_context.getRenderContext().getFunctions().deleteVertexArrays(1, &m_vaoID); 295 m_vaoID = 0; 296 } 297 298 if (m_texID) 299 { 300 m_context.getRenderContext().getFunctions().deleteTextures(1, &m_texID); 301 m_texID = 0; 302 } 303 304 if (m_samplerProgram) 305 { 306 delete m_samplerProgram; 307 m_samplerProgram = DE_NULL; 308 } 309 } 310 311 SamplePosRasterizationTest::IterateResult SamplePosRasterizationTest::iterate (void) 312 { 313 m_allIterationsOk &= testMultisampleTexture(m_iteration); 314 m_iteration++; 315 316 if (m_iteration < m_samples) 317 return CONTINUE; 318 319 // End result 320 if (m_allIterationsOk) 321 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 322 else 323 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Pixel comparison failed"); 324 325 return STOP; 326 } 327 328 void SamplePosRasterizationTest::genMultisampleTexture (void) 329 { 330 const char* const vertexShaderSource = "#version 310 es\n" 331 "in highp vec4 a_position;\n" 332 "void main (void)\n" 333 "{\n" 334 " gl_Position = a_position;\n" 335 "}\n"; 336 const char* const fragmentShaderSource = "#version 310 es\n" 337 "layout(location = 0) out highp vec4 fragColor;\n" 338 "void main (void)\n" 339 "{\n" 340 " fragColor = vec4(1.0, 1.0, 1.0, 1.0);\n" 341 "}\n"; 342 343 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 344 const glu::ShaderProgram program (m_context.getRenderContext(), glu::ProgramSources() 345 << glu::VertexSource(vertexShaderSource) 346 << glu::FragmentSource(fragmentShaderSource)); 347 const GLuint posLoc = gl.getAttribLocation(program.getProgram(), "a_position"); 348 GLuint fboID = 0; 349 350 if (!program.isOk()) 351 { 352 m_testCtx.getLog() << program; 353 throw tcu::TestError("Failed to build shader."); 354 } 355 356 gl.bindTexture (GL_TEXTURE_2D_MULTISAMPLE, m_texID); 357 gl.bindVertexArray (m_vaoID); 358 gl.bindBuffer (GL_ARRAY_BUFFER, m_vboID); 359 360 // Setup fbo for drawing and for sample position query 361 362 m_testCtx.getLog() << tcu::TestLog::Message << "Attaching texture to FBO" << tcu::TestLog::EndMessage; 363 364 gl.genFramebuffers (1, &fboID); 365 gl.bindFramebuffer (GL_FRAMEBUFFER, fboID); 366 gl.framebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, m_texID, 0); 367 GLU_EXPECT_NO_ERROR (gl.getError(), "framebufferTexture2D"); 368 369 // Query sample positions of the multisample texture by querying the sample positions 370 // from an fbo which has the multisample texture as attachment. 371 372 m_testCtx.getLog() << tcu::TestLog::Message << "Sample locations:" << tcu::TestLog::EndMessage; 373 374 for (int sampleNdx = 0; sampleNdx < m_samples; ++sampleNdx) 375 { 376 gls::StateQueryUtil::StateQueryMemoryWriteGuard<float[2]> position; 377 378 gl.getMultisamplefv(GL_SAMPLE_POSITION, (deUint32)sampleNdx, position); 379 if (!position.verifyValidity(m_testCtx)) 380 throw tcu::TestError("Error while querying sample positions"); 381 382 m_testCtx.getLog() << tcu::TestLog::Message << "\t" << sampleNdx << ": (" << position[0] << ", " << position[1] << ")" << tcu::TestLog::EndMessage; 383 m_samplePositions.push_back(tcu::Vec2(position[0], position[1])); 384 } 385 386 // Draw test pattern to texture 387 388 m_testCtx.getLog() << tcu::TestLog::Message << "Drawing test pattern to the texture" << tcu::TestLog::EndMessage; 389 390 gl.bufferData (GL_ARRAY_BUFFER, (glw::GLsizeiptr)(m_testTriangles.size() * sizeof(Triangle)), &m_testTriangles[0], GL_STATIC_DRAW); 391 GLU_EXPECT_NO_ERROR (gl.getError(), "bufferData"); 392 393 gl.viewport (0, 0, m_canvasSize, m_canvasSize); 394 gl.clearColor (0, 0, 0, 1); 395 gl.clear (GL_COLOR_BUFFER_BIT); 396 gl.vertexAttribPointer (posLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL); 397 gl.enableVertexAttribArray (posLoc); 398 GLU_EXPECT_NO_ERROR (gl.getError(), "vertexAttribPointer"); 399 400 gl.useProgram (program.getProgram()); 401 gl.drawArrays (GL_TRIANGLES, 0, (glw::GLsizei)(m_testTriangles.size() * 3)); 402 GLU_EXPECT_NO_ERROR (gl.getError(), "drawArrays"); 403 404 gl.disableVertexAttribArray (posLoc); 405 gl.useProgram (0); 406 gl.deleteFramebuffers (1, &fboID); 407 GLU_EXPECT_NO_ERROR (gl.getError(), "cleanup"); 408 } 409 410 void SamplePosRasterizationTest::genSamplerProgram (void) 411 { 412 const char* const vertexShaderSource = "#version 310 es\n" 413 "in highp vec4 a_position;\n" 414 "void main (void)\n" 415 "{\n" 416 " gl_Position = a_position;\n" 417 "}\n"; 418 const char* const fragShaderSource = "#version 310 es\n" 419 "layout(location = 0) out highp vec4 fragColor;\n" 420 "uniform highp sampler2DMS u_sampler;\n" 421 "uniform highp int u_sample;\n" 422 "void main (void)\n" 423 "{\n" 424 " fragColor = texelFetch(u_sampler, ivec2(int(floor(gl_FragCoord.x)), int(floor(gl_FragCoord.y))), u_sample);\n" 425 "}\n"; 426 const tcu::ScopedLogSection section (m_testCtx.getLog(), "Generate sampler shader", "Generate sampler shader"); 427 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 428 429 m_samplerProgram = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(vertexShaderSource) << glu::FragmentSource(fragShaderSource)); 430 m_testCtx.getLog() << *m_samplerProgram; 431 432 if (!m_samplerProgram->isOk()) 433 throw tcu::TestError("Could not create sampler program."); 434 435 m_samplerProgramPosLoc = gl.getAttribLocation(m_samplerProgram->getProgram(), "a_position"); 436 m_samplerProgramSamplerLoc = gl.getUniformLocation(m_samplerProgram->getProgram(), "u_sampler"); 437 m_samplerProgramSampleNdxLoc = gl.getUniformLocation(m_samplerProgram->getProgram(), "u_sample"); 438 } 439 440 bool SamplePosRasterizationTest::testMultisampleTexture (int sampleNdx) 441 { 442 tcu::Surface glSurface(m_canvasSize, m_canvasSize); 443 TriangleSceneSpec scene; 444 445 // Draw sample 446 drawSample(glSurface, sampleNdx); 447 448 // Draw reference(s) 449 convertToSceneSpec(scene, m_samplePositions[sampleNdx]); 450 451 // Compare 452 { 453 RasterizationArguments args; 454 args.redBits = m_context.getRenderTarget().getPixelFormat().redBits; 455 args.greenBits = m_context.getRenderTarget().getPixelFormat().greenBits; 456 args.blueBits = m_context.getRenderTarget().getPixelFormat().blueBits; 457 args.numSamples = 0; 458 args.subpixelBits = m_subpixelBits; 459 460 return tcu::verifyTriangleGroupRasterization(glSurface, scene, args, m_testCtx.getLog(), tcu::VERIFICATIONMODE_STRICT); 461 } 462 } 463 464 void SamplePosRasterizationTest::drawSample (tcu::Surface& dst, int sampleNdx) 465 { 466 // Downsample using only one sample 467 static const tcu::Vec4 fullscreenQuad[] = 468 { 469 tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f), 470 tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f), 471 tcu::Vec4( 1.0f, 1.0f, 0.0f, 1.0f), 472 tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f) 473 }; 474 475 const tcu::ScopedLogSection section (m_testCtx.getLog(), "Test sample position " + de::toString(sampleNdx+1) + "/" + de::toString(m_samples), "Test sample position " + de::toString(sampleNdx+1) + "/" + de::toString(m_samples)); 476 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 477 478 gl.bindTexture (GL_TEXTURE_2D_MULTISAMPLE, m_texID); 479 gl.bindVertexArray (m_vaoID); 480 gl.bindBuffer (GL_ARRAY_BUFFER, m_vboID); 481 482 gl.bufferData (GL_ARRAY_BUFFER, sizeof(fullscreenQuad), &fullscreenQuad[0], GL_STATIC_DRAW); 483 GLU_EXPECT_NO_ERROR (gl.getError(), "bufferData"); 484 485 gl.viewport (0, 0, m_canvasSize, m_canvasSize); 486 gl.clearColor (0, 0, 0, 1); 487 gl.clear (GL_COLOR_BUFFER_BIT); 488 gl.vertexAttribPointer (m_samplerProgramPosLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL); 489 gl.enableVertexAttribArray (m_samplerProgramPosLoc); 490 GLU_EXPECT_NO_ERROR (gl.getError(), "vertexAttribPointer"); 491 492 gl.useProgram (m_samplerProgram->getProgram()); 493 gl.uniform1i (m_samplerProgramSamplerLoc, 0); 494 gl.uniform1i (m_samplerProgramSampleNdxLoc, (deInt32)sampleNdx); 495 GLU_EXPECT_NO_ERROR (gl.getError(), "useprogram"); 496 497 m_testCtx.getLog() << tcu::TestLog::Message << "Reading from texture with sample index " << sampleNdx << tcu::TestLog::EndMessage; 498 499 gl.drawArrays (GL_TRIANGLE_STRIP, 0, 4); 500 GLU_EXPECT_NO_ERROR (gl.getError(), "drawArrays"); 501 502 gl.disableVertexAttribArray (m_samplerProgramPosLoc); 503 gl.useProgram (0); 504 GLU_EXPECT_NO_ERROR (gl.getError(), "cleanup"); 505 506 gl.finish (); 507 glu::readPixels (m_context.getRenderContext(), 0, 0, dst.getAccess()); 508 GLU_EXPECT_NO_ERROR (gl.getError(), "readPixels"); 509 } 510 511 void SamplePosRasterizationTest::convertToSceneSpec (TriangleSceneSpec& scene, const tcu::Vec2& samplePos) const 512 { 513 // Triangles are offset from the pixel center by "offset". Move the triangles back to take this into account. 514 const tcu::Vec4 offset = tcu::Vec4(samplePos.x() - 0.5f, samplePos.y() - 0.5f, 0.0f, 0.0f) / tcu::Vec4((float)m_canvasSize, (float)m_canvasSize, 1.0f, 1.0f) * 2.0f; 515 516 for (int triangleNdx = 0; triangleNdx < (int)m_testTriangles.size(); ++triangleNdx) 517 { 518 TriangleSceneSpec::SceneTriangle triangle; 519 520 triangle.positions[0] = m_testTriangles[triangleNdx].p1 - offset; 521 triangle.positions[1] = m_testTriangles[triangleNdx].p2 - offset; 522 triangle.positions[2] = m_testTriangles[triangleNdx].p3 - offset; 523 524 triangle.sharedEdge[0] = false; 525 triangle.sharedEdge[1] = false; 526 triangle.sharedEdge[2] = false; 527 528 scene.triangles.push_back(triangle); 529 } 530 } 531 532 class SampleMaskCase : public TestCase 533 { 534 public: 535 enum CaseFlags 536 { 537 FLAGS_NONE = 0, 538 FLAGS_ALPHA_TO_COVERAGE = (1ULL << 0), 539 FLAGS_SAMPLE_COVERAGE = (1ULL << 1), 540 FLAGS_HIGH_BITS = (1ULL << 2), 541 }; 542 543 SampleMaskCase (Context& context, const char* name, const char* desc, int samples, int flags); 544 ~SampleMaskCase (void); 545 546 private: 547 void init (void); 548 void deinit (void); 549 IterateResult iterate (void); 550 551 void genSamplerProgram (void); 552 void genAlphaProgram (void); 553 void updateTexture (int sample); 554 bool verifyTexture (int sample); 555 void drawSample (tcu::Surface& dst, int sample); 556 557 const int m_samples; 558 const int m_canvasSize; 559 const int m_gridsize; 560 const int m_effectiveSampleMaskWordCount; 561 562 int m_flags; 563 int m_currentSample; 564 int m_allIterationsOk; 565 566 glw::GLuint m_texID; 567 glw::GLuint m_vaoID; 568 glw::GLuint m_vboID; 569 glw::GLuint m_fboID; 570 571 const glu::ShaderProgram* m_samplerProgram; 572 glw::GLint m_samplerProgramPosLoc; 573 glw::GLint m_samplerProgramSamplerLoc; 574 glw::GLint m_samplerProgramSampleNdxLoc; 575 576 const glu::ShaderProgram* m_alphaProgram; 577 glw::GLint m_alphaProgramPosLoc; 578 }; 579 580 SampleMaskCase::SampleMaskCase (Context& context, const char* name, const char* desc, int samples, int flags) 581 : TestCase (context, name, desc) 582 , m_samples (samples) 583 , m_canvasSize (256) 584 , m_gridsize (16) 585 , m_effectiveSampleMaskWordCount(getEffectiveSampleMaskWordCount(samples - 1)) 586 , m_flags (flags) 587 , m_currentSample (-1) 588 , m_allIterationsOk (true) 589 , m_texID (0) 590 , m_vaoID (0) 591 , m_vboID (0) 592 , m_fboID (0) 593 , m_samplerProgram (DE_NULL) 594 , m_samplerProgramPosLoc (-1) 595 , m_samplerProgramSamplerLoc (-1) 596 , m_samplerProgramSampleNdxLoc (-1) 597 , m_alphaProgram (DE_NULL) 598 , m_alphaProgramPosLoc (-1) 599 { 600 } 601 602 SampleMaskCase::~SampleMaskCase (void) 603 { 604 deinit(); 605 } 606 607 void SampleMaskCase::init (void) 608 { 609 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 610 glw::GLint maxSamples = 0; 611 glw::GLint maxSampleMaskWords = 0; 612 613 // requirements 614 615 if (m_context.getRenderTarget().getWidth() < m_canvasSize || m_context.getRenderTarget().getHeight() < m_canvasSize) 616 throw tcu::NotSupportedError("render target size must be at least " + de::toString(m_canvasSize) + "x" + de::toString(m_canvasSize)); 617 618 gl.getIntegerv(GL_MAX_SAMPLE_MASK_WORDS, &maxSampleMaskWords); 619 if (m_effectiveSampleMaskWordCount > maxSampleMaskWords) 620 throw tcu::NotSupportedError("Test requires larger GL_MAX_SAMPLE_MASK_WORDS"); 621 622 gl.getIntegerv(GL_MAX_COLOR_TEXTURE_SAMPLES, &maxSamples); 623 if (m_samples > maxSamples) 624 throw tcu::NotSupportedError("Requested sample count is greater than GL_MAX_COLOR_TEXTURE_SAMPLES"); 625 626 m_testCtx.getLog() << tcu::TestLog::Message << "GL_MAX_COLOR_TEXTURE_SAMPLES = " << maxSamples << tcu::TestLog::EndMessage; 627 628 // Don't even try to test high bits if there are none 629 630 if ((m_flags & FLAGS_HIGH_BITS) && (m_samples % 32 == 0)) 631 { 632 m_testCtx.getLog() << tcu::TestLog::Message << "Sample count is multiple of word size. No unused high bits in sample mask.\nSkipping." << tcu::TestLog::EndMessage; 633 throw tcu::NotSupportedError("Test requires unused high bits (sample count not multiple of 32)"); 634 } 635 636 // generate textures 637 638 m_testCtx.getLog() << tcu::TestLog::Message << "Creating multisample texture with sample count " << m_samples << tcu::TestLog::EndMessage; 639 640 gl.genTextures (1, &m_texID); 641 gl.bindTexture (GL_TEXTURE_2D_MULTISAMPLE, m_texID); 642 gl.texStorage2DMultisample (GL_TEXTURE_2D_MULTISAMPLE, m_samples, GL_RGBA8, m_canvasSize, m_canvasSize, GL_FALSE); 643 GLU_EXPECT_NO_ERROR (gl.getError(), "texStorage2DMultisample"); 644 645 // attach texture to fbo 646 647 m_testCtx.getLog() << tcu::TestLog::Message << "Attaching texture to FBO" << tcu::TestLog::EndMessage; 648 649 gl.genFramebuffers (1, &m_fboID); 650 gl.bindFramebuffer (GL_FRAMEBUFFER, m_fboID); 651 gl.framebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, m_texID, 0); 652 GLU_EXPECT_NO_ERROR (gl.getError(), "framebufferTexture2D"); 653 654 // buffers 655 656 gl.genVertexArrays (1, &m_vaoID); 657 GLU_EXPECT_NO_ERROR (gl.getError(), "genVertexArrays"); 658 659 gl.genBuffers (1, &m_vboID); 660 gl.bindBuffer (GL_ARRAY_BUFFER, m_vboID); 661 GLU_EXPECT_NO_ERROR (gl.getError(), "genBuffers"); 662 663 // generate grid pattern 664 { 665 std::vector<tcu::Vec4> gridData(m_gridsize*m_gridsize*6); 666 667 for (int y = 0; y < m_gridsize; ++y) 668 for (int x = 0; x < m_gridsize; ++x) 669 { 670 gridData[(y * m_gridsize + x)*6 + 0] = tcu::Vec4(((float)(x+0) / (float)m_gridsize) * 2.0f - 1.0f, ((float)(y+0) / (float)m_gridsize) * 2.0f - 1.0f, 0.0f, 1.0f); 671 gridData[(y * m_gridsize + x)*6 + 1] = tcu::Vec4(((float)(x+0) / (float)m_gridsize) * 2.0f - 1.0f, ((float)(y+1) / (float)m_gridsize) * 2.0f - 1.0f, 0.0f, 1.0f); 672 gridData[(y * m_gridsize + x)*6 + 2] = tcu::Vec4(((float)(x+1) / (float)m_gridsize) * 2.0f - 1.0f, ((float)(y+1) / (float)m_gridsize) * 2.0f - 1.0f, 0.0f, 1.0f); 673 gridData[(y * m_gridsize + x)*6 + 3] = tcu::Vec4(((float)(x+0) / (float)m_gridsize) * 2.0f - 1.0f, ((float)(y+0) / (float)m_gridsize) * 2.0f - 1.0f, 0.0f, 1.0f); 674 gridData[(y * m_gridsize + x)*6 + 4] = tcu::Vec4(((float)(x+1) / (float)m_gridsize) * 2.0f - 1.0f, ((float)(y+1) / (float)m_gridsize) * 2.0f - 1.0f, 0.0f, 1.0f); 675 gridData[(y * m_gridsize + x)*6 + 5] = tcu::Vec4(((float)(x+1) / (float)m_gridsize) * 2.0f - 1.0f, ((float)(y+0) / (float)m_gridsize) * 2.0f - 1.0f, 0.0f, 1.0f); 676 } 677 678 gl.bufferData (GL_ARRAY_BUFFER, (int)(gridData.size() * sizeof(tcu::Vec4)), gridData[0].getPtr(), GL_STATIC_DRAW); 679 GLU_EXPECT_NO_ERROR (gl.getError(), "bufferData"); 680 } 681 682 // generate programs 683 684 genSamplerProgram(); 685 genAlphaProgram(); 686 } 687 688 void SampleMaskCase::deinit (void) 689 { 690 if (m_texID) 691 { 692 m_context.getRenderContext().getFunctions().deleteTextures(1, &m_texID); 693 m_texID = 0; 694 } 695 if (m_vaoID) 696 { 697 m_context.getRenderContext().getFunctions().deleteVertexArrays(1, &m_vaoID); 698 m_vaoID = 0; 699 } 700 if (m_vboID) 701 { 702 m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_vboID); 703 m_vboID = 0; 704 } 705 if (m_fboID) 706 { 707 m_context.getRenderContext().getFunctions().deleteFramebuffers(1, &m_fboID); 708 m_fboID = 0; 709 } 710 711 if (m_samplerProgram) 712 { 713 delete m_samplerProgram; 714 m_samplerProgram = DE_NULL; 715 } 716 if (m_alphaProgram) 717 { 718 delete m_alphaProgram; 719 m_alphaProgram = DE_NULL; 720 } 721 } 722 723 SampleMaskCase::IterateResult SampleMaskCase::iterate (void) 724 { 725 const tcu::ScopedLogSection section(m_testCtx.getLog(), "Iteration", (m_currentSample == -1) ? ("Verifying with zero mask") : (std::string() + "Verifying sample " + de::toString(m_currentSample + 1) + "/" + de::toString(m_samples))); 726 727 bool iterationOk; 728 729 // Mask only one sample, clear rest 730 731 updateTexture(m_currentSample); 732 733 // Verify only one sample set is in the texture 734 735 iterationOk = verifyTexture(m_currentSample); 736 if (!iterationOk) 737 m_allIterationsOk = false; 738 739 m_currentSample++; 740 if (m_currentSample < m_samples) 741 return CONTINUE; 742 743 // End result 744 745 if (m_allIterationsOk) 746 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 747 else if (m_flags & FLAGS_HIGH_BITS) 748 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Unused mask bits have effect"); 749 else 750 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Sample test failed"); 751 752 return STOP; 753 } 754 755 void SampleMaskCase::genSamplerProgram (void) 756 { 757 const char* const vertexShaderSource = "#version 310 es\n" 758 "in highp vec4 a_position;\n" 759 "void main (void)\n" 760 "{\n" 761 " gl_Position = a_position;\n" 762 "}\n"; 763 const char* const fragShaderSource = "#version 310 es\n" 764 "layout(location = 0) out highp vec4 fragColor;\n" 765 "uniform highp sampler2DMS u_sampler;\n" 766 "uniform highp int u_sample;\n" 767 "void main (void)\n" 768 "{\n" 769 " highp float correctCoverage = 0.0;\n" 770 " highp float incorrectCoverage = 0.0;\n" 771 " highp ivec2 texelPos = ivec2(int(floor(gl_FragCoord.x)), int(floor(gl_FragCoord.y)));\n" 772 "\n" 773 " for (int sampleNdx = 0; sampleNdx < ${NUMSAMPLES}; ++sampleNdx)\n" 774 " {\n" 775 " highp float sampleColor = texelFetch(u_sampler, texelPos, sampleNdx).r;\n" 776 " if (sampleNdx == u_sample)\n" 777 " correctCoverage += sampleColor;\n" 778 " else\n" 779 " incorrectCoverage += sampleColor;\n" 780 " }\n" 781 " fragColor = vec4(correctCoverage, incorrectCoverage, 0.0, 1.0);\n" 782 "}\n"; 783 const tcu::ScopedLogSection section (m_testCtx.getLog(), "GenerateSamplerShader", "Generate sampler shader"); 784 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 785 std::map<std::string, std::string> args; 786 787 args["NUMSAMPLES"] = de::toString(m_samples); 788 789 m_samplerProgram = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(vertexShaderSource) << glu::FragmentSource(tcu::StringTemplate(fragShaderSource).specialize(args))); 790 m_testCtx.getLog() << *m_samplerProgram; 791 792 if (!m_samplerProgram->isOk()) 793 throw tcu::TestError("Could not create sampler program."); 794 795 m_samplerProgramPosLoc = gl.getAttribLocation(m_samplerProgram->getProgram(), "a_position"); 796 m_samplerProgramSamplerLoc = gl.getUniformLocation(m_samplerProgram->getProgram(), "u_sampler"); 797 m_samplerProgramSampleNdxLoc = gl.getUniformLocation(m_samplerProgram->getProgram(), "u_sample"); 798 } 799 800 void SampleMaskCase::genAlphaProgram (void) 801 { 802 const char* const vertexShaderSource = "#version 310 es\n" 803 "in highp vec4 a_position;\n" 804 "out highp float v_alpha;\n" 805 "void main (void)\n" 806 "{\n" 807 " gl_Position = a_position;\n" 808 " v_alpha = (a_position.x * 0.5 + 0.5)*(a_position.y * 0.5 + 0.5);\n" 809 "}\n"; 810 const char* const fragShaderSource = "#version 310 es\n" 811 "layout(location = 0) out highp vec4 fragColor;\n" 812 "in mediump float v_alpha;\n" 813 "void main (void)\n" 814 "{\n" 815 " fragColor = vec4(1.0, 1.0, 1.0, v_alpha);\n" 816 "}\n"; 817 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 818 819 m_alphaProgram = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(vertexShaderSource) << glu::FragmentSource(fragShaderSource)); 820 821 if (!m_alphaProgram->isOk()) 822 { 823 m_testCtx.getLog() << *m_alphaProgram; 824 throw tcu::TestError("Could not create aplha program."); 825 } 826 827 m_alphaProgramPosLoc = gl.getAttribLocation(m_alphaProgram->getProgram(), "a_position"); 828 } 829 830 void SampleMaskCase::updateTexture (int sample) 831 { 832 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 833 834 // prepare draw 835 836 gl.bindFramebuffer(GL_FRAMEBUFFER, m_fboID); 837 gl.viewport(0, 0, m_canvasSize, m_canvasSize); 838 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f); 839 840 // clear all samples 841 842 m_testCtx.getLog() << tcu::TestLog::Message << "Clearing image" << tcu::TestLog::EndMessage; 843 gl.clear(GL_COLOR_BUFFER_BIT); 844 845 // set mask state 846 847 if (m_flags & FLAGS_HIGH_BITS) 848 { 849 const std::vector<deUint32> bitmask = genSetNthBitSampleMask(sample); 850 const std::vector<deUint32> effectiveMask = genAllSetToNthBitSampleMask(m_samples); 851 std::vector<deUint32> totalBitmask (effectiveMask.size()); 852 853 DE_ASSERT((int)totalBitmask.size() == m_effectiveSampleMaskWordCount); 854 855 // set some arbitrary high bits to non-effective bits 856 for (int wordNdx = 0; wordNdx < (int)effectiveMask.size(); ++wordNdx) 857 { 858 const deUint32 randomMask = (deUint32)deUint32Hash(wordNdx << 2 ^ sample); 859 const deUint32 sampleMask = (wordNdx < (int)bitmask.size()) ? (bitmask[wordNdx]) : (0); 860 const deUint32 maskMask = effectiveMask[wordNdx]; 861 862 totalBitmask[wordNdx] = (sampleMask & maskMask) | (randomMask & ~maskMask); 863 } 864 865 m_testCtx.getLog() << tcu::TestLog::Message << "Setting sample mask to 0b" << sampleMaskToString(totalBitmask, (int)totalBitmask.size() * 32) << tcu::TestLog::EndMessage; 866 867 gl.enable(GL_SAMPLE_MASK); 868 for (int wordNdx = 0; wordNdx < m_effectiveSampleMaskWordCount; ++wordNdx) 869 { 870 const GLbitfield wordmask = (wordNdx < (int)totalBitmask.size()) ? ((GLbitfield)(totalBitmask[wordNdx])) : (0); 871 gl.sampleMaski((deUint32)wordNdx, wordmask); 872 } 873 } 874 else 875 { 876 const std::vector<deUint32> bitmask = genSetNthBitSampleMask(sample); 877 DE_ASSERT((int)bitmask.size() <= m_effectiveSampleMaskWordCount); 878 879 m_testCtx.getLog() << tcu::TestLog::Message << "Setting sample mask to 0b" << sampleMaskToString(bitmask, m_samples) << tcu::TestLog::EndMessage; 880 881 gl.enable(GL_SAMPLE_MASK); 882 for (int wordNdx = 0; wordNdx < m_effectiveSampleMaskWordCount; ++wordNdx) 883 { 884 const GLbitfield wordmask = (wordNdx < (int)bitmask.size()) ? ((GLbitfield)(bitmask[wordNdx])) : (0); 885 gl.sampleMaski((deUint32)wordNdx, wordmask); 886 } 887 } 888 if (m_flags & FLAGS_ALPHA_TO_COVERAGE) 889 { 890 m_testCtx.getLog() << tcu::TestLog::Message << "Enabling alpha to coverage." << tcu::TestLog::EndMessage; 891 gl.enable(GL_SAMPLE_ALPHA_TO_COVERAGE); 892 } 893 if (m_flags & FLAGS_SAMPLE_COVERAGE) 894 { 895 m_testCtx.getLog() << tcu::TestLog::Message << "Enabling sample coverage. Varying sample coverage for grid cells." << tcu::TestLog::EndMessage; 896 gl.enable(GL_SAMPLE_COVERAGE); 897 } 898 899 // draw test pattern 900 901 m_testCtx.getLog() << tcu::TestLog::Message << "Drawing test grid" << tcu::TestLog::EndMessage; 902 903 gl.bindVertexArray (m_vaoID); 904 gl.bindBuffer (GL_ARRAY_BUFFER, m_vboID); 905 gl.vertexAttribPointer (m_alphaProgramPosLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL); 906 gl.enableVertexAttribArray (m_alphaProgramPosLoc); 907 GLU_EXPECT_NO_ERROR (gl.getError(), "vertexAttribPointer"); 908 909 gl.useProgram (m_alphaProgram->getProgram()); 910 911 for (int y = 0; y < m_gridsize; ++y) 912 for (int x = 0; x < m_gridsize; ++x) 913 { 914 if (m_flags & FLAGS_SAMPLE_COVERAGE) 915 gl.sampleCoverage((float)(y*m_gridsize + x) / float(m_gridsize*m_gridsize), GL_FALSE); 916 917 gl.drawArrays (GL_TRIANGLES, (y*m_gridsize + x) * 6, 6); 918 GLU_EXPECT_NO_ERROR (gl.getError(), "drawArrays"); 919 } 920 921 // clean state 922 923 gl.disableVertexAttribArray (m_alphaProgramPosLoc); 924 gl.useProgram (0); 925 gl.bindFramebuffer (GL_FRAMEBUFFER, 0); 926 gl.disable (GL_SAMPLE_MASK); 927 gl.disable (GL_SAMPLE_ALPHA_TO_COVERAGE); 928 gl.disable (GL_SAMPLE_COVERAGE); 929 GLU_EXPECT_NO_ERROR (gl.getError(), "clean"); 930 } 931 932 bool SampleMaskCase::verifyTexture (int sample) 933 { 934 tcu::Surface result (m_canvasSize, m_canvasSize); 935 tcu::Surface errorMask (m_canvasSize, m_canvasSize); 936 bool error = false; 937 938 tcu::clear(errorMask.getAccess(), tcu::RGBA::green().toVec()); 939 940 // Draw sample: 941 // Sample sampleNdx is set to red channel 942 // Other samples are set to green channel 943 drawSample(result, sample); 944 945 // Check surface contains only sampleNdx 946 for (int y = 0; y < m_canvasSize; ++y) 947 for (int x = 0; x < m_canvasSize; ++x) 948 { 949 const tcu::RGBA color = result.getPixel(x, y); 950 951 // Allow missing coverage with FLAGS_ALPHA_TO_COVERAGE and FLAGS_SAMPLE_COVERAGE, or if there are no samples enabled 952 const bool allowMissingCoverage = ((m_flags & (FLAGS_ALPHA_TO_COVERAGE | FLAGS_SAMPLE_COVERAGE)) != 0) || (sample == -1); 953 954 // disabled sample was written to 955 if (color.getGreen() != 0) 956 { 957 error = true; 958 errorMask.setPixel(x, y, tcu::RGBA::red()); 959 } 960 // enabled sample was not written to 961 else if (color.getRed() != 255 && !allowMissingCoverage) 962 { 963 error = true; 964 errorMask.setPixel(x, y, tcu::RGBA::red()); 965 } 966 } 967 968 if (error) 969 { 970 m_testCtx.getLog() 971 << tcu::TestLog::Message << "Image verification failed, disabled samples found." << tcu::TestLog::EndMessage 972 << tcu::TestLog::ImageSet("VerificationResult", "Result of rendering") 973 << tcu::TestLog::Image("Result", "Result", result) 974 << tcu::TestLog::Image("ErrorMask", "Error Mask", errorMask) 975 << tcu::TestLog::EndImageSet; 976 return false; 977 } 978 else 979 { 980 m_testCtx.getLog() << tcu::TestLog::Message << "Image verification ok, no disabled samples found." << tcu::TestLog::EndMessage; 981 return true; 982 } 983 } 984 985 void SampleMaskCase::drawSample (tcu::Surface& dst, int sample) 986 { 987 // Downsample using only one sample 988 static const tcu::Vec4 fullscreenQuad[] = 989 { 990 tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f), 991 tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f), 992 tcu::Vec4( 1.0f, 1.0f, 0.0f, 1.0f), 993 tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f) 994 }; 995 996 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 997 glu::Buffer vertexBuffer (m_context.getRenderContext()); 998 999 gl.bindTexture (GL_TEXTURE_2D_MULTISAMPLE, m_texID); 1000 gl.bindVertexArray (m_vaoID); 1001 1002 gl.bindBuffer (GL_ARRAY_BUFFER, *vertexBuffer); 1003 gl.bufferData (GL_ARRAY_BUFFER, sizeof(fullscreenQuad), &fullscreenQuad[0], GL_STATIC_DRAW); 1004 GLU_EXPECT_NO_ERROR (gl.getError(), "bufferData"); 1005 1006 gl.viewport (0, 0, m_canvasSize, m_canvasSize); 1007 gl.clearColor (0, 0, 0, 1); 1008 gl.clear (GL_COLOR_BUFFER_BIT); 1009 gl.vertexAttribPointer (m_samplerProgramPosLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL); 1010 gl.enableVertexAttribArray (m_samplerProgramPosLoc); 1011 GLU_EXPECT_NO_ERROR (gl.getError(), "vertexAttribPointer"); 1012 1013 gl.useProgram (m_samplerProgram->getProgram()); 1014 gl.uniform1i (m_samplerProgramSamplerLoc, 0); 1015 gl.uniform1i (m_samplerProgramSampleNdxLoc, (deInt32)sample); 1016 GLU_EXPECT_NO_ERROR (gl.getError(), "useprogram"); 1017 1018 m_testCtx.getLog() << tcu::TestLog::Message << "Reading from texture with sampler shader, u_sample = " << sample << tcu::TestLog::EndMessage; 1019 1020 gl.drawArrays (GL_TRIANGLE_STRIP, 0, 4); 1021 GLU_EXPECT_NO_ERROR (gl.getError(), "drawArrays"); 1022 1023 gl.disableVertexAttribArray (m_samplerProgramPosLoc); 1024 gl.useProgram (0); 1025 GLU_EXPECT_NO_ERROR (gl.getError(), "cleanup"); 1026 1027 gl.finish (); 1028 glu::readPixels (m_context.getRenderContext(), 0, 0, dst.getAccess()); 1029 GLU_EXPECT_NO_ERROR (gl.getError(), "readPixels"); 1030 } 1031 1032 class MultisampleTextureUsageCase : public TestCase 1033 { 1034 public: 1035 1036 enum TextureType 1037 { 1038 TEXTURE_COLOR_2D = 0, 1039 TEXTURE_COLOR_2D_ARRAY, 1040 TEXTURE_INT_2D, 1041 TEXTURE_INT_2D_ARRAY, 1042 TEXTURE_UINT_2D, 1043 TEXTURE_UINT_2D_ARRAY, 1044 TEXTURE_DEPTH_2D, 1045 TEXTURE_DEPTH_2D_ARRAY, 1046 1047 TEXTURE_LAST 1048 }; 1049 1050 MultisampleTextureUsageCase (Context& ctx, const char* name, const char* desc, int samples, TextureType type); 1051 ~MultisampleTextureUsageCase (void); 1052 1053 private: 1054 void init (void); 1055 void deinit (void); 1056 IterateResult iterate (void); 1057 1058 void genDrawShader (void); 1059 void genSamplerShader (void); 1060 1061 void renderToTexture (float value); 1062 void sampleTexture (tcu::Surface& dst, float value); 1063 bool verifyImage (const tcu::Surface& dst); 1064 1065 static const int s_textureSize = 256; 1066 static const int s_textureArraySize = 8; 1067 static const int s_textureLayer = 3; 1068 1069 const TextureType m_type; 1070 const int m_numSamples; 1071 1072 glw::GLuint m_fboID; 1073 glw::GLuint m_textureID; 1074 1075 glu::ShaderProgram* m_drawShader; 1076 glu::ShaderProgram* m_samplerShader; 1077 1078 const bool m_isColorFormat; 1079 const bool m_isSignedFormat; 1080 const bool m_isUnsignedFormat; 1081 const bool m_isDepthFormat; 1082 const bool m_isArrayType; 1083 }; 1084 1085 MultisampleTextureUsageCase::MultisampleTextureUsageCase (Context& ctx, const char* name, const char* desc, int samples, TextureType type) 1086 : TestCase (ctx, name, desc) 1087 , m_type (type) 1088 , m_numSamples (samples) 1089 , m_fboID (0) 1090 , m_textureID (0) 1091 , m_drawShader (DE_NULL) 1092 , m_samplerShader (DE_NULL) 1093 , m_isColorFormat (m_type == TEXTURE_COLOR_2D || m_type == TEXTURE_COLOR_2D_ARRAY) 1094 , m_isSignedFormat (m_type == TEXTURE_INT_2D || m_type == TEXTURE_INT_2D_ARRAY) 1095 , m_isUnsignedFormat(m_type == TEXTURE_UINT_2D || m_type == TEXTURE_UINT_2D_ARRAY) 1096 , m_isDepthFormat (m_type == TEXTURE_DEPTH_2D || m_type == TEXTURE_DEPTH_2D_ARRAY) 1097 , m_isArrayType (m_type == TEXTURE_COLOR_2D_ARRAY || m_type == TEXTURE_INT_2D_ARRAY || m_type == TEXTURE_UINT_2D_ARRAY || m_type == TEXTURE_DEPTH_2D_ARRAY) 1098 { 1099 DE_ASSERT(m_type < TEXTURE_LAST); 1100 } 1101 1102 MultisampleTextureUsageCase::~MultisampleTextureUsageCase (void) 1103 { 1104 deinit(); 1105 } 1106 1107 void MultisampleTextureUsageCase::init (void) 1108 { 1109 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 1110 const glw::GLenum internalFormat = (m_isColorFormat) ? (GL_R8) : (m_isSignedFormat) ? (GL_R8I) : (m_isUnsignedFormat) ? (GL_R8UI) : (m_isDepthFormat) ? (GL_DEPTH_COMPONENT32F) : (0); 1111 const glw::GLenum textureTarget = (m_isArrayType) ? (GL_TEXTURE_2D_MULTISAMPLE_ARRAY) : (GL_TEXTURE_2D_MULTISAMPLE); 1112 const glw::GLenum fboAttachment = (m_isDepthFormat) ? (GL_DEPTH_ATTACHMENT) : (GL_COLOR_ATTACHMENT0); 1113 1114 DE_ASSERT(internalFormat); 1115 1116 // requirements 1117 1118 if (m_isArrayType && !m_context.getContextInfo().isExtensionSupported("GL_OES_texture_storage_multisample_2d_array")) 1119 throw tcu::NotSupportedError("Test requires OES_texture_storage_multisample_2d_array extension"); 1120 if (m_context.getRenderTarget().getWidth() < s_textureSize || m_context.getRenderTarget().getHeight() < s_textureSize) 1121 throw tcu::NotSupportedError("render target size must be at least " + de::toString(static_cast<int>(s_textureSize)) + "x" + de::toString(static_cast<int>(s_textureSize))); 1122 1123 { 1124 glw::GLint maxSamples = 0; 1125 gl.getInternalformativ(textureTarget, internalFormat, GL_SAMPLES, 1, &maxSamples); 1126 1127 if (m_numSamples > maxSamples) 1128 throw tcu::NotSupportedError("Requested sample count is greater than supported"); 1129 1130 m_testCtx.getLog() << tcu::TestLog::Message << "Max sample count for " << glu::getTextureFormatStr(internalFormat) << ": " << maxSamples << tcu::TestLog::EndMessage; 1131 } 1132 1133 { 1134 GLint maxTextureSize = 0; 1135 gl.getIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize); 1136 1137 if (s_textureSize > maxTextureSize) 1138 throw tcu::NotSupportedError("Larger GL_MAX_TEXTURE_SIZE is required"); 1139 } 1140 1141 if (m_isArrayType) 1142 { 1143 GLint maxTextureLayers = 0; 1144 gl.getIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &maxTextureLayers); 1145 1146 if (s_textureArraySize > maxTextureLayers) 1147 throw tcu::NotSupportedError("Larger GL_MAX_ARRAY_TEXTURE_LAYERS is required"); 1148 } 1149 1150 // create texture 1151 1152 m_testCtx.getLog() << tcu::TestLog::Message << "Creating multisample " << ((m_isDepthFormat) ? ("depth") : ("")) << " texture" << ((m_isArrayType) ? (" array") : ("")) << tcu::TestLog::EndMessage; 1153 1154 gl.genTextures(1, &m_textureID); 1155 gl.bindTexture(textureTarget, m_textureID); 1156 GLU_EXPECT_NO_ERROR(gl.getError(), "bind texture"); 1157 1158 if (m_isArrayType) 1159 gl.texStorage3DMultisample(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, m_numSamples, internalFormat, s_textureSize, s_textureSize, s_textureArraySize, GL_FALSE); 1160 else 1161 gl.texStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_numSamples, internalFormat, s_textureSize, s_textureSize, GL_FALSE); 1162 GLU_EXPECT_NO_ERROR(gl.getError(), "texstorage"); 1163 1164 // create fbo for drawing 1165 1166 gl.genFramebuffers(1, &m_fboID); 1167 gl.bindFramebuffer(GL_FRAMEBUFFER, m_fboID); 1168 1169 if (m_isArrayType) 1170 { 1171 m_testCtx.getLog() << tcu::TestLog::Message << "Attaching multisample texture array layer " << static_cast<int>(s_textureLayer) << " to fbo" << tcu::TestLog::EndMessage; 1172 gl.framebufferTextureLayer(GL_FRAMEBUFFER, fboAttachment, m_textureID, 0, s_textureLayer); 1173 } 1174 else 1175 { 1176 m_testCtx.getLog() << tcu::TestLog::Message << "Attaching multisample texture to fbo" << tcu::TestLog::EndMessage; 1177 gl.framebufferTexture2D(GL_FRAMEBUFFER, fboAttachment, textureTarget, m_textureID, 0); 1178 } 1179 GLU_EXPECT_NO_ERROR(gl.getError(), "gen fbo"); 1180 1181 // create shader for rendering to fbo 1182 genDrawShader(); 1183 1184 // create shader for sampling the texture rendered to 1185 genSamplerShader(); 1186 } 1187 1188 void MultisampleTextureUsageCase::deinit (void) 1189 { 1190 if (m_textureID) 1191 { 1192 m_context.getRenderContext().getFunctions().deleteTextures(1, &m_textureID); 1193 m_textureID = 0; 1194 } 1195 1196 if (m_fboID) 1197 { 1198 m_context.getRenderContext().getFunctions().deleteFramebuffers(1, &m_fboID); 1199 m_fboID = 0; 1200 } 1201 1202 if (m_drawShader) 1203 { 1204 delete m_drawShader; 1205 m_drawShader = DE_NULL; 1206 } 1207 1208 if (m_samplerShader) 1209 { 1210 delete m_samplerShader; 1211 m_samplerShader = DE_NULL; 1212 } 1213 } 1214 1215 MultisampleTextureUsageCase::IterateResult MultisampleTextureUsageCase::iterate (void) 1216 { 1217 const tcu::ScopedLogSection section (m_testCtx.getLog(), "Sample", "Render to texture and sample texture"); 1218 tcu::Surface result (s_textureSize, s_textureSize); 1219 const float minValue = (m_isColorFormat || m_isDepthFormat) ? (0.0f) : (m_isSignedFormat) ? (-100.0f) : (m_isUnsignedFormat) ? (0.0f) : ( 1.0f); 1220 const float maxValue = (m_isColorFormat || m_isDepthFormat) ? (1.0f) : (m_isSignedFormat) ? ( 100.0f) : (m_isUnsignedFormat) ? (200.0f) : (-1.0f); 1221 de::Random rnd (deUint32Hash((deUint32)m_type)); 1222 const float rawValue = rnd.getFloat(minValue, maxValue); 1223 const float preparedValue = (m_isSignedFormat || m_isUnsignedFormat) ? (deFloatFloor(rawValue)) : (rawValue); 1224 1225 // draw to fbo with a random value 1226 1227 renderToTexture(preparedValue); 1228 1229 // draw from texture to front buffer 1230 1231 sampleTexture(result, preparedValue); 1232 1233 // result is ok? 1234 1235 if (verifyImage(result)) 1236 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 1237 else 1238 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed"); 1239 1240 return STOP; 1241 } 1242 1243 void MultisampleTextureUsageCase::genDrawShader (void) 1244 { 1245 const tcu::ScopedLogSection section(m_testCtx.getLog(), "RenderShader", "Generate render-to-texture shader"); 1246 1247 static const char* const vertexShaderSource = "#version 310 es\n" 1248 "in highp vec4 a_position;\n" 1249 "void main (void)\n" 1250 "{\n" 1251 " gl_Position = a_position;\n" 1252 "}\n"; 1253 static const char* const fragmentShaderSourceColor = "#version 310 es\n" 1254 "layout(location = 0) out highp ${OUTTYPE} fragColor;\n" 1255 "uniform highp float u_writeValue;\n" 1256 "void main (void)\n" 1257 "{\n" 1258 " fragColor = ${OUTTYPE}(vec4(u_writeValue, 1.0, 1.0, 1.0));\n" 1259 "}\n"; 1260 static const char* const fragmentShaderSourceDepth = "#version 310 es\n" 1261 "layout(location = 0) out highp vec4 fragColor;\n" 1262 "uniform highp float u_writeValue;\n" 1263 "void main (void)\n" 1264 "{\n" 1265 " fragColor = vec4(0.0, 0.0, 0.0, 1.0);\n" 1266 " gl_FragDepth = u_writeValue;\n" 1267 "}\n"; 1268 const char* const fragmentSource = (m_isDepthFormat) ? (fragmentShaderSourceDepth) : (fragmentShaderSourceColor); 1269 1270 std::map<std::string, std::string> fragmentArguments; 1271 1272 if (m_isColorFormat || m_isDepthFormat) 1273 fragmentArguments["OUTTYPE"] = "vec4"; 1274 else if (m_isSignedFormat) 1275 fragmentArguments["OUTTYPE"] = "ivec4"; 1276 else if (m_isUnsignedFormat) 1277 fragmentArguments["OUTTYPE"] = "uvec4"; 1278 else 1279 DE_ASSERT(DE_FALSE); 1280 1281 m_drawShader = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(vertexShaderSource) << glu::FragmentSource(tcu::StringTemplate(fragmentSource).specialize(fragmentArguments))); 1282 m_testCtx.getLog() << *m_drawShader; 1283 1284 if (!m_drawShader->isOk()) 1285 throw tcu::TestError("could not build shader"); 1286 } 1287 1288 void MultisampleTextureUsageCase::genSamplerShader (void) 1289 { 1290 const tcu::ScopedLogSection section(m_testCtx.getLog(), "SamplerShader", "Generate texture sampler shader"); 1291 1292 static const char* const vertexShaderSource = "#version 310 es\n" 1293 "in highp vec4 a_position;\n" 1294 "out highp float v_gradient;\n" 1295 "void main (void)\n" 1296 "{\n" 1297 " gl_Position = a_position;\n" 1298 " v_gradient = a_position.x * 0.5 + 0.5;\n" 1299 "}\n"; 1300 static const char* const fragmentShaderSource = "#version 310 es\n" 1301 "${EXTENSION_STATEMENT}" 1302 "layout(location = 0) out highp vec4 fragColor;\n" 1303 "uniform highp ${SAMPLERTYPE} u_sampler;\n" 1304 "uniform highp int u_maxSamples;\n" 1305 "uniform highp int u_layer;\n" 1306 "uniform highp float u_cmpValue;\n" 1307 "in highp float v_gradient;\n" 1308 "void main (void)\n" 1309 "{\n" 1310 " const highp vec4 okColor = vec4(0.0, 1.0, 0.0, 1.0);\n" 1311 " const highp vec4 failColor = vec4(1.0, 0.0, 0.0, 1.0);\n" 1312 " const highp float epsilon = ${EPSILON};\n" 1313 "\n" 1314 " highp int sampleNdx = clamp(int(floor(v_gradient * float(u_maxSamples))), 0, u_maxSamples-1);\n" 1315 " highp float value = float(texelFetch(u_sampler, ${FETCHPOS}, sampleNdx).r);\n" 1316 " fragColor = (abs(u_cmpValue - value) < epsilon) ? (okColor) : (failColor);\n" 1317 "}\n"; 1318 1319 std::map<std::string, std::string> fragmentArguments; 1320 1321 if (m_isArrayType) 1322 fragmentArguments["FETCHPOS"] = "ivec3(floor(gl_FragCoord.xy), u_layer)"; 1323 else 1324 fragmentArguments["FETCHPOS"] = "ivec2(floor(gl_FragCoord.xy))"; 1325 1326 if (m_isColorFormat || m_isDepthFormat) 1327 fragmentArguments["EPSILON"] = "0.1"; 1328 else 1329 fragmentArguments["EPSILON"] = "1.0"; 1330 1331 if (m_isArrayType) 1332 fragmentArguments["EXTENSION_STATEMENT"] = "#extension GL_OES_texture_storage_multisample_2d_array : require\n"; 1333 else 1334 fragmentArguments["EXTENSION_STATEMENT"] = ""; 1335 1336 switch (m_type) 1337 { 1338 case TEXTURE_COLOR_2D: fragmentArguments["SAMPLERTYPE"] = "sampler2DMS"; break; 1339 case TEXTURE_COLOR_2D_ARRAY: fragmentArguments["SAMPLERTYPE"] = "sampler2DMSArray"; break; 1340 case TEXTURE_INT_2D: fragmentArguments["SAMPLERTYPE"] = "isampler2DMS"; break; 1341 case TEXTURE_INT_2D_ARRAY: fragmentArguments["SAMPLERTYPE"] = "isampler2DMSArray"; break; 1342 case TEXTURE_UINT_2D: fragmentArguments["SAMPLERTYPE"] = "usampler2DMS"; break; 1343 case TEXTURE_UINT_2D_ARRAY: fragmentArguments["SAMPLERTYPE"] = "usampler2DMSArray"; break; 1344 case TEXTURE_DEPTH_2D: fragmentArguments["SAMPLERTYPE"] = "sampler2DMS"; break; 1345 case TEXTURE_DEPTH_2D_ARRAY: fragmentArguments["SAMPLERTYPE"] = "sampler2DMSArray"; break; 1346 1347 default: 1348 DE_ASSERT(DE_FALSE); 1349 } 1350 1351 m_samplerShader = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(vertexShaderSource) << glu::FragmentSource(tcu::StringTemplate(fragmentShaderSource).specialize(fragmentArguments))); 1352 m_testCtx.getLog() << *m_samplerShader; 1353 1354 if (!m_samplerShader->isOk()) 1355 throw tcu::TestError("could not build shader"); 1356 } 1357 1358 void MultisampleTextureUsageCase::renderToTexture (float value) 1359 { 1360 static const tcu::Vec4 fullscreenQuad[] = 1361 { 1362 tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f), 1363 tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f), 1364 tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f), 1365 tcu::Vec4( 1.0f, 1.0f, 0.0f, 1.0f), 1366 }; 1367 1368 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 1369 const int posLocation = gl.getAttribLocation(m_drawShader->getProgram(), "a_position"); 1370 const int valueLocation = gl.getUniformLocation(m_drawShader->getProgram(), "u_writeValue"); 1371 glu::Buffer vertexAttibBuffer (m_context.getRenderContext()); 1372 1373 m_testCtx.getLog() << tcu::TestLog::Message << "Filling multisample texture with value " << value << tcu::TestLog::EndMessage; 1374 1375 // upload data 1376 1377 gl.bindBuffer(GL_ARRAY_BUFFER, *vertexAttibBuffer); 1378 gl.bufferData(GL_ARRAY_BUFFER, sizeof(fullscreenQuad), fullscreenQuad[0].getPtr(), GL_STATIC_DRAW); 1379 GLU_EXPECT_NO_ERROR(gl.getError(), "bufferdata"); 1380 1381 // clear buffer 1382 1383 gl.bindFramebuffer(GL_FRAMEBUFFER, m_fboID); 1384 gl.viewport(0, 0, s_textureSize, s_textureSize); 1385 1386 if (m_isColorFormat) 1387 { 1388 const float clearColor[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; 1389 gl.clearBufferfv(GL_COLOR, 0, clearColor); 1390 } 1391 else if (m_isSignedFormat) 1392 { 1393 const deInt32 clearColor[4] = { 0, 0, 0, 0 }; 1394 gl.clearBufferiv(GL_COLOR, 0, clearColor); 1395 } 1396 else if (m_isUnsignedFormat) 1397 { 1398 const deUint32 clearColor[4] = { 0, 0, 0, 0 }; 1399 gl.clearBufferuiv(GL_COLOR, 0, clearColor); 1400 } 1401 else if (m_isDepthFormat) 1402 { 1403 const float clearDepth = 0.5f; 1404 gl.clearBufferfv(GL_DEPTH, 0, &clearDepth); 1405 } 1406 1407 GLU_EXPECT_NO_ERROR(gl.getError(), "clear buffer"); 1408 1409 // setup shader and draw 1410 1411 gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL); 1412 gl.enableVertexAttribArray(posLocation); 1413 1414 gl.useProgram(m_drawShader->getProgram()); 1415 gl.uniform1f(valueLocation, value); 1416 1417 GLU_EXPECT_NO_ERROR(gl.getError(), "setup draw"); 1418 1419 if (m_isDepthFormat) 1420 { 1421 gl.enable(GL_DEPTH_TEST); 1422 gl.depthFunc(GL_ALWAYS); 1423 } 1424 1425 gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4); 1426 GLU_EXPECT_NO_ERROR(gl.getError(), "draw"); 1427 1428 // clean state 1429 1430 if (m_isDepthFormat) 1431 gl.disable(GL_DEPTH_TEST); 1432 1433 gl.disableVertexAttribArray(posLocation); 1434 gl.useProgram(0); 1435 gl.bindFramebuffer(GL_FRAMEBUFFER, 0); 1436 GLU_EXPECT_NO_ERROR(gl.getError(), "clean"); 1437 } 1438 1439 void MultisampleTextureUsageCase::sampleTexture (tcu::Surface& dst, float value) 1440 { 1441 static const tcu::Vec4 fullscreenQuad[] = 1442 { 1443 tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f), 1444 tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f), 1445 tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f), 1446 tcu::Vec4( 1.0f, 1.0f, 0.0f, 1.0f), 1447 }; 1448 1449 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 1450 const int posLocation = gl.getAttribLocation(m_samplerShader->getProgram(), "a_position"); 1451 const int samplerLocation = gl.getUniformLocation(m_samplerShader->getProgram(), "u_sampler"); 1452 const int maxSamplesLocation = gl.getUniformLocation(m_samplerShader->getProgram(), "u_maxSamples"); 1453 const int layerLocation = gl.getUniformLocation(m_samplerShader->getProgram(), "u_layer"); 1454 const int valueLocation = gl.getUniformLocation(m_samplerShader->getProgram(), "u_cmpValue"); 1455 const glw::GLenum textureTarget = (m_isArrayType) ? (GL_TEXTURE_2D_MULTISAMPLE_ARRAY) : (GL_TEXTURE_2D_MULTISAMPLE); 1456 glu::Buffer vertexAttibBuffer (m_context.getRenderContext()); 1457 1458 m_testCtx.getLog() << tcu::TestLog::Message << "Sampling from texture." << tcu::TestLog::EndMessage; 1459 1460 // upload data 1461 1462 gl.bindBuffer(GL_ARRAY_BUFFER, *vertexAttibBuffer); 1463 gl.bufferData(GL_ARRAY_BUFFER, sizeof(fullscreenQuad), fullscreenQuad[0].getPtr(), GL_STATIC_DRAW); 1464 GLU_EXPECT_NO_ERROR(gl.getError(), "bufferdata"); 1465 1466 // clear 1467 1468 gl.viewport(0, 0, s_textureSize, s_textureSize); 1469 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f); 1470 gl.clear(GL_COLOR_BUFFER_BIT); 1471 1472 // setup shader and draw 1473 1474 gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL); 1475 gl.enableVertexAttribArray(posLocation); 1476 1477 gl.useProgram(m_samplerShader->getProgram()); 1478 gl.uniform1i(samplerLocation, 0); 1479 gl.uniform1i(maxSamplesLocation, m_numSamples); 1480 if (m_isArrayType) 1481 gl.uniform1i(layerLocation, s_textureLayer); 1482 gl.uniform1f(valueLocation, value); 1483 gl.bindTexture(textureTarget, m_textureID); 1484 GLU_EXPECT_NO_ERROR(gl.getError(), "setup draw"); 1485 1486 gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4); 1487 GLU_EXPECT_NO_ERROR(gl.getError(), "draw"); 1488 1489 // clean state 1490 1491 gl.disableVertexAttribArray(posLocation); 1492 gl.useProgram(0); 1493 GLU_EXPECT_NO_ERROR(gl.getError(), "clean"); 1494 1495 // read results 1496 gl.finish(); 1497 glu::readPixels(m_context.getRenderContext(), 0, 0, dst.getAccess()); 1498 } 1499 1500 bool MultisampleTextureUsageCase::verifyImage (const tcu::Surface& dst) 1501 { 1502 bool error = false; 1503 1504 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying image." << tcu::TestLog::EndMessage; 1505 1506 for (int y = 0; y < dst.getHeight(); ++y) 1507 for (int x = 0; x < dst.getWidth(); ++x) 1508 { 1509 const tcu::RGBA color = dst.getPixel(x, y); 1510 const int colorThresholdRed = 1 << (8 - m_context.getRenderTarget().getPixelFormat().redBits); 1511 const int colorThresholdGreen = 1 << (8 - m_context.getRenderTarget().getPixelFormat().greenBits); 1512 const int colorThresholdBlue = 1 << (8 - m_context.getRenderTarget().getPixelFormat().blueBits); 1513 1514 // only green is accepted 1515 if (color.getRed() > colorThresholdRed || color.getGreen() < 255 - colorThresholdGreen || color.getBlue() > colorThresholdBlue) 1516 error = true; 1517 } 1518 1519 if (error) 1520 { 1521 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid pixels found." << tcu::TestLog::EndMessage; 1522 m_testCtx.getLog() 1523 << tcu::TestLog::ImageSet("Verification result", "Result of rendering") 1524 << tcu::TestLog::Image("Result", "Result", dst) 1525 << tcu::TestLog::EndImageSet; 1526 1527 return false; 1528 } 1529 else 1530 { 1531 m_testCtx.getLog() << tcu::TestLog::Message << "No invalid pixels found." << tcu::TestLog::EndMessage; 1532 return true; 1533 } 1534 } 1535 1536 class NegativeFramebufferCase : public TestCase 1537 { 1538 public: 1539 enum CaseType 1540 { 1541 CASE_DIFFERENT_N_SAMPLES_TEX = 0, 1542 CASE_DIFFERENT_N_SAMPLES_RBO, 1543 CASE_DIFFERENT_FIXED_TEX, 1544 CASE_DIFFERENT_FIXED_RBO, 1545 CASE_NON_ZERO_LEVEL, 1546 1547 CASE_LAST 1548 }; 1549 1550 NegativeFramebufferCase (Context& context, const char* name, const char* desc, CaseType caseType); 1551 ~NegativeFramebufferCase (void); 1552 1553 private: 1554 void init (void); 1555 void deinit (void); 1556 IterateResult iterate (void); 1557 1558 void getFormatSamples (glw::GLenum target, std::vector<int>& samples); 1559 1560 const CaseType m_caseType; 1561 const int m_fboSize; 1562 const glw::GLenum m_internalFormat; 1563 1564 int m_numSamples0; // !< samples for attachment 0 1565 int m_numSamples1; // !< samples for attachment 1 1566 }; 1567 1568 NegativeFramebufferCase::NegativeFramebufferCase (Context& context, const char* name, const char* desc, CaseType caseType) 1569 : TestCase (context, name, desc) 1570 , m_caseType (caseType) 1571 , m_fboSize (64) 1572 , m_internalFormat (GL_RGBA8) 1573 , m_numSamples0 (-1) 1574 , m_numSamples1 (-1) 1575 { 1576 } 1577 1578 NegativeFramebufferCase::~NegativeFramebufferCase (void) 1579 { 1580 deinit(); 1581 } 1582 1583 void NegativeFramebufferCase::init (void) 1584 { 1585 const bool colorAttachmentTexture = (m_caseType == CASE_DIFFERENT_N_SAMPLES_TEX) || (m_caseType == CASE_DIFFERENT_FIXED_TEX); 1586 const bool colorAttachmentRbo = (m_caseType == CASE_DIFFERENT_N_SAMPLES_RBO) || (m_caseType == CASE_DIFFERENT_FIXED_RBO); 1587 const bool useDifferentSampleCounts= (m_caseType == CASE_DIFFERENT_N_SAMPLES_TEX) || (m_caseType == CASE_DIFFERENT_N_SAMPLES_RBO); 1588 std::vector<int> textureSamples; 1589 std::vector<int> rboSamples; 1590 1591 getFormatSamples(GL_TEXTURE_2D_MULTISAMPLE, textureSamples); 1592 getFormatSamples(GL_RENDERBUFFER, rboSamples); 1593 1594 TCU_CHECK(!textureSamples.empty()); 1595 TCU_CHECK(!rboSamples.empty()); 1596 1597 // select sample counts 1598 1599 if (useDifferentSampleCounts) 1600 { 1601 if (colorAttachmentTexture) 1602 { 1603 m_numSamples0 = textureSamples[0]; 1604 1605 if (textureSamples.size() >= 2) 1606 m_numSamples1 = textureSamples[1]; 1607 else 1608 throw tcu::NotSupportedError("Test requires multiple supported sample counts"); 1609 } 1610 else if (colorAttachmentRbo) 1611 { 1612 for (int texNdx = 0; texNdx < (int)textureSamples.size(); ++texNdx) 1613 for (int rboNdx = 0; rboNdx < (int)rboSamples.size(); ++rboNdx) 1614 { 1615 if (textureSamples[texNdx] != rboSamples[rboNdx]) 1616 { 1617 m_numSamples0 = textureSamples[texNdx]; 1618 m_numSamples1 = rboSamples[rboNdx]; 1619 return; 1620 } 1621 } 1622 1623 throw tcu::NotSupportedError("Test requires multiple supported sample counts"); 1624 } 1625 else 1626 DE_ASSERT(DE_FALSE); 1627 } 1628 else 1629 { 1630 if (colorAttachmentTexture) 1631 { 1632 m_numSamples0 = textureSamples[0]; 1633 m_numSamples1 = textureSamples[0]; 1634 } 1635 else if (colorAttachmentRbo) 1636 { 1637 for (int texNdx = 0; texNdx < (int)textureSamples.size(); ++texNdx) 1638 for (int rboNdx = 0; rboNdx < (int)rboSamples.size(); ++rboNdx) 1639 { 1640 if (textureSamples[texNdx] == rboSamples[rboNdx]) 1641 { 1642 m_numSamples0 = textureSamples[texNdx]; 1643 m_numSamples1 = rboSamples[rboNdx]; 1644 return; 1645 } 1646 } 1647 1648 throw tcu::NotSupportedError("Test requires a sample count supported in both rbo and texture"); 1649 } 1650 else 1651 { 1652 m_numSamples0 = textureSamples[0]; 1653 } 1654 } 1655 } 1656 1657 void NegativeFramebufferCase::deinit (void) 1658 { 1659 } 1660 1661 NegativeFramebufferCase::IterateResult NegativeFramebufferCase::iterate (void) 1662 { 1663 const bool colorAttachmentTexture = (m_caseType == CASE_DIFFERENT_N_SAMPLES_TEX) || (m_caseType == CASE_DIFFERENT_FIXED_TEX); 1664 const bool colorAttachmentRbo = (m_caseType == CASE_DIFFERENT_N_SAMPLES_RBO) || (m_caseType == CASE_DIFFERENT_FIXED_RBO); 1665 const glw::GLboolean fixedSampleLocations0 = (m_caseType == CASE_DIFFERENT_N_SAMPLES_RBO) ? (GL_TRUE) : (GL_FALSE); 1666 const glw::GLboolean fixedSampleLocations1 = ((m_caseType == CASE_DIFFERENT_FIXED_TEX) || (m_caseType == CASE_DIFFERENT_FIXED_RBO)) ? (GL_TRUE) : (GL_FALSE); 1667 glu::CallLogWrapper gl (m_context.getRenderContext().getFunctions(), m_testCtx.getLog()); 1668 glw::GLuint fboId = 0; 1669 glw::GLuint rboId = 0; 1670 glw::GLuint tex0Id = 0; 1671 glw::GLuint tex1Id = 0; 1672 1673 bool testFailed = false; 1674 1675 gl.enableLogging(true); 1676 1677 try 1678 { 1679 gl.glGenFramebuffers(1, &fboId); 1680 gl.glBindFramebuffer(GL_FRAMEBUFFER, fboId); 1681 GLU_EXPECT_NO_ERROR(gl.glGetError(), "gen fbo"); 1682 1683 gl.glGenTextures(1, &tex0Id); 1684 gl.glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, tex0Id); 1685 gl.glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_numSamples0, m_internalFormat, m_fboSize, m_fboSize, fixedSampleLocations0); 1686 GLU_EXPECT_NO_ERROR(gl.glGetError(), "gen texture 0"); 1687 1688 if (m_caseType == CASE_NON_ZERO_LEVEL) 1689 { 1690 glw::GLenum error; 1691 1692 // attaching non-zero level generates invalid value 1693 gl.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, tex0Id, 5); 1694 error = gl.glGetError(); 1695 1696 if (error != GL_INVALID_VALUE) 1697 { 1698 m_testCtx.getLog() << tcu::TestLog::Message << "ERROR! Expected GL_INVALID_VALUE, got " << glu::getErrorStr(error) << tcu::TestLog::EndMessage; 1699 testFailed = true; 1700 } 1701 } 1702 else 1703 { 1704 gl.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, tex0Id, 0); 1705 GLU_EXPECT_NO_ERROR(gl.glGetError(), "attach to c0"); 1706 1707 if (colorAttachmentTexture) 1708 { 1709 gl.glGenTextures(1, &tex1Id); 1710 gl.glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, tex1Id); 1711 gl.glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_numSamples1, m_internalFormat, m_fboSize, m_fboSize, fixedSampleLocations1); 1712 GLU_EXPECT_NO_ERROR(gl.glGetError(), "gen texture 1"); 1713 1714 gl.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D_MULTISAMPLE, tex1Id, 0); 1715 GLU_EXPECT_NO_ERROR(gl.glGetError(), "attach to c1"); 1716 } 1717 else if (colorAttachmentRbo) 1718 { 1719 gl.glGenRenderbuffers(1, &rboId); 1720 gl.glBindRenderbuffer(GL_RENDERBUFFER, rboId); 1721 gl.glRenderbufferStorageMultisample(GL_RENDERBUFFER, m_numSamples1, m_internalFormat, m_fboSize, m_fboSize); 1722 GLU_EXPECT_NO_ERROR(gl.glGetError(), "gen rb"); 1723 1724 gl.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_RENDERBUFFER, rboId); 1725 GLU_EXPECT_NO_ERROR(gl.glGetError(), "attach to c1"); 1726 } 1727 else 1728 DE_ASSERT(DE_FALSE); 1729 1730 // should not be complete 1731 { 1732 glw::GLenum status = gl.glCheckFramebufferStatus(GL_FRAMEBUFFER); 1733 1734 if (status != GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE) 1735 { 1736 m_testCtx.getLog() << tcu::TestLog::Message << "ERROR! Expected GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE, got " << glu::getFramebufferStatusName(status) << tcu::TestLog::EndMessage; 1737 testFailed = true; 1738 } 1739 } 1740 } 1741 } 1742 catch (...) 1743 { 1744 gl.glDeleteFramebuffers(1, &fboId); 1745 gl.glDeleteRenderbuffers(1, &rboId); 1746 gl.glDeleteTextures(1, &tex0Id); 1747 gl.glDeleteTextures(1, &tex1Id); 1748 throw; 1749 } 1750 1751 gl.glDeleteFramebuffers(1, &fboId); 1752 gl.glDeleteRenderbuffers(1, &rboId); 1753 gl.glDeleteTextures(1, &tex0Id); 1754 gl.glDeleteTextures(1, &tex1Id); 1755 1756 if (testFailed) 1757 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got wrong error code"); 1758 else 1759 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 1760 return STOP; 1761 } 1762 1763 void NegativeFramebufferCase::getFormatSamples (glw::GLenum target, std::vector<int>& samples) 1764 { 1765 const glw::Functions gl = m_context.getRenderContext().getFunctions(); 1766 int sampleCount = 0; 1767 1768 gl.getInternalformativ(target, m_internalFormat, GL_NUM_SAMPLE_COUNTS, 1, &sampleCount); 1769 samples.resize(sampleCount); 1770 1771 if (sampleCount > 0) 1772 { 1773 gl.getInternalformativ(target, m_internalFormat, GL_SAMPLES, sampleCount, &samples[0]); 1774 GLU_EXPECT_NO_ERROR(gl.getError(), "get max samples"); 1775 } 1776 } 1777 1778 class NegativeTexParameterCase : public TestCase 1779 { 1780 public: 1781 enum TexParam 1782 { 1783 TEXTURE_MIN_FILTER = 0, 1784 TEXTURE_MAG_FILTER, 1785 TEXTURE_WRAP_S, 1786 TEXTURE_WRAP_T, 1787 TEXTURE_WRAP_R, 1788 TEXTURE_MIN_LOD, 1789 TEXTURE_MAX_LOD, 1790 TEXTURE_COMPARE_MODE, 1791 TEXTURE_COMPARE_FUNC, 1792 TEXTURE_BASE_LEVEL, 1793 1794 TEXTURE_LAST 1795 }; 1796 1797 NegativeTexParameterCase (Context& context, const char* name, const char* desc, TexParam param); 1798 ~NegativeTexParameterCase (void); 1799 1800 private: 1801 void init (void); 1802 void deinit (void); 1803 IterateResult iterate (void); 1804 1805 glw::GLenum getParamGLEnum (void) const; 1806 glw::GLint getParamValue (void) const; 1807 glw::GLenum getExpectedError (void) const; 1808 1809 const TexParam m_texParam; 1810 int m_iteration; 1811 }; 1812 1813 NegativeTexParameterCase::NegativeTexParameterCase (Context& context, const char* name, const char* desc, TexParam param) 1814 : TestCase (context, name, desc) 1815 , m_texParam (param) 1816 , m_iteration (0) 1817 { 1818 DE_ASSERT(param < TEXTURE_LAST); 1819 } 1820 1821 NegativeTexParameterCase::~NegativeTexParameterCase (void) 1822 { 1823 deinit(); 1824 } 1825 1826 void NegativeTexParameterCase::init (void) 1827 { 1828 // default value 1829 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 1830 } 1831 1832 void NegativeTexParameterCase::deinit (void) 1833 { 1834 } 1835 1836 NegativeTexParameterCase::IterateResult NegativeTexParameterCase::iterate (void) 1837 { 1838 static const struct TextureType 1839 { 1840 const char* name; 1841 glw::GLenum target; 1842 glw::GLenum internalFormat; 1843 bool isArrayType; 1844 } types[] = 1845 { 1846 { "color", GL_TEXTURE_2D_MULTISAMPLE, GL_RGBA8, false }, 1847 { "color array", GL_TEXTURE_2D_MULTISAMPLE_ARRAY, GL_RGBA8, true }, 1848 { "signed integer", GL_TEXTURE_2D_MULTISAMPLE, GL_R8I, false }, 1849 { "signed integer array", GL_TEXTURE_2D_MULTISAMPLE_ARRAY, GL_R8I, true }, 1850 { "unsigned integer", GL_TEXTURE_2D_MULTISAMPLE, GL_R8UI, false }, 1851 { "unsigned integer array", GL_TEXTURE_2D_MULTISAMPLE_ARRAY, GL_R8UI, true }, 1852 }; 1853 1854 const tcu::ScopedLogSection scope(m_testCtx.getLog(), "Iteration", std::string() + "Testing parameter with " + types[m_iteration].name + " texture"); 1855 1856 if (types[m_iteration].isArrayType && !m_context.getContextInfo().isExtensionSupported("GL_OES_texture_storage_multisample_2d_array")) 1857 m_testCtx.getLog() << tcu::TestLog::Message << "GL_OES_texture_storage_multisample_2d_array not supported, skipping target" << tcu::TestLog::EndMessage; 1858 else 1859 { 1860 glu::CallLogWrapper gl (m_context.getRenderContext().getFunctions(), m_testCtx.getLog()); 1861 glu::Texture texture (m_context.getRenderContext()); 1862 glw::GLenum error; 1863 1864 gl.enableLogging(true); 1865 1866 // gen texture 1867 1868 gl.glBindTexture(types[m_iteration].target, *texture); 1869 1870 if (types[m_iteration].isArrayType) 1871 gl.glTexStorage3DMultisample(types[m_iteration].target, 1, types[m_iteration].internalFormat, 16, 16, 16, GL_FALSE); 1872 else 1873 gl.glTexStorage2DMultisample(types[m_iteration].target, 1, types[m_iteration].internalFormat, 16, 16, GL_FALSE); 1874 GLU_EXPECT_NO_ERROR(gl.glGetError(), "setup texture"); 1875 1876 // set param 1877 1878 gl.glTexParameteri(types[m_iteration].target, getParamGLEnum(), getParamValue()); 1879 error = gl.glGetError(); 1880 1881 // expect failure 1882 1883 if (error != getExpectedError()) 1884 { 1885 m_testCtx.getLog() << tcu::TestLog::Message << "Got unexpected error: " << glu::getErrorStr(error) << ", expected: " << glu::getErrorStr(getExpectedError()) << tcu::TestLog::EndMessage; 1886 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got wrong error code"); 1887 } 1888 } 1889 1890 if (++m_iteration < DE_LENGTH_OF_ARRAY(types)) 1891 return CONTINUE; 1892 return STOP; 1893 } 1894 1895 glw::GLenum NegativeTexParameterCase::getParamGLEnum (void) const 1896 { 1897 switch (m_texParam) 1898 { 1899 case TEXTURE_MIN_FILTER: return GL_TEXTURE_MIN_FILTER; 1900 case TEXTURE_MAG_FILTER: return GL_TEXTURE_MAG_FILTER; 1901 case TEXTURE_WRAP_S: return GL_TEXTURE_WRAP_S; 1902 case TEXTURE_WRAP_T: return GL_TEXTURE_WRAP_T; 1903 case TEXTURE_WRAP_R: return GL_TEXTURE_WRAP_R; 1904 case TEXTURE_MIN_LOD: return GL_TEXTURE_MIN_LOD; 1905 case TEXTURE_MAX_LOD: return GL_TEXTURE_MAX_LOD; 1906 case TEXTURE_COMPARE_MODE: return GL_TEXTURE_COMPARE_MODE; 1907 case TEXTURE_COMPARE_FUNC: return GL_TEXTURE_COMPARE_FUNC; 1908 case TEXTURE_BASE_LEVEL: return GL_TEXTURE_BASE_LEVEL; 1909 default: 1910 DE_ASSERT(DE_FALSE); 1911 return 0; 1912 } 1913 } 1914 1915 glw::GLint NegativeTexParameterCase::getParamValue (void) const 1916 { 1917 switch (m_texParam) 1918 { 1919 case TEXTURE_MIN_FILTER: return GL_LINEAR; 1920 case TEXTURE_MAG_FILTER: return GL_LINEAR; 1921 case TEXTURE_WRAP_S: return GL_CLAMP_TO_EDGE; 1922 case TEXTURE_WRAP_T: return GL_CLAMP_TO_EDGE; 1923 case TEXTURE_WRAP_R: return GL_CLAMP_TO_EDGE; 1924 case TEXTURE_MIN_LOD: return 1; 1925 case TEXTURE_MAX_LOD: return 5; 1926 case TEXTURE_COMPARE_MODE: return GL_NONE; 1927 case TEXTURE_COMPARE_FUNC: return GL_NOTEQUAL; 1928 case TEXTURE_BASE_LEVEL: return 2; 1929 default: 1930 DE_ASSERT(DE_FALSE); 1931 return 0; 1932 } 1933 } 1934 1935 glw::GLenum NegativeTexParameterCase::getExpectedError (void) const 1936 { 1937 switch (m_texParam) 1938 { 1939 case TEXTURE_MIN_FILTER: return GL_INVALID_ENUM; 1940 case TEXTURE_MAG_FILTER: return GL_INVALID_ENUM; 1941 case TEXTURE_WRAP_S: return GL_INVALID_ENUM; 1942 case TEXTURE_WRAP_T: return GL_INVALID_ENUM; 1943 case TEXTURE_WRAP_R: return GL_INVALID_ENUM; 1944 case TEXTURE_MIN_LOD: return GL_INVALID_ENUM; 1945 case TEXTURE_MAX_LOD: return GL_INVALID_ENUM; 1946 case TEXTURE_COMPARE_MODE: return GL_INVALID_ENUM; 1947 case TEXTURE_COMPARE_FUNC: return GL_INVALID_ENUM; 1948 case TEXTURE_BASE_LEVEL: return GL_INVALID_OPERATION; 1949 default: 1950 DE_ASSERT(DE_FALSE); 1951 return 0; 1952 } 1953 } 1954 1955 class NegativeTexureSampleCase : public TestCase 1956 { 1957 public: 1958 enum SampleCountParam 1959 { 1960 SAMPLECOUNT_HIGH = 0, 1961 SAMPLECOUNT_ZERO, 1962 1963 SAMPLECOUNT_LAST 1964 }; 1965 1966 NegativeTexureSampleCase (Context& context, const char* name, const char* desc, SampleCountParam param); 1967 private: 1968 IterateResult iterate (void); 1969 1970 const SampleCountParam m_sampleParam; 1971 }; 1972 1973 NegativeTexureSampleCase::NegativeTexureSampleCase (Context& context, const char* name, const char* desc, SampleCountParam param) 1974 : TestCase (context, name, desc) 1975 , m_sampleParam (param) 1976 { 1977 DE_ASSERT(param < SAMPLECOUNT_LAST); 1978 } 1979 1980 NegativeTexureSampleCase::IterateResult NegativeTexureSampleCase::iterate (void) 1981 { 1982 const glw::GLenum expectedError = (m_sampleParam == SAMPLECOUNT_HIGH) ? (GL_INVALID_OPERATION) : (GL_INVALID_VALUE); 1983 glu::CallLogWrapper gl (m_context.getRenderContext().getFunctions(), m_testCtx.getLog()); 1984 glu::Texture texture (m_context.getRenderContext()); 1985 glw::GLenum error; 1986 int samples = -1; 1987 1988 gl.enableLogging(true); 1989 1990 // calc samples 1991 1992 if (m_sampleParam == SAMPLECOUNT_HIGH) 1993 { 1994 int maxSamples = 0; 1995 1996 gl.glGetInternalformativ(GL_TEXTURE_2D_MULTISAMPLE, GL_RGBA8, GL_SAMPLES, 1, &maxSamples); 1997 GLU_EXPECT_NO_ERROR(gl.glGetError(), "glGetInternalformativ"); 1998 1999 samples = maxSamples + 1; 2000 } 2001 else if (m_sampleParam == SAMPLECOUNT_ZERO) 2002 samples = 0; 2003 else 2004 DE_ASSERT(DE_FALSE); 2005 2006 // create texture with bad values 2007 2008 gl.glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, *texture); 2009 gl.glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, GL_RGBA8, 64, 64, GL_FALSE); 2010 error = gl.glGetError(); 2011 2012 // expect failure 2013 2014 if (error == expectedError) 2015 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 2016 else 2017 { 2018 m_testCtx.getLog() << tcu::TestLog::Message << "Got unexpected error: " << glu::getErrorStr(error) << ", expected: " << glu::getErrorStr(expectedError) << tcu::TestLog::EndMessage; 2019 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got wrong error code"); 2020 } 2021 2022 return STOP; 2023 } 2024 2025 2026 } // anonymous 2027 2028 TextureMultisampleTests::TextureMultisampleTests (Context& context) 2029 : TestCaseGroup(context, "multisample", "Multisample texture tests") 2030 { 2031 } 2032 2033 TextureMultisampleTests::~TextureMultisampleTests (void) 2034 { 2035 } 2036 2037 void TextureMultisampleTests::init (void) 2038 { 2039 static const int sampleCounts[] = { 1, 2, 3, 4, 8, 10, 12, 13, 16, 64 }; 2040 2041 static const struct TextureType 2042 { 2043 const char* name; 2044 MultisampleTextureUsageCase::TextureType type; 2045 } textureTypes[] = 2046 { 2047 { "texture_color_2d", MultisampleTextureUsageCase::TEXTURE_COLOR_2D }, 2048 { "texture_color_2d_array", MultisampleTextureUsageCase::TEXTURE_COLOR_2D_ARRAY }, 2049 { "texture_int_2d", MultisampleTextureUsageCase::TEXTURE_INT_2D }, 2050 { "texture_int_2d_array", MultisampleTextureUsageCase::TEXTURE_INT_2D_ARRAY }, 2051 { "texture_uint_2d", MultisampleTextureUsageCase::TEXTURE_UINT_2D }, 2052 { "texture_uint_2d_array", MultisampleTextureUsageCase::TEXTURE_UINT_2D_ARRAY }, 2053 { "texture_depth_2d", MultisampleTextureUsageCase::TEXTURE_DEPTH_2D }, 2054 { "texture_depth_2d_array", MultisampleTextureUsageCase::TEXTURE_DEPTH_2D_ARRAY }, 2055 }; 2056 2057 // .samples_x 2058 for (int sampleNdx = 0; sampleNdx < DE_LENGTH_OF_ARRAY(sampleCounts); ++sampleNdx) 2059 { 2060 tcu::TestCaseGroup* const sampleGroup = new tcu::TestCaseGroup(m_testCtx, (std::string("samples_") + de::toString(sampleCounts[sampleNdx])).c_str(), "Test with N samples"); 2061 addChild(sampleGroup); 2062 2063 // position query works 2064 sampleGroup->addChild(new SamplePosRasterizationTest(m_context, "sample_position", "test SAMPLE_POSITION", sampleCounts[sampleNdx])); 2065 2066 // sample mask is ANDed properly 2067 sampleGroup->addChild(new SampleMaskCase(m_context, "sample_mask_only", "Test with SampleMask only", sampleCounts[sampleNdx], SampleMaskCase::FLAGS_NONE)); 2068 sampleGroup->addChild(new SampleMaskCase(m_context, "sample_mask_and_alpha_to_coverage", "Test with SampleMask and alpha to coverage", sampleCounts[sampleNdx], SampleMaskCase::FLAGS_ALPHA_TO_COVERAGE)); 2069 sampleGroup->addChild(new SampleMaskCase(m_context, "sample_mask_and_sample_coverage", "Test with SampleMask and sample coverage", sampleCounts[sampleNdx], SampleMaskCase::FLAGS_SAMPLE_COVERAGE)); 2070 sampleGroup->addChild(new SampleMaskCase(m_context, "sample_mask_and_sample_coverage_and_alpha_to_coverage", "Test with SampleMask, sample coverage, and alpha to coverage", sampleCounts[sampleNdx], SampleMaskCase::FLAGS_ALPHA_TO_COVERAGE | SampleMaskCase::FLAGS_SAMPLE_COVERAGE)); 2071 2072 // high bits cause no unexpected behavior 2073 sampleGroup->addChild(new SampleMaskCase(m_context, "sample_mask_non_effective_bits", "Test with SampleMask, set higher bits than sample count", sampleCounts[sampleNdx], SampleMaskCase::FLAGS_HIGH_BITS)); 2074 2075 // usage 2076 for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(textureTypes); ++typeNdx) 2077 sampleGroup->addChild(new MultisampleTextureUsageCase(m_context, (std::string("use_") + textureTypes[typeNdx].name).c_str(), textureTypes[typeNdx].name, sampleCounts[sampleNdx], textureTypes[typeNdx].type)); 2078 } 2079 2080 // .negative 2081 { 2082 tcu::TestCaseGroup* const negativeGroup = new tcu::TestCaseGroup(m_testCtx, "negative", "Negative tests"); 2083 addChild(negativeGroup); 2084 2085 negativeGroup->addChild(new NegativeFramebufferCase (m_context, "fbo_attach_different_sample_count_tex_tex", "Attach different sample counts", NegativeFramebufferCase::CASE_DIFFERENT_N_SAMPLES_TEX)); 2086 negativeGroup->addChild(new NegativeFramebufferCase (m_context, "fbo_attach_different_sample_count_tex_rbo", "Attach different sample counts", NegativeFramebufferCase::CASE_DIFFERENT_N_SAMPLES_RBO)); 2087 negativeGroup->addChild(new NegativeFramebufferCase (m_context, "fbo_attach_different_fixed_state_tex_tex", "Attach fixed and non fixed", NegativeFramebufferCase::CASE_DIFFERENT_FIXED_TEX)); 2088 negativeGroup->addChild(new NegativeFramebufferCase (m_context, "fbo_attach_different_fixed_state_tex_rbo", "Attach fixed and non fixed", NegativeFramebufferCase::CASE_DIFFERENT_FIXED_RBO)); 2089 negativeGroup->addChild(new NegativeFramebufferCase (m_context, "fbo_attach_non_zero_level", "Attach non-zero level", NegativeFramebufferCase::CASE_NON_ZERO_LEVEL)); 2090 negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_min_filter", "set TEXTURE_MIN_FILTER", NegativeTexParameterCase::TEXTURE_MIN_FILTER)); 2091 negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_mag_filter", "set TEXTURE_MAG_FILTER", NegativeTexParameterCase::TEXTURE_MAG_FILTER)); 2092 negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_wrap_s", "set TEXTURE_WRAP_S", NegativeTexParameterCase::TEXTURE_WRAP_S)); 2093 negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_wrap_t", "set TEXTURE_WRAP_T", NegativeTexParameterCase::TEXTURE_WRAP_T)); 2094 negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_wrap_r", "set TEXTURE_WRAP_R", NegativeTexParameterCase::TEXTURE_WRAP_R)); 2095 negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_min_lod", "set TEXTURE_MIN_LOD", NegativeTexParameterCase::TEXTURE_MIN_LOD)); 2096 negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_max_lod", "set TEXTURE_MAX_LOD", NegativeTexParameterCase::TEXTURE_MAX_LOD)); 2097 negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_compare_mode", "set TEXTURE_COMPARE_MODE", NegativeTexParameterCase::TEXTURE_COMPARE_MODE)); 2098 negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_compare_func", "set TEXTURE_COMPARE_FUNC", NegativeTexParameterCase::TEXTURE_COMPARE_FUNC)); 2099 negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_base_level", "set TEXTURE_BASE_LEVEL", NegativeTexParameterCase::TEXTURE_BASE_LEVEL)); 2100 negativeGroup->addChild(new NegativeTexureSampleCase(m_context, "texture_high_sample_count", "TexStorage with high numSamples", NegativeTexureSampleCase::SAMPLECOUNT_HIGH)); 2101 negativeGroup->addChild(new NegativeTexureSampleCase(m_context, "texture_zero_sample_count", "TexStorage with zero numSamples", NegativeTexureSampleCase::SAMPLECOUNT_ZERO)); 2102 } 2103 } 2104 2105 } // Functional 2106 } // gles31 2107 } // deqp 2108