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 = 7; 89 const int numRows = 5; 90 de::Random rnd (seed); 91 92 for (int slice = 0; slice < dst.getDepth(); slice++) 93 for (int row = 0; row < numRows; row++) 94 for (int col = 0; col < numCols; col++) 95 { 96 const int yBegin = (row+0)*dst.getHeight()/numRows; 97 const int yEnd = (row+1)*dst.getHeight()/numRows; 98 const int xBegin = (col+0)*dst.getWidth()/numCols; 99 const int xEnd = (col+1)*dst.getWidth()/numCols; 100 Vec4 color; 101 for (int i = 0; i < 4; i++) 102 color[i] = rnd.getFloat(minVal[i], maxVal[i]); 103 tcu::clear(tcu::getSubregion(dst, xBegin, yBegin, slice, xEnd-xBegin, yEnd-yBegin, 1), color); 104 } 105 } 106 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 static inline const char* gatherTypeName (GatherType type) 755 { 756 switch (type) 757 { 758 case GATHERTYPE_BASIC: return "basic"; 759 case GATHERTYPE_OFFSET: return "offset"; 760 case GATHERTYPE_OFFSET_DYNAMIC: return "offset_dynamic"; 761 case GATHERTYPE_OFFSETS: return "offsets"; 762 default: DE_ASSERT(false); return DE_NULL; 763 } 764 } 765 766 static inline const char* gatherTypeDescription (GatherType type) 767 { 768 switch (type) 769 { 770 case GATHERTYPE_BASIC: return "textureGather"; 771 case GATHERTYPE_OFFSET: return "textureGatherOffset"; 772 case GATHERTYPE_OFFSET_DYNAMIC: return "textureGatherOffset with dynamic offsets"; 773 case GATHERTYPE_OFFSETS: return "textureGatherOffsets"; 774 default: DE_ASSERT(false); return DE_NULL; 775 } 776 } 777 778 static inline bool requireGpuShader5 (GatherType gatherType) 779 { 780 return gatherType == GATHERTYPE_OFFSET_DYNAMIC || gatherType == GATHERTYPE_OFFSETS; 781 } 782 783 struct GatherArgs 784 { 785 int componentNdx; // If negative, implicit component index 0 is used (i.e. the parameter is not given). 786 IVec2 offsets[4]; // \note Unless GATHERTYPE_OFFSETS is used, only offsets[0] is relevant; also, for GATHERTYPE_OFFSET_DYNAMIC, none are relevant. 787 788 GatherArgs (void) 789 : componentNdx(-1) 790 { 791 std::fill(DE_ARRAY_BEGIN(offsets), DE_ARRAY_END(offsets), IVec2()); 792 } 793 794 GatherArgs (int comp, 795 const IVec2& off0 = IVec2(), 796 const IVec2& off1 = IVec2(), 797 const IVec2& off2 = IVec2(), 798 const IVec2& off3 = IVec2()) 799 : componentNdx(comp) 800 { 801 offsets[0] = off0; 802 offsets[1] = off1; 803 offsets[2] = off2; 804 offsets[3] = off3; 805 } 806 }; 807 808 static MovePtr<PixelOffsets> makePixelOffsetsFunctor (GatherType gatherType, const GatherArgs& gatherArgs, const IVec2& offsetRange) 809 { 810 if (gatherType == GATHERTYPE_BASIC || gatherType == GATHERTYPE_OFFSET) 811 { 812 const IVec2 offset = gatherType == GATHERTYPE_BASIC ? IVec2(0) : gatherArgs.offsets[0]; 813 return MovePtr<PixelOffsets>(new SinglePixelOffsets(offset)); 814 } 815 else if (gatherType == GATHERTYPE_OFFSET_DYNAMIC) 816 { 817 return MovePtr<PixelOffsets>(new DynamicSinglePixelOffsets(offsetRange)); 818 } 819 else if (gatherType == GATHERTYPE_OFFSETS) 820 return MovePtr<PixelOffsets>(new MultiplePixelOffsets(gatherArgs.offsets[0], 821 gatherArgs.offsets[1], 822 gatherArgs.offsets[2], 823 gatherArgs.offsets[3])); 824 else 825 { 826 DE_ASSERT(false); 827 return MovePtr<PixelOffsets>(DE_NULL); 828 } 829 } 830 831 static inline glu::DataType getSamplerType (TextureType textureType, const tcu::TextureFormat& format) 832 { 833 if (isDepthFormat(format)) 834 { 835 switch (textureType) 836 { 837 case TEXTURETYPE_2D: return glu::TYPE_SAMPLER_2D_SHADOW; 838 case TEXTURETYPE_2D_ARRAY: return glu::TYPE_SAMPLER_2D_ARRAY_SHADOW; 839 case TEXTURETYPE_CUBE: return glu::TYPE_SAMPLER_CUBE_SHADOW; 840 default: DE_ASSERT(false); return glu::TYPE_LAST; 841 } 842 } 843 else 844 { 845 switch (textureType) 846 { 847 case TEXTURETYPE_2D: return glu::getSampler2DType(format); 848 case TEXTURETYPE_2D_ARRAY: return glu::getSampler2DArrayType(format); 849 case TEXTURETYPE_CUBE: return glu::getSamplerCubeType(format); 850 default: DE_ASSERT(false); return glu::TYPE_LAST; 851 } 852 } 853 } 854 855 static inline glu::DataType getSamplerGatherResultType (glu::DataType samplerType) 856 { 857 switch (samplerType) 858 { 859 case glu::TYPE_SAMPLER_2D_SHADOW: 860 case glu::TYPE_SAMPLER_2D_ARRAY_SHADOW: 861 case glu::TYPE_SAMPLER_CUBE_SHADOW: 862 case glu::TYPE_SAMPLER_2D: 863 case glu::TYPE_SAMPLER_2D_ARRAY: 864 case glu::TYPE_SAMPLER_CUBE: 865 return glu::TYPE_FLOAT_VEC4; 866 867 case glu::TYPE_INT_SAMPLER_2D: 868 case glu::TYPE_INT_SAMPLER_2D_ARRAY: 869 case glu::TYPE_INT_SAMPLER_CUBE: 870 return glu::TYPE_INT_VEC4; 871 872 case glu::TYPE_UINT_SAMPLER_2D: 873 case glu::TYPE_UINT_SAMPLER_2D_ARRAY: 874 case glu::TYPE_UINT_SAMPLER_CUBE: 875 return glu::TYPE_UINT_VEC4; 876 877 default: 878 DE_ASSERT(false); 879 return glu::TYPE_LAST; 880 } 881 } 882 883 static inline int getNumTextureSamplingDimensions (TextureType type) 884 { 885 switch (type) 886 { 887 case TEXTURETYPE_2D: return 2; 888 case TEXTURETYPE_2D_ARRAY: return 3; 889 case TEXTURETYPE_CUBE: return 3; 890 default: DE_ASSERT(false); return -1; 891 } 892 } 893 894 static deUint32 getGLTextureType (TextureType type) 895 { 896 switch (type) 897 { 898 case TEXTURETYPE_2D: return GL_TEXTURE_2D; 899 case TEXTURETYPE_2D_ARRAY: return GL_TEXTURE_2D_ARRAY; 900 case TEXTURETYPE_CUBE: return GL_TEXTURE_CUBE_MAP; 901 default: DE_ASSERT(false); return (deUint32)-1; 902 } 903 } 904 905 enum OffsetSize 906 { 907 OFFSETSIZE_NONE = 0, 908 OFFSETSIZE_MINIMUM_REQUIRED, 909 OFFSETSIZE_IMPLEMENTATION_MAXIMUM, 910 911 OFFSETSIZE_LAST 912 }; 913 914 static inline bool isMipmapFilter (tcu::Sampler::FilterMode filter) 915 { 916 switch (filter) 917 { 918 case tcu::Sampler::NEAREST: 919 case tcu::Sampler::LINEAR: 920 return false; 921 922 case tcu::Sampler::NEAREST_MIPMAP_NEAREST: 923 case tcu::Sampler::NEAREST_MIPMAP_LINEAR: 924 case tcu::Sampler::LINEAR_MIPMAP_NEAREST: 925 case tcu::Sampler::LINEAR_MIPMAP_LINEAR: 926 return true; 927 928 default: 929 DE_ASSERT(false); 930 return false; 931 } 932 } 933 934 class TextureGatherCase : public TestCase 935 { 936 public: 937 TextureGatherCase (Context& context, 938 const char* name, 939 const char* description, 940 TextureType textureType, 941 GatherType gatherType, 942 OffsetSize offsetSize, 943 tcu::TextureFormat textureFormat, 944 tcu::Sampler::CompareMode shadowCompareMode, //!< Should be COMPAREMODE_NONE iff textureFormat is a depth format. 945 tcu::Sampler::WrapMode wrapS, 946 tcu::Sampler::WrapMode wrapT, 947 const MaybeTextureSwizzle& texSwizzle, 948 // \note Filter modes have no effect on gather (except when it comes to 949 // texture completeness); these are supposed to test just that. 950 tcu::Sampler::FilterMode minFilter, 951 tcu::Sampler::FilterMode magFilter, 952 int baseLevel, 953 bool mipmapIncomplete); 954 955 void init (void); 956 void deinit (void); 957 IterateResult iterate (void); 958 959 protected: 960 IVec2 getOffsetRange (void) const; 961 962 template <typename TexViewT, typename TexCoordT> 963 bool verify (const ConstPixelBufferAccess& rendered, 964 const TexViewT& texture, 965 const TexCoordT (&bottomLeft)[4], 966 const GatherArgs& gatherArgs) const; 967 968 virtual void generateIterations (void) = 0; 969 virtual void createAndUploadTexture (void) = 0; 970 virtual int getNumIterations (void) const = 0; 971 virtual GatherArgs getGatherArgs (int iterationNdx) const = 0; 972 virtual vector<float> computeQuadTexCoord (int iterationNdx) const = 0; 973 virtual bool verify (int iterationNdx, const ConstPixelBufferAccess& rendered) const = 0; 974 975 const GatherType m_gatherType; 976 const OffsetSize m_offsetSize; 977 const tcu::TextureFormat m_textureFormat; 978 const tcu::Sampler::CompareMode m_shadowCompareMode; 979 const tcu::Sampler::WrapMode m_wrapS; 980 const tcu::Sampler::WrapMode m_wrapT; 981 const MaybeTextureSwizzle m_textureSwizzle; 982 const tcu::Sampler::FilterMode m_minFilter; 983 const tcu::Sampler::FilterMode m_magFilter; 984 const int m_baseLevel; 985 const bool m_mipmapIncomplete; 986 987 private: 988 enum 989 { 990 SPEC_MAX_MIN_OFFSET = -8, 991 SPEC_MIN_MAX_OFFSET = 7 992 }; 993 994 static const IVec2 RENDER_SIZE; 995 996 static glu::VertexSource genVertexShaderSource (bool requireGpuShader5, int numTexCoordComponents, bool useNormalizedCoordInput); 997 static glu::FragmentSource genFragmentShaderSource (bool requireGpuShader5, int numTexCoordComponents, glu::DataType samplerType, const string& funcCall, bool useNormalizedCoordInput, bool usePixCoord); 998 static string genGatherFuncCall (GatherType, const tcu::TextureFormat&, const GatherArgs&, const string& refZExpr, const IVec2& offsetRange, int indentationDepth); 999 static glu::ProgramSources genProgramSources (GatherType, TextureType, const tcu::TextureFormat&, const GatherArgs&, const string& refZExpr, const IVec2& offsetRange); 1000 1001 const TextureType m_textureType; 1002 1003 const tcu::TextureFormat m_colorBufferFormat; 1004 MovePtr<glu::Renderbuffer> m_colorBuffer; 1005 MovePtr<glu::Framebuffer> m_fbo; 1006 1007 int m_currentIteration; 1008 MovePtr<ShaderProgram> m_program; 1009 }; 1010 1011 const IVec2 TextureGatherCase::RENDER_SIZE = IVec2(64, 64); 1012 1013 TextureGatherCase::TextureGatherCase (Context& context, 1014 const char* name, 1015 const char* description, 1016 TextureType textureType, 1017 GatherType gatherType, 1018 OffsetSize offsetSize, 1019 tcu::TextureFormat textureFormat, 1020 tcu::Sampler::CompareMode shadowCompareMode, //!< Should be COMPAREMODE_NONE iff textureType == TEXTURETYPE_NORMAL. 1021 tcu::Sampler::WrapMode wrapS, 1022 tcu::Sampler::WrapMode wrapT, 1023 const MaybeTextureSwizzle& textureSwizzle, 1024 tcu::Sampler::FilterMode minFilter, 1025 tcu::Sampler::FilterMode magFilter, 1026 int baseLevel, 1027 bool mipmapIncomplete) 1028 : TestCase (context, name, description) 1029 , m_gatherType (gatherType) 1030 , m_offsetSize (offsetSize) 1031 , m_textureFormat (textureFormat) 1032 , m_shadowCompareMode (shadowCompareMode) 1033 , m_wrapS (wrapS) 1034 , m_wrapT (wrapT) 1035 , m_textureSwizzle (textureSwizzle) 1036 , m_minFilter (minFilter) 1037 , m_magFilter (magFilter) 1038 , m_baseLevel (baseLevel) 1039 , m_mipmapIncomplete (mipmapIncomplete) 1040 , m_textureType (textureType) 1041 , m_colorBufferFormat (tcu::TextureFormat(tcu::TextureFormat::RGBA, 1042 isDepthFormat(textureFormat) ? tcu::TextureFormat::UNORM_INT8 : textureFormat.type)) 1043 , m_currentIteration (0) 1044 { 1045 DE_ASSERT((m_gatherType == GATHERTYPE_BASIC) == (m_offsetSize == OFFSETSIZE_NONE)); 1046 DE_ASSERT((m_shadowCompareMode != tcu::Sampler::COMPAREMODE_NONE) == isDepthFormat(m_textureFormat)); 1047 DE_ASSERT(isUnormFormatType(m_colorBufferFormat.type) || 1048 m_colorBufferFormat.type == tcu::TextureFormat::UNSIGNED_INT8 || 1049 m_colorBufferFormat.type == tcu::TextureFormat::UNSIGNED_INT16 || 1050 m_colorBufferFormat.type == tcu::TextureFormat::SIGNED_INT8 || 1051 m_colorBufferFormat.type == tcu::TextureFormat::SIGNED_INT16); 1052 DE_ASSERT(glu::isGLInternalColorFormatFilterable(glu::getInternalFormat(m_colorBufferFormat)) || 1053 (m_magFilter == tcu::Sampler::NEAREST && (m_minFilter == tcu::Sampler::NEAREST || m_minFilter == tcu::Sampler::NEAREST_MIPMAP_NEAREST))); 1054 DE_ASSERT(isMipmapFilter(m_minFilter) || !m_mipmapIncomplete); 1055 DE_ASSERT(!(m_mipmapIncomplete && isDepthFormat(m_textureFormat))); // It's not clear what shadow textures should return when incomplete. 1056 } 1057 1058 IVec2 TextureGatherCase::getOffsetRange (void) const 1059 { 1060 switch (m_offsetSize) 1061 { 1062 case OFFSETSIZE_NONE: 1063 return IVec2(0); 1064 break; 1065 1066 case OFFSETSIZE_MINIMUM_REQUIRED: 1067 // \note Defined by spec. 1068 return IVec2(SPEC_MAX_MIN_OFFSET, 1069 SPEC_MIN_MAX_OFFSET); 1070 break; 1071 1072 case OFFSETSIZE_IMPLEMENTATION_MAXIMUM: 1073 return IVec2(m_context.getContextInfo().getInt(GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET), 1074 m_context.getContextInfo().getInt(GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET)); 1075 break; 1076 1077 default: 1078 DE_ASSERT(false); 1079 return IVec2(-1); 1080 } 1081 } 1082 1083 glu::VertexSource TextureGatherCase::genVertexShaderSource (bool requireGpuShader5, int numTexCoordComponents, bool useNormalizedCoordInput) 1084 { 1085 DE_ASSERT(numTexCoordComponents == 2 || numTexCoordComponents == 3); 1086 const string texCoordType = "vec" + de::toString(numTexCoordComponents); 1087 return glu::VertexSource("#version 310 es\n" 1088 + string(requireGpuShader5 ? "#extension GL_EXT_gpu_shader5 : require\n" : "") + 1089 "\n" 1090 "in highp vec2 a_position;\n" 1091 "in highp " + texCoordType + " a_texCoord;\n" 1092 + (useNormalizedCoordInput ? "in highp vec2 a_normalizedCoord; // (0,0) to (1,1)\n" : "") + 1093 "\n" 1094 "out highp " + texCoordType + " v_texCoord;\n" 1095 + (useNormalizedCoordInput ? "out highp vec2 v_normalizedCoord;\n" : "") + 1096 "\n" 1097 "void main (void)\n" 1098 "{\n" 1099 " gl_Position = vec4(a_position.x, a_position.y, 0.0, 1.0);\n" 1100 " v_texCoord = a_texCoord;\n" 1101 + (useNormalizedCoordInput ? "\tv_normalizedCoord = a_normalizedCoord;\n" : "") + 1102 "}\n"); 1103 } 1104 1105 glu::FragmentSource TextureGatherCase::genFragmentShaderSource (bool requireGpuShader5, 1106 int numTexCoordComponents, 1107 glu::DataType samplerType, 1108 const string& funcCall, 1109 bool useNormalizedCoordInput, 1110 bool usePixCoord) 1111 { 1112 DE_ASSERT(glu::isDataTypeSampler(samplerType)); 1113 DE_ASSERT(de::inRange(numTexCoordComponents, 2, 3)); 1114 DE_ASSERT(!usePixCoord || useNormalizedCoordInput); 1115 1116 const string texCoordType = "vec" + de::toString(numTexCoordComponents); 1117 1118 return glu::FragmentSource("#version 310 es\n" 1119 + string(requireGpuShader5 ? "#extension GL_EXT_gpu_shader5 : require\n" : "") + 1120 "\n" 1121 "layout (location = 0) out mediump " + glu::getDataTypeName(getSamplerGatherResultType(samplerType)) + " o_color;\n" 1122 "\n" 1123 "in highp " + texCoordType + " v_texCoord;\n" 1124 + (useNormalizedCoordInput ? "in highp vec2 v_normalizedCoord;\n" : "") + 1125 "\n" 1126 "uniform highp " + string(glu::getDataTypeName(samplerType)) + " u_sampler;\n" 1127 + (useNormalizedCoordInput ? "uniform highp vec2 u_viewportSize;\n" : "") + 1128 "\n" 1129 "void main(void)\n" 1130 "{\n" 1131 + (usePixCoord ? "\tivec2 pixCoord = ivec2(v_normalizedCoord*u_viewportSize);\n" : "") + 1132 " o_color = " + funcCall + ";\n" 1133 "}\n"); 1134 } 1135 1136 string TextureGatherCase::genGatherFuncCall (GatherType gatherType, const tcu::TextureFormat& textureFormat, const GatherArgs& gatherArgs, const string& refZExpr, const IVec2& offsetRange, int indentationDepth) 1137 { 1138 string result; 1139 1140 switch (gatherType) 1141 { 1142 case GATHERTYPE_BASIC: 1143 result += "textureGather"; 1144 break; 1145 case GATHERTYPE_OFFSET: // \note Fallthrough. 1146 case GATHERTYPE_OFFSET_DYNAMIC: 1147 result += "textureGatherOffset"; 1148 break; 1149 case GATHERTYPE_OFFSETS: 1150 result += "textureGatherOffsets"; 1151 break; 1152 default: 1153 DE_ASSERT(false); 1154 } 1155 1156 result += "(u_sampler, v_texCoord"; 1157 1158 if (isDepthFormat(textureFormat)) 1159 { 1160 DE_ASSERT(gatherArgs.componentNdx < 0); 1161 result += ", " + refZExpr; 1162 } 1163 1164 if (gatherType == GATHERTYPE_OFFSET || 1165 gatherType == GATHERTYPE_OFFSET_DYNAMIC || 1166 gatherType == GATHERTYPE_OFFSETS) 1167 { 1168 result += ", "; 1169 switch (gatherType) 1170 { 1171 case GATHERTYPE_OFFSET: 1172 result += "ivec2" + de::toString(gatherArgs.offsets[0]); 1173 break; 1174 1175 case GATHERTYPE_OFFSET_DYNAMIC: 1176 result += "pixCoord.yx % ivec2(" + de::toString(offsetRange.y() - offsetRange.x() + 1) + ") + " + de::toString(offsetRange.x()); 1177 break; 1178 1179 case GATHERTYPE_OFFSETS: 1180 result += "ivec2[4](\n" 1181 + string(indentationDepth, '\t') + "\tivec2" + de::toString(gatherArgs.offsets[0]) + ",\n" 1182 + string(indentationDepth, '\t') + "\tivec2" + de::toString(gatherArgs.offsets[1]) + ",\n" 1183 + string(indentationDepth, '\t') + "\tivec2" + de::toString(gatherArgs.offsets[2]) + ",\n" 1184 + string(indentationDepth, '\t') + "\tivec2" + de::toString(gatherArgs.offsets[3]) + ")\n" 1185 + string(indentationDepth, '\t') + "\t"; 1186 break; 1187 1188 default: 1189 DE_ASSERT(false); 1190 } 1191 } 1192 1193 if (gatherArgs.componentNdx >= 0) 1194 { 1195 DE_ASSERT(gatherArgs.componentNdx < 4); 1196 result += ", " + de::toString(gatherArgs.componentNdx); 1197 } 1198 1199 result += ")"; 1200 1201 return result; 1202 } 1203 1204 // \note If componentNdx for genProgramSources() is -1, component index is not specified. 1205 glu::ProgramSources TextureGatherCase::genProgramSources (GatherType gatherType, 1206 TextureType textureType, 1207 const tcu::TextureFormat& textureFormat, 1208 const GatherArgs& gatherArgs, 1209 const string& refZExpr, 1210 const IVec2& offsetRange) 1211 { 1212 const bool usePixCoord = gatherType == GATHERTYPE_OFFSET_DYNAMIC; 1213 const bool useNormalizedCoord = usePixCoord || isDepthFormat(textureFormat); 1214 const bool isDynamicOffset = gatherType == GATHERTYPE_OFFSET_DYNAMIC; 1215 const bool isShadow = isDepthFormat(textureFormat); 1216 const glu::DataType samplerType = getSamplerType(textureType, textureFormat); 1217 const int numDims = getNumTextureSamplingDimensions(textureType); 1218 const string funcCall = genGatherFuncCall(gatherType, textureFormat, gatherArgs, refZExpr, offsetRange, 1); 1219 1220 return glu::ProgramSources() << genVertexShaderSource(requireGpuShader5(gatherType), numDims, isDynamicOffset || isShadow) 1221 << genFragmentShaderSource(requireGpuShader5(gatherType), numDims, samplerType, funcCall, useNormalizedCoord, usePixCoord); 1222 } 1223 1224 void TextureGatherCase::init (void) 1225 { 1226 TestLog& log = m_testCtx.getLog(); 1227 const glu::RenderContext& renderCtx = m_context.getRenderContext(); 1228 const glw::Functions& gl = renderCtx.getFunctions(); 1229 const deUint32 texTypeGL = getGLTextureType(m_textureType); 1230 1231 // Check prerequisites. 1232 if (requireGpuShader5(m_gatherType) && !m_context.getContextInfo().isExtensionSupported("GL_EXT_gpu_shader5")) 1233 throw tcu::NotSupportedError("GL_EXT_gpu_shader5 required"); 1234 1235 // Log and check implementation offset limits, if appropriate. 1236 if (m_offsetSize == OFFSETSIZE_IMPLEMENTATION_MAXIMUM) 1237 { 1238 const IVec2 offsetRange = getOffsetRange(); 1239 log << TestLog::Integer("ImplementationMinTextureGatherOffset", "Implementation's value for GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET", "", QP_KEY_TAG_NONE, offsetRange[0]) 1240 << TestLog::Integer("ImplementationMaxTextureGatherOffset", "Implementation's value for GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET", "", QP_KEY_TAG_NONE, offsetRange[1]); 1241 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()); 1242 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()); 1243 } 1244 1245 // Create rbo and fbo. 1246 1247 m_colorBuffer = MovePtr<glu::Renderbuffer>(new glu::Renderbuffer(renderCtx)); 1248 gl.bindRenderbuffer(GL_RENDERBUFFER, **m_colorBuffer); 1249 gl.renderbufferStorage(GL_RENDERBUFFER, glu::getInternalFormat(m_colorBufferFormat), RENDER_SIZE.x(), RENDER_SIZE.y()); 1250 GLU_EXPECT_NO_ERROR(gl.getError(), "Create and setup renderbuffer object"); 1251 1252 m_fbo = MovePtr<glu::Framebuffer>(new glu::Framebuffer(renderCtx)); 1253 gl.bindFramebuffer(GL_FRAMEBUFFER, **m_fbo); 1254 gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, **m_colorBuffer); 1255 GLU_EXPECT_NO_ERROR(gl.getError(), "Create and setup framebuffer object"); 1256 1257 log << TestLog::Message << "Using a framebuffer object with renderbuffer with format " 1258 << glu::getPixelFormatName(glu::getInternalFormat(m_colorBufferFormat)) 1259 << " and size " << RENDER_SIZE << TestLog::EndMessage; 1260 1261 // Generate subclass-specific iterations. 1262 1263 generateIterations(); 1264 m_currentIteration = 0; 1265 1266 // Initialize texture. 1267 1268 createAndUploadTexture(); 1269 gl.texParameteri(texTypeGL, GL_TEXTURE_WRAP_S, glu::getGLWrapMode(m_wrapS)); 1270 gl.texParameteri(texTypeGL, GL_TEXTURE_WRAP_T, glu::getGLWrapMode(m_wrapT)); 1271 gl.texParameteri(texTypeGL, GL_TEXTURE_MIN_FILTER, glu::getGLFilterMode(m_minFilter)); 1272 gl.texParameteri(texTypeGL, GL_TEXTURE_MAG_FILTER, glu::getGLFilterMode(m_magFilter)); 1273 1274 if (m_baseLevel != 0) 1275 gl.texParameteri(texTypeGL, GL_TEXTURE_BASE_LEVEL, m_baseLevel); 1276 1277 if (isDepthFormat(m_textureFormat)) 1278 { 1279 gl.texParameteri(texTypeGL, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); 1280 gl.texParameteri(texTypeGL, GL_TEXTURE_COMPARE_FUNC, glu::getGLCompareFunc(m_shadowCompareMode)); 1281 } 1282 1283 if (m_textureSwizzle.isSome()) 1284 { 1285 const deUint32 swizzleNamesGL[4] = 1286 { 1287 GL_TEXTURE_SWIZZLE_R, 1288 GL_TEXTURE_SWIZZLE_G, 1289 GL_TEXTURE_SWIZZLE_B, 1290 GL_TEXTURE_SWIZZLE_A 1291 }; 1292 1293 for (int i = 0; i < 4; i++) 1294 { 1295 const deUint32 curGLSwizzle = getGLTextureSwizzleComponent(m_textureSwizzle.getSwizzle()[i]); 1296 gl.texParameteri(texTypeGL, swizzleNamesGL[i], curGLSwizzle); 1297 } 1298 } 1299 1300 GLU_EXPECT_NO_ERROR(gl.getError(), "Set texture parameters"); 1301 1302 log << TestLog::Message << "Texture base level is " << m_baseLevel << TestLog::EndMessage 1303 << TestLog::Message << "s and t wrap modes are " 1304 << glu::getTextureWrapModeName(glu::getGLWrapMode(m_wrapS)) << " and " 1305 << glu::getTextureWrapModeName(glu::getGLWrapMode(m_wrapT)) << ", respectively" << TestLog::EndMessage 1306 << TestLog::Message << "Minification and magnification filter modes are " 1307 << glu::getTextureFilterName(glu::getGLFilterMode(m_minFilter)) << " and " 1308 << glu::getTextureFilterName(glu::getGLFilterMode(m_magFilter)) << ", respectively " 1309 << (m_mipmapIncomplete ? 1310 "(note that they cause the texture to be incomplete)" : 1311 "(note that they should have no effect on gather result)") 1312 << TestLog::EndMessage 1313 << TestLog::Message << "Using texture swizzle " << m_textureSwizzle << TestLog::EndMessage; 1314 1315 if (m_shadowCompareMode != tcu::Sampler::COMPAREMODE_NONE) 1316 log << TestLog::Message << "Using texture compare func " << glu::getCompareFuncName(glu::getGLCompareFunc(m_shadowCompareMode)) << TestLog::EndMessage; 1317 } 1318 1319 void TextureGatherCase::deinit (void) 1320 { 1321 m_program = MovePtr<ShaderProgram>(DE_NULL); 1322 m_fbo = MovePtr<glu::Framebuffer>(DE_NULL); 1323 m_colorBuffer = MovePtr<glu::Renderbuffer>(DE_NULL); 1324 } 1325 1326 TextureGatherCase::IterateResult TextureGatherCase::iterate (void) 1327 { 1328 TestLog& log = m_testCtx.getLog(); 1329 const tcu::ScopedLogSection iterationSection (log, "Iteration" + de::toString(m_currentIteration), "Iteration " + de::toString(m_currentIteration)); 1330 const glu::RenderContext& renderCtx = m_context.getRenderContext(); 1331 const tcu::IVec2 renderSize = RENDER_SIZE; 1332 const glw::Functions& gl = renderCtx.getFunctions(); 1333 const GatherArgs& gatherArgs = getGatherArgs(m_currentIteration); 1334 const string refZExpr = "v_normalizedCoord.x"; 1335 const bool needPixelCoordInShader = m_gatherType == GATHERTYPE_OFFSET_DYNAMIC; 1336 const bool needNormalizedCoordInShader = needPixelCoordInShader || isDepthFormat(m_textureFormat); 1337 1338 // Generate a program appropriate for this iteration. 1339 1340 m_program = MovePtr<ShaderProgram>(new ShaderProgram(renderCtx, genProgramSources(m_gatherType, m_textureType, m_textureFormat, gatherArgs, refZExpr, getOffsetRange()))); 1341 if (m_currentIteration == 0) 1342 m_testCtx.getLog() << *m_program; 1343 else 1344 m_testCtx.getLog() << TestLog::Message << "Using a program similar to the previous one, except with a gather function call as follows:\n" 1345 << genGatherFuncCall(m_gatherType, m_textureFormat, gatherArgs, refZExpr, getOffsetRange(), 0) 1346 << TestLog::EndMessage; 1347 if (!m_program->isOk()) 1348 { 1349 if (m_currentIteration != 0) 1350 m_testCtx.getLog() << *m_program; 1351 TCU_FAIL("Failed to build program"); 1352 } 1353 1354 // Render. 1355 1356 gl.viewport(0, 0, RENDER_SIZE.x(), RENDER_SIZE.y()); 1357 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f); 1358 gl.clear(GL_COLOR_BUFFER_BIT); 1359 1360 { 1361 const float position[4*2] = 1362 { 1363 -1.0f, -1.0f, 1364 -1.0f, +1.0f, 1365 +1.0f, -1.0f, 1366 +1.0f, +1.0f, 1367 }; 1368 1369 const float normalizedCoord[4*2] = 1370 { 1371 0.0f, 0.0f, 1372 0.0f, 1.0f, 1373 1.0f, 0.0f, 1374 1.0f, 1.0f, 1375 }; 1376 1377 const vector<float> texCoord = computeQuadTexCoord(m_currentIteration); 1378 1379 vector<glu::VertexArrayBinding> attrBindings; 1380 attrBindings.push_back(glu::va::Float("a_position", 2, 4, 0, &position[0])); 1381 attrBindings.push_back(glu::va::Float("a_texCoord", (int)texCoord.size()/4, 4, 0, &texCoord[0])); 1382 if (needNormalizedCoordInShader) 1383 attrBindings.push_back(glu::va::Float("a_normalizedCoord", 2, 4, 0, &normalizedCoord[0])); 1384 1385 const deUint16 indices[6] = { 0, 1, 2, 2, 1, 3 }; 1386 1387 gl.useProgram(m_program->getProgram()); 1388 1389 { 1390 const int samplerUniformLocation = gl.getUniformLocation(m_program->getProgram(), "u_sampler"); 1391 TCU_CHECK(samplerUniformLocation >= 0); 1392 gl.uniform1i(samplerUniformLocation, 0); 1393 } 1394 1395 if (needPixelCoordInShader) 1396 { 1397 const int viewportSizeUniformLocation = gl.getUniformLocation(m_program->getProgram(), "u_viewportSize"); 1398 TCU_CHECK(viewportSizeUniformLocation >= 0); 1399 gl.uniform2f(viewportSizeUniformLocation, (float)RENDER_SIZE.x(), (float)RENDER_SIZE.y()); 1400 } 1401 1402 if (texCoord.size() == 2*4) 1403 { 1404 Vec2 texCoordVec[4]; 1405 computeTexCoordVecs(texCoord, texCoordVec); 1406 log << TestLog::Message << "Texture coordinates run from " << texCoordVec[0] << " to " << texCoordVec[3] << TestLog::EndMessage; 1407 } 1408 else if (texCoord.size() == 3*4) 1409 { 1410 Vec3 texCoordVec[4]; 1411 computeTexCoordVecs(texCoord, texCoordVec); 1412 log << TestLog::Message << "Texture coordinates run from " << texCoordVec[0] << " to " << texCoordVec[3] << TestLog::EndMessage; 1413 } 1414 else 1415 DE_ASSERT(false); 1416 1417 glu::draw(renderCtx, m_program->getProgram(), (int)attrBindings.size(), &attrBindings[0], 1418 glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indices), &indices[0])); 1419 } 1420 1421 // Verify result. 1422 1423 { 1424 const tcu::TextureLevel rendered = getPixels(renderCtx, RENDER_SIZE, m_colorBufferFormat); 1425 1426 if (!verify(m_currentIteration, rendered.getAccess())) 1427 { 1428 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Result verification failed"); 1429 return STOP; 1430 } 1431 } 1432 1433 m_currentIteration++; 1434 if (m_currentIteration == (int)getNumIterations()) 1435 { 1436 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 1437 return STOP; 1438 } 1439 else 1440 return CONTINUE; 1441 } 1442 1443 template <typename TexViewT, typename TexCoordT> 1444 bool TextureGatherCase::verify (const ConstPixelBufferAccess& rendered, 1445 const TexViewT& texture, 1446 const TexCoordT (&texCoords)[4], 1447 const GatherArgs& gatherArgs) const 1448 { 1449 TestLog& log = m_testCtx.getLog(); 1450 1451 if (m_mipmapIncomplete) 1452 { 1453 const int componentNdx = de::max(0, gatherArgs.componentNdx); 1454 const Vec4 incompleteColor (0.0f, 0.0f, 0.0f, 1.0f); 1455 const Vec4 refColor (incompleteColor[componentNdx]); 1456 const bool isOk = verifySingleColored(log, rendered, refColor); 1457 1458 if (!isOk) 1459 log << TestLog::Message << "Note: expected color " << refColor << " for all pixels; " 1460 << incompleteColor[componentNdx] << " is component at index " << componentNdx 1461 << " in the color " << incompleteColor << ", which is used for incomplete textures" << TestLog::EndMessage; 1462 1463 return isOk; 1464 } 1465 else 1466 { 1467 DE_ASSERT(m_colorBufferFormat.order == tcu::TextureFormat::RGBA); 1468 DE_ASSERT(m_colorBufferFormat.type == tcu::TextureFormat::UNORM_INT8 || 1469 m_colorBufferFormat.type == tcu::TextureFormat::UNSIGNED_INT8 || 1470 m_colorBufferFormat.type == tcu::TextureFormat::SIGNED_INT8); 1471 1472 const MovePtr<PixelOffsets> pixelOffsets = makePixelOffsetsFunctor(m_gatherType, gatherArgs, getOffsetRange()); 1473 const tcu::PixelFormat pixelFormat = tcu::PixelFormat(8,8,8,8); 1474 const IVec4 colorBits = tcu::max(gls::TextureTestUtil::getBitsVec(pixelFormat) - 1, tcu::IVec4(0)); 1475 const IVec3 coordBits = m_textureType == TEXTURETYPE_2D ? IVec3(20,20,0) 1476 : m_textureType == TEXTURETYPE_CUBE ? IVec3(10,10,10) 1477 : m_textureType == TEXTURETYPE_2D_ARRAY ? IVec3(20,20,20) 1478 : IVec3(-1); 1479 const IVec3 uvwBits = m_textureType == TEXTURETYPE_2D ? IVec3(7,7,0) 1480 : m_textureType == TEXTURETYPE_CUBE ? IVec3(6,6,0) 1481 : m_textureType == TEXTURETYPE_2D_ARRAY ? IVec3(7,7,7) 1482 : IVec3(-1); 1483 tcu::Sampler sampler; 1484 sampler.wrapS = m_wrapS; 1485 sampler.wrapT = m_wrapT; 1486 sampler.compare = m_shadowCompareMode; 1487 1488 if (isDepthFormat(m_textureFormat)) 1489 { 1490 tcu::TexComparePrecision comparePrec; 1491 comparePrec.coordBits = coordBits; 1492 comparePrec.uvwBits = uvwBits; 1493 comparePrec.referenceBits = 16; 1494 comparePrec.resultBits = pixelFormat.redBits-1; 1495 1496 return verifyGatherOffsetsCompare(log, rendered, texture, texCoords, sampler, comparePrec, PixelCompareRefZDefault(RENDER_SIZE), *pixelOffsets); 1497 } 1498 else 1499 { 1500 const int componentNdx = de::max(0, gatherArgs.componentNdx); 1501 1502 if (isUnormFormatType(m_textureFormat.type)) 1503 { 1504 tcu::LookupPrecision lookupPrec; 1505 lookupPrec.colorThreshold = tcu::computeFixedPointThreshold(colorBits); 1506 lookupPrec.coordBits = coordBits; 1507 lookupPrec.uvwBits = uvwBits; 1508 lookupPrec.colorMask = gls::TextureTestUtil::getCompareMask(pixelFormat); 1509 return verifyGatherOffsets<float>(log, rendered, texture, texCoords, sampler, lookupPrec, componentNdx, *pixelOffsets); 1510 } 1511 else if (isUIntFormatType(m_textureFormat.type) || isSIntFormatType(m_textureFormat.type)) 1512 { 1513 tcu::IntLookupPrecision lookupPrec; 1514 lookupPrec.colorThreshold = UVec4(0); 1515 lookupPrec.coordBits = coordBits; 1516 lookupPrec.uvwBits = uvwBits; 1517 lookupPrec.colorMask = gls::TextureTestUtil::getCompareMask(pixelFormat); 1518 1519 if (isUIntFormatType(m_textureFormat.type)) 1520 return verifyGatherOffsets<deUint32>(log, rendered, texture, texCoords, sampler, lookupPrec, componentNdx, *pixelOffsets); 1521 else if (isSIntFormatType(m_textureFormat.type)) 1522 return verifyGatherOffsets<deInt32>(log, rendered, texture, texCoords, sampler, lookupPrec, componentNdx, *pixelOffsets); 1523 else 1524 { 1525 DE_ASSERT(false); 1526 return false; 1527 } 1528 } 1529 else 1530 { 1531 DE_ASSERT(false); 1532 return false; 1533 } 1534 } 1535 } 1536 } 1537 1538 vector<GatherArgs> generateBasic2DCaseIterations (GatherType gatherType, const tcu::TextureFormat& textureFormat, const IVec2& offsetRange) 1539 { 1540 const int numComponentCases = isDepthFormat(textureFormat) ? 1 : 4+1; // \note For non-depth textures, test explicit components 0 to 3 and implicit component 0. 1541 vector<GatherArgs> result; 1542 1543 for (int componentCaseNdx = 0; componentCaseNdx < numComponentCases; componentCaseNdx++) 1544 { 1545 const int componentNdx = componentCaseNdx - 1; 1546 1547 switch (gatherType) 1548 { 1549 case GATHERTYPE_BASIC: 1550 result.push_back(GatherArgs(componentNdx)); 1551 break; 1552 1553 case GATHERTYPE_OFFSET: 1554 { 1555 const int min = offsetRange.x(); 1556 const int max = offsetRange.y(); 1557 const int hmin = divRoundToZero(min, 2); 1558 const int hmax = divRoundToZero(max, 2); 1559 1560 result.push_back(GatherArgs(componentNdx, IVec2(min, max))); 1561 1562 if (componentCaseNdx == 0) // Don't test all offsets variants for all color components (they should be pretty orthogonal). 1563 { 1564 result.push_back(GatherArgs(componentNdx, IVec2(min, min))); 1565 result.push_back(GatherArgs(componentNdx, IVec2(max, min))); 1566 result.push_back(GatherArgs(componentNdx, IVec2(max, max))); 1567 1568 result.push_back(GatherArgs(componentNdx, IVec2(0, hmax))); 1569 result.push_back(GatherArgs(componentNdx, IVec2(hmin, 0))); 1570 result.push_back(GatherArgs(componentNdx, IVec2(0, 0))); 1571 } 1572 1573 break; 1574 } 1575 1576 case GATHERTYPE_OFFSET_DYNAMIC: 1577 result.push_back(GatherArgs(componentNdx)); 1578 break; 1579 1580 case GATHERTYPE_OFFSETS: 1581 { 1582 const int min = offsetRange.x(); 1583 const int max = offsetRange.y(); 1584 const int hmin = divRoundToZero(min, 2); 1585 const int hmax = divRoundToZero(max, 2); 1586 1587 result.push_back(GatherArgs(componentNdx, 1588 IVec2(min, min), 1589 IVec2(min, max), 1590 IVec2(max, min), 1591 IVec2(max, max))); 1592 1593 if (componentCaseNdx == 0) // Don't test all offsets variants for all color components (they should be pretty orthogonal). 1594 result.push_back(GatherArgs(componentNdx, 1595 IVec2(min, hmax), 1596 IVec2(hmin, max), 1597 IVec2(0, hmax), 1598 IVec2(hmax, 0))); 1599 break; 1600 } 1601 1602 default: 1603 DE_ASSERT(false); 1604 } 1605 } 1606 1607 return result; 1608 } 1609 1610 class TextureGather2DCase : public TextureGatherCase 1611 { 1612 public: 1613 TextureGather2DCase (Context& context, 1614 const char* name, 1615 const char* description, 1616 GatherType gatherType, 1617 OffsetSize offsetSize, 1618 tcu::TextureFormat textureFormat, 1619 tcu::Sampler::CompareMode shadowCompareMode, 1620 tcu::Sampler::WrapMode wrapS, 1621 tcu::Sampler::WrapMode wrapT, 1622 const MaybeTextureSwizzle& texSwizzle, 1623 tcu::Sampler::FilterMode minFilter, 1624 tcu::Sampler::FilterMode magFilter, 1625 int baseLevel, 1626 bool mipmapIncomplete, 1627 const IVec2& textureSize) 1628 : TextureGatherCase (context, name, description, TEXTURETYPE_2D, gatherType, offsetSize, textureFormat, shadowCompareMode, wrapS, wrapT, texSwizzle, minFilter, magFilter, baseLevel, mipmapIncomplete) 1629 , m_textureSize (textureSize) 1630 , m_swizzledTexture (tcu::TextureFormat(), 1, 1) 1631 { 1632 } 1633 1634 protected: 1635 void generateIterations (void); 1636 void createAndUploadTexture (void); 1637 int getNumIterations (void) const { DE_ASSERT(!m_iterations.empty()); return (int)m_iterations.size(); } 1638 GatherArgs getGatherArgs (int iterationNdx) const { return m_iterations[iterationNdx]; } 1639 vector<float> computeQuadTexCoord (int iterationNdx) const; 1640 bool verify (int iterationNdx, const ConstPixelBufferAccess& rendered) const; 1641 1642 private: 1643 const IVec2 m_textureSize; 1644 1645 MovePtr<glu::Texture2D> m_texture; 1646 tcu::Texture2D m_swizzledTexture; 1647 vector<GatherArgs> m_iterations; 1648 }; 1649 1650 vector<float> TextureGather2DCase::computeQuadTexCoord (int /* iterationNdx */) const 1651 { 1652 vector<float> res; 1653 gls::TextureTestUtil::computeQuadTexCoord2D(res, Vec2(-0.3f, -0.4f), Vec2(1.5f, 1.6f)); 1654 return res; 1655 } 1656 1657 void TextureGather2DCase::generateIterations (void) 1658 { 1659 DE_ASSERT(m_iterations.empty()); 1660 m_iterations = generateBasic2DCaseIterations(m_gatherType, m_textureFormat, getOffsetRange()); 1661 } 1662 1663 void TextureGather2DCase::createAndUploadTexture (void) 1664 { 1665 const glu::RenderContext& renderCtx = m_context.getRenderContext(); 1666 const glw::Functions& gl = renderCtx.getFunctions(); 1667 const tcu::TextureFormatInfo texFmtInfo = tcu::getTextureFormatInfo(m_textureFormat); 1668 1669 m_texture = MovePtr<glu::Texture2D>(new glu::Texture2D(renderCtx, glu::getInternalFormat(m_textureFormat), m_textureSize.x(), m_textureSize.y())); 1670 1671 { 1672 tcu::Texture2D& refTexture = m_texture->getRefTexture(); 1673 const int levelBegin = m_baseLevel; 1674 const int levelEnd = isMipmapFilter(m_minFilter) && !m_mipmapIncomplete ? refTexture.getNumLevels() : m_baseLevel+1; 1675 DE_ASSERT(m_baseLevel < refTexture.getNumLevels()); 1676 1677 for (int levelNdx = levelBegin; levelNdx < levelEnd; levelNdx++) 1678 { 1679 refTexture.allocLevel(levelNdx); 1680 const PixelBufferAccess& level = refTexture.getLevel(levelNdx); 1681 fillWithRandomColorTiles(level, texFmtInfo.valueMin, texFmtInfo.valueMax, (deUint32)m_testCtx.getCommandLine().getBaseSeed()); 1682 m_testCtx.getLog() << TestLog::Image("InputTextureLevel" + de::toString(levelNdx), "Input texture, level " + de::toString(levelNdx), level) 1683 << TestLog::Message << "Note: texture level's size is " << IVec2(level.getWidth(), level.getHeight()) << TestLog::EndMessage; 1684 } 1685 1686 swizzleTexture(m_swizzledTexture, refTexture, m_textureSwizzle); 1687 } 1688 1689 gl.activeTexture(GL_TEXTURE0); 1690 m_texture->upload(); 1691 } 1692 1693 bool TextureGather2DCase::verify (int iterationNdx, const ConstPixelBufferAccess& rendered) const 1694 { 1695 Vec2 texCoords[4]; 1696 computeTexCoordVecs(computeQuadTexCoord(iterationNdx), texCoords); 1697 return TextureGatherCase::verify(rendered, getOneLevelSubView(tcu::Texture2DView(m_swizzledTexture), m_baseLevel), texCoords, m_iterations[iterationNdx]); 1698 } 1699 1700 class TextureGather2DArrayCase : public TextureGatherCase 1701 { 1702 public: 1703 TextureGather2DArrayCase (Context& context, 1704 const char* name, 1705 const char* description, 1706 GatherType gatherType, 1707 OffsetSize offsetSize, 1708 tcu::TextureFormat textureFormat, 1709 tcu::Sampler::CompareMode shadowCompareMode, 1710 tcu::Sampler::WrapMode wrapS, 1711 tcu::Sampler::WrapMode wrapT, 1712 const MaybeTextureSwizzle& texSwizzle, 1713 tcu::Sampler::FilterMode minFilter, 1714 tcu::Sampler::FilterMode magFilter, 1715 int baseLevel, 1716 bool mipmapIncomplete, 1717 const IVec3& textureSize) 1718 : TextureGatherCase (context, name, description, TEXTURETYPE_2D_ARRAY, gatherType, offsetSize, textureFormat, shadowCompareMode, wrapS, wrapT, texSwizzle, minFilter, magFilter, baseLevel, mipmapIncomplete) 1719 , m_textureSize (textureSize) 1720 , m_swizzledTexture (tcu::TextureFormat(), 1, 1, 1) 1721 { 1722 } 1723 1724 protected: 1725 void generateIterations (void); 1726 void createAndUploadTexture (void); 1727 int getNumIterations (void) const { DE_ASSERT(!m_iterations.empty()); return (int)m_iterations.size(); } 1728 GatherArgs getGatherArgs (int iterationNdx) const { return m_iterations[iterationNdx].gatherArgs; } 1729 vector<float> computeQuadTexCoord (int iterationNdx) const; 1730 bool verify (int iterationNdx, const ConstPixelBufferAccess& rendered) const; 1731 1732 private: 1733 struct Iteration 1734 { 1735 GatherArgs gatherArgs; 1736 int layerNdx; 1737 }; 1738 1739 const IVec3 m_textureSize; 1740 1741 MovePtr<glu::Texture2DArray> m_texture; 1742 tcu::Texture2DArray m_swizzledTexture; 1743 vector<Iteration> m_iterations; 1744 }; 1745 1746 vector<float> TextureGather2DArrayCase::computeQuadTexCoord (int iterationNdx) const 1747 { 1748 vector<float> res; 1749 gls::TextureTestUtil::computeQuadTexCoord2DArray(res, m_iterations[iterationNdx].layerNdx, Vec2(-0.3f, -0.4f), Vec2(1.5f, 1.6f)); 1750 return res; 1751 } 1752 1753 void TextureGather2DArrayCase::generateIterations (void) 1754 { 1755 DE_ASSERT(m_iterations.empty()); 1756 1757 const vector<GatherArgs> basicIterations = generateBasic2DCaseIterations(m_gatherType, m_textureFormat, getOffsetRange()); 1758 1759 // \note Out-of-bounds layer indices are tested too. 1760 for (int layerNdx = -1; layerNdx < m_textureSize.z()+1; layerNdx++) 1761 { 1762 // Don't duplicate all cases for all layers. 1763 if (layerNdx == 0) 1764 { 1765 for (int basicNdx = 0; basicNdx < (int)basicIterations.size(); basicNdx++) 1766 { 1767 m_iterations.push_back(Iteration()); 1768 m_iterations.back().gatherArgs = basicIterations[basicNdx]; 1769 m_iterations.back().layerNdx = layerNdx; 1770 } 1771 } 1772 else 1773 { 1774 // For other layers than 0, only test one component and one set of offsets per layer. 1775 for (int basicNdx = 0; basicNdx < (int)basicIterations.size(); basicNdx++) 1776 { 1777 if (isDepthFormat(m_textureFormat) || basicIterations[basicNdx].componentNdx == (layerNdx + 2) % 4) 1778 { 1779 m_iterations.push_back(Iteration()); 1780 m_iterations.back().gatherArgs = basicIterations[basicNdx]; 1781 m_iterations.back().layerNdx = layerNdx; 1782 break; 1783 } 1784 } 1785 } 1786 } 1787 } 1788 1789 void TextureGather2DArrayCase::createAndUploadTexture (void) 1790 { 1791 TestLog& log = m_testCtx.getLog(); 1792 const glu::RenderContext& renderCtx = m_context.getRenderContext(); 1793 const glw::Functions& gl = renderCtx.getFunctions(); 1794 const tcu::TextureFormatInfo texFmtInfo = tcu::getTextureFormatInfo(m_textureFormat); 1795 1796 m_texture = MovePtr<glu::Texture2DArray>(new glu::Texture2DArray(renderCtx, glu::getInternalFormat(m_textureFormat), m_textureSize.x(), m_textureSize.y(), m_textureSize.z())); 1797 1798 { 1799 tcu::Texture2DArray& refTexture = m_texture->getRefTexture(); 1800 const int levelBegin = m_baseLevel; 1801 const int levelEnd = isMipmapFilter(m_minFilter) && !m_mipmapIncomplete ? refTexture.getNumLevels() : m_baseLevel+1; 1802 DE_ASSERT(m_baseLevel < refTexture.getNumLevels()); 1803 1804 for (int levelNdx = levelBegin; levelNdx < levelEnd; levelNdx++) 1805 { 1806 refTexture.allocLevel(levelNdx); 1807 const PixelBufferAccess& level = refTexture.getLevel(levelNdx); 1808 fillWithRandomColorTiles(level, texFmtInfo.valueMin, texFmtInfo.valueMax, (deUint32)m_testCtx.getCommandLine().getBaseSeed()); 1809 1810 log << TestLog::ImageSet("InputTextureLevel", "Input texture, level " + de::toString(levelNdx)); 1811 for (int layerNdx = 0; layerNdx < m_textureSize.z(); layerNdx++) 1812 log << TestLog::Image("InputTextureLevel" + de::toString(layerNdx) + "Layer" + de::toString(layerNdx), 1813 "Layer " + de::toString(layerNdx), 1814 tcu::getSubregion(level, 0, 0, layerNdx, level.getWidth(), level.getHeight(), 1)); 1815 log << TestLog::EndImageSet 1816 << TestLog::Message << "Note: texture level's size is " << IVec3(level.getWidth(), level.getHeight(), level.getDepth()) << TestLog::EndMessage; 1817 } 1818 1819 swizzleTexture(m_swizzledTexture, refTexture, m_textureSwizzle); 1820 } 1821 1822 gl.activeTexture(GL_TEXTURE0); 1823 m_texture->upload(); 1824 } 1825 1826 bool TextureGather2DArrayCase::verify (int iterationNdx, const ConstPixelBufferAccess& rendered) const 1827 { 1828 Vec3 texCoords[4]; 1829 computeTexCoordVecs(computeQuadTexCoord(iterationNdx), texCoords); 1830 return TextureGatherCase::verify(rendered, getOneLevelSubView(tcu::Texture2DArrayView(m_swizzledTexture), m_baseLevel), texCoords, m_iterations[iterationNdx].gatherArgs); 1831 } 1832 1833 // \note Cube case always uses just basic textureGather(); offset versions are not defined for cube maps. 1834 class TextureGatherCubeCase : public TextureGatherCase 1835 { 1836 public: 1837 TextureGatherCubeCase (Context& context, 1838 const char* name, 1839 const char* description, 1840 tcu::TextureFormat textureFormat, 1841 tcu::Sampler::CompareMode shadowCompareMode, 1842 tcu::Sampler::WrapMode wrapS, 1843 tcu::Sampler::WrapMode wrapT, 1844 const MaybeTextureSwizzle& texSwizzle, 1845 tcu::Sampler::FilterMode minFilter, 1846 tcu::Sampler::FilterMode magFilter, 1847 int baseLevel, 1848 bool mipmapIncomplete, 1849 int textureSize) 1850 : TextureGatherCase (context, name, description, TEXTURETYPE_CUBE, GATHERTYPE_BASIC, OFFSETSIZE_NONE, textureFormat, shadowCompareMode, wrapS, wrapT, texSwizzle, minFilter, magFilter, baseLevel, mipmapIncomplete) 1851 , m_textureSize (textureSize) 1852 , m_swizzledTexture (tcu::TextureFormat(), 1) 1853 { 1854 } 1855 1856 protected: 1857 void generateIterations (void); 1858 void createAndUploadTexture (void); 1859 int getNumIterations (void) const { DE_ASSERT(!m_iterations.empty()); return (int)m_iterations.size(); } 1860 GatherArgs getGatherArgs (int iterationNdx) const { return m_iterations[iterationNdx].gatherArgs; } 1861 vector<float> computeQuadTexCoord (int iterationNdx) const; 1862 bool verify (int iterationNdx, const ConstPixelBufferAccess& rendered) const; 1863 1864 private: 1865 struct Iteration 1866 { 1867 GatherArgs gatherArgs; 1868 tcu::CubeFace face; 1869 }; 1870 1871 const int m_textureSize; 1872 1873 MovePtr<glu::TextureCube> m_texture; 1874 tcu::TextureCube m_swizzledTexture; 1875 vector<Iteration> m_iterations; 1876 }; 1877 1878 vector<float> TextureGatherCubeCase::computeQuadTexCoord (int iterationNdx) const 1879 { 1880 vector<float> res; 1881 gls::TextureTestUtil::computeQuadTexCoordCube(res, m_iterations[iterationNdx].face, Vec2(-1.2f), Vec2(1.2f)); 1882 return res; 1883 } 1884 1885 void TextureGatherCubeCase::generateIterations (void) 1886 { 1887 DE_ASSERT(m_iterations.empty()); 1888 1889 const vector<GatherArgs> basicIterations = generateBasic2DCaseIterations(m_gatherType, m_textureFormat, getOffsetRange()); 1890 1891 for (int cubeFaceI = 0; cubeFaceI < tcu::CUBEFACE_LAST; cubeFaceI++) 1892 { 1893 const tcu::CubeFace cubeFace = (tcu::CubeFace)cubeFaceI; 1894 1895 // Don't duplicate all cases for all faces. 1896 if (cubeFaceI == 0) 1897 { 1898 for (int basicNdx = 0; basicNdx < (int)basicIterations.size(); basicNdx++) 1899 { 1900 m_iterations.push_back(Iteration()); 1901 m_iterations.back().gatherArgs = basicIterations[basicNdx]; 1902 m_iterations.back().face = cubeFace; 1903 } 1904 } 1905 else 1906 { 1907 // For other faces than first, only test one component per face. 1908 for (int basicNdx = 0; basicNdx < (int)basicIterations.size(); basicNdx++) 1909 { 1910 if (isDepthFormat(m_textureFormat) || basicIterations[basicNdx].componentNdx == cubeFaceI % 4) 1911 { 1912 m_iterations.push_back(Iteration()); 1913 m_iterations.back().gatherArgs = basicIterations[basicNdx]; 1914 m_iterations.back().face = cubeFace; 1915 break; 1916 } 1917 } 1918 } 1919 } 1920 } 1921 1922 void TextureGatherCubeCase::createAndUploadTexture (void) 1923 { 1924 TestLog& log = m_testCtx.getLog(); 1925 const glu::RenderContext& renderCtx = m_context.getRenderContext(); 1926 const glw::Functions& gl = renderCtx.getFunctions(); 1927 const tcu::TextureFormatInfo texFmtInfo = tcu::getTextureFormatInfo(m_textureFormat); 1928 1929 m_texture = MovePtr<glu::TextureCube>(new glu::TextureCube(renderCtx, glu::getInternalFormat(m_textureFormat), m_textureSize)); 1930 1931 { 1932 tcu::TextureCube& refTexture = m_texture->getRefTexture(); 1933 const int levelBegin = m_baseLevel; 1934 const int levelEnd = isMipmapFilter(m_minFilter) && !m_mipmapIncomplete ? refTexture.getNumLevels() : m_baseLevel+1; 1935 DE_ASSERT(m_baseLevel < refTexture.getNumLevels()); 1936 1937 for (int levelNdx = levelBegin; levelNdx < levelEnd; levelNdx++) 1938 { 1939 log << TestLog::ImageSet("InputTextureLevel" + de::toString(levelNdx), "Input texture, level " + de::toString(levelNdx)); 1940 1941 for (int cubeFaceI = 0; cubeFaceI < tcu::CUBEFACE_LAST; cubeFaceI++) 1942 { 1943 const tcu::CubeFace cubeFace = (tcu::CubeFace)cubeFaceI; 1944 refTexture.allocLevel(cubeFace, levelNdx); 1945 const PixelBufferAccess& levelFace = refTexture.getLevelFace(levelNdx, cubeFace); 1946 fillWithRandomColorTiles(levelFace, texFmtInfo.valueMin, texFmtInfo.valueMax, (deUint32)m_testCtx.getCommandLine().getBaseSeed() ^ (deUint32)cubeFaceI); 1947 1948 m_testCtx.getLog() << TestLog::Image("InputTextureLevel" + de::toString(levelNdx) + "Face" + de::toString((int)cubeFace), 1949 de::toString(cubeFace), 1950 levelFace); 1951 } 1952 1953 log << TestLog::EndImageSet 1954 << TestLog::Message << "Note: texture level's size is " << refTexture.getLevelFace(levelNdx, tcu::CUBEFACE_NEGATIVE_X).getWidth() << TestLog::EndMessage; 1955 } 1956 1957 swizzleTexture(m_swizzledTexture, refTexture, m_textureSwizzle); 1958 } 1959 1960 gl.activeTexture(GL_TEXTURE0); 1961 m_texture->upload(); 1962 } 1963 1964 bool TextureGatherCubeCase::verify (int iterationNdx, const ConstPixelBufferAccess& rendered) const 1965 { 1966 Vec3 texCoords[4]; 1967 computeTexCoordVecs(computeQuadTexCoord(iterationNdx), texCoords); 1968 return TextureGatherCase::verify(rendered, getOneLevelSubView(tcu::TextureCubeView(m_swizzledTexture), m_baseLevel), texCoords, m_iterations[iterationNdx].gatherArgs); 1969 } 1970 1971 static inline TextureGatherCase* makeTextureGatherCase (TextureType textureType, 1972 Context& context, 1973 const char* name, 1974 const char* description, 1975 GatherType gatherType, 1976 OffsetSize offsetSize, 1977 tcu::TextureFormat textureFormat, 1978 tcu::Sampler::CompareMode shadowCompareMode, 1979 tcu::Sampler::WrapMode wrapS, 1980 tcu::Sampler::WrapMode wrapT, 1981 const MaybeTextureSwizzle& texSwizzle, 1982 tcu::Sampler::FilterMode minFilter, 1983 tcu::Sampler::FilterMode magFilter, 1984 int baseLevel, 1985 const IVec3& textureSize, 1986 bool mipmapIncomplete = false) 1987 { 1988 switch (textureType) 1989 { 1990 case TEXTURETYPE_2D: 1991 return new TextureGather2DCase(context, name, description, gatherType, offsetSize, textureFormat, shadowCompareMode, 1992 wrapS, wrapT, texSwizzle, minFilter, magFilter, baseLevel, mipmapIncomplete, textureSize.swizzle(0, 1)); 1993 1994 case TEXTURETYPE_2D_ARRAY: 1995 return new TextureGather2DArrayCase(context, name, description, gatherType, offsetSize, textureFormat, shadowCompareMode, 1996 wrapS, wrapT, texSwizzle, minFilter, magFilter, baseLevel, mipmapIncomplete, textureSize); 1997 1998 case TEXTURETYPE_CUBE: 1999 DE_ASSERT(gatherType == GATHERTYPE_BASIC); 2000 DE_ASSERT(offsetSize == OFFSETSIZE_NONE); 2001 return new TextureGatherCubeCase(context, name, description, textureFormat, shadowCompareMode, 2002 wrapS, wrapT, texSwizzle, minFilter, magFilter, baseLevel, mipmapIncomplete, textureSize.x()); 2003 2004 default: 2005 DE_ASSERT(false); 2006 return DE_NULL; 2007 } 2008 } 2009 2010 } // anonymous 2011 2012 TextureGatherTests::TextureGatherTests (Context& context) 2013 : TestCaseGroup(context, "gather", "textureGather* tests") 2014 { 2015 } 2016 2017 static inline const char* compareModeName (tcu::Sampler::CompareMode mode) 2018 { 2019 switch (mode) 2020 { 2021 case tcu::Sampler::COMPAREMODE_LESS: return "less"; 2022 case tcu::Sampler::COMPAREMODE_LESS_OR_EQUAL: return "less_or_equal"; 2023 case tcu::Sampler::COMPAREMODE_GREATER: return "greater"; 2024 case tcu::Sampler::COMPAREMODE_GREATER_OR_EQUAL: return "greater_or_equal"; 2025 case tcu::Sampler::COMPAREMODE_EQUAL: return "equal"; 2026 case tcu::Sampler::COMPAREMODE_NOT_EQUAL: return "not_equal"; 2027 case tcu::Sampler::COMPAREMODE_ALWAYS: return "always"; 2028 case tcu::Sampler::COMPAREMODE_NEVER: return "never"; 2029 default: DE_ASSERT(false); return DE_NULL; 2030 } 2031 } 2032 2033 void TextureGatherTests::init (void) 2034 { 2035 const struct 2036 { 2037 const char* name; 2038 TextureType type; 2039 } textureTypes[] = 2040 { 2041 { "2d", TEXTURETYPE_2D }, 2042 { "2d_array", TEXTURETYPE_2D_ARRAY }, 2043 { "cube", TEXTURETYPE_CUBE } 2044 }; 2045 2046 const struct 2047 { 2048 const char* name; 2049 tcu::TextureFormat format; 2050 } formats[] = 2051 { 2052 { "rgba8", tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8) }, 2053 { "rgba8ui", tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNSIGNED_INT8) }, 2054 { "rgba8i", tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::SIGNED_INT8) }, 2055 { "depth32f", tcu::TextureFormat(tcu::TextureFormat::D, tcu::TextureFormat::FLOAT) } 2056 }; 2057 2058 const struct 2059 { 2060 const char* name; 2061 IVec3 size; 2062 } textureSizes[] = 2063 { 2064 { "size_pot", IVec3(64, 64, 3) }, 2065 { "size_npot", IVec3(17, 23, 3) } 2066 }; 2067 2068 const struct 2069 { 2070 const char* name; 2071 tcu::Sampler::WrapMode mode; 2072 } wrapModes[] = 2073 { 2074 { "clamp_to_edge", tcu::Sampler::CLAMP_TO_EDGE }, 2075 { "repeat", tcu::Sampler::REPEAT_GL }, 2076 { "mirrored_repeat", tcu::Sampler::MIRRORED_REPEAT_GL } 2077 }; 2078 2079 for (int gatherTypeI = 0; gatherTypeI < GATHERTYPE_LAST; gatherTypeI++) 2080 { 2081 const GatherType gatherType = (GatherType)gatherTypeI; 2082 TestCaseGroup* const gatherTypeGroup = new TestCaseGroup(m_context, gatherTypeName(gatherType), gatherTypeDescription(gatherType)); 2083 addChild(gatherTypeGroup); 2084 2085 for (int offsetSizeI = 0; offsetSizeI < OFFSETSIZE_LAST; offsetSizeI++) 2086 { 2087 const OffsetSize offsetSize = (OffsetSize)offsetSizeI; 2088 if ((gatherType == GATHERTYPE_BASIC) != (offsetSize == OFFSETSIZE_NONE)) 2089 continue; 2090 2091 TestCaseGroup* const offsetSizeGroup = offsetSize == OFFSETSIZE_NONE ? 2092 gatherTypeGroup : 2093 new TestCaseGroup(m_context, 2094 offsetSize == OFFSETSIZE_MINIMUM_REQUIRED ? "min_required_offset" 2095 : offsetSize == OFFSETSIZE_IMPLEMENTATION_MAXIMUM ? "implementation_offset" 2096 : DE_NULL, 2097 offsetSize == OFFSETSIZE_MINIMUM_REQUIRED ? "Use offsets within GL minimum required range" 2098 : offsetSize == OFFSETSIZE_IMPLEMENTATION_MAXIMUM ? "Use offsets within the implementation range" 2099 : DE_NULL); 2100 if (offsetSizeGroup != gatherTypeGroup) 2101 gatherTypeGroup->addChild(offsetSizeGroup); 2102 2103 for (int textureTypeNdx = 0; textureTypeNdx < DE_LENGTH_OF_ARRAY(textureTypes); textureTypeNdx++) 2104 { 2105 const TextureType textureType = textureTypes[textureTypeNdx].type; 2106 2107 if (textureType == TEXTURETYPE_CUBE && gatherType != GATHERTYPE_BASIC) 2108 continue; 2109 2110 TestCaseGroup* const textureTypeGroup = new TestCaseGroup(m_context, textureTypes[textureTypeNdx].name, ""); 2111 offsetSizeGroup->addChild(textureTypeGroup); 2112 2113 for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(formats); formatNdx++) 2114 { 2115 const tcu::TextureFormat& format = formats[formatNdx].format; 2116 TestCaseGroup* const formatGroup = new TestCaseGroup(m_context, formats[formatNdx].name, ""); 2117 textureTypeGroup->addChild(formatGroup); 2118 2119 for (int textureSizeNdx = 0; textureSizeNdx < DE_LENGTH_OF_ARRAY(textureSizes); textureSizeNdx++) 2120 { 2121 const IVec3& textureSize = textureSizes[textureSizeNdx].size; 2122 TestCaseGroup* const textureSizeGroup = new TestCaseGroup(m_context, textureSizes[textureSizeNdx].name, ""); 2123 formatGroup->addChild(textureSizeGroup); 2124 2125 for (int compareModeI = 0; compareModeI < tcu::Sampler::COMPAREMODE_LAST; compareModeI++) 2126 { 2127 const tcu::Sampler::CompareMode compareMode = (tcu::Sampler::CompareMode)compareModeI; 2128 2129 if ((compareMode != tcu::Sampler::COMPAREMODE_NONE) != isDepthFormat(format)) 2130 continue; 2131 2132 if (compareMode != tcu::Sampler::COMPAREMODE_NONE && 2133 compareMode != tcu::Sampler::COMPAREMODE_LESS && 2134 compareMode != tcu::Sampler::COMPAREMODE_GREATER) 2135 continue; 2136 2137 TestCaseGroup* const compareModeGroup = compareMode == tcu::Sampler::COMPAREMODE_NONE ? 2138 textureSizeGroup : 2139 new TestCaseGroup(m_context, 2140 (string() + "compare_" + compareModeName(compareMode)).c_str(), 2141 ""); 2142 if (compareModeGroup != textureSizeGroup) 2143 textureSizeGroup->addChild(compareModeGroup); 2144 2145 for (int wrapCaseNdx = 0; wrapCaseNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapCaseNdx++) 2146 { 2147 const int wrapSNdx = wrapCaseNdx; 2148 const int wrapTNdx = (wrapCaseNdx + 1) % DE_LENGTH_OF_ARRAY(wrapModes); 2149 const tcu::Sampler::WrapMode wrapS = wrapModes[wrapSNdx].mode; 2150 const tcu::Sampler::WrapMode wrapT = wrapModes[wrapTNdx].mode; 2151 2152 const string caseName = string() + wrapModes[wrapSNdx].name + "_" + wrapModes[wrapTNdx].name; 2153 2154 compareModeGroup->addChild(makeTextureGatherCase(textureType, m_context, caseName.c_str(), "", gatherType, offsetSize, format, compareMode, wrapS, wrapT, 2155 MaybeTextureSwizzle::createNoneTextureSwizzle(), tcu::Sampler::NEAREST, tcu::Sampler::NEAREST, 0, textureSize)); 2156 } 2157 } 2158 } 2159 2160 if (offsetSize != OFFSETSIZE_MINIMUM_REQUIRED) // Don't test all features for both offset size types, as they should be rather orthogonal. 2161 { 2162 if (!isDepthFormat(format)) 2163 { 2164 TestCaseGroup* const swizzleGroup = new TestCaseGroup(m_context, "texture_swizzle", ""); 2165 formatGroup->addChild(swizzleGroup); 2166 2167 DE_STATIC_ASSERT(TEXTURESWIZZLECOMPONENT_R == 0); 2168 for (int swizzleCaseNdx = 0; swizzleCaseNdx < TEXTURESWIZZLECOMPONENT_LAST; swizzleCaseNdx++) 2169 { 2170 MaybeTextureSwizzle swizzle = MaybeTextureSwizzle::createSomeTextureSwizzle(); 2171 string caseName; 2172 2173 for (int i = 0; i < 4; i++) 2174 { 2175 swizzle.getSwizzle()[i] = (TextureSwizzleComponent)((swizzleCaseNdx + i) % (int)TEXTURESWIZZLECOMPONENT_LAST); 2176 caseName += (i > 0 ? "_" : "") + de::toLower(de::toString(swizzle.getSwizzle()[i])); 2177 } 2178 2179 swizzleGroup->addChild(makeTextureGatherCase(textureType, m_context, caseName.c_str(), "", gatherType, offsetSize, format, 2180 tcu::Sampler::COMPAREMODE_NONE, tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL, 2181 swizzle, tcu::Sampler::NEAREST, tcu::Sampler::NEAREST, 0, IVec3(64, 64, 3))); 2182 } 2183 } 2184 2185 { 2186 TestCaseGroup* const filterModeGroup = new TestCaseGroup(m_context, "filter_mode", "Test that filter modes have no effect"); 2187 formatGroup->addChild(filterModeGroup); 2188 2189 const struct 2190 { 2191 const char* name; 2192 tcu::Sampler::FilterMode filter; 2193 } magFilters[] = 2194 { 2195 { "linear", tcu::Sampler::LINEAR }, 2196 { "nearest", tcu::Sampler::NEAREST } 2197 }; 2198 2199 const struct 2200 { 2201 const char* name; 2202 tcu::Sampler::FilterMode filter; 2203 } minFilters[] = 2204 { 2205 // \note Don't test NEAREST here, as it's covered by other cases. 2206 { "linear", tcu::Sampler::LINEAR }, 2207 { "nearest_mipmap_nearest", tcu::Sampler::NEAREST_MIPMAP_NEAREST }, 2208 { "nearest_mipmap_linear", tcu::Sampler::NEAREST_MIPMAP_LINEAR }, 2209 { "linear_mipmap_nearest", tcu::Sampler::LINEAR_MIPMAP_NEAREST }, 2210 { "linear_mipmap_linear", tcu::Sampler::LINEAR_MIPMAP_LINEAR }, 2211 }; 2212 2213 for (int minFilterNdx = 0; minFilterNdx < DE_LENGTH_OF_ARRAY(minFilters); minFilterNdx++) 2214 for (int magFilterNdx = 0; magFilterNdx < DE_LENGTH_OF_ARRAY(magFilters); magFilterNdx++) 2215 { 2216 const tcu::Sampler::FilterMode minFilter = minFilters[minFilterNdx].filter; 2217 const tcu::Sampler::FilterMode magFilter = magFilters[magFilterNdx].filter; 2218 const tcu::Sampler::CompareMode compareMode = isDepthFormat(format) ? tcu::Sampler::COMPAREMODE_LESS : tcu::Sampler::COMPAREMODE_NONE; 2219 2220 if ((isUnormFormatType(format.type) || isDepthFormat(format)) && magFilter == tcu::Sampler::NEAREST) 2221 continue; // Covered by other cases. 2222 if ((isUIntFormatType(format.type) || isSIntFormatType(format.type)) && 2223 (magFilter != tcu::Sampler::NEAREST || minFilter != tcu::Sampler::NEAREST_MIPMAP_NEAREST)) 2224 continue; 2225 2226 const string caseName = string() + "min_" + minFilters[minFilterNdx].name + "_mag_" + magFilters[magFilterNdx].name; 2227 2228 filterModeGroup->addChild(makeTextureGatherCase(textureType, m_context, caseName.c_str(), "", gatherType, offsetSize, format, compareMode, 2229 tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL, MaybeTextureSwizzle::createNoneTextureSwizzle(), 2230 minFilter, magFilter, 0, IVec3(64, 64, 3))); 2231 } 2232 } 2233 2234 { 2235 TestCaseGroup* const baseLevelGroup = new TestCaseGroup(m_context, "base_level", ""); 2236 formatGroup->addChild(baseLevelGroup); 2237 2238 for (int baseLevel = 1; baseLevel <= 2; baseLevel++) 2239 { 2240 const string caseName = "level_" + de::toString(baseLevel); 2241 const tcu::Sampler::CompareMode compareMode = isDepthFormat(format) ? tcu::Sampler::COMPAREMODE_LESS : tcu::Sampler::COMPAREMODE_NONE; 2242 baseLevelGroup->addChild(makeTextureGatherCase(textureType, m_context, caseName.c_str(), "", gatherType, offsetSize, format, 2243 compareMode, tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL, 2244 MaybeTextureSwizzle::createNoneTextureSwizzle(), tcu::Sampler::NEAREST, tcu::Sampler::NEAREST, 2245 baseLevel, IVec3(64, 64, 3))); 2246 } 2247 } 2248 2249 if (!isDepthFormat(format)) // What shadow textures should return for incomplete textures is unclear. 2250 { 2251 TestCaseGroup* const incompleteGroup = new TestCaseGroup(m_context, "incomplete", "Test that textureGather* takes components from (0,0,0,1) for incomplete textures"); 2252 formatGroup->addChild(incompleteGroup); 2253 2254 const tcu::Sampler::CompareMode compareMode = isDepthFormat(format) ? tcu::Sampler::COMPAREMODE_LESS : tcu::Sampler::COMPAREMODE_NONE; 2255 incompleteGroup->addChild(makeTextureGatherCase(textureType, m_context, "mipmap_incomplete", "", gatherType, offsetSize, format, 2256 compareMode, tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL, 2257 MaybeTextureSwizzle::createNoneTextureSwizzle(), tcu::Sampler::NEAREST_MIPMAP_NEAREST, tcu::Sampler::NEAREST, 2258 0, IVec3(64, 64, 3), true /* Mipmap-incomplete */)); 2259 } 2260 } 2261 } 2262 } 2263 } 2264 } 2265 } 2266 2267 } // Functional 2268 } // gles31 2269 } // deqp 2270