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 size tests 22 *//*--------------------------------------------------------------------*/ 23 24 #include "es31fShaderTextureSizeTests.hpp" 25 #include "gluRenderContext.hpp" 26 #include "gluShaderProgram.hpp" 27 #include "gluPixelTransfer.hpp" 28 #include "gluContextInfo.hpp" 29 #include "glwEnums.hpp" 30 #include "glwFunctions.hpp" 31 #include "tcuTestLog.hpp" 32 #include "tcuStringTemplate.hpp" 33 #include "tcuSurface.hpp" 34 #include "tcuRenderTarget.hpp" 35 #include "deStringUtil.hpp" 36 37 using namespace glw; 38 39 namespace deqp 40 { 41 namespace gles31 42 { 43 namespace Functional 44 { 45 namespace 46 { 47 48 static const char* const s_positionVertexShaderSource = "${GLSL_VERSION_DECL}\n" 49 "in highp vec4 a_position;\n" 50 "void main (void)\n" 51 "{\n" 52 " gl_Position = a_position;\n" 53 "}\n"; 54 55 static std::string specializeShader(Context& context, const char* code) 56 { 57 glu::GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(context.getRenderContext().getType()); 58 std::map<std::string, std::string> specializationMap; 59 60 specializationMap["GLSL_VERSION_DECL"] = glu::getGLSLVersionDeclaration(glslVersion); 61 62 return tcu::StringTemplate(code).specialize(specializationMap); 63 } 64 65 class TextureSizeCase : public TestCase 66 { 67 public: 68 enum TextureType 69 { 70 TEXTURE_FLOAT_2D = 0, 71 TEXTURE_FLOAT_2D_ARRAY, 72 TEXTURE_INT_2D, 73 TEXTURE_INT_2D_ARRAY, 74 TEXTURE_UINT_2D, 75 TEXTURE_UINT_2D_ARRAY, 76 77 TEXTURE_LAST 78 }; 79 80 TextureSizeCase (Context& context, const char* name, const char* desc, TextureType type, int samples); 81 ~TextureSizeCase (void); 82 83 private: 84 void init (void); 85 void deinit (void); 86 IterateResult iterate (void); 87 88 std::string genFragmentSource (void); 89 glw::GLenum getTextureGLTarget (void); 90 glw::GLenum getTextureGLInternalFormat (void); 91 92 void createTexture (const tcu::IVec3& size); 93 void deleteTexture (void); 94 void runShader (tcu::Surface& dst, const tcu::IVec3& size); 95 bool verifyImage (const tcu::Surface& dst); 96 97 const TextureType m_type; 98 const int m_numSamples; 99 const bool m_isArrayType; 100 101 glw::GLuint m_texture; 102 glw::GLuint m_vbo; 103 glu::ShaderProgram* m_shader; 104 std::vector<tcu::IVec3> m_iterations; 105 int m_iteration; 106 107 bool m_allIterationsPassed; 108 bool m_allCasesSkipped; 109 }; 110 111 TextureSizeCase::TextureSizeCase (Context& context, const char* name, const char* desc, TextureType type, int samples) 112 : TestCase (context, name, desc) 113 , m_type (type) 114 , m_numSamples (samples) 115 , m_isArrayType (m_type == TEXTURE_FLOAT_2D_ARRAY || m_type == TEXTURE_INT_2D_ARRAY || m_type == TEXTURE_UINT_2D_ARRAY) 116 , m_texture (0) 117 , m_vbo (0) 118 , m_shader (DE_NULL) 119 , m_iteration (0) 120 , m_allIterationsPassed (true) 121 , m_allCasesSkipped (true) 122 { 123 DE_ASSERT(type < TEXTURE_LAST); 124 } 125 126 TextureSizeCase::~TextureSizeCase (void) 127 { 128 deinit(); 129 } 130 131 void TextureSizeCase::init (void) 132 { 133 static const tcu::IVec2 testSizes2D[] = 134 { 135 tcu::IVec2(1, 1), 136 tcu::IVec2(1, 4), 137 tcu::IVec2(4, 8), 138 tcu::IVec2(21, 11), 139 tcu::IVec2(107, 254), 140 tcu::IVec2(-1, 3), 141 tcu::IVec2(3, -1), 142 }; 143 static const tcu::IVec3 testSizes3D[] = 144 { 145 tcu::IVec3(1, 1, 1), 146 tcu::IVec3(1, 4, 7), 147 tcu::IVec3(4, 8, 12), 148 tcu::IVec3(21, 11, 9), 149 tcu::IVec3(107, 254, 2), 150 tcu::IVec3(-1, 3, 3), 151 tcu::IVec3(3, -1, 3), 152 tcu::IVec3(4, 4, -1), 153 }; 154 static const tcu::Vec4 fullscreenQuad[] = 155 { 156 tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f), 157 tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f), 158 tcu::Vec4( 1.0f, 1.0f, 0.0f, 1.0f), 159 tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f) 160 }; 161 162 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 163 const bool supportsES32 = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)); 164 165 // requirements 166 if (m_isArrayType && !supportsES32 && !m_context.getContextInfo().isExtensionSupported("GL_OES_texture_storage_multisample_2d_array")) 167 TCU_THROW(NotSupportedError, "Test requires OES_texture_storage_multisample_2d_array extension"); 168 169 if (m_context.getRenderTarget().getWidth() < 1 || m_context.getRenderTarget().getHeight() < 1) 170 TCU_THROW(NotSupportedError, "rendertarget size must be at least 1x1"); 171 172 glw::GLint maxTextureSize = 0; 173 glw::GLint maxTextureLayers = 0; 174 glw::GLint maxSamples = 0; 175 176 gl.getIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize); 177 gl.getIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &maxTextureLayers); 178 gl.getInternalformativ(getTextureGLTarget(), getTextureGLInternalFormat(), GL_SAMPLES, 1, &maxSamples); 179 180 if (m_numSamples > maxSamples) 181 TCU_THROW(NotSupportedError, "sample count is not supported"); 182 183 // gen shade 184 185 m_shader = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(specializeShader(m_context, s_positionVertexShaderSource)) << glu::FragmentSource(genFragmentSource())); 186 m_testCtx.getLog() << *m_shader; 187 if (!m_shader->isOk()) 188 throw tcu::TestError("shader build failed"); 189 190 // gen buffer 191 192 gl.genBuffers(1, &m_vbo); 193 gl.bindBuffer(GL_ARRAY_BUFFER, m_vbo); 194 gl.bufferData(GL_ARRAY_BUFFER, sizeof(fullscreenQuad), fullscreenQuad, GL_STATIC_DRAW); 195 196 // gen iterations 197 198 m_testCtx.getLog() 199 << tcu::TestLog::Message 200 << "GL_MAX_TEXTURE_SIZE = " << maxTextureSize << "\n" 201 << "GL_MAX_ARRAY_TEXTURE_LAYERS = " << maxTextureLayers 202 << tcu::TestLog::EndMessage; 203 204 if (!m_isArrayType) 205 { 206 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(testSizes2D); ++ndx) 207 { 208 if (testSizes2D[ndx].x() <= maxTextureSize && testSizes2D[ndx].y() <= maxTextureSize) 209 { 210 const int w = (testSizes2D[ndx].x() < 0) ? (maxTextureSize) : (testSizes2D[ndx].x()); 211 const int h = (testSizes2D[ndx].y() < 0) ? (maxTextureSize) : (testSizes2D[ndx].y()); 212 213 m_iterations.push_back(tcu::IVec3(w, h, 0)); 214 } 215 } 216 } 217 else 218 { 219 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(testSizes3D); ++ndx) 220 { 221 if (testSizes3D[ndx].x() <= maxTextureSize && testSizes3D[ndx].y() <= maxTextureSize && testSizes3D[ndx].z() <= maxTextureLayers) 222 { 223 const int w = (testSizes3D[ndx].x() < 0) ? (maxTextureSize) : (testSizes3D[ndx].x()); 224 const int h = (testSizes3D[ndx].y() < 0) ? (maxTextureSize) : (testSizes3D[ndx].y()); 225 const int d = (testSizes3D[ndx].z() < 0) ? (maxTextureLayers) : (testSizes3D[ndx].z()); 226 227 m_iterations.push_back(tcu::IVec3(w, h, d)); 228 } 229 } 230 } 231 } 232 233 void TextureSizeCase::deinit (void) 234 { 235 if (m_texture) 236 { 237 m_context.getRenderContext().getFunctions().deleteTextures(1, &m_texture); 238 m_texture = 0; 239 } 240 241 if (m_vbo) 242 { 243 m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_vbo); 244 m_vbo = 0; 245 } 246 247 if (m_shader) 248 { 249 delete m_shader; 250 m_shader = DE_NULL; 251 } 252 } 253 254 TextureSizeCase::IterateResult TextureSizeCase::iterate (void) 255 { 256 tcu::Surface result (1, 1); 257 bool skipTest = false; 258 259 m_testCtx.getLog() << tcu::TestLog::Message << "\nIteration " << (m_iteration+1) << " / " << (int)m_iterations.size() << tcu::TestLog::EndMessage; 260 261 try 262 { 263 // set texture size 264 265 createTexture(m_iterations[m_iteration]); 266 267 // query texture size 268 269 runShader(result, m_iterations[m_iteration]); 270 } 271 catch (glu::OutOfMemoryError&) 272 { 273 m_testCtx.getLog() << tcu::TestLog::Message << "Got GL_OUT_OF_MEMORY, skipping this size" << tcu::TestLog::EndMessage; 274 275 skipTest = true; 276 } 277 278 // free resources 279 280 deleteTexture(); 281 282 // queried value was correct? 283 284 if (!skipTest) 285 { 286 m_allCasesSkipped = false; 287 288 if (!verifyImage(result)) 289 m_allIterationsPassed = false; 290 } 291 292 // final result 293 294 if (++m_iteration < (int)m_iterations.size()) 295 return CONTINUE; 296 297 if (!m_allIterationsPassed) 298 { 299 m_testCtx.getLog() << tcu::TestLog::Message << "One or more test sizes failed." << tcu::TestLog::EndMessage; 300 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got invalid texture size"); 301 } 302 else if (m_allCasesSkipped) 303 { 304 m_testCtx.getLog() << tcu::TestLog::Message << "Could not test any texture size, texture creation failed." << tcu::TestLog::EndMessage; 305 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "All test texture creations failed"); 306 } 307 else 308 { 309 m_testCtx.getLog() << tcu::TestLog::Message << "All texture sizes passed." << tcu::TestLog::EndMessage; 310 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 311 } 312 313 return STOP; 314 } 315 316 std::string TextureSizeCase::genFragmentSource (void) 317 { 318 static const char* const templateSource = "${GLSL_VERSION_DECL}\n" 319 "${EXTENSION_STATEMENT}" 320 "layout(location = 0) out highp vec4 fragColor;\n" 321 "uniform highp ${SAMPLERTYPE} u_sampler;\n" 322 "uniform highp ${SIZETYPE} u_size;\n" 323 "void main (void)\n" 324 "{\n" 325 " const highp vec4 okColor = vec4(0.0, 1.0, 0.0, 1.0);\n" 326 " const highp vec4 failColor = vec4(1.0, 0.0, 0.0, 1.0);\n" 327 " fragColor = (textureSize(u_sampler) == u_size) ? (okColor) : (failColor);\n" 328 "}\n"; 329 330 std::map<std::string, std::string> args; 331 332 switch (m_type) 333 { 334 case TEXTURE_FLOAT_2D: args["SAMPLERTYPE"] = "sampler2DMS"; break; 335 case TEXTURE_FLOAT_2D_ARRAY: args["SAMPLERTYPE"] = "sampler2DMSArray"; break; 336 case TEXTURE_INT_2D: args["SAMPLERTYPE"] = "isampler2DMS"; break; 337 case TEXTURE_INT_2D_ARRAY: args["SAMPLERTYPE"] = "isampler2DMSArray"; break; 338 case TEXTURE_UINT_2D: args["SAMPLERTYPE"] = "usampler2DMS"; break; 339 case TEXTURE_UINT_2D_ARRAY: args["SAMPLERTYPE"] = "usampler2DMSArray"; break; 340 default: 341 DE_ASSERT(DE_FALSE); 342 } 343 344 if (!m_isArrayType) 345 args["SIZETYPE"] = "ivec2"; 346 else 347 args["SIZETYPE"] = "ivec3"; 348 349 const glu::ContextType contextType = m_context.getRenderContext().getType(); 350 const bool supportsES32 = glu::contextSupports(contextType, glu::ApiType::es(3, 2)); 351 352 if (m_isArrayType && !supportsES32) 353 args["EXTENSION_STATEMENT"] = "#extension GL_OES_texture_storage_multisample_2d_array : require\n"; 354 else 355 args["EXTENSION_STATEMENT"] = ""; 356 357 args["GLSL_VERSION_DECL"] = glu::getGLSLVersionDeclaration(glu::getContextTypeGLSLVersion(contextType)); 358 359 return tcu::StringTemplate(templateSource).specialize(args); 360 } 361 362 glw::GLenum TextureSizeCase::getTextureGLTarget (void) 363 { 364 switch (m_type) 365 { 366 case TEXTURE_FLOAT_2D: return GL_TEXTURE_2D_MULTISAMPLE; 367 case TEXTURE_FLOAT_2D_ARRAY: return GL_TEXTURE_2D_MULTISAMPLE_ARRAY; 368 case TEXTURE_INT_2D: return GL_TEXTURE_2D_MULTISAMPLE; 369 case TEXTURE_INT_2D_ARRAY: return GL_TEXTURE_2D_MULTISAMPLE_ARRAY; 370 case TEXTURE_UINT_2D: return GL_TEXTURE_2D_MULTISAMPLE; 371 case TEXTURE_UINT_2D_ARRAY: return GL_TEXTURE_2D_MULTISAMPLE_ARRAY; 372 default: 373 DE_ASSERT(DE_FALSE); 374 return 0; 375 } 376 } 377 378 glw::GLenum TextureSizeCase::getTextureGLInternalFormat (void) 379 { 380 switch (m_type) 381 { 382 case TEXTURE_FLOAT_2D: return GL_RGBA8; 383 case TEXTURE_FLOAT_2D_ARRAY: return GL_RGBA8; 384 case TEXTURE_INT_2D: return GL_R8I; 385 case TEXTURE_INT_2D_ARRAY: return GL_R8I; 386 case TEXTURE_UINT_2D: return GL_R8UI; 387 case TEXTURE_UINT_2D_ARRAY: return GL_R8UI; 388 default: 389 DE_ASSERT(DE_FALSE); 390 return 0; 391 } 392 } 393 394 void TextureSizeCase::createTexture (const tcu::IVec3& size) 395 { 396 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 397 398 if (!m_isArrayType) 399 m_testCtx.getLog() << tcu::TestLog::Message << "Creating texture with size " << size.x() << "x" << size.y() << tcu::TestLog::EndMessage; 400 else 401 m_testCtx.getLog() << tcu::TestLog::Message << "Creating texture with size " << size.x() << "x" << size.y() << "x" << size.z() << tcu::TestLog::EndMessage; 402 403 gl.genTextures(1, &m_texture); 404 gl.bindTexture(getTextureGLTarget(), m_texture); 405 GLU_EXPECT_NO_ERROR(gl.getError(), "texture gen"); 406 407 if (!m_isArrayType) 408 gl.texStorage2DMultisample(getTextureGLTarget(), m_numSamples, getTextureGLInternalFormat(), size.x(), size.y(), GL_FALSE); 409 else 410 gl.texStorage3DMultisample(getTextureGLTarget(), m_numSamples, getTextureGLInternalFormat(), size.x(), size.y(), size.z(), GL_FALSE); 411 GLU_EXPECT_NO_ERROR(gl.getError(), "texStorage"); 412 } 413 414 void TextureSizeCase::deleteTexture (void) 415 { 416 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 417 418 if (m_texture) 419 { 420 gl.deleteTextures(1, &m_texture); 421 m_texture = 0; 422 423 GLU_EXPECT_NO_ERROR(gl.getError(), "texture delete"); 424 } 425 } 426 427 void TextureSizeCase::runShader (tcu::Surface& dst, const tcu::IVec3& size) 428 { 429 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 430 const int positionLoc = gl.getAttribLocation(m_shader->getProgram(), "a_position"); 431 const int shaderSamplerLoc = gl.getUniformLocation(m_shader->getProgram(), "u_sampler"); 432 const int shaderSizeLoc = gl.getUniformLocation(m_shader->getProgram(), "u_size"); 433 434 m_testCtx.getLog() << tcu::TestLog::Message << "Running the verification shader." << tcu::TestLog::EndMessage; 435 436 GLU_EXPECT_NO_ERROR(gl.getError(), "preclear"); 437 gl.viewport(0, 0, 1, 1); 438 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f); 439 gl.clear(GL_COLOR_BUFFER_BIT); 440 GLU_EXPECT_NO_ERROR(gl.getError(), "clear"); 441 442 gl.bindBuffer(GL_ARRAY_BUFFER, m_vbo); 443 gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL); 444 gl.enableVertexAttribArray(positionLoc); 445 GLU_EXPECT_NO_ERROR(gl.getError(), "vertexAttrib"); 446 447 gl.useProgram(m_shader->getProgram()); 448 gl.uniform1i(shaderSamplerLoc, 0); 449 if (m_isArrayType) 450 gl.uniform3iv(shaderSizeLoc, 1, size.getPtr()); 451 else 452 gl.uniform2iv(shaderSizeLoc, 1, size.getPtr()); 453 GLU_EXPECT_NO_ERROR(gl.getError(), "setup program"); 454 455 gl.bindTexture(getTextureGLTarget(), m_texture); 456 GLU_EXPECT_NO_ERROR(gl.getError(), "bindtex"); 457 458 gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4); 459 GLU_EXPECT_NO_ERROR(gl.getError(), "drawArrays"); 460 461 gl.disableVertexAttribArray(positionLoc); 462 gl.useProgram(0); 463 GLU_EXPECT_NO_ERROR(gl.getError(), "cleanup"); 464 465 gl.finish(); 466 glu::readPixels(m_context.getRenderContext(), 0, 0, dst.getAccess()); 467 GLU_EXPECT_NO_ERROR(gl.getError(), "readPixels"); 468 } 469 470 bool TextureSizeCase::verifyImage (const tcu::Surface& dst) 471 { 472 DE_ASSERT(dst.getWidth() == 1 && dst.getHeight() == 1); 473 474 const int colorThresholdRed = 1 << (8 - m_context.getRenderTarget().getPixelFormat().redBits); 475 const int colorThresholdGreen = 1 << (8 - m_context.getRenderTarget().getPixelFormat().greenBits); 476 const int colorThresholdBlue = 1 << (8 - m_context.getRenderTarget().getPixelFormat().blueBits); 477 const tcu::RGBA color = dst.getPixel(0,0); 478 479 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying image." << tcu::TestLog::EndMessage; 480 481 // green 482 if (color.getRed() < colorThresholdRed && color.getGreen() > 255 - colorThresholdGreen && color.getBlue() < colorThresholdBlue) 483 { 484 m_testCtx.getLog() << tcu::TestLog::Message << "Result ok." << tcu::TestLog::EndMessage; 485 return true; 486 } 487 // red 488 else if (color.getRed() > 255 - colorThresholdRed && color.getGreen() < colorThresholdGreen && color.getBlue() < colorThresholdBlue) 489 { 490 m_testCtx.getLog() << tcu::TestLog::Message << "Image size incorrect." << tcu::TestLog::EndMessage; 491 return false; 492 } 493 494 m_testCtx.getLog() << tcu::TestLog::Message << "Expected either green or red pixel, got " << color << tcu::TestLog::EndMessage; 495 return false; 496 } 497 498 } // anonymous 499 500 ShaderTextureSizeTests::ShaderTextureSizeTests (Context& context) 501 : TestCaseGroup(context, "texture_size", "Texture size tests") 502 { 503 } 504 505 ShaderTextureSizeTests::~ShaderTextureSizeTests (void) 506 { 507 } 508 509 void ShaderTextureSizeTests::init (void) 510 { 511 static const struct SamplerType 512 { 513 TextureSizeCase::TextureType type; 514 const char* name; 515 } samplerTypes[] = 516 { 517 { TextureSizeCase::TEXTURE_FLOAT_2D, "texture_2d" }, 518 { TextureSizeCase::TEXTURE_FLOAT_2D_ARRAY, "texture_2d_array" }, 519 { TextureSizeCase::TEXTURE_INT_2D, "texture_int_2d" }, 520 { TextureSizeCase::TEXTURE_INT_2D_ARRAY, "texture_int_2d_array" }, 521 { TextureSizeCase::TEXTURE_UINT_2D, "texture_uint_2d" }, 522 { TextureSizeCase::TEXTURE_UINT_2D_ARRAY, "texture_uint_2d_array" }, 523 }; 524 525 static const int sampleCounts[] = { 1, 4 }; 526 527 for (int samplerTypeNdx = 0; samplerTypeNdx < DE_LENGTH_OF_ARRAY(samplerTypes); ++samplerTypeNdx) 528 { 529 for (int sampleCountNdx = 0; sampleCountNdx < DE_LENGTH_OF_ARRAY(sampleCounts); ++sampleCountNdx) 530 { 531 const std::string name = std::string() + "samples_" + de::toString(sampleCounts[sampleCountNdx]) + "_" + samplerTypes[samplerTypeNdx].name; 532 const std::string desc = std::string() + "samples count = " + de::toString(sampleCounts[sampleCountNdx]) + ", type = " + samplerTypes[samplerTypeNdx].name; 533 534 addChild(new TextureSizeCase(m_context, name.c_str(), desc.c_str(), samplerTypes[samplerTypeNdx].type, sampleCounts[sampleCountNdx])); 535 } 536 } 537 } 538 539 } // Functional 540 } // gles31 541 } // deqp 542