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.getLog(), 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.getLog(), 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.getLog(), 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.getLog(), 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{ 489 DE_ASSERT(width == dstRef.getWidth() && height == dstRef.getHeight()); 490 491 vector<float> texCoord; 492 493 DE_STATIC_ASSERT(tcu::CUBEFACE_LAST == 6); 494 for (int face = 0; face < tcu::CUBEFACE_LAST; face++) 495 { 496 bool isRightmost = (face == 2) || (face == 5); 497 bool isTop = face >= 3; 498 int curX = (face % 3) * (width / 3); 499 int curY = (face / 3) * (height / 2); 500 int curW = isRightmost ? (width-curX) : (width / 3); 501 int curH = isTop ? (height-curY) : (height / 2); 502 503 computeQuadTexCoordCube(texCoord, (tcu::CubeFace)face, bottomLeft, topRight); 504 505 { 506 // Move the top and right edges of the texture coord quad. This is useful when we want a cube edge visible. 507 int texCoordSRow = face == tcu::CUBEFACE_NEGATIVE_X || face == tcu::CUBEFACE_POSITIVE_X ? 2 : 0; 508 int texCoordTRow = face == tcu::CUBEFACE_NEGATIVE_Y || face == tcu::CUBEFACE_POSITIVE_Y ? 2 : 1; 509 texCoord[6 + texCoordSRow] *= texCoordTopRightFactor.x(); 510 texCoord[9 + texCoordSRow] *= texCoordTopRightFactor.x(); 511 texCoord[3 + texCoordTRow] *= texCoordTopRightFactor.y(); 512 texCoord[9 + texCoordTRow] *= texCoordTopRightFactor.y(); 513 } 514 515 gl.viewport(x+curX, y+curY, curW, curH); 516 517 renderer.renderQuad(0, &texCoord[0], params); 518 519 sampleTexture(SurfaceAccess(dstRef, curX, curY, curW, curH), refTexture, &texCoord[0], params); 520 } 521 522 GLU_EXPECT_NO_ERROR(gl.getError(), "Post render"); 523} 524 525TextureCubeFilteringCase::IterateResult TextureCubeFilteringCase::iterate (void) 526{ 527 const glw::Functions& gl = m_renderCtx.getFunctions(); 528 TestLog& log = m_testCtx.getLog(); 529 const int cellSize = 28; 530 const int defViewportWidth = cellSize*6; 531 const int defViewportHeight = cellSize*4; 532 RandomViewport viewport (m_renderCtx.getRenderTarget(), cellSize*6, cellSize*4, deStringHash(getName())); 533 tcu::Surface renderedFrame (viewport.width, viewport.height); 534 tcu::Surface referenceFrame (viewport.width, viewport.height); 535 ReferenceParams sampleParams (TEXTURETYPE_CUBE); 536 const tcu::TextureFormat& texFmt = m_textures[0]->getRefTexture().getFormat(); 537 tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(texFmt); 538 539 // Accuracy measurements are off unless viewport size is exactly as expected. 540 if (getNodeType() == tcu::NODETYPE_ACCURACY && (viewport.width < defViewportWidth || viewport.height < defViewportHeight)) 541 throw tcu::NotSupportedError("Too small viewport", "", __FILE__, __LINE__); 542 543 // Viewport is divided into 4 sections. 544 int leftWidth = viewport.width / 2; 545 int rightWidth = viewport.width - leftWidth; 546 int bottomHeight = viewport.height / 2; 547 int topHeight = viewport.height - bottomHeight; 548 549 int curTexNdx = 0; 550 551 // Sampling parameters. 552 sampleParams.sampler = glu::mapGLSampler(m_wrapS, m_wrapT, m_minFilter, m_magFilter); 553 sampleParams.sampler.seamlessCubeMap = true; 554 sampleParams.samplerType = getSamplerType(texFmt); 555 sampleParams.colorBias = fmtInfo.lookupBias; 556 sampleParams.colorScale = fmtInfo.lookupScale; 557 sampleParams.lodMode = LODMODE_EXACT; 558 559 // Use unit 0. 560 gl.activeTexture(GL_TEXTURE0); 561 562 // Setup gradient texture. 563 gl.bindTexture(GL_TEXTURE_CUBE_MAP, m_textures[curTexNdx]->getGLTexture()); 564 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, m_wrapS); 565 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, m_wrapT); 566 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, m_minFilter); 567 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, m_magFilter); 568 569 // Bottom left: Minification 570 renderFaces(gl, 571 SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), 0, 0, leftWidth, bottomHeight), 572 m_textures[curTexNdx]->getRefTexture(), sampleParams, 573 m_renderer, 574 viewport.x, viewport.y, leftWidth, bottomHeight, 575 m_onlySampleFaceInterior ? tcu::Vec2(-0.81f, -0.81f) : tcu::Vec2(-0.975f, -0.975f), 576 m_onlySampleFaceInterior ? tcu::Vec2( 0.8f, 0.8f) : tcu::Vec2( 0.975f, 0.975f), 577 !m_onlySampleFaceInterior ? tcu::Vec2(1.3f, 1.25f) : tcu::Vec2(1.0f, 1.0f)); 578 579 // Bottom right: Magnification 580 renderFaces(gl, 581 SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), leftWidth, 0, rightWidth, bottomHeight), 582 m_textures[curTexNdx]->getRefTexture(), sampleParams, 583 m_renderer, 584 viewport.x+leftWidth, viewport.y, rightWidth, bottomHeight, 585 tcu::Vec2(0.5f, 0.65f), m_onlySampleFaceInterior ? tcu::Vec2(0.8f, 0.8f) : tcu::Vec2(0.975f, 0.975f), 586 !m_onlySampleFaceInterior ? tcu::Vec2(1.1f, 1.06f) : tcu::Vec2(1.0f, 1.0f)); 587 588 if (m_textures.size() >= 2) 589 { 590 curTexNdx += 1; 591 592 // Setup second texture. 593 gl.bindTexture(GL_TEXTURE_CUBE_MAP, m_textures[curTexNdx]->getGLTexture()); 594 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, m_wrapS); 595 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, m_wrapT); 596 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, m_minFilter); 597 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, m_magFilter); 598 } 599 600 // Top left: Minification 601 renderFaces(gl, 602 SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), 0, bottomHeight, leftWidth, topHeight), 603 m_textures[curTexNdx]->getRefTexture(), sampleParams, 604 m_renderer, 605 viewport.x, viewport.y+bottomHeight, leftWidth, topHeight, 606 m_onlySampleFaceInterior ? tcu::Vec2(-0.81f, -0.81f) : tcu::Vec2(-0.975f, -0.975f), 607 m_onlySampleFaceInterior ? tcu::Vec2( 0.8f, 0.8f) : tcu::Vec2( 0.975f, 0.975f), 608 !m_onlySampleFaceInterior ? tcu::Vec2(1.3f, 1.25f) : tcu::Vec2(1.0f, 1.0f)); 609 610 // Top right: Magnification 611 renderFaces(gl, 612 SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), leftWidth, bottomHeight, rightWidth, topHeight), 613 m_textures[curTexNdx]->getRefTexture(), sampleParams, 614 m_renderer, 615 viewport.x+leftWidth, viewport.y+bottomHeight, rightWidth, topHeight, 616 tcu::Vec2(0.5f, -0.65f), m_onlySampleFaceInterior ? tcu::Vec2(0.8f, -0.8f) : tcu::Vec2(0.975f, -0.975f), 617 !m_onlySampleFaceInterior ? tcu::Vec2(1.1f, 1.06f) : tcu::Vec2(1.0f, 1.0f)); 618 619 // Read result. 620 glu::readPixels(m_renderCtx, viewport.x, viewport.y, renderedFrame.getAccess()); 621 622 // Compare and log. 623 { 624 const int bestScoreDiff = 16; 625 const int worstScoreDiff = 10000; 626 627 int score = measureAccuracy(log, referenceFrame, renderedFrame, bestScoreDiff, worstScoreDiff); 628 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, de::toString(score).c_str()); 629 } 630 631 return STOP; 632} 633 634TextureFilteringTests::TextureFilteringTests (Context& context) 635 : TestCaseGroup(context, "filter", "Texture Filtering Accuracy Tests") 636{ 637} 638 639TextureFilteringTests::~TextureFilteringTests (void) 640{ 641} 642 643void TextureFilteringTests::init (void) 644{ 645 tcu::TestCaseGroup* group2D = new tcu::TestCaseGroup(m_testCtx, "2d", "2D Texture Filtering"); 646 tcu::TestCaseGroup* groupCube = new tcu::TestCaseGroup(m_testCtx, "cube", "Cube Map Filtering"); 647 addChild(group2D); 648 addChild(groupCube); 649 650 static const struct 651 { 652 const char* name; 653 deUint32 mode; 654 } wrapModes[] = 655 { 656 { "clamp", GL_CLAMP_TO_EDGE }, 657 { "repeat", GL_REPEAT }, 658 { "mirror", GL_MIRRORED_REPEAT } 659 }; 660 661 static const struct 662 { 663 const char* name; 664 deUint32 mode; 665 } minFilterModes[] = 666 { 667 { "nearest", GL_NEAREST }, 668 { "linear", GL_LINEAR }, 669 { "nearest_mipmap_nearest", GL_NEAREST_MIPMAP_NEAREST }, 670 { "linear_mipmap_nearest", GL_LINEAR_MIPMAP_NEAREST }, 671 { "nearest_mipmap_linear", GL_NEAREST_MIPMAP_LINEAR }, 672 { "linear_mipmap_linear", GL_LINEAR_MIPMAP_LINEAR } 673 }; 674 675 static const struct 676 { 677 const char* name; 678 deUint32 mode; 679 } magFilterModes[] = 680 { 681 { "nearest", GL_NEAREST }, 682 { "linear", GL_LINEAR } 683 }; 684 685 static const struct 686 { 687 const char* name; 688 int width; 689 int height; 690 } sizes2D[] = 691 { 692 { "pot", 32, 64 }, 693 { "npot", 31, 55 } 694 }; 695 696 static const struct 697 { 698 const char* name; 699 int width; 700 int height; 701 } sizesCube[] = 702 { 703 { "pot", 64, 64 }, 704 { "npot", 63, 63 } 705 }; 706 707 static const struct 708 { 709 const char* name; 710 deUint32 format; 711 } formats[] = 712 { 713 { "rgba8", GL_RGBA8 } 714 }; 715 716#define FOR_EACH(ITERATOR, ARRAY, BODY) \ 717 for (int ITERATOR = 0; ITERATOR < DE_LENGTH_OF_ARRAY(ARRAY); ITERATOR++) \ 718 BODY 719 720 // 2D cases. 721 FOR_EACH(minFilter, minFilterModes, 722 FOR_EACH(magFilter, magFilterModes, 723 FOR_EACH(wrapMode, wrapModes, 724 FOR_EACH(format, formats, 725 FOR_EACH(size, sizes2D, 726 { 727 string name = string("") + minFilterModes[minFilter].name + "_" + magFilterModes[magFilter].name + "_" + wrapModes[wrapMode].name + "_" + formats[format].name + string("_") + sizes2D[size].name; 728 729 group2D->addChild(new Texture2DFilteringCase(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(), 730 name.c_str(), "", 731 minFilterModes[minFilter].mode, 732 magFilterModes[magFilter].mode, 733 wrapModes[wrapMode].mode, 734 wrapModes[wrapMode].mode, 735 formats[format].format, 736 sizes2D[size].width, sizes2D[size].height)); 737 }))))); 738 739 // Cubemap cases. 740 FOR_EACH(minFilter, minFilterModes, 741 FOR_EACH(magFilter, magFilterModes, 742 FOR_EACH(wrapMode, wrapModes, 743 FOR_EACH(format, formats, 744 FOR_EACH(size, sizesCube, 745 { 746 string name = string("") + minFilterModes[minFilter].name + "_" + magFilterModes[magFilter].name + "_" + wrapModes[wrapMode].name + "_" + formats[format].name + string("_") + sizesCube[size].name; 747 748 groupCube->addChild(new TextureCubeFilteringCase(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(), 749 name.c_str(), "", 750 minFilterModes[minFilter].mode, 751 magFilterModes[magFilter].mode, 752 wrapModes[wrapMode].mode, 753 wrapModes[wrapMode].mode, 754 false, 755 formats[format].format, 756 sizesCube[size].width, sizesCube[size].height)); 757 }))))); 758} 759 760} // Accuracy 761} // gles3 762} // deqp 763