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