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 gls::TextureTestUtil::TextureType; 68 using gls::TextureTestUtil::TEXTURETYPE_2D; 69 using gls::TextureTestUtil::TEXTURETYPE_2D_ARRAY; 70 using gls::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::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 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 tcu::IVec2 renderSize = RENDER_SIZE; 1339 const glw::Functions& gl = renderCtx.getFunctions(); 1340 const GatherArgs& gatherArgs = getGatherArgs(m_currentIteration); 1341 const string refZExpr = "v_normalizedCoord.x"; 1342 const bool needPixelCoordInShader = m_gatherType == GATHERTYPE_OFFSET_DYNAMIC; 1343 const bool needNormalizedCoordInShader = needPixelCoordInShader || isDepthFormat(m_textureFormat); 1344 1345 // Generate a program appropriate for this iteration. 1346 1347 m_program = MovePtr<ShaderProgram>(new ShaderProgram(renderCtx, genProgramSources(m_gatherType, m_textureType, m_textureFormat, gatherArgs, refZExpr, getOffsetRange()))); 1348 if (m_currentIteration == 0) 1349 m_testCtx.getLog() << *m_program; 1350 else 1351 m_testCtx.getLog() << TestLog::Message << "Using a program similar to the previous one, except with a gather function call as follows:\n" 1352 << genGatherFuncCall(m_gatherType, m_textureFormat, gatherArgs, refZExpr, getOffsetRange(), 0) 1353 << TestLog::EndMessage; 1354 if (!m_program->isOk()) 1355 { 1356 if (m_currentIteration != 0) 1357 m_testCtx.getLog() << *m_program; 1358 TCU_FAIL("Failed to build program"); 1359 } 1360 1361 // Render. 1362 1363 gl.viewport(0, 0, RENDER_SIZE.x(), RENDER_SIZE.y()); 1364 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f); 1365 gl.clear(GL_COLOR_BUFFER_BIT); 1366 1367 { 1368 const float position[4*2] = 1369 { 1370 -1.0f, -1.0f, 1371 -1.0f, +1.0f, 1372 +1.0f, -1.0f, 1373 +1.0f, +1.0f, 1374 }; 1375 1376 const float normalizedCoord[4*2] = 1377 { 1378 0.0f, 0.0f, 1379 0.0f, 1.0f, 1380 1.0f, 0.0f, 1381 1.0f, 1.0f, 1382 }; 1383 1384 const vector<float> texCoord = computeQuadTexCoord(m_currentIteration); 1385 1386 vector<glu::VertexArrayBinding> attrBindings; 1387 attrBindings.push_back(glu::va::Float("a_position", 2, 4, 0, &position[0])); 1388 attrBindings.push_back(glu::va::Float("a_texCoord", (int)texCoord.size()/4, 4, 0, &texCoord[0])); 1389 if (needNormalizedCoordInShader) 1390 attrBindings.push_back(glu::va::Float("a_normalizedCoord", 2, 4, 0, &normalizedCoord[0])); 1391 1392 const deUint16 indices[6] = { 0, 1, 2, 2, 1, 3 }; 1393 1394 gl.useProgram(m_program->getProgram()); 1395 1396 { 1397 const int samplerUniformLocation = gl.getUniformLocation(m_program->getProgram(), "u_sampler"); 1398 TCU_CHECK(samplerUniformLocation >= 0); 1399 gl.uniform1i(samplerUniformLocation, 0); 1400 } 1401 1402 if (needPixelCoordInShader) 1403 { 1404 const int viewportSizeUniformLocation = gl.getUniformLocation(m_program->getProgram(), "u_viewportSize"); 1405 TCU_CHECK(viewportSizeUniformLocation >= 0); 1406 gl.uniform2f(viewportSizeUniformLocation, (float)RENDER_SIZE.x(), (float)RENDER_SIZE.y()); 1407 } 1408 1409 if (texCoord.size() == 2*4) 1410 { 1411 Vec2 texCoordVec[4]; 1412 computeTexCoordVecs(texCoord, texCoordVec); 1413 log << TestLog::Message << "Texture coordinates run from " << texCoordVec[0] << " to " << texCoordVec[3] << TestLog::EndMessage; 1414 } 1415 else if (texCoord.size() == 3*4) 1416 { 1417 Vec3 texCoordVec[4]; 1418 computeTexCoordVecs(texCoord, texCoordVec); 1419 log << TestLog::Message << "Texture coordinates run from " << texCoordVec[0] << " to " << texCoordVec[3] << TestLog::EndMessage; 1420 } 1421 else 1422 DE_ASSERT(false); 1423 1424 glu::draw(renderCtx, m_program->getProgram(), (int)attrBindings.size(), &attrBindings[0], 1425 glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indices), &indices[0])); 1426 } 1427 1428 // Verify result. 1429 1430 { 1431 const tcu::TextureLevel rendered = getPixels(renderCtx, RENDER_SIZE, m_colorBufferFormat); 1432 1433 if (!verify(m_currentIteration, rendered.getAccess())) 1434 { 1435 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Result verification failed"); 1436 return STOP; 1437 } 1438 } 1439 1440 m_currentIteration++; 1441 if (m_currentIteration == (int)getNumIterations()) 1442 { 1443 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 1444 return STOP; 1445 } 1446 else 1447 return CONTINUE; 1448 } 1449 1450 template <typename TexViewT, typename TexCoordT> 1451 bool TextureGatherCase::verify (const ConstPixelBufferAccess& rendered, 1452 const TexViewT& texture, 1453 const TexCoordT (&texCoords)[4], 1454 const GatherArgs& gatherArgs) const 1455 { 1456 TestLog& log = m_testCtx.getLog(); 1457 1458 if (m_flags & GATHERCASE_MIPMAP_INCOMPLETE) 1459 { 1460 const int componentNdx = de::max(0, gatherArgs.componentNdx); 1461 const Vec4 incompleteColor (0.0f, 0.0f, 0.0f, 1.0f); 1462 const Vec4 refColor (incompleteColor[componentNdx]); 1463 const bool isOk = verifySingleColored(log, rendered, refColor); 1464 1465 if (!isOk) 1466 log << TestLog::Message << "Note: expected color " << refColor << " for all pixels; " 1467 << incompleteColor[componentNdx] << " is component at index " << componentNdx 1468 << " in the color " << incompleteColor << ", which is used for incomplete textures" << TestLog::EndMessage; 1469 1470 return isOk; 1471 } 1472 else 1473 { 1474 DE_ASSERT(m_colorBufferFormat.order == tcu::TextureFormat::RGBA); 1475 DE_ASSERT(m_colorBufferFormat.type == tcu::TextureFormat::UNORM_INT8 || 1476 m_colorBufferFormat.type == tcu::TextureFormat::UNSIGNED_INT8 || 1477 m_colorBufferFormat.type == tcu::TextureFormat::SIGNED_INT8); 1478 1479 const MovePtr<PixelOffsets> pixelOffsets = makePixelOffsetsFunctor(m_gatherType, gatherArgs, getOffsetRange()); 1480 const tcu::PixelFormat pixelFormat = tcu::PixelFormat(8,8,8,8); 1481 const IVec4 colorBits = tcu::max(gls::TextureTestUtil::getBitsVec(pixelFormat) - 1, tcu::IVec4(0)); 1482 const IVec3 coordBits = m_textureType == TEXTURETYPE_2D ? IVec3(20,20,0) 1483 : m_textureType == TEXTURETYPE_CUBE ? IVec3(10,10,10) 1484 : m_textureType == TEXTURETYPE_2D_ARRAY ? IVec3(20,20,20) 1485 : IVec3(-1); 1486 const IVec3 uvwBits = m_textureType == TEXTURETYPE_2D ? IVec3(7,7,0) 1487 : m_textureType == TEXTURETYPE_CUBE ? IVec3(6,6,0) 1488 : m_textureType == TEXTURETYPE_2D_ARRAY ? IVec3(7,7,7) 1489 : IVec3(-1); 1490 tcu::Sampler sampler; 1491 sampler.wrapS = m_wrapS; 1492 sampler.wrapT = m_wrapT; 1493 sampler.compare = m_shadowCompareMode; 1494 1495 if (isDepthFormat(m_textureFormat)) 1496 { 1497 tcu::TexComparePrecision comparePrec; 1498 comparePrec.coordBits = coordBits; 1499 comparePrec.uvwBits = uvwBits; 1500 comparePrec.referenceBits = 16; 1501 comparePrec.resultBits = pixelFormat.redBits-1; 1502 1503 return verifyGatherOffsetsCompare(log, rendered, texture, texCoords, sampler, comparePrec, PixelCompareRefZDefault(RENDER_SIZE), *pixelOffsets); 1504 } 1505 else 1506 { 1507 const int componentNdx = de::max(0, gatherArgs.componentNdx); 1508 1509 if (isUnormFormatType(m_textureFormat.type)) 1510 { 1511 tcu::LookupPrecision lookupPrec; 1512 lookupPrec.colorThreshold = tcu::computeFixedPointThreshold(colorBits); 1513 lookupPrec.coordBits = coordBits; 1514 lookupPrec.uvwBits = uvwBits; 1515 lookupPrec.colorMask = gls::TextureTestUtil::getCompareMask(pixelFormat); 1516 return verifyGatherOffsets<float>(log, rendered, texture, texCoords, sampler, lookupPrec, componentNdx, *pixelOffsets); 1517 } 1518 else if (isUIntFormatType(m_textureFormat.type) || isSIntFormatType(m_textureFormat.type)) 1519 { 1520 tcu::IntLookupPrecision lookupPrec; 1521 lookupPrec.colorThreshold = UVec4(0); 1522 lookupPrec.coordBits = coordBits; 1523 lookupPrec.uvwBits = uvwBits; 1524 lookupPrec.colorMask = gls::TextureTestUtil::getCompareMask(pixelFormat); 1525 1526 if (isUIntFormatType(m_textureFormat.type)) 1527 return verifyGatherOffsets<deUint32>(log, rendered, texture, texCoords, sampler, lookupPrec, componentNdx, *pixelOffsets); 1528 else if (isSIntFormatType(m_textureFormat.type)) 1529 return verifyGatherOffsets<deInt32>(log, rendered, texture, texCoords, sampler, lookupPrec, componentNdx, *pixelOffsets); 1530 else 1531 { 1532 DE_ASSERT(false); 1533 return false; 1534 } 1535 } 1536 else 1537 { 1538 DE_ASSERT(false); 1539 return false; 1540 } 1541 } 1542 } 1543 } 1544 1545 vector<GatherArgs> generateBasic2DCaseIterations (GatherType gatherType, const tcu::TextureFormat& textureFormat, const IVec2& offsetRange) 1546 { 1547 const int numComponentCases = isDepthFormat(textureFormat) ? 1 : 4+1; // \note For non-depth textures, test explicit components 0 to 3 and implicit component 0. 1548 vector<GatherArgs> result; 1549 1550 for (int componentCaseNdx = 0; componentCaseNdx < numComponentCases; componentCaseNdx++) 1551 { 1552 const int componentNdx = componentCaseNdx - 1; 1553 1554 switch (gatherType) 1555 { 1556 case GATHERTYPE_BASIC: 1557 result.push_back(GatherArgs(componentNdx)); 1558 break; 1559 1560 case GATHERTYPE_OFFSET: 1561 { 1562 const int min = offsetRange.x(); 1563 const int max = offsetRange.y(); 1564 const int hmin = divRoundToZero(min, 2); 1565 const int hmax = divRoundToZero(max, 2); 1566 1567 result.push_back(GatherArgs(componentNdx, IVec2(min, max))); 1568 1569 if (componentCaseNdx == 0) // Don't test all offsets variants for all color components (they should be pretty orthogonal). 1570 { 1571 result.push_back(GatherArgs(componentNdx, IVec2(min, min))); 1572 result.push_back(GatherArgs(componentNdx, IVec2(max, min))); 1573 result.push_back(GatherArgs(componentNdx, IVec2(max, max))); 1574 1575 result.push_back(GatherArgs(componentNdx, IVec2(0, hmax))); 1576 result.push_back(GatherArgs(componentNdx, IVec2(hmin, 0))); 1577 result.push_back(GatherArgs(componentNdx, IVec2(0, 0))); 1578 } 1579 1580 break; 1581 } 1582 1583 case GATHERTYPE_OFFSET_DYNAMIC: 1584 result.push_back(GatherArgs(componentNdx)); 1585 break; 1586 1587 case GATHERTYPE_OFFSETS: 1588 { 1589 const int min = offsetRange.x(); 1590 const int max = offsetRange.y(); 1591 const int hmin = divRoundToZero(min, 2); 1592 const int hmax = divRoundToZero(max, 2); 1593 1594 result.push_back(GatherArgs(componentNdx, 1595 IVec2(min, min), 1596 IVec2(min, max), 1597 IVec2(max, min), 1598 IVec2(max, max))); 1599 1600 if (componentCaseNdx == 0) // Don't test all offsets variants for all color components (they should be pretty orthogonal). 1601 result.push_back(GatherArgs(componentNdx, 1602 IVec2(min, hmax), 1603 IVec2(hmin, max), 1604 IVec2(0, hmax), 1605 IVec2(hmax, 0))); 1606 break; 1607 } 1608 1609 default: 1610 DE_ASSERT(false); 1611 } 1612 } 1613 1614 return result; 1615 } 1616 1617 class TextureGather2DCase : public TextureGatherCase 1618 { 1619 public: 1620 TextureGather2DCase (Context& context, 1621 const char* name, 1622 const char* description, 1623 GatherType gatherType, 1624 OffsetSize offsetSize, 1625 tcu::TextureFormat textureFormat, 1626 tcu::Sampler::CompareMode shadowCompareMode, 1627 tcu::Sampler::WrapMode wrapS, 1628 tcu::Sampler::WrapMode wrapT, 1629 const MaybeTextureSwizzle& texSwizzle, 1630 tcu::Sampler::FilterMode minFilter, 1631 tcu::Sampler::FilterMode magFilter, 1632 int baseLevel, 1633 deUint32 flags, 1634 const IVec2& textureSize) 1635 : TextureGatherCase (context, name, description, TEXTURETYPE_2D, gatherType, offsetSize, textureFormat, shadowCompareMode, wrapS, wrapT, texSwizzle, minFilter, magFilter, baseLevel, flags) 1636 , m_textureSize (textureSize) 1637 , m_swizzledTexture (tcu::TextureFormat(), 1, 1) 1638 { 1639 } 1640 1641 protected: 1642 void generateIterations (void); 1643 void createAndUploadTexture (void); 1644 int getNumIterations (void) const { DE_ASSERT(!m_iterations.empty()); return (int)m_iterations.size(); } 1645 GatherArgs getGatherArgs (int iterationNdx) const { return m_iterations[iterationNdx]; } 1646 vector<float> computeQuadTexCoord (int iterationNdx) const; 1647 bool verify (int iterationNdx, const ConstPixelBufferAccess& rendered) const; 1648 1649 private: 1650 const IVec2 m_textureSize; 1651 1652 MovePtr<glu::Texture2D> m_texture; 1653 tcu::Texture2D m_swizzledTexture; 1654 vector<GatherArgs> m_iterations; 1655 }; 1656 1657 vector<float> TextureGather2DCase::computeQuadTexCoord (int /* iterationNdx */) const 1658 { 1659 vector<float> res; 1660 gls::TextureTestUtil::computeQuadTexCoord2D(res, Vec2(-0.3f, -0.4f), Vec2(1.5f, 1.6f)); 1661 return res; 1662 } 1663 1664 void TextureGather2DCase::generateIterations (void) 1665 { 1666 DE_ASSERT(m_iterations.empty()); 1667 m_iterations = generateBasic2DCaseIterations(m_gatherType, m_textureFormat, getOffsetRange()); 1668 } 1669 1670 void TextureGather2DCase::createAndUploadTexture (void) 1671 { 1672 const glu::RenderContext& renderCtx = m_context.getRenderContext(); 1673 const glw::Functions& gl = renderCtx.getFunctions(); 1674 const tcu::TextureFormatInfo texFmtInfo = tcu::getTextureFormatInfo(m_textureFormat); 1675 1676 m_texture = MovePtr<glu::Texture2D>(new glu::Texture2D(renderCtx, glu::getInternalFormat(m_textureFormat), m_textureSize.x(), m_textureSize.y())); 1677 1678 { 1679 tcu::Texture2D& refTexture = m_texture->getRefTexture(); 1680 const int levelBegin = m_baseLevel; 1681 const int levelEnd = isMipmapFilter(m_minFilter) && !(m_flags & GATHERCASE_MIPMAP_INCOMPLETE) ? refTexture.getNumLevels() : m_baseLevel+1; 1682 DE_ASSERT(m_baseLevel < refTexture.getNumLevels()); 1683 1684 for (int levelNdx = levelBegin; levelNdx < levelEnd; levelNdx++) 1685 { 1686 refTexture.allocLevel(levelNdx); 1687 const PixelBufferAccess& level = refTexture.getLevel(levelNdx); 1688 fillWithRandomColorTiles(level, texFmtInfo.valueMin, texFmtInfo.valueMax, (deUint32)m_testCtx.getCommandLine().getBaseSeed()); 1689 m_testCtx.getLog() << TestLog::Image("InputTextureLevel" + de::toString(levelNdx), "Input texture, level " + de::toString(levelNdx), level) 1690 << TestLog::Message << "Note: texture level's size is " << IVec2(level.getWidth(), level.getHeight()) << TestLog::EndMessage; 1691 } 1692 1693 swizzleTexture(m_swizzledTexture, refTexture, m_textureSwizzle); 1694 } 1695 1696 gl.activeTexture(GL_TEXTURE0); 1697 m_texture->upload(); 1698 } 1699 1700 bool TextureGather2DCase::verify (int iterationNdx, const ConstPixelBufferAccess& rendered) const 1701 { 1702 Vec2 texCoords[4]; 1703 computeTexCoordVecs(computeQuadTexCoord(iterationNdx), texCoords); 1704 return TextureGatherCase::verify(rendered, getOneLevelSubView(tcu::Texture2DView(m_swizzledTexture), m_baseLevel), texCoords, m_iterations[iterationNdx]); 1705 } 1706 1707 class TextureGather2DArrayCase : public TextureGatherCase 1708 { 1709 public: 1710 TextureGather2DArrayCase (Context& context, 1711 const char* name, 1712 const char* description, 1713 GatherType gatherType, 1714 OffsetSize offsetSize, 1715 tcu::TextureFormat textureFormat, 1716 tcu::Sampler::CompareMode shadowCompareMode, 1717 tcu::Sampler::WrapMode wrapS, 1718 tcu::Sampler::WrapMode wrapT, 1719 const MaybeTextureSwizzle& texSwizzle, 1720 tcu::Sampler::FilterMode minFilter, 1721 tcu::Sampler::FilterMode magFilter, 1722 int baseLevel, 1723 deUint32 flags, 1724 const IVec3& textureSize) 1725 : TextureGatherCase (context, name, description, TEXTURETYPE_2D_ARRAY, gatherType, offsetSize, textureFormat, shadowCompareMode, wrapS, wrapT, texSwizzle, minFilter, magFilter, baseLevel, flags) 1726 , m_textureSize (textureSize) 1727 , m_swizzledTexture (tcu::TextureFormat(), 1, 1, 1) 1728 { 1729 } 1730 1731 protected: 1732 void generateIterations (void); 1733 void createAndUploadTexture (void); 1734 int getNumIterations (void) const { DE_ASSERT(!m_iterations.empty()); return (int)m_iterations.size(); } 1735 GatherArgs getGatherArgs (int iterationNdx) const { return m_iterations[iterationNdx].gatherArgs; } 1736 vector<float> computeQuadTexCoord (int iterationNdx) const; 1737 bool verify (int iterationNdx, const ConstPixelBufferAccess& rendered) const; 1738 1739 private: 1740 struct Iteration 1741 { 1742 GatherArgs gatherArgs; 1743 int layerNdx; 1744 }; 1745 1746 const IVec3 m_textureSize; 1747 1748 MovePtr<glu::Texture2DArray> m_texture; 1749 tcu::Texture2DArray m_swizzledTexture; 1750 vector<Iteration> m_iterations; 1751 }; 1752 1753 vector<float> TextureGather2DArrayCase::computeQuadTexCoord (int iterationNdx) const 1754 { 1755 vector<float> res; 1756 gls::TextureTestUtil::computeQuadTexCoord2DArray(res, m_iterations[iterationNdx].layerNdx, Vec2(-0.3f, -0.4f), Vec2(1.5f, 1.6f)); 1757 return res; 1758 } 1759 1760 void TextureGather2DArrayCase::generateIterations (void) 1761 { 1762 DE_ASSERT(m_iterations.empty()); 1763 1764 const vector<GatherArgs> basicIterations = generateBasic2DCaseIterations(m_gatherType, m_textureFormat, getOffsetRange()); 1765 1766 // \note Out-of-bounds layer indices are tested too. 1767 for (int layerNdx = -1; layerNdx < m_textureSize.z()+1; layerNdx++) 1768 { 1769 // Don't duplicate all cases for all layers. 1770 if (layerNdx == 0) 1771 { 1772 for (int basicNdx = 0; basicNdx < (int)basicIterations.size(); basicNdx++) 1773 { 1774 m_iterations.push_back(Iteration()); 1775 m_iterations.back().gatherArgs = basicIterations[basicNdx]; 1776 m_iterations.back().layerNdx = layerNdx; 1777 } 1778 } 1779 else 1780 { 1781 // For other layers than 0, only test one component and one set of offsets per layer. 1782 for (int basicNdx = 0; basicNdx < (int)basicIterations.size(); basicNdx++) 1783 { 1784 if (isDepthFormat(m_textureFormat) || basicIterations[basicNdx].componentNdx == (layerNdx + 2) % 4) 1785 { 1786 m_iterations.push_back(Iteration()); 1787 m_iterations.back().gatherArgs = basicIterations[basicNdx]; 1788 m_iterations.back().layerNdx = layerNdx; 1789 break; 1790 } 1791 } 1792 } 1793 } 1794 } 1795 1796 void TextureGather2DArrayCase::createAndUploadTexture (void) 1797 { 1798 TestLog& log = m_testCtx.getLog(); 1799 const glu::RenderContext& renderCtx = m_context.getRenderContext(); 1800 const glw::Functions& gl = renderCtx.getFunctions(); 1801 const tcu::TextureFormatInfo texFmtInfo = tcu::getTextureFormatInfo(m_textureFormat); 1802 1803 m_texture = MovePtr<glu::Texture2DArray>(new glu::Texture2DArray(renderCtx, glu::getInternalFormat(m_textureFormat), m_textureSize.x(), m_textureSize.y(), m_textureSize.z())); 1804 1805 { 1806 tcu::Texture2DArray& refTexture = m_texture->getRefTexture(); 1807 const int levelBegin = m_baseLevel; 1808 const int levelEnd = isMipmapFilter(m_minFilter) && !(m_flags & GATHERCASE_MIPMAP_INCOMPLETE) ? refTexture.getNumLevels() : m_baseLevel+1; 1809 DE_ASSERT(m_baseLevel < refTexture.getNumLevels()); 1810 1811 for (int levelNdx = levelBegin; levelNdx < levelEnd; levelNdx++) 1812 { 1813 refTexture.allocLevel(levelNdx); 1814 const PixelBufferAccess& level = refTexture.getLevel(levelNdx); 1815 fillWithRandomColorTiles(level, texFmtInfo.valueMin, texFmtInfo.valueMax, (deUint32)m_testCtx.getCommandLine().getBaseSeed()); 1816 1817 log << TestLog::ImageSet("InputTextureLevel", "Input texture, level " + de::toString(levelNdx)); 1818 for (int layerNdx = 0; layerNdx < m_textureSize.z(); layerNdx++) 1819 log << TestLog::Image("InputTextureLevel" + de::toString(layerNdx) + "Layer" + de::toString(layerNdx), 1820 "Layer " + de::toString(layerNdx), 1821 tcu::getSubregion(level, 0, 0, layerNdx, level.getWidth(), level.getHeight(), 1)); 1822 log << TestLog::EndImageSet 1823 << TestLog::Message << "Note: texture level's size is " << IVec3(level.getWidth(), level.getHeight(), level.getDepth()) << TestLog::EndMessage; 1824 } 1825 1826 swizzleTexture(m_swizzledTexture, refTexture, m_textureSwizzle); 1827 } 1828 1829 gl.activeTexture(GL_TEXTURE0); 1830 m_texture->upload(); 1831 } 1832 1833 bool TextureGather2DArrayCase::verify (int iterationNdx, const ConstPixelBufferAccess& rendered) const 1834 { 1835 Vec3 texCoords[4]; 1836 computeTexCoordVecs(computeQuadTexCoord(iterationNdx), texCoords); 1837 return TextureGatherCase::verify(rendered, getOneLevelSubView(tcu::Texture2DArrayView(m_swizzledTexture), m_baseLevel), texCoords, m_iterations[iterationNdx].gatherArgs); 1838 } 1839 1840 // \note Cube case always uses just basic textureGather(); offset versions are not defined for cube maps. 1841 class TextureGatherCubeCase : public TextureGatherCase 1842 { 1843 public: 1844 TextureGatherCubeCase (Context& context, 1845 const char* name, 1846 const char* description, 1847 tcu::TextureFormat textureFormat, 1848 tcu::Sampler::CompareMode shadowCompareMode, 1849 tcu::Sampler::WrapMode wrapS, 1850 tcu::Sampler::WrapMode wrapT, 1851 const MaybeTextureSwizzle& texSwizzle, 1852 tcu::Sampler::FilterMode minFilter, 1853 tcu::Sampler::FilterMode magFilter, 1854 int baseLevel, 1855 deUint32 flags, 1856 int textureSize) 1857 : TextureGatherCase (context, name, description, TEXTURETYPE_CUBE, GATHERTYPE_BASIC, OFFSETSIZE_NONE, textureFormat, shadowCompareMode, wrapS, wrapT, texSwizzle, minFilter, magFilter, baseLevel, flags) 1858 , m_textureSize (textureSize) 1859 , m_swizzledTexture (tcu::TextureFormat(), 1) 1860 { 1861 } 1862 1863 protected: 1864 void generateIterations (void); 1865 void createAndUploadTexture (void); 1866 int getNumIterations (void) const { DE_ASSERT(!m_iterations.empty()); return (int)m_iterations.size(); } 1867 GatherArgs getGatherArgs (int iterationNdx) const { return m_iterations[iterationNdx].gatherArgs; } 1868 vector<float> computeQuadTexCoord (int iterationNdx) const; 1869 bool verify (int iterationNdx, const ConstPixelBufferAccess& rendered) const; 1870 1871 private: 1872 struct Iteration 1873 { 1874 GatherArgs gatherArgs; 1875 tcu::CubeFace face; 1876 }; 1877 1878 const int m_textureSize; 1879 1880 MovePtr<glu::TextureCube> m_texture; 1881 tcu::TextureCube m_swizzledTexture; 1882 vector<Iteration> m_iterations; 1883 }; 1884 1885 vector<float> TextureGatherCubeCase::computeQuadTexCoord (int iterationNdx) const 1886 { 1887 const bool corners = (m_flags & GATHERCASE_DONT_SAMPLE_CUBE_CORNERS) == 0; 1888 const Vec2 minC = corners ? Vec2(-1.2f) : Vec2(-0.6f, -1.2f); 1889 const Vec2 maxC = corners ? Vec2( 1.2f) : Vec2( 0.6f, 1.2f); 1890 vector<float> res; 1891 gls::TextureTestUtil::computeQuadTexCoordCube(res, m_iterations[iterationNdx].face, minC, maxC); 1892 return res; 1893 } 1894 1895 void TextureGatherCubeCase::generateIterations (void) 1896 { 1897 DE_ASSERT(m_iterations.empty()); 1898 1899 const vector<GatherArgs> basicIterations = generateBasic2DCaseIterations(m_gatherType, m_textureFormat, getOffsetRange()); 1900 1901 for (int cubeFaceI = 0; cubeFaceI < tcu::CUBEFACE_LAST; cubeFaceI++) 1902 { 1903 const tcu::CubeFace cubeFace = (tcu::CubeFace)cubeFaceI; 1904 1905 // Don't duplicate all cases for all faces. 1906 if (cubeFaceI == 0) 1907 { 1908 for (int basicNdx = 0; basicNdx < (int)basicIterations.size(); basicNdx++) 1909 { 1910 m_iterations.push_back(Iteration()); 1911 m_iterations.back().gatherArgs = basicIterations[basicNdx]; 1912 m_iterations.back().face = cubeFace; 1913 } 1914 } 1915 else 1916 { 1917 // For other faces than first, only test one component per face. 1918 for (int basicNdx = 0; basicNdx < (int)basicIterations.size(); basicNdx++) 1919 { 1920 if (isDepthFormat(m_textureFormat) || basicIterations[basicNdx].componentNdx == cubeFaceI % 4) 1921 { 1922 m_iterations.push_back(Iteration()); 1923 m_iterations.back().gatherArgs = basicIterations[basicNdx]; 1924 m_iterations.back().face = cubeFace; 1925 break; 1926 } 1927 } 1928 } 1929 } 1930 } 1931 1932 void TextureGatherCubeCase::createAndUploadTexture (void) 1933 { 1934 TestLog& log = m_testCtx.getLog(); 1935 const glu::RenderContext& renderCtx = m_context.getRenderContext(); 1936 const glw::Functions& gl = renderCtx.getFunctions(); 1937 const tcu::TextureFormatInfo texFmtInfo = tcu::getTextureFormatInfo(m_textureFormat); 1938 1939 m_texture = MovePtr<glu::TextureCube>(new glu::TextureCube(renderCtx, glu::getInternalFormat(m_textureFormat), m_textureSize)); 1940 1941 { 1942 tcu::TextureCube& refTexture = m_texture->getRefTexture(); 1943 const int levelBegin = m_baseLevel; 1944 const int levelEnd = isMipmapFilter(m_minFilter) && !(m_flags & GATHERCASE_MIPMAP_INCOMPLETE) ? refTexture.getNumLevels() : m_baseLevel+1; 1945 DE_ASSERT(m_baseLevel < refTexture.getNumLevels()); 1946 1947 for (int levelNdx = levelBegin; levelNdx < levelEnd; levelNdx++) 1948 { 1949 log << TestLog::ImageSet("InputTextureLevel" + de::toString(levelNdx), "Input texture, level " + de::toString(levelNdx)); 1950 1951 for (int cubeFaceI = 0; cubeFaceI < tcu::CUBEFACE_LAST; cubeFaceI++) 1952 { 1953 const tcu::CubeFace cubeFace = (tcu::CubeFace)cubeFaceI; 1954 refTexture.allocLevel(cubeFace, levelNdx); 1955 const PixelBufferAccess& levelFace = refTexture.getLevelFace(levelNdx, cubeFace); 1956 fillWithRandomColorTiles(levelFace, texFmtInfo.valueMin, texFmtInfo.valueMax, (deUint32)m_testCtx.getCommandLine().getBaseSeed() ^ (deUint32)cubeFaceI); 1957 1958 m_testCtx.getLog() << TestLog::Image("InputTextureLevel" + de::toString(levelNdx) + "Face" + de::toString((int)cubeFace), 1959 de::toString(cubeFace), 1960 levelFace); 1961 } 1962 1963 log << TestLog::EndImageSet 1964 << TestLog::Message << "Note: texture level's size is " << refTexture.getLevelFace(levelNdx, tcu::CUBEFACE_NEGATIVE_X).getWidth() << TestLog::EndMessage; 1965 } 1966 1967 swizzleTexture(m_swizzledTexture, refTexture, m_textureSwizzle); 1968 } 1969 1970 gl.activeTexture(GL_TEXTURE0); 1971 m_texture->upload(); 1972 } 1973 1974 bool TextureGatherCubeCase::verify (int iterationNdx, const ConstPixelBufferAccess& rendered) const 1975 { 1976 Vec3 texCoords[4]; 1977 computeTexCoordVecs(computeQuadTexCoord(iterationNdx), texCoords); 1978 return TextureGatherCase::verify(rendered, getOneLevelSubView(tcu::TextureCubeView(m_swizzledTexture), m_baseLevel), texCoords, m_iterations[iterationNdx].gatherArgs); 1979 } 1980 1981 static inline TextureGatherCase* makeTextureGatherCase (TextureType textureType, 1982 Context& context, 1983 const char* name, 1984 const char* description, 1985 GatherType gatherType, 1986 OffsetSize offsetSize, 1987 tcu::TextureFormat textureFormat, 1988 tcu::Sampler::CompareMode shadowCompareMode, 1989 tcu::Sampler::WrapMode wrapS, 1990 tcu::Sampler::WrapMode wrapT, 1991 const MaybeTextureSwizzle& texSwizzle, 1992 tcu::Sampler::FilterMode minFilter, 1993 tcu::Sampler::FilterMode magFilter, 1994 int baseLevel, 1995 const IVec3& textureSize, 1996 deUint32 flags = 0) 1997 { 1998 switch (textureType) 1999 { 2000 case TEXTURETYPE_2D: 2001 return new TextureGather2DCase(context, name, description, gatherType, offsetSize, textureFormat, shadowCompareMode, 2002 wrapS, wrapT, texSwizzle, minFilter, magFilter, baseLevel, flags, textureSize.swizzle(0, 1)); 2003 2004 case TEXTURETYPE_2D_ARRAY: 2005 return new TextureGather2DArrayCase(context, name, description, gatherType, offsetSize, textureFormat, shadowCompareMode, 2006 wrapS, wrapT, texSwizzle, minFilter, magFilter, baseLevel, flags, textureSize); 2007 2008 case TEXTURETYPE_CUBE: 2009 DE_ASSERT(gatherType == GATHERTYPE_BASIC); 2010 DE_ASSERT(offsetSize == OFFSETSIZE_NONE); 2011 return new TextureGatherCubeCase(context, name, description, textureFormat, shadowCompareMode, 2012 wrapS, wrapT, texSwizzle, minFilter, magFilter, baseLevel, flags, textureSize.x()); 2013 2014 default: 2015 DE_ASSERT(false); 2016 return DE_NULL; 2017 } 2018 } 2019 2020 } // anonymous 2021 2022 TextureGatherTests::TextureGatherTests (Context& context) 2023 : TestCaseGroup(context, "gather", "textureGather* tests") 2024 { 2025 } 2026 2027 static inline const char* compareModeName (tcu::Sampler::CompareMode mode) 2028 { 2029 switch (mode) 2030 { 2031 case tcu::Sampler::COMPAREMODE_LESS: return "less"; 2032 case tcu::Sampler::COMPAREMODE_LESS_OR_EQUAL: return "less_or_equal"; 2033 case tcu::Sampler::COMPAREMODE_GREATER: return "greater"; 2034 case tcu::Sampler::COMPAREMODE_GREATER_OR_EQUAL: return "greater_or_equal"; 2035 case tcu::Sampler::COMPAREMODE_EQUAL: return "equal"; 2036 case tcu::Sampler::COMPAREMODE_NOT_EQUAL: return "not_equal"; 2037 case tcu::Sampler::COMPAREMODE_ALWAYS: return "always"; 2038 case tcu::Sampler::COMPAREMODE_NEVER: return "never"; 2039 default: DE_ASSERT(false); return DE_NULL; 2040 } 2041 } 2042 2043 void TextureGatherTests::init (void) 2044 { 2045 const struct 2046 { 2047 const char* name; 2048 TextureType type; 2049 } textureTypes[] = 2050 { 2051 { "2d", TEXTURETYPE_2D }, 2052 { "2d_array", TEXTURETYPE_2D_ARRAY }, 2053 { "cube", TEXTURETYPE_CUBE } 2054 }; 2055 2056 const struct 2057 { 2058 const char* name; 2059 tcu::TextureFormat format; 2060 } formats[] = 2061 { 2062 { "rgba8", tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8) }, 2063 { "rgba8ui", tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNSIGNED_INT8) }, 2064 { "rgba8i", tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::SIGNED_INT8) }, 2065 { "depth32f", tcu::TextureFormat(tcu::TextureFormat::D, tcu::TextureFormat::FLOAT) } 2066 }; 2067 2068 const struct 2069 { 2070 const char* name; 2071 IVec3 size; 2072 } textureSizes[] = 2073 { 2074 { "size_pot", IVec3(64, 64, 3) }, 2075 { "size_npot", IVec3(17, 23, 3) } 2076 }; 2077 2078 const struct 2079 { 2080 const char* name; 2081 tcu::Sampler::WrapMode mode; 2082 } wrapModes[] = 2083 { 2084 { "clamp_to_edge", tcu::Sampler::CLAMP_TO_EDGE }, 2085 { "repeat", tcu::Sampler::REPEAT_GL }, 2086 { "mirrored_repeat", tcu::Sampler::MIRRORED_REPEAT_GL } 2087 }; 2088 2089 for (int gatherTypeI = 0; gatherTypeI < GATHERTYPE_LAST; gatherTypeI++) 2090 { 2091 const GatherType gatherType = (GatherType)gatherTypeI; 2092 TestCaseGroup* const gatherTypeGroup = new TestCaseGroup(m_context, gatherTypeName(gatherType), gatherTypeDescription(gatherType)); 2093 addChild(gatherTypeGroup); 2094 2095 for (int offsetSizeI = 0; offsetSizeI < OFFSETSIZE_LAST; offsetSizeI++) 2096 { 2097 const OffsetSize offsetSize = (OffsetSize)offsetSizeI; 2098 if ((gatherType == GATHERTYPE_BASIC) != (offsetSize == OFFSETSIZE_NONE)) 2099 continue; 2100 2101 TestCaseGroup* const offsetSizeGroup = offsetSize == OFFSETSIZE_NONE ? 2102 gatherTypeGroup : 2103 new TestCaseGroup(m_context, 2104 offsetSize == OFFSETSIZE_MINIMUM_REQUIRED ? "min_required_offset" 2105 : offsetSize == OFFSETSIZE_IMPLEMENTATION_MAXIMUM ? "implementation_offset" 2106 : DE_NULL, 2107 offsetSize == OFFSETSIZE_MINIMUM_REQUIRED ? "Use offsets within GL minimum required range" 2108 : offsetSize == OFFSETSIZE_IMPLEMENTATION_MAXIMUM ? "Use offsets within the implementation range" 2109 : DE_NULL); 2110 if (offsetSizeGroup != gatherTypeGroup) 2111 gatherTypeGroup->addChild(offsetSizeGroup); 2112 2113 for (int textureTypeNdx = 0; textureTypeNdx < DE_LENGTH_OF_ARRAY(textureTypes); textureTypeNdx++) 2114 { 2115 const TextureType textureType = textureTypes[textureTypeNdx].type; 2116 2117 if (textureType == TEXTURETYPE_CUBE && gatherType != GATHERTYPE_BASIC) 2118 continue; 2119 2120 TestCaseGroup* const textureTypeGroup = new TestCaseGroup(m_context, textureTypes[textureTypeNdx].name, ""); 2121 offsetSizeGroup->addChild(textureTypeGroup); 2122 2123 for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(formats); formatNdx++) 2124 { 2125 const tcu::TextureFormat& format = formats[formatNdx].format; 2126 TestCaseGroup* const formatGroup = new TestCaseGroup(m_context, formats[formatNdx].name, ""); 2127 textureTypeGroup->addChild(formatGroup); 2128 2129 for (int noCornersI = 0; noCornersI <= (textureType == TEXTURETYPE_CUBE)?1:0; noCornersI++) 2130 { 2131 const bool noCorners = noCornersI!= 0; 2132 TestCaseGroup* const cornersGroup = noCorners 2133 ? new TestCaseGroup(m_context, "no_corners", "Test case variants that don't sample around cube map corners") 2134 : formatGroup; 2135 2136 if (formatGroup != cornersGroup) 2137 formatGroup->addChild(cornersGroup); 2138 2139 for (int textureSizeNdx = 0; textureSizeNdx < DE_LENGTH_OF_ARRAY(textureSizes); textureSizeNdx++) 2140 { 2141 const IVec3& textureSize = textureSizes[textureSizeNdx].size; 2142 TestCaseGroup* const textureSizeGroup = new TestCaseGroup(m_context, textureSizes[textureSizeNdx].name, ""); 2143 cornersGroup->addChild(textureSizeGroup); 2144 2145 for (int compareModeI = 0; compareModeI < tcu::Sampler::COMPAREMODE_LAST; compareModeI++) 2146 { 2147 const tcu::Sampler::CompareMode compareMode = (tcu::Sampler::CompareMode)compareModeI; 2148 2149 if ((compareMode != tcu::Sampler::COMPAREMODE_NONE) != isDepthFormat(format)) 2150 continue; 2151 2152 if (compareMode != tcu::Sampler::COMPAREMODE_NONE && 2153 compareMode != tcu::Sampler::COMPAREMODE_LESS && 2154 compareMode != tcu::Sampler::COMPAREMODE_GREATER) 2155 continue; 2156 2157 TestCaseGroup* const compareModeGroup = compareMode == tcu::Sampler::COMPAREMODE_NONE ? 2158 textureSizeGroup : 2159 new TestCaseGroup(m_context, 2160 (string() + "compare_" + compareModeName(compareMode)).c_str(), 2161 ""); 2162 if (compareModeGroup != textureSizeGroup) 2163 textureSizeGroup->addChild(compareModeGroup); 2164 2165 for (int wrapCaseNdx = 0; wrapCaseNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapCaseNdx++) 2166 { 2167 const int wrapSNdx = wrapCaseNdx; 2168 const int wrapTNdx = (wrapCaseNdx + 1) % DE_LENGTH_OF_ARRAY(wrapModes); 2169 const tcu::Sampler::WrapMode wrapS = wrapModes[wrapSNdx].mode; 2170 const tcu::Sampler::WrapMode wrapT = wrapModes[wrapTNdx].mode; 2171 2172 const string caseName = string() + wrapModes[wrapSNdx].name + "_" + wrapModes[wrapTNdx].name; 2173 2174 compareModeGroup->addChild(makeTextureGatherCase(textureType, m_context, caseName.c_str(), "", gatherType, offsetSize, format, compareMode, wrapS, wrapT, 2175 MaybeTextureSwizzle::createNoneTextureSwizzle(), tcu::Sampler::NEAREST, tcu::Sampler::NEAREST, 0, textureSize, 2176 noCorners ? GATHERCASE_DONT_SAMPLE_CUBE_CORNERS : 0)); 2177 } 2178 } 2179 } 2180 } 2181 2182 if (offsetSize != OFFSETSIZE_MINIMUM_REQUIRED) // Don't test all features for both offset size types, as they should be rather orthogonal. 2183 { 2184 if (!isDepthFormat(format)) 2185 { 2186 TestCaseGroup* const swizzleGroup = new TestCaseGroup(m_context, "texture_swizzle", ""); 2187 formatGroup->addChild(swizzleGroup); 2188 2189 DE_STATIC_ASSERT(TEXTURESWIZZLECOMPONENT_R == 0); 2190 for (int swizzleCaseNdx = 0; swizzleCaseNdx < TEXTURESWIZZLECOMPONENT_LAST; swizzleCaseNdx++) 2191 { 2192 MaybeTextureSwizzle swizzle = MaybeTextureSwizzle::createSomeTextureSwizzle(); 2193 string caseName; 2194 2195 for (int i = 0; i < 4; i++) 2196 { 2197 swizzle.getSwizzle()[i] = (TextureSwizzleComponent)((swizzleCaseNdx + i) % (int)TEXTURESWIZZLECOMPONENT_LAST); 2198 caseName += (i > 0 ? "_" : "") + de::toLower(de::toString(swizzle.getSwizzle()[i])); 2199 } 2200 2201 swizzleGroup->addChild(makeTextureGatherCase(textureType, m_context, caseName.c_str(), "", gatherType, offsetSize, format, 2202 tcu::Sampler::COMPAREMODE_NONE, tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL, 2203 swizzle, tcu::Sampler::NEAREST, tcu::Sampler::NEAREST, 0, IVec3(64, 64, 3))); 2204 } 2205 } 2206 2207 { 2208 TestCaseGroup* const filterModeGroup = new TestCaseGroup(m_context, "filter_mode", "Test that filter modes have no effect"); 2209 formatGroup->addChild(filterModeGroup); 2210 2211 const struct 2212 { 2213 const char* name; 2214 tcu::Sampler::FilterMode filter; 2215 } magFilters[] = 2216 { 2217 { "linear", tcu::Sampler::LINEAR }, 2218 { "nearest", tcu::Sampler::NEAREST } 2219 }; 2220 2221 const struct 2222 { 2223 const char* name; 2224 tcu::Sampler::FilterMode filter; 2225 } minFilters[] = 2226 { 2227 // \note Don't test NEAREST here, as it's covered by other cases. 2228 { "linear", tcu::Sampler::LINEAR }, 2229 { "nearest_mipmap_nearest", tcu::Sampler::NEAREST_MIPMAP_NEAREST }, 2230 { "nearest_mipmap_linear", tcu::Sampler::NEAREST_MIPMAP_LINEAR }, 2231 { "linear_mipmap_nearest", tcu::Sampler::LINEAR_MIPMAP_NEAREST }, 2232 { "linear_mipmap_linear", tcu::Sampler::LINEAR_MIPMAP_LINEAR }, 2233 }; 2234 2235 for (int minFilterNdx = 0; minFilterNdx < DE_LENGTH_OF_ARRAY(minFilters); minFilterNdx++) 2236 for (int magFilterNdx = 0; magFilterNdx < DE_LENGTH_OF_ARRAY(magFilters); magFilterNdx++) 2237 { 2238 const tcu::Sampler::FilterMode minFilter = minFilters[minFilterNdx].filter; 2239 const tcu::Sampler::FilterMode magFilter = magFilters[magFilterNdx].filter; 2240 const tcu::Sampler::CompareMode compareMode = isDepthFormat(format) ? tcu::Sampler::COMPAREMODE_LESS : tcu::Sampler::COMPAREMODE_NONE; 2241 2242 if ((isUnormFormatType(format.type) || isDepthFormat(format)) && magFilter == tcu::Sampler::NEAREST) 2243 continue; // Covered by other cases. 2244 if ((isUIntFormatType(format.type) || isSIntFormatType(format.type)) && 2245 (magFilter != tcu::Sampler::NEAREST || minFilter != tcu::Sampler::NEAREST_MIPMAP_NEAREST)) 2246 continue; 2247 2248 const string caseName = string() + "min_" + minFilters[minFilterNdx].name + "_mag_" + magFilters[magFilterNdx].name; 2249 2250 filterModeGroup->addChild(makeTextureGatherCase(textureType, m_context, caseName.c_str(), "", gatherType, offsetSize, format, compareMode, 2251 tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL, MaybeTextureSwizzle::createNoneTextureSwizzle(), 2252 minFilter, magFilter, 0, IVec3(64, 64, 3))); 2253 } 2254 } 2255 2256 { 2257 TestCaseGroup* const baseLevelGroup = new TestCaseGroup(m_context, "base_level", ""); 2258 formatGroup->addChild(baseLevelGroup); 2259 2260 for (int baseLevel = 1; baseLevel <= 2; baseLevel++) 2261 { 2262 const string caseName = "level_" + de::toString(baseLevel); 2263 const tcu::Sampler::CompareMode compareMode = isDepthFormat(format) ? tcu::Sampler::COMPAREMODE_LESS : tcu::Sampler::COMPAREMODE_NONE; 2264 baseLevelGroup->addChild(makeTextureGatherCase(textureType, m_context, caseName.c_str(), "", gatherType, offsetSize, format, 2265 compareMode, tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL, 2266 MaybeTextureSwizzle::createNoneTextureSwizzle(), tcu::Sampler::NEAREST, tcu::Sampler::NEAREST, 2267 baseLevel, IVec3(64, 64, 3))); 2268 } 2269 } 2270 2271 if (!isDepthFormat(format)) // What shadow textures should return for incomplete textures is unclear. 2272 { 2273 TestCaseGroup* const incompleteGroup = new TestCaseGroup(m_context, "incomplete", "Test that textureGather* takes components from (0,0,0,1) for incomplete textures"); 2274 formatGroup->addChild(incompleteGroup); 2275 2276 const tcu::Sampler::CompareMode compareMode = isDepthFormat(format) ? tcu::Sampler::COMPAREMODE_LESS : tcu::Sampler::COMPAREMODE_NONE; 2277 incompleteGroup->addChild(makeTextureGatherCase(textureType, m_context, "mipmap_incomplete", "", gatherType, offsetSize, format, 2278 compareMode, tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL, 2279 MaybeTextureSwizzle::createNoneTextureSwizzle(), tcu::Sampler::NEAREST_MIPMAP_NEAREST, tcu::Sampler::NEAREST, 2280 0, IVec3(64, 64, 3), GATHERCASE_MIPMAP_INCOMPLETE)); 2281 } 2282 } 2283 } 2284 } 2285 } 2286 } 2287 } 2288 2289 } // Functional 2290 } // gles31 2291 } // deqp 2292