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 44using namespace glw; 45 46namespace deqp 47{ 48namespace gles31 49{ 50namespace Functional 51{ 52namespace 53{ 54 55using tcu::RasterizationArguments; 56using tcu::TriangleSceneSpec; 57 58static 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 *//*--------------------------------------------------------------------*/ 84static 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 *//*--------------------------------------------------------------------*/ 95static 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 *//*--------------------------------------------------------------------*/ 112static 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 126std::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 137class SamplePosRasterizationTest : public TestCase 138{ 139public: 140 SamplePosRasterizationTest (Context& context, const char* name, const char* desc, int samples); 141 ~SamplePosRasterizationTest (void); 142 143private: 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 179SamplePosRasterizationTest::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 196SamplePosRasterizationTest::~SamplePosRasterizationTest (void) 197{ 198 deinit(); 199} 200 201void 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 295void 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 322SamplePosRasterizationTest::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 339void 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 421void 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 451bool 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 475void 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 522void 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 543class SampleMaskCase : public TestCase 544{ 545public: 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 557private: 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 glw::GLint getMaxConformantSampleCount (glw::GLenum target, glw::GLenum internalFormat); 569 570 const int m_samples; 571 const int m_canvasSize; 572 const int m_gridsize; 573 const int m_effectiveSampleMaskWordCount; 574 575 int m_flags; 576 int m_currentSample; 577 int m_allIterationsOk; 578 579 glw::GLuint m_texID; 580 glw::GLuint m_vaoID; 581 glw::GLuint m_vboID; 582 glw::GLuint m_fboID; 583 584 const glu::ShaderProgram* m_samplerProgram; 585 glw::GLint m_samplerProgramPosLoc; 586 glw::GLint m_samplerProgramSamplerLoc; 587 glw::GLint m_samplerProgramSampleNdxLoc; 588 589 const glu::ShaderProgram* m_alphaProgram; 590 glw::GLint m_alphaProgramPosLoc; 591}; 592 593SampleMaskCase::SampleMaskCase (Context& context, const char* name, const char* desc, int samples, int flags) 594 : TestCase (context, name, desc) 595 , m_samples (samples) 596 , m_canvasSize (256) 597 , m_gridsize (16) 598 , m_effectiveSampleMaskWordCount(getEffectiveSampleMaskWordCount(samples - 1)) 599 , m_flags (flags) 600 , m_currentSample (-1) 601 , m_allIterationsOk (true) 602 , m_texID (0) 603 , m_vaoID (0) 604 , m_vboID (0) 605 , m_fboID (0) 606 , m_samplerProgram (DE_NULL) 607 , m_samplerProgramPosLoc (-1) 608 , m_samplerProgramSamplerLoc (-1) 609 , m_samplerProgramSampleNdxLoc (-1) 610 , m_alphaProgram (DE_NULL) 611 , m_alphaProgramPosLoc (-1) 612{ 613} 614 615SampleMaskCase::~SampleMaskCase (void) 616{ 617 deinit(); 618} 619 620void SampleMaskCase::init (void) 621{ 622 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 623 glw::GLint maxSamples = 0; 624 glw::GLint maxSampleMaskWords = 0; 625 626 // requirements 627 628 if (m_context.getRenderTarget().getWidth() < m_canvasSize || m_context.getRenderTarget().getHeight() < m_canvasSize) 629 throw tcu::NotSupportedError("render target size must be at least " + de::toString(m_canvasSize) + "x" + de::toString(m_canvasSize)); 630 631 gl.getIntegerv(GL_MAX_SAMPLE_MASK_WORDS, &maxSampleMaskWords); 632 if (m_effectiveSampleMaskWordCount > maxSampleMaskWords) 633 throw tcu::NotSupportedError("Test requires larger GL_MAX_SAMPLE_MASK_WORDS"); 634 635 maxSamples = getMaxConformantSampleCount(GL_TEXTURE_2D_MULTISAMPLE, GL_RGBA8); 636 if (m_samples > maxSamples) 637 throw tcu::NotSupportedError("Requested sample count is greater than glGetInternalformativ(GL_SAMPLES) for this target/format"); 638 639 m_testCtx.getLog() << tcu::TestLog::Message << "glGetInternalformativ(GL_SAMPLES) = " << maxSamples << tcu::TestLog::EndMessage; 640 641 // Don't even try to test high bits if there are none 642 643 if ((m_flags & FLAGS_HIGH_BITS) && (m_samples % 32 == 0)) 644 { 645 m_testCtx.getLog() << tcu::TestLog::Message << "Sample count is multiple of word size. No unused high bits in sample mask.\nSkipping." << tcu::TestLog::EndMessage; 646 throw tcu::NotSupportedError("Test requires unused high bits (sample count not multiple of 32)"); 647 } 648 649 // generate textures 650 651 m_testCtx.getLog() << tcu::TestLog::Message << "Creating multisample texture with sample count " << m_samples << tcu::TestLog::EndMessage; 652 653 gl.genTextures (1, &m_texID); 654 gl.bindTexture (GL_TEXTURE_2D_MULTISAMPLE, m_texID); 655 gl.texStorage2DMultisample (GL_TEXTURE_2D_MULTISAMPLE, m_samples, GL_RGBA8, m_canvasSize, m_canvasSize, GL_FALSE); 656 GLU_EXPECT_NO_ERROR (gl.getError(), "texStorage2DMultisample"); 657 658 // attach texture to fbo 659 660 m_testCtx.getLog() << tcu::TestLog::Message << "Attaching texture to FBO" << tcu::TestLog::EndMessage; 661 662 gl.genFramebuffers (1, &m_fboID); 663 gl.bindFramebuffer (GL_FRAMEBUFFER, m_fboID); 664 gl.framebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, m_texID, 0); 665 GLU_EXPECT_NO_ERROR (gl.getError(), "framebufferTexture2D"); 666 667 // buffers 668 669 gl.genVertexArrays (1, &m_vaoID); 670 GLU_EXPECT_NO_ERROR (gl.getError(), "genVertexArrays"); 671 672 gl.genBuffers (1, &m_vboID); 673 gl.bindBuffer (GL_ARRAY_BUFFER, m_vboID); 674 GLU_EXPECT_NO_ERROR (gl.getError(), "genBuffers"); 675 676 // generate grid pattern 677 { 678 std::vector<tcu::Vec4> gridData(m_gridsize*m_gridsize*6); 679 680 for (int y = 0; y < m_gridsize; ++y) 681 for (int x = 0; x < m_gridsize; ++x) 682 { 683 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); 684 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); 685 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); 686 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); 687 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); 688 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); 689 } 690 691 gl.bufferData (GL_ARRAY_BUFFER, (int)(gridData.size() * sizeof(tcu::Vec4)), gridData[0].getPtr(), GL_STATIC_DRAW); 692 GLU_EXPECT_NO_ERROR (gl.getError(), "bufferData"); 693 } 694 695 // generate programs 696 697 genSamplerProgram(); 698 genAlphaProgram(); 699} 700 701void SampleMaskCase::deinit (void) 702{ 703 if (m_texID) 704 { 705 m_context.getRenderContext().getFunctions().deleteTextures(1, &m_texID); 706 m_texID = 0; 707 } 708 if (m_vaoID) 709 { 710 m_context.getRenderContext().getFunctions().deleteVertexArrays(1, &m_vaoID); 711 m_vaoID = 0; 712 } 713 if (m_vboID) 714 { 715 m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_vboID); 716 m_vboID = 0; 717 } 718 if (m_fboID) 719 { 720 m_context.getRenderContext().getFunctions().deleteFramebuffers(1, &m_fboID); 721 m_fboID = 0; 722 } 723 724 if (m_samplerProgram) 725 { 726 delete m_samplerProgram; 727 m_samplerProgram = DE_NULL; 728 } 729 if (m_alphaProgram) 730 { 731 delete m_alphaProgram; 732 m_alphaProgram = DE_NULL; 733 } 734} 735 736SampleMaskCase::IterateResult SampleMaskCase::iterate (void) 737{ 738 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))); 739 740 bool iterationOk; 741 742 // Mask only one sample, clear rest 743 744 updateTexture(m_currentSample); 745 746 // Verify only one sample set is in the texture 747 748 iterationOk = verifyTexture(m_currentSample); 749 if (!iterationOk) 750 m_allIterationsOk = false; 751 752 m_currentSample++; 753 if (m_currentSample < m_samples) 754 return CONTINUE; 755 756 // End result 757 758 if (m_allIterationsOk) 759 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 760 else if (m_flags & FLAGS_HIGH_BITS) 761 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Unused mask bits have effect"); 762 else 763 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Sample test failed"); 764 765 return STOP; 766} 767 768void SampleMaskCase::genSamplerProgram (void) 769{ 770 const char* const vertexShaderSource = "${GLSL_VERSION_DECL}\n" 771 "in highp vec4 a_position;\n" 772 "void main (void)\n" 773 "{\n" 774 " gl_Position = a_position;\n" 775 "}\n"; 776 const char* const fragShaderSource = "${GLSL_VERSION_DECL}\n" 777 "layout(location = 0) out highp vec4 fragColor;\n" 778 "uniform highp sampler2DMS u_sampler;\n" 779 "uniform highp int u_sample;\n" 780 "void main (void)\n" 781 "{\n" 782 " highp float correctCoverage = 0.0;\n" 783 " highp float incorrectCoverage = 0.0;\n" 784 " highp ivec2 texelPos = ivec2(int(floor(gl_FragCoord.x)), int(floor(gl_FragCoord.y)));\n" 785 "\n" 786 " for (int sampleNdx = 0; sampleNdx < ${NUMSAMPLES}; ++sampleNdx)\n" 787 " {\n" 788 " highp float sampleColor = texelFetch(u_sampler, texelPos, sampleNdx).r;\n" 789 " if (sampleNdx == u_sample)\n" 790 " correctCoverage += sampleColor;\n" 791 " else\n" 792 " incorrectCoverage += sampleColor;\n" 793 " }\n" 794 " fragColor = vec4(correctCoverage, incorrectCoverage, 0.0, 1.0);\n" 795 "}\n"; 796 const tcu::ScopedLogSection section (m_testCtx.getLog(), "GenerateSamplerShader", "Generate sampler shader"); 797 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 798 std::map<std::string, std::string> args; 799 const glu::GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(m_context.getRenderContext().getType()); 800 801 args["GLSL_VERSION_DECL"] = glu::getGLSLVersionDeclaration(glslVersion); 802 args["NUMSAMPLES"] = de::toString(m_samples); 803 804 m_samplerProgram = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(specializeShader(m_context, vertexShaderSource)) << glu::FragmentSource(tcu::StringTemplate(fragShaderSource).specialize(args))); 805 m_testCtx.getLog() << *m_samplerProgram; 806 807 if (!m_samplerProgram->isOk()) 808 throw tcu::TestError("Could not create sampler program."); 809 810 m_samplerProgramPosLoc = gl.getAttribLocation(m_samplerProgram->getProgram(), "a_position"); 811 m_samplerProgramSamplerLoc = gl.getUniformLocation(m_samplerProgram->getProgram(), "u_sampler"); 812 m_samplerProgramSampleNdxLoc = gl.getUniformLocation(m_samplerProgram->getProgram(), "u_sample"); 813} 814 815void SampleMaskCase::genAlphaProgram (void) 816{ 817 const char* const vertexShaderSource = "${GLSL_VERSION_DECL}\n" 818 "in highp vec4 a_position;\n" 819 "out highp float v_alpha;\n" 820 "void main (void)\n" 821 "{\n" 822 " gl_Position = a_position;\n" 823 " v_alpha = (a_position.x * 0.5 + 0.5)*(a_position.y * 0.5 + 0.5);\n" 824 "}\n"; 825 const char* const fragShaderSource = "${GLSL_VERSION_DECL}\n" 826 "layout(location = 0) out highp vec4 fragColor;\n" 827 "in mediump float v_alpha;\n" 828 "void main (void)\n" 829 "{\n" 830 " fragColor = vec4(1.0, 1.0, 1.0, v_alpha);\n" 831 "}\n"; 832 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 833 834 m_alphaProgram = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(specializeShader(m_context, vertexShaderSource)) << glu::FragmentSource(specializeShader(m_context, fragShaderSource))); 835 836 if (!m_alphaProgram->isOk()) 837 { 838 m_testCtx.getLog() << *m_alphaProgram; 839 throw tcu::TestError("Could not create aplha program."); 840 } 841 842 m_alphaProgramPosLoc = gl.getAttribLocation(m_alphaProgram->getProgram(), "a_position"); 843} 844 845void SampleMaskCase::updateTexture (int sample) 846{ 847 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 848 849 // prepare draw 850 851 gl.bindFramebuffer(GL_FRAMEBUFFER, m_fboID); 852 gl.viewport(0, 0, m_canvasSize, m_canvasSize); 853 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f); 854 855 // clear all samples 856 857 m_testCtx.getLog() << tcu::TestLog::Message << "Clearing image" << tcu::TestLog::EndMessage; 858 gl.clear(GL_COLOR_BUFFER_BIT); 859 860 // set mask state 861 862 if (m_flags & FLAGS_HIGH_BITS) 863 { 864 const std::vector<deUint32> bitmask = genSetNthBitSampleMask(sample); 865 const std::vector<deUint32> effectiveMask = genAllSetToNthBitSampleMask(m_samples); 866 std::vector<deUint32> totalBitmask (effectiveMask.size()); 867 868 DE_ASSERT((int)totalBitmask.size() == m_effectiveSampleMaskWordCount); 869 870 // set some arbitrary high bits to non-effective bits 871 for (int wordNdx = 0; wordNdx < (int)effectiveMask.size(); ++wordNdx) 872 { 873 const deUint32 randomMask = (deUint32)deUint32Hash(wordNdx << 2 ^ sample); 874 const deUint32 sampleMask = (wordNdx < (int)bitmask.size()) ? (bitmask[wordNdx]) : (0); 875 const deUint32 maskMask = effectiveMask[wordNdx]; 876 877 totalBitmask[wordNdx] = (sampleMask & maskMask) | (randomMask & ~maskMask); 878 } 879 880 m_testCtx.getLog() << tcu::TestLog::Message << "Setting sample mask to 0b" << sampleMaskToString(totalBitmask, (int)totalBitmask.size() * 32) << tcu::TestLog::EndMessage; 881 882 gl.enable(GL_SAMPLE_MASK); 883 for (int wordNdx = 0; wordNdx < m_effectiveSampleMaskWordCount; ++wordNdx) 884 { 885 const GLbitfield wordmask = (wordNdx < (int)totalBitmask.size()) ? ((GLbitfield)(totalBitmask[wordNdx])) : (0); 886 gl.sampleMaski((deUint32)wordNdx, wordmask); 887 } 888 } 889 else 890 { 891 const std::vector<deUint32> bitmask = sample < 0 ? std::vector<deUint32>(m_effectiveSampleMaskWordCount, 0) : genSetNthBitSampleMask(sample); 892 DE_ASSERT((int)bitmask.size() <= m_effectiveSampleMaskWordCount); 893 894 m_testCtx.getLog() << tcu::TestLog::Message << "Setting sample mask to 0b" << sampleMaskToString(bitmask, m_samples) << tcu::TestLog::EndMessage; 895 896 gl.enable(GL_SAMPLE_MASK); 897 for (int wordNdx = 0; wordNdx < m_effectiveSampleMaskWordCount; ++wordNdx) 898 { 899 const GLbitfield wordmask = (wordNdx < (int)bitmask.size()) ? ((GLbitfield)(bitmask[wordNdx])) : (0); 900 gl.sampleMaski((deUint32)wordNdx, wordmask); 901 } 902 } 903 if (m_flags & FLAGS_ALPHA_TO_COVERAGE) 904 { 905 m_testCtx.getLog() << tcu::TestLog::Message << "Enabling alpha to coverage." << tcu::TestLog::EndMessage; 906 gl.enable(GL_SAMPLE_ALPHA_TO_COVERAGE); 907 } 908 if (m_flags & FLAGS_SAMPLE_COVERAGE) 909 { 910 m_testCtx.getLog() << tcu::TestLog::Message << "Enabling sample coverage. Varying sample coverage for grid cells." << tcu::TestLog::EndMessage; 911 gl.enable(GL_SAMPLE_COVERAGE); 912 } 913 914 // draw test pattern 915 916 m_testCtx.getLog() << tcu::TestLog::Message << "Drawing test grid" << tcu::TestLog::EndMessage; 917 918 gl.bindVertexArray (m_vaoID); 919 gl.bindBuffer (GL_ARRAY_BUFFER, m_vboID); 920 gl.vertexAttribPointer (m_alphaProgramPosLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL); 921 gl.enableVertexAttribArray (m_alphaProgramPosLoc); 922 GLU_EXPECT_NO_ERROR (gl.getError(), "vertexAttribPointer"); 923 924 gl.useProgram (m_alphaProgram->getProgram()); 925 926 for (int y = 0; y < m_gridsize; ++y) 927 for (int x = 0; x < m_gridsize; ++x) 928 { 929 if (m_flags & FLAGS_SAMPLE_COVERAGE) 930 gl.sampleCoverage((float)(y*m_gridsize + x) / float(m_gridsize*m_gridsize), GL_FALSE); 931 932 gl.drawArrays (GL_TRIANGLES, (y*m_gridsize + x) * 6, 6); 933 GLU_EXPECT_NO_ERROR (gl.getError(), "drawArrays"); 934 } 935 936 // clean state 937 938 gl.disableVertexAttribArray (m_alphaProgramPosLoc); 939 gl.useProgram (0); 940 gl.bindFramebuffer (GL_FRAMEBUFFER, 0); 941 gl.disable (GL_SAMPLE_MASK); 942 gl.disable (GL_SAMPLE_ALPHA_TO_COVERAGE); 943 gl.disable (GL_SAMPLE_COVERAGE); 944 GLU_EXPECT_NO_ERROR (gl.getError(), "clean"); 945} 946 947bool SampleMaskCase::verifyTexture (int sample) 948{ 949 tcu::Surface result (m_canvasSize, m_canvasSize); 950 tcu::Surface errorMask (m_canvasSize, m_canvasSize); 951 bool error = false; 952 953 tcu::clear(errorMask.getAccess(), tcu::RGBA::green().toVec()); 954 955 // Draw sample: 956 // Sample sampleNdx is set to red channel 957 // Other samples are set to green channel 958 drawSample(result, sample); 959 960 // Check surface contains only sampleNdx 961 for (int y = 0; y < m_canvasSize; ++y) 962 for (int x = 0; x < m_canvasSize; ++x) 963 { 964 const tcu::RGBA color = result.getPixel(x, y); 965 966 // Allow missing coverage with FLAGS_ALPHA_TO_COVERAGE and FLAGS_SAMPLE_COVERAGE, or if there are no samples enabled 967 const bool allowMissingCoverage = ((m_flags & (FLAGS_ALPHA_TO_COVERAGE | FLAGS_SAMPLE_COVERAGE)) != 0) || (sample == -1); 968 969 // disabled sample was written to 970 if (color.getGreen() != 0) 971 { 972 error = true; 973 errorMask.setPixel(x, y, tcu::RGBA::red()); 974 } 975 // enabled sample was not written to 976 else if (color.getRed() != 255 && !allowMissingCoverage) 977 { 978 error = true; 979 errorMask.setPixel(x, y, tcu::RGBA::red()); 980 } 981 } 982 983 if (error) 984 { 985 m_testCtx.getLog() 986 << tcu::TestLog::Message << "Image verification failed, disabled samples found." << tcu::TestLog::EndMessage 987 << tcu::TestLog::ImageSet("VerificationResult", "Result of rendering") 988 << tcu::TestLog::Image("Result", "Result", result) 989 << tcu::TestLog::Image("ErrorMask", "Error Mask", errorMask) 990 << tcu::TestLog::EndImageSet; 991 return false; 992 } 993 else 994 { 995 m_testCtx.getLog() << tcu::TestLog::Message << "Image verification ok, no disabled samples found." << tcu::TestLog::EndMessage; 996 return true; 997 } 998} 999 1000void SampleMaskCase::drawSample (tcu::Surface& dst, int sample) 1001{ 1002 // Downsample using only one sample 1003 static const tcu::Vec4 fullscreenQuad[] = 1004 { 1005 tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f), 1006 tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f), 1007 tcu::Vec4( 1.0f, 1.0f, 0.0f, 1.0f), 1008 tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f) 1009 }; 1010 1011 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 1012 glu::Buffer vertexBuffer (m_context.getRenderContext()); 1013 1014 gl.bindTexture (GL_TEXTURE_2D_MULTISAMPLE, m_texID); 1015 gl.bindVertexArray (m_vaoID); 1016 1017 gl.bindBuffer (GL_ARRAY_BUFFER, *vertexBuffer); 1018 gl.bufferData (GL_ARRAY_BUFFER, sizeof(fullscreenQuad), &fullscreenQuad[0], GL_STATIC_DRAW); 1019 GLU_EXPECT_NO_ERROR (gl.getError(), "bufferData"); 1020 1021 gl.viewport (0, 0, m_canvasSize, m_canvasSize); 1022 gl.clearColor (0, 0, 0, 1); 1023 gl.clear (GL_COLOR_BUFFER_BIT); 1024 gl.vertexAttribPointer (m_samplerProgramPosLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL); 1025 gl.enableVertexAttribArray (m_samplerProgramPosLoc); 1026 GLU_EXPECT_NO_ERROR (gl.getError(), "vertexAttribPointer"); 1027 1028 gl.useProgram (m_samplerProgram->getProgram()); 1029 gl.uniform1i (m_samplerProgramSamplerLoc, 0); 1030 gl.uniform1i (m_samplerProgramSampleNdxLoc, (deInt32)sample); 1031 GLU_EXPECT_NO_ERROR (gl.getError(), "useprogram"); 1032 1033 m_testCtx.getLog() << tcu::TestLog::Message << "Reading from texture with sampler shader, u_sample = " << sample << tcu::TestLog::EndMessage; 1034 1035 gl.drawArrays (GL_TRIANGLE_STRIP, 0, 4); 1036 GLU_EXPECT_NO_ERROR (gl.getError(), "drawArrays"); 1037 1038 gl.disableVertexAttribArray (m_samplerProgramPosLoc); 1039 gl.useProgram (0); 1040 GLU_EXPECT_NO_ERROR (gl.getError(), "cleanup"); 1041 1042 gl.finish (); 1043 glu::readPixels (m_context.getRenderContext(), 0, 0, dst.getAccess()); 1044 GLU_EXPECT_NO_ERROR (gl.getError(), "readPixels"); 1045} 1046 1047glw::GLint SampleMaskCase::getMaxConformantSampleCount(glw::GLenum target, glw::GLenum internalFormat) 1048{ 1049 deInt32 maxTextureSamples = 0; 1050 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 1051 if (m_context.getContextInfo().isExtensionSupported("GL_NV_internalformat_sample_query")) 1052 { 1053 glw::GLint gl_sample_counts = 0; 1054 gl.getInternalformativ(target, internalFormat, GL_NUM_SAMPLE_COUNTS, 1, &gl_sample_counts); 1055 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetInternalformativ() failed for GL_NUM_SAMPLE_COUNTS pname"); 1056 /* Check and return the first conformant sample count */ 1057 glw::GLint* gl_supported_samples = new glw::GLint[gl_sample_counts]; 1058 if (gl_supported_samples) 1059 { 1060 gl.getInternalformativ(target, internalFormat, GL_SAMPLES, gl_sample_counts, gl_supported_samples); 1061 for (glw::GLint i = 0; i < gl_sample_counts; i++) 1062 { 1063 glw::GLint isConformant = 0; 1064 gl.getInternalformatSampleivNV(target, internalFormat, gl_supported_samples[i], GL_CONFORMANT_NV, 1, 1065 &isConformant); 1066 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetInternalformatSampleivNV() call(s) failed"); 1067 if (isConformant && gl_supported_samples[i] > maxTextureSamples) 1068 { 1069 maxTextureSamples = gl_supported_samples[i]; 1070 } 1071 } 1072 delete[] gl_supported_samples; 1073 } 1074 } 1075 else 1076 { 1077 gl.getInternalformativ(target, internalFormat, GL_SAMPLES, 1, &maxTextureSamples); 1078 } 1079 return maxTextureSamples; 1080} 1081 1082 1083class MultisampleTextureUsageCase : public TestCase 1084{ 1085public: 1086 1087 enum TextureType 1088 { 1089 TEXTURE_COLOR_2D = 0, 1090 TEXTURE_COLOR_2D_ARRAY, 1091 TEXTURE_INT_2D, 1092 TEXTURE_INT_2D_ARRAY, 1093 TEXTURE_UINT_2D, 1094 TEXTURE_UINT_2D_ARRAY, 1095 TEXTURE_DEPTH_2D, 1096 TEXTURE_DEPTH_2D_ARRAY, 1097 1098 TEXTURE_LAST 1099 }; 1100 1101 MultisampleTextureUsageCase (Context& ctx, const char* name, const char* desc, int samples, TextureType type); 1102 ~MultisampleTextureUsageCase (void); 1103 1104private: 1105 void init (void); 1106 void deinit (void); 1107 IterateResult iterate (void); 1108 1109 void genDrawShader (void); 1110 void genSamplerShader (void); 1111 1112 void renderToTexture (float value); 1113 void sampleTexture (tcu::Surface& dst, float value); 1114 bool verifyImage (const tcu::Surface& dst); 1115 1116 static const int s_textureSize = 256; 1117 static const int s_textureArraySize = 8; 1118 static const int s_textureLayer = 3; 1119 1120 const TextureType m_type; 1121 const int m_numSamples; 1122 1123 glw::GLuint m_fboID; 1124 glw::GLuint m_vaoID; 1125 glw::GLuint m_textureID; 1126 1127 glu::ShaderProgram* m_drawShader; 1128 glu::ShaderProgram* m_samplerShader; 1129 1130 const bool m_isColorFormat; 1131 const bool m_isSignedFormat; 1132 const bool m_isUnsignedFormat; 1133 const bool m_isDepthFormat; 1134 const bool m_isArrayType; 1135}; 1136 1137MultisampleTextureUsageCase::MultisampleTextureUsageCase (Context& ctx, const char* name, const char* desc, int samples, TextureType type) 1138 : TestCase (ctx, name, desc) 1139 , m_type (type) 1140 , m_numSamples (samples) 1141 , m_fboID (0) 1142 , m_vaoID (0) 1143 , m_textureID (0) 1144 , m_drawShader (DE_NULL) 1145 , m_samplerShader (DE_NULL) 1146 , m_isColorFormat (m_type == TEXTURE_COLOR_2D || m_type == TEXTURE_COLOR_2D_ARRAY) 1147 , m_isSignedFormat (m_type == TEXTURE_INT_2D || m_type == TEXTURE_INT_2D_ARRAY) 1148 , m_isUnsignedFormat(m_type == TEXTURE_UINT_2D || m_type == TEXTURE_UINT_2D_ARRAY) 1149 , m_isDepthFormat (m_type == TEXTURE_DEPTH_2D || m_type == TEXTURE_DEPTH_2D_ARRAY) 1150 , 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) 1151{ 1152 DE_ASSERT(m_type < TEXTURE_LAST); 1153} 1154 1155MultisampleTextureUsageCase::~MultisampleTextureUsageCase (void) 1156{ 1157 deinit(); 1158} 1159 1160void MultisampleTextureUsageCase::init (void) 1161{ 1162 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 1163 const glw::GLenum internalFormat = (m_isColorFormat) ? (GL_R8) : (m_isSignedFormat) ? (GL_R8I) : (m_isUnsignedFormat) ? (GL_R8UI) : (m_isDepthFormat) ? (GL_DEPTH_COMPONENT32F) : (0); 1164 const glw::GLenum textureTarget = (m_isArrayType) ? (GL_TEXTURE_2D_MULTISAMPLE_ARRAY) : (GL_TEXTURE_2D_MULTISAMPLE); 1165 const glw::GLenum fboAttachment = (m_isDepthFormat) ? (GL_DEPTH_ATTACHMENT) : (GL_COLOR_ATTACHMENT0); 1166 const bool supportsES32orGL45 = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)) || 1167 glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5)); 1168 1169 DE_ASSERT(internalFormat); 1170 1171 // requirements 1172 1173 if (m_isArrayType && !supportsES32orGL45 && !m_context.getContextInfo().isExtensionSupported("GL_OES_texture_storage_multisample_2d_array")) 1174 throw tcu::NotSupportedError("Test requires OES_texture_storage_multisample_2d_array extension"); 1175 if (m_context.getRenderTarget().getWidth() < s_textureSize || m_context.getRenderTarget().getHeight() < s_textureSize) 1176 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))); 1177 1178 { 1179 glw::GLint maxSamples = 0; 1180 gl.getInternalformativ(textureTarget, internalFormat, GL_SAMPLES, 1, &maxSamples); 1181 1182 if (m_numSamples > maxSamples) 1183 throw tcu::NotSupportedError("Requested sample count is greater than supported"); 1184 1185 m_testCtx.getLog() << tcu::TestLog::Message << "Max sample count for " << glu::getTextureFormatStr(internalFormat) << ": " << maxSamples << tcu::TestLog::EndMessage; 1186 } 1187 1188 { 1189 GLint maxTextureSize = 0; 1190 gl.getIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize); 1191 1192 if (s_textureSize > maxTextureSize) 1193 throw tcu::NotSupportedError("Larger GL_MAX_TEXTURE_SIZE is required"); 1194 } 1195 1196 if (m_isArrayType) 1197 { 1198 GLint maxTextureLayers = 0; 1199 gl.getIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &maxTextureLayers); 1200 1201 if (s_textureArraySize > maxTextureLayers) 1202 throw tcu::NotSupportedError("Larger GL_MAX_ARRAY_TEXTURE_LAYERS is required"); 1203 } 1204 1205 // create texture 1206 1207 m_testCtx.getLog() << tcu::TestLog::Message << "Creating multisample " << ((m_isDepthFormat) ? ("depth") : ("")) << " texture" << ((m_isArrayType) ? (" array") : ("")) << tcu::TestLog::EndMessage; 1208 1209 gl.genTextures(1, &m_textureID); 1210 gl.bindTexture(textureTarget, m_textureID); 1211 GLU_EXPECT_NO_ERROR(gl.getError(), "bind texture"); 1212 1213 if (m_isArrayType) 1214 gl.texStorage3DMultisample(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, m_numSamples, internalFormat, s_textureSize, s_textureSize, s_textureArraySize, GL_FALSE); 1215 else 1216 gl.texStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_numSamples, internalFormat, s_textureSize, s_textureSize, GL_FALSE); 1217 GLU_EXPECT_NO_ERROR(gl.getError(), "texstorage"); 1218 1219 // create fbo for drawing 1220 1221 gl.genFramebuffers(1, &m_fboID); 1222 gl.bindFramebuffer(GL_FRAMEBUFFER, m_fboID); 1223 1224 if (m_isArrayType) 1225 { 1226 m_testCtx.getLog() << tcu::TestLog::Message << "Attaching multisample texture array layer " << static_cast<int>(s_textureLayer) << " to fbo" << tcu::TestLog::EndMessage; 1227 gl.framebufferTextureLayer(GL_FRAMEBUFFER, fboAttachment, m_textureID, 0, s_textureLayer); 1228 } 1229 else 1230 { 1231 m_testCtx.getLog() << tcu::TestLog::Message << "Attaching multisample texture to fbo" << tcu::TestLog::EndMessage; 1232 gl.framebufferTexture2D(GL_FRAMEBUFFER, fboAttachment, textureTarget, m_textureID, 0); 1233 } 1234 GLU_EXPECT_NO_ERROR(gl.getError(), "gen fbo"); 1235 1236 // create vao if context is GL4.5 1237 if (!glu::isContextTypeES(m_context.getRenderContext().getType())) 1238 gl.genVertexArrays(1, &m_vaoID); 1239 1240 // create shader for rendering to fbo 1241 genDrawShader(); 1242 1243 // create shader for sampling the texture rendered to 1244 genSamplerShader(); 1245} 1246 1247void MultisampleTextureUsageCase::deinit (void) 1248{ 1249 if (m_textureID) 1250 { 1251 m_context.getRenderContext().getFunctions().deleteTextures(1, &m_textureID); 1252 m_textureID = 0; 1253 } 1254 1255 if (m_fboID) 1256 { 1257 m_context.getRenderContext().getFunctions().deleteFramebuffers(1, &m_fboID); 1258 m_fboID = 0; 1259 } 1260 1261 if (m_vaoID) 1262 { 1263 m_context.getRenderContext().getFunctions().deleteVertexArrays(1, &m_vaoID); 1264 m_vaoID = 0; 1265 } 1266 1267 if (m_drawShader) 1268 { 1269 delete m_drawShader; 1270 m_drawShader = DE_NULL; 1271 } 1272 1273 if (m_samplerShader) 1274 { 1275 delete m_samplerShader; 1276 m_samplerShader = DE_NULL; 1277 } 1278} 1279 1280MultisampleTextureUsageCase::IterateResult MultisampleTextureUsageCase::iterate (void) 1281{ 1282 const tcu::ScopedLogSection section (m_testCtx.getLog(), "Sample", "Render to texture and sample texture"); 1283 tcu::Surface result (s_textureSize, s_textureSize); 1284 const float minValue = (m_isColorFormat || m_isDepthFormat) ? (0.0f) : (m_isSignedFormat) ? (-100.0f) : (m_isUnsignedFormat) ? (0.0f) : ( 1.0f); 1285 const float maxValue = (m_isColorFormat || m_isDepthFormat) ? (1.0f) : (m_isSignedFormat) ? ( 100.0f) : (m_isUnsignedFormat) ? (200.0f) : (-1.0f); 1286 de::Random rnd (deUint32Hash((deUint32)m_type)); 1287 const float rawValue = rnd.getFloat(minValue, maxValue); 1288 const float preparedValue = (m_isSignedFormat || m_isUnsignedFormat) ? (deFloatFloor(rawValue)) : (rawValue); 1289 1290 // draw to fbo with a random value 1291 1292 renderToTexture(preparedValue); 1293 1294 // draw from texture to front buffer 1295 1296 sampleTexture(result, preparedValue); 1297 1298 // result is ok? 1299 1300 if (verifyImage(result)) 1301 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 1302 else 1303 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed"); 1304 1305 return STOP; 1306} 1307 1308void MultisampleTextureUsageCase::genDrawShader (void) 1309{ 1310 const tcu::ScopedLogSection section(m_testCtx.getLog(), "RenderShader", "Generate render-to-texture shader"); 1311 1312 static const char* const vertexShaderSource = "${GLSL_VERSION_DECL}\n" 1313 "in highp vec4 a_position;\n" 1314 "void main (void)\n" 1315 "{\n" 1316 " gl_Position = a_position;\n" 1317 "}\n"; 1318 static const char* const fragmentShaderSourceColor = "${GLSL_VERSION_DECL}\n" 1319 "layout(location = 0) out highp ${OUTTYPE} fragColor;\n" 1320 "uniform highp float u_writeValue;\n" 1321 "void main (void)\n" 1322 "{\n" 1323 " fragColor = ${OUTTYPE}(vec4(u_writeValue, 1.0, 1.0, 1.0));\n" 1324 "}\n"; 1325 static const char* const fragmentShaderSourceDepth = "${GLSL_VERSION_DECL}\n" 1326 "layout(location = 0) out highp vec4 fragColor;\n" 1327 "uniform highp float u_writeValue;\n" 1328 "void main (void)\n" 1329 "{\n" 1330 " fragColor = vec4(0.0, 0.0, 0.0, 1.0);\n" 1331 " gl_FragDepth = u_writeValue;\n" 1332 "}\n"; 1333 const char* const fragmentSource = (m_isDepthFormat) ? (fragmentShaderSourceDepth) : (fragmentShaderSourceColor); 1334 1335 std::map<std::string, std::string> fragmentArguments; 1336 1337 const glu::GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(m_context.getRenderContext().getType()); 1338 fragmentArguments["GLSL_VERSION_DECL"] = glu::getGLSLVersionDeclaration(glslVersion); 1339 1340 if (m_isColorFormat || m_isDepthFormat) 1341 fragmentArguments["OUTTYPE"] = "vec4"; 1342 else if (m_isSignedFormat) 1343 fragmentArguments["OUTTYPE"] = "ivec4"; 1344 else if (m_isUnsignedFormat) 1345 fragmentArguments["OUTTYPE"] = "uvec4"; 1346 else 1347 DE_ASSERT(DE_FALSE); 1348 1349 m_drawShader = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(specializeShader(m_context, vertexShaderSource)) << glu::FragmentSource(tcu::StringTemplate(fragmentSource).specialize(fragmentArguments))); 1350 m_testCtx.getLog() << *m_drawShader; 1351 1352 if (!m_drawShader->isOk()) 1353 throw tcu::TestError("could not build shader"); 1354} 1355 1356void MultisampleTextureUsageCase::genSamplerShader (void) 1357{ 1358 const tcu::ScopedLogSection section(m_testCtx.getLog(), "SamplerShader", "Generate texture sampler shader"); 1359 1360 static const char* const vertexShaderSource = "${GLSL_VERSION_DECL}\n" 1361 "in highp vec4 a_position;\n" 1362 "out highp float v_gradient;\n" 1363 "void main (void)\n" 1364 "{\n" 1365 " gl_Position = a_position;\n" 1366 " v_gradient = a_position.x * 0.5 + 0.5;\n" 1367 "}\n"; 1368 static const char* const fragmentShaderSource = "${GLSL_VERSION_DECL}\n" 1369 "${EXTENSION_STATEMENT}" 1370 "layout(location = 0) out highp vec4 fragColor;\n" 1371 "uniform highp ${SAMPLERTYPE} u_sampler;\n" 1372 "uniform highp int u_maxSamples;\n" 1373 "uniform highp int u_layer;\n" 1374 "uniform highp float u_cmpValue;\n" 1375 "in highp float v_gradient;\n" 1376 "void main (void)\n" 1377 "{\n" 1378 " const highp vec4 okColor = vec4(0.0, 1.0, 0.0, 1.0);\n" 1379 " const highp vec4 failColor = vec4(1.0, 0.0, 0.0, 1.0);\n" 1380 " const highp float epsilon = ${EPSILON};\n" 1381 "\n" 1382 " highp int sampleNdx = clamp(int(floor(v_gradient * float(u_maxSamples))), 0, u_maxSamples-1);\n" 1383 " highp float value = float(texelFetch(u_sampler, ${FETCHPOS}, sampleNdx).r);\n" 1384 " fragColor = (abs(u_cmpValue - value) < epsilon) ? (okColor) : (failColor);\n" 1385 "}\n"; 1386 1387 std::map<std::string, std::string> fragmentArguments; 1388 1389 const glu::GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(m_context.getRenderContext().getType()); 1390 fragmentArguments["GLSL_VERSION_DECL"] = glu::getGLSLVersionDeclaration(glslVersion); 1391 1392 const bool supportsES32orGL45 = 1393 glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)) || 1394 glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5)); 1395 1396 if (m_isArrayType) 1397 fragmentArguments["FETCHPOS"] = "ivec3(floor(gl_FragCoord.xy), u_layer)"; 1398 else 1399 fragmentArguments["FETCHPOS"] = "ivec2(floor(gl_FragCoord.xy))"; 1400 1401 if (m_isColorFormat || m_isDepthFormat) 1402 fragmentArguments["EPSILON"] = "0.1"; 1403 else 1404 fragmentArguments["EPSILON"] = "1.0"; 1405 1406 if (m_isArrayType && !supportsES32orGL45) 1407 fragmentArguments["EXTENSION_STATEMENT"] = "#extension GL_OES_texture_storage_multisample_2d_array : require\n"; 1408 else 1409 fragmentArguments["EXTENSION_STATEMENT"] = ""; 1410 1411 switch (m_type) 1412 { 1413 case TEXTURE_COLOR_2D: fragmentArguments["SAMPLERTYPE"] = "sampler2DMS"; break; 1414 case TEXTURE_COLOR_2D_ARRAY: fragmentArguments["SAMPLERTYPE"] = "sampler2DMSArray"; break; 1415 case TEXTURE_INT_2D: fragmentArguments["SAMPLERTYPE"] = "isampler2DMS"; break; 1416 case TEXTURE_INT_2D_ARRAY: fragmentArguments["SAMPLERTYPE"] = "isampler2DMSArray"; break; 1417 case TEXTURE_UINT_2D: fragmentArguments["SAMPLERTYPE"] = "usampler2DMS"; break; 1418 case TEXTURE_UINT_2D_ARRAY: fragmentArguments["SAMPLERTYPE"] = "usampler2DMSArray"; break; 1419 case TEXTURE_DEPTH_2D: fragmentArguments["SAMPLERTYPE"] = "sampler2DMS"; break; 1420 case TEXTURE_DEPTH_2D_ARRAY: fragmentArguments["SAMPLERTYPE"] = "sampler2DMSArray"; break; 1421 1422 default: 1423 DE_ASSERT(DE_FALSE); 1424 } 1425 1426 m_samplerShader = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(specializeShader(m_context, vertexShaderSource)) << glu::FragmentSource(tcu::StringTemplate(fragmentShaderSource).specialize(fragmentArguments))); 1427 m_testCtx.getLog() << *m_samplerShader; 1428 1429 if (!m_samplerShader->isOk()) 1430 throw tcu::TestError("could not build shader"); 1431} 1432 1433void MultisampleTextureUsageCase::renderToTexture (float value) 1434{ 1435 static const tcu::Vec4 fullscreenQuad[] = 1436 { 1437 tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f), 1438 tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f), 1439 tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f), 1440 tcu::Vec4( 1.0f, 1.0f, 0.0f, 1.0f), 1441 }; 1442 1443 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 1444 const int posLocation = gl.getAttribLocation(m_drawShader->getProgram(), "a_position"); 1445 const int valueLocation = gl.getUniformLocation(m_drawShader->getProgram(), "u_writeValue"); 1446 glu::Buffer vertexAttibBuffer (m_context.getRenderContext()); 1447 1448 m_testCtx.getLog() << tcu::TestLog::Message << "Filling multisample texture with value " << value << tcu::TestLog::EndMessage; 1449 1450 // upload data 1451 1452 gl.bindBuffer(GL_ARRAY_BUFFER, *vertexAttibBuffer); 1453 gl.bufferData(GL_ARRAY_BUFFER, sizeof(fullscreenQuad), fullscreenQuad[0].getPtr(), GL_STATIC_DRAW); 1454 GLU_EXPECT_NO_ERROR(gl.getError(), "bufferdata"); 1455 1456 // clear buffer 1457 1458 gl.bindFramebuffer(GL_FRAMEBUFFER, m_fboID); 1459 gl.viewport(0, 0, s_textureSize, s_textureSize); 1460 1461 if (m_isColorFormat) 1462 { 1463 const float clearColor[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; 1464 gl.clearBufferfv(GL_COLOR, 0, clearColor); 1465 } 1466 else if (m_isSignedFormat) 1467 { 1468 const deInt32 clearColor[4] = { 0, 0, 0, 0 }; 1469 gl.clearBufferiv(GL_COLOR, 0, clearColor); 1470 } 1471 else if (m_isUnsignedFormat) 1472 { 1473 const deUint32 clearColor[4] = { 0, 0, 0, 0 }; 1474 gl.clearBufferuiv(GL_COLOR, 0, clearColor); 1475 } 1476 else if (m_isDepthFormat) 1477 { 1478 const float clearDepth = 0.5f; 1479 gl.clearBufferfv(GL_DEPTH, 0, &clearDepth); 1480 } 1481 1482 GLU_EXPECT_NO_ERROR(gl.getError(), "clear buffer"); 1483 1484 // setup shader and draw 1485 if (m_vaoID) 1486 gl.bindVertexArray(m_vaoID); 1487 1488 gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL); 1489 gl.enableVertexAttribArray(posLocation); 1490 1491 gl.useProgram(m_drawShader->getProgram()); 1492 gl.uniform1f(valueLocation, value); 1493 1494 GLU_EXPECT_NO_ERROR(gl.getError(), "setup draw"); 1495 1496 if (m_isDepthFormat) 1497 { 1498 gl.enable(GL_DEPTH_TEST); 1499 gl.depthFunc(GL_ALWAYS); 1500 } 1501 1502 gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4); 1503 GLU_EXPECT_NO_ERROR(gl.getError(), "draw"); 1504 1505 // clean state 1506 1507 if (m_isDepthFormat) 1508 gl.disable(GL_DEPTH_TEST); 1509 1510 gl.disableVertexAttribArray(posLocation); 1511 gl.useProgram(0); 1512 gl.bindFramebuffer(GL_FRAMEBUFFER, 0); 1513 GLU_EXPECT_NO_ERROR(gl.getError(), "clean"); 1514} 1515 1516void MultisampleTextureUsageCase::sampleTexture (tcu::Surface& dst, float value) 1517{ 1518 static const tcu::Vec4 fullscreenQuad[] = 1519 { 1520 tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f), 1521 tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f), 1522 tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f), 1523 tcu::Vec4( 1.0f, 1.0f, 0.0f, 1.0f), 1524 }; 1525 1526 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 1527 const int posLocation = gl.getAttribLocation(m_samplerShader->getProgram(), "a_position"); 1528 const int samplerLocation = gl.getUniformLocation(m_samplerShader->getProgram(), "u_sampler"); 1529 const int maxSamplesLocation = gl.getUniformLocation(m_samplerShader->getProgram(), "u_maxSamples"); 1530 const int layerLocation = gl.getUniformLocation(m_samplerShader->getProgram(), "u_layer"); 1531 const int valueLocation = gl.getUniformLocation(m_samplerShader->getProgram(), "u_cmpValue"); 1532 const glw::GLenum textureTarget = (m_isArrayType) ? (GL_TEXTURE_2D_MULTISAMPLE_ARRAY) : (GL_TEXTURE_2D_MULTISAMPLE); 1533 glu::Buffer vertexAttibBuffer (m_context.getRenderContext()); 1534 1535 m_testCtx.getLog() << tcu::TestLog::Message << "Sampling from texture." << tcu::TestLog::EndMessage; 1536 1537 // upload data 1538 1539 gl.bindBuffer(GL_ARRAY_BUFFER, *vertexAttibBuffer); 1540 gl.bufferData(GL_ARRAY_BUFFER, sizeof(fullscreenQuad), fullscreenQuad[0].getPtr(), GL_STATIC_DRAW); 1541 GLU_EXPECT_NO_ERROR(gl.getError(), "bufferdata"); 1542 1543 // clear 1544 1545 gl.viewport(0, 0, s_textureSize, s_textureSize); 1546 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f); 1547 gl.clear(GL_COLOR_BUFFER_BIT); 1548 1549 // setup shader and draw 1550 1551 gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL); 1552 gl.enableVertexAttribArray(posLocation); 1553 1554 gl.useProgram(m_samplerShader->getProgram()); 1555 gl.uniform1i(samplerLocation, 0); 1556 gl.uniform1i(maxSamplesLocation, m_numSamples); 1557 if (m_isArrayType) 1558 gl.uniform1i(layerLocation, s_textureLayer); 1559 gl.uniform1f(valueLocation, value); 1560 gl.bindTexture(textureTarget, m_textureID); 1561 GLU_EXPECT_NO_ERROR(gl.getError(), "setup draw"); 1562 1563 gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4); 1564 GLU_EXPECT_NO_ERROR(gl.getError(), "draw"); 1565 1566 // clean state 1567 1568 gl.disableVertexAttribArray(posLocation); 1569 gl.useProgram(0); 1570 GLU_EXPECT_NO_ERROR(gl.getError(), "clean"); 1571 1572 // read results 1573 gl.finish(); 1574 glu::readPixels(m_context.getRenderContext(), 0, 0, dst.getAccess()); 1575} 1576 1577bool MultisampleTextureUsageCase::verifyImage (const tcu::Surface& dst) 1578{ 1579 bool error = false; 1580 1581 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying image." << tcu::TestLog::EndMessage; 1582 1583 for (int y = 0; y < dst.getHeight(); ++y) 1584 for (int x = 0; x < dst.getWidth(); ++x) 1585 { 1586 const tcu::RGBA color = dst.getPixel(x, y); 1587 const int colorThresholdRed = 1 << (8 - m_context.getRenderTarget().getPixelFormat().redBits); 1588 const int colorThresholdGreen = 1 << (8 - m_context.getRenderTarget().getPixelFormat().greenBits); 1589 const int colorThresholdBlue = 1 << (8 - m_context.getRenderTarget().getPixelFormat().blueBits); 1590 1591 // only green is accepted 1592 if (color.getRed() > colorThresholdRed || color.getGreen() < 255 - colorThresholdGreen || color.getBlue() > colorThresholdBlue) 1593 error = true; 1594 } 1595 1596 if (error) 1597 { 1598 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid pixels found." << tcu::TestLog::EndMessage; 1599 m_testCtx.getLog() 1600 << tcu::TestLog::ImageSet("Verification result", "Result of rendering") 1601 << tcu::TestLog::Image("Result", "Result", dst) 1602 << tcu::TestLog::EndImageSet; 1603 1604 return false; 1605 } 1606 else 1607 { 1608 m_testCtx.getLog() << tcu::TestLog::Message << "No invalid pixels found." << tcu::TestLog::EndMessage; 1609 return true; 1610 } 1611} 1612 1613class NegativeFramebufferCase : public TestCase 1614{ 1615public: 1616 enum CaseType 1617 { 1618 CASE_DIFFERENT_N_SAMPLES_TEX = 0, 1619 CASE_DIFFERENT_N_SAMPLES_RBO, 1620 CASE_DIFFERENT_FIXED_TEX, 1621 CASE_DIFFERENT_FIXED_RBO, 1622 CASE_NON_ZERO_LEVEL, 1623 1624 CASE_LAST 1625 }; 1626 1627 NegativeFramebufferCase (Context& context, const char* name, const char* desc, CaseType caseType); 1628 ~NegativeFramebufferCase (void); 1629 1630private: 1631 void init (void); 1632 void deinit (void); 1633 IterateResult iterate (void); 1634 1635 void getFormatSamples (glw::GLenum target, std::vector<int>& samples); 1636 1637 const CaseType m_caseType; 1638 const int m_fboSize; 1639 const glw::GLenum m_internalFormat; 1640 1641 int m_numSamples0; // !< samples for attachment 0 1642 int m_numSamples1; // !< samples for attachment 1 1643}; 1644 1645NegativeFramebufferCase::NegativeFramebufferCase (Context& context, const char* name, const char* desc, CaseType caseType) 1646 : TestCase (context, name, desc) 1647 , m_caseType (caseType) 1648 , m_fboSize (64) 1649 , m_internalFormat (GL_RGBA8) 1650 , m_numSamples0 (-1) 1651 , m_numSamples1 (-1) 1652{ 1653} 1654 1655NegativeFramebufferCase::~NegativeFramebufferCase (void) 1656{ 1657 deinit(); 1658} 1659 1660void NegativeFramebufferCase::init (void) 1661{ 1662 const bool colorAttachmentTexture = (m_caseType == CASE_DIFFERENT_N_SAMPLES_TEX) || (m_caseType == CASE_DIFFERENT_FIXED_TEX); 1663 const bool colorAttachmentRbo = (m_caseType == CASE_DIFFERENT_N_SAMPLES_RBO) || (m_caseType == CASE_DIFFERENT_FIXED_RBO); 1664 const bool useDifferentSampleCounts= (m_caseType == CASE_DIFFERENT_N_SAMPLES_TEX) || (m_caseType == CASE_DIFFERENT_N_SAMPLES_RBO); 1665 std::vector<int> textureSamples; 1666 std::vector<int> rboSamples; 1667 1668 getFormatSamples(GL_TEXTURE_2D_MULTISAMPLE, textureSamples); 1669 getFormatSamples(GL_RENDERBUFFER, rboSamples); 1670 1671 TCU_CHECK(!textureSamples.empty()); 1672 TCU_CHECK(!rboSamples.empty()); 1673 1674 // select sample counts 1675 1676 if (useDifferentSampleCounts) 1677 { 1678 if (colorAttachmentTexture) 1679 { 1680 m_numSamples0 = textureSamples[0]; 1681 1682 if (textureSamples.size() >= 2) 1683 m_numSamples1 = textureSamples[1]; 1684 else 1685 throw tcu::NotSupportedError("Test requires multiple supported sample counts"); 1686 } 1687 else if (colorAttachmentRbo) 1688 { 1689 for (int texNdx = 0; texNdx < (int)textureSamples.size(); ++texNdx) 1690 for (int rboNdx = 0; rboNdx < (int)rboSamples.size(); ++rboNdx) 1691 { 1692 if (textureSamples[texNdx] != rboSamples[rboNdx]) 1693 { 1694 m_numSamples0 = textureSamples[texNdx]; 1695 m_numSamples1 = rboSamples[rboNdx]; 1696 return; 1697 } 1698 } 1699 1700 throw tcu::NotSupportedError("Test requires multiple supported sample counts"); 1701 } 1702 else 1703 DE_ASSERT(DE_FALSE); 1704 } 1705 else 1706 { 1707 if (colorAttachmentTexture) 1708 { 1709 m_numSamples0 = textureSamples[0]; 1710 m_numSamples1 = textureSamples[0]; 1711 } 1712 else if (colorAttachmentRbo) 1713 { 1714 for (int texNdx = 0; texNdx < (int)textureSamples.size(); ++texNdx) 1715 for (int rboNdx = 0; rboNdx < (int)rboSamples.size(); ++rboNdx) 1716 { 1717 if (textureSamples[texNdx] == rboSamples[rboNdx]) 1718 { 1719 m_numSamples0 = textureSamples[texNdx]; 1720 m_numSamples1 = rboSamples[rboNdx]; 1721 return; 1722 } 1723 } 1724 1725 throw tcu::NotSupportedError("Test requires a sample count supported in both rbo and texture"); 1726 } 1727 else 1728 { 1729 m_numSamples0 = textureSamples[0]; 1730 } 1731 } 1732} 1733 1734void NegativeFramebufferCase::deinit (void) 1735{ 1736} 1737 1738NegativeFramebufferCase::IterateResult NegativeFramebufferCase::iterate (void) 1739{ 1740 const bool colorAttachmentTexture = (m_caseType == CASE_DIFFERENT_N_SAMPLES_TEX) || (m_caseType == CASE_DIFFERENT_FIXED_TEX); 1741 const bool colorAttachmentRbo = (m_caseType == CASE_DIFFERENT_N_SAMPLES_RBO) || (m_caseType == CASE_DIFFERENT_FIXED_RBO); 1742 const glw::GLboolean fixedSampleLocations0 = (m_caseType == CASE_DIFFERENT_N_SAMPLES_RBO) ? (GL_TRUE) : (GL_FALSE); 1743 const glw::GLboolean fixedSampleLocations1 = ((m_caseType == CASE_DIFFERENT_FIXED_TEX) || (m_caseType == CASE_DIFFERENT_FIXED_RBO)) ? (GL_TRUE) : (GL_FALSE); 1744 glu::CallLogWrapper gl (m_context.getRenderContext().getFunctions(), m_testCtx.getLog()); 1745 glw::GLuint fboId = 0; 1746 glw::GLuint rboId = 0; 1747 glw::GLuint tex0Id = 0; 1748 glw::GLuint tex1Id = 0; 1749 1750 bool testFailed = false; 1751 1752 gl.enableLogging(true); 1753 1754 try 1755 { 1756 gl.glGenFramebuffers(1, &fboId); 1757 gl.glBindFramebuffer(GL_FRAMEBUFFER, fboId); 1758 GLU_EXPECT_NO_ERROR(gl.glGetError(), "gen fbo"); 1759 1760 gl.glGenTextures(1, &tex0Id); 1761 gl.glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, tex0Id); 1762 gl.glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_numSamples0, m_internalFormat, m_fboSize, m_fboSize, fixedSampleLocations0); 1763 GLU_EXPECT_NO_ERROR(gl.glGetError(), "gen texture 0"); 1764 1765 int textureSamples; 1766 gl.glGetTexLevelParameteriv(GL_TEXTURE_2D_MULTISAMPLE, 0, GL_TEXTURE_SAMPLES, &textureSamples); 1767 1768 if (m_caseType == CASE_NON_ZERO_LEVEL) 1769 { 1770 glw::GLenum error; 1771 1772 // attaching non-zero level generates invalid value 1773 gl.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, tex0Id, 5); 1774 error = gl.glGetError(); 1775 1776 if (error != GL_INVALID_VALUE) 1777 { 1778 m_testCtx.getLog() << tcu::TestLog::Message << "ERROR! Expected GL_INVALID_VALUE, got " << glu::getErrorStr(error) << tcu::TestLog::EndMessage; 1779 testFailed = true; 1780 } 1781 } 1782 else 1783 { 1784 gl.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, tex0Id, 0); 1785 GLU_EXPECT_NO_ERROR(gl.glGetError(), "attach to c0"); 1786 1787 int fbSamples = 0; 1788 1789 if (colorAttachmentTexture) 1790 { 1791 gl.glGenTextures(1, &tex1Id); 1792 gl.glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, tex1Id); 1793 gl.glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_numSamples1, m_internalFormat, m_fboSize, m_fboSize, fixedSampleLocations1); 1794 GLU_EXPECT_NO_ERROR(gl.glGetError(), "gen texture 1"); 1795 gl.glGetTexLevelParameteriv(GL_TEXTURE_2D_MULTISAMPLE, 0, GL_TEXTURE_SAMPLES, &fbSamples); 1796 1797 gl.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D_MULTISAMPLE, tex1Id, 0); 1798 GLU_EXPECT_NO_ERROR(gl.glGetError(), "attach to c1"); 1799 } 1800 else if (colorAttachmentRbo) 1801 { 1802 gl.glGenRenderbuffers(1, &rboId); 1803 gl.glBindRenderbuffer(GL_RENDERBUFFER, rboId); 1804 gl.glRenderbufferStorageMultisample(GL_RENDERBUFFER, m_numSamples1, m_internalFormat, m_fboSize, m_fboSize); 1805 GLU_EXPECT_NO_ERROR(gl.glGetError(), "gen rb"); 1806 gl.glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_SAMPLES, &fbSamples); 1807 1808 gl.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_RENDERBUFFER, rboId); 1809 GLU_EXPECT_NO_ERROR(gl.glGetError(), "attach to c1"); 1810 } 1811 else 1812 DE_ASSERT(DE_FALSE); 1813 1814 { 1815 glw::GLenum status = gl.glCheckFramebufferStatus(GL_FRAMEBUFFER); 1816 1817 if ((textureSamples != fbSamples) || (fixedSampleLocations0 != fixedSampleLocations1)) 1818 { 1819 if (status != GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE) // should not be complete 1820 { 1821 m_testCtx.getLog() << tcu::TestLog::Message << "ERROR! Expected GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE, got " << glu::getFramebufferStatusName(status) << tcu::TestLog::EndMessage; 1822 testFailed = true; 1823 } 1824 } 1825 else 1826 { 1827 if (status != GL_FRAMEBUFFER_COMPLETE) // should be complete 1828 { 1829 m_testCtx.getLog() << tcu::TestLog::Message << "ERROR! Expected GL_FRAMEBUFFER_COMPLETE, got " << glu::getFramebufferStatusName(status) << tcu::TestLog::EndMessage; 1830 testFailed = true; 1831 } 1832 } 1833 } 1834 } 1835 } 1836 catch (...) 1837 { 1838 gl.glDeleteFramebuffers(1, &fboId); 1839 gl.glDeleteRenderbuffers(1, &rboId); 1840 gl.glDeleteTextures(1, &tex0Id); 1841 gl.glDeleteTextures(1, &tex1Id); 1842 throw; 1843 } 1844 1845 gl.glDeleteFramebuffers(1, &fboId); 1846 gl.glDeleteRenderbuffers(1, &rboId); 1847 gl.glDeleteTextures(1, &tex0Id); 1848 gl.glDeleteTextures(1, &tex1Id); 1849 1850 if (testFailed) 1851 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got wrong error code"); 1852 else 1853 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 1854 return STOP; 1855} 1856 1857void NegativeFramebufferCase::getFormatSamples (glw::GLenum target, std::vector<int>& samples) 1858{ 1859 const glw::Functions gl = m_context.getRenderContext().getFunctions(); 1860 int sampleCount = 0; 1861 1862 gl.getInternalformativ(target, m_internalFormat, GL_NUM_SAMPLE_COUNTS, 1, &sampleCount); 1863 samples.resize(sampleCount); 1864 1865 if (sampleCount > 0) 1866 { 1867 gl.getInternalformativ(target, m_internalFormat, GL_SAMPLES, sampleCount, &samples[0]); 1868 GLU_EXPECT_NO_ERROR(gl.getError(), "get max samples"); 1869 } 1870} 1871 1872class NegativeTexParameterCase : public TestCase 1873{ 1874public: 1875 enum TexParam 1876 { 1877 TEXTURE_MIN_FILTER = 0, 1878 TEXTURE_MAG_FILTER, 1879 TEXTURE_WRAP_S, 1880 TEXTURE_WRAP_T, 1881 TEXTURE_WRAP_R, 1882 TEXTURE_MIN_LOD, 1883 TEXTURE_MAX_LOD, 1884 TEXTURE_COMPARE_MODE, 1885 TEXTURE_COMPARE_FUNC, 1886 TEXTURE_BASE_LEVEL, 1887 1888 TEXTURE_LAST 1889 }; 1890 1891 NegativeTexParameterCase (Context& context, const char* name, const char* desc, TexParam param); 1892 ~NegativeTexParameterCase (void); 1893 1894private: 1895 void init (void); 1896 void deinit (void); 1897 IterateResult iterate (void); 1898 1899 glw::GLenum getParamGLEnum (void) const; 1900 glw::GLint getParamValue (void) const; 1901 glw::GLenum getExpectedError (void) const; 1902 1903 const TexParam m_texParam; 1904 int m_iteration; 1905}; 1906 1907NegativeTexParameterCase::NegativeTexParameterCase (Context& context, const char* name, const char* desc, TexParam param) 1908 : TestCase (context, name, desc) 1909 , m_texParam (param) 1910 , m_iteration (0) 1911{ 1912 DE_ASSERT(param < TEXTURE_LAST); 1913} 1914 1915NegativeTexParameterCase::~NegativeTexParameterCase (void) 1916{ 1917 deinit(); 1918} 1919 1920void NegativeTexParameterCase::init (void) 1921{ 1922 // default value 1923 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 1924} 1925 1926void NegativeTexParameterCase::deinit (void) 1927{ 1928} 1929 1930NegativeTexParameterCase::IterateResult NegativeTexParameterCase::iterate (void) 1931{ 1932 static const struct TextureType 1933 { 1934 const char* name; 1935 glw::GLenum target; 1936 glw::GLenum internalFormat; 1937 bool isArrayType; 1938 } types[] = 1939 { 1940 { "color", GL_TEXTURE_2D_MULTISAMPLE, GL_RGBA8, false }, 1941 { "color array", GL_TEXTURE_2D_MULTISAMPLE_ARRAY, GL_RGBA8, true }, 1942 { "signed integer", GL_TEXTURE_2D_MULTISAMPLE, GL_R8I, false }, 1943 { "signed integer array", GL_TEXTURE_2D_MULTISAMPLE_ARRAY, GL_R8I, true }, 1944 { "unsigned integer", GL_TEXTURE_2D_MULTISAMPLE, GL_R8UI, false }, 1945 { "unsigned integer array", GL_TEXTURE_2D_MULTISAMPLE_ARRAY, GL_R8UI, true }, 1946 }; 1947 1948 const tcu::ScopedLogSection scope(m_testCtx.getLog(), "Iteration", std::string() + "Testing parameter with " + types[m_iteration].name + " texture"); 1949 const bool supportsES32orGL45 = 1950 glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)) || 1951 glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5)); 1952 1953 if (types[m_iteration].isArrayType && !supportsES32orGL45 && !m_context.getContextInfo().isExtensionSupported("GL_OES_texture_storage_multisample_2d_array")) 1954 m_testCtx.getLog() << tcu::TestLog::Message << "GL_OES_texture_storage_multisample_2d_array not supported, skipping target" << tcu::TestLog::EndMessage; 1955 else 1956 { 1957 glu::CallLogWrapper gl (m_context.getRenderContext().getFunctions(), m_testCtx.getLog()); 1958 glu::Texture texture (m_context.getRenderContext()); 1959 glw::GLenum error; 1960 1961 gl.enableLogging(true); 1962 1963 // gen texture 1964 1965 gl.glBindTexture(types[m_iteration].target, *texture); 1966 1967 if (types[m_iteration].isArrayType) 1968 gl.glTexStorage3DMultisample(types[m_iteration].target, 1, types[m_iteration].internalFormat, 16, 16, 16, GL_FALSE); 1969 else 1970 gl.glTexStorage2DMultisample(types[m_iteration].target, 1, types[m_iteration].internalFormat, 16, 16, GL_FALSE); 1971 GLU_EXPECT_NO_ERROR(gl.glGetError(), "setup texture"); 1972 1973 // set param 1974 1975 gl.glTexParameteri(types[m_iteration].target, getParamGLEnum(), getParamValue()); 1976 error = gl.glGetError(); 1977 1978 // expect failure 1979 1980 if (error != getExpectedError()) 1981 { 1982 m_testCtx.getLog() << tcu::TestLog::Message << "Got unexpected error: " << glu::getErrorStr(error) << ", expected: " << glu::getErrorStr(getExpectedError()) << tcu::TestLog::EndMessage; 1983 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got wrong error code"); 1984 } 1985 } 1986 1987 if (++m_iteration < DE_LENGTH_OF_ARRAY(types)) 1988 return CONTINUE; 1989 return STOP; 1990} 1991 1992glw::GLenum NegativeTexParameterCase::getParamGLEnum (void) const 1993{ 1994 switch (m_texParam) 1995 { 1996 case TEXTURE_MIN_FILTER: return GL_TEXTURE_MIN_FILTER; 1997 case TEXTURE_MAG_FILTER: return GL_TEXTURE_MAG_FILTER; 1998 case TEXTURE_WRAP_S: return GL_TEXTURE_WRAP_S; 1999 case TEXTURE_WRAP_T: return GL_TEXTURE_WRAP_T; 2000 case TEXTURE_WRAP_R: return GL_TEXTURE_WRAP_R; 2001 case TEXTURE_MIN_LOD: return GL_TEXTURE_MIN_LOD; 2002 case TEXTURE_MAX_LOD: return GL_TEXTURE_MAX_LOD; 2003 case TEXTURE_COMPARE_MODE: return GL_TEXTURE_COMPARE_MODE; 2004 case TEXTURE_COMPARE_FUNC: return GL_TEXTURE_COMPARE_FUNC; 2005 case TEXTURE_BASE_LEVEL: return GL_TEXTURE_BASE_LEVEL; 2006 default: 2007 DE_ASSERT(DE_FALSE); 2008 return 0; 2009 } 2010} 2011 2012glw::GLint NegativeTexParameterCase::getParamValue (void) const 2013{ 2014 switch (m_texParam) 2015 { 2016 case TEXTURE_MIN_FILTER: return GL_LINEAR; 2017 case TEXTURE_MAG_FILTER: return GL_LINEAR; 2018 case TEXTURE_WRAP_S: return GL_CLAMP_TO_EDGE; 2019 case TEXTURE_WRAP_T: return GL_CLAMP_TO_EDGE; 2020 case TEXTURE_WRAP_R: return GL_CLAMP_TO_EDGE; 2021 case TEXTURE_MIN_LOD: return 1; 2022 case TEXTURE_MAX_LOD: return 5; 2023 case TEXTURE_COMPARE_MODE: return GL_NONE; 2024 case TEXTURE_COMPARE_FUNC: return GL_NOTEQUAL; 2025 case TEXTURE_BASE_LEVEL: return 2; 2026 default: 2027 DE_ASSERT(DE_FALSE); 2028 return 0; 2029 } 2030} 2031 2032glw::GLenum NegativeTexParameterCase::getExpectedError (void) const 2033{ 2034 switch (m_texParam) 2035 { 2036 case TEXTURE_MIN_FILTER: return GL_INVALID_ENUM; 2037 case TEXTURE_MAG_FILTER: return GL_INVALID_ENUM; 2038 case TEXTURE_WRAP_S: return GL_INVALID_ENUM; 2039 case TEXTURE_WRAP_T: return GL_INVALID_ENUM; 2040 case TEXTURE_WRAP_R: return GL_INVALID_ENUM; 2041 case TEXTURE_MIN_LOD: return GL_INVALID_ENUM; 2042 case TEXTURE_MAX_LOD: return GL_INVALID_ENUM; 2043 case TEXTURE_COMPARE_MODE: return GL_INVALID_ENUM; 2044 case TEXTURE_COMPARE_FUNC: return GL_INVALID_ENUM; 2045 case TEXTURE_BASE_LEVEL: return GL_INVALID_OPERATION; 2046 default: 2047 DE_ASSERT(DE_FALSE); 2048 return 0; 2049 } 2050} 2051 2052class NegativeTexureSampleCase : public TestCase 2053{ 2054public: 2055 enum SampleCountParam 2056 { 2057 SAMPLECOUNT_HIGH = 0, 2058 SAMPLECOUNT_ZERO, 2059 2060 SAMPLECOUNT_LAST 2061 }; 2062 2063 NegativeTexureSampleCase (Context& context, const char* name, const char* desc, SampleCountParam param); 2064private: 2065 IterateResult iterate (void); 2066 2067 const SampleCountParam m_sampleParam; 2068}; 2069 2070NegativeTexureSampleCase::NegativeTexureSampleCase (Context& context, const char* name, const char* desc, SampleCountParam param) 2071 : TestCase (context, name, desc) 2072 , m_sampleParam (param) 2073{ 2074 DE_ASSERT(param < SAMPLECOUNT_LAST); 2075} 2076 2077NegativeTexureSampleCase::IterateResult NegativeTexureSampleCase::iterate (void) 2078{ 2079 const glw::GLenum expectedError = (m_sampleParam == SAMPLECOUNT_HIGH) ? (GL_INVALID_OPERATION) : (GL_INVALID_VALUE); 2080 glu::CallLogWrapper gl (m_context.getRenderContext().getFunctions(), m_testCtx.getLog()); 2081 glu::Texture texture (m_context.getRenderContext()); 2082 glw::GLenum error; 2083 int samples = -1; 2084 2085 gl.enableLogging(true); 2086 2087 // calc samples 2088 2089 if (m_sampleParam == SAMPLECOUNT_HIGH) 2090 { 2091 int maxSamples = 0; 2092 2093 gl.glGetInternalformativ(GL_TEXTURE_2D_MULTISAMPLE, GL_RGBA8, GL_SAMPLES, 1, &maxSamples); 2094 GLU_EXPECT_NO_ERROR(gl.glGetError(), "glGetInternalformativ"); 2095 2096 samples = maxSamples + 1; 2097 } 2098 else if (m_sampleParam == SAMPLECOUNT_ZERO) 2099 samples = 0; 2100 else 2101 DE_ASSERT(DE_FALSE); 2102 2103 // create texture with bad values 2104 2105 gl.glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, *texture); 2106 gl.glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, GL_RGBA8, 64, 64, GL_FALSE); 2107 error = gl.glGetError(); 2108 2109 // expect failure 2110 2111 if (error == expectedError) 2112 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 2113 else 2114 { 2115 m_testCtx.getLog() << tcu::TestLog::Message << "Got unexpected error: " << glu::getErrorStr(error) << ", expected: " << glu::getErrorStr(expectedError) << tcu::TestLog::EndMessage; 2116 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got wrong error code"); 2117 } 2118 2119 return STOP; 2120} 2121 2122 2123} // anonymous 2124 2125TextureMultisampleTests::TextureMultisampleTests (Context& context) 2126 : TestCaseGroup(context, "multisample", "Multisample texture tests") 2127{ 2128} 2129 2130TextureMultisampleTests::~TextureMultisampleTests (void) 2131{ 2132} 2133 2134void TextureMultisampleTests::init (void) 2135{ 2136 static const int sampleCounts[] = { 1, 2, 3, 4, 8, 10, 12, 13, 16, 64 }; 2137 2138 static const struct TextureType 2139 { 2140 const char* name; 2141 MultisampleTextureUsageCase::TextureType type; 2142 } textureTypes[] = 2143 { 2144 { "texture_color_2d", MultisampleTextureUsageCase::TEXTURE_COLOR_2D }, 2145 { "texture_color_2d_array", MultisampleTextureUsageCase::TEXTURE_COLOR_2D_ARRAY }, 2146 { "texture_int_2d", MultisampleTextureUsageCase::TEXTURE_INT_2D }, 2147 { "texture_int_2d_array", MultisampleTextureUsageCase::TEXTURE_INT_2D_ARRAY }, 2148 { "texture_uint_2d", MultisampleTextureUsageCase::TEXTURE_UINT_2D }, 2149 { "texture_uint_2d_array", MultisampleTextureUsageCase::TEXTURE_UINT_2D_ARRAY }, 2150 { "texture_depth_2d", MultisampleTextureUsageCase::TEXTURE_DEPTH_2D }, 2151 { "texture_depth_2d_array", MultisampleTextureUsageCase::TEXTURE_DEPTH_2D_ARRAY }, 2152 }; 2153 2154 // .samples_x 2155 for (int sampleNdx = 0; sampleNdx < DE_LENGTH_OF_ARRAY(sampleCounts); ++sampleNdx) 2156 { 2157 tcu::TestCaseGroup* const sampleGroup = new tcu::TestCaseGroup(m_testCtx, (std::string("samples_") + de::toString(sampleCounts[sampleNdx])).c_str(), "Test with N samples"); 2158 addChild(sampleGroup); 2159 2160 // position query works 2161 sampleGroup->addChild(new SamplePosRasterizationTest(m_context, "sample_position", "test SAMPLE_POSITION", sampleCounts[sampleNdx])); 2162 2163 // sample mask is ANDed properly 2164 sampleGroup->addChild(new SampleMaskCase(m_context, "sample_mask_only", "Test with SampleMask only", sampleCounts[sampleNdx], SampleMaskCase::FLAGS_NONE)); 2165 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)); 2166 sampleGroup->addChild(new SampleMaskCase(m_context, "sample_mask_and_sample_coverage", "Test with SampleMask and sample coverage", sampleCounts[sampleNdx], SampleMaskCase::FLAGS_SAMPLE_COVERAGE)); 2167 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)); 2168 2169 // high bits cause no unexpected behavior 2170 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)); 2171 2172 // usage 2173 for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(textureTypes); ++typeNdx) 2174 sampleGroup->addChild(new MultisampleTextureUsageCase(m_context, (std::string("use_") + textureTypes[typeNdx].name).c_str(), textureTypes[typeNdx].name, sampleCounts[sampleNdx], textureTypes[typeNdx].type)); 2175 } 2176 2177 // .negative 2178 { 2179 tcu::TestCaseGroup* const negativeGroup = new tcu::TestCaseGroup(m_testCtx, "negative", "Negative tests"); 2180 addChild(negativeGroup); 2181 2182 negativeGroup->addChild(new NegativeFramebufferCase (m_context, "fbo_attach_different_sample_count_tex_tex", "Attach different sample counts", NegativeFramebufferCase::CASE_DIFFERENT_N_SAMPLES_TEX)); 2183 negativeGroup->addChild(new NegativeFramebufferCase (m_context, "fbo_attach_different_sample_count_tex_rbo", "Attach different sample counts", NegativeFramebufferCase::CASE_DIFFERENT_N_SAMPLES_RBO)); 2184 negativeGroup->addChild(new NegativeFramebufferCase (m_context, "fbo_attach_different_fixed_state_tex_tex", "Attach fixed and non fixed", NegativeFramebufferCase::CASE_DIFFERENT_FIXED_TEX)); 2185 negativeGroup->addChild(new NegativeFramebufferCase (m_context, "fbo_attach_different_fixed_state_tex_rbo", "Attach fixed and non fixed", NegativeFramebufferCase::CASE_DIFFERENT_FIXED_RBO)); 2186 negativeGroup->addChild(new NegativeFramebufferCase (m_context, "fbo_attach_non_zero_level", "Attach non-zero level", NegativeFramebufferCase::CASE_NON_ZERO_LEVEL)); 2187 negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_min_filter", "set TEXTURE_MIN_FILTER", NegativeTexParameterCase::TEXTURE_MIN_FILTER)); 2188 negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_mag_filter", "set TEXTURE_MAG_FILTER", NegativeTexParameterCase::TEXTURE_MAG_FILTER)); 2189 negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_wrap_s", "set TEXTURE_WRAP_S", NegativeTexParameterCase::TEXTURE_WRAP_S)); 2190 negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_wrap_t", "set TEXTURE_WRAP_T", NegativeTexParameterCase::TEXTURE_WRAP_T)); 2191 negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_wrap_r", "set TEXTURE_WRAP_R", NegativeTexParameterCase::TEXTURE_WRAP_R)); 2192 negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_min_lod", "set TEXTURE_MIN_LOD", NegativeTexParameterCase::TEXTURE_MIN_LOD)); 2193 negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_max_lod", "set TEXTURE_MAX_LOD", NegativeTexParameterCase::TEXTURE_MAX_LOD)); 2194 negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_compare_mode", "set TEXTURE_COMPARE_MODE", NegativeTexParameterCase::TEXTURE_COMPARE_MODE)); 2195 negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_compare_func", "set TEXTURE_COMPARE_FUNC", NegativeTexParameterCase::TEXTURE_COMPARE_FUNC)); 2196 negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_base_level", "set TEXTURE_BASE_LEVEL", NegativeTexParameterCase::TEXTURE_BASE_LEVEL)); 2197 negativeGroup->addChild(new NegativeTexureSampleCase(m_context, "texture_high_sample_count", "TexStorage with high numSamples", NegativeTexureSampleCase::SAMPLECOUNT_HIGH)); 2198 negativeGroup->addChild(new NegativeTexureSampleCase(m_context, "texture_zero_sample_count", "TexStorage with zero numSamples", NegativeTexureSampleCase::SAMPLECOUNT_ZERO)); 2199 } 2200} 2201 2202} // Functional 2203} // gles31 2204} // deqp 2205