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