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 48 using glu::ShaderProgram; 49 using tcu::ConstPixelBufferAccess; 50 using tcu::PixelBufferAccess; 51 using tcu::TestLog; 52 using tcu::IVec2; 53 using tcu::IVec3; 54 using tcu::IVec4; 55 using tcu::UVec4; 56 using tcu::Vec2; 57 using tcu::Vec3; 58 using tcu::Vec4; 59 using de::MovePtr; 60 61 using std::string; 62 using std::vector; 63 64 namespace deqp 65 { 66 67 using glu::TextureTestUtil::TextureType; 68 using glu::TextureTestUtil::TEXTURETYPE_2D; 69 using glu::TextureTestUtil::TEXTURETYPE_2D_ARRAY; 70 using glu::TextureTestUtil::TEXTURETYPE_CUBE; 71 72 namespace gles31 73 { 74 namespace Functional 75 { 76 77 namespace 78 { 79 80 // Round-to-zero int division, because pre-c++11 it's somewhat implementation-defined for negative values. 81 static inline int divRoundToZero (int a, int b) 82 { 83 return de::abs(a) / de::abs(b) * deSign32(a) * deSign32(b); 84 } 85 86 static 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 107 static inline bool isDepthFormat (const tcu::TextureFormat& fmt) 108 { 109 return fmt.order == tcu::TextureFormat::D || fmt.order == tcu::TextureFormat::DS; 110 } 111 112 static 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 119 static 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 126 static 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 133 static 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 169 enum 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 181 static 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 195 struct MaybeTextureSwizzle 196 { 197 public: 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 208 private: 209 MaybeTextureSwizzle (void); 210 211 tcu::Vector<TextureSwizzleComponent, 4> m_swizzle; 212 bool m_isSome; 213 }; 214 215 static 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 229 MaybeTextureSwizzle 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 242 MaybeTextureSwizzle 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 255 bool MaybeTextureSwizzle::isSome (void) const 256 { 257 return m_isSome; 258 } 259 260 bool MaybeTextureSwizzle::isNone (void) const 261 { 262 return !m_isSome; 263 } 264 265 bool 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 274 tcu::Vector<TextureSwizzleComponent, 4>& MaybeTextureSwizzle::getSwizzle (void) 275 { 276 return m_swizzle; 277 } 278 279 const tcu::Vector<TextureSwizzleComponent, 4>& MaybeTextureSwizzle::getSwizzle (void) const 280 { 281 return m_swizzle; 282 } 283 284 MaybeTextureSwizzle::MaybeTextureSwizzle (void) 285 : m_swizzle (TEXTURESWIZZLECOMPONENT_LAST, TEXTURESWIZZLECOMPONENT_LAST, TEXTURESWIZZLECOMPONENT_LAST, TEXTURESWIZZLECOMPONENT_LAST) 286 , m_isSome (false) 287 { 288 } 289 290 static 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 304 template <typename T> 305 static 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 319 template <typename T> 320 static 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 330 template <typename T> 331 static 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 342 static 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 359 static 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 371 static 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 383 static 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 399 static tcu::Texture2DView getOneLevelSubView (const tcu::Texture2DView& view, int level) 400 { 401 return tcu::Texture2DView(1, view.getLevels() + level); 402 } 403 404 static tcu::Texture2DArrayView getOneLevelSubView (const tcu::Texture2DArrayView& view, int level) 405 { 406 return tcu::Texture2DArrayView(1, view.getLevels() + level); 407 } 408 409 static 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 419 class PixelOffsets 420 { 421 public: 422 virtual void operator() (const IVec2& pixCoord, IVec2 (&dst)[4]) const = 0; 423 virtual ~PixelOffsets (void) {} 424 }; 425 426 class MultiplePixelOffsets : public PixelOffsets 427 { 428 public: 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 446 private: 447 IVec2 m_offsets[4]; 448 }; 449 450 class SinglePixelOffsets : public MultiplePixelOffsets 451 { 452 public: 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 462 class DynamicSinglePixelOffsets : public PixelOffsets 463 { 464 public: 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 473 private: 474 IVec2 m_offsetRange; 475 }; 476 477 template <typename T> 478 static 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 486 template <int N> 487 static 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(). 497 static 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 507 template <typename ColorScalarType> 508 static 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 513 template <typename ColorScalarType> 514 static 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 519 template <typename ColorScalarType> 520 static 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 527 static 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 532 static 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 537 static 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 544 template <typename PrecType, typename ColorScalarT> 545 static 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 558 static 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 571 template <typename ColorScalarType, typename PrecType, typename TexViewT, typename TexCoordT> 572 static 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 631 class PixelCompareRefZ 632 { 633 public: 634 virtual float operator() (const IVec2& pixCoord) const = 0; 635 }; 636 637 class PixelCompareRefZDefault : public PixelCompareRefZ 638 { 639 public: 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 647 private: 648 IVec2 m_renderSize; 649 }; 650 651 template <typename TexViewT, typename TexCoordT> 652 static 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 708 static 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 744 enum GatherType 745 { 746 GATHERTYPE_BASIC = 0, 747 GATHERTYPE_OFFSET, 748 GATHERTYPE_OFFSET_DYNAMIC, 749 GATHERTYPE_OFFSETS, 750 751 GATHERTYPE_LAST 752 }; 753 754 enum 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 760 static 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 772 static 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 784 static inline bool requireGpuShader5 (GatherType gatherType) 785 { 786 return gatherType == GATHERTYPE_OFFSET_DYNAMIC || gatherType == GATHERTYPE_OFFSETS; 787 } 788 789 struct 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 814 static 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 837 static 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 861 static 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 889 static 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 900 static 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 911 enum OffsetSize 912 { 913 OFFSETSIZE_NONE = 0, 914 OFFSETSIZE_MINIMUM_REQUIRED, 915 OFFSETSIZE_IMPLEMENTATION_MAXIMUM, 916 917 OFFSETSIZE_LAST 918 }; 919 920 static 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 940 class TextureGatherCase : public TestCase 941 { 942 public: 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 965 protected: 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 993 private: 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 1017 const IVec2 TextureGatherCase::RENDER_SIZE = IVec2(64, 64); 1018 1019 TextureGatherCase::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 1065 IVec2 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 1090 glu::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 1112 glu::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 1143 string 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. 1212 glu::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 1231 void 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::getTextureFormatName(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 1326 void 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 1333 TextureGatherCase::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 1449 template <typename TexViewT, typename TexCoordT> 1450 bool 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(glu::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 = glu::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 = glu::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 1544 vector<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 1616 class TextureGather2DCase : public TextureGatherCase 1617 { 1618 public: 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 1640 protected: 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 1648 private: 1649 const IVec2 m_textureSize; 1650 1651 MovePtr<glu::Texture2D> m_texture; 1652 tcu::Texture2D m_swizzledTexture; 1653 vector<GatherArgs> m_iterations; 1654 }; 1655 1656 vector<float> TextureGather2DCase::computeQuadTexCoord (int /* iterationNdx */) const 1657 { 1658 vector<float> res; 1659 glu::TextureTestUtil::computeQuadTexCoord2D(res, Vec2(-0.3f, -0.4f), Vec2(1.5f, 1.6f)); 1660 return res; 1661 } 1662 1663 void TextureGather2DCase::generateIterations (void) 1664 { 1665 DE_ASSERT(m_iterations.empty()); 1666 m_iterations = generateBasic2DCaseIterations(m_gatherType, m_textureFormat, getOffsetRange()); 1667 } 1668 1669 void 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 1699 bool 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 1706 class TextureGather2DArrayCase : public TextureGatherCase 1707 { 1708 public: 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 1730 protected: 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 1738 private: 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 1752 vector<float> TextureGather2DArrayCase::computeQuadTexCoord (int iterationNdx) const 1753 { 1754 vector<float> res; 1755 glu::TextureTestUtil::computeQuadTexCoord2DArray(res, m_iterations[iterationNdx].layerNdx, Vec2(-0.3f, -0.4f), Vec2(1.5f, 1.6f)); 1756 return res; 1757 } 1758 1759 void 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 1795 void 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 1832 bool 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. 1840 class TextureGatherCubeCase : public TextureGatherCase 1841 { 1842 public: 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 1862 protected: 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 1870 private: 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 1884 vector<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 glu::TextureTestUtil::computeQuadTexCoordCube(res, m_iterations[iterationNdx].face, minC, maxC); 1891 return res; 1892 } 1893 1894 void 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 1931 void 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 1973 bool 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 1980 static 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 2021 TextureGatherTests::TextureGatherTests (Context& context) 2022 : TestCaseGroup(context, "gather", "textureGather* tests") 2023 { 2024 } 2025 2026 static 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 2042 void 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 // What shadow textures should return for incomplete textures is unclear. 2271 // Integer and unsigned integer lookups from incomplete textures return undefined values. 2272 if (!isDepthFormat(format) && !isSIntFormatType(format.type) && !isUIntFormatType(format.type)) 2273 { 2274 TestCaseGroup* const incompleteGroup = new TestCaseGroup(m_context, "incomplete", "Test that textureGather* takes components from (0,0,0,1) for incomplete textures"); 2275 formatGroup->addChild(incompleteGroup); 2276 2277 const tcu::Sampler::CompareMode compareMode = isDepthFormat(format) ? tcu::Sampler::COMPAREMODE_LESS : tcu::Sampler::COMPAREMODE_NONE; 2278 incompleteGroup->addChild(makeTextureGatherCase(textureType, m_context, "mipmap_incomplete", "", gatherType, offsetSize, format, 2279 compareMode, tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL, 2280 MaybeTextureSwizzle::createNoneTextureSwizzle(), tcu::Sampler::NEAREST_MIPMAP_NEAREST, tcu::Sampler::NEAREST, 2281 0, IVec3(64, 64, 3), GATHERCASE_MIPMAP_INCOMPLETE)); 2282 } 2283 } 2284 } 2285 } 2286 } 2287 } 2288 } 2289 2290 } // Functional 2291 } // gles31 2292 } // deqp 2293