es31fTextureGatherTests.cpp revision 3c827367444ee418f129b2c238299f49d3264554
1/*------------------------------------------------------------------------- 2 * drawElements Quality Program OpenGL ES 3.1 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 GLSL textureGather[Offset[s]] tests. 22 *//*--------------------------------------------------------------------*/ 23 24#include "es31fTextureGatherTests.hpp" 25#include "glsTextureTestUtil.hpp" 26#include "gluShaderProgram.hpp" 27#include "gluTexture.hpp" 28#include "gluDrawUtil.hpp" 29#include "gluPixelTransfer.hpp" 30#include "gluTextureUtil.hpp" 31#include "gluStrUtil.hpp" 32#include "gluObjectWrapper.hpp" 33#include "tcuTextureUtil.hpp" 34#include "tcuSurface.hpp" 35#include "tcuTestLog.hpp" 36#include "tcuVectorUtil.hpp" 37#include "tcuTexLookupVerifier.hpp" 38#include "tcuTexCompareVerifier.hpp" 39#include "tcuCommandLine.hpp" 40#include "deUniquePtr.hpp" 41#include "deStringUtil.hpp" 42#include "deRandom.hpp" 43#include "deString.h" 44 45#include "glwEnums.hpp" 46#include "glwFunctions.hpp" 47 48using glu::ShaderProgram; 49using tcu::ConstPixelBufferAccess; 50using tcu::PixelBufferAccess; 51using tcu::TestLog; 52using tcu::IVec2; 53using tcu::IVec3; 54using tcu::IVec4; 55using tcu::UVec4; 56using tcu::Vec2; 57using tcu::Vec3; 58using tcu::Vec4; 59using de::MovePtr; 60 61using std::string; 62using std::vector; 63 64namespace deqp 65{ 66 67using gls::TextureTestUtil::TextureType; 68using gls::TextureTestUtil::TEXTURETYPE_2D; 69using gls::TextureTestUtil::TEXTURETYPE_2D_ARRAY; 70using gls::TextureTestUtil::TEXTURETYPE_CUBE; 71 72namespace gles31 73{ 74namespace Functional 75{ 76 77namespace 78{ 79 80// Round-to-zero int division, because pre-c++11 it's somewhat implementation-defined for negative values. 81static inline int divRoundToZero (int a, int b) 82{ 83 return de::abs(a) / de::abs(b) * deSign32(a) * deSign32(b); 84} 85 86static void fillWithRandomColorTiles (const PixelBufferAccess& dst, const Vec4& minVal, const Vec4& maxVal, deUint32 seed) 87{ 88 const int numCols = 7; 89 const int numRows = 5; 90 de::Random rnd (seed); 91 92 for (int slice = 0; slice < dst.getDepth(); slice++) 93 for (int row = 0; row < numRows; row++) 94 for (int col = 0; col < numCols; col++) 95 { 96 const int yBegin = (row+0)*dst.getHeight()/numRows; 97 const int yEnd = (row+1)*dst.getHeight()/numRows; 98 const int xBegin = (col+0)*dst.getWidth()/numCols; 99 const int xEnd = (col+1)*dst.getWidth()/numCols; 100 Vec4 color; 101 for (int i = 0; i < 4; i++) 102 color[i] = rnd.getFloat(minVal[i], maxVal[i]); 103 tcu::clear(tcu::getSubregion(dst, xBegin, yBegin, slice, xEnd-xBegin, yEnd-yBegin, 1), color); 104 } 105} 106 107static tcu::TextureLevel getPixels (const glu::RenderContext& renderCtx, const IVec2& size, const tcu::TextureFormat& colorBufferFormat) 108{ 109 tcu::TextureLevel result(colorBufferFormat, size.x(), size.y()); 110 glu::readPixels(renderCtx, 0, 0, result.getAccess()); 111 return result; 112} 113 114static inline bool isDepthFormat (const tcu::TextureFormat& fmt) 115{ 116 return fmt.order == tcu::TextureFormat::D || fmt.order == tcu::TextureFormat::DS; 117} 118 119static inline bool isUnormFormatType (tcu::TextureFormat::ChannelType type) 120{ 121 return type == tcu::TextureFormat::UNORM_INT8 || 122 type == tcu::TextureFormat::UNORM_INT16 || 123 type == tcu::TextureFormat::UNORM_INT32; 124} 125 126static inline bool isSIntFormatType (tcu::TextureFormat::ChannelType type) 127{ 128 return type == tcu::TextureFormat::SIGNED_INT8 || 129 type == tcu::TextureFormat::SIGNED_INT16 || 130 type == tcu::TextureFormat::SIGNED_INT32; 131} 132 133static inline bool isUIntFormatType (tcu::TextureFormat::ChannelType type) 134{ 135 return type == tcu::TextureFormat::UNSIGNED_INT8 || 136 type == tcu::TextureFormat::UNSIGNED_INT16 || 137 type == tcu::TextureFormat::UNSIGNED_INT32; 138} 139 140enum TextureSwizzleComponent 141{ 142 TEXTURESWIZZLECOMPONENT_R = 0, 143 TEXTURESWIZZLECOMPONENT_G, 144 TEXTURESWIZZLECOMPONENT_B, 145 TEXTURESWIZZLECOMPONENT_A, 146 TEXTURESWIZZLECOMPONENT_ZERO, 147 TEXTURESWIZZLECOMPONENT_ONE, 148 149 TEXTURESWIZZLECOMPONENT_LAST 150}; 151 152static std::ostream& operator<< (std::ostream& stream, TextureSwizzleComponent comp) 153{ 154 switch (comp) 155 { 156 case TEXTURESWIZZLECOMPONENT_R: return stream << "RED"; 157 case TEXTURESWIZZLECOMPONENT_G: return stream << "GREEN"; 158 case TEXTURESWIZZLECOMPONENT_B: return stream << "BLUE"; 159 case TEXTURESWIZZLECOMPONENT_A: return stream << "ALPHA"; 160 case TEXTURESWIZZLECOMPONENT_ZERO: return stream << "ZERO"; 161 case TEXTURESWIZZLECOMPONENT_ONE: return stream << "ONE"; 162 default: DE_ASSERT(false); return stream; 163 } 164} 165 166typedef tcu::Vector<TextureSwizzleComponent, 4> TextureSwizzle; 167 168static const TextureSwizzle s_identityTextureSwizzle(TEXTURESWIZZLECOMPONENT_R, 169 TEXTURESWIZZLECOMPONENT_G, 170 TEXTURESWIZZLECOMPONENT_B, 171 TEXTURESWIZZLECOMPONENT_A); 172 173static deUint32 getGLTextureSwizzleComponent (TextureSwizzleComponent c) 174{ 175 switch (c) 176 { 177 case TEXTURESWIZZLECOMPONENT_R: return GL_RED; 178 case TEXTURESWIZZLECOMPONENT_G: return GL_GREEN; 179 case TEXTURESWIZZLECOMPONENT_B: return GL_BLUE; 180 case TEXTURESWIZZLECOMPONENT_A: return GL_ALPHA; 181 case TEXTURESWIZZLECOMPONENT_ZERO: return GL_ZERO; 182 case TEXTURESWIZZLECOMPONENT_ONE: return GL_ONE; 183 default: DE_ASSERT(false); return (deUint32)-1; 184 } 185} 186 187template <typename T> 188static inline T swizzleColorChannel (const tcu::Vector<T, 4>& src, TextureSwizzleComponent swizzle) 189{ 190 switch (swizzle) 191 { 192 case TEXTURESWIZZLECOMPONENT_R: return src[0]; 193 case TEXTURESWIZZLECOMPONENT_G: return src[1]; 194 case TEXTURESWIZZLECOMPONENT_B: return src[2]; 195 case TEXTURESWIZZLECOMPONENT_A: return src[3]; 196 case TEXTURESWIZZLECOMPONENT_ZERO: return (T)0; 197 case TEXTURESWIZZLECOMPONENT_ONE: return (T)1; 198 default: DE_ASSERT(false); return (T)-1; 199 } 200} 201 202template <typename T> 203static inline tcu::Vector<T, 4> swizzleColor (const tcu::Vector<T, 4>& src, const TextureSwizzle& swizzle) 204{ 205 tcu::Vector<T, 4> result; 206 for (int i = 0; i < 4; i++) 207 result[i] = swizzleColorChannel(src, swizzle[i]); 208 return result; 209} 210 211template <typename T> 212static void swizzlePixels (const PixelBufferAccess& dst, const ConstPixelBufferAccess& src, const TextureSwizzle& swizzle) 213{ 214 DE_ASSERT(dst.getWidth() == src.getWidth() && 215 dst.getHeight() == src.getHeight() && 216 dst.getDepth() == src.getDepth()); 217 for (int z = 0; z < src.getDepth(); z++) 218 for (int y = 0; y < src.getHeight(); y++) 219 for (int x = 0; x < src.getWidth(); x++) 220 dst.setPixel(swizzleColor(src.getPixelT<T>(x, y, z), swizzle), x, y, z); 221} 222 223static void swizzlePixels (const PixelBufferAccess& dst, const ConstPixelBufferAccess& src, const TextureSwizzle& swizzle) 224{ 225 if (isDepthFormat(dst.getFormat())) 226 { 227 DE_ASSERT(swizzle == s_identityTextureSwizzle); 228 tcu::copy(dst, src); 229 } 230 else if (isUnormFormatType(dst.getFormat().type)) 231 swizzlePixels<float>(dst, src, swizzle); 232 else if (isUIntFormatType(dst.getFormat().type)) 233 swizzlePixels<deUint32>(dst, src, swizzle); 234 else if (isSIntFormatType(dst.getFormat().type)) 235 swizzlePixels<deInt32>(dst, src, swizzle); 236 else 237 DE_ASSERT(false); 238} 239 240static void swizzleTexture (tcu::Texture2D& dst, const tcu::Texture2D& src, const TextureSwizzle& swizzle) 241{ 242 dst = tcu::Texture2D(src.getFormat(), src.getWidth(), src.getHeight()); 243 for (int levelNdx = 0; levelNdx < src.getNumLevels(); levelNdx++) 244 { 245 if (src.isLevelEmpty(levelNdx)) 246 continue; 247 dst.allocLevel(levelNdx); 248 swizzlePixels(dst.getLevel(levelNdx), src.getLevel(levelNdx), swizzle); 249 } 250} 251 252static void swizzleTexture (tcu::Texture2DArray& dst, const tcu::Texture2DArray& src, const TextureSwizzle& swizzle) 253{ 254 dst = tcu::Texture2DArray(src.getFormat(), src.getWidth(), src.getHeight(), src.getNumLayers()); 255 for (int levelNdx = 0; levelNdx < src.getNumLevels(); levelNdx++) 256 { 257 if (src.isLevelEmpty(levelNdx)) 258 continue; 259 dst.allocLevel(levelNdx); 260 swizzlePixels(dst.getLevel(levelNdx), src.getLevel(levelNdx), swizzle); 261 } 262} 263 264static void swizzleTexture (tcu::TextureCube& dst, const tcu::TextureCube& src, const TextureSwizzle& swizzle) 265{ 266 dst = tcu::TextureCube(src.getFormat(), src.getSize()); 267 for (int faceI = 0; faceI < tcu::CUBEFACE_LAST; faceI++) 268 { 269 const tcu::CubeFace face = (tcu::CubeFace)faceI; 270 for (int levelNdx = 0; levelNdx < src.getNumLevels(); levelNdx++) 271 { 272 if (src.isLevelEmpty(face, levelNdx)) 273 continue; 274 dst.allocLevel(face, levelNdx); 275 swizzlePixels(dst.getLevelFace(levelNdx, face), src.getLevelFace(levelNdx, face), swizzle); 276 } 277 } 278} 279 280static tcu::Texture2DView getOneLevelSubView (const tcu::Texture2DView& view, int level) 281{ 282 return tcu::Texture2DView(1, view.getLevels() + level); 283} 284 285static tcu::Texture2DArrayView getOneLevelSubView (const tcu::Texture2DArrayView& view, int level) 286{ 287 return tcu::Texture2DArrayView(1, view.getLevels() + level); 288} 289 290static tcu::TextureCubeView getOneLevelSubView (const tcu::TextureCubeView& view, int level) 291{ 292 const tcu::ConstPixelBufferAccess* levels[tcu::CUBEFACE_LAST]; 293 294 for (int face = 0; face < tcu::CUBEFACE_LAST; face++) 295 levels[face] = view.getFaceLevels((tcu::CubeFace)face) + level; 296 297 return tcu::TextureCubeView(1, levels); 298} 299 300class PixelOffsets 301{ 302public: 303 virtual void operator() (const IVec2& pixCoord, IVec2 (&dst)[4]) const = 0; 304 virtual ~PixelOffsets (void) {} 305}; 306 307class MultiplePixelOffsets : public PixelOffsets 308{ 309public: 310 MultiplePixelOffsets (const IVec2& a, 311 const IVec2& b, 312 const IVec2& c, 313 const IVec2& d) 314 { 315 m_offsets[0] = a; 316 m_offsets[1] = b; 317 m_offsets[2] = c; 318 m_offsets[3] = d; 319 } 320 321 void operator() (const IVec2& /* pixCoord */, IVec2 (&dst)[4]) const 322 { 323 for (int i = 0; i < DE_LENGTH_OF_ARRAY(dst); i++) 324 dst[i] = m_offsets[i]; 325 } 326 327private: 328 IVec2 m_offsets[4]; 329}; 330 331class SinglePixelOffsets : public MultiplePixelOffsets 332{ 333public: 334 SinglePixelOffsets (const IVec2& offset) 335 : MultiplePixelOffsets(offset + IVec2(0, 1), 336 offset + IVec2(1, 1), 337 offset + IVec2(1, 0), 338 offset + IVec2(0, 0)) 339 { 340 } 341}; 342 343class DynamicSinglePixelOffsets : public PixelOffsets 344{ 345public: 346 DynamicSinglePixelOffsets (const IVec2& offsetRange) : m_offsetRange(offsetRange) {} 347 348 void operator() (const IVec2& pixCoord, IVec2 (&dst)[4]) const 349 { 350 const int offsetRangeSize = m_offsetRange.y() - m_offsetRange.x() + 1; 351 SinglePixelOffsets(tcu::mod(pixCoord.swizzle(1,0), IVec2(offsetRangeSize)) + m_offsetRange.x())(IVec2(), dst); 352 } 353 354private: 355 IVec2 m_offsetRange; 356}; 357 358template <typename T> 359static inline T triQuadInterpolate (const T (&values)[4], float xFactor, float yFactor) 360{ 361 if (xFactor + yFactor < 1.0f) 362 return values[0] + (values[2]-values[0])*xFactor + (values[1]-values[0])*yFactor; 363 else 364 return values[3] + (values[1]-values[3])*(1.0f-xFactor) + (values[2]-values[3])*(1.0f-yFactor); 365} 366 367template <int N> 368static inline void computeTexCoordVecs (const vector<float>& texCoords, tcu::Vector<float, N> (&dst)[4]) 369{ 370 DE_ASSERT((int)texCoords.size() == 4*N); 371 for (int i = 0; i < 4; i++) 372 for (int j = 0; j < N; j++) 373 dst[i][j] = texCoords[i*N + j]; 374} 375 376#if defined(DE_DEBUG) 377// Whether offsets correspond to the sample offsets used with plain textureGather(). 378static inline bool isZeroOffsetOffsets (const IVec2 (&offsets)[4]) 379{ 380 IVec2 ref[4]; 381 SinglePixelOffsets(IVec2(0))(IVec2(), ref); 382 return std::equal(DE_ARRAY_BEGIN(offsets), 383 DE_ARRAY_END(offsets), 384 DE_ARRAY_BEGIN(ref)); 385} 386#endif 387 388template <typename ColorScalarType> 389static tcu::Vector<ColorScalarType, 4> gatherOffsets (const tcu::Texture2DView& texture, const tcu::Sampler& sampler, const Vec2& coord, int componentNdx, const IVec2 (&offsets)[4]) 390{ 391 return texture.gatherOffsets(sampler, coord.x(), coord.y(), componentNdx, offsets).cast<ColorScalarType>(); 392} 393 394template <typename ColorScalarType> 395static tcu::Vector<ColorScalarType, 4> gatherOffsets (const tcu::Texture2DArrayView& texture, const tcu::Sampler& sampler, const Vec3& coord, int componentNdx, const IVec2 (&offsets)[4]) 396{ 397 return texture.gatherOffsets(sampler, coord.x(), coord.y(), coord.z(), componentNdx, offsets).cast<ColorScalarType>(); 398} 399 400template <typename ColorScalarType> 401static tcu::Vector<ColorScalarType, 4> gatherOffsets (const tcu::TextureCubeView& texture, const tcu::Sampler& sampler, const Vec3& coord, int componentNdx, const IVec2 (&offsets)[4]) 402{ 403 DE_ASSERT(isZeroOffsetOffsets(offsets)); 404 DE_UNREF(offsets); 405 return texture.gather(sampler, coord.x(), coord.y(), coord.z(), componentNdx).cast<ColorScalarType>(); 406} 407 408static Vec4 gatherOffsetsCompare (const tcu::Texture2DView& texture, const tcu::Sampler& sampler, float refZ, const Vec2& coord, const IVec2 (&offsets)[4]) 409{ 410 return texture.gatherOffsetsCompare(sampler, refZ, coord.x(), coord.y(), offsets); 411} 412 413static Vec4 gatherOffsetsCompare (const tcu::Texture2DArrayView& texture, const tcu::Sampler& sampler, float refZ, const Vec3& coord, const IVec2 (&offsets)[4]) 414{ 415 return texture.gatherOffsetsCompare(sampler, refZ, coord.x(), coord.y(), coord.z(), offsets); 416} 417 418static Vec4 gatherOffsetsCompare (const tcu::TextureCubeView& texture, const tcu::Sampler& sampler, float refZ, const Vec3& coord, const IVec2 (&offsets)[4]) 419{ 420 DE_ASSERT(isZeroOffsetOffsets(offsets)); 421 DE_UNREF(offsets); 422 return texture.gatherCompare(sampler, refZ, coord.x(), coord.y(), coord.z()); 423} 424 425template <typename PrecType, typename ColorScalarT> 426static bool isGatherOffsetsResultValid (const tcu::TextureCubeView& texture, 427 const tcu::Sampler& sampler, 428 const PrecType& prec, 429 const Vec3& coord, 430 int componentNdx, 431 const IVec2 (&offsets)[4], 432 const tcu::Vector<ColorScalarT, 4>& result) 433{ 434 DE_ASSERT(isZeroOffsetOffsets(offsets)); 435 DE_UNREF(offsets); 436 return tcu::isGatherResultValid(texture, sampler, prec, coord, componentNdx, result); 437} 438 439static bool isGatherOffsetsCompareResultValid (const tcu::TextureCubeView& texture, 440 const tcu::Sampler& sampler, 441 const tcu::TexComparePrecision& prec, 442 const Vec3& coord, 443 const IVec2 (&offsets)[4], 444 float cmpReference, 445 const Vec4& result) 446{ 447 DE_ASSERT(isZeroOffsetOffsets(offsets)); 448 DE_UNREF(offsets); 449 return tcu::isGatherCompareResultValid(texture, sampler, prec, coord, cmpReference, result); 450} 451 452template <typename ColorScalarType, typename PrecType, typename TexViewT, typename TexCoordT> 453static bool verifyGatherOffsets (TestLog& log, 454 const ConstPixelBufferAccess& result, 455 const TexViewT& texture, 456 const TexCoordT (&texCoords)[4], 457 const tcu::Sampler& sampler, 458 const PrecType& lookupPrec, 459 int componentNdx, 460 const PixelOffsets& getPixelOffsets) 461{ 462 typedef tcu::Vector<ColorScalarType, 4> ColorVec; 463 464 const int width = result.getWidth(); 465 const int height = result.getWidth(); 466 tcu::TextureLevel ideal (result.getFormat(), width, height); 467 const PixelBufferAccess idealAccess = ideal.getAccess(); 468 tcu::Surface errorMask (width, height); 469 bool success = true; 470 471 tcu::clear(errorMask.getAccess(), tcu::RGBA::green.toVec()); 472 473 for (int py = 0; py < height; py++) 474 for (int px = 0; px < width; px++) 475 { 476 IVec2 offsets[4]; 477 getPixelOffsets(IVec2(px, py), offsets); 478 479 const Vec2 viewportCoord = (Vec2((float)px, (float)py) + 0.5f) / Vec2((float)width, (float)height); 480 const TexCoordT texCoord = triQuadInterpolate(texCoords, viewportCoord.x(), viewportCoord.y()); 481 const ColorVec resultPix = result.getPixelT<ColorScalarType>(px, py); 482 const ColorVec idealPix = gatherOffsets<ColorScalarType>(texture, sampler, texCoord, componentNdx, offsets); 483 484 idealAccess.setPixel(idealPix, px, py); 485 486 if (tcu::boolAny(tcu::logicalAnd(lookupPrec.colorMask, 487 tcu::greaterThan(tcu::absDiff(resultPix, idealPix), 488 lookupPrec.colorThreshold.template cast<ColorScalarType>())))) 489 { 490 if (!isGatherOffsetsResultValid(texture, sampler, lookupPrec, texCoord, componentNdx, offsets, resultPix)) 491 { 492 errorMask.setPixel(px, py, tcu::RGBA::red); 493 success = false; 494 } 495 } 496 } 497 498 log << TestLog::ImageSet("VerifyResult", "Verification result") 499 << TestLog::Image("Rendered", "Rendered image", result); 500 501 if (!success) 502 { 503 log << TestLog::Image("Reference", "Ideal reference image", ideal) 504 << TestLog::Image("ErrorMask", "Error mask", errorMask); 505 } 506 507 log << TestLog::EndImageSet; 508 509 return success; 510} 511 512class PixelCompareRefZ 513{ 514public: 515 virtual float operator() (const IVec2& pixCoord) const = 0; 516}; 517 518class PixelCompareRefZDefault : public PixelCompareRefZ 519{ 520public: 521 PixelCompareRefZDefault (const IVec2& renderSize) : m_renderSize(renderSize) {} 522 523 float operator() (const IVec2& pixCoord) const 524 { 525 return (float)(pixCoord.x() + 0.5f) / (float)m_renderSize.x(); 526 } 527 528private: 529 IVec2 m_renderSize; 530}; 531 532template <typename TexViewT, typename TexCoordT> 533static bool verifyGatherOffsetsCompare (TestLog& log, 534 const ConstPixelBufferAccess& result, 535 const TexViewT& texture, 536 const TexCoordT (&texCoords)[4], 537 const tcu::Sampler& sampler, 538 const tcu::TexComparePrecision& compPrec, 539 const PixelCompareRefZ& getPixelRefZ, 540 const PixelOffsets& getPixelOffsets) 541{ 542 const int width = result.getWidth(); 543 const int height = result.getWidth(); 544 tcu::Surface ideal (width, height); 545 const PixelBufferAccess idealAccess = ideal.getAccess(); 546 tcu::Surface errorMask (width, height); 547 bool success = true; 548 549 tcu::clear(errorMask.getAccess(), tcu::RGBA::green.toVec()); 550 551 for (int py = 0; py < height; py++) 552 for (int px = 0; px < width; px++) 553 { 554 IVec2 offsets[4]; 555 getPixelOffsets(IVec2(px, py), offsets); 556 557 const Vec2 viewportCoord = (Vec2((float)px, (float)py) + 0.5f) / Vec2((float)width, (float)height); 558 const TexCoordT texCoord = triQuadInterpolate(texCoords, viewportCoord.x(), viewportCoord.y()); 559 const float refZ = getPixelRefZ(IVec2(px, py)); 560 const Vec4 resultPix = result.getPixel(px, py); 561 const Vec4 idealPix = gatherOffsetsCompare(texture, sampler, refZ, texCoord, offsets); 562 563 idealAccess.setPixel(idealPix, px, py); 564 565 if (!tcu::boolAll(tcu::equal(resultPix, idealPix))) 566 { 567 if (!isGatherOffsetsCompareResultValid(texture, sampler, compPrec, texCoord, offsets, refZ, resultPix)) 568 { 569 errorMask.setPixel(px, py, tcu::RGBA::red); 570 success = false; 571 } 572 } 573 } 574 575 log << TestLog::ImageSet("VerifyResult", "Verification result") 576 << TestLog::Image("Rendered", "Rendered image", result); 577 578 if (!success) 579 { 580 log << TestLog::Image("Reference", "Ideal reference image", ideal) 581 << TestLog::Image("ErrorMask", "Error mask", errorMask); 582 } 583 584 log << TestLog::EndImageSet; 585 586 return success; 587} 588 589static bool verifySingleColored (TestLog& log, const ConstPixelBufferAccess& result, const Vec4& refColor) 590{ 591 const int width = result.getWidth(); 592 const int height = result.getWidth(); 593 tcu::Surface ideal (width, height); 594 const PixelBufferAccess idealAccess = ideal.getAccess(); 595 tcu::Surface errorMask (width, height); 596 bool success = true; 597 598 tcu::clear(errorMask.getAccess(), tcu::RGBA::green.toVec()); 599 tcu::clear(idealAccess, refColor); 600 601 for (int py = 0; py < height; py++) 602 for (int px = 0; px < width; px++) 603 { 604 if (result.getPixel(px, py) != refColor) 605 { 606 errorMask.setPixel(px, py, tcu::RGBA::red); 607 success = false; 608 } 609 } 610 611 log << TestLog::ImageSet("VerifyResult", "Verification result") 612 << TestLog::Image("Rendered", "Rendered image", result); 613 614 if (!success) 615 { 616 log << TestLog::Image("Reference", "Ideal reference image", ideal) 617 << TestLog::Image("ErrorMask", "Error mask", errorMask); 618 } 619 620 log << TestLog::EndImageSet; 621 622 return success; 623} 624 625enum GatherType 626{ 627 GATHERTYPE_BASIC = 0, 628 GATHERTYPE_OFFSET, 629 GATHERTYPE_OFFSET_DYNAMIC, 630 GATHERTYPE_OFFSETS, 631 632 GATHERTYPE_LAST 633}; 634 635static inline const char* gatherTypeName (GatherType type) 636{ 637 switch (type) 638 { 639 case GATHERTYPE_BASIC: return "basic"; 640 case GATHERTYPE_OFFSET: return "offset"; 641 case GATHERTYPE_OFFSET_DYNAMIC: return "offset_dynamic"; 642 case GATHERTYPE_OFFSETS: return "offsets"; 643 default: DE_ASSERT(false); return DE_NULL; 644 } 645} 646 647static inline const char* gatherTypeDescription (GatherType type) 648{ 649 switch (type) 650 { 651 case GATHERTYPE_BASIC: return "textureGather"; 652 case GATHERTYPE_OFFSET: return "textureGatherOffset"; 653 case GATHERTYPE_OFFSET_DYNAMIC: return "textureGatherOffset with dynamic offsets"; 654 case GATHERTYPE_OFFSETS: return "textureGatherOffsets"; 655 default: DE_ASSERT(false); return DE_NULL; 656 } 657} 658 659static inline bool requireGpuShader5 (GatherType gatherType) 660{ 661 return gatherType == GATHERTYPE_OFFSET_DYNAMIC || gatherType == GATHERTYPE_OFFSETS; 662} 663 664struct GatherArgs 665{ 666 int componentNdx; // If negative, implicit component index 0 is used (i.e. the parameter is not given). 667 IVec2 offsets[4]; // \note Unless GATHERTYPE_OFFSETS is used, only offsets[0] is relevant; also, for GATHERTYPE_OFFSET_DYNAMIC, none are relevant. 668 669 GatherArgs (void) 670 : componentNdx(-1) 671 { 672 std::fill(DE_ARRAY_BEGIN(offsets), DE_ARRAY_END(offsets), IVec2()); 673 } 674 675 GatherArgs (int comp, 676 const IVec2& off0 = IVec2(), 677 const IVec2& off1 = IVec2(), 678 const IVec2& off2 = IVec2(), 679 const IVec2& off3 = IVec2()) 680 : componentNdx(comp) 681 { 682 offsets[0] = off0; 683 offsets[1] = off1; 684 offsets[2] = off2; 685 offsets[3] = off3; 686 } 687}; 688 689static MovePtr<PixelOffsets> makePixelOffsetsFunctor (GatherType gatherType, const GatherArgs& gatherArgs, const IVec2& offsetRange) 690{ 691 if (gatherType == GATHERTYPE_BASIC || gatherType == GATHERTYPE_OFFSET) 692 { 693 const IVec2 offset = gatherType == GATHERTYPE_BASIC ? IVec2(0) : gatherArgs.offsets[0]; 694 return MovePtr<PixelOffsets>(new SinglePixelOffsets(offset)); 695 } 696 else if (gatherType == GATHERTYPE_OFFSET_DYNAMIC) 697 { 698 return MovePtr<PixelOffsets>(new DynamicSinglePixelOffsets(offsetRange)); 699 } 700 else if (gatherType == GATHERTYPE_OFFSETS) 701 return MovePtr<PixelOffsets>(new MultiplePixelOffsets(gatherArgs.offsets[0], 702 gatherArgs.offsets[1], 703 gatherArgs.offsets[2], 704 gatherArgs.offsets[3])); 705 else 706 { 707 DE_ASSERT(false); 708 return MovePtr<PixelOffsets>(DE_NULL); 709 } 710} 711 712static inline glu::DataType getSamplerType (TextureType textureType, const tcu::TextureFormat& format) 713{ 714 if (isDepthFormat(format)) 715 { 716 switch (textureType) 717 { 718 case TEXTURETYPE_2D: return glu::TYPE_SAMPLER_2D_SHADOW; 719 case TEXTURETYPE_2D_ARRAY: return glu::TYPE_SAMPLER_2D_ARRAY_SHADOW; 720 case TEXTURETYPE_CUBE: return glu::TYPE_SAMPLER_CUBE_SHADOW; 721 default: DE_ASSERT(false); return glu::TYPE_LAST; 722 } 723 } 724 else 725 { 726 switch (textureType) 727 { 728 case TEXTURETYPE_2D: return glu::getSampler2DType(format); 729 case TEXTURETYPE_2D_ARRAY: return glu::getSampler2DArrayType(format); 730 case TEXTURETYPE_CUBE: return glu::getSamplerCubeType(format); 731 default: DE_ASSERT(false); return glu::TYPE_LAST; 732 } 733 } 734} 735 736static inline glu::DataType getSamplerGatherResultType (glu::DataType samplerType) 737{ 738 switch (samplerType) 739 { 740 case glu::TYPE_SAMPLER_2D_SHADOW: 741 case glu::TYPE_SAMPLER_2D_ARRAY_SHADOW: 742 case glu::TYPE_SAMPLER_CUBE_SHADOW: 743 case glu::TYPE_SAMPLER_2D: 744 case glu::TYPE_SAMPLER_2D_ARRAY: 745 case glu::TYPE_SAMPLER_CUBE: 746 return glu::TYPE_FLOAT_VEC4; 747 748 case glu::TYPE_INT_SAMPLER_2D: 749 case glu::TYPE_INT_SAMPLER_2D_ARRAY: 750 case glu::TYPE_INT_SAMPLER_CUBE: 751 return glu::TYPE_INT_VEC4; 752 753 case glu::TYPE_UINT_SAMPLER_2D: 754 case glu::TYPE_UINT_SAMPLER_2D_ARRAY: 755 case glu::TYPE_UINT_SAMPLER_CUBE: 756 return glu::TYPE_UINT_VEC4; 757 758 default: 759 DE_ASSERT(false); 760 return glu::TYPE_LAST; 761 } 762} 763 764static inline int getNumTextureSamplingDimensions (TextureType type) 765{ 766 switch (type) 767 { 768 case TEXTURETYPE_2D: return 2; 769 case TEXTURETYPE_2D_ARRAY: return 3; 770 case TEXTURETYPE_CUBE: return 3; 771 default: DE_ASSERT(false); return -1; 772 } 773} 774 775static deUint32 getGLTextureType (TextureType type) 776{ 777 switch (type) 778 { 779 case TEXTURETYPE_2D: return GL_TEXTURE_2D; 780 case TEXTURETYPE_2D_ARRAY: return GL_TEXTURE_2D_ARRAY; 781 case TEXTURETYPE_CUBE: return GL_TEXTURE_CUBE_MAP; 782 default: DE_ASSERT(false); return (deUint32)-1; 783 } 784} 785 786enum OffsetSize 787{ 788 OFFSETSIZE_NONE = 0, 789 OFFSETSIZE_MINIMUM_REQUIRED, 790 OFFSETSIZE_IMPLEMENTATION_MAXIMUM, 791 792 OFFSETSIZE_LAST 793}; 794 795static inline bool isMipmapFilter (tcu::Sampler::FilterMode filter) 796{ 797 switch (filter) 798 { 799 case tcu::Sampler::NEAREST: 800 case tcu::Sampler::LINEAR: 801 return false; 802 803 case tcu::Sampler::NEAREST_MIPMAP_NEAREST: 804 case tcu::Sampler::NEAREST_MIPMAP_LINEAR: 805 case tcu::Sampler::LINEAR_MIPMAP_NEAREST: 806 case tcu::Sampler::LINEAR_MIPMAP_LINEAR: 807 return true; 808 809 default: 810 DE_ASSERT(false); 811 return false; 812 } 813} 814 815class TextureGatherCase : public TestCase 816{ 817public: 818 TextureGatherCase (Context& context, 819 const char* name, 820 const char* description, 821 TextureType textureType, 822 GatherType gatherType, 823 OffsetSize offsetSize, 824 tcu::TextureFormat textureFormat, 825 tcu::Sampler::CompareMode shadowCompareMode, //!< Should be COMPAREMODE_NONE iff textureFormat is a depth format. 826 tcu::Sampler::WrapMode wrapS, 827 tcu::Sampler::WrapMode wrapT, 828 const TextureSwizzle& texSwizzle, 829 // \note Filter modes have no effect on gather (except when it comes to 830 // texture completeness); these are supposed to test just that. 831 tcu::Sampler::FilterMode minFilter, 832 tcu::Sampler::FilterMode magFilter, 833 int baseLevel, 834 bool mipmapIncomplete); 835 836 void init (void); 837 void deinit (void); 838 IterateResult iterate (void); 839 840protected: 841 IVec2 getOffsetRange (void) const; 842 843 template <typename TexViewT, typename TexCoordT> 844 bool verify (const ConstPixelBufferAccess& rendered, 845 const TexViewT& texture, 846 const TexCoordT (&bottomLeft)[4], 847 const GatherArgs& gatherArgs) const; 848 849 virtual void generateIterations (void) = 0; 850 virtual void createAndUploadTexture (void) = 0; 851 virtual int getNumIterations (void) const = 0; 852 virtual GatherArgs getGatherArgs (int iterationNdx) const = 0; 853 virtual vector<float> computeQuadTexCoord (int iterationNdx) const = 0; 854 virtual bool verify (int iterationNdx, const ConstPixelBufferAccess& rendered) const = 0; 855 856 const GatherType m_gatherType; 857 const OffsetSize m_offsetSize; 858 const tcu::TextureFormat m_textureFormat; 859 const tcu::Sampler::CompareMode m_shadowCompareMode; 860 const tcu::Sampler::WrapMode m_wrapS; 861 const tcu::Sampler::WrapMode m_wrapT; 862 const TextureSwizzle m_textureSwizzle; 863 const tcu::Sampler::FilterMode m_minFilter; 864 const tcu::Sampler::FilterMode m_magFilter; 865 const int m_baseLevel; 866 const bool m_mipmapIncomplete; 867 868private: 869 enum 870 { 871 SPEC_MAX_MIN_OFFSET = -8, 872 SPEC_MIN_MAX_OFFSET = 7 873 }; 874 875 static const IVec2 RENDER_SIZE; 876 877 static glu::VertexSource genVertexShaderSource (bool requireGpuShader5, int numTexCoordComponents, bool useNormalizedCoordInput); 878 static glu::FragmentSource genFragmentShaderSource (bool requireGpuShader5, int numTexCoordComponents, glu::DataType samplerType, const string& funcCall, bool useNormalizedCoordInput, bool usePixCoord); 879 static string genGatherFuncCall (GatherType, const tcu::TextureFormat&, const GatherArgs&, const string& refZExpr, const IVec2& offsetRange, int indentationDepth); 880 static glu::ProgramSources genProgramSources (GatherType, TextureType, const tcu::TextureFormat&, const GatherArgs&, const string& refZExpr, const IVec2& offsetRange); 881 882 const TextureType m_textureType; 883 884 const tcu::TextureFormat m_colorBufferFormat; 885 MovePtr<glu::Renderbuffer> m_colorBuffer; 886 MovePtr<glu::Framebuffer> m_fbo; 887 888 int m_currentIteration; 889 MovePtr<ShaderProgram> m_program; 890}; 891 892const IVec2 TextureGatherCase::RENDER_SIZE = IVec2(64, 64); 893 894TextureGatherCase::TextureGatherCase (Context& context, 895 const char* name, 896 const char* description, 897 TextureType textureType, 898 GatherType gatherType, 899 OffsetSize offsetSize, 900 tcu::TextureFormat textureFormat, 901 tcu::Sampler::CompareMode shadowCompareMode, //!< Should be COMPAREMODE_NONE iff textureType == TEXTURETYPE_NORMAL. 902 tcu::Sampler::WrapMode wrapS, 903 tcu::Sampler::WrapMode wrapT, 904 const TextureSwizzle& textureSwizzle, 905 tcu::Sampler::FilterMode minFilter, 906 tcu::Sampler::FilterMode magFilter, 907 int baseLevel, 908 bool mipmapIncomplete) 909 : TestCase (context, name, description) 910 , m_gatherType (gatherType) 911 , m_offsetSize (offsetSize) 912 , m_textureFormat (textureFormat) 913 , m_shadowCompareMode (shadowCompareMode) 914 , m_wrapS (wrapS) 915 , m_wrapT (wrapT) 916 , m_textureSwizzle (textureSwizzle) 917 , m_minFilter (minFilter) 918 , m_magFilter (magFilter) 919 , m_baseLevel (baseLevel) 920 , m_mipmapIncomplete (mipmapIncomplete) 921 , m_textureType (textureType) 922 , m_colorBufferFormat (tcu::TextureFormat(tcu::TextureFormat::RGBA, 923 isDepthFormat(textureFormat) ? tcu::TextureFormat::UNORM_INT8 : textureFormat.type)) 924 , m_currentIteration (0) 925{ 926 DE_ASSERT((m_gatherType == GATHERTYPE_BASIC) == (m_offsetSize == OFFSETSIZE_NONE)); 927 DE_ASSERT((m_shadowCompareMode != tcu::Sampler::COMPAREMODE_NONE) == isDepthFormat(m_textureFormat)); 928 DE_ASSERT(isUnormFormatType(m_colorBufferFormat.type) || 929 m_colorBufferFormat.type == tcu::TextureFormat::UNSIGNED_INT8 || 930 m_colorBufferFormat.type == tcu::TextureFormat::UNSIGNED_INT16 || 931 m_colorBufferFormat.type == tcu::TextureFormat::SIGNED_INT8 || 932 m_colorBufferFormat.type == tcu::TextureFormat::SIGNED_INT16); 933 DE_ASSERT(glu::isGLInternalColorFormatFilterable(glu::getInternalFormat(m_colorBufferFormat)) || 934 (m_magFilter == tcu::Sampler::NEAREST && (m_minFilter == tcu::Sampler::NEAREST || m_minFilter == tcu::Sampler::NEAREST_MIPMAP_NEAREST))); 935 DE_ASSERT(isMipmapFilter(m_minFilter) || !m_mipmapIncomplete); 936 DE_ASSERT(!(m_mipmapIncomplete && isDepthFormat(m_textureFormat))); // It's not clear what shadow textures should return when incomplete. 937} 938 939IVec2 TextureGatherCase::getOffsetRange (void) const 940{ 941 switch (m_offsetSize) 942 { 943 case OFFSETSIZE_NONE: 944 return IVec2(0); 945 break; 946 947 case OFFSETSIZE_MINIMUM_REQUIRED: 948 // \note Defined by spec. 949 return IVec2(SPEC_MAX_MIN_OFFSET, 950 SPEC_MIN_MAX_OFFSET); 951 break; 952 953 case OFFSETSIZE_IMPLEMENTATION_MAXIMUM: 954 return IVec2(m_context.getContextInfo().getInt(GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET), 955 m_context.getContextInfo().getInt(GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET)); 956 break; 957 958 default: 959 DE_ASSERT(false); 960 return IVec2(-1); 961 } 962} 963 964glu::VertexSource TextureGatherCase::genVertexShaderSource (bool requireGpuShader5, int numTexCoordComponents, bool useNormalizedCoordInput) 965{ 966 DE_ASSERT(numTexCoordComponents == 2 || numTexCoordComponents == 3); 967 const string texCoordType = "vec" + de::toString(numTexCoordComponents); 968 return glu::VertexSource("#version 310 es\n" 969 + string(requireGpuShader5 ? "#extension GL_EXT_gpu_shader5 : require\n" : "") + 970 "\n" 971 "in highp vec2 a_position;\n" 972 "in highp " + texCoordType + " a_texCoord;\n" 973 + (useNormalizedCoordInput ? "in highp vec2 a_normalizedCoord; // (0,0) to (1,1)\n" : "") + 974 "\n" 975 "out highp " + texCoordType + " v_texCoord;\n" 976 + (useNormalizedCoordInput ? "out highp vec2 v_normalizedCoord;\n" : "") + 977 "\n" 978 "void main (void)\n" 979 "{\n" 980 " gl_Position = vec4(a_position.x, a_position.y, 0.0, 1.0);\n" 981 " v_texCoord = a_texCoord;\n" 982 + (useNormalizedCoordInput ? "\tv_normalizedCoord = a_normalizedCoord;\n" : "") + 983 "}\n"); 984} 985 986glu::FragmentSource TextureGatherCase::genFragmentShaderSource (bool requireGpuShader5, 987 int numTexCoordComponents, 988 glu::DataType samplerType, 989 const string& funcCall, 990 bool useNormalizedCoordInput, 991 bool usePixCoord) 992{ 993 DE_ASSERT(glu::isDataTypeSampler(samplerType)); 994 DE_ASSERT(de::inRange(numTexCoordComponents, 2, 3)); 995 DE_ASSERT(!usePixCoord || useNormalizedCoordInput); 996 997 const string texCoordType = "vec" + de::toString(numTexCoordComponents); 998 999 return glu::FragmentSource("#version 310 es\n" 1000 + string(requireGpuShader5 ? "#extension GL_EXT_gpu_shader5 : require\n" : "") + 1001 "\n" 1002 "layout (location = 0) out mediump " + glu::getDataTypeName(getSamplerGatherResultType(samplerType)) + " o_color;\n" 1003 "\n" 1004 "in highp " + texCoordType + " v_texCoord;\n" 1005 + (useNormalizedCoordInput ? "in highp vec2 v_normalizedCoord;\n" : "") + 1006 "\n" 1007 "uniform highp " + string(glu::getDataTypeName(samplerType)) + " u_sampler;\n" 1008 + (useNormalizedCoordInput ? "uniform highp vec2 u_viewportSize;\n" : "") + 1009 "\n" 1010 "void main(void)\n" 1011 "{\n" 1012 + (usePixCoord ? "\tivec2 pixCoord = ivec2(v_normalizedCoord*u_viewportSize);\n" : "") + 1013 " o_color = " + funcCall + ";\n" 1014 "}\n"); 1015} 1016 1017string TextureGatherCase::genGatherFuncCall (GatherType gatherType, const tcu::TextureFormat& textureFormat, const GatherArgs& gatherArgs, const string& refZExpr, const IVec2& offsetRange, int indentationDepth) 1018{ 1019 string result; 1020 1021 switch (gatherType) 1022 { 1023 case GATHERTYPE_BASIC: 1024 result += "textureGather"; 1025 break; 1026 case GATHERTYPE_OFFSET: // \note Fallthrough. 1027 case GATHERTYPE_OFFSET_DYNAMIC: 1028 result += "textureGatherOffset"; 1029 break; 1030 case GATHERTYPE_OFFSETS: 1031 result += "textureGatherOffsets"; 1032 break; 1033 default: 1034 DE_ASSERT(false); 1035 } 1036 1037 result += "(u_sampler, v_texCoord"; 1038 1039 if (isDepthFormat(textureFormat)) 1040 { 1041 DE_ASSERT(gatherArgs.componentNdx < 0); 1042 result += ", " + refZExpr; 1043 } 1044 1045 if (gatherType == GATHERTYPE_OFFSET || 1046 gatherType == GATHERTYPE_OFFSET_DYNAMIC || 1047 gatherType == GATHERTYPE_OFFSETS) 1048 { 1049 result += ", "; 1050 switch (gatherType) 1051 { 1052 case GATHERTYPE_OFFSET: 1053 result += "ivec2" + de::toString(gatherArgs.offsets[0]); 1054 break; 1055 1056 case GATHERTYPE_OFFSET_DYNAMIC: 1057 result += "pixCoord.yx % ivec2(" + de::toString(offsetRange.y() - offsetRange.x() + 1) + ") + " + de::toString(offsetRange.x()); 1058 break; 1059 1060 case GATHERTYPE_OFFSETS: 1061 result += "ivec2[4](\n" 1062 + string(indentationDepth, '\t') + "\tivec2" + de::toString(gatherArgs.offsets[0]) + ",\n" 1063 + string(indentationDepth, '\t') + "\tivec2" + de::toString(gatherArgs.offsets[1]) + ",\n" 1064 + string(indentationDepth, '\t') + "\tivec2" + de::toString(gatherArgs.offsets[2]) + ",\n" 1065 + string(indentationDepth, '\t') + "\tivec2" + de::toString(gatherArgs.offsets[3]) + ")\n" 1066 + string(indentationDepth, '\t') + "\t"; 1067 break; 1068 1069 default: 1070 DE_ASSERT(false); 1071 } 1072 } 1073 1074 if (gatherArgs.componentNdx >= 0) 1075 { 1076 DE_ASSERT(gatherArgs.componentNdx < 4); 1077 result += ", " + de::toString(gatherArgs.componentNdx); 1078 } 1079 1080 result += ")"; 1081 1082 return result; 1083} 1084 1085// \note If componentNdx for genProgramSources() is -1, component index is not specified. 1086glu::ProgramSources TextureGatherCase::genProgramSources (GatherType gatherType, 1087 TextureType textureType, 1088 const tcu::TextureFormat& textureFormat, 1089 const GatherArgs& gatherArgs, 1090 const string& refZExpr, 1091 const IVec2& offsetRange) 1092{ 1093 const bool usePixCoord = gatherType == GATHERTYPE_OFFSET_DYNAMIC; 1094 const bool useNormalizedCoord = usePixCoord || isDepthFormat(textureFormat); 1095 const bool isDynamicOffset = gatherType == GATHERTYPE_OFFSET_DYNAMIC; 1096 const bool isShadow = isDepthFormat(textureFormat); 1097 const glu::DataType samplerType = getSamplerType(textureType, textureFormat); 1098 const int numDims = getNumTextureSamplingDimensions(textureType); 1099 const string funcCall = genGatherFuncCall(gatherType, textureFormat, gatherArgs, refZExpr, offsetRange, 1); 1100 1101 return glu::ProgramSources() << genVertexShaderSource(requireGpuShader5(gatherType), numDims, isDynamicOffset || isShadow) 1102 << genFragmentShaderSource(requireGpuShader5(gatherType), numDims, samplerType, funcCall, useNormalizedCoord, usePixCoord); 1103} 1104 1105void TextureGatherCase::init (void) 1106{ 1107 TestLog& log = m_testCtx.getLog(); 1108 const glu::RenderContext& renderCtx = m_context.getRenderContext(); 1109 const glw::Functions& gl = renderCtx.getFunctions(); 1110 const deUint32 texTypeGL = getGLTextureType(m_textureType); 1111 1112 // Check prerequisites. 1113 if (requireGpuShader5(m_gatherType) && !m_context.getContextInfo().isExtensionSupported("GL_EXT_gpu_shader5")) 1114 throw tcu::NotSupportedError("GL_EXT_gpu_shader5 required"); 1115 1116 // Log and check implementation offset limits, if appropriate. 1117 if (m_offsetSize == OFFSETSIZE_IMPLEMENTATION_MAXIMUM) 1118 { 1119 const IVec2 offsetRange = getOffsetRange(); 1120 log << TestLog::Integer("ImplementationMinTextureGatherOffset", "Implementation's value for GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET", "", QP_KEY_TAG_NONE, offsetRange[0]) 1121 << TestLog::Integer("ImplementationMaxTextureGatherOffset", "Implementation's value for GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET", "", QP_KEY_TAG_NONE, offsetRange[1]); 1122 TCU_CHECK_MSG(offsetRange[0] <= SPEC_MAX_MIN_OFFSET, ("GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET must be at most " + de::toString((int)SPEC_MAX_MIN_OFFSET)).c_str()); 1123 TCU_CHECK_MSG(offsetRange[1] >= SPEC_MIN_MAX_OFFSET, ("GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET must be at least " + de::toString((int)SPEC_MIN_MAX_OFFSET)).c_str()); 1124 } 1125 1126 // Create rbo and fbo. 1127 1128 m_colorBuffer = MovePtr<glu::Renderbuffer>(new glu::Renderbuffer(renderCtx)); 1129 gl.bindRenderbuffer(GL_RENDERBUFFER, **m_colorBuffer); 1130 gl.renderbufferStorage(GL_RENDERBUFFER, glu::getInternalFormat(m_colorBufferFormat), RENDER_SIZE.x(), RENDER_SIZE.y()); 1131 GLU_EXPECT_NO_ERROR(gl.getError(), "Create and setup renderbuffer object"); 1132 1133 m_fbo = MovePtr<glu::Framebuffer>(new glu::Framebuffer(renderCtx)); 1134 gl.bindFramebuffer(GL_FRAMEBUFFER, **m_fbo); 1135 gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, **m_colorBuffer); 1136 GLU_EXPECT_NO_ERROR(gl.getError(), "Create and setup framebuffer object"); 1137 1138 log << TestLog::Message << "Using a framebuffer object with renderbuffer with format " 1139 << glu::getPixelFormatName(glu::getInternalFormat(m_colorBufferFormat)) 1140 << " and size " << RENDER_SIZE << TestLog::EndMessage; 1141 1142 // Generate subclass-specific iterations. 1143 1144 generateIterations(); 1145 m_currentIteration = 0; 1146 1147 // Initialize texture. 1148 1149 createAndUploadTexture(); 1150 gl.texParameteri(texTypeGL, GL_TEXTURE_WRAP_S, glu::getGLWrapMode(m_wrapS)); 1151 gl.texParameteri(texTypeGL, GL_TEXTURE_WRAP_T, glu::getGLWrapMode(m_wrapT)); 1152 gl.texParameteri(texTypeGL, GL_TEXTURE_MIN_FILTER, glu::getGLFilterMode(m_minFilter)); 1153 gl.texParameteri(texTypeGL, GL_TEXTURE_MAG_FILTER, glu::getGLFilterMode(m_magFilter)); 1154 1155 if (m_baseLevel != 0) 1156 gl.texParameteri(texTypeGL, GL_TEXTURE_BASE_LEVEL, m_baseLevel); 1157 1158 if (isDepthFormat(m_textureFormat)) 1159 { 1160 gl.texParameteri(texTypeGL, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); 1161 gl.texParameteri(texTypeGL, GL_TEXTURE_COMPARE_FUNC, glu::getGLCompareFunc(m_shadowCompareMode)); 1162 } 1163 1164 { 1165 const deUint32 swizzleNamesGL[4] = 1166 { 1167 GL_TEXTURE_SWIZZLE_R, 1168 GL_TEXTURE_SWIZZLE_G, 1169 GL_TEXTURE_SWIZZLE_B, 1170 GL_TEXTURE_SWIZZLE_A 1171 }; 1172 const deUint32 initialGLTexSwizzles[4] = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA }; 1173 1174 for (int i = 0; i < 4; i++) 1175 { 1176 const deUint32 curGLSwizzle = getGLTextureSwizzleComponent(m_textureSwizzle[i]); 1177 if (curGLSwizzle != initialGLTexSwizzles[i]) 1178 gl.texParameteri(texTypeGL, swizzleNamesGL[i], curGLSwizzle); 1179 } 1180 } 1181 1182 GLU_EXPECT_NO_ERROR(gl.getError(), "Set texture parameters"); 1183 1184 log << TestLog::Message << "Texture base level is " << m_baseLevel << TestLog::EndMessage 1185 << TestLog::Message << "s and t wrap modes are " 1186 << glu::getTextureWrapModeName(glu::getGLWrapMode(m_wrapS)) << " and " 1187 << glu::getTextureWrapModeName(glu::getGLWrapMode(m_wrapT)) << ", respectively" << TestLog::EndMessage 1188 << TestLog::Message << "Minification and magnification filter modes are " 1189 << glu::getTextureFilterName(glu::getGLFilterMode(m_minFilter)) << " and " 1190 << glu::getTextureFilterName(glu::getGLFilterMode(m_magFilter)) << ", respectively " 1191 << (m_mipmapIncomplete ? 1192 "(note that they cause the texture to be incomplete)" : 1193 "(note that they should have no effect on gather result)") 1194 << TestLog::EndMessage 1195 << TestLog::Message << "Using texture swizzle " << m_textureSwizzle << TestLog::EndMessage; 1196 1197 if (m_shadowCompareMode != tcu::Sampler::COMPAREMODE_NONE) 1198 log << TestLog::Message << "Using texture compare func " << glu::getCompareFuncName(glu::getGLCompareFunc(m_shadowCompareMode)) << TestLog::EndMessage; 1199} 1200 1201void TextureGatherCase::deinit (void) 1202{ 1203 m_program = MovePtr<ShaderProgram>(DE_NULL); 1204 m_fbo = MovePtr<glu::Framebuffer>(DE_NULL); 1205 m_colorBuffer = MovePtr<glu::Renderbuffer>(DE_NULL); 1206} 1207 1208TextureGatherCase::IterateResult TextureGatherCase::iterate (void) 1209{ 1210 TestLog& log = m_testCtx.getLog(); 1211 const tcu::ScopedLogSection iterationSection (log, "Iteration" + de::toString(m_currentIteration), "Iteration " + de::toString(m_currentIteration)); 1212 const glu::RenderContext& renderCtx = m_context.getRenderContext(); 1213 const tcu::IVec2 renderSize = RENDER_SIZE; 1214 const glw::Functions& gl = renderCtx.getFunctions(); 1215 const GatherArgs& gatherArgs = getGatherArgs(m_currentIteration); 1216 const string refZExpr = "v_normalizedCoord.x"; 1217 const bool needPixelCoordInShader = m_gatherType == GATHERTYPE_OFFSET_DYNAMIC; 1218 const bool needNormalizedCoordInShader = needPixelCoordInShader || isDepthFormat(m_textureFormat); 1219 1220 // Generate a program appropriate for this iteration. 1221 1222 m_program = MovePtr<ShaderProgram>(new ShaderProgram(renderCtx, genProgramSources(m_gatherType, m_textureType, m_textureFormat, gatherArgs, refZExpr, getOffsetRange()))); 1223 if (m_currentIteration == 0) 1224 m_testCtx.getLog() << *m_program; 1225 else 1226 m_testCtx.getLog() << TestLog::Message << "Using a program similar to the previous one, except with a gather function call as follows:\n" 1227 << genGatherFuncCall(m_gatherType, m_textureFormat, gatherArgs, refZExpr, getOffsetRange(), 0) 1228 << TestLog::EndMessage; 1229 if (!m_program->isOk()) 1230 { 1231 if (m_currentIteration != 0) 1232 m_testCtx.getLog() << *m_program; 1233 TCU_FAIL("Failed to build program"); 1234 } 1235 1236 // Render. 1237 1238 gl.viewport(0, 0, RENDER_SIZE.x(), RENDER_SIZE.y()); 1239 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f); 1240 gl.clear(GL_COLOR_BUFFER_BIT); 1241 1242 { 1243 const float position[4*2] = 1244 { 1245 -1.0f, -1.0f, 1246 -1.0f, +1.0f, 1247 +1.0f, -1.0f, 1248 +1.0f, +1.0f, 1249 }; 1250 1251 const float normalizedCoord[4*2] = 1252 { 1253 0.0f, 0.0f, 1254 0.0f, 1.0f, 1255 1.0f, 0.0f, 1256 1.0f, 1.0f, 1257 }; 1258 1259 const vector<float> texCoord = computeQuadTexCoord(m_currentIteration); 1260 1261 vector<glu::VertexArrayBinding> attrBindings; 1262 attrBindings.push_back(glu::va::Float("a_position", 2, 4, 0, &position[0])); 1263 attrBindings.push_back(glu::va::Float("a_texCoord", (int)texCoord.size()/4, 4, 0, &texCoord[0])); 1264 if (needNormalizedCoordInShader) 1265 attrBindings.push_back(glu::va::Float("a_normalizedCoord", 2, 4, 0, &normalizedCoord[0])); 1266 1267 const deUint16 indices[6] = { 0, 1, 2, 2, 1, 3 }; 1268 1269 gl.useProgram(m_program->getProgram()); 1270 1271 { 1272 const int samplerUniformLocation = gl.getUniformLocation(m_program->getProgram(), "u_sampler"); 1273 TCU_CHECK(samplerUniformLocation >= 0); 1274 gl.uniform1i(samplerUniformLocation, 0); 1275 } 1276 1277 if (needPixelCoordInShader) 1278 { 1279 const int viewportSizeUniformLocation = gl.getUniformLocation(m_program->getProgram(), "u_viewportSize"); 1280 TCU_CHECK(viewportSizeUniformLocation >= 0); 1281 gl.uniform2f(viewportSizeUniformLocation, (float)RENDER_SIZE.x(), (float)RENDER_SIZE.y()); 1282 } 1283 1284 if (texCoord.size() == 2*4) 1285 { 1286 Vec2 texCoordVec[4]; 1287 computeTexCoordVecs(texCoord, texCoordVec); 1288 log << TestLog::Message << "Texture coordinates run from " << texCoordVec[0] << " to " << texCoordVec[3] << TestLog::EndMessage; 1289 } 1290 else if (texCoord.size() == 3*4) 1291 { 1292 Vec3 texCoordVec[4]; 1293 computeTexCoordVecs(texCoord, texCoordVec); 1294 log << TestLog::Message << "Texture coordinates run from " << texCoordVec[0] << " to " << texCoordVec[3] << TestLog::EndMessage; 1295 } 1296 else 1297 DE_ASSERT(false); 1298 1299 glu::draw(renderCtx, m_program->getProgram(), (int)attrBindings.size(), &attrBindings[0], 1300 glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indices), &indices[0])); 1301 } 1302 1303 // Verify result. 1304 1305 { 1306 const tcu::TextureLevel rendered = getPixels(renderCtx, RENDER_SIZE, m_colorBufferFormat); 1307 1308 if (!verify(m_currentIteration, rendered.getAccess())) 1309 { 1310 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Result verification failed"); 1311 return STOP; 1312 } 1313 } 1314 1315 m_currentIteration++; 1316 if (m_currentIteration == (int)getNumIterations()) 1317 { 1318 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 1319 return STOP; 1320 } 1321 else 1322 return CONTINUE; 1323} 1324 1325template <typename TexViewT, typename TexCoordT> 1326bool TextureGatherCase::verify (const ConstPixelBufferAccess& rendered, 1327 const TexViewT& texture, 1328 const TexCoordT (&texCoords)[4], 1329 const GatherArgs& gatherArgs) const 1330{ 1331 TestLog& log = m_testCtx.getLog(); 1332 1333 if (m_mipmapIncomplete) 1334 { 1335 const int componentNdx = de::max(0, gatherArgs.componentNdx); 1336 const Vec4 incompleteColor (0.0f, 0.0f, 0.0f, 1.0f); 1337 const Vec4 refColor (incompleteColor[componentNdx]); 1338 const bool isOk = verifySingleColored(log, rendered, refColor); 1339 1340 if (!isOk) 1341 log << TestLog::Message << "Note: expected color " << refColor << " for all pixels; " 1342 << incompleteColor[componentNdx] << " is component at index " << componentNdx 1343 << " in the color " << incompleteColor << ", which is used for incomplete textures" << TestLog::EndMessage; 1344 1345 return isOk; 1346 } 1347 else 1348 { 1349 DE_ASSERT(m_colorBufferFormat.order == tcu::TextureFormat::RGBA); 1350 DE_ASSERT(m_colorBufferFormat.type == tcu::TextureFormat::UNORM_INT8 || 1351 m_colorBufferFormat.type == tcu::TextureFormat::UNSIGNED_INT8 || 1352 m_colorBufferFormat.type == tcu::TextureFormat::SIGNED_INT8); 1353 1354 const MovePtr<PixelOffsets> pixelOffsets = makePixelOffsetsFunctor(m_gatherType, gatherArgs, getOffsetRange()); 1355 const tcu::PixelFormat pixelFormat = tcu::PixelFormat(8,8,8,8); 1356 const IVec4 colorBits = tcu::max(gls::TextureTestUtil::getBitsVec(pixelFormat) - 1, tcu::IVec4(0)); 1357 const IVec3 coordBits = m_textureType == TEXTURETYPE_2D ? IVec3(20,20,0) 1358 : m_textureType == TEXTURETYPE_CUBE ? IVec3(10,10,10) 1359 : m_textureType == TEXTURETYPE_2D_ARRAY ? IVec3(20,20,20) 1360 : IVec3(-1); 1361 const IVec3 uvwBits = m_textureType == TEXTURETYPE_2D ? IVec3(7,7,0) 1362 : m_textureType == TEXTURETYPE_CUBE ? IVec3(6,6,0) 1363 : m_textureType == TEXTURETYPE_2D_ARRAY ? IVec3(7,7,7) 1364 : IVec3(-1); 1365 tcu::Sampler sampler; 1366 sampler.wrapS = m_wrapS; 1367 sampler.wrapT = m_wrapT; 1368 sampler.compare = m_shadowCompareMode; 1369 1370 if (isDepthFormat(m_textureFormat)) 1371 { 1372 tcu::TexComparePrecision comparePrec; 1373 comparePrec.coordBits = coordBits; 1374 comparePrec.uvwBits = uvwBits; 1375 comparePrec.referenceBits = 16; 1376 comparePrec.resultBits = pixelFormat.redBits-1; 1377 1378 return verifyGatherOffsetsCompare(log, rendered, texture, texCoords, sampler, comparePrec, PixelCompareRefZDefault(RENDER_SIZE), *pixelOffsets); 1379 } 1380 else 1381 { 1382 const int componentNdx = de::max(0, gatherArgs.componentNdx); 1383 1384 if (isUnormFormatType(m_textureFormat.type)) 1385 { 1386 tcu::LookupPrecision lookupPrec; 1387 lookupPrec.colorThreshold = tcu::computeFixedPointThreshold(colorBits); 1388 lookupPrec.coordBits = coordBits; 1389 lookupPrec.uvwBits = uvwBits; 1390 lookupPrec.colorMask = gls::TextureTestUtil::getCompareMask(pixelFormat); 1391 return verifyGatherOffsets<float>(log, rendered, texture, texCoords, sampler, lookupPrec, componentNdx, *pixelOffsets); 1392 } 1393 else if (isUIntFormatType(m_textureFormat.type) || isSIntFormatType(m_textureFormat.type)) 1394 { 1395 tcu::IntLookupPrecision lookupPrec; 1396 lookupPrec.colorThreshold = UVec4(0); 1397 lookupPrec.coordBits = coordBits; 1398 lookupPrec.uvwBits = uvwBits; 1399 lookupPrec.colorMask = gls::TextureTestUtil::getCompareMask(pixelFormat); 1400 1401 if (isUIntFormatType(m_textureFormat.type)) 1402 return verifyGatherOffsets<deUint32>(log, rendered, texture, texCoords, sampler, lookupPrec, componentNdx, *pixelOffsets); 1403 else if (isSIntFormatType(m_textureFormat.type)) 1404 return verifyGatherOffsets<deInt32>(log, rendered, texture, texCoords, sampler, lookupPrec, componentNdx, *pixelOffsets); 1405 else 1406 { 1407 DE_ASSERT(false); 1408 return false; 1409 } 1410 } 1411 else 1412 { 1413 DE_ASSERT(false); 1414 return false; 1415 } 1416 } 1417 } 1418} 1419 1420vector<GatherArgs> generateBasic2DCaseIterations (GatherType gatherType, const tcu::TextureFormat& textureFormat, const IVec2& offsetRange) 1421{ 1422 const int numComponentCases = isDepthFormat(textureFormat) ? 1 : 4+1; // \note For non-depth textures, test explicit components 0 to 3 and implicit component 0. 1423 vector<GatherArgs> result; 1424 1425 for (int componentCaseNdx = 0; componentCaseNdx < numComponentCases; componentCaseNdx++) 1426 { 1427 const int componentNdx = componentCaseNdx - 1; 1428 1429 switch (gatherType) 1430 { 1431 case GATHERTYPE_BASIC: 1432 result.push_back(GatherArgs(componentNdx)); 1433 break; 1434 1435 case GATHERTYPE_OFFSET: 1436 { 1437 const int min = offsetRange.x(); 1438 const int max = offsetRange.y(); 1439 const int hmin = divRoundToZero(min, 2); 1440 const int hmax = divRoundToZero(max, 2); 1441 1442 result.push_back(GatherArgs(componentNdx, IVec2(min, max))); 1443 1444 if (componentCaseNdx == 0) // Don't test all offsets variants for all color components (they should be pretty orthogonal). 1445 { 1446 result.push_back(GatherArgs(componentNdx, IVec2(min, min))); 1447 result.push_back(GatherArgs(componentNdx, IVec2(max, min))); 1448 result.push_back(GatherArgs(componentNdx, IVec2(max, max))); 1449 1450 result.push_back(GatherArgs(componentNdx, IVec2(0, hmax))); 1451 result.push_back(GatherArgs(componentNdx, IVec2(hmin, 0))); 1452 result.push_back(GatherArgs(componentNdx, IVec2(0, 0))); 1453 } 1454 1455 break; 1456 } 1457 1458 case GATHERTYPE_OFFSET_DYNAMIC: 1459 result.push_back(GatherArgs(componentNdx)); 1460 break; 1461 1462 case GATHERTYPE_OFFSETS: 1463 { 1464 const int min = offsetRange.x(); 1465 const int max = offsetRange.y(); 1466 const int hmin = divRoundToZero(min, 2); 1467 const int hmax = divRoundToZero(max, 2); 1468 1469 result.push_back(GatherArgs(componentNdx, 1470 IVec2(min, min), 1471 IVec2(min, max), 1472 IVec2(max, min), 1473 IVec2(max, max))); 1474 1475 if (componentCaseNdx == 0) // Don't test all offsets variants for all color components (they should be pretty orthogonal). 1476 result.push_back(GatherArgs(componentNdx, 1477 IVec2(min, hmax), 1478 IVec2(hmin, max), 1479 IVec2(0, hmax), 1480 IVec2(hmax, 0))); 1481 break; 1482 } 1483 1484 default: 1485 DE_ASSERT(false); 1486 } 1487 } 1488 1489 return result; 1490} 1491 1492class TextureGather2DCase : public TextureGatherCase 1493{ 1494public: 1495 TextureGather2DCase (Context& context, 1496 const char* name, 1497 const char* description, 1498 GatherType gatherType, 1499 OffsetSize offsetSize, 1500 tcu::TextureFormat textureFormat, 1501 tcu::Sampler::CompareMode shadowCompareMode, 1502 tcu::Sampler::WrapMode wrapS, 1503 tcu::Sampler::WrapMode wrapT, 1504 const TextureSwizzle& texSwizzle, 1505 tcu::Sampler::FilterMode minFilter, 1506 tcu::Sampler::FilterMode magFilter, 1507 int baseLevel, 1508 bool mipmapIncomplete, 1509 const IVec2& textureSize) 1510 : TextureGatherCase (context, name, description, TEXTURETYPE_2D, gatherType, offsetSize, textureFormat, shadowCompareMode, wrapS, wrapT, texSwizzle, minFilter, magFilter, baseLevel, mipmapIncomplete) 1511 , m_textureSize (textureSize) 1512 , m_swizzledTexture (tcu::TextureFormat(), 1, 1) 1513 { 1514 } 1515 1516protected: 1517 void generateIterations (void); 1518 void createAndUploadTexture (void); 1519 int getNumIterations (void) const { DE_ASSERT(!m_iterations.empty()); return (int)m_iterations.size(); } 1520 GatherArgs getGatherArgs (int iterationNdx) const { return m_iterations[iterationNdx]; } 1521 vector<float> computeQuadTexCoord (int iterationNdx) const; 1522 bool verify (int iterationNdx, const ConstPixelBufferAccess& rendered) const; 1523 1524private: 1525 const IVec2 m_textureSize; 1526 1527 MovePtr<glu::Texture2D> m_texture; 1528 tcu::Texture2D m_swizzledTexture; 1529 vector<GatherArgs> m_iterations; 1530}; 1531 1532vector<float> TextureGather2DCase::computeQuadTexCoord (int /* iterationNdx */) const 1533{ 1534 vector<float> res; 1535 gls::TextureTestUtil::computeQuadTexCoord2D(res, Vec2(-0.3f, -0.4f), Vec2(1.5f, 1.6f)); 1536 return res; 1537} 1538 1539void TextureGather2DCase::generateIterations (void) 1540{ 1541 DE_ASSERT(m_iterations.empty()); 1542 m_iterations = generateBasic2DCaseIterations(m_gatherType, m_textureFormat, getOffsetRange()); 1543} 1544 1545void TextureGather2DCase::createAndUploadTexture (void) 1546{ 1547 const glu::RenderContext& renderCtx = m_context.getRenderContext(); 1548 const glw::Functions& gl = renderCtx.getFunctions(); 1549 const tcu::TextureFormatInfo texFmtInfo = tcu::getTextureFormatInfo(m_textureFormat); 1550 1551 m_texture = MovePtr<glu::Texture2D>(new glu::Texture2D(renderCtx, glu::getInternalFormat(m_textureFormat), m_textureSize.x(), m_textureSize.y())); 1552 1553 { 1554 tcu::Texture2D& refTexture = m_texture->getRefTexture(); 1555 const int levelBegin = m_baseLevel; 1556 const int levelEnd = isMipmapFilter(m_minFilter) && !m_mipmapIncomplete ? refTexture.getNumLevels() : m_baseLevel+1; 1557 DE_ASSERT(m_baseLevel < refTexture.getNumLevels()); 1558 1559 for (int levelNdx = levelBegin; levelNdx < levelEnd; levelNdx++) 1560 { 1561 refTexture.allocLevel(levelNdx); 1562 const PixelBufferAccess& level = refTexture.getLevel(levelNdx); 1563 fillWithRandomColorTiles(level, texFmtInfo.valueMin, texFmtInfo.valueMax, (deUint32)m_testCtx.getCommandLine().getBaseSeed()); 1564 m_testCtx.getLog() << TestLog::Image("InputTextureLevel" + de::toString(levelNdx), "Input texture, level " + de::toString(levelNdx), level) 1565 << TestLog::Message << "Note: texture level's size is " << IVec2(level.getWidth(), level.getHeight()) << TestLog::EndMessage; 1566 } 1567 1568 swizzleTexture(m_swizzledTexture, refTexture, m_textureSwizzle); 1569 } 1570 1571 gl.activeTexture(GL_TEXTURE0); 1572 m_texture->upload(); 1573} 1574 1575bool TextureGather2DCase::verify (int iterationNdx, const ConstPixelBufferAccess& rendered) const 1576{ 1577 Vec2 texCoords[4]; 1578 computeTexCoordVecs(computeQuadTexCoord(iterationNdx), texCoords); 1579 return TextureGatherCase::verify(rendered, getOneLevelSubView(tcu::Texture2DView(m_swizzledTexture), m_baseLevel), texCoords, m_iterations[iterationNdx]); 1580} 1581 1582class TextureGather2DArrayCase : public TextureGatherCase 1583{ 1584public: 1585 TextureGather2DArrayCase (Context& context, 1586 const char* name, 1587 const char* description, 1588 GatherType gatherType, 1589 OffsetSize offsetSize, 1590 tcu::TextureFormat textureFormat, 1591 tcu::Sampler::CompareMode shadowCompareMode, 1592 tcu::Sampler::WrapMode wrapS, 1593 tcu::Sampler::WrapMode wrapT, 1594 const TextureSwizzle& texSwizzle, 1595 tcu::Sampler::FilterMode minFilter, 1596 tcu::Sampler::FilterMode magFilter, 1597 int baseLevel, 1598 bool mipmapIncomplete, 1599 const IVec3& textureSize) 1600 : TextureGatherCase (context, name, description, TEXTURETYPE_2D_ARRAY, gatherType, offsetSize, textureFormat, shadowCompareMode, wrapS, wrapT, texSwizzle, minFilter, magFilter, baseLevel, mipmapIncomplete) 1601 , m_textureSize (textureSize) 1602 , m_swizzledTexture (tcu::TextureFormat(), 1, 1, 1) 1603 { 1604 } 1605 1606protected: 1607 void generateIterations (void); 1608 void createAndUploadTexture (void); 1609 int getNumIterations (void) const { DE_ASSERT(!m_iterations.empty()); return (int)m_iterations.size(); } 1610 GatherArgs getGatherArgs (int iterationNdx) const { return m_iterations[iterationNdx].gatherArgs; } 1611 vector<float> computeQuadTexCoord (int iterationNdx) const; 1612 bool verify (int iterationNdx, const ConstPixelBufferAccess& rendered) const; 1613 1614private: 1615 struct Iteration 1616 { 1617 GatherArgs gatherArgs; 1618 int layerNdx; 1619 }; 1620 1621 const IVec3 m_textureSize; 1622 1623 MovePtr<glu::Texture2DArray> m_texture; 1624 tcu::Texture2DArray m_swizzledTexture; 1625 vector<Iteration> m_iterations; 1626}; 1627 1628vector<float> TextureGather2DArrayCase::computeQuadTexCoord (int iterationNdx) const 1629{ 1630 vector<float> res; 1631 gls::TextureTestUtil::computeQuadTexCoord2DArray(res, m_iterations[iterationNdx].layerNdx, Vec2(-0.3f, -0.4f), Vec2(1.5f, 1.6f)); 1632 return res; 1633} 1634 1635void TextureGather2DArrayCase::generateIterations (void) 1636{ 1637 DE_ASSERT(m_iterations.empty()); 1638 1639 const vector<GatherArgs> basicIterations = generateBasic2DCaseIterations(m_gatherType, m_textureFormat, getOffsetRange()); 1640 1641 // \note Out-of-bounds layer indices are tested too. 1642 for (int layerNdx = -1; layerNdx < m_textureSize.z()+1; layerNdx++) 1643 { 1644 // Don't duplicate all cases for all layers. 1645 if (layerNdx == 0) 1646 { 1647 for (int basicNdx = 0; basicNdx < (int)basicIterations.size(); basicNdx++) 1648 { 1649 m_iterations.push_back(Iteration()); 1650 m_iterations.back().gatherArgs = basicIterations[basicNdx]; 1651 m_iterations.back().layerNdx = layerNdx; 1652 } 1653 } 1654 else 1655 { 1656 // For other layers than 0, only test one component and one set of offsets per layer. 1657 for (int basicNdx = 0; basicNdx < (int)basicIterations.size(); basicNdx++) 1658 { 1659 if (isDepthFormat(m_textureFormat) || basicIterations[basicNdx].componentNdx == (layerNdx + 2) % 4) 1660 { 1661 m_iterations.push_back(Iteration()); 1662 m_iterations.back().gatherArgs = basicIterations[basicNdx]; 1663 m_iterations.back().layerNdx = layerNdx; 1664 break; 1665 } 1666 } 1667 } 1668 } 1669} 1670 1671void TextureGather2DArrayCase::createAndUploadTexture (void) 1672{ 1673 TestLog& log = m_testCtx.getLog(); 1674 const glu::RenderContext& renderCtx = m_context.getRenderContext(); 1675 const glw::Functions& gl = renderCtx.getFunctions(); 1676 const tcu::TextureFormatInfo texFmtInfo = tcu::getTextureFormatInfo(m_textureFormat); 1677 1678 m_texture = MovePtr<glu::Texture2DArray>(new glu::Texture2DArray(renderCtx, glu::getInternalFormat(m_textureFormat), m_textureSize.x(), m_textureSize.y(), m_textureSize.z())); 1679 1680 { 1681 tcu::Texture2DArray& refTexture = m_texture->getRefTexture(); 1682 const int levelBegin = m_baseLevel; 1683 const int levelEnd = isMipmapFilter(m_minFilter) && !m_mipmapIncomplete ? refTexture.getNumLevels() : m_baseLevel+1; 1684 DE_ASSERT(m_baseLevel < refTexture.getNumLevels()); 1685 1686 for (int levelNdx = levelBegin; levelNdx < levelEnd; levelNdx++) 1687 { 1688 refTexture.allocLevel(levelNdx); 1689 const PixelBufferAccess& level = refTexture.getLevel(levelNdx); 1690 fillWithRandomColorTiles(level, texFmtInfo.valueMin, texFmtInfo.valueMax, (deUint32)m_testCtx.getCommandLine().getBaseSeed()); 1691 1692 log << TestLog::ImageSet("InputTextureLevel", "Input texture, level " + de::toString(levelNdx)); 1693 for (int layerNdx = 0; layerNdx < m_textureSize.z(); layerNdx++) 1694 log << TestLog::Image("InputTextureLevel" + de::toString(layerNdx) + "Layer" + de::toString(layerNdx), 1695 "Layer " + de::toString(layerNdx), 1696 tcu::getSubregion(level, 0, 0, layerNdx, level.getWidth(), level.getHeight(), 1)); 1697 log << TestLog::EndImageSet 1698 << TestLog::Message << "Note: texture level's size is " << IVec3(level.getWidth(), level.getHeight(), level.getDepth()) << TestLog::EndMessage; 1699 } 1700 1701 swizzleTexture(m_swizzledTexture, refTexture, m_textureSwizzle); 1702 } 1703 1704 gl.activeTexture(GL_TEXTURE0); 1705 m_texture->upload(); 1706} 1707 1708bool TextureGather2DArrayCase::verify (int iterationNdx, const ConstPixelBufferAccess& rendered) const 1709{ 1710 Vec3 texCoords[4]; 1711 computeTexCoordVecs(computeQuadTexCoord(iterationNdx), texCoords); 1712 return TextureGatherCase::verify(rendered, getOneLevelSubView(tcu::Texture2DArrayView(m_swizzledTexture), m_baseLevel), texCoords, m_iterations[iterationNdx].gatherArgs); 1713} 1714 1715// \note Cube case always uses just basic textureGather(); offset versions are not defined for cube maps. 1716class TextureGatherCubeCase : public TextureGatherCase 1717{ 1718public: 1719 TextureGatherCubeCase (Context& context, 1720 const char* name, 1721 const char* description, 1722 tcu::TextureFormat textureFormat, 1723 tcu::Sampler::CompareMode shadowCompareMode, 1724 tcu::Sampler::WrapMode wrapS, 1725 tcu::Sampler::WrapMode wrapT, 1726 const TextureSwizzle& texSwizzle, 1727 tcu::Sampler::FilterMode minFilter, 1728 tcu::Sampler::FilterMode magFilter, 1729 int baseLevel, 1730 bool mipmapIncomplete, 1731 int textureSize) 1732 : TextureGatherCase (context, name, description, TEXTURETYPE_CUBE, GATHERTYPE_BASIC, OFFSETSIZE_NONE, textureFormat, shadowCompareMode, wrapS, wrapT, texSwizzle, minFilter, magFilter, baseLevel, mipmapIncomplete) 1733 , m_textureSize (textureSize) 1734 , m_swizzledTexture (tcu::TextureFormat(), 1) 1735 { 1736 } 1737 1738protected: 1739 void generateIterations (void); 1740 void createAndUploadTexture (void); 1741 int getNumIterations (void) const { DE_ASSERT(!m_iterations.empty()); return (int)m_iterations.size(); } 1742 GatherArgs getGatherArgs (int iterationNdx) const { return m_iterations[iterationNdx].gatherArgs; } 1743 vector<float> computeQuadTexCoord (int iterationNdx) const; 1744 bool verify (int iterationNdx, const ConstPixelBufferAccess& rendered) const; 1745 1746private: 1747 struct Iteration 1748 { 1749 GatherArgs gatherArgs; 1750 tcu::CubeFace face; 1751 }; 1752 1753 const int m_textureSize; 1754 1755 MovePtr<glu::TextureCube> m_texture; 1756 tcu::TextureCube m_swizzledTexture; 1757 vector<Iteration> m_iterations; 1758}; 1759 1760vector<float> TextureGatherCubeCase::computeQuadTexCoord (int iterationNdx) const 1761{ 1762 vector<float> res; 1763 gls::TextureTestUtil::computeQuadTexCoordCube(res, m_iterations[iterationNdx].face, Vec2(-1.2f), Vec2(1.2f)); 1764 return res; 1765} 1766 1767void TextureGatherCubeCase::generateIterations (void) 1768{ 1769 DE_ASSERT(m_iterations.empty()); 1770 1771 const vector<GatherArgs> basicIterations = generateBasic2DCaseIterations(m_gatherType, m_textureFormat, getOffsetRange()); 1772 1773 for (int cubeFaceI = 0; cubeFaceI < tcu::CUBEFACE_LAST; cubeFaceI++) 1774 { 1775 const tcu::CubeFace cubeFace = (tcu::CubeFace)cubeFaceI; 1776 1777 // Don't duplicate all cases for all faces. 1778 if (cubeFaceI == 0) 1779 { 1780 for (int basicNdx = 0; basicNdx < (int)basicIterations.size(); basicNdx++) 1781 { 1782 m_iterations.push_back(Iteration()); 1783 m_iterations.back().gatherArgs = basicIterations[basicNdx]; 1784 m_iterations.back().face = cubeFace; 1785 } 1786 } 1787 else 1788 { 1789 // For other faces than first, only test one component per face. 1790 for (int basicNdx = 0; basicNdx < (int)basicIterations.size(); basicNdx++) 1791 { 1792 if (isDepthFormat(m_textureFormat) || basicIterations[basicNdx].componentNdx == cubeFaceI % 4) 1793 { 1794 m_iterations.push_back(Iteration()); 1795 m_iterations.back().gatherArgs = basicIterations[basicNdx]; 1796 m_iterations.back().face = cubeFace; 1797 break; 1798 } 1799 } 1800 } 1801 } 1802} 1803 1804void TextureGatherCubeCase::createAndUploadTexture (void) 1805{ 1806 TestLog& log = m_testCtx.getLog(); 1807 const glu::RenderContext& renderCtx = m_context.getRenderContext(); 1808 const glw::Functions& gl = renderCtx.getFunctions(); 1809 const tcu::TextureFormatInfo texFmtInfo = tcu::getTextureFormatInfo(m_textureFormat); 1810 1811 m_texture = MovePtr<glu::TextureCube>(new glu::TextureCube(renderCtx, glu::getInternalFormat(m_textureFormat), m_textureSize)); 1812 1813 { 1814 tcu::TextureCube& refTexture = m_texture->getRefTexture(); 1815 const int levelBegin = m_baseLevel; 1816 const int levelEnd = isMipmapFilter(m_minFilter) && !m_mipmapIncomplete ? refTexture.getNumLevels() : m_baseLevel+1; 1817 DE_ASSERT(m_baseLevel < refTexture.getNumLevels()); 1818 1819 for (int levelNdx = levelBegin; levelNdx < levelEnd; levelNdx++) 1820 { 1821 log << TestLog::ImageSet("InputTextureLevel" + de::toString(levelNdx), "Input texture, level " + de::toString(levelNdx)); 1822 1823 for (int cubeFaceI = 0; cubeFaceI < tcu::CUBEFACE_LAST; cubeFaceI++) 1824 { 1825 const tcu::CubeFace cubeFace = (tcu::CubeFace)cubeFaceI; 1826 refTexture.allocLevel(cubeFace, levelNdx); 1827 const PixelBufferAccess& levelFace = refTexture.getLevelFace(levelNdx, cubeFace); 1828 fillWithRandomColorTiles(levelFace, texFmtInfo.valueMin, texFmtInfo.valueMax, (deUint32)m_testCtx.getCommandLine().getBaseSeed() ^ (deUint32)cubeFaceI); 1829 1830 m_testCtx.getLog() << TestLog::Image("InputTextureLevel" + de::toString(levelNdx) + "Face" + de::toString((int)cubeFace), 1831 de::toString(cubeFace), 1832 levelFace); 1833 } 1834 1835 log << TestLog::EndImageSet 1836 << TestLog::Message << "Note: texture level's size is " << refTexture.getLevelFace(levelNdx, tcu::CUBEFACE_NEGATIVE_X).getWidth() << TestLog::EndMessage; 1837 } 1838 1839 swizzleTexture(m_swizzledTexture, refTexture, m_textureSwizzle); 1840 } 1841 1842 gl.activeTexture(GL_TEXTURE0); 1843 m_texture->upload(); 1844} 1845 1846bool TextureGatherCubeCase::verify (int iterationNdx, const ConstPixelBufferAccess& rendered) const 1847{ 1848 Vec3 texCoords[4]; 1849 computeTexCoordVecs(computeQuadTexCoord(iterationNdx), texCoords); 1850 return TextureGatherCase::verify(rendered, getOneLevelSubView(tcu::TextureCubeView(m_swizzledTexture), m_baseLevel), texCoords, m_iterations[iterationNdx].gatherArgs); 1851} 1852 1853static inline TextureGatherCase* makeTextureGatherCase (TextureType textureType, 1854 Context& context, 1855 const char* name, 1856 const char* description, 1857 GatherType gatherType, 1858 OffsetSize offsetSize, 1859 tcu::TextureFormat textureFormat, 1860 tcu::Sampler::CompareMode shadowCompareMode, 1861 tcu::Sampler::WrapMode wrapS, 1862 tcu::Sampler::WrapMode wrapT, 1863 const TextureSwizzle& texSwizzle, 1864 tcu::Sampler::FilterMode minFilter, 1865 tcu::Sampler::FilterMode magFilter, 1866 int baseLevel, 1867 const IVec3& textureSize, 1868 bool mipmapIncomplete = false) 1869{ 1870 switch (textureType) 1871 { 1872 case TEXTURETYPE_2D: 1873 return new TextureGather2DCase(context, name, description, gatherType, offsetSize, textureFormat, shadowCompareMode, 1874 wrapS, wrapT, texSwizzle, minFilter, magFilter, baseLevel, mipmapIncomplete, textureSize.swizzle(0, 1)); 1875 1876 case TEXTURETYPE_2D_ARRAY: 1877 return new TextureGather2DArrayCase(context, name, description, gatherType, offsetSize, textureFormat, shadowCompareMode, 1878 wrapS, wrapT, texSwizzle, minFilter, magFilter, baseLevel, mipmapIncomplete, textureSize); 1879 1880 case TEXTURETYPE_CUBE: 1881 DE_ASSERT(gatherType == GATHERTYPE_BASIC); 1882 DE_ASSERT(offsetSize == OFFSETSIZE_NONE); 1883 return new TextureGatherCubeCase(context, name, description, textureFormat, shadowCompareMode, 1884 wrapS, wrapT, texSwizzle, minFilter, magFilter, baseLevel, mipmapIncomplete, textureSize.x()); 1885 1886 default: 1887 DE_ASSERT(false); 1888 return DE_NULL; 1889 } 1890} 1891 1892} // anonymous 1893 1894TextureGatherTests::TextureGatherTests (Context& context) 1895 : TestCaseGroup(context, "gather", "textureGather* tests") 1896{ 1897} 1898 1899static inline const char* compareModeName (tcu::Sampler::CompareMode mode) 1900{ 1901 switch (mode) 1902 { 1903 case tcu::Sampler::COMPAREMODE_LESS: return "less"; 1904 case tcu::Sampler::COMPAREMODE_LESS_OR_EQUAL: return "less_or_equal"; 1905 case tcu::Sampler::COMPAREMODE_GREATER: return "greater"; 1906 case tcu::Sampler::COMPAREMODE_GREATER_OR_EQUAL: return "greater_or_equal"; 1907 case tcu::Sampler::COMPAREMODE_EQUAL: return "equal"; 1908 case tcu::Sampler::COMPAREMODE_NOT_EQUAL: return "not_equal"; 1909 case tcu::Sampler::COMPAREMODE_ALWAYS: return "always"; 1910 case tcu::Sampler::COMPAREMODE_NEVER: return "never"; 1911 default: DE_ASSERT(false); return DE_NULL; 1912 } 1913} 1914 1915void TextureGatherTests::init (void) 1916{ 1917 const struct 1918 { 1919 const char* name; 1920 TextureType type; 1921 } textureTypes[] = 1922 { 1923 { "2d", TEXTURETYPE_2D }, 1924 { "2d_array", TEXTURETYPE_2D_ARRAY }, 1925 { "cube", TEXTURETYPE_CUBE } 1926 }; 1927 1928 const struct 1929 { 1930 const char* name; 1931 tcu::TextureFormat format; 1932 } formats[] = 1933 { 1934 { "rgba8", tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8) }, 1935 { "rgba8ui", tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNSIGNED_INT8) }, 1936 { "rgba8i", tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::SIGNED_INT8) }, 1937 { "depth32f", tcu::TextureFormat(tcu::TextureFormat::D, tcu::TextureFormat::FLOAT) } 1938 }; 1939 1940 const struct 1941 { 1942 const char* name; 1943 IVec3 size; 1944 } textureSizes[] = 1945 { 1946 { "size_pot", IVec3(64, 64, 3) }, 1947 { "size_npot", IVec3(17, 23, 3) } 1948 }; 1949 1950 const struct 1951 { 1952 const char* name; 1953 tcu::Sampler::WrapMode mode; 1954 } wrapModes[] = 1955 { 1956 { "clamp_to_edge", tcu::Sampler::CLAMP_TO_EDGE }, 1957 { "repeat", tcu::Sampler::REPEAT_GL }, 1958 { "mirrored_repeat", tcu::Sampler::MIRRORED_REPEAT_GL } 1959 }; 1960 1961 for (int gatherTypeI = 0; gatherTypeI < GATHERTYPE_LAST; gatherTypeI++) 1962 { 1963 const GatherType gatherType = (GatherType)gatherTypeI; 1964 TestCaseGroup* const gatherTypeGroup = new TestCaseGroup(m_context, gatherTypeName(gatherType), gatherTypeDescription(gatherType)); 1965 addChild(gatherTypeGroup); 1966 1967 for (int offsetSizeI = 0; offsetSizeI < OFFSETSIZE_LAST; offsetSizeI++) 1968 { 1969 const OffsetSize offsetSize = (OffsetSize)offsetSizeI; 1970 if ((gatherType == GATHERTYPE_BASIC) != (offsetSize == OFFSETSIZE_NONE)) 1971 continue; 1972 1973 TestCaseGroup* const offsetSizeGroup = offsetSize == OFFSETSIZE_NONE ? 1974 gatherTypeGroup : 1975 new TestCaseGroup(m_context, 1976 offsetSize == OFFSETSIZE_MINIMUM_REQUIRED ? "min_required_offset" 1977 : offsetSize == OFFSETSIZE_IMPLEMENTATION_MAXIMUM ? "implementation_offset" 1978 : DE_NULL, 1979 offsetSize == OFFSETSIZE_MINIMUM_REQUIRED ? "Use offsets within GL minimum required range" 1980 : offsetSize == OFFSETSIZE_IMPLEMENTATION_MAXIMUM ? "Use offsets within the implementation range" 1981 : DE_NULL); 1982 if (offsetSizeGroup != gatherTypeGroup) 1983 gatherTypeGroup->addChild(offsetSizeGroup); 1984 1985 for (int textureTypeNdx = 0; textureTypeNdx < DE_LENGTH_OF_ARRAY(textureTypes); textureTypeNdx++) 1986 { 1987 const TextureType textureType = textureTypes[textureTypeNdx].type; 1988 1989 if (textureType == TEXTURETYPE_CUBE && gatherType != GATHERTYPE_BASIC) 1990 continue; 1991 1992 TestCaseGroup* const textureTypeGroup = new TestCaseGroup(m_context, textureTypes[textureTypeNdx].name, ""); 1993 offsetSizeGroup->addChild(textureTypeGroup); 1994 1995 for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(formats); formatNdx++) 1996 { 1997 const tcu::TextureFormat& format = formats[formatNdx].format; 1998 TestCaseGroup* const formatGroup = new TestCaseGroup(m_context, formats[formatNdx].name, ""); 1999 textureTypeGroup->addChild(formatGroup); 2000 2001 for (int textureSizeNdx = 0; textureSizeNdx < DE_LENGTH_OF_ARRAY(textureSizes); textureSizeNdx++) 2002 { 2003 const IVec3& textureSize = textureSizes[textureSizeNdx].size; 2004 TestCaseGroup* const textureSizeGroup = new TestCaseGroup(m_context, textureSizes[textureSizeNdx].name, ""); 2005 formatGroup->addChild(textureSizeGroup); 2006 2007 for (int compareModeI = 0; compareModeI < tcu::Sampler::COMPAREMODE_LAST; compareModeI++) 2008 { 2009 const tcu::Sampler::CompareMode compareMode = (tcu::Sampler::CompareMode)compareModeI; 2010 2011 if ((compareMode != tcu::Sampler::COMPAREMODE_NONE) != isDepthFormat(format)) 2012 continue; 2013 2014 if (compareMode != tcu::Sampler::COMPAREMODE_NONE && 2015 compareMode != tcu::Sampler::COMPAREMODE_LESS && 2016 compareMode != tcu::Sampler::COMPAREMODE_GREATER) 2017 continue; 2018 2019 TestCaseGroup* const compareModeGroup = compareMode == tcu::Sampler::COMPAREMODE_NONE ? 2020 textureSizeGroup : 2021 new TestCaseGroup(m_context, 2022 (string() + "compare_" + compareModeName(compareMode)).c_str(), 2023 ""); 2024 if (compareModeGroup != textureSizeGroup) 2025 textureSizeGroup->addChild(compareModeGroup); 2026 2027 for (int wrapCaseNdx = 0; wrapCaseNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapCaseNdx++) 2028 { 2029 const int wrapSNdx = wrapCaseNdx; 2030 const int wrapTNdx = (wrapCaseNdx + 1) % DE_LENGTH_OF_ARRAY(wrapModes); 2031 const tcu::Sampler::WrapMode wrapS = wrapModes[wrapSNdx].mode; 2032 const tcu::Sampler::WrapMode wrapT = wrapModes[wrapTNdx].mode; 2033 2034 const string caseName = string() + wrapModes[wrapSNdx].name + "_" + wrapModes[wrapTNdx].name; 2035 2036 compareModeGroup->addChild(makeTextureGatherCase(textureType, m_context, caseName.c_str(), "", gatherType, offsetSize, format, compareMode, wrapS, wrapT, 2037 s_identityTextureSwizzle, tcu::Sampler::NEAREST, tcu::Sampler::NEAREST, 0, textureSize)); 2038 } 2039 } 2040 } 2041 2042 if (offsetSize != OFFSETSIZE_MINIMUM_REQUIRED) // Don't test all features for both offset size types, as they should be rather orthogonal. 2043 { 2044 if (!isDepthFormat(format)) 2045 { 2046 TestCaseGroup* const swizzleGroup = new TestCaseGroup(m_context, "texture_swizzle", ""); 2047 formatGroup->addChild(swizzleGroup); 2048 2049 DE_STATIC_ASSERT(TEXTURESWIZZLECOMPONENT_R == 0); 2050 for (int swizzleCaseNdx = 0; swizzleCaseNdx < TEXTURESWIZZLECOMPONENT_LAST; swizzleCaseNdx++) 2051 { 2052 TextureSwizzle swizzle; 2053 string caseName; 2054 2055 for (int i = 0; i < 4; i++) 2056 { 2057 swizzle[i] = (TextureSwizzleComponent)((swizzleCaseNdx + i) % (int)TEXTURESWIZZLECOMPONENT_LAST); 2058 caseName += (i > 0 ? "_" : "") + de::toLower(de::toString(swizzle[i])); 2059 } 2060 2061 if (swizzle == s_identityTextureSwizzle) 2062 continue; // Already tested in above cases. 2063 2064 swizzleGroup->addChild(makeTextureGatherCase(textureType, m_context, caseName.c_str(), "", gatherType, offsetSize, format, 2065 tcu::Sampler::COMPAREMODE_NONE, tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL, 2066 swizzle, tcu::Sampler::NEAREST, tcu::Sampler::NEAREST, 0, IVec3(64, 64, 3))); 2067 } 2068 } 2069 2070 { 2071 TestCaseGroup* const filterModeGroup = new TestCaseGroup(m_context, "filter_mode", "Test that filter modes have no effect"); 2072 formatGroup->addChild(filterModeGroup); 2073 2074 const struct 2075 { 2076 const char* name; 2077 tcu::Sampler::FilterMode filter; 2078 } magFilters[] = 2079 { 2080 { "linear", tcu::Sampler::LINEAR }, 2081 { "nearest", tcu::Sampler::NEAREST } 2082 }; 2083 2084 const struct 2085 { 2086 const char* name; 2087 tcu::Sampler::FilterMode filter; 2088 } minFilters[] = 2089 { 2090 // \note Don't test NEAREST here, as it's covered by other cases. 2091 { "linear", tcu::Sampler::LINEAR }, 2092 { "nearest_mipmap_nearest", tcu::Sampler::NEAREST_MIPMAP_NEAREST }, 2093 { "nearest_mipmap_linear", tcu::Sampler::NEAREST_MIPMAP_LINEAR }, 2094 { "linear_mipmap_nearest", tcu::Sampler::LINEAR_MIPMAP_NEAREST }, 2095 { "linear_mipmap_linear", tcu::Sampler::LINEAR_MIPMAP_LINEAR }, 2096 }; 2097 2098 for (int minFilterNdx = 0; minFilterNdx < DE_LENGTH_OF_ARRAY(minFilters); minFilterNdx++) 2099 for (int magFilterNdx = 0; magFilterNdx < DE_LENGTH_OF_ARRAY(magFilters); magFilterNdx++) 2100 { 2101 const tcu::Sampler::FilterMode minFilter = minFilters[minFilterNdx].filter; 2102 const tcu::Sampler::FilterMode magFilter = magFilters[magFilterNdx].filter; 2103 const tcu::Sampler::CompareMode compareMode = isDepthFormat(format) ? tcu::Sampler::COMPAREMODE_LESS : tcu::Sampler::COMPAREMODE_NONE; 2104 2105 if ((isUnormFormatType(format.type) || isDepthFormat(format)) && magFilter == tcu::Sampler::NEAREST) 2106 continue; // Covered by other cases. 2107 if ((isUIntFormatType(format.type) || isSIntFormatType(format.type)) && 2108 (magFilter != tcu::Sampler::NEAREST || minFilter != tcu::Sampler::NEAREST_MIPMAP_NEAREST)) 2109 continue; 2110 2111 const string caseName = string() + "min_" + minFilters[minFilterNdx].name + "_mag_" + magFilters[magFilterNdx].name; 2112 2113 filterModeGroup->addChild(makeTextureGatherCase(textureType, m_context, caseName.c_str(), "", gatherType, offsetSize, format, compareMode, 2114 tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL, s_identityTextureSwizzle, minFilter, magFilter, 0, IVec3(64, 64, 3))); 2115 } 2116 } 2117 2118 { 2119 TestCaseGroup* const baseLevelGroup = new TestCaseGroup(m_context, "base_level", ""); 2120 formatGroup->addChild(baseLevelGroup); 2121 2122 for (int baseLevel = 1; baseLevel <= 2; baseLevel++) 2123 { 2124 const string caseName = "level_" + de::toString(baseLevel); 2125 const tcu::Sampler::CompareMode compareMode = isDepthFormat(format) ? tcu::Sampler::COMPAREMODE_LESS : tcu::Sampler::COMPAREMODE_NONE; 2126 baseLevelGroup->addChild(makeTextureGatherCase(textureType, m_context, caseName.c_str(), "", gatherType, offsetSize, format, 2127 compareMode, tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL, 2128 s_identityTextureSwizzle, tcu::Sampler::NEAREST, tcu::Sampler::NEAREST, baseLevel, IVec3(64, 64, 3))); 2129 } 2130 } 2131 2132 if (!isDepthFormat(format)) // What shadow textures should return for incomplete textures is unclear. 2133 { 2134 TestCaseGroup* const incompleteGroup = new TestCaseGroup(m_context, "incomplete", "Test that textureGather* takes components from (0,0,0,1) for incomplete textures"); 2135 formatGroup->addChild(incompleteGroup); 2136 2137 const tcu::Sampler::CompareMode compareMode = isDepthFormat(format) ? tcu::Sampler::COMPAREMODE_LESS : tcu::Sampler::COMPAREMODE_NONE; 2138 incompleteGroup->addChild(makeTextureGatherCase(textureType, m_context, "mipmap_incomplete", "", gatherType, offsetSize, format, 2139 compareMode, tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL, 2140 s_identityTextureSwizzle, tcu::Sampler::NEAREST_MIPMAP_NEAREST, tcu::Sampler::NEAREST, 0, IVec3(64, 64, 3), 2141 true /* Mipmap-incomplete */)); 2142 } 2143 } 2144 } 2145 } 2146 } 2147 } 2148} 2149 2150} // Functional 2151} // gles31 2152} // deqp 2153