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