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