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