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 filtering tests. 22 *//*--------------------------------------------------------------------*/ 23 24 #include "es3fTextureFilteringTests.hpp" 25 #include "glsTextureTestUtil.hpp" 26 #include "gluPixelTransfer.hpp" 27 #include "gluTexture.hpp" 28 #include "gluTextureUtil.hpp" 29 #include "tcuTextureUtil.hpp" 30 #include "tcuImageCompare.hpp" 31 #include "tcuTexLookupVerifier.hpp" 32 #include "tcuVectorUtil.hpp" 33 #include "deStringUtil.hpp" 34 #include "deString.h" 35 #include "glwFunctions.hpp" 36 #include "glwEnums.hpp" 37 #include "gluContextInfo.hpp" 38 #include "deUniquePtr.hpp" 39 40 using de::MovePtr; 41 using glu::ContextInfo; 42 43 namespace deqp 44 { 45 namespace gles3 46 { 47 namespace Functional 48 { 49 50 using std::vector; 51 using std::string; 52 using tcu::TestLog; 53 using namespace gls::TextureTestUtil; 54 using namespace glu::TextureTestUtil; 55 56 enum 57 { 58 TEX2D_VIEWPORT_WIDTH = 64, 59 TEX2D_VIEWPORT_HEIGHT = 64, 60 TEX2D_MIN_VIEWPORT_WIDTH = 64, 61 TEX2D_MIN_VIEWPORT_HEIGHT = 64, 62 63 TEX3D_VIEWPORT_WIDTH = 64, 64 TEX3D_VIEWPORT_HEIGHT = 64, 65 TEX3D_MIN_VIEWPORT_WIDTH = 64, 66 TEX3D_MIN_VIEWPORT_HEIGHT = 64 67 }; 68 69 namespace 70 { 71 72 void checkSupport (const glu::ContextInfo& info, deUint32 internalFormat) 73 { 74 if (internalFormat == GL_SR8_EXT && !info.isExtensionSupported("GL_EXT_texture_sRGB_R8")) 75 TCU_THROW(NotSupportedError, "GL_EXT_texture_sRGB_decode is not supported."); 76 } 77 78 } // anonymous 79 80 class Texture2DFilteringCase : public tcu::TestCase 81 { 82 public: 83 Texture2DFilteringCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const glu::ContextInfo& ctxInfo, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT, deUint32 internalFormat, int width, int height); 84 Texture2DFilteringCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const glu::ContextInfo& ctxInfo, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT, const std::vector<std::string>& filenames); 85 ~Texture2DFilteringCase (void); 86 87 void init (void); 88 void deinit (void); 89 IterateResult iterate (void); 90 91 private: 92 Texture2DFilteringCase (const Texture2DFilteringCase& other); 93 Texture2DFilteringCase& operator= (const Texture2DFilteringCase& other); 94 95 glu::RenderContext& m_renderCtx; 96 const glu::ContextInfo& m_renderCtxInfo; 97 98 const deUint32 m_minFilter; 99 const deUint32 m_magFilter; 100 const deUint32 m_wrapS; 101 const deUint32 m_wrapT; 102 103 const deUint32 m_internalFormat; 104 const int m_width; 105 const int m_height; 106 107 const std::vector<std::string> m_filenames; 108 109 struct FilterCase 110 { 111 const glu::Texture2D* texture; 112 tcu::Vec2 minCoord; 113 tcu::Vec2 maxCoord; 114 115 FilterCase (void) 116 : texture(DE_NULL) 117 { 118 } 119 120 FilterCase (const glu::Texture2D* tex_, const tcu::Vec2& minCoord_, const tcu::Vec2& maxCoord_) 121 : texture (tex_) 122 , minCoord (minCoord_) 123 , maxCoord (maxCoord_) 124 { 125 } 126 }; 127 128 std::vector<glu::Texture2D*> m_textures; 129 std::vector<FilterCase> m_cases; 130 131 TextureRenderer m_renderer; 132 133 int m_caseNdx; 134 }; 135 136 Texture2DFilteringCase::Texture2DFilteringCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const glu::ContextInfo& ctxInfo, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT, deUint32 internalFormat, int width, int height) 137 : TestCase (testCtx, name, desc) 138 , m_renderCtx (renderCtx) 139 , m_renderCtxInfo (ctxInfo) 140 , m_minFilter (minFilter) 141 , m_magFilter (magFilter) 142 , m_wrapS (wrapS) 143 , m_wrapT (wrapT) 144 , m_internalFormat (internalFormat) 145 , m_width (width) 146 , m_height (height) 147 , m_renderer (renderCtx, testCtx.getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_HIGHP) 148 , m_caseNdx (0) 149 { 150 } 151 152 Texture2DFilteringCase::Texture2DFilteringCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const glu::ContextInfo& ctxInfo, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT, const std::vector<std::string>& filenames) 153 : TestCase (testCtx, name, desc) 154 , m_renderCtx (renderCtx) 155 , m_renderCtxInfo (ctxInfo) 156 , m_minFilter (minFilter) 157 , m_magFilter (magFilter) 158 , m_wrapS (wrapS) 159 , m_wrapT (wrapT) 160 , m_internalFormat (GL_NONE) 161 , m_width (0) 162 , m_height (0) 163 , m_filenames (filenames) 164 , m_renderer (renderCtx, testCtx.getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_HIGHP) 165 , m_caseNdx (0) 166 { 167 } 168 169 Texture2DFilteringCase::~Texture2DFilteringCase (void) 170 { 171 deinit(); 172 } 173 174 void Texture2DFilteringCase::init (void) 175 { 176 checkSupport(m_renderCtxInfo, m_internalFormat); 177 178 try 179 { 180 if (!m_filenames.empty()) 181 { 182 m_textures.reserve(1); 183 m_textures.push_back(glu::Texture2D::create(m_renderCtx, m_renderCtxInfo, m_testCtx.getArchive(), (int)m_filenames.size(), m_filenames)); 184 } 185 else 186 { 187 // Create 2 textures. 188 m_textures.reserve(2); 189 for (int ndx = 0; ndx < 2; ndx++) 190 m_textures.push_back(new glu::Texture2D(m_renderCtx, m_internalFormat, m_width, m_height)); 191 192 const bool mipmaps = true; 193 const int numLevels = mipmaps ? deLog2Floor32(de::max(m_width, m_height))+1 : 1; 194 const tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(m_textures[0]->getRefTexture().getFormat()); 195 const tcu::Vec4 cBias = fmtInfo.valueMin; 196 const tcu::Vec4 cScale = fmtInfo.valueMax-fmtInfo.valueMin; 197 198 // Fill first gradient texture. 199 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++) 200 { 201 tcu::Vec4 gMin = tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f)*cScale + cBias; 202 tcu::Vec4 gMax = tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f)*cScale + cBias; 203 204 m_textures[0]->getRefTexture().allocLevel(levelNdx); 205 tcu::fillWithComponentGradients(m_textures[0]->getRefTexture().getLevel(levelNdx), gMin, gMax); 206 } 207 208 // Fill second with grid texture. 209 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++) 210 { 211 deUint32 step = 0x00ffffff / numLevels; 212 deUint32 rgb = step*levelNdx; 213 deUint32 colorA = 0xff000000 | rgb; 214 deUint32 colorB = 0xff000000 | ~rgb; 215 216 m_textures[1]->getRefTexture().allocLevel(levelNdx); 217 tcu::fillWithGrid(m_textures[1]->getRefTexture().getLevel(levelNdx), 4, tcu::RGBA(colorA).toVec()*cScale + cBias, tcu::RGBA(colorB).toVec()*cScale + cBias); 218 } 219 220 // Upload. 221 for (std::vector<glu::Texture2D*>::iterator i = m_textures.begin(); i != m_textures.end(); i++) 222 (*i)->upload(); 223 } 224 225 // Compute cases. 226 { 227 const struct 228 { 229 int texNdx; 230 float lodX; 231 float lodY; 232 float oX; 233 float oY; 234 } cases[] = 235 { 236 { 0, 1.6f, 2.9f, -1.0f, -2.7f }, 237 { 0, -2.0f, -1.35f, -0.2f, 0.7f }, 238 { 1, 0.14f, 0.275f, -1.5f, -1.1f }, 239 { 1, -0.92f, -2.64f, 0.4f, -0.1f }, 240 }; 241 242 const float viewportW = (float)de::min<int>(TEX2D_VIEWPORT_WIDTH, m_renderCtx.getRenderTarget().getWidth()); 243 const float viewportH = (float)de::min<int>(TEX2D_VIEWPORT_HEIGHT, m_renderCtx.getRenderTarget().getHeight()); 244 245 for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(cases); caseNdx++) 246 { 247 const int texNdx = de::clamp(cases[caseNdx].texNdx, 0, (int)m_textures.size()-1); 248 const float lodX = cases[caseNdx].lodX; 249 const float lodY = cases[caseNdx].lodY; 250 const float oX = cases[caseNdx].oX; 251 const float oY = cases[caseNdx].oY; 252 const float sX = deFloatExp2(lodX)*viewportW / float(m_textures[texNdx]->getRefTexture().getWidth()); 253 const float sY = deFloatExp2(lodY)*viewportH / float(m_textures[texNdx]->getRefTexture().getHeight()); 254 255 m_cases.push_back(FilterCase(m_textures[texNdx], tcu::Vec2(oX, oY), tcu::Vec2(oX+sX, oY+sY))); 256 } 257 } 258 259 m_caseNdx = 0; 260 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 261 } 262 catch (...) 263 { 264 // Clean up to save memory. 265 Texture2DFilteringCase::deinit(); 266 throw; 267 } 268 } 269 270 void Texture2DFilteringCase::deinit (void) 271 { 272 for (std::vector<glu::Texture2D*>::iterator i = m_textures.begin(); i != m_textures.end(); i++) 273 delete *i; 274 m_textures.clear(); 275 276 m_renderer.clear(); 277 m_cases.clear(); 278 } 279 280 Texture2DFilteringCase::IterateResult Texture2DFilteringCase::iterate (void) 281 { 282 const glw::Functions& gl = m_renderCtx.getFunctions(); 283 const RandomViewport viewport (m_renderCtx.getRenderTarget(), TEX2D_VIEWPORT_WIDTH, TEX2D_VIEWPORT_HEIGHT, deStringHash(getName()) ^ deInt32Hash(m_caseNdx)); 284 const tcu::TextureFormat texFmt = m_textures[0]->getRefTexture().getFormat(); 285 const tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(texFmt); 286 const FilterCase& curCase = m_cases[m_caseNdx]; 287 const tcu::ScopedLogSection section (m_testCtx.getLog(), string("Test") + de::toString(m_caseNdx), string("Test ") + de::toString(m_caseNdx)); 288 ReferenceParams refParams (TEXTURETYPE_2D); 289 tcu::Surface rendered (viewport.width, viewport.height); 290 vector<float> texCoord; 291 292 if (viewport.width < TEX2D_MIN_VIEWPORT_WIDTH || viewport.height < TEX2D_MIN_VIEWPORT_HEIGHT) 293 throw tcu::NotSupportedError("Too small render target", "", __FILE__, __LINE__); 294 295 // Setup params for reference. 296 refParams.sampler = glu::mapGLSampler(m_wrapS, m_wrapT, m_minFilter, m_magFilter); 297 refParams.samplerType = getSamplerType(texFmt); 298 refParams.lodMode = LODMODE_EXACT; 299 refParams.colorBias = fmtInfo.lookupBias; 300 refParams.colorScale = fmtInfo.lookupScale; 301 302 // Compute texture coordinates. 303 m_testCtx.getLog() << TestLog::Message << "Texture coordinates: " << curCase.minCoord << " -> " << curCase.maxCoord << TestLog::EndMessage; 304 computeQuadTexCoord2D(texCoord, curCase.minCoord, curCase.maxCoord); 305 306 gl.bindTexture (GL_TEXTURE_2D, curCase.texture->getGLTexture()); 307 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_minFilter); 308 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, m_magFilter); 309 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, m_wrapS); 310 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, m_wrapT); 311 312 gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height); 313 m_renderer.renderQuad(0, &texCoord[0], refParams); 314 glu::readPixels(m_renderCtx, viewport.x, viewport.y, rendered.getAccess()); 315 316 { 317 const bool isNearestOnly = m_minFilter == GL_NEAREST && m_magFilter == GL_NEAREST; 318 const tcu::PixelFormat pixelFormat = m_renderCtx.getRenderTarget().getPixelFormat(); 319 const tcu::IVec4 colorBits = max(getBitsVec(pixelFormat) - (isNearestOnly ? 1 : 2), tcu::IVec4(0)); // 1 inaccurate bit if nearest only, 2 otherwise 320 tcu::LodPrecision lodPrecision; 321 tcu::LookupPrecision lookupPrecision; 322 323 lodPrecision.derivateBits = 18; 324 lodPrecision.lodBits = 6; 325 lookupPrecision.colorThreshold = tcu::computeFixedPointThreshold(colorBits) / refParams.colorScale; 326 lookupPrecision.coordBits = tcu::IVec3(20,20,0); 327 lookupPrecision.uvwBits = tcu::IVec3(7,7,0); 328 lookupPrecision.colorMask = getCompareMask(pixelFormat); 329 330 const bool isHighQuality = verifyTextureResult(m_testCtx, rendered.getAccess(), curCase.texture->getRefTexture(), 331 &texCoord[0], refParams, lookupPrecision, lodPrecision, pixelFormat); 332 333 if (!isHighQuality) 334 { 335 // Evaluate against lower precision requirements. 336 lodPrecision.lodBits = 4; 337 lookupPrecision.uvwBits = tcu::IVec3(4,4,0); 338 339 m_testCtx.getLog() << TestLog::Message << "Warning: Verification against high precision requirements failed, trying with lower requirements." << TestLog::EndMessage; 340 341 const bool isOk = verifyTextureResult(m_testCtx, rendered.getAccess(), curCase.texture->getRefTexture(), 342 &texCoord[0], refParams, lookupPrecision, lodPrecision, pixelFormat); 343 344 if (!isOk) 345 { 346 m_testCtx.getLog() << TestLog::Message << "ERROR: Verification against low precision requirements failed, failing test case." << TestLog::EndMessage; 347 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed"); 348 } 349 else if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS) 350 m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, "Low-quality filtering result"); 351 } 352 } 353 354 m_caseNdx += 1; 355 return m_caseNdx < (int)m_cases.size() ? CONTINUE : STOP; 356 } 357 358 class TextureCubeFilteringCase : public tcu::TestCase 359 { 360 public: 361 TextureCubeFilteringCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const glu::ContextInfo& ctxInfo, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT, bool onlySampleFaceInterior, deUint32 internalFormat, int width, int height); 362 TextureCubeFilteringCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const glu::ContextInfo& ctxInfo, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT, bool onlySampleFaceInterior, const std::vector<std::string>& filenames); 363 ~TextureCubeFilteringCase (void); 364 365 void init (void); 366 void deinit (void); 367 IterateResult iterate (void); 368 369 private: 370 TextureCubeFilteringCase (const TextureCubeFilteringCase& other); 371 TextureCubeFilteringCase& operator= (const TextureCubeFilteringCase& other); 372 373 glu::RenderContext& m_renderCtx; 374 const glu::ContextInfo& m_renderCtxInfo; 375 376 const deUint32 m_minFilter; 377 const deUint32 m_magFilter; 378 const deUint32 m_wrapS; 379 const deUint32 m_wrapT; 380 const bool m_onlySampleFaceInterior; //!< If true, we avoid sampling anywhere near a face's edges. 381 382 const deUint32 m_internalFormat; 383 const int m_width; 384 const int m_height; 385 386 const std::vector<std::string> m_filenames; 387 388 struct FilterCase 389 { 390 const glu::TextureCube* texture; 391 tcu::Vec2 bottomLeft; 392 tcu::Vec2 topRight; 393 394 FilterCase (void) 395 : texture(DE_NULL) 396 { 397 } 398 399 FilterCase (const glu::TextureCube* tex_, const tcu::Vec2& bottomLeft_, const tcu::Vec2& topRight_) 400 : texture (tex_) 401 , bottomLeft(bottomLeft_) 402 , topRight (topRight_) 403 { 404 } 405 }; 406 407 std::vector<glu::TextureCube*> m_textures; 408 std::vector<FilterCase> m_cases; 409 410 TextureRenderer m_renderer; 411 412 int m_caseNdx; 413 }; 414 415 TextureCubeFilteringCase::TextureCubeFilteringCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const glu::ContextInfo& ctxInfo, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT, bool onlySampleFaceInterior, deUint32 internalFormat, int width, int height) 416 : TestCase (testCtx, name, desc) 417 , m_renderCtx (renderCtx) 418 , m_renderCtxInfo (ctxInfo) 419 , m_minFilter (minFilter) 420 , m_magFilter (magFilter) 421 , m_wrapS (wrapS) 422 , m_wrapT (wrapT) 423 , m_onlySampleFaceInterior (onlySampleFaceInterior) 424 , m_internalFormat (internalFormat) 425 , m_width (width) 426 , m_height (height) 427 , m_renderer (renderCtx, testCtx.getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_HIGHP) 428 , m_caseNdx (0) 429 { 430 } 431 432 TextureCubeFilteringCase::TextureCubeFilteringCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const glu::ContextInfo& ctxInfo, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT, bool onlySampleFaceInterior, const std::vector<std::string>& filenames) 433 : TestCase (testCtx, name, desc) 434 , m_renderCtx (renderCtx) 435 , m_renderCtxInfo (ctxInfo) 436 , m_minFilter (minFilter) 437 , m_magFilter (magFilter) 438 , m_wrapS (wrapS) 439 , m_wrapT (wrapT) 440 , m_onlySampleFaceInterior (onlySampleFaceInterior) 441 , m_internalFormat (GL_NONE) 442 , m_width (0) 443 , m_height (0) 444 , m_filenames (filenames) 445 , m_renderer (renderCtx, testCtx.getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_HIGHP) 446 , m_caseNdx (0) 447 { 448 } 449 450 TextureCubeFilteringCase::~TextureCubeFilteringCase (void) 451 { 452 deinit(); 453 } 454 455 void TextureCubeFilteringCase::init (void) 456 { 457 checkSupport(m_renderCtxInfo, m_internalFormat); 458 459 try 460 { 461 if (!m_filenames.empty()) 462 { 463 m_textures.reserve(1); 464 m_textures.push_back(glu::TextureCube::create(m_renderCtx, m_renderCtxInfo, m_testCtx.getArchive(), (int)m_filenames.size() / 6, m_filenames)); 465 } 466 else 467 { 468 DE_ASSERT(m_width == m_height); 469 m_textures.reserve(2); 470 for (int ndx = 0; ndx < 2; ndx++) 471 m_textures.push_back(new glu::TextureCube(m_renderCtx, m_internalFormat, m_width)); 472 473 const int numLevels = deLog2Floor32(de::max(m_width, m_height))+1; 474 tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(m_textures[0]->getRefTexture().getFormat()); 475 tcu::Vec4 cBias = fmtInfo.valueMin; 476 tcu::Vec4 cScale = fmtInfo.valueMax-fmtInfo.valueMin; 477 478 // Fill first with gradient texture. 479 static const tcu::Vec4 gradients[tcu::CUBEFACE_LAST][2] = 480 { 481 { tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // negative x 482 { tcu::Vec4(0.5f, 0.0f, 0.0f, 1.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // positive x 483 { tcu::Vec4(0.0f, 0.5f, 0.0f, 1.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // negative y 484 { tcu::Vec4(0.0f, 0.0f, 0.5f, 1.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // positive y 485 { tcu::Vec4(0.0f, 0.0f, 0.0f, 0.5f), tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f) }, // negative z 486 { tcu::Vec4(0.5f, 0.5f, 0.5f, 1.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) } // positive z 487 }; 488 for (int face = 0; face < tcu::CUBEFACE_LAST; face++) 489 { 490 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++) 491 { 492 m_textures[0]->getRefTexture().allocLevel((tcu::CubeFace)face, levelNdx); 493 tcu::fillWithComponentGradients(m_textures[0]->getRefTexture().getLevelFace(levelNdx, (tcu::CubeFace)face), gradients[face][0]*cScale + cBias, gradients[face][1]*cScale + cBias); 494 } 495 } 496 497 // Fill second with grid texture. 498 for (int face = 0; face < tcu::CUBEFACE_LAST; face++) 499 { 500 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++) 501 { 502 deUint32 step = 0x00ffffff / (numLevels*tcu::CUBEFACE_LAST); 503 deUint32 rgb = step*levelNdx*face; 504 deUint32 colorA = 0xff000000 | rgb; 505 deUint32 colorB = 0xff000000 | ~rgb; 506 507 m_textures[1]->getRefTexture().allocLevel((tcu::CubeFace)face, levelNdx); 508 tcu::fillWithGrid(m_textures[1]->getRefTexture().getLevelFace(levelNdx, (tcu::CubeFace)face), 4, tcu::RGBA(colorA).toVec()*cScale + cBias, tcu::RGBA(colorB).toVec()*cScale + cBias); 509 } 510 } 511 512 // Upload. 513 for (std::vector<glu::TextureCube*>::iterator i = m_textures.begin(); i != m_textures.end(); i++) 514 (*i)->upload(); 515 } 516 517 // Compute cases 518 { 519 const glu::TextureCube* tex0 = m_textures[0]; 520 const glu::TextureCube* tex1 = m_textures.size() > 1 ? m_textures[1] : tex0; 521 522 if (m_onlySampleFaceInterior) 523 { 524 m_cases.push_back(FilterCase(tex0, tcu::Vec2(-0.8f, -0.8f), tcu::Vec2(0.8f, 0.8f))); // minification 525 m_cases.push_back(FilterCase(tex0, tcu::Vec2(0.5f, 0.65f), tcu::Vec2(0.8f, 0.8f))); // magnification 526 m_cases.push_back(FilterCase(tex1, tcu::Vec2(-0.8f, -0.8f), tcu::Vec2(0.8f, 0.8f))); // minification 527 m_cases.push_back(FilterCase(tex1, tcu::Vec2(0.2f, 0.2f), tcu::Vec2(0.6f, 0.5f))); // magnification 528 } 529 else 530 { 531 if (m_renderCtx.getRenderTarget().getNumSamples() == 0) 532 m_cases.push_back(FilterCase(tex0, tcu::Vec2(-1.25f, -1.2f), tcu::Vec2(1.2f, 1.25f))); // minification 533 else 534 m_cases.push_back(FilterCase(tex0, tcu::Vec2(-1.19f, -1.3f), tcu::Vec2(1.1f, 1.35f))); // minification - w/ tweak to avoid hitting triangle edges with face switchpoint 535 536 m_cases.push_back(FilterCase(tex0, tcu::Vec2(0.8f, 0.8f), tcu::Vec2(1.25f, 1.20f))); // magnification 537 m_cases.push_back(FilterCase(tex1, tcu::Vec2(-1.19f, -1.3f), tcu::Vec2(1.1f, 1.35f))); // minification 538 m_cases.push_back(FilterCase(tex1, tcu::Vec2(-1.2f, -1.1f), tcu::Vec2(-0.8f, -0.8f))); // magnification 539 } 540 } 541 542 m_caseNdx = 0; 543 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 544 } 545 catch (...) 546 { 547 // Clean up to save memory. 548 TextureCubeFilteringCase::deinit(); 549 throw; 550 } 551 } 552 553 void TextureCubeFilteringCase::deinit (void) 554 { 555 for (std::vector<glu::TextureCube*>::iterator i = m_textures.begin(); i != m_textures.end(); i++) 556 delete *i; 557 m_textures.clear(); 558 559 m_renderer.clear(); 560 m_cases.clear(); 561 } 562 563 static const char* getFaceDesc (const tcu::CubeFace face) 564 { 565 switch (face) 566 { 567 case tcu::CUBEFACE_NEGATIVE_X: return "-X"; 568 case tcu::CUBEFACE_POSITIVE_X: return "+X"; 569 case tcu::CUBEFACE_NEGATIVE_Y: return "-Y"; 570 case tcu::CUBEFACE_POSITIVE_Y: return "+Y"; 571 case tcu::CUBEFACE_NEGATIVE_Z: return "-Z"; 572 case tcu::CUBEFACE_POSITIVE_Z: return "+Z"; 573 default: 574 DE_ASSERT(false); 575 return DE_NULL; 576 } 577 } 578 579 TextureCubeFilteringCase::IterateResult TextureCubeFilteringCase::iterate (void) 580 { 581 const glw::Functions& gl = m_renderCtx.getFunctions(); 582 const int viewportSize = 28; 583 const RandomViewport viewport (m_renderCtx.getRenderTarget(), viewportSize, viewportSize, deStringHash(getName()) ^ deInt32Hash(m_caseNdx)); 584 const tcu::ScopedLogSection iterSection (m_testCtx.getLog(), string("Test") + de::toString(m_caseNdx), string("Test ") + de::toString(m_caseNdx)); 585 const FilterCase& curCase = m_cases[m_caseNdx]; 586 const tcu::TextureFormat& texFmt = curCase.texture->getRefTexture().getFormat(); 587 const tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(texFmt); 588 ReferenceParams sampleParams (TEXTURETYPE_CUBE); 589 590 if (viewport.width < viewportSize || viewport.height < viewportSize) 591 throw tcu::NotSupportedError("Too small render target", DE_NULL, __FILE__, __LINE__); 592 593 // Setup texture 594 gl.bindTexture (GL_TEXTURE_CUBE_MAP, curCase.texture->getGLTexture()); 595 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, m_minFilter); 596 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, m_magFilter); 597 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, m_wrapS); 598 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, m_wrapT); 599 600 // Other state 601 gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height); 602 603 // Params for reference computation. 604 sampleParams.sampler = glu::mapGLSampler(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, m_minFilter, m_magFilter); 605 sampleParams.sampler.seamlessCubeMap = true; 606 sampleParams.samplerType = getSamplerType(texFmt); 607 sampleParams.colorBias = fmtInfo.lookupBias; 608 sampleParams.colorScale = fmtInfo.lookupScale; 609 sampleParams.lodMode = LODMODE_EXACT; 610 611 m_testCtx.getLog() << TestLog::Message << "Coordinates: " << curCase.bottomLeft << " -> " << curCase.topRight << TestLog::EndMessage; 612 613 for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; faceNdx++) 614 { 615 const tcu::CubeFace face = tcu::CubeFace(faceNdx); 616 tcu::Surface result (viewport.width, viewport.height); 617 vector<float> texCoord; 618 619 computeQuadTexCoordCube(texCoord, face, curCase.bottomLeft, curCase.topRight); 620 621 m_testCtx.getLog() << TestLog::Message << "Face " << getFaceDesc(face) << TestLog::EndMessage; 622 623 // \todo Log texture coordinates. 624 625 m_renderer.renderQuad(0, &texCoord[0], sampleParams); 626 GLU_EXPECT_NO_ERROR(gl.getError(), "Draw"); 627 628 glu::readPixels(m_renderCtx, viewport.x, viewport.y, result.getAccess()); 629 GLU_EXPECT_NO_ERROR(gl.getError(), "Read pixels"); 630 631 { 632 const bool isNearestOnly = m_minFilter == GL_NEAREST && m_magFilter == GL_NEAREST; 633 const tcu::PixelFormat pixelFormat = m_renderCtx.getRenderTarget().getPixelFormat(); 634 const tcu::IVec4 colorBits = max(getBitsVec(pixelFormat) - (isNearestOnly ? 1 : 2), tcu::IVec4(0)); // 1 inaccurate bit if nearest only, 2 otherwise 635 tcu::LodPrecision lodPrecision; 636 tcu::LookupPrecision lookupPrecision; 637 638 lodPrecision.derivateBits = 10; 639 lodPrecision.lodBits = 5; 640 lookupPrecision.colorThreshold = tcu::computeFixedPointThreshold(colorBits) / sampleParams.colorScale; 641 lookupPrecision.coordBits = tcu::IVec3(10,10,10); 642 lookupPrecision.uvwBits = tcu::IVec3(6,6,0); 643 lookupPrecision.colorMask = getCompareMask(pixelFormat); 644 645 const bool isHighQuality = verifyTextureResult(m_testCtx, result.getAccess(), curCase.texture->getRefTexture(), 646 &texCoord[0], sampleParams, lookupPrecision, lodPrecision, pixelFormat); 647 648 if (!isHighQuality) 649 { 650 // Evaluate against lower precision requirements. 651 lodPrecision.lodBits = 4; 652 lookupPrecision.uvwBits = tcu::IVec3(4,4,0); 653 654 m_testCtx.getLog() << TestLog::Message << "Warning: Verification against high precision requirements failed, trying with lower requirements." << TestLog::EndMessage; 655 656 const bool isOk = verifyTextureResult(m_testCtx, result.getAccess(), curCase.texture->getRefTexture(), 657 &texCoord[0], sampleParams, lookupPrecision, lodPrecision, pixelFormat); 658 659 if (!isOk) 660 { 661 m_testCtx.getLog() << TestLog::Message << "ERROR: Verification against low precision requirements failed, failing test case." << TestLog::EndMessage; 662 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed"); 663 } 664 else if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS) 665 m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, "Low-quality filtering result"); 666 } 667 } 668 } 669 670 m_caseNdx += 1; 671 return m_caseNdx < (int)m_cases.size() ? CONTINUE : STOP; 672 } 673 674 // 2D array filtering 675 676 class Texture2DArrayFilteringCase : public TestCase 677 { 678 public: 679 Texture2DArrayFilteringCase (Context& context, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT, deUint32 internalFormat, int width, int height, int numLayers); 680 ~Texture2DArrayFilteringCase (void); 681 682 void init (void); 683 void deinit (void); 684 IterateResult iterate (void); 685 686 private: 687 Texture2DArrayFilteringCase (const Texture2DArrayFilteringCase&); 688 Texture2DArrayFilteringCase& operator= (const Texture2DArrayFilteringCase&); 689 690 const deUint32 m_minFilter; 691 const deUint32 m_magFilter; 692 const deUint32 m_wrapS; 693 const deUint32 m_wrapT; 694 695 const deUint32 m_internalFormat; 696 const int m_width; 697 const int m_height; 698 const int m_numLayers; 699 700 struct FilterCase 701 { 702 const glu::Texture2DArray* texture; 703 tcu::Vec2 lod; 704 tcu::Vec2 offset; 705 tcu::Vec2 layerRange; 706 707 FilterCase (void) 708 : texture(DE_NULL) 709 { 710 } 711 712 FilterCase (const glu::Texture2DArray* tex_, const tcu::Vec2& lod_, const tcu::Vec2& offset_, const tcu::Vec2& layerRange_) 713 : texture (tex_) 714 , lod (lod_) 715 , offset (offset_) 716 , layerRange(layerRange_) 717 { 718 } 719 }; 720 721 glu::Texture2DArray* m_gradientTex; 722 glu::Texture2DArray* m_gridTex; 723 724 TextureRenderer m_renderer; 725 726 std::vector<FilterCase> m_cases; 727 int m_caseNdx; 728 }; 729 730 Texture2DArrayFilteringCase::Texture2DArrayFilteringCase (Context& context, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT, deUint32 internalFormat, int width, int height, int numLayers) 731 : TestCase (context, name, desc) 732 , m_minFilter (minFilter) 733 , m_magFilter (magFilter) 734 , m_wrapS (wrapS) 735 , m_wrapT (wrapT) 736 , m_internalFormat (internalFormat) 737 , m_width (width) 738 , m_height (height) 739 , m_numLayers (numLayers) 740 , m_gradientTex (DE_NULL) 741 , m_gridTex (DE_NULL) 742 , m_renderer (context.getRenderContext(), context.getTestContext().getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_HIGHP) 743 , m_caseNdx (0) 744 { 745 } 746 747 Texture2DArrayFilteringCase::~Texture2DArrayFilteringCase (void) 748 { 749 Texture2DArrayFilteringCase::deinit(); 750 } 751 752 void Texture2DArrayFilteringCase::init (void) 753 { 754 checkSupport(m_context.getContextInfo(), m_internalFormat); 755 756 try 757 { 758 const tcu::TextureFormat texFmt = glu::mapGLInternalFormat(m_internalFormat); 759 const tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(texFmt); 760 const tcu::Vec4 cScale = fmtInfo.valueMax-fmtInfo.valueMin; 761 const tcu::Vec4 cBias = fmtInfo.valueMin; 762 const int numLevels = deLog2Floor32(de::max(m_width, m_height)) + 1; 763 764 // Create textures. 765 m_gradientTex = new glu::Texture2DArray(m_context.getRenderContext(), m_internalFormat, m_width, m_height, m_numLayers); 766 m_gridTex = new glu::Texture2DArray(m_context.getRenderContext(), m_internalFormat, m_width, m_height, m_numLayers); 767 768 const tcu::IVec4 levelSwz[] = 769 { 770 tcu::IVec4(0,1,2,3), 771 tcu::IVec4(2,1,3,0), 772 tcu::IVec4(3,0,1,2), 773 tcu::IVec4(1,3,2,0), 774 }; 775 776 // Fill first gradient texture (gradient direction varies between layers). 777 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++) 778 { 779 m_gradientTex->getRefTexture().allocLevel(levelNdx); 780 781 const tcu::PixelBufferAccess levelBuf = m_gradientTex->getRefTexture().getLevel(levelNdx); 782 783 for (int layerNdx = 0; layerNdx < m_numLayers; layerNdx++) 784 { 785 const tcu::IVec4 swz = levelSwz[layerNdx%DE_LENGTH_OF_ARRAY(levelSwz)]; 786 const tcu::Vec4 gMin = tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f).swizzle(swz[0],swz[1],swz[2],swz[3])*cScale + cBias; 787 const tcu::Vec4 gMax = tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f).swizzle(swz[0],swz[1],swz[2],swz[3])*cScale + cBias; 788 789 tcu::fillWithComponentGradients(tcu::getSubregion(levelBuf, 0, 0, layerNdx, levelBuf.getWidth(), levelBuf.getHeight(), 1), gMin, gMax); 790 } 791 } 792 793 // Fill second with grid texture (each layer has unique colors). 794 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++) 795 { 796 m_gridTex->getRefTexture().allocLevel(levelNdx); 797 798 const tcu::PixelBufferAccess levelBuf = m_gridTex->getRefTexture().getLevel(levelNdx); 799 800 for (int layerNdx = 0; layerNdx < m_numLayers; layerNdx++) 801 { 802 const deUint32 step = 0x00ffffff / (numLevels*m_numLayers - 1); 803 const deUint32 rgb = step * (levelNdx + layerNdx*numLevels); 804 const deUint32 colorA = 0xff000000 | rgb; 805 const deUint32 colorB = 0xff000000 | ~rgb; 806 807 tcu::fillWithGrid(tcu::getSubregion(levelBuf, 0, 0, layerNdx, levelBuf.getWidth(), levelBuf.getHeight(), 1), 808 4, tcu::RGBA(colorA).toVec()*cScale + cBias, tcu::RGBA(colorB).toVec()*cScale + cBias); 809 } 810 } 811 812 // Upload. 813 m_gradientTex->upload(); 814 m_gridTex->upload(); 815 816 // Test cases 817 m_cases.push_back(FilterCase(m_gradientTex, tcu::Vec2( 1.5f, 2.8f ), tcu::Vec2(-1.0f, -2.7f), tcu::Vec2(-0.5f, float(m_numLayers)+0.5f))); 818 m_cases.push_back(FilterCase(m_gridTex, tcu::Vec2( 0.2f, 0.175f), tcu::Vec2(-2.0f, -3.7f), tcu::Vec2(-0.5f, float(m_numLayers)+0.5f))); 819 m_cases.push_back(FilterCase(m_gridTex, tcu::Vec2(-0.8f, -2.3f ), tcu::Vec2( 0.2f, -0.1f), tcu::Vec2(float(m_numLayers)+0.5f, -0.5f))); 820 821 // Level rounding - only in single-sample configs as multisample configs may produce smooth transition at the middle. 822 if (m_context.getRenderTarget().getNumSamples() == 0) 823 m_cases.push_back(FilterCase(m_gradientTex, tcu::Vec2(-2.0f, -1.5f ), tcu::Vec2(-0.1f, 0.9f), tcu::Vec2(1.50001f, 1.49999f))); 824 825 m_caseNdx = 0; 826 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 827 } 828 catch (...) 829 { 830 // Clean up to save memory. 831 Texture2DArrayFilteringCase::deinit(); 832 throw; 833 } 834 } 835 836 void Texture2DArrayFilteringCase::deinit (void) 837 { 838 delete m_gradientTex; 839 delete m_gridTex; 840 841 m_gradientTex = DE_NULL; 842 m_gridTex = DE_NULL; 843 844 m_renderer.clear(); 845 m_cases.clear(); 846 } 847 848 Texture2DArrayFilteringCase::IterateResult Texture2DArrayFilteringCase::iterate (void) 849 { 850 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 851 const RandomViewport viewport (m_context.getRenderTarget(), TEX3D_VIEWPORT_WIDTH, TEX3D_VIEWPORT_HEIGHT, deStringHash(getName()) ^ deInt32Hash(m_caseNdx)); 852 const FilterCase& curCase = m_cases[m_caseNdx]; 853 const tcu::TextureFormat texFmt = curCase.texture->getRefTexture().getFormat(); 854 const tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(texFmt); 855 const tcu::ScopedLogSection section (m_testCtx.getLog(), string("Test") + de::toString(m_caseNdx), string("Test ") + de::toString(m_caseNdx)); 856 ReferenceParams refParams (TEXTURETYPE_2D_ARRAY); 857 tcu::Surface rendered (viewport.width, viewport.height); 858 tcu::Vec3 texCoord[4]; 859 860 if (viewport.width < TEX3D_MIN_VIEWPORT_WIDTH || viewport.height < TEX3D_MIN_VIEWPORT_HEIGHT) 861 throw tcu::NotSupportedError("Too small render target", "", __FILE__, __LINE__); 862 863 // Setup params for reference. 864 refParams.sampler = glu::mapGLSampler(m_wrapS, m_wrapT, m_wrapT, m_minFilter, m_magFilter); 865 refParams.samplerType = getSamplerType(texFmt); 866 refParams.lodMode = LODMODE_EXACT; 867 refParams.colorBias = fmtInfo.lookupBias; 868 refParams.colorScale = fmtInfo.lookupScale; 869 870 // Compute texture coordinates. 871 m_testCtx.getLog() << TestLog::Message << "Approximate lod per axis = " << curCase.lod << ", offset = " << curCase.offset << TestLog::EndMessage; 872 873 { 874 const float lodX = curCase.lod.x(); 875 const float lodY = curCase.lod.y(); 876 const float oX = curCase.offset.x(); 877 const float oY = curCase.offset.y(); 878 const float sX = deFloatExp2(lodX)*float(viewport.width) / float(m_gradientTex->getRefTexture().getWidth()); 879 const float sY = deFloatExp2(lodY)*float(viewport.height) / float(m_gradientTex->getRefTexture().getHeight()); 880 const float l0 = curCase.layerRange.x(); 881 const float l1 = curCase.layerRange.y(); 882 883 texCoord[0] = tcu::Vec3(oX, oY, l0); 884 texCoord[1] = tcu::Vec3(oX, oY+sY, l0*0.5f + l1*0.5f); 885 texCoord[2] = tcu::Vec3(oX+sX, oY, l0*0.5f + l1*0.5f); 886 texCoord[3] = tcu::Vec3(oX+sX, oY+sY, l1); 887 } 888 889 gl.bindTexture (GL_TEXTURE_2D_ARRAY, curCase.texture->getGLTexture()); 890 gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, m_minFilter); 891 gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, m_magFilter); 892 gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, m_wrapS); 893 gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, m_wrapT); 894 895 gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height); 896 m_renderer.renderQuad(0, (const float*)&texCoord[0], refParams); 897 glu::readPixels(m_context.getRenderContext(), viewport.x, viewport.y, rendered.getAccess()); 898 899 { 900 const bool isNearestOnly = m_minFilter == GL_NEAREST && m_magFilter == GL_NEAREST; 901 const tcu::PixelFormat pixelFormat = m_context.getRenderTarget().getPixelFormat(); 902 const tcu::IVec4 colorBits = max(getBitsVec(pixelFormat) - (isNearestOnly ? 1 : 2), tcu::IVec4(0)); // 1 inaccurate bit if nearest only, 2 otherwise 903 tcu::LodPrecision lodPrecision; 904 tcu::LookupPrecision lookupPrecision; 905 906 lodPrecision.derivateBits = 18; 907 lodPrecision.lodBits = 6; 908 lookupPrecision.colorThreshold = tcu::computeFixedPointThreshold(colorBits) / refParams.colorScale; 909 lookupPrecision.coordBits = tcu::IVec3(20,20,20); 910 lookupPrecision.uvwBits = tcu::IVec3(7,7,0); 911 lookupPrecision.colorMask = getCompareMask(pixelFormat); 912 913 const bool isHighQuality = verifyTextureResult(m_testCtx, rendered.getAccess(), curCase.texture->getRefTexture(), 914 (const float*)&texCoord[0], refParams, lookupPrecision, lodPrecision, pixelFormat); 915 916 if (!isHighQuality) 917 { 918 // Evaluate against lower precision requirements. 919 lodPrecision.lodBits = 4; 920 lookupPrecision.uvwBits = tcu::IVec3(4,4,0); 921 922 m_testCtx.getLog() << TestLog::Message << "Warning: Verification against high precision requirements failed, trying with lower requirements." << TestLog::EndMessage; 923 924 const bool isOk = verifyTextureResult(m_testCtx, rendered.getAccess(), curCase.texture->getRefTexture(), 925 (const float*)&texCoord[0], refParams, lookupPrecision, lodPrecision, pixelFormat); 926 927 if (!isOk) 928 { 929 m_testCtx.getLog() << TestLog::Message << "ERROR: Verification against low precision requirements failed, failing test case." << TestLog::EndMessage; 930 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed"); 931 } 932 else if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS) 933 m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, "Low-quality filtering result"); 934 } 935 } 936 937 m_caseNdx += 1; 938 return m_caseNdx < (int)m_cases.size() ? CONTINUE : STOP; 939 } 940 941 // 3D filtering 942 943 class Texture3DFilteringCase : public TestCase 944 { 945 public: 946 Texture3DFilteringCase (Context& context, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT, deUint32 wrapR, deUint32 internalFormat, int width, int height, int depth); 947 ~Texture3DFilteringCase (void); 948 949 void init (void); 950 void deinit (void); 951 IterateResult iterate (void); 952 953 private: 954 Texture3DFilteringCase (const Texture3DFilteringCase& other); 955 Texture3DFilteringCase& operator= (const Texture3DFilteringCase& other); 956 957 const deUint32 m_minFilter; 958 const deUint32 m_magFilter; 959 const deUint32 m_wrapS; 960 const deUint32 m_wrapT; 961 const deUint32 m_wrapR; 962 963 const deUint32 m_internalFormat; 964 const int m_width; 965 const int m_height; 966 const int m_depth; 967 968 struct FilterCase 969 { 970 const glu::Texture3D* texture; 971 tcu::Vec3 lod; 972 tcu::Vec3 offset; 973 974 FilterCase (void) 975 : texture(DE_NULL) 976 { 977 } 978 979 FilterCase (const glu::Texture3D* tex_, const tcu::Vec3& lod_, const tcu::Vec3& offset_) 980 : texture (tex_) 981 , lod (lod_) 982 , offset (offset_) 983 { 984 } 985 }; 986 987 glu::Texture3D* m_gradientTex; 988 glu::Texture3D* m_gridTex; 989 990 TextureRenderer m_renderer; 991 992 std::vector<FilterCase> m_cases; 993 int m_caseNdx; 994 }; 995 996 Texture3DFilteringCase::Texture3DFilteringCase (Context& context, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT, deUint32 wrapR, deUint32 internalFormat, int width, int height, int depth) 997 : TestCase (context, name, desc) 998 , m_minFilter (minFilter) 999 , m_magFilter (magFilter) 1000 , m_wrapS (wrapS) 1001 , m_wrapT (wrapT) 1002 , m_wrapR (wrapR) 1003 , m_internalFormat (internalFormat) 1004 , m_width (width) 1005 , m_height (height) 1006 , m_depth (depth) 1007 , m_gradientTex (DE_NULL) 1008 , m_gridTex (DE_NULL) 1009 , m_renderer (context.getRenderContext(), context.getTestContext().getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_HIGHP) 1010 , m_caseNdx (0) 1011 { 1012 } 1013 1014 Texture3DFilteringCase::~Texture3DFilteringCase (void) 1015 { 1016 Texture3DFilteringCase::deinit(); 1017 } 1018 1019 void Texture3DFilteringCase::init (void) 1020 { 1021 checkSupport(m_context.getContextInfo(), m_internalFormat); 1022 1023 try 1024 { 1025 const tcu::TextureFormat texFmt = glu::mapGLInternalFormat(m_internalFormat); 1026 const tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(texFmt); 1027 const tcu::Vec4 cScale = fmtInfo.valueMax-fmtInfo.valueMin; 1028 const tcu::Vec4 cBias = fmtInfo.valueMin; 1029 const int numLevels = deLog2Floor32(de::max(de::max(m_width, m_height), m_depth)) + 1; 1030 1031 // Create textures. 1032 m_gradientTex = new glu::Texture3D(m_context.getRenderContext(), m_internalFormat, m_width, m_height, m_depth); 1033 m_gridTex = new glu::Texture3D(m_context.getRenderContext(), m_internalFormat, m_width, m_height, m_depth); 1034 1035 // Fill first gradient texture. 1036 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++) 1037 { 1038 tcu::Vec4 gMin = tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f)*cScale + cBias; 1039 tcu::Vec4 gMax = tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f)*cScale + cBias; 1040 1041 m_gradientTex->getRefTexture().allocLevel(levelNdx); 1042 tcu::fillWithComponentGradients(m_gradientTex->getRefTexture().getLevel(levelNdx), gMin, gMax); 1043 } 1044 1045 // Fill second with grid texture. 1046 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++) 1047 { 1048 deUint32 step = 0x00ffffff / numLevels; 1049 deUint32 rgb = step*levelNdx; 1050 deUint32 colorA = 0xff000000 | rgb; 1051 deUint32 colorB = 0xff000000 | ~rgb; 1052 1053 m_gridTex->getRefTexture().allocLevel(levelNdx); 1054 tcu::fillWithGrid(m_gridTex->getRefTexture().getLevel(levelNdx), 4, tcu::RGBA(colorA).toVec()*cScale + cBias, tcu::RGBA(colorB).toVec()*cScale + cBias); 1055 } 1056 1057 // Upload. 1058 m_gradientTex->upload(); 1059 m_gridTex->upload(); 1060 1061 // Test cases 1062 m_cases.push_back(FilterCase(m_gradientTex, tcu::Vec3(1.5f, 2.8f, 1.0f), tcu::Vec3(-1.0f, -2.7f, -2.275f))); 1063 m_cases.push_back(FilterCase(m_gradientTex, tcu::Vec3(-2.0f, -1.5f, -1.8f), tcu::Vec3(-0.1f, 0.9f, -0.25f))); 1064 m_cases.push_back(FilterCase(m_gridTex, tcu::Vec3(0.2f, 0.175f, 0.3f), tcu::Vec3(-2.0f, -3.7f, -1.825f))); 1065 m_cases.push_back(FilterCase(m_gridTex, tcu::Vec3(-0.8f, -2.3f, -2.5f), tcu::Vec3(0.2f, -0.1f, 1.325f))); 1066 1067 m_caseNdx = 0; 1068 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 1069 } 1070 catch (...) 1071 { 1072 // Clean up to save memory. 1073 Texture3DFilteringCase::deinit(); 1074 throw; 1075 } 1076 } 1077 1078 void Texture3DFilteringCase::deinit (void) 1079 { 1080 delete m_gradientTex; 1081 delete m_gridTex; 1082 1083 m_gradientTex = DE_NULL; 1084 m_gridTex = DE_NULL; 1085 1086 m_renderer.clear(); 1087 m_cases.clear(); 1088 } 1089 1090 Texture3DFilteringCase::IterateResult Texture3DFilteringCase::iterate (void) 1091 { 1092 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 1093 const RandomViewport viewport (m_context.getRenderTarget(), TEX3D_VIEWPORT_WIDTH, TEX3D_VIEWPORT_HEIGHT, deStringHash(getName()) ^ deInt32Hash(m_caseNdx)); 1094 const FilterCase& curCase = m_cases[m_caseNdx]; 1095 const tcu::TextureFormat texFmt = curCase.texture->getRefTexture().getFormat(); 1096 const tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(texFmt); 1097 const tcu::ScopedLogSection section (m_testCtx.getLog(), string("Test") + de::toString(m_caseNdx), string("Test ") + de::toString(m_caseNdx)); 1098 ReferenceParams refParams (TEXTURETYPE_3D); 1099 tcu::Surface rendered (viewport.width, viewport.height); 1100 tcu::Vec3 texCoord[4]; 1101 1102 if (viewport.width < TEX3D_MIN_VIEWPORT_WIDTH || viewport.height < TEX3D_MIN_VIEWPORT_HEIGHT) 1103 throw tcu::NotSupportedError("Too small render target", "", __FILE__, __LINE__); 1104 1105 // Setup params for reference. 1106 refParams.sampler = glu::mapGLSampler(m_wrapS, m_wrapT, m_wrapR, m_minFilter, m_magFilter); 1107 refParams.samplerType = getSamplerType(texFmt); 1108 refParams.lodMode = LODMODE_EXACT; 1109 refParams.colorBias = fmtInfo.lookupBias; 1110 refParams.colorScale = fmtInfo.lookupScale; 1111 1112 // Compute texture coordinates. 1113 m_testCtx.getLog() << TestLog::Message << "Approximate lod per axis = " << curCase.lod << ", offset = " << curCase.offset << TestLog::EndMessage; 1114 1115 { 1116 const float lodX = curCase.lod.x(); 1117 const float lodY = curCase.lod.y(); 1118 const float lodZ = curCase.lod.z(); 1119 const float oX = curCase.offset.x(); 1120 const float oY = curCase.offset.y(); 1121 const float oZ = curCase.offset.z(); 1122 const float sX = deFloatExp2(lodX)*float(viewport.width) / float(m_gradientTex->getRefTexture().getWidth()); 1123 const float sY = deFloatExp2(lodY)*float(viewport.height) / float(m_gradientTex->getRefTexture().getHeight()); 1124 const float sZ = deFloatExp2(lodZ)*float(de::max(viewport.width, viewport.height)) / float(m_gradientTex->getRefTexture().getDepth()); 1125 1126 texCoord[0] = tcu::Vec3(oX, oY, oZ); 1127 texCoord[1] = tcu::Vec3(oX, oY+sY, oZ + sZ*0.5f); 1128 texCoord[2] = tcu::Vec3(oX+sX, oY, oZ + sZ*0.5f); 1129 texCoord[3] = tcu::Vec3(oX+sX, oY+sY, oZ + sZ); 1130 } 1131 1132 gl.bindTexture (GL_TEXTURE_3D, curCase.texture->getGLTexture()); 1133 gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, m_minFilter); 1134 gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, m_magFilter); 1135 gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, m_wrapS); 1136 gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, m_wrapT); 1137 gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, m_wrapR); 1138 1139 gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height); 1140 m_renderer.renderQuad(0, (const float*)&texCoord[0], refParams); 1141 glu::readPixels(m_context.getRenderContext(), viewport.x, viewport.y, rendered.getAccess()); 1142 1143 { 1144 const bool isNearestOnly = m_minFilter == GL_NEAREST && m_magFilter == GL_NEAREST; 1145 const tcu::PixelFormat pixelFormat = m_context.getRenderTarget().getPixelFormat(); 1146 const tcu::IVec4 colorBits = max(getBitsVec(pixelFormat) - (isNearestOnly ? 1 : 2), tcu::IVec4(0)); // 1 inaccurate bit if nearest only, 2 otherwise 1147 tcu::LodPrecision lodPrecision; 1148 tcu::LookupPrecision lookupPrecision; 1149 1150 lodPrecision.derivateBits = 18; 1151 lodPrecision.lodBits = 6; 1152 lookupPrecision.colorThreshold = tcu::computeFixedPointThreshold(colorBits) / refParams.colorScale; 1153 lookupPrecision.coordBits = tcu::IVec3(20,20,20); 1154 lookupPrecision.uvwBits = tcu::IVec3(7,7,7); 1155 lookupPrecision.colorMask = getCompareMask(pixelFormat); 1156 1157 const bool isHighQuality = verifyTextureResult(m_testCtx, rendered.getAccess(), curCase.texture->getRefTexture(), 1158 (const float*)&texCoord[0], refParams, lookupPrecision, lodPrecision, pixelFormat); 1159 1160 if (!isHighQuality) 1161 { 1162 // Evaluate against lower precision requirements. 1163 lodPrecision.lodBits = 4; 1164 lookupPrecision.uvwBits = tcu::IVec3(4,4,4); 1165 1166 m_testCtx.getLog() << TestLog::Message << "Warning: Verification against high precision requirements failed, trying with lower requirements." << TestLog::EndMessage; 1167 1168 const bool isOk = verifyTextureResult(m_testCtx, rendered.getAccess(), curCase.texture->getRefTexture(), 1169 (const float*)&texCoord[0], refParams, lookupPrecision, lodPrecision, pixelFormat); 1170 1171 if (!isOk) 1172 { 1173 m_testCtx.getLog() << TestLog::Message << "ERROR: Verification against low precision requirements failed, failing test case." << TestLog::EndMessage; 1174 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed"); 1175 } 1176 else if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS) 1177 m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, "Low-quality filtering result"); 1178 } 1179 } 1180 1181 m_caseNdx += 1; 1182 return m_caseNdx < (int)m_cases.size() ? CONTINUE : STOP; 1183 } 1184 1185 TextureFilteringTests::TextureFilteringTests (Context& context) 1186 : TestCaseGroup(context, "filtering", "Texture Filtering Tests") 1187 { 1188 } 1189 1190 TextureFilteringTests::~TextureFilteringTests (void) 1191 { 1192 } 1193 1194 void TextureFilteringTests::init (void) 1195 { 1196 static const struct 1197 { 1198 const char* name; 1199 deUint32 mode; 1200 } wrapModes[] = 1201 { 1202 { "clamp", GL_CLAMP_TO_EDGE }, 1203 { "repeat", GL_REPEAT }, 1204 { "mirror", GL_MIRRORED_REPEAT } 1205 }; 1206 1207 static const struct 1208 { 1209 const char* name; 1210 deUint32 mode; 1211 } minFilterModes[] = 1212 { 1213 { "nearest", GL_NEAREST }, 1214 { "linear", GL_LINEAR }, 1215 { "nearest_mipmap_nearest", GL_NEAREST_MIPMAP_NEAREST }, 1216 { "linear_mipmap_nearest", GL_LINEAR_MIPMAP_NEAREST }, 1217 { "nearest_mipmap_linear", GL_NEAREST_MIPMAP_LINEAR }, 1218 { "linear_mipmap_linear", GL_LINEAR_MIPMAP_LINEAR } 1219 }; 1220 1221 static const struct 1222 { 1223 const char* name; 1224 deUint32 mode; 1225 } magFilterModes[] = 1226 { 1227 { "nearest", GL_NEAREST }, 1228 { "linear", GL_LINEAR } 1229 }; 1230 1231 static const struct 1232 { 1233 int width; 1234 int height; 1235 } sizes2D[] = 1236 { 1237 { 4, 8 }, 1238 { 32, 64 }, 1239 { 128, 128 }, 1240 { 3, 7 }, 1241 { 31, 55 }, 1242 { 127, 99 } 1243 }; 1244 1245 static const struct 1246 { 1247 int width; 1248 int height; 1249 } sizesCube[] = 1250 { 1251 { 8, 8 }, 1252 { 64, 64 }, 1253 { 128, 128 }, 1254 { 7, 7 }, 1255 { 63, 63 } 1256 }; 1257 1258 static const struct 1259 { 1260 int width; 1261 int height; 1262 int numLayers; 1263 } sizes2DArray[] = 1264 { 1265 { 4, 8, 8 }, 1266 { 32, 64, 16 }, 1267 { 128, 32, 64 }, 1268 { 3, 7, 5 }, 1269 { 63, 63, 63 } 1270 }; 1271 1272 static const struct 1273 { 1274 int width; 1275 int height; 1276 int depth; 1277 } sizes3D[] = 1278 { 1279 { 4, 8, 8 }, 1280 { 32, 64, 16 }, 1281 { 128, 32, 64 }, 1282 { 3, 7, 5 }, 1283 { 63, 63, 63 } 1284 }; 1285 1286 static const struct 1287 { 1288 const char* name; 1289 deUint32 format; 1290 } filterableFormatsByType[] = 1291 { 1292 { "rgba16f", GL_RGBA16F }, 1293 { "r11f_g11f_b10f", GL_R11F_G11F_B10F }, 1294 { "rgb9_e5", GL_RGB9_E5 }, 1295 { "rgba8", GL_RGBA8 }, 1296 { "rgba8_snorm", GL_RGBA8_SNORM }, 1297 { "rgb565", GL_RGB565 }, 1298 { "rgba4", GL_RGBA4 }, 1299 { "rgb5_a1", GL_RGB5_A1 }, 1300 { "srgb8_alpha8", GL_SRGB8_ALPHA8 }, 1301 { "srgb_r8", GL_SR8_EXT }, 1302 { "rgb10_a2", GL_RGB10_A2 } 1303 }; 1304 1305 // 2D texture filtering. 1306 { 1307 tcu::TestCaseGroup* group2D = new tcu::TestCaseGroup(m_testCtx, "2d", "2D Texture Filtering"); 1308 addChild(group2D); 1309 1310 // Formats. 1311 tcu::TestCaseGroup* formatsGroup = new tcu::TestCaseGroup(m_testCtx, "formats", "2D Texture Formats"); 1312 group2D->addChild(formatsGroup); 1313 for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(filterableFormatsByType); fmtNdx++) 1314 { 1315 for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++) 1316 { 1317 deUint32 minFilter = minFilterModes[filterNdx].mode; 1318 const char* filterName = minFilterModes[filterNdx].name; 1319 deUint32 format = filterableFormatsByType[fmtNdx].format; 1320 const char* formatName = filterableFormatsByType[fmtNdx].name; 1321 bool isMipmap = minFilter != GL_NEAREST && minFilter != GL_LINEAR; 1322 deUint32 magFilter = isMipmap ? GL_LINEAR : minFilter; 1323 string name = string(formatName) + "_" + filterName; 1324 deUint32 wrapS = GL_REPEAT; 1325 deUint32 wrapT = GL_REPEAT; 1326 int width = 64; 1327 int height = 64; 1328 1329 formatsGroup->addChild(new Texture2DFilteringCase(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(), 1330 name.c_str(), "", 1331 minFilter, magFilter, 1332 wrapS, wrapT, 1333 format, 1334 width, height)); 1335 } 1336 } 1337 1338 // ETC1 format. 1339 { 1340 std::vector<std::string> filenames; 1341 for (int i = 0; i <= 7; i++) 1342 filenames.push_back(string("data/etc1/photo_helsinki_mip_") + de::toString(i) + ".pkm"); 1343 1344 for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++) 1345 { 1346 deUint32 minFilter = minFilterModes[filterNdx].mode; 1347 const char* filterName = minFilterModes[filterNdx].name; 1348 bool isMipmap = minFilter != GL_NEAREST && minFilter != GL_LINEAR; 1349 deUint32 magFilter = isMipmap ? GL_LINEAR : minFilter; 1350 string name = string("etc1_rgb8_") + filterName; 1351 deUint32 wrapS = GL_REPEAT; 1352 deUint32 wrapT = GL_REPEAT; 1353 1354 formatsGroup->addChild(new Texture2DFilteringCase(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(), 1355 name.c_str(), "", 1356 minFilter, magFilter, 1357 wrapS, wrapT, 1358 filenames)); 1359 } 1360 } 1361 1362 // Sizes. 1363 tcu::TestCaseGroup* sizesGroup = new tcu::TestCaseGroup(m_testCtx, "sizes", "Texture Sizes"); 1364 group2D->addChild(sizesGroup); 1365 for (int sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(sizes2D); sizeNdx++) 1366 { 1367 for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++) 1368 { 1369 deUint32 minFilter = minFilterModes[filterNdx].mode; 1370 const char* filterName = minFilterModes[filterNdx].name; 1371 deUint32 format = GL_RGBA8; 1372 bool isMipmap = minFilter != GL_NEAREST && minFilter != GL_LINEAR; 1373 deUint32 magFilter = isMipmap ? GL_LINEAR : minFilter; 1374 deUint32 wrapS = GL_REPEAT; 1375 deUint32 wrapT = GL_REPEAT; 1376 int width = sizes2D[sizeNdx].width; 1377 int height = sizes2D[sizeNdx].height; 1378 string name = de::toString(width) + "x" + de::toString(height) + "_" + filterName; 1379 1380 sizesGroup->addChild(new Texture2DFilteringCase(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(), 1381 name.c_str(), "", 1382 minFilter, magFilter, 1383 wrapS, wrapT, 1384 format, 1385 width, height)); 1386 } 1387 } 1388 1389 // Wrap modes. 1390 tcu::TestCaseGroup* combinationsGroup = new tcu::TestCaseGroup(m_testCtx, "combinations", "Filter and wrap mode combinations"); 1391 group2D->addChild(combinationsGroup); 1392 for (int minFilterNdx = 0; minFilterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); minFilterNdx++) 1393 { 1394 for (int magFilterNdx = 0; magFilterNdx < DE_LENGTH_OF_ARRAY(magFilterModes); magFilterNdx++) 1395 { 1396 for (int wrapSNdx = 0; wrapSNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapSNdx++) 1397 { 1398 for (int wrapTNdx = 0; wrapTNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapTNdx++) 1399 { 1400 deUint32 minFilter = minFilterModes[minFilterNdx].mode; 1401 deUint32 magFilter = magFilterModes[magFilterNdx].mode; 1402 deUint32 format = GL_RGBA8; 1403 deUint32 wrapS = wrapModes[wrapSNdx].mode; 1404 deUint32 wrapT = wrapModes[wrapTNdx].mode; 1405 int width = 63; 1406 int height = 57; 1407 string name = string(minFilterModes[minFilterNdx].name) + "_" + magFilterModes[magFilterNdx].name + "_" + wrapModes[wrapSNdx].name + "_" + wrapModes[wrapTNdx].name; 1408 1409 combinationsGroup->addChild(new Texture2DFilteringCase(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(), 1410 name.c_str(), "", 1411 minFilter, magFilter, 1412 wrapS, wrapT, 1413 format, 1414 width, height)); 1415 } 1416 } 1417 } 1418 } 1419 } 1420 1421 // Cube map texture filtering. 1422 { 1423 tcu::TestCaseGroup* groupCube = new tcu::TestCaseGroup(m_testCtx, "cube", "Cube Map Texture Filtering"); 1424 addChild(groupCube); 1425 1426 // Formats. 1427 tcu::TestCaseGroup* formatsGroup = new tcu::TestCaseGroup(m_testCtx, "formats", "2D Texture Formats"); 1428 groupCube->addChild(formatsGroup); 1429 for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(filterableFormatsByType); fmtNdx++) 1430 { 1431 for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++) 1432 { 1433 deUint32 minFilter = minFilterModes[filterNdx].mode; 1434 const char* filterName = minFilterModes[filterNdx].name; 1435 deUint32 format = filterableFormatsByType[fmtNdx].format; 1436 const char* formatName = filterableFormatsByType[fmtNdx].name; 1437 bool isMipmap = minFilter != GL_NEAREST && minFilter != GL_LINEAR; 1438 deUint32 magFilter = isMipmap ? GL_LINEAR : minFilter; 1439 string name = string(formatName) + "_" + filterName; 1440 deUint32 wrapS = GL_REPEAT; 1441 deUint32 wrapT = GL_REPEAT; 1442 int width = 64; 1443 int height = 64; 1444 1445 formatsGroup->addChild(new TextureCubeFilteringCase(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(), 1446 name.c_str(), "", 1447 minFilter, magFilter, 1448 wrapS, wrapT, 1449 false /* always sample exterior as well */, 1450 format, 1451 width, height)); 1452 } 1453 } 1454 1455 // ETC1 format. 1456 { 1457 static const char* faceExt[] = { "neg_x", "pos_x", "neg_y", "pos_y", "neg_z", "pos_z" }; 1458 1459 const int numLevels = 7; 1460 vector<string> filenames; 1461 for (int level = 0; level < numLevels; level++) 1462 for (int face = 0; face < tcu::CUBEFACE_LAST; face++) 1463 filenames.push_back(string("data/etc1/skybox_") + faceExt[face] + "_mip_" + de::toString(level) + ".pkm"); 1464 1465 for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++) 1466 { 1467 deUint32 minFilter = minFilterModes[filterNdx].mode; 1468 const char* filterName = minFilterModes[filterNdx].name; 1469 bool isMipmap = minFilter != GL_NEAREST && minFilter != GL_LINEAR; 1470 deUint32 magFilter = isMipmap ? GL_LINEAR : minFilter; 1471 string name = string("etc1_rgb8_") + filterName; 1472 deUint32 wrapS = GL_REPEAT; 1473 deUint32 wrapT = GL_REPEAT; 1474 1475 formatsGroup->addChild(new TextureCubeFilteringCase(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(), 1476 name.c_str(), "", 1477 minFilter, magFilter, 1478 wrapS, wrapT, 1479 false /* always sample exterior as well */, 1480 filenames)); 1481 } 1482 } 1483 1484 // Sizes. 1485 tcu::TestCaseGroup* sizesGroup = new tcu::TestCaseGroup(m_testCtx, "sizes", "Texture Sizes"); 1486 groupCube->addChild(sizesGroup); 1487 for (int sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(sizesCube); sizeNdx++) 1488 { 1489 for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++) 1490 { 1491 deUint32 minFilter = minFilterModes[filterNdx].mode; 1492 const char* filterName = minFilterModes[filterNdx].name; 1493 deUint32 format = GL_RGBA8; 1494 bool isMipmap = minFilter != GL_NEAREST && minFilter != GL_LINEAR; 1495 deUint32 magFilter = isMipmap ? GL_LINEAR : minFilter; 1496 deUint32 wrapS = GL_REPEAT; 1497 deUint32 wrapT = GL_REPEAT; 1498 int width = sizesCube[sizeNdx].width; 1499 int height = sizesCube[sizeNdx].height; 1500 string name = de::toString(width) + "x" + de::toString(height) + "_" + filterName; 1501 1502 sizesGroup->addChild(new TextureCubeFilteringCase(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(), 1503 name.c_str(), "", 1504 minFilter, magFilter, 1505 wrapS, wrapT, 1506 false, 1507 format, 1508 width, height)); 1509 } 1510 } 1511 1512 // Filter/wrap mode combinations. 1513 tcu::TestCaseGroup* combinationsGroup = new tcu::TestCaseGroup(m_testCtx, "combinations", "Filter and wrap mode combinations"); 1514 groupCube->addChild(combinationsGroup); 1515 for (int minFilterNdx = 0; minFilterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); minFilterNdx++) 1516 { 1517 for (int magFilterNdx = 0; magFilterNdx < DE_LENGTH_OF_ARRAY(magFilterModes); magFilterNdx++) 1518 { 1519 for (int wrapSNdx = 0; wrapSNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapSNdx++) 1520 { 1521 for (int wrapTNdx = 0; wrapTNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapTNdx++) 1522 { 1523 deUint32 minFilter = minFilterModes[minFilterNdx].mode; 1524 deUint32 magFilter = magFilterModes[magFilterNdx].mode; 1525 deUint32 format = GL_RGBA8; 1526 deUint32 wrapS = wrapModes[wrapSNdx].mode; 1527 deUint32 wrapT = wrapModes[wrapTNdx].mode; 1528 int width = 63; 1529 int height = 63; 1530 string name = string(minFilterModes[minFilterNdx].name) + "_" + magFilterModes[magFilterNdx].name + "_" + wrapModes[wrapSNdx].name + "_" + wrapModes[wrapTNdx].name; 1531 1532 combinationsGroup->addChild(new TextureCubeFilteringCase(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(), 1533 name.c_str(), "", 1534 minFilter, magFilter, 1535 wrapS, wrapT, 1536 false, 1537 format, 1538 width, height)); 1539 } 1540 } 1541 } 1542 } 1543 1544 // Cases with no visible cube edges. 1545 tcu::TestCaseGroup* onlyFaceInteriorGroup = new tcu::TestCaseGroup(m_testCtx, "no_edges_visible", "Don't sample anywhere near a face's edges"); 1546 groupCube->addChild(onlyFaceInteriorGroup); 1547 1548 for (int isLinearI = 0; isLinearI <= 1; isLinearI++) 1549 { 1550 bool isLinear = isLinearI != 0; 1551 deUint32 filter = isLinear ? GL_LINEAR : GL_NEAREST; 1552 1553 onlyFaceInteriorGroup->addChild(new TextureCubeFilteringCase(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(), 1554 isLinear ? "linear" : "nearest", "", 1555 filter, filter, 1556 GL_REPEAT, GL_REPEAT, 1557 true, 1558 GL_RGBA8, 1559 63, 63)); 1560 } 1561 } 1562 1563 // 2D array texture filtering. 1564 { 1565 tcu::TestCaseGroup* const group2DArray = new tcu::TestCaseGroup(m_testCtx, "2d_array", "2D Array Texture Filtering"); 1566 addChild(group2DArray); 1567 1568 // Formats. 1569 tcu::TestCaseGroup* const formatsGroup = new tcu::TestCaseGroup(m_testCtx, "formats", "2D Array Texture Formats"); 1570 group2DArray->addChild(formatsGroup); 1571 for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(filterableFormatsByType); fmtNdx++) 1572 { 1573 for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++) 1574 { 1575 deUint32 minFilter = minFilterModes[filterNdx].mode; 1576 const char* filterName = minFilterModes[filterNdx].name; 1577 deUint32 format = filterableFormatsByType[fmtNdx].format; 1578 const char* formatName = filterableFormatsByType[fmtNdx].name; 1579 bool isMipmap = minFilter != GL_NEAREST && minFilter != GL_LINEAR; 1580 deUint32 magFilter = isMipmap ? GL_LINEAR : minFilter; 1581 string name = string(formatName) + "_" + filterName; 1582 deUint32 wrapS = GL_REPEAT; 1583 deUint32 wrapT = GL_REPEAT; 1584 int width = 128; 1585 int height = 128; 1586 int numLayers = 8; 1587 1588 formatsGroup->addChild(new Texture2DArrayFilteringCase(m_context, 1589 name.c_str(), "", 1590 minFilter, magFilter, 1591 wrapS, wrapT, 1592 format, 1593 width, height, numLayers)); 1594 } 1595 } 1596 1597 // Sizes. 1598 tcu::TestCaseGroup* sizesGroup = new tcu::TestCaseGroup(m_testCtx, "sizes", "Texture Sizes"); 1599 group2DArray->addChild(sizesGroup); 1600 for (int sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(sizes2DArray); sizeNdx++) 1601 { 1602 for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++) 1603 { 1604 deUint32 minFilter = minFilterModes[filterNdx].mode; 1605 const char* filterName = minFilterModes[filterNdx].name; 1606 deUint32 format = GL_RGBA8; 1607 bool isMipmap = minFilter != GL_NEAREST && minFilter != GL_LINEAR; 1608 deUint32 magFilter = isMipmap ? GL_LINEAR : minFilter; 1609 deUint32 wrapS = GL_REPEAT; 1610 deUint32 wrapT = GL_REPEAT; 1611 int width = sizes2DArray[sizeNdx].width; 1612 int height = sizes2DArray[sizeNdx].height; 1613 int numLayers = sizes2DArray[sizeNdx].numLayers; 1614 string name = de::toString(width) + "x" + de::toString(height) + "x" + de::toString(numLayers) + "_" + filterName; 1615 1616 sizesGroup->addChild(new Texture2DArrayFilteringCase(m_context, 1617 name.c_str(), "", 1618 minFilter, magFilter, 1619 wrapS, wrapT, 1620 format, 1621 width, height, numLayers)); 1622 } 1623 } 1624 1625 // Wrap modes. 1626 tcu::TestCaseGroup* const combinationsGroup = new tcu::TestCaseGroup(m_testCtx, "combinations", "Filter and wrap mode combinations"); 1627 group2DArray->addChild(combinationsGroup); 1628 for (int minFilterNdx = 0; minFilterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); minFilterNdx++) 1629 { 1630 for (int magFilterNdx = 0; magFilterNdx < DE_LENGTH_OF_ARRAY(magFilterModes); magFilterNdx++) 1631 { 1632 for (int wrapSNdx = 0; wrapSNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapSNdx++) 1633 { 1634 for (int wrapTNdx = 0; wrapTNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapTNdx++) 1635 { 1636 deUint32 minFilter = minFilterModes[minFilterNdx].mode; 1637 deUint32 magFilter = magFilterModes[magFilterNdx].mode; 1638 deUint32 format = GL_RGBA8; 1639 deUint32 wrapS = wrapModes[wrapSNdx].mode; 1640 deUint32 wrapT = wrapModes[wrapTNdx].mode; 1641 int width = 123; 1642 int height = 107; 1643 int numLayers = 7; 1644 string name = string(minFilterModes[minFilterNdx].name) + "_" + magFilterModes[magFilterNdx].name + "_" + wrapModes[wrapSNdx].name + "_" + wrapModes[wrapTNdx].name; 1645 1646 combinationsGroup->addChild(new Texture2DArrayFilteringCase(m_context, 1647 name.c_str(), "", 1648 minFilter, magFilter, 1649 wrapS, wrapT, 1650 format, 1651 width, height, numLayers)); 1652 } 1653 } 1654 } 1655 } 1656 } 1657 1658 // 3D texture filtering. 1659 { 1660 tcu::TestCaseGroup* group3D = new tcu::TestCaseGroup(m_testCtx, "3d", "3D Texture Filtering"); 1661 addChild(group3D); 1662 1663 // Formats. 1664 tcu::TestCaseGroup* formatsGroup = new tcu::TestCaseGroup(m_testCtx, "formats", "3D Texture Formats"); 1665 group3D->addChild(formatsGroup); 1666 for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(filterableFormatsByType); fmtNdx++) 1667 { 1668 for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++) 1669 { 1670 deUint32 minFilter = minFilterModes[filterNdx].mode; 1671 const char* filterName = minFilterModes[filterNdx].name; 1672 deUint32 format = filterableFormatsByType[fmtNdx].format; 1673 const char* formatName = filterableFormatsByType[fmtNdx].name; 1674 bool isMipmap = minFilter != GL_NEAREST && minFilter != GL_LINEAR; 1675 deUint32 magFilter = isMipmap ? GL_LINEAR : minFilter; 1676 string name = string(formatName) + "_" + filterName; 1677 deUint32 wrapS = GL_REPEAT; 1678 deUint32 wrapT = GL_REPEAT; 1679 deUint32 wrapR = GL_REPEAT; 1680 int width = 64; 1681 int height = 64; 1682 int depth = 64; 1683 1684 formatsGroup->addChild(new Texture3DFilteringCase(m_context, 1685 name.c_str(), "", 1686 minFilter, magFilter, 1687 wrapS, wrapT, wrapR, 1688 format, 1689 width, height, depth)); 1690 } 1691 } 1692 1693 // Sizes. 1694 tcu::TestCaseGroup* sizesGroup = new tcu::TestCaseGroup(m_testCtx, "sizes", "Texture Sizes"); 1695 group3D->addChild(sizesGroup); 1696 for (int sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(sizes3D); sizeNdx++) 1697 { 1698 for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++) 1699 { 1700 deUint32 minFilter = minFilterModes[filterNdx].mode; 1701 const char* filterName = minFilterModes[filterNdx].name; 1702 deUint32 format = GL_RGBA8; 1703 bool isMipmap = minFilter != GL_NEAREST && minFilter != GL_LINEAR; 1704 deUint32 magFilter = isMipmap ? GL_LINEAR : minFilter; 1705 deUint32 wrapS = GL_REPEAT; 1706 deUint32 wrapT = GL_REPEAT; 1707 deUint32 wrapR = GL_REPEAT; 1708 int width = sizes3D[sizeNdx].width; 1709 int height = sizes3D[sizeNdx].height; 1710 int depth = sizes3D[sizeNdx].depth; 1711 string name = de::toString(width) + "x" + de::toString(height) + "x" + de::toString(depth) + "_" + filterName; 1712 1713 sizesGroup->addChild(new Texture3DFilteringCase(m_context, 1714 name.c_str(), "", 1715 minFilter, magFilter, 1716 wrapS, wrapT, wrapR, 1717 format, 1718 width, height, depth)); 1719 } 1720 } 1721 1722 // Wrap modes. 1723 tcu::TestCaseGroup* combinationsGroup = new tcu::TestCaseGroup(m_testCtx, "combinations", "Filter and wrap mode combinations"); 1724 group3D->addChild(combinationsGroup); 1725 for (int minFilterNdx = 0; minFilterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); minFilterNdx++) 1726 { 1727 for (int magFilterNdx = 0; magFilterNdx < DE_LENGTH_OF_ARRAY(magFilterModes); magFilterNdx++) 1728 { 1729 for (int wrapSNdx = 0; wrapSNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapSNdx++) 1730 { 1731 for (int wrapTNdx = 0; wrapTNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapTNdx++) 1732 { 1733 for (int wrapRNdx = 0; wrapRNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapRNdx++) 1734 { 1735 deUint32 minFilter = minFilterModes[minFilterNdx].mode; 1736 deUint32 magFilter = magFilterModes[magFilterNdx].mode; 1737 deUint32 format = GL_RGBA8; 1738 deUint32 wrapS = wrapModes[wrapSNdx].mode; 1739 deUint32 wrapT = wrapModes[wrapTNdx].mode; 1740 deUint32 wrapR = wrapModes[wrapRNdx].mode; 1741 int width = 63; 1742 int height = 57; 1743 int depth = 67; 1744 string name = string(minFilterModes[minFilterNdx].name) + "_" + magFilterModes[magFilterNdx].name + "_" + wrapModes[wrapSNdx].name + "_" + wrapModes[wrapTNdx].name + "_" + wrapModes[wrapRNdx].name; 1745 1746 combinationsGroup->addChild(new Texture3DFilteringCase(m_context, 1747 name.c_str(), "", 1748 minFilter, magFilter, 1749 wrapS, wrapT, wrapR, 1750 format, 1751 width, height, depth)); 1752 } 1753 } 1754 } 1755 } 1756 } 1757 } 1758 } 1759 1760 } // Functional 1761 } // gles3 1762 } // deqp 1763