1 /*------------------------------------------------------------------------- 2 * drawElements Quality Program OpenGL ES 2.0 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 Texture size tests. 22 *//*--------------------------------------------------------------------*/ 23 24 #include "es2fTextureSizeTests.hpp" 25 #include "glsTextureTestUtil.hpp" 26 #include "gluTexture.hpp" 27 #include "gluStrUtil.hpp" 28 #include "gluTextureUtil.hpp" 29 #include "gluPixelTransfer.hpp" 30 #include "tcuTestLog.hpp" 31 #include "tcuTextureUtil.hpp" 32 33 #include "glwEnums.hpp" 34 #include "glwFunctions.hpp" 35 36 namespace deqp 37 { 38 namespace gles2 39 { 40 namespace Functional 41 { 42 43 using tcu::TestLog; 44 using std::vector; 45 using std::string; 46 using tcu::Sampler; 47 using namespace glu; 48 using namespace gls::TextureTestUtil; 49 using namespace glu::TextureTestUtil; 50 51 class Texture2DSizeCase : public tcu::TestCase 52 { 53 public: 54 Texture2DSizeCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* description, deUint32 format, deUint32 dataType, int width, int height, bool mipmaps); 55 ~Texture2DSizeCase (void); 56 57 void init (void); 58 void deinit (void); 59 IterateResult iterate (void); 60 61 private: 62 Texture2DSizeCase (const Texture2DSizeCase& other); 63 Texture2DSizeCase& operator= (const Texture2DSizeCase& other); 64 65 glu::RenderContext& m_renderCtx; 66 67 deUint32 m_format; 68 deUint32 m_dataType; 69 int m_width; 70 int m_height; 71 bool m_useMipmaps; 72 73 glu::Texture2D* m_texture; 74 TextureRenderer m_renderer; 75 }; 76 77 Texture2DSizeCase::Texture2DSizeCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* description, deUint32 format, deUint32 dataType, int width, int height, bool mipmaps) 78 : TestCase (testCtx, name, description) 79 , m_renderCtx (renderCtx) 80 , m_format (format) 81 , m_dataType (dataType) 82 , m_width (width) 83 , m_height (height) 84 , m_useMipmaps (mipmaps) 85 , m_texture (DE_NULL) 86 , m_renderer (renderCtx, testCtx.getLog(), glu::GLSL_VERSION_100_ES, glu::PRECISION_MEDIUMP) 87 { 88 } 89 90 Texture2DSizeCase::~Texture2DSizeCase (void) 91 { 92 Texture2DSizeCase::deinit(); 93 } 94 95 void Texture2DSizeCase::init (void) 96 { 97 DE_ASSERT(!m_texture); 98 m_texture = new Texture2D(m_renderCtx, m_format, m_dataType, m_width, m_height); 99 100 int numLevels = m_useMipmaps ? deLog2Floor32(de::max(m_width, m_height))+1 : 1; 101 102 // Fill levels. 103 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++) 104 { 105 m_texture->getRefTexture().allocLevel(levelNdx); 106 tcu::fillWithComponentGradients(m_texture->getRefTexture().getLevel(levelNdx), tcu::Vec4(-1.0f, -1.0f, -1.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f)); 107 } 108 } 109 110 void Texture2DSizeCase::deinit (void) 111 { 112 delete m_texture; 113 m_texture = DE_NULL; 114 115 m_renderer.clear(); 116 } 117 118 Texture2DSizeCase::IterateResult Texture2DSizeCase::iterate (void) 119 { 120 const glw::Functions& gl = m_renderCtx.getFunctions(); 121 TestLog& log = m_testCtx.getLog(); 122 RandomViewport viewport (m_renderCtx.getRenderTarget(), 128, 128, deStringHash(getName())); 123 tcu::Surface renderedFrame (viewport.width, viewport.height); 124 tcu::Surface referenceFrame (viewport.width, viewport.height); 125 const tcu::IVec4 texBits = tcu::getTextureFormatBitDepth(glu::mapGLTransferFormat(m_format, m_dataType)); 126 const tcu::PixelFormat& rtFmt = m_renderCtx.getRenderTarget().getPixelFormat(); 127 const tcu::PixelFormat thresholdFormat(std::min(texBits[0], rtFmt.redBits), std::min(texBits[1], rtFmt.greenBits), std::min(texBits[2], rtFmt.blueBits), std::min(texBits[3], rtFmt.alphaBits)); 128 tcu::RGBA threshold = thresholdFormat.getColorThreshold() + tcu::RGBA(7,7,7,7); 129 deUint32 wrapS = GL_CLAMP_TO_EDGE; 130 deUint32 wrapT = GL_CLAMP_TO_EDGE; 131 // Do not minify with GL_NEAREST. A large POT texture with a small POT render target will produce 132 // indeterminate results. 133 deUint32 minFilter = m_useMipmaps ? GL_NEAREST_MIPMAP_NEAREST : GL_LINEAR; 134 deUint32 magFilter = GL_NEAREST; 135 vector<float> texCoord; 136 137 computeQuadTexCoord2D(texCoord, tcu::Vec2(0.0f, 0.0f), tcu::Vec2(1.0f, 1.0f)); 138 139 // Setup base viewport. 140 gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height); 141 142 // Upload texture data to GL. 143 m_texture->upload(); 144 145 // Bind to unit 0. 146 gl.activeTexture(GL_TEXTURE0); 147 gl.bindTexture(GL_TEXTURE_2D, m_texture->getGLTexture()); 148 149 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapS); 150 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapT); 151 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter); 152 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter); 153 GLU_EXPECT_NO_ERROR(gl.getError(), "Set texturing state"); 154 155 // Draw. 156 m_renderer.renderQuad(0, &texCoord[0], TEXTURETYPE_2D); 157 glu::readPixels(m_renderCtx, viewport.x, viewport.y, renderedFrame.getAccess()); 158 159 // Compute reference. 160 sampleTexture(tcu::SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat()), m_texture->getRefTexture(), &texCoord[0], ReferenceParams(TEXTURETYPE_2D, mapGLSampler(wrapS, wrapT, minFilter, magFilter))); 161 162 // Compare and log. 163 bool isOk = compareImages(log, referenceFrame, renderedFrame, threshold); 164 165 m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, 166 isOk ? "Pass" : "Image comparison failed"); 167 168 return STOP; 169 } 170 171 class TextureCubeSizeCase : public tcu::TestCase 172 { 173 public: 174 TextureCubeSizeCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* description, deUint32 format, deUint32 dataType, int width, int height, bool mipmaps); 175 ~TextureCubeSizeCase (void); 176 177 void init (void); 178 void deinit (void); 179 IterateResult iterate (void); 180 181 private: 182 TextureCubeSizeCase (const TextureCubeSizeCase& other); 183 TextureCubeSizeCase& operator= (const TextureCubeSizeCase& other); 184 185 bool testFace (tcu::CubeFace face); 186 187 glu::RenderContext& m_renderCtx; 188 189 deUint32 m_format; 190 deUint32 m_dataType; 191 int m_width; 192 int m_height; 193 bool m_useMipmaps; 194 195 glu::TextureCube* m_texture; 196 TextureRenderer m_renderer; 197 198 int m_curFace; 199 bool m_isOk; 200 }; 201 202 TextureCubeSizeCase::TextureCubeSizeCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* description, deUint32 format, deUint32 dataType, int width, int height, bool mipmaps) 203 : TestCase (testCtx, name, description) 204 , m_renderCtx (renderCtx) 205 , m_format (format) 206 , m_dataType (dataType) 207 , m_width (width) 208 , m_height (height) 209 , m_useMipmaps (mipmaps) 210 , m_texture (DE_NULL) 211 , m_renderer (renderCtx, testCtx.getLog(), glu::GLSL_VERSION_100_ES, glu::PRECISION_MEDIUMP) 212 , m_curFace (0) 213 , m_isOk (false) 214 { 215 } 216 217 TextureCubeSizeCase::~TextureCubeSizeCase (void) 218 { 219 TextureCubeSizeCase::deinit(); 220 } 221 222 void TextureCubeSizeCase::init (void) 223 { 224 DE_ASSERT(!m_texture); 225 DE_ASSERT(m_width == m_height); 226 m_texture = new TextureCube(m_renderCtx, m_format, m_dataType, m_width); 227 228 static const tcu::Vec4 gradients[tcu::CUBEFACE_LAST][2] = 229 { 230 { tcu::Vec4(-1.0f, -1.0f, -1.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // negative x 231 { tcu::Vec4( 0.0f, -1.0f, -1.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // positive x 232 { tcu::Vec4(-1.0f, 0.0f, -1.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // negative y 233 { tcu::Vec4(-1.0f, -1.0f, 0.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // positive y 234 { tcu::Vec4(-1.0f, -1.0f, -1.0f, 0.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f) }, // negative z 235 { tcu::Vec4( 0.0f, 0.0f, 0.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) } // positive z 236 }; 237 238 int numLevels = m_useMipmaps ? deLog2Floor32(de::max(m_width, m_height))+1 : 1; 239 240 // Fill levels. 241 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++) 242 { 243 for (int face = 0; face < tcu::CUBEFACE_LAST; face++) 244 { 245 m_texture->getRefTexture().allocLevel((tcu::CubeFace)face, levelNdx); 246 fillWithComponentGradients(m_texture->getRefTexture().getLevelFace(levelNdx, (tcu::CubeFace)face), gradients[face][0], gradients[face][1]); 247 } 248 } 249 250 // Upload texture data to GL. 251 m_texture->upload(); 252 253 // Initialize iteration state. 254 m_curFace = 0; 255 m_isOk = true; 256 } 257 258 void TextureCubeSizeCase::deinit (void) 259 { 260 delete m_texture; 261 m_texture = DE_NULL; 262 263 m_renderer.clear(); 264 } 265 266 bool TextureCubeSizeCase::testFace (tcu::CubeFace face) 267 { 268 const glw::Functions& gl = m_renderCtx.getFunctions(); 269 TestLog& log = m_testCtx.getLog(); 270 RandomViewport viewport (m_renderCtx.getRenderTarget(), 128, 128, deStringHash(getName())+(deUint32)face); 271 tcu::Surface renderedFrame (viewport.width, viewport.height); 272 tcu::Surface referenceFrame (viewport.width, viewport.height); 273 const tcu::IVec4 texBits = tcu::getTextureFormatBitDepth(glu::mapGLTransferFormat(m_format, m_dataType)); 274 const tcu::PixelFormat& rtFmt = m_renderCtx.getRenderTarget().getPixelFormat(); 275 const tcu::PixelFormat thresholdFormat(std::min(texBits[0], rtFmt.redBits), std::min(texBits[1], rtFmt.greenBits), std::min(texBits[2], rtFmt.blueBits), std::min(texBits[3], rtFmt.alphaBits)); 276 tcu::RGBA threshold = thresholdFormat.getColorThreshold() + tcu::RGBA(7,7,7,7); 277 deUint32 wrapS = GL_CLAMP_TO_EDGE; 278 deUint32 wrapT = GL_CLAMP_TO_EDGE; 279 // Do not minify with GL_NEAREST. A large POT texture with a small POT render target will produce 280 // indeterminate results. 281 deUint32 minFilter = m_useMipmaps ? GL_NEAREST_MIPMAP_NEAREST : GL_LINEAR; 282 deUint32 magFilter = GL_NEAREST; 283 vector<float> texCoord; 284 285 computeQuadTexCoordCube(texCoord, face); 286 287 // \todo [2011-10-28 pyry] Image set name / section? 288 log << TestLog::Message << face << TestLog::EndMessage; 289 290 // Setup base viewport. 291 gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height); 292 293 // Bind to unit 0. 294 gl.activeTexture(GL_TEXTURE0); 295 gl.bindTexture(GL_TEXTURE_CUBE_MAP, m_texture->getGLTexture()); 296 297 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, wrapS); 298 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, wrapT); 299 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, minFilter); 300 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, magFilter); 301 GLU_EXPECT_NO_ERROR(gl.getError(), "Set texturing state"); 302 303 m_renderer.renderQuad(0, &texCoord[0], TEXTURETYPE_CUBE); 304 glu::readPixels(m_renderCtx, viewport.x, viewport.y, renderedFrame.getAccess()); 305 306 // Compute reference. 307 Sampler sampler = mapGLSampler(wrapS, wrapT, minFilter, magFilter); 308 sampler.seamlessCubeMap = false; 309 sampleTexture(tcu::SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat()), m_texture->getRefTexture(), &texCoord[0], ReferenceParams(TEXTURETYPE_CUBE, sampler)); 310 311 // Compare and log. 312 return compareImages(log, referenceFrame, renderedFrame, threshold); 313 } 314 315 TextureCubeSizeCase::IterateResult TextureCubeSizeCase::iterate (void) 316 { 317 // Execute test for all faces. 318 if (!testFace((tcu::CubeFace)m_curFace)) 319 m_isOk = false; 320 321 m_curFace += 1; 322 323 if (m_curFace == tcu::CUBEFACE_LAST) 324 { 325 m_testCtx.setTestResult(m_isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, 326 m_isOk ? "Pass" : "Image comparison failed"); 327 return STOP; 328 } 329 else 330 return CONTINUE; 331 } 332 333 TextureSizeTests::TextureSizeTests (Context& context) 334 : TestCaseGroup(context, "size", "Texture Size Tests") 335 { 336 } 337 338 TextureSizeTests::~TextureSizeTests (void) 339 { 340 } 341 342 void TextureSizeTests::init (void) 343 { 344 struct 345 { 346 int width; 347 int height; 348 } sizes2D[] = 349 { 350 { 64, 64 }, // Spec-mandated minimum. 351 { 65, 63 }, 352 { 512, 512 }, 353 { 1024, 1024 }, 354 { 2048, 2048 } 355 }; 356 357 struct 358 { 359 int width; 360 int height; 361 } sizesCube[] = 362 { 363 { 15, 15 }, 364 { 16, 16 }, // Spec-mandated minimum 365 { 64, 64 }, 366 { 128, 128 }, 367 { 256, 256 }, 368 { 512, 512 } 369 }; 370 371 struct 372 { 373 const char* name; 374 deUint32 format; 375 deUint32 dataType; 376 } formats[] = 377 { 378 { "l8", GL_LUMINANCE, GL_UNSIGNED_BYTE }, 379 { "rgba4444", GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4 }, 380 { "rgb888", GL_RGB, GL_UNSIGNED_BYTE }, 381 { "rgba8888", GL_RGBA, GL_UNSIGNED_BYTE } 382 }; 383 384 // 2D cases. 385 tcu::TestCaseGroup* group2D = new tcu::TestCaseGroup(m_testCtx, "2d", "2D Texture Size Tests"); 386 addChild(group2D); 387 for (int sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(sizes2D); sizeNdx++) 388 { 389 int width = sizes2D[sizeNdx].width; 390 int height = sizes2D[sizeNdx].height; 391 bool isPOT = deIsPowerOfTwo32(width) && deIsPowerOfTwo32(height); 392 393 for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(formats); formatNdx++) 394 { 395 for (int mipmap = 0; mipmap < (isPOT ? 2 : 1); mipmap++) 396 { 397 std::ostringstream name; 398 name << width << "x" << height << "_" << formats[formatNdx].name << (mipmap ? "_mipmap" : ""); 399 400 group2D->addChild(new Texture2DSizeCase(m_testCtx, m_context.getRenderContext(), name.str().c_str(), "", 401 formats[formatNdx].format, formats[formatNdx].dataType, 402 width, height, mipmap != 0)); 403 } 404 } 405 } 406 407 // Cubemap cases. 408 tcu::TestCaseGroup* groupCube = new tcu::TestCaseGroup(m_testCtx, "cube", "Cubemap Texture Size Tests"); 409 addChild(groupCube); 410 for (int sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(sizesCube); sizeNdx++) 411 { 412 int width = sizesCube[sizeNdx].width; 413 int height = sizesCube[sizeNdx].height; 414 bool isPOT = deIsPowerOfTwo32(width) && deIsPowerOfTwo32(height); 415 416 for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(formats); formatNdx++) 417 { 418 for (int mipmap = 0; mipmap < (isPOT ? 2 : 1); mipmap++) 419 { 420 std::ostringstream name; 421 name << width << "x" << height << "_" << formats[formatNdx].name << (mipmap ? "_mipmap" : ""); 422 423 groupCube->addChild(new TextureCubeSizeCase(m_testCtx, m_context.getRenderContext(), name.str().c_str(), "", 424 formats[formatNdx].format, formats[formatNdx].dataType, 425 width, height, mipmap != 0)); 426 } 427 } 428 } 429 } 430 431 } // Functional 432 } // gles2 433 } // deqp 434