1 /*------------------------------------------------------------------------- 2 * drawElements Quality Program OpenGL ES 3.1 Module 3 * ------------------------------------------------- 4 * 5 * Copyright 2014 The Android Open Source Project 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 * 19 *//*! 20 * \file 21 * \brief Texture filtering tests. 22 *//*--------------------------------------------------------------------*/ 23 24 #include "es31fTextureFilteringTests.hpp" 25 26 #include "glsTextureTestUtil.hpp" 27 28 #include "gluPixelTransfer.hpp" 29 #include "gluTexture.hpp" 30 #include "gluTextureUtil.hpp" 31 32 #include "tcuCommandLine.hpp" 33 #include "tcuTextureUtil.hpp" 34 #include "tcuImageCompare.hpp" 35 #include "tcuTexLookupVerifier.hpp" 36 #include "tcuVectorUtil.hpp" 37 38 #include "deStringUtil.hpp" 39 #include "deString.h" 40 41 #include "glwFunctions.hpp" 42 #include "glwEnums.hpp" 43 44 namespace deqp 45 { 46 namespace gles31 47 { 48 namespace Functional 49 { 50 51 using std::vector; 52 using std::string; 53 using tcu::TestLog; 54 using namespace gls::TextureTestUtil; 55 using namespace glu::TextureTestUtil; 56 57 static const char* getFaceDesc (const tcu::CubeFace face) 58 { 59 switch (face) 60 { 61 case tcu::CUBEFACE_NEGATIVE_X: return "-X"; 62 case tcu::CUBEFACE_POSITIVE_X: return "+X"; 63 case tcu::CUBEFACE_NEGATIVE_Y: return "-Y"; 64 case tcu::CUBEFACE_POSITIVE_Y: return "+Y"; 65 case tcu::CUBEFACE_NEGATIVE_Z: return "-Z"; 66 case tcu::CUBEFACE_POSITIVE_Z: return "+Z"; 67 default: 68 DE_ASSERT(false); 69 return DE_NULL; 70 } 71 } 72 73 static void logCubeArrayTexCoords(TestLog& log, vector<float>& texCoord) 74 { 75 const size_t numVerts = texCoord.size() / 4; 76 77 DE_ASSERT(texCoord.size() % 4 == 0); 78 79 for (size_t vertNdx = 0; vertNdx < numVerts; vertNdx++) 80 { 81 const size_t coordNdx = vertNdx * 4; 82 83 const float u = texCoord[coordNdx + 0]; 84 const float v = texCoord[coordNdx + 1]; 85 const float w = texCoord[coordNdx + 2]; 86 const float q = texCoord[coordNdx + 3]; 87 88 log << TestLog::Message 89 << vertNdx << ": (" 90 << u << ", " 91 << v << ", " 92 << w << ", " 93 << q << ")" 94 << TestLog::EndMessage; 95 } 96 } 97 98 // Cube map array filtering 99 100 class TextureCubeArrayFilteringCase : public TestCase 101 { 102 public: 103 TextureCubeArrayFilteringCase (Context& context, 104 const char* name, 105 const char* desc, 106 deUint32 minFilter, 107 deUint32 magFilter, 108 deUint32 wrapS, 109 deUint32 wrapT, 110 deUint32 internalFormat, 111 int size, 112 int depth, 113 bool onlySampleFaceInterior = false); 114 115 ~TextureCubeArrayFilteringCase (void); 116 117 void init (void); 118 void deinit (void); 119 IterateResult iterate (void); 120 121 private: 122 TextureCubeArrayFilteringCase (const TextureCubeArrayFilteringCase&); 123 TextureCubeArrayFilteringCase& operator= (const TextureCubeArrayFilteringCase&); 124 125 const deUint32 m_minFilter; 126 const deUint32 m_magFilter; 127 const deUint32 m_wrapS; 128 const deUint32 m_wrapT; 129 130 const deUint32 m_internalFormat; 131 const int m_size; 132 const int m_depth; 133 134 const bool m_onlySampleFaceInterior; //!< If true, we avoid sampling anywhere near a face's edges. 135 136 struct FilterCase 137 { 138 const glu::TextureCubeArray* texture; 139 tcu::Vec2 bottomLeft; 140 tcu::Vec2 topRight; 141 tcu::Vec2 layerRange; 142 143 FilterCase (void) 144 : texture(DE_NULL) 145 { 146 } 147 148 FilterCase (const glu::TextureCubeArray* tex_, const tcu::Vec2& bottomLeft_, const tcu::Vec2& topRight_, const tcu::Vec2& layerRange_) 149 : texture (tex_) 150 , bottomLeft (bottomLeft_) 151 , topRight (topRight_) 152 , layerRange (layerRange_) 153 { 154 } 155 }; 156 157 glu::TextureCubeArray* m_gradientTex; 158 glu::TextureCubeArray* m_gridTex; 159 160 TextureRenderer m_renderer; 161 162 std::vector<FilterCase> m_cases; 163 int m_caseNdx; 164 }; 165 166 TextureCubeArrayFilteringCase::TextureCubeArrayFilteringCase (Context& context, 167 const char* name, 168 const char* desc, 169 deUint32 minFilter, 170 deUint32 magFilter, 171 deUint32 wrapS, 172 deUint32 wrapT, 173 deUint32 internalFormat, 174 int size, 175 int depth, 176 bool onlySampleFaceInterior) 177 : TestCase (context, name, desc) 178 , m_minFilter (minFilter) 179 , m_magFilter (magFilter) 180 , m_wrapS (wrapS) 181 , m_wrapT (wrapT) 182 , m_internalFormat (internalFormat) 183 , m_size (size) 184 , m_depth (depth) 185 , m_onlySampleFaceInterior (onlySampleFaceInterior) 186 , m_gradientTex (DE_NULL) 187 , m_gridTex (DE_NULL) 188 , m_renderer (context.getRenderContext(), context.getTestContext().getLog(), glu::GLSL_VERSION_310_ES, glu::PRECISION_HIGHP) 189 , m_caseNdx (0) 190 { 191 } 192 193 TextureCubeArrayFilteringCase::~TextureCubeArrayFilteringCase (void) 194 { 195 TextureCubeArrayFilteringCase::deinit(); 196 } 197 198 void TextureCubeArrayFilteringCase::init (void) 199 { 200 if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_texture_cube_map_array")) 201 throw tcu::NotSupportedError("GL_EXT_texture_cube_map_array not supported"); 202 203 try 204 { 205 const tcu::TextureFormat texFmt = glu::mapGLInternalFormat(m_internalFormat); 206 const tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(texFmt); 207 const tcu::Vec4 cScale = fmtInfo.valueMax-fmtInfo.valueMin; 208 const tcu::Vec4 cBias = fmtInfo.valueMin; 209 const int numLevels = deLog2Floor32(m_size) + 1; 210 const int numLayers = m_depth / 6; 211 212 // Create textures. 213 m_gradientTex = new glu::TextureCubeArray(m_context.getRenderContext(), m_internalFormat, m_size, m_depth); 214 m_gridTex = new glu::TextureCubeArray(m_context.getRenderContext(), m_internalFormat, m_size, m_depth); 215 216 const tcu::IVec4 levelSwz[] = 217 { 218 tcu::IVec4(0,1,2,3), 219 tcu::IVec4(2,1,3,0), 220 tcu::IVec4(3,0,1,2), 221 tcu::IVec4(1,3,2,0), 222 }; 223 224 // Fill first gradient texture (gradient direction varies between layers). 225 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++) 226 { 227 m_gradientTex->getRefTexture().allocLevel(levelNdx); 228 229 const tcu::PixelBufferAccess levelBuf = m_gradientTex->getRefTexture().getLevel(levelNdx); 230 231 for (int layerFaceNdx = 0; layerFaceNdx < m_depth; layerFaceNdx++) 232 { 233 const tcu::IVec4 swz = levelSwz[layerFaceNdx % DE_LENGTH_OF_ARRAY(levelSwz)]; 234 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; 235 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; 236 237 tcu::fillWithComponentGradients(tcu::getSubregion(levelBuf, 0, 0, layerFaceNdx, levelBuf.getWidth(), levelBuf.getHeight(), 1), gMin, gMax); 238 } 239 } 240 241 // Fill second with grid texture (each layer has unique colors). 242 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++) 243 { 244 m_gridTex->getRefTexture().allocLevel(levelNdx); 245 246 const tcu::PixelBufferAccess levelBuf = m_gridTex->getRefTexture().getLevel(levelNdx); 247 248 for (int layerFaceNdx = 0; layerFaceNdx < m_depth; layerFaceNdx++) 249 { 250 const deUint32 step = 0x00ffffff / (numLevels*m_depth - 1); 251 const deUint32 rgb = step * (levelNdx + layerFaceNdx*numLevels); 252 const deUint32 colorA = 0xff000000 | rgb; 253 const deUint32 colorB = 0xff000000 | ~rgb; 254 255 tcu::fillWithGrid(tcu::getSubregion(levelBuf, 0, 0, layerFaceNdx, levelBuf.getWidth(), levelBuf.getHeight(), 1), 256 4, tcu::RGBA(colorA).toVec()*cScale + cBias, tcu::RGBA(colorB).toVec()*cScale + cBias); 257 } 258 } 259 260 // Upload. 261 m_gradientTex->upload(); 262 m_gridTex->upload(); 263 264 // Test cases 265 { 266 const glu::TextureCubeArray* const tex0 = m_gradientTex; 267 const glu::TextureCubeArray* const tex1 = m_gridTex; 268 269 if (m_onlySampleFaceInterior) 270 { 271 m_cases.push_back(FilterCase(tex0, tcu::Vec2(-0.8f, -0.8f), tcu::Vec2(0.8f, 0.8f), tcu::Vec2(-0.5f, float(numLayers)+0.5f))); // minification 272 m_cases.push_back(FilterCase(tex0, tcu::Vec2(0.5f, 0.65f), tcu::Vec2(0.8f, 0.8f), tcu::Vec2(-0.5f, float(numLayers)+0.5f))); // magnification 273 m_cases.push_back(FilterCase(tex1, tcu::Vec2(-0.8f, -0.8f), tcu::Vec2(0.8f, 0.8f), tcu::Vec2(float(numLayers)+0.5f, -0.5f))); // minification 274 m_cases.push_back(FilterCase(tex1, tcu::Vec2(0.2f, 0.2f), tcu::Vec2(0.6f, 0.5f), tcu::Vec2(float(numLayers)+0.5f, -0.5f))); // magnification 275 } 276 else 277 { 278 const bool isSingleSample = (m_context.getRenderTarget().getNumSamples() == 0); 279 280 // minification - w/ tweak to avoid hitting triangle edges with a face switchpoint in multisample configs 281 if (isSingleSample) 282 m_cases.push_back(FilterCase(tex0, tcu::Vec2(-1.25f, -1.2f), tcu::Vec2(1.2f, 1.25f), tcu::Vec2(-0.5f, float(numLayers)+0.5f))); 283 else 284 m_cases.push_back(FilterCase(tex0, tcu::Vec2(-1.19f, -1.3f), tcu::Vec2(1.1f, 1.35f), tcu::Vec2(-0.5f, float(numLayers)+0.5f))); 285 286 m_cases.push_back(FilterCase(tex0, tcu::Vec2(0.8f, 0.8f), tcu::Vec2(1.25f, 1.20f), tcu::Vec2(-0.5f, float(numLayers)+0.5f))); // magnification 287 m_cases.push_back(FilterCase(tex1, tcu::Vec2(-1.19f, -1.3f), tcu::Vec2(1.1f, 1.35f), tcu::Vec2(float(numLayers)+0.5f, -0.5f))); // minification 288 m_cases.push_back(FilterCase(tex1, tcu::Vec2(-1.2f, -1.1f), tcu::Vec2(-0.8f, -0.8f), tcu::Vec2(float(numLayers)+0.5f, -0.5f))); // magnification 289 290 // Layer rounding - only in single-sample configs as multisample configs may produce smooth transition at the middle. 291 if (isSingleSample && (numLayers > 1)) 292 m_cases.push_back(FilterCase(tex0, tcu::Vec2(-2.0f, -1.5f ), tcu::Vec2(-0.1f, 0.9f), tcu::Vec2(1.50001f, 1.49999f))); 293 } 294 } 295 296 m_caseNdx = 0; 297 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 298 } 299 catch (...) 300 { 301 // Clean up to save memory. 302 TextureCubeArrayFilteringCase::deinit(); 303 throw; 304 } 305 } 306 307 void TextureCubeArrayFilteringCase::deinit (void) 308 { 309 delete m_gradientTex; 310 delete m_gridTex; 311 312 m_gradientTex = DE_NULL; 313 m_gridTex = DE_NULL; 314 315 m_renderer.clear(); 316 m_cases.clear(); 317 } 318 319 TextureCubeArrayFilteringCase::IterateResult TextureCubeArrayFilteringCase::iterate (void) 320 { 321 TestLog& log = m_testCtx.getLog(); 322 const glu::RenderContext& renderCtx = m_context.getRenderContext(); 323 const glw::Functions& gl = renderCtx.getFunctions(); 324 const int viewportSize = 28; 325 const deUint32 randomSeed = deStringHash(getName()) ^ deInt32Hash(m_caseNdx) ^ m_testCtx.getCommandLine().getBaseSeed(); 326 const RandomViewport viewport (m_context.getRenderTarget(), viewportSize, viewportSize, randomSeed); 327 const FilterCase& curCase = m_cases[m_caseNdx]; 328 const tcu::TextureFormat texFmt = curCase.texture->getRefTexture().getFormat(); 329 const tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(texFmt); 330 const tcu::ScopedLogSection section (m_testCtx.getLog(), string("Test") + de::toString(m_caseNdx), string("Test ") + de::toString(m_caseNdx)); 331 ReferenceParams refParams (TEXTURETYPE_CUBE_ARRAY); 332 333 if (viewport.width < viewportSize || viewport.height < viewportSize) 334 throw tcu::NotSupportedError("Render target too small", "", __FILE__, __LINE__); 335 336 // Params for reference computation. 337 refParams.sampler = glu::mapGLSampler(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, m_minFilter, m_magFilter); 338 refParams.sampler.seamlessCubeMap = true; 339 refParams.samplerType = getSamplerType(texFmt); 340 refParams.colorBias = fmtInfo.lookupBias; 341 refParams.colorScale = fmtInfo.lookupScale; 342 refParams.lodMode = LODMODE_EXACT; 343 344 gl.bindTexture (GL_TEXTURE_CUBE_MAP_ARRAY, curCase.texture->getGLTexture()); 345 gl.texParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_MIN_FILTER, m_minFilter); 346 gl.texParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_MAG_FILTER, m_magFilter); 347 gl.texParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_WRAP_S, m_wrapS); 348 gl.texParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_WRAP_T, m_wrapT); 349 350 gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height); 351 352 m_testCtx.getLog() << TestLog::Message << "Coordinates: " << curCase.bottomLeft << " -> " << curCase.topRight << TestLog::EndMessage; 353 354 for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; faceNdx++) 355 { 356 const tcu::CubeFace face = tcu::CubeFace(faceNdx); 357 tcu::Surface result (viewport.width, viewport.height); 358 vector<float> texCoord; 359 360 computeQuadTexCoordCubeArray(texCoord, face, curCase.bottomLeft, curCase.topRight, curCase.layerRange); 361 362 log << TestLog::Message << "Face " << getFaceDesc(face) << TestLog::EndMessage; 363 364 log << TestLog::Message << "Texture coordinates:" << TestLog::EndMessage; 365 366 logCubeArrayTexCoords(log, texCoord); 367 368 m_renderer.renderQuad(0, &texCoord[0], refParams); 369 GLU_EXPECT_NO_ERROR(gl.getError(), "Draw"); 370 371 glu::readPixels(renderCtx, viewport.x, viewport.y, result.getAccess()); 372 GLU_EXPECT_NO_ERROR(gl.getError(), "Read pixels"); 373 374 { 375 const bool isNearestOnly = m_minFilter == GL_NEAREST && m_magFilter == GL_NEAREST; 376 const tcu::PixelFormat pixelFormat = renderCtx.getRenderTarget().getPixelFormat(); 377 const tcu::IVec4 coordBits = tcu::IVec4(10); 378 const tcu::IVec4 colorBits = max(getBitsVec(pixelFormat) - (isNearestOnly ? 1 : 2), tcu::IVec4(0)); // 1 inaccurate bit if nearest only, 2 otherwise 379 tcu::LodPrecision lodPrecision; 380 tcu::LookupPrecision lookupPrecision; 381 382 lodPrecision.derivateBits = 10; 383 lodPrecision.lodBits = 5; 384 lookupPrecision.colorThreshold = tcu::computeFixedPointThreshold(colorBits) / refParams.colorScale; 385 lookupPrecision.coordBits = coordBits.toWidth<3>(); 386 lookupPrecision.uvwBits = tcu::IVec3(6); 387 lookupPrecision.colorMask = getCompareMask(pixelFormat); 388 389 const bool isHighQuality = verifyTextureResult(m_testCtx, result.getAccess(), curCase.texture->getRefTexture(), 390 &texCoord[0], refParams, lookupPrecision, coordBits, lodPrecision, pixelFormat); 391 392 if (!isHighQuality) 393 { 394 // Evaluate against lower precision requirements. 395 lodPrecision.lodBits = 4; 396 lookupPrecision.uvwBits = tcu::IVec3(4); 397 398 m_testCtx.getLog() << TestLog::Message << "Warning: Verification against high precision requirements failed, trying with lower requirements." << TestLog::EndMessage; 399 400 const bool isOk = verifyTextureResult(m_testCtx, result.getAccess(), curCase.texture->getRefTexture(), 401 &texCoord[0], refParams, lookupPrecision, coordBits, lodPrecision, pixelFormat); 402 403 if (!isOk) 404 { 405 m_testCtx.getLog() << TestLog::Message << "ERROR: Verification against low precision requirements failed, failing test case." << TestLog::EndMessage; 406 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed"); 407 } 408 else if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS) 409 m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, "Low-quality filtering result"); 410 } 411 } 412 } 413 414 m_caseNdx += 1; 415 return m_caseNdx < (int)m_cases.size() ? CONTINUE : STOP; 416 } 417 418 TextureFilteringTests::TextureFilteringTests (Context& context) 419 : TestCaseGroup(context, "filtering", "Texture Filtering Tests") 420 { 421 } 422 423 TextureFilteringTests::~TextureFilteringTests (void) 424 { 425 } 426 427 void TextureFilteringTests::init (void) 428 { 429 static const struct 430 { 431 const char* name; 432 deUint32 mode; 433 } wrapModes[] = 434 { 435 { "clamp", GL_CLAMP_TO_EDGE }, 436 { "repeat", GL_REPEAT }, 437 { "mirror", GL_MIRRORED_REPEAT } 438 }; 439 440 static const struct 441 { 442 const char* name; 443 deUint32 mode; 444 } minFilterModes[] = 445 { 446 { "nearest", GL_NEAREST }, 447 { "linear", GL_LINEAR }, 448 { "nearest_mipmap_nearest", GL_NEAREST_MIPMAP_NEAREST }, 449 { "linear_mipmap_nearest", GL_LINEAR_MIPMAP_NEAREST }, 450 { "nearest_mipmap_linear", GL_NEAREST_MIPMAP_LINEAR }, 451 { "linear_mipmap_linear", GL_LINEAR_MIPMAP_LINEAR } 452 }; 453 454 static const struct 455 { 456 const char* name; 457 deUint32 mode; 458 } magFilterModes[] = 459 { 460 { "nearest", GL_NEAREST }, 461 { "linear", GL_LINEAR } 462 }; 463 464 static const struct 465 { 466 int size; 467 int depth; 468 } sizesCubeArray[] = 469 { 470 { 8, 6 }, 471 { 64, 12 }, 472 { 128, 12 }, 473 { 7, 12 }, 474 { 63, 18 } 475 }; 476 477 static const struct 478 { 479 const char* name; 480 deUint32 format; 481 } filterableFormatsByType[] = 482 { 483 { "rgba16f", GL_RGBA16F }, 484 { "r11f_g11f_b10f", GL_R11F_G11F_B10F }, 485 { "rgb9_e5", GL_RGB9_E5 }, 486 { "rgba8", GL_RGBA8 }, 487 { "rgba8_snorm", GL_RGBA8_SNORM }, 488 { "rgb565", GL_RGB565 }, 489 { "rgba4", GL_RGBA4 }, 490 { "rgb5_a1", GL_RGB5_A1 }, 491 { "srgb8_alpha8", GL_SRGB8_ALPHA8 }, 492 { "rgb10_a2", GL_RGB10_A2 } 493 }; 494 495 // Cube map array texture filtering. 496 { 497 tcu::TestCaseGroup* const groupCubeArray = new tcu::TestCaseGroup(m_testCtx, "cube_array", "Cube Map Array Texture Filtering"); 498 addChild(groupCubeArray); 499 500 // Formats. 501 { 502 tcu::TestCaseGroup* const formatsGroup = new tcu::TestCaseGroup(m_testCtx, "formats", "Cube Map Array Texture Formats"); 503 groupCubeArray->addChild(formatsGroup); 504 505 for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(filterableFormatsByType); fmtNdx++) 506 { 507 for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++) 508 { 509 const deUint32 minFilter = minFilterModes[filterNdx].mode; 510 const char* filterName = minFilterModes[filterNdx].name; 511 const deUint32 format = filterableFormatsByType[fmtNdx].format; 512 const char* formatName = filterableFormatsByType[fmtNdx].name; 513 const bool isMipmap = minFilter != GL_NEAREST && minFilter != GL_LINEAR; 514 const deUint32 magFilter = isMipmap ? GL_LINEAR : minFilter; 515 const string name = string(formatName) + "_" + filterName; 516 const deUint32 wrapS = GL_REPEAT; 517 const deUint32 wrapT = GL_REPEAT; 518 const int size = 64; 519 const int depth = 12; 520 521 formatsGroup->addChild(new TextureCubeArrayFilteringCase(m_context, 522 name.c_str(), "", 523 minFilter, magFilter, 524 wrapS, wrapT, 525 format, 526 size, depth)); 527 } 528 } 529 } 530 531 // Sizes. 532 { 533 tcu::TestCaseGroup* const sizesGroup = new tcu::TestCaseGroup(m_testCtx, "sizes", "Texture Sizes"); 534 groupCubeArray->addChild(sizesGroup); 535 536 for (int sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(sizesCubeArray); sizeNdx++) 537 { 538 for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++) 539 { 540 const deUint32 minFilter = minFilterModes[filterNdx].mode; 541 const char* filterName = minFilterModes[filterNdx].name; 542 const deUint32 format = GL_RGBA8; 543 const bool isMipmap = minFilter != GL_NEAREST && minFilter != GL_LINEAR; 544 const deUint32 magFilter = isMipmap ? GL_LINEAR : minFilter; 545 const deUint32 wrapS = GL_REPEAT; 546 const deUint32 wrapT = GL_REPEAT; 547 const int size = sizesCubeArray[sizeNdx].size; 548 const int depth = sizesCubeArray[sizeNdx].depth; 549 const string name = de::toString(size) + "x" + de::toString(size) + "x" + de::toString(depth) + "_" + filterName; 550 551 sizesGroup->addChild(new TextureCubeArrayFilteringCase(m_context, 552 name.c_str(), "", 553 minFilter, magFilter, 554 wrapS, wrapT, 555 format, 556 size, depth)); 557 } 558 } 559 } 560 561 // Wrap modes. 562 { 563 tcu::TestCaseGroup* const combinationsGroup = new tcu::TestCaseGroup(m_testCtx, "combinations", "Filter and wrap mode combinations"); 564 groupCubeArray->addChild(combinationsGroup); 565 566 for (int minFilterNdx = 0; minFilterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); minFilterNdx++) 567 { 568 for (int magFilterNdx = 0; magFilterNdx < DE_LENGTH_OF_ARRAY(magFilterModes); magFilterNdx++) 569 { 570 for (int wrapSNdx = 0; wrapSNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapSNdx++) 571 { 572 for (int wrapTNdx = 0; wrapTNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapTNdx++) 573 { 574 const deUint32 minFilter = minFilterModes[minFilterNdx].mode; 575 const deUint32 magFilter = magFilterModes[magFilterNdx].mode; 576 const deUint32 format = GL_RGBA8; 577 const deUint32 wrapS = wrapModes[wrapSNdx].mode; 578 const deUint32 wrapT = wrapModes[wrapTNdx].mode; 579 const int size = 63; 580 const int depth = 12; 581 const string name = string(minFilterModes[minFilterNdx].name) + "_" + magFilterModes[magFilterNdx].name + "_" + wrapModes[wrapSNdx].name + "_" + wrapModes[wrapTNdx].name; 582 583 combinationsGroup->addChild(new TextureCubeArrayFilteringCase(m_context, 584 name.c_str(), "", 585 minFilter, magFilter, 586 wrapS, wrapT, 587 format, 588 size, depth)); 589 } 590 } 591 } 592 } 593 } 594 595 // Cases with no visible cube edges. 596 { 597 tcu::TestCaseGroup* const onlyFaceInteriorGroup = new tcu::TestCaseGroup(m_testCtx, "no_edges_visible", "Don't sample anywhere near a face's edges"); 598 groupCubeArray->addChild(onlyFaceInteriorGroup); 599 600 for (int isLinearI = 0; isLinearI <= 1; isLinearI++) 601 { 602 const bool isLinear = isLinearI != 0; 603 const deUint32 filter = isLinear ? GL_LINEAR : GL_NEAREST; 604 605 onlyFaceInteriorGroup->addChild(new TextureCubeArrayFilteringCase(m_context, 606 isLinear ? "linear" : "nearest", "", 607 filter, filter, 608 GL_REPEAT, GL_REPEAT, 609 GL_RGBA8, 610 63, 12, 611 true)); 612 } 613 } 614 } 615 } 616 617 } // Functional 618 } // gles31 619 } // deqp 620