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