1/*------------------------------------------------------------------------- 2 * drawElements Quality Program OpenGL ES 2.0 Module 3 * ------------------------------------------------- 4 * 5 * Copyright 2014 The Android Open Source Project 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 * 19 *//*! 20 * \file 21 * \brief Texture filtering accuracy tests. 22 *//*--------------------------------------------------------------------*/ 23 24#include "es2aTextureFilteringTests.hpp" 25#include "glsTextureTestUtil.hpp" 26#include "gluTexture.hpp" 27#include "gluStrUtil.hpp" 28#include "gluTextureUtil.hpp" 29#include "gluPixelTransfer.hpp" 30#include "tcuSurfaceAccess.hpp" 31#include "tcuTestLog.hpp" 32#include "tcuTextureUtil.hpp" 33#include "deStringUtil.hpp" 34 35#include "glwFunctions.hpp" 36#include "glwEnums.hpp" 37 38using std::string; 39 40namespace deqp 41{ 42namespace gles2 43{ 44namespace Accuracy 45{ 46 47using tcu::TestLog; 48using std::vector; 49using std::string; 50using tcu::Sampler; 51using namespace glu; 52using namespace gls::TextureTestUtil; 53using namespace glu::TextureTestUtil; 54 55class Texture2DFilteringCase : public tcu::TestCase 56{ 57public: 58 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 format, deUint32 dataType, int width, int height); 59 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); 60 ~Texture2DFilteringCase (void); 61 62 void init (void); 63 void deinit (void); 64 IterateResult iterate (void); 65 66private: 67 Texture2DFilteringCase (const Texture2DFilteringCase& other); 68 Texture2DFilteringCase& operator= (const Texture2DFilteringCase& other); 69 70 glu::RenderContext& m_renderCtx; 71 const glu::ContextInfo& m_renderCtxInfo; 72 73 deUint32 m_minFilter; 74 deUint32 m_magFilter; 75 deUint32 m_wrapS; 76 deUint32 m_wrapT; 77 78 deUint32 m_format; 79 deUint32 m_dataType; 80 int m_width; 81 int m_height; 82 83 std::vector<std::string> m_filenames; 84 85 std::vector<glu::Texture2D*> m_textures; 86 TextureRenderer m_renderer; 87}; 88 89 90Texture2DFilteringCase::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 format, deUint32 dataType, int width, int height) 91 : TestCase (testCtx, tcu::NODETYPE_ACCURACY, name, desc) 92 , m_renderCtx (renderCtx) 93 , m_renderCtxInfo (ctxInfo) 94 , m_minFilter (minFilter) 95 , m_magFilter (magFilter) 96 , m_wrapS (wrapS) 97 , m_wrapT (wrapT) 98 , m_format (format) 99 , m_dataType (dataType) 100 , m_width (width) 101 , m_height (height) 102 , m_renderer (renderCtx, testCtx.getLog(), glu::GLSL_VERSION_100_ES, glu::PRECISION_MEDIUMP) 103{ 104} 105 106Texture2DFilteringCase::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) 107 : TestCase (testCtx, tcu::NODETYPE_ACCURACY, name, desc) 108 , m_renderCtx (renderCtx) 109 , m_renderCtxInfo (ctxInfo) 110 , m_minFilter (minFilter) 111 , m_magFilter (magFilter) 112 , m_wrapS (wrapS) 113 , m_wrapT (wrapT) 114 , m_format (GL_NONE) 115 , m_dataType (GL_NONE) 116 , m_width (0) 117 , m_height (0) 118 , m_filenames (filenames) 119 , m_renderer (renderCtx, testCtx.getLog(), glu::GLSL_VERSION_100_ES, glu::PRECISION_MEDIUMP) 120{ 121} 122 123Texture2DFilteringCase::~Texture2DFilteringCase (void) 124{ 125 deinit(); 126} 127 128void Texture2DFilteringCase::init (void) 129{ 130 try 131 { 132 if (!m_filenames.empty()) 133 { 134 m_textures.reserve(1); 135 m_textures.push_back(glu::Texture2D::create(m_renderCtx, m_renderCtxInfo, m_testCtx.getArchive(), (int)m_filenames.size(), m_filenames)); 136 } 137 else 138 { 139 // Create 2 textures. 140 m_textures.reserve(2); 141 for (int ndx = 0; ndx < 2; ndx++) 142 m_textures.push_back(new glu::Texture2D(m_renderCtx, m_format, m_dataType, m_width, m_height)); 143 144 const bool mipmaps = deIsPowerOfTwo32(m_width) && deIsPowerOfTwo32(m_height); 145 const int numLevels = mipmaps ? deLog2Floor32(de::max(m_width, m_height))+1 : 1; 146 tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(m_textures[0]->getRefTexture().getFormat()); 147 tcu::Vec4 cBias = fmtInfo.valueMin; 148 tcu::Vec4 cScale = fmtInfo.valueMax-fmtInfo.valueMin; 149 150 // Fill first gradient texture. 151 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++) 152 { 153 tcu::Vec4 gMin = tcu::Vec4(-0.5f, -0.5f, -0.5f, 2.0f)*cScale + cBias; 154 tcu::Vec4 gMax = tcu::Vec4( 1.0f, 1.0f, 1.0f, 0.0f)*cScale + cBias; 155 156 m_textures[0]->getRefTexture().allocLevel(levelNdx); 157 tcu::fillWithComponentGradients(m_textures[0]->getRefTexture().getLevel(levelNdx), gMin, gMax); 158 } 159 160 // Fill second with grid texture. 161 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++) 162 { 163 deUint32 step = 0x00ffffff / numLevels; 164 deUint32 rgb = step*levelNdx; 165 deUint32 colorA = 0xff000000 | rgb; 166 deUint32 colorB = 0xff000000 | ~rgb; 167 168 m_textures[1]->getRefTexture().allocLevel(levelNdx); 169 tcu::fillWithGrid(m_textures[1]->getRefTexture().getLevel(levelNdx), 4, tcu::RGBA(colorA).toVec()*cScale + cBias, tcu::RGBA(colorB).toVec()*cScale + cBias); 170 } 171 172 // Upload. 173 for (std::vector<glu::Texture2D*>::iterator i = m_textures.begin(); i != m_textures.end(); i++) 174 (*i)->upload(); 175 } 176 } 177 catch (...) 178 { 179 // Clean up to save memory. 180 Texture2DFilteringCase::deinit(); 181 throw; 182 } 183} 184 185void Texture2DFilteringCase::deinit (void) 186{ 187 for (std::vector<glu::Texture2D*>::iterator i = m_textures.begin(); i != m_textures.end(); i++) 188 delete *i; 189 m_textures.clear(); 190 191 m_renderer.clear(); 192} 193 194Texture2DFilteringCase::IterateResult Texture2DFilteringCase::iterate (void) 195{ 196 const glw::Functions& gl = m_renderCtx.getFunctions(); 197 TestLog& log = m_testCtx.getLog(); 198 const int defViewportWidth = 256; 199 const int defViewportHeight = 256; 200 RandomViewport viewport (m_renderCtx.getRenderTarget(), defViewportWidth, defViewportHeight, deStringHash(getName())); 201 tcu::Surface renderedFrame (viewport.width, viewport.height); 202 tcu::Surface referenceFrame (viewport.width, viewport.height); 203 const tcu::TextureFormat& texFmt = m_textures[0]->getRefTexture().getFormat(); 204 tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(texFmt); 205 ReferenceParams refParams (TEXTURETYPE_2D); 206 vector<float> texCoord; 207 208 // Accuracy measurements are off unless viewport size is 256x256 209 if (viewport.width < defViewportWidth || viewport.height < defViewportHeight) 210 throw tcu::NotSupportedError("Too small viewport", "", __FILE__, __LINE__); 211 212 // Viewport is divided into 4 sections. 213 int leftWidth = viewport.width / 2; 214 int rightWidth = viewport.width - leftWidth; 215 int bottomHeight = viewport.height / 2; 216 int topHeight = viewport.height - bottomHeight; 217 218 int curTexNdx = 0; 219 220 // Use unit 0. 221 gl.activeTexture(GL_TEXTURE0); 222 223 // Bind gradient texture and setup sampler parameters. 224 gl.bindTexture(GL_TEXTURE_2D, m_textures[curTexNdx]->getGLTexture()); 225 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, m_wrapS); 226 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, m_wrapT); 227 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_minFilter); 228 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, m_magFilter); 229 230 // Setup params for reference. 231 refParams.sampler = mapGLSampler(m_wrapS, m_wrapT, m_minFilter, m_magFilter); 232 refParams.samplerType = getSamplerType(texFmt); 233 refParams.lodMode = LODMODE_EXACT; 234 refParams.colorBias = fmtInfo.lookupBias; 235 refParams.colorScale = fmtInfo.lookupScale; 236 237 // Bottom left: Minification 238 { 239 gl.viewport(viewport.x, viewport.y, leftWidth, bottomHeight); 240 241 computeQuadTexCoord2D(texCoord, tcu::Vec2(-4.0f, -4.5f), tcu::Vec2(4.0f, 2.5f)); 242 243 m_renderer.renderQuad(0, &texCoord[0], refParams); 244 sampleTexture(tcu::SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), 0, 0, leftWidth, bottomHeight), 245 m_textures[curTexNdx]->getRefTexture(), &texCoord[0], refParams); 246 } 247 248 // Bottom right: Magnification 249 { 250 gl.viewport(viewport.x+leftWidth, viewport.y, rightWidth, bottomHeight); 251 252 computeQuadTexCoord2D(texCoord, tcu::Vec2(-0.5f, 0.75f), tcu::Vec2(0.25f, 1.25f)); 253 254 m_renderer.renderQuad(0, &texCoord[0], refParams); 255 sampleTexture(tcu::SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), leftWidth, 0, rightWidth, bottomHeight), 256 m_textures[curTexNdx]->getRefTexture(), &texCoord[0], refParams); 257 } 258 259 if (m_textures.size() >= 2) 260 { 261 curTexNdx += 1; 262 263 // Setup second texture. 264 gl.bindTexture(GL_TEXTURE_2D, m_textures[curTexNdx]->getGLTexture()); 265 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, m_wrapS); 266 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, m_wrapT); 267 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_minFilter); 268 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, m_magFilter); 269 } 270 271 // Top left: Minification 272 // \note Minification is chosen so that 0.0 < lod <= 0.5. This way special minification threshold rule will be triggered. 273 { 274 gl.viewport(viewport.x, viewport.y+bottomHeight, leftWidth, topHeight); 275 276 float sMin = -0.5f; 277 float tMin = -0.2f; 278 float sRange = ((float)leftWidth * 1.2f) / (float)m_textures[curTexNdx]->getRefTexture().getWidth(); 279 float tRange = ((float)topHeight * 1.1f) / (float)m_textures[curTexNdx]->getRefTexture().getHeight(); 280 281 computeQuadTexCoord2D(texCoord, tcu::Vec2(sMin, tMin), tcu::Vec2(sMin+sRange, tMin+tRange)); 282 283 m_renderer.renderQuad(0, &texCoord[0], refParams); 284 sampleTexture(tcu::SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), 0, bottomHeight, leftWidth, topHeight), 285 m_textures[curTexNdx]->getRefTexture(), &texCoord[0], refParams); 286 } 287 288 // Top right: Magnification 289 { 290 gl.viewport(viewport.x+leftWidth, viewport.y+bottomHeight, rightWidth, topHeight); 291 292 computeQuadTexCoord2D(texCoord, tcu::Vec2(-0.5f, 0.75f), tcu::Vec2(0.25f, 1.25f)); 293 294 m_renderer.renderQuad(0, &texCoord[0], refParams); 295 sampleTexture(tcu::SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), leftWidth, bottomHeight, rightWidth, topHeight), 296 m_textures[curTexNdx]->getRefTexture(), &texCoord[0], refParams); 297 } 298 299 // Read result. 300 glu::readPixels(m_renderCtx, viewport.x, viewport.y, renderedFrame.getAccess()); 301 302 // Compare and log. 303 { 304 DE_ASSERT(getNodeType() == tcu::NODETYPE_ACCURACY); 305 306 const int bestScoreDiff = 16; 307 const int worstScoreDiff = 3200; 308 309 int score = measureAccuracy(log, referenceFrame, renderedFrame, bestScoreDiff, worstScoreDiff); 310 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, de::toString(score).c_str()); 311 } 312 313 return STOP; 314} 315 316class TextureCubeFilteringCase : public tcu::TestCase 317{ 318public: 319 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, deUint32 format, deUint32 dataType, int width, int height); 320 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, const std::vector<std::string>& filenames); 321 ~TextureCubeFilteringCase (void); 322 323 void init (void); 324 void deinit (void); 325 IterateResult iterate (void); 326 327private: 328 TextureCubeFilteringCase (const TextureCubeFilteringCase& other); 329 TextureCubeFilteringCase& operator= (const TextureCubeFilteringCase& other); 330 331 glu::RenderContext& m_renderCtx; 332 const glu::ContextInfo& m_renderCtxInfo; 333 334 deUint32 m_minFilter; 335 deUint32 m_magFilter; 336 deUint32 m_wrapS; 337 deUint32 m_wrapT; 338 339 deUint32 m_format; 340 deUint32 m_dataType; 341 int m_width; 342 int m_height; 343 344 std::vector<std::string> m_filenames; 345 346 std::vector<glu::TextureCube*> m_textures; 347 TextureRenderer m_renderer; 348}; 349 350 351TextureCubeFilteringCase::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, deUint32 format, deUint32 dataType, int width, int height) 352 : TestCase (testCtx, tcu::NODETYPE_ACCURACY, name, desc) 353 , m_renderCtx (renderCtx) 354 , m_renderCtxInfo (ctxInfo) 355 , m_minFilter (minFilter) 356 , m_magFilter (magFilter) 357 , m_wrapS (wrapS) 358 , m_wrapT (wrapT) 359 , m_format (format) 360 , m_dataType (dataType) 361 , m_width (width) 362 , m_height (height) 363 , m_renderer (renderCtx, testCtx.getLog(), glu::GLSL_VERSION_100_ES, glu::PRECISION_MEDIUMP) 364{ 365} 366 367TextureCubeFilteringCase::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, const std::vector<std::string>& filenames) 368 : TestCase (testCtx, tcu::NODETYPE_ACCURACY, name, desc) 369 , m_renderCtx (renderCtx) 370 , m_renderCtxInfo (ctxInfo) 371 , m_minFilter (minFilter) 372 , m_magFilter (magFilter) 373 , m_wrapS (wrapS) 374 , m_wrapT (wrapT) 375 , m_format (GL_NONE) 376 , m_dataType (GL_NONE) 377 , m_width (0) 378 , m_height (0) 379 , m_filenames (filenames) 380 , m_renderer (renderCtx, testCtx.getLog(), glu::GLSL_VERSION_100_ES, glu::PRECISION_MEDIUMP) 381{ 382} 383 384TextureCubeFilteringCase::~TextureCubeFilteringCase (void) 385{ 386 deinit(); 387} 388 389void TextureCubeFilteringCase::init (void) 390{ 391 try 392 { 393 if (!m_filenames.empty()) 394 { 395 m_textures.reserve(1); 396 m_textures.push_back(glu::TextureCube::create(m_renderCtx, m_renderCtxInfo, m_testCtx.getArchive(), (int)m_filenames.size() / 6, m_filenames)); 397 } 398 else 399 { 400 m_textures.reserve(2); 401 DE_ASSERT(m_width == m_height); 402 for (int ndx = 0; ndx < 2; ndx++) 403 m_textures.push_back(new glu::TextureCube(m_renderCtx, m_format, m_dataType, m_width)); 404 405 const bool mipmaps = deIsPowerOfTwo32(m_width) && deIsPowerOfTwo32(m_height); 406 const int numLevels = mipmaps ? deLog2Floor32(de::max(m_width, m_height))+1 : 1; 407 tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(m_textures[0]->getRefTexture().getFormat()); 408 tcu::Vec4 cBias = fmtInfo.valueMin; 409 tcu::Vec4 cScale = fmtInfo.valueMax-fmtInfo.valueMin; 410 411 // Fill first with gradient texture. 412 static const tcu::Vec4 gradients[tcu::CUBEFACE_LAST][2] = 413 { 414 { tcu::Vec4(-1.0f, -1.0f, -1.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // negative x 415 { tcu::Vec4( 0.0f, -1.0f, -1.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // positive x 416 { tcu::Vec4(-1.0f, 0.0f, -1.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // negative y 417 { tcu::Vec4(-1.0f, -1.0f, 0.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // positive y 418 { tcu::Vec4(-1.0f, -1.0f, -1.0f, 0.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f) }, // negative z 419 { tcu::Vec4( 0.0f, 0.0f, 0.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) } // positive z 420 }; 421 for (int face = 0; face < tcu::CUBEFACE_LAST; face++) 422 { 423 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++) 424 { 425 m_textures[0]->getRefTexture().allocLevel((tcu::CubeFace)face, levelNdx); 426 tcu::fillWithComponentGradients(m_textures[0]->getRefTexture().getLevelFace(levelNdx, (tcu::CubeFace)face), gradients[face][0]*cScale + cBias, gradients[face][1]*cScale + cBias); 427 } 428 } 429 430 // Fill second with grid texture. 431 for (int face = 0; face < tcu::CUBEFACE_LAST; face++) 432 { 433 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++) 434 { 435 deUint32 step = 0x00ffffff / (numLevels*tcu::CUBEFACE_LAST); 436 deUint32 rgb = step*levelNdx*face; 437 deUint32 colorA = 0xff000000 | rgb; 438 deUint32 colorB = 0xff000000 | ~rgb; 439 440 m_textures[1]->getRefTexture().allocLevel((tcu::CubeFace)face, levelNdx); 441 tcu::fillWithGrid(m_textures[1]->getRefTexture().getLevelFace(levelNdx, (tcu::CubeFace)face), 4, tcu::RGBA(colorA).toVec()*cScale + cBias, tcu::RGBA(colorB).toVec()*cScale + cBias); 442 } 443 } 444 445 // Upload. 446 for (std::vector<glu::TextureCube*>::iterator i = m_textures.begin(); i != m_textures.end(); i++) 447 (*i)->upload(); 448 } 449 } 450 catch (const std::exception&) 451 { 452 // Clean up to save memory. 453 TextureCubeFilteringCase::deinit(); 454 throw; 455 } 456} 457 458void TextureCubeFilteringCase::deinit (void) 459{ 460 for (std::vector<glu::TextureCube*>::iterator i = m_textures.begin(); i != m_textures.end(); i++) 461 delete *i; 462 m_textures.clear(); 463 464 m_renderer.clear(); 465} 466 467static void renderFaces ( 468 const glw::Functions& gl, 469 const tcu::SurfaceAccess& dstRef, 470 const tcu::TextureCube& refTexture, 471 const ReferenceParams& params, 472 TextureRenderer& renderer, 473 int x, 474 int y, 475 int width, 476 int height, 477 const tcu::Vec2& bottomLeft, 478 const tcu::Vec2& topRight, 479 const tcu::Vec2& texCoordTopRightFactor) 480{ 481 DE_ASSERT(width == dstRef.getWidth() && height == dstRef.getHeight()); 482 483 vector<float> texCoord; 484 485 DE_STATIC_ASSERT(tcu::CUBEFACE_LAST == 6); 486 for (int face = 0; face < tcu::CUBEFACE_LAST; face++) 487 { 488 bool isRightmost = (face == 2) || (face == 5); 489 bool isTop = face >= 3; 490 int curX = (face % 3) * (width / 3); 491 int curY = (face / 3) * (height / 2); 492 int curW = isRightmost ? (width-curX) : (width / 3); 493 int curH = isTop ? (height-curY) : (height / 2); 494 495 computeQuadTexCoordCube(texCoord, (tcu::CubeFace)face, bottomLeft, topRight); 496 497 { 498 // Move the top and right edges of the texture coord quad. This is useful when we want a cube edge visible. 499 int texCoordSRow = face == tcu::CUBEFACE_NEGATIVE_X || face == tcu::CUBEFACE_POSITIVE_X ? 2 : 0; 500 int texCoordTRow = face == tcu::CUBEFACE_NEGATIVE_Y || face == tcu::CUBEFACE_POSITIVE_Y ? 2 : 1; 501 texCoord[6 + texCoordSRow] *= texCoordTopRightFactor.x(); 502 texCoord[9 + texCoordSRow] *= texCoordTopRightFactor.x(); 503 texCoord[3 + texCoordTRow] *= texCoordTopRightFactor.y(); 504 texCoord[9 + texCoordTRow] *= texCoordTopRightFactor.y(); 505 } 506 507 gl.viewport(x+curX, y+curY, curW, curH); 508 509 renderer.renderQuad(0, &texCoord[0], params); 510 511 sampleTexture(tcu::SurfaceAccess(dstRef, curX, curY, curW, curH), refTexture, &texCoord[0], params); 512 } 513 514 GLU_EXPECT_NO_ERROR(gl.getError(), "Post render"); 515} 516 517TextureCubeFilteringCase::IterateResult TextureCubeFilteringCase::iterate (void) 518{ 519 const glw::Functions& gl = m_renderCtx.getFunctions(); 520 TestLog& log = m_testCtx.getLog(); 521 const int cellSize = 28; 522 const int defViewportWidth = cellSize*6; 523 const int defViewportHeight = cellSize*4; 524 RandomViewport viewport (m_renderCtx.getRenderTarget(), cellSize*6, cellSize*4, deStringHash(getName())); 525 tcu::Surface renderedFrame (viewport.width, viewport.height); 526 tcu::Surface referenceFrame (viewport.width, viewport.height); 527 ReferenceParams sampleParams (TEXTURETYPE_CUBE); 528 const tcu::TextureFormat& texFmt = m_textures[0]->getRefTexture().getFormat(); 529 tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(texFmt); 530 531 // Accuracy measurements are off unless viewport size is exactly as expected. 532 if (viewport.width < defViewportWidth || viewport.height < defViewportHeight) 533 throw tcu::NotSupportedError("Too small viewport", "", __FILE__, __LINE__); 534 535 // Viewport is divided into 4 sections. 536 int leftWidth = viewport.width / 2; 537 int rightWidth = viewport.width - leftWidth; 538 int bottomHeight = viewport.height / 2; 539 int topHeight = viewport.height - bottomHeight; 540 541 int curTexNdx = 0; 542 543 // Sampling parameters. 544 sampleParams.sampler = mapGLSampler(m_wrapS, m_wrapT, m_minFilter, m_magFilter); 545 sampleParams.sampler.seamlessCubeMap = false; 546 sampleParams.samplerType = getSamplerType(texFmt); 547 sampleParams.colorBias = fmtInfo.lookupBias; 548 sampleParams.colorScale = fmtInfo.lookupScale; 549 sampleParams.lodMode = LODMODE_EXACT; 550 551 // Use unit 0. 552 gl.activeTexture(GL_TEXTURE0); 553 554 // Setup gradient texture. 555 gl.bindTexture(GL_TEXTURE_CUBE_MAP, m_textures[curTexNdx]->getGLTexture()); 556 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, m_wrapS); 557 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, m_wrapT); 558 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, m_minFilter); 559 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, m_magFilter); 560 561 // Bottom left: Minification 562 renderFaces(gl, 563 tcu::SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), 0, 0, leftWidth, bottomHeight), 564 m_textures[curTexNdx]->getRefTexture(), sampleParams, 565 m_renderer, 566 viewport.x, viewport.y, leftWidth, bottomHeight, 567 tcu::Vec2(-0.81f, -0.81f), 568 tcu::Vec2( 0.8f, 0.8f), 569 tcu::Vec2(1.0f, 1.0f)); 570 571 // Bottom right: Magnification 572 renderFaces(gl, 573 tcu::SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), leftWidth, 0, rightWidth, bottomHeight), 574 m_textures[curTexNdx]->getRefTexture(), sampleParams, 575 m_renderer, 576 viewport.x+leftWidth, viewport.y, rightWidth, bottomHeight, 577 tcu::Vec2(0.5f, 0.65f), tcu::Vec2(0.8f, 0.8f), 578 tcu::Vec2(1.0f, 1.0f)); 579 580 if (m_textures.size() >= 2) 581 { 582 curTexNdx += 1; 583 584 // Setup second texture. 585 gl.bindTexture(GL_TEXTURE_CUBE_MAP, m_textures[curTexNdx]->getGLTexture()); 586 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, m_wrapS); 587 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, m_wrapT); 588 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, m_minFilter); 589 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, m_magFilter); 590 } 591 592 // Top left: Minification 593 renderFaces(gl, 594 tcu::SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), 0, bottomHeight, leftWidth, topHeight), 595 m_textures[curTexNdx]->getRefTexture(), sampleParams, 596 m_renderer, 597 viewport.x, viewport.y+bottomHeight, leftWidth, topHeight, 598 tcu::Vec2(-0.81f, -0.81f), 599 tcu::Vec2( 0.8f, 0.8f), 600 tcu::Vec2(1.0f, 1.0f)); 601 602 // Top right: Magnification 603 renderFaces(gl, 604 tcu::SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), leftWidth, bottomHeight, rightWidth, topHeight), 605 m_textures[curTexNdx]->getRefTexture(), sampleParams, 606 m_renderer, 607 viewport.x+leftWidth, viewport.y+bottomHeight, rightWidth, topHeight, 608 tcu::Vec2(0.5f, -0.65f), tcu::Vec2(0.8f, -0.8f), 609 tcu::Vec2(1.0f, 1.0f)); 610 611 // Read result. 612 glu::readPixels(m_renderCtx, viewport.x, viewport.y, renderedFrame.getAccess()); 613 614 // Compare and log. 615 { 616 DE_ASSERT(getNodeType() == tcu::NODETYPE_ACCURACY); 617 618 const int bestScoreDiff = 16; 619 const int worstScoreDiff = 10000; 620 621 int score = measureAccuracy(log, referenceFrame, renderedFrame, bestScoreDiff, worstScoreDiff); 622 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, de::toString(score).c_str()); 623 } 624 625 return STOP; 626} 627 628TextureFilteringTests::TextureFilteringTests (Context& context) 629 : TestCaseGroup(context, "filter", "Texture Filtering Accuracy Tests") 630{ 631} 632 633TextureFilteringTests::~TextureFilteringTests (void) 634{ 635} 636 637void TextureFilteringTests::init (void) 638{ 639 tcu::TestCaseGroup* group2D = new tcu::TestCaseGroup(m_testCtx, "2d", "2D Texture Filtering"); 640 tcu::TestCaseGroup* groupCube = new tcu::TestCaseGroup(m_testCtx, "cube", "Cube Map Filtering"); 641 addChild(group2D); 642 addChild(groupCube); 643 644 static const struct 645 { 646 const char* name; 647 deUint32 mode; 648 } wrapModes[] = 649 { 650 { "clamp", GL_CLAMP_TO_EDGE }, 651 { "repeat", GL_REPEAT }, 652 { "mirror", GL_MIRRORED_REPEAT } 653 }; 654 655 static const struct 656 { 657 const char* name; 658 deUint32 mode; 659 } minFilterModes[] = 660 { 661 { "nearest", GL_NEAREST }, 662 { "linear", GL_LINEAR }, 663 { "nearest_mipmap_nearest", GL_NEAREST_MIPMAP_NEAREST }, 664 { "linear_mipmap_nearest", GL_LINEAR_MIPMAP_NEAREST }, 665 { "nearest_mipmap_linear", GL_NEAREST_MIPMAP_LINEAR }, 666 { "linear_mipmap_linear", GL_LINEAR_MIPMAP_LINEAR } 667 }; 668 669 static const struct 670 { 671 const char* name; 672 deUint32 mode; 673 } magFilterModes[] = 674 { 675 { "nearest", GL_NEAREST }, 676 { "linear", GL_LINEAR } 677 }; 678 679 static const struct 680 { 681 const char* name; 682 int width; 683 int height; 684 } sizes2D[] = 685 { 686 { "pot", 32, 64 }, 687 { "npot", 31, 55 } 688 }; 689 690 static const struct 691 { 692 const char* name; 693 int width; 694 int height; 695 } sizesCube[] = 696 { 697 { "pot", 64, 64 }, 698 { "npot", 63, 63 } 699 }; 700 701 static const struct 702 { 703 const char* name; 704 deUint32 format; 705 deUint32 dataType; 706 } formats[] = 707 { 708 { "rgba8888", GL_RGBA, GL_UNSIGNED_BYTE }, 709 { "rgba4444", GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4 } 710 }; 711 712#define FOR_EACH(ITERATOR, ARRAY, BODY) \ 713 for (int (ITERATOR) = 0; (ITERATOR) < DE_LENGTH_OF_ARRAY(ARRAY); (ITERATOR)++) \ 714 BODY 715 716 // 2D cases. 717 FOR_EACH(minFilter, minFilterModes, 718 FOR_EACH(magFilter, magFilterModes, 719 FOR_EACH(wrapMode, wrapModes, 720 FOR_EACH(format, formats, 721 FOR_EACH(size, sizes2D, 722 { 723 bool isMipmap = minFilterModes[minFilter].mode != GL_NEAREST && minFilterModes[minFilter].mode != GL_LINEAR; 724 bool isClamp = wrapModes[wrapMode].mode == GL_CLAMP_TO_EDGE; 725 bool isRepeat = wrapModes[wrapMode].mode == GL_REPEAT; 726 bool isMagNearest = magFilterModes[magFilter].mode == GL_NEAREST; 727 bool isPotSize = deIsPowerOfTwo32(sizes2D[size].width) && deIsPowerOfTwo32(sizes2D[size].height); 728 729 if ((isMipmap || !isClamp) && !isPotSize) 730 continue; // Not supported. 731 732 if ((format != 0) && !(!isMipmap || (isRepeat && isMagNearest))) 733 continue; // Skip. 734 735 string name = string("") + minFilterModes[minFilter].name + "_" + magFilterModes[magFilter].name + "_" + wrapModes[wrapMode].name + "_" + formats[format].name; 736 737 if (!isMipmap) 738 name += string("_") + sizes2D[size].name; 739 740 group2D->addChild(new Texture2DFilteringCase(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(), 741 name.c_str(), "", 742 minFilterModes[minFilter].mode, 743 magFilterModes[magFilter].mode, 744 wrapModes[wrapMode].mode, 745 wrapModes[wrapMode].mode, 746 formats[format].format, formats[format].dataType, 747 sizes2D[size].width, sizes2D[size].height)); 748 }))))); 749 750 // Cubemap cases. 751 FOR_EACH(minFilter, minFilterModes, 752 FOR_EACH(magFilter, magFilterModes, 753 FOR_EACH(wrapMode, wrapModes, 754 FOR_EACH(format, formats, 755 FOR_EACH(size, sizesCube, 756 { 757 bool isMipmap = minFilterModes[minFilter].mode != GL_NEAREST && minFilterModes[minFilter].mode != GL_LINEAR; 758 bool isClamp = wrapModes[wrapMode].mode == GL_CLAMP_TO_EDGE; 759 bool isRepeat = wrapModes[wrapMode].mode == GL_REPEAT; 760 bool isMagNearest = magFilterModes[magFilter].mode == GL_NEAREST; 761 bool isPotSize = deIsPowerOfTwo32(sizesCube[size].width) && deIsPowerOfTwo32(sizesCube[size].height); 762 763 if ((isMipmap || !isClamp) && !isPotSize) 764 continue; // Not supported. 765 766 if (format != 0 && !(!isMipmap || (isRepeat && isMagNearest))) 767 continue; // Skip. 768 769 string name = string("") + minFilterModes[minFilter].name + "_" + magFilterModes[magFilter].name + "_" + wrapModes[wrapMode].name + "_" + formats[format].name; 770 771 if (!isMipmap) 772 name += string("_") + sizesCube[size].name; 773 774 groupCube->addChild(new TextureCubeFilteringCase(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(), 775 name.c_str(), "", 776 minFilterModes[minFilter].mode, 777 magFilterModes[magFilter].mode, 778 wrapModes[wrapMode].mode, 779 wrapModes[wrapMode].mode, 780 formats[format].format, formats[format].dataType, 781 sizesCube[size].width, sizesCube[size].height)); 782 }))))); 783} 784 785} // Accuracy 786} // gles2 787} // deqp 788