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