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