1 /*------------------------------------------------------------------------ 2 * Vulkan Conformance Tests 3 * ------------------------ 4 * 5 * Copyright (c) 2016 The Khronos Group Inc. 6 * Copyright (c) 2016 Samsung Electronics Co., Ltd. 7 * Copyright (c) 2016 The Android Open Source Project 8 * 9 * Licensed under the Apache License, Version 2.0 (the "License"); 10 * you may not use this file except in compliance with the License. 11 * You may obtain a copy of the License at 12 * 13 * http://www.apache.org/licenses/LICENSE-2.0 14 * 15 * Unless required by applicable law or agreed to in writing, software 16 * distributed under the License is distributed on an "AS IS" BASIS, 17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 * See the License for the specific language governing permissions and 19 * limitations under the License. 20 * 21 *//*! 22 * \file 23 * \brief GLSL textureGather[Offset[s]] tests. 24 *//*--------------------------------------------------------------------*/ 25 26 #include "vktShaderRenderTextureGatherTests.hpp" 27 #include "vktShaderRender.hpp" 28 #include "vkImageUtil.hpp" 29 #include "gluTextureUtil.hpp" 30 #include "tcuTexture.hpp" 31 #include "tcuTextureUtil.hpp" 32 #include "tcuSurface.hpp" 33 #include "tcuTestLog.hpp" 34 #include "tcuVectorUtil.hpp" 35 #include "tcuTexLookupVerifier.hpp" 36 #include "tcuTexCompareVerifier.hpp" 37 #include "tcuPixelFormat.hpp" 38 #include "tcuCommandLine.hpp" 39 #include "deUniquePtr.hpp" 40 #include "deStringUtil.hpp" 41 #include "deRandom.hpp" 42 43 using tcu::ConstPixelBufferAccess; 44 using tcu::PixelBufferAccess; 45 using tcu::TestLog; 46 using tcu::IVec2; 47 using tcu::IVec3; 48 using tcu::IVec4; 49 using tcu::UVec4; 50 using tcu::Vec2; 51 using tcu::Vec3; 52 using tcu::Vec4; 53 using de::MovePtr; 54 55 using std::string; 56 using std::vector; 57 58 namespace vkt 59 { 60 namespace sr 61 { 62 namespace 63 { 64 65 typedef ShaderRenderCaseInstance::ImageBackingMode ImageBackingMode; 66 67 enum 68 { 69 SPEC_MAX_MIN_OFFSET = -8, 70 SPEC_MIN_MAX_OFFSET = 7 71 }; 72 73 enum TextureType 74 { 75 TEXTURETYPE_2D, 76 TEXTURETYPE_2D_ARRAY, 77 TEXTURETYPE_CUBE, 78 79 TEXTURETYPE_LAST 80 }; 81 82 // \note TextureTestUtil functions are copied from glsTextureTestUtil 83 namespace TextureTestUtil 84 { 85 86 inline tcu::IVec4 getBitsVec (const tcu::PixelFormat& format) 87 { 88 return tcu::IVec4(format.redBits, format.greenBits, format.blueBits, format.alphaBits); 89 } 90 91 inline tcu::BVec4 getCompareMask (const tcu::PixelFormat& format) 92 { 93 return tcu::BVec4(format.redBits > 0, 94 format.greenBits > 0, 95 format.blueBits > 0, 96 format.alphaBits > 0); 97 } 98 99 void computeQuadTexCoord2D (std::vector<float>& dst, const tcu::Vec2& bottomLeft, const tcu::Vec2& topRight) 100 { 101 dst.resize(4*2); 102 103 dst[0] = bottomLeft.x(); dst[1] = bottomLeft.y(); 104 dst[2] = bottomLeft.x(); dst[3] = topRight.y(); 105 dst[4] = topRight.x(); dst[5] = bottomLeft.y(); 106 dst[6] = topRight.x(); dst[7] = topRight.y(); 107 } 108 109 void computeQuadTexCoord2DArray (std::vector<float>& dst, int layerNdx, const tcu::Vec2& bottomLeft, const tcu::Vec2& topRight) 110 { 111 dst.resize(4*3); 112 113 dst[0] = bottomLeft.x(); dst[ 1] = bottomLeft.y(); dst[ 2] = (float)layerNdx; 114 dst[3] = bottomLeft.x(); dst[ 4] = topRight.y(); dst[ 5] = (float)layerNdx; 115 dst[6] = topRight.x(); dst[ 7] = bottomLeft.y(); dst[ 8] = (float)layerNdx; 116 dst[9] = topRight.x(); dst[10] = topRight.y(); dst[11] = (float)layerNdx; 117 } 118 119 void computeQuadTexCoordCube (std::vector<float>& dst, tcu::CubeFace face, const tcu::Vec2& bottomLeft, const tcu::Vec2& topRight) 120 { 121 int sRow = 0; 122 int tRow = 0; 123 int mRow = 0; 124 float sSign = 1.0f; 125 float tSign = 1.0f; 126 float mSign = 1.0f; 127 128 switch (face) 129 { 130 case tcu::CUBEFACE_NEGATIVE_X: mRow = 0; sRow = 2; tRow = 1; mSign = -1.0f; tSign = -1.0f; break; 131 case tcu::CUBEFACE_POSITIVE_X: mRow = 0; sRow = 2; tRow = 1; sSign = -1.0f; tSign = -1.0f; break; 132 case tcu::CUBEFACE_NEGATIVE_Y: mRow = 1; sRow = 0; tRow = 2; mSign = -1.0f; tSign = -1.0f; break; 133 case tcu::CUBEFACE_POSITIVE_Y: mRow = 1; sRow = 0; tRow = 2; break; 134 case tcu::CUBEFACE_NEGATIVE_Z: mRow = 2; sRow = 0; tRow = 1; mSign = -1.0f; sSign = -1.0f; tSign = -1.0f; break; 135 case tcu::CUBEFACE_POSITIVE_Z: mRow = 2; sRow = 0; tRow = 1; tSign = -1.0f; break; 136 default: 137 DE_ASSERT(DE_FALSE); 138 return; 139 } 140 141 dst.resize(3*4); 142 143 dst[0+mRow] = mSign; 144 dst[3+mRow] = mSign; 145 dst[6+mRow] = mSign; 146 dst[9+mRow] = mSign; 147 148 dst[0+sRow] = sSign * bottomLeft.x(); 149 dst[3+sRow] = sSign * bottomLeft.x(); 150 dst[6+sRow] = sSign * topRight.x(); 151 dst[9+sRow] = sSign * topRight.x(); 152 153 dst[0+tRow] = tSign * bottomLeft.y(); 154 dst[3+tRow] = tSign * topRight.y(); 155 dst[6+tRow] = tSign * bottomLeft.y(); 156 dst[9+tRow] = tSign * topRight.y(); 157 } 158 159 } // TextureTestUtil 160 161 // Round-to-zero int division, because pre-c++11 it's somewhat implementation-defined for negative values. 162 static inline int divRoundToZero (int a, int b) 163 { 164 return de::abs(a) / de::abs(b) * deSign32(a) * deSign32(b); 165 } 166 167 static void fillWithRandomColorTiles (const PixelBufferAccess& dst, const Vec4& minVal, const Vec4& maxVal, deUint32 seed) 168 { 169 const int numCols = dst.getWidth() >= 7 ? 7 : dst.getWidth(); 170 const int numRows = dst.getHeight() >= 5 ? 5 : dst.getHeight(); 171 de::Random rnd (seed); 172 173 for (int slice = 0; slice < dst.getDepth(); slice++) 174 for (int row = 0; row < numRows; row++) 175 for (int col = 0; col < numCols; col++) 176 { 177 const int yBegin = (row+0)*dst.getHeight()/numRows; 178 const int yEnd = (row+1)*dst.getHeight()/numRows; 179 const int xBegin = (col+0)*dst.getWidth()/numCols; 180 const int xEnd = (col+1)*dst.getWidth()/numCols; 181 Vec4 color; 182 for (int i = 0; i < 4; i++) 183 color[i] = rnd.getFloat(minVal[i], maxVal[i]); 184 tcu::clear(tcu::getSubregion(dst, xBegin, yBegin, slice, xEnd-xBegin, yEnd-yBegin, 1), color); 185 } 186 } 187 188 static inline bool isDepthFormat (const tcu::TextureFormat& fmt) 189 { 190 return fmt.order == tcu::TextureFormat::D || fmt.order == tcu::TextureFormat::DS; 191 } 192 193 static inline bool isUnormFormatType (tcu::TextureFormat::ChannelType type) 194 { 195 return type == tcu::TextureFormat::UNORM_INT8 || 196 type == tcu::TextureFormat::UNORM_INT16 || 197 type == tcu::TextureFormat::UNORM_INT32; 198 } 199 200 static inline bool isSIntFormatType (tcu::TextureFormat::ChannelType type) 201 { 202 return type == tcu::TextureFormat::SIGNED_INT8 || 203 type == tcu::TextureFormat::SIGNED_INT16 || 204 type == tcu::TextureFormat::SIGNED_INT32; 205 } 206 207 static inline bool isUIntFormatType (tcu::TextureFormat::ChannelType type) 208 { 209 return type == tcu::TextureFormat::UNSIGNED_INT8 || 210 type == tcu::TextureFormat::UNSIGNED_INT16 || 211 type == tcu::TextureFormat::UNSIGNED_INT32; 212 } 213 214 enum TextureSwizzleComponent 215 { 216 TEXTURESWIZZLECOMPONENT_R = 0, 217 TEXTURESWIZZLECOMPONENT_G, 218 TEXTURESWIZZLECOMPONENT_B, 219 TEXTURESWIZZLECOMPONENT_A, 220 TEXTURESWIZZLECOMPONENT_ZERO, 221 TEXTURESWIZZLECOMPONENT_ONE, 222 223 TEXTURESWIZZLECOMPONENT_LAST 224 }; 225 226 static std::ostream& operator<< (std::ostream& stream, TextureSwizzleComponent comp) 227 { 228 switch (comp) 229 { 230 case TEXTURESWIZZLECOMPONENT_R: return stream << "RED"; 231 case TEXTURESWIZZLECOMPONENT_G: return stream << "GREEN"; 232 case TEXTURESWIZZLECOMPONENT_B: return stream << "BLUE"; 233 case TEXTURESWIZZLECOMPONENT_A: return stream << "ALPHA"; 234 case TEXTURESWIZZLECOMPONENT_ZERO: return stream << "ZERO"; 235 case TEXTURESWIZZLECOMPONENT_ONE: return stream << "ONE"; 236 default: DE_ASSERT(false); return stream; 237 } 238 } 239 240 struct MaybeTextureSwizzle 241 { 242 public: 243 static MaybeTextureSwizzle createNoneTextureSwizzle (void); 244 static MaybeTextureSwizzle createSomeTextureSwizzle (void); 245 246 bool isSome (void) const; 247 bool isNone (void) const; 248 bool isIdentitySwizzle (void) const; 249 250 tcu::Vector<TextureSwizzleComponent, 4>& getSwizzle (void); 251 const tcu::Vector<TextureSwizzleComponent, 4>& getSwizzle (void) const; 252 253 private: 254 MaybeTextureSwizzle (void); 255 256 tcu::Vector<TextureSwizzleComponent, 4> m_swizzle; 257 bool m_isSome; 258 }; 259 260 static std::ostream& operator<< (std::ostream& stream, const MaybeTextureSwizzle& comp) 261 { 262 if (comp.isNone()) 263 stream << "[default swizzle state]"; 264 else 265 stream << "(" << comp.getSwizzle()[0] 266 << ", " << comp.getSwizzle()[1] 267 << ", " << comp.getSwizzle()[2] 268 << ", " << comp.getSwizzle()[3] 269 << ")"; 270 271 return stream; 272 } 273 274 MaybeTextureSwizzle MaybeTextureSwizzle::createNoneTextureSwizzle (void) 275 { 276 MaybeTextureSwizzle swizzle; 277 278 swizzle.m_swizzle[0] = TEXTURESWIZZLECOMPONENT_LAST; 279 swizzle.m_swizzle[1] = TEXTURESWIZZLECOMPONENT_LAST; 280 swizzle.m_swizzle[2] = TEXTURESWIZZLECOMPONENT_LAST; 281 swizzle.m_swizzle[3] = TEXTURESWIZZLECOMPONENT_LAST; 282 swizzle.m_isSome = false; 283 284 return swizzle; 285 } 286 287 MaybeTextureSwizzle MaybeTextureSwizzle::createSomeTextureSwizzle (void) 288 { 289 MaybeTextureSwizzle swizzle; 290 291 swizzle.m_swizzle[0] = TEXTURESWIZZLECOMPONENT_R; 292 swizzle.m_swizzle[1] = TEXTURESWIZZLECOMPONENT_G; 293 swizzle.m_swizzle[2] = TEXTURESWIZZLECOMPONENT_B; 294 swizzle.m_swizzle[3] = TEXTURESWIZZLECOMPONENT_A; 295 swizzle.m_isSome = true; 296 297 return swizzle; 298 } 299 300 bool MaybeTextureSwizzle::isSome (void) const 301 { 302 return m_isSome; 303 } 304 305 bool MaybeTextureSwizzle::isNone (void) const 306 { 307 return !m_isSome; 308 } 309 310 bool MaybeTextureSwizzle::isIdentitySwizzle (void) const 311 { 312 return m_isSome && 313 m_swizzle[0] == TEXTURESWIZZLECOMPONENT_R && 314 m_swizzle[1] == TEXTURESWIZZLECOMPONENT_G && 315 m_swizzle[2] == TEXTURESWIZZLECOMPONENT_B && 316 m_swizzle[3] == TEXTURESWIZZLECOMPONENT_A; 317 } 318 319 tcu::Vector<TextureSwizzleComponent, 4>& MaybeTextureSwizzle::getSwizzle (void) 320 { 321 return m_swizzle; 322 } 323 324 const tcu::Vector<TextureSwizzleComponent, 4>& MaybeTextureSwizzle::getSwizzle (void) const 325 { 326 return m_swizzle; 327 } 328 329 MaybeTextureSwizzle::MaybeTextureSwizzle (void) 330 : m_swizzle (TEXTURESWIZZLECOMPONENT_LAST, TEXTURESWIZZLECOMPONENT_LAST, TEXTURESWIZZLECOMPONENT_LAST, TEXTURESWIZZLECOMPONENT_LAST) 331 , m_isSome (false) 332 { 333 } 334 335 static vk::VkComponentSwizzle getTextureSwizzleComponent (TextureSwizzleComponent c) 336 { 337 switch (c) 338 { 339 case TEXTURESWIZZLECOMPONENT_R: return vk::VK_COMPONENT_SWIZZLE_R; 340 case TEXTURESWIZZLECOMPONENT_G: return vk::VK_COMPONENT_SWIZZLE_G; 341 case TEXTURESWIZZLECOMPONENT_B: return vk::VK_COMPONENT_SWIZZLE_B; 342 case TEXTURESWIZZLECOMPONENT_A: return vk::VK_COMPONENT_SWIZZLE_A; 343 case TEXTURESWIZZLECOMPONENT_ZERO: return vk::VK_COMPONENT_SWIZZLE_ZERO; 344 case TEXTURESWIZZLECOMPONENT_ONE: return vk::VK_COMPONENT_SWIZZLE_ONE; 345 default: DE_ASSERT(false); return (vk::VkComponentSwizzle)0; 346 } 347 } 348 349 template <typename T> 350 static inline T swizzleColorChannel (const tcu::Vector<T, 4>& src, TextureSwizzleComponent swizzle) 351 { 352 switch (swizzle) 353 { 354 case TEXTURESWIZZLECOMPONENT_R: return src[0]; 355 case TEXTURESWIZZLECOMPONENT_G: return src[1]; 356 case TEXTURESWIZZLECOMPONENT_B: return src[2]; 357 case TEXTURESWIZZLECOMPONENT_A: return src[3]; 358 case TEXTURESWIZZLECOMPONENT_ZERO: return (T)0; 359 case TEXTURESWIZZLECOMPONENT_ONE: return (T)1; 360 default: DE_ASSERT(false); return (T)-1; 361 } 362 } 363 364 template <typename T> 365 static inline tcu::Vector<T, 4> swizzleColor (const tcu::Vector<T, 4>& src, const MaybeTextureSwizzle& swizzle) 366 { 367 DE_ASSERT(swizzle.isSome()); 368 369 tcu::Vector<T, 4> result; 370 for (int i = 0; i < 4; i++) 371 result[i] = swizzleColorChannel(src, swizzle.getSwizzle()[i]); 372 return result; 373 } 374 375 template <typename T> 376 static void swizzlePixels (const PixelBufferAccess& dst, const ConstPixelBufferAccess& src, const MaybeTextureSwizzle& swizzle) 377 { 378 DE_ASSERT(dst.getWidth() == src.getWidth() && 379 dst.getHeight() == src.getHeight() && 380 dst.getDepth() == src.getDepth()); 381 for (int z = 0; z < src.getDepth(); z++) 382 for (int y = 0; y < src.getHeight(); y++) 383 for (int x = 0; x < src.getWidth(); x++) 384 dst.setPixel(swizzleColor(src.getPixelT<T>(x, y, z), swizzle), x, y, z); 385 } 386 387 static void swizzlePixels (const PixelBufferAccess& dst, const ConstPixelBufferAccess& src, const MaybeTextureSwizzle& swizzle) 388 { 389 if (isDepthFormat(dst.getFormat())) 390 DE_ASSERT(swizzle.isNone() || swizzle.isIdentitySwizzle()); 391 392 if (swizzle.isNone() || swizzle.isIdentitySwizzle()) 393 tcu::copy(dst, src); 394 else if (isUnormFormatType(dst.getFormat().type)) 395 swizzlePixels<float>(dst, src, swizzle); 396 else if (isUIntFormatType(dst.getFormat().type)) 397 swizzlePixels<deUint32>(dst, src, swizzle); 398 else if (isSIntFormatType(dst.getFormat().type)) 399 swizzlePixels<deInt32>(dst, src, swizzle); 400 else 401 DE_ASSERT(false); 402 } 403 404 static void swizzleTexture (tcu::Texture2D& dst, const tcu::Texture2D& src, const MaybeTextureSwizzle& swizzle) 405 { 406 dst = tcu::Texture2D(src.getFormat(), src.getWidth(), src.getHeight()); 407 for (int levelNdx = 0; levelNdx < src.getNumLevels(); levelNdx++) 408 { 409 if (src.isLevelEmpty(levelNdx)) 410 continue; 411 dst.allocLevel(levelNdx); 412 swizzlePixels(dst.getLevel(levelNdx), src.getLevel(levelNdx), swizzle); 413 } 414 } 415 416 static void swizzleTexture (tcu::Texture2DArray& dst, const tcu::Texture2DArray& src, const MaybeTextureSwizzle& swizzle) 417 { 418 dst = tcu::Texture2DArray(src.getFormat(), src.getWidth(), src.getHeight(), src.getNumLayers()); 419 for (int levelNdx = 0; levelNdx < src.getNumLevels(); levelNdx++) 420 { 421 if (src.isLevelEmpty(levelNdx)) 422 continue; 423 dst.allocLevel(levelNdx); 424 swizzlePixels(dst.getLevel(levelNdx), src.getLevel(levelNdx), swizzle); 425 } 426 } 427 428 static void swizzleTexture (tcu::TextureCube& dst, const tcu::TextureCube& src, const MaybeTextureSwizzle& swizzle) 429 { 430 dst = tcu::TextureCube(src.getFormat(), src.getSize()); 431 for (int faceI = 0; faceI < tcu::CUBEFACE_LAST; faceI++) 432 { 433 const tcu::CubeFace face = (tcu::CubeFace)faceI; 434 for (int levelNdx = 0; levelNdx < src.getNumLevels(); levelNdx++) 435 { 436 if (src.isLevelEmpty(face, levelNdx)) 437 continue; 438 dst.allocLevel(face, levelNdx); 439 swizzlePixels(dst.getLevelFace(levelNdx, face), src.getLevelFace(levelNdx, face), swizzle); 440 } 441 } 442 } 443 444 static tcu::Texture2DView getOneLevelSubView (const tcu::Texture2DView& view, int level) 445 { 446 return tcu::Texture2DView(1, view.getLevels() + level); 447 } 448 449 static tcu::Texture2DArrayView getOneLevelSubView (const tcu::Texture2DArrayView& view, int level) 450 { 451 return tcu::Texture2DArrayView(1, view.getLevels() + level); 452 } 453 454 static tcu::TextureCubeView getOneLevelSubView (const tcu::TextureCubeView& view, int level) 455 { 456 const tcu::ConstPixelBufferAccess* levels[tcu::CUBEFACE_LAST]; 457 458 for (int face = 0; face < tcu::CUBEFACE_LAST; face++) 459 levels[face] = view.getFaceLevels((tcu::CubeFace)face) + level; 460 461 return tcu::TextureCubeView(1, levels); 462 } 463 464 class PixelOffsets 465 { 466 public: 467 virtual void operator() (const IVec2& pixCoord, IVec2 (&dst)[4]) const = 0; 468 virtual ~PixelOffsets (void) {} 469 }; 470 471 class MultiplePixelOffsets : public PixelOffsets 472 { 473 public: 474 MultiplePixelOffsets (const IVec2& a, 475 const IVec2& b, 476 const IVec2& c, 477 const IVec2& d) 478 { 479 m_offsets[0] = a; 480 m_offsets[1] = b; 481 m_offsets[2] = c; 482 m_offsets[3] = d; 483 } 484 485 void operator() (const IVec2& /* pixCoord */, IVec2 (&dst)[4]) const 486 { 487 for (int i = 0; i < DE_LENGTH_OF_ARRAY(dst); i++) 488 dst[i] = m_offsets[i]; 489 } 490 491 private: 492 IVec2 m_offsets[4]; 493 }; 494 495 class SinglePixelOffsets : public MultiplePixelOffsets 496 { 497 public: 498 SinglePixelOffsets (const IVec2& offset) 499 : MultiplePixelOffsets(offset + IVec2(0, 1), 500 offset + IVec2(1, 1), 501 offset + IVec2(1, 0), 502 offset + IVec2(0, 0)) 503 { 504 } 505 }; 506 507 class DynamicSinglePixelOffsets : public PixelOffsets 508 { 509 public: 510 DynamicSinglePixelOffsets (const IVec2& offsetRange) : m_offsetRange(offsetRange) {} 511 512 void operator() (const IVec2& pixCoord, IVec2 (&dst)[4]) const 513 { 514 const int offsetRangeSize = m_offsetRange.y() - m_offsetRange.x() + 1; 515 SinglePixelOffsets(tcu::mod(pixCoord.swizzle(1,0), IVec2(offsetRangeSize)) + m_offsetRange.x())(IVec2(), dst); 516 } 517 518 private: 519 IVec2 m_offsetRange; 520 }; 521 522 template <typename T> 523 static inline T triQuadInterpolate (const T (&values)[4], float xFactor, float yFactor) 524 { 525 if (xFactor + yFactor < 1.0f) 526 return values[0] + (values[2]-values[0])*xFactor + (values[1]-values[0])*yFactor; 527 else 528 return values[3] + (values[1]-values[3])*(1.0f-xFactor) + (values[2]-values[3])*(1.0f-yFactor); 529 } 530 531 template <int N> 532 static inline void computeTexCoordVecs (const vector<float>& texCoords, tcu::Vector<float, N> (&dst)[4]) 533 { 534 DE_ASSERT((int)texCoords.size() == 4*N); 535 for (int i = 0; i < 4; i++) 536 for (int j = 0; j < N; j++) 537 dst[i][j] = texCoords[i*N + j]; 538 } 539 540 #if defined(DE_DEBUG) 541 // Whether offsets correspond to the sample offsets used with plain textureGather(). 542 static inline bool isZeroOffsetOffsets (const IVec2 (&offsets)[4]) 543 { 544 IVec2 ref[4]; 545 SinglePixelOffsets(IVec2(0))(IVec2(), ref); 546 return std::equal(DE_ARRAY_BEGIN(offsets), 547 DE_ARRAY_END(offsets), 548 DE_ARRAY_BEGIN(ref)); 549 } 550 #endif 551 552 template <typename ColorScalarType> 553 static tcu::Vector<ColorScalarType, 4> gatherOffsets (const tcu::Texture2DView& texture, const tcu::Sampler& sampler, const Vec2& coord, int componentNdx, const IVec2 (&offsets)[4]) 554 { 555 return texture.gatherOffsets(sampler, coord.x(), coord.y(), componentNdx, offsets).cast<ColorScalarType>(); 556 } 557 558 template <typename ColorScalarType> 559 static tcu::Vector<ColorScalarType, 4> gatherOffsets (const tcu::Texture2DArrayView& texture, const tcu::Sampler& sampler, const Vec3& coord, int componentNdx, const IVec2 (&offsets)[4]) 560 { 561 return texture.gatherOffsets(sampler, coord.x(), coord.y(), coord.z(), componentNdx, offsets).cast<ColorScalarType>(); 562 } 563 564 template <typename ColorScalarType> 565 static tcu::Vector<ColorScalarType, 4> gatherOffsets (const tcu::TextureCubeView& texture, const tcu::Sampler& sampler, const Vec3& coord, int componentNdx, const IVec2 (&offsets)[4]) 566 { 567 DE_ASSERT(isZeroOffsetOffsets(offsets)); 568 DE_UNREF(offsets); 569 return texture.gather(sampler, coord.x(), coord.y(), coord.z(), componentNdx).cast<ColorScalarType>(); 570 } 571 572 static Vec4 gatherOffsetsCompare (const tcu::Texture2DView& texture, const tcu::Sampler& sampler, float refZ, const Vec2& coord, const IVec2 (&offsets)[4]) 573 { 574 return texture.gatherOffsetsCompare(sampler, refZ, coord.x(), coord.y(), offsets); 575 } 576 577 static Vec4 gatherOffsetsCompare (const tcu::Texture2DArrayView& texture, const tcu::Sampler& sampler, float refZ, const Vec3& coord, const IVec2 (&offsets)[4]) 578 { 579 return texture.gatherOffsetsCompare(sampler, refZ, coord.x(), coord.y(), coord.z(), offsets); 580 } 581 582 static Vec4 gatherOffsetsCompare (const tcu::TextureCubeView& texture, const tcu::Sampler& sampler, float refZ, const Vec3& coord, const IVec2 (&offsets)[4]) 583 { 584 DE_ASSERT(isZeroOffsetOffsets(offsets)); 585 DE_UNREF(offsets); 586 return texture.gatherCompare(sampler, refZ, coord.x(), coord.y(), coord.z()); 587 } 588 589 template <typename PrecType, typename ColorScalarT> 590 static bool isGatherOffsetsResultValid (const tcu::TextureCubeView& texture, 591 const tcu::Sampler& sampler, 592 const PrecType& prec, 593 const Vec3& coord, 594 int componentNdx, 595 const IVec2 (&offsets)[4], 596 const tcu::Vector<ColorScalarT, 4>& result) 597 { 598 DE_ASSERT(isZeroOffsetOffsets(offsets)); 599 DE_UNREF(offsets); 600 return tcu::isGatherResultValid(texture, sampler, prec, coord, componentNdx, result); 601 } 602 603 static bool isGatherOffsetsCompareResultValid (const tcu::TextureCubeView& texture, 604 const tcu::Sampler& sampler, 605 const tcu::TexComparePrecision& prec, 606 const Vec3& coord, 607 const IVec2 (&offsets)[4], 608 float cmpReference, 609 const Vec4& result) 610 { 611 DE_ASSERT(isZeroOffsetOffsets(offsets)); 612 DE_UNREF(offsets); 613 return tcu::isGatherCompareResultValid(texture, sampler, prec, coord, cmpReference, result); 614 } 615 616 template <typename ColorScalarType, typename PrecType, typename TexViewT, typename TexCoordT> 617 static bool verifyGatherOffsets (TestLog& log, 618 const ConstPixelBufferAccess& result, 619 const TexViewT& texture, 620 const TexCoordT (&texCoords)[4], 621 const tcu::Sampler& sampler, 622 const PrecType& lookupPrec, 623 int componentNdx, 624 const PixelOffsets& getPixelOffsets) 625 { 626 typedef tcu::Vector<ColorScalarType, 4> ColorVec; 627 628 const int width = result.getWidth(); 629 const int height = result.getWidth(); 630 tcu::TextureLevel ideal (result.getFormat(), width, height); 631 const PixelBufferAccess idealAccess = ideal.getAccess(); 632 tcu::Surface errorMask (width, height); 633 bool success = true; 634 635 tcu::clear(errorMask.getAccess(), tcu::RGBA::green().toVec()); 636 637 for (int py = 0; py < height; py++) 638 for (int px = 0; px < width; px++) 639 { 640 IVec2 offsets[4]; 641 getPixelOffsets(IVec2(px, py), offsets); 642 643 const Vec2 viewportCoord = (Vec2((float)px, (float)py) + 0.5f) / Vec2((float)width, (float)height); 644 const TexCoordT texCoord = triQuadInterpolate(texCoords, viewportCoord.x(), viewportCoord.y()); 645 const ColorVec resultPix = result.getPixelT<ColorScalarType>(px, py); 646 const ColorVec idealPix = gatherOffsets<ColorScalarType>(texture, sampler, texCoord, componentNdx, offsets); 647 648 idealAccess.setPixel(idealPix, px, py); 649 650 if (tcu::boolAny(tcu::logicalAnd(lookupPrec.colorMask, 651 tcu::greaterThan(tcu::absDiff(resultPix, idealPix), 652 lookupPrec.colorThreshold.template cast<ColorScalarType>())))) 653 { 654 if (!isGatherOffsetsResultValid(texture, sampler, lookupPrec, texCoord, componentNdx, offsets, resultPix)) 655 { 656 errorMask.setPixel(px, py, tcu::RGBA::red()); 657 success = false; 658 } 659 } 660 } 661 662 log << TestLog::ImageSet("VerifyResult", "Verification result") 663 << TestLog::Image("Rendered", "Rendered image", result); 664 665 if (!success) 666 { 667 log << TestLog::Image("Reference", "Ideal reference image", ideal) 668 << TestLog::Image("ErrorMask", "Error mask", errorMask); 669 } 670 671 log << TestLog::EndImageSet; 672 673 return success; 674 } 675 676 class PixelCompareRefZ 677 { 678 public: 679 virtual float operator() (const IVec2& pixCoord) const = 0; 680 }; 681 682 class PixelCompareRefZDefault : public PixelCompareRefZ 683 { 684 public: 685 PixelCompareRefZDefault (const IVec2& renderSize) : m_renderSize(renderSize) {} 686 687 float operator() (const IVec2& pixCoord) const 688 { 689 return ((float)pixCoord.x() + 0.5f) / (float)m_renderSize.x(); 690 } 691 692 private: 693 IVec2 m_renderSize; 694 }; 695 696 template <typename TexViewT, typename TexCoordT> 697 static bool verifyGatherOffsetsCompare (TestLog& log, 698 const ConstPixelBufferAccess& result, 699 const TexViewT& texture, 700 const TexCoordT (&texCoords)[4], 701 const tcu::Sampler& sampler, 702 const tcu::TexComparePrecision& compPrec, 703 const PixelCompareRefZ& getPixelRefZ, 704 const PixelOffsets& getPixelOffsets) 705 { 706 const int width = result.getWidth(); 707 const int height = result.getWidth(); 708 tcu::Surface ideal (width, height); 709 const PixelBufferAccess idealAccess = ideal.getAccess(); 710 tcu::Surface errorMask (width, height); 711 bool success = true; 712 713 tcu::clear(errorMask.getAccess(), tcu::RGBA::green().toVec()); 714 715 for (int py = 0; py < height; py++) 716 for (int px = 0; px < width; px++) 717 { 718 IVec2 offsets[4]; 719 getPixelOffsets(IVec2(px, py), offsets); 720 721 const Vec2 viewportCoord = (Vec2((float)px, (float)py) + 0.5f) / Vec2((float)width, (float)height); 722 const TexCoordT texCoord = triQuadInterpolate(texCoords, viewportCoord.x(), viewportCoord.y()); 723 const float refZ = getPixelRefZ(IVec2(px, py)); 724 const Vec4 resultPix = result.getPixel(px, py); 725 const Vec4 idealPix = gatherOffsetsCompare(texture, sampler, refZ, texCoord, offsets); 726 727 idealAccess.setPixel(idealPix, px, py); 728 729 if (!tcu::boolAll(tcu::equal(resultPix, idealPix))) 730 { 731 if (!isGatherOffsetsCompareResultValid(texture, sampler, compPrec, texCoord, offsets, refZ, resultPix)) 732 { 733 errorMask.setPixel(px, py, tcu::RGBA::red()); 734 success = false; 735 } 736 } 737 } 738 739 log << TestLog::ImageSet("VerifyResult", "Verification result") 740 << TestLog::Image("Rendered", "Rendered image", result); 741 742 if (!success) 743 { 744 log << TestLog::Image("Reference", "Ideal reference image", ideal) 745 << TestLog::Image("ErrorMask", "Error mask", errorMask); 746 } 747 748 log << TestLog::EndImageSet; 749 750 return success; 751 } 752 753 enum GatherType 754 { 755 GATHERTYPE_BASIC = 0, 756 GATHERTYPE_OFFSET, 757 GATHERTYPE_OFFSET_DYNAMIC, 758 GATHERTYPE_OFFSETS, 759 760 GATHERTYPE_LAST 761 }; 762 763 enum GatherCaseFlags 764 { 765 GATHERCASE_DONT_SAMPLE_CUBE_CORNERS = (1<<0) //!< For cube map cases: do not sample cube corners 766 }; 767 768 enum OffsetSize 769 { 770 OFFSETSIZE_NONE = 0, 771 OFFSETSIZE_MINIMUM_REQUIRED, 772 OFFSETSIZE_IMPLEMENTATION_MAXIMUM, 773 774 OFFSETSIZE_LAST 775 }; 776 777 static inline const char* gatherTypeName (GatherType type) 778 { 779 switch (type) 780 { 781 case GATHERTYPE_BASIC: return "basic"; 782 case GATHERTYPE_OFFSET: return "offset"; 783 case GATHERTYPE_OFFSET_DYNAMIC: return "offset_dynamic"; 784 case GATHERTYPE_OFFSETS: return "offsets"; 785 default: DE_ASSERT(false); return DE_NULL; 786 } 787 } 788 789 static inline const char* gatherTypeDescription (GatherType type) 790 { 791 switch (type) 792 { 793 case GATHERTYPE_BASIC: return "textureGather"; 794 case GATHERTYPE_OFFSET: return "textureGatherOffset"; 795 case GATHERTYPE_OFFSET_DYNAMIC: return "textureGatherOffset with dynamic offsets"; 796 case GATHERTYPE_OFFSETS: return "textureGatherOffsets"; 797 default: DE_ASSERT(false); return DE_NULL; 798 } 799 } 800 801 static inline bool requireGpuShader5 (GatherType gatherType, OffsetSize offsetSize) 802 { 803 return gatherType == GATHERTYPE_OFFSET_DYNAMIC || gatherType == GATHERTYPE_OFFSETS 804 || offsetSize == OFFSETSIZE_IMPLEMENTATION_MAXIMUM; // \note Implementation limits are not available while generating the shaders, they are passed dynamically at runtime 805 } 806 807 struct GatherArgs 808 { 809 int componentNdx; // If negative, implicit component index 0 is used (i.e. the parameter is not given). 810 IVec2 offsets[4]; // \note Unless GATHERTYPE_OFFSETS is used, only offsets[0] is relevant; also, for GATHERTYPE_OFFSET_DYNAMIC, none are relevant. 811 812 GatherArgs (void) 813 : componentNdx(-1) 814 { 815 std::fill(DE_ARRAY_BEGIN(offsets), DE_ARRAY_END(offsets), IVec2()); 816 } 817 818 GatherArgs (int comp, 819 const IVec2& off0 = IVec2(), 820 const IVec2& off1 = IVec2(), 821 const IVec2& off2 = IVec2(), 822 const IVec2& off3 = IVec2()) 823 : componentNdx(comp) 824 { 825 offsets[0] = off0; 826 offsets[1] = off1; 827 offsets[2] = off2; 828 offsets[3] = off3; 829 } 830 }; 831 832 static MovePtr<PixelOffsets> makePixelOffsetsFunctor (GatherType gatherType, const GatherArgs& gatherArgs, const IVec2& offsetRange) 833 { 834 if (gatherType == GATHERTYPE_BASIC || gatherType == GATHERTYPE_OFFSET) 835 { 836 const IVec2 offset = gatherType == GATHERTYPE_BASIC ? IVec2(0) : gatherArgs.offsets[0]; 837 return MovePtr<PixelOffsets>(new SinglePixelOffsets(offset)); 838 } 839 else if (gatherType == GATHERTYPE_OFFSET_DYNAMIC) 840 { 841 return MovePtr<PixelOffsets>(new DynamicSinglePixelOffsets(offsetRange)); 842 } 843 else if (gatherType == GATHERTYPE_OFFSETS) 844 return MovePtr<PixelOffsets>(new MultiplePixelOffsets(gatherArgs.offsets[0], 845 gatherArgs.offsets[1], 846 gatherArgs.offsets[2], 847 gatherArgs.offsets[3])); 848 else 849 { 850 DE_ASSERT(false); 851 return MovePtr<PixelOffsets>(DE_NULL); 852 } 853 } 854 855 static inline glu::DataType getSamplerType (TextureType textureType, const tcu::TextureFormat& format) 856 { 857 if (isDepthFormat(format)) 858 { 859 switch (textureType) 860 { 861 case TEXTURETYPE_2D: return glu::TYPE_SAMPLER_2D_SHADOW; 862 case TEXTURETYPE_2D_ARRAY: return glu::TYPE_SAMPLER_2D_ARRAY_SHADOW; 863 case TEXTURETYPE_CUBE: return glu::TYPE_SAMPLER_CUBE_SHADOW; 864 default: DE_ASSERT(false); return glu::TYPE_LAST; 865 } 866 } 867 else 868 { 869 switch (textureType) 870 { 871 case TEXTURETYPE_2D: return glu::getSampler2DType(format); 872 case TEXTURETYPE_2D_ARRAY: return glu::getSampler2DArrayType(format); 873 case TEXTURETYPE_CUBE: return glu::getSamplerCubeType(format); 874 default: DE_ASSERT(false); return glu::TYPE_LAST; 875 } 876 } 877 } 878 879 static inline glu::DataType getSamplerGatherResultType (glu::DataType samplerType) 880 { 881 switch (samplerType) 882 { 883 case glu::TYPE_SAMPLER_2D_SHADOW: 884 case glu::TYPE_SAMPLER_2D_ARRAY_SHADOW: 885 case glu::TYPE_SAMPLER_CUBE_SHADOW: 886 case glu::TYPE_SAMPLER_2D: 887 case glu::TYPE_SAMPLER_2D_ARRAY: 888 case glu::TYPE_SAMPLER_CUBE: 889 return glu::TYPE_FLOAT_VEC4; 890 891 case glu::TYPE_INT_SAMPLER_2D: 892 case glu::TYPE_INT_SAMPLER_2D_ARRAY: 893 case glu::TYPE_INT_SAMPLER_CUBE: 894 return glu::TYPE_INT_VEC4; 895 896 case glu::TYPE_UINT_SAMPLER_2D: 897 case glu::TYPE_UINT_SAMPLER_2D_ARRAY: 898 case glu::TYPE_UINT_SAMPLER_CUBE: 899 return glu::TYPE_UINT_VEC4; 900 901 default: 902 DE_ASSERT(false); 903 return glu::TYPE_LAST; 904 } 905 } 906 907 static inline int getNumTextureSamplingDimensions (TextureType type) 908 { 909 switch (type) 910 { 911 case TEXTURETYPE_2D: return 2; 912 case TEXTURETYPE_2D_ARRAY: return 3; 913 case TEXTURETYPE_CUBE: return 3; 914 default: DE_ASSERT(false); return -1; 915 } 916 } 917 918 vector<GatherArgs> generateBasic2DCaseIterations (GatherType gatherType, const tcu::TextureFormat& textureFormat, const IVec2& offsetRange) 919 { 920 const int numComponentCases = isDepthFormat(textureFormat) ? 1 : 4+1; // \note For non-depth textures, test explicit components 0 to 3 and implicit component 0. 921 vector<GatherArgs> result; 922 923 for (int componentCaseNdx = 0; componentCaseNdx < numComponentCases; componentCaseNdx++) 924 { 925 const int componentNdx = componentCaseNdx - 1; 926 927 switch (gatherType) 928 { 929 case GATHERTYPE_BASIC: 930 result.push_back(GatherArgs(componentNdx)); 931 break; 932 933 case GATHERTYPE_OFFSET: 934 { 935 const int min = offsetRange.x(); 936 const int max = offsetRange.y(); 937 const int hmin = divRoundToZero(min, 2); 938 const int hmax = divRoundToZero(max, 2); 939 940 result.push_back(GatherArgs(componentNdx, IVec2(min, max))); 941 942 if (componentCaseNdx == 0) // Don't test all offsets variants for all color components (they should be pretty orthogonal). 943 { 944 result.push_back(GatherArgs(componentNdx, IVec2(min, min))); 945 result.push_back(GatherArgs(componentNdx, IVec2(max, min))); 946 result.push_back(GatherArgs(componentNdx, IVec2(max, max))); 947 948 result.push_back(GatherArgs(componentNdx, IVec2(0, hmax))); 949 result.push_back(GatherArgs(componentNdx, IVec2(hmin, 0))); 950 result.push_back(GatherArgs(componentNdx, IVec2(0, 0))); 951 } 952 953 break; 954 } 955 956 case GATHERTYPE_OFFSET_DYNAMIC: 957 result.push_back(GatherArgs(componentNdx)); 958 break; 959 960 case GATHERTYPE_OFFSETS: 961 { 962 const int min = offsetRange.x(); 963 const int max = offsetRange.y(); 964 const int hmin = divRoundToZero(min, 2); 965 const int hmax = divRoundToZero(max, 2); 966 967 result.push_back(GatherArgs(componentNdx, 968 IVec2(min, min), 969 IVec2(min, max), 970 IVec2(max, min), 971 IVec2(max, max))); 972 973 if (componentCaseNdx == 0) // Don't test all offsets variants for all color components (they should be pretty orthogonal). 974 result.push_back(GatherArgs(componentNdx, 975 IVec2(min, hmax), 976 IVec2(hmin, max), 977 IVec2(0, hmax), 978 IVec2(hmax, 0))); 979 break; 980 } 981 982 default: 983 DE_ASSERT(false); 984 } 985 } 986 987 return result; 988 } 989 990 struct GatherCaseBaseParams 991 { 992 GatherType gatherType; 993 OffsetSize offsetSize; 994 tcu::TextureFormat textureFormat; 995 tcu::Sampler::CompareMode shadowCompareMode; 996 tcu::Sampler::WrapMode wrapS; 997 tcu::Sampler::WrapMode wrapT; 998 MaybeTextureSwizzle textureSwizzle; 999 tcu::Sampler::FilterMode minFilter; 1000 tcu::Sampler::FilterMode magFilter; 1001 int baseLevel; 1002 deUint32 flags; 1003 TextureType textureType; 1004 ImageBackingMode sparseCase; 1005 1006 GatherCaseBaseParams (const TextureType textureType_, 1007 const GatherType gatherType_, 1008 const OffsetSize offsetSize_, 1009 const tcu::TextureFormat textureFormat_, 1010 const tcu::Sampler::CompareMode shadowCompareMode_, 1011 const tcu::Sampler::WrapMode wrapS_, 1012 const tcu::Sampler::WrapMode wrapT_, 1013 const MaybeTextureSwizzle& textureSwizzle_, 1014 const tcu::Sampler::FilterMode minFilter_, 1015 const tcu::Sampler::FilterMode magFilter_, 1016 const int baseLevel_, 1017 const deUint32 flags_, 1018 const ImageBackingMode sparseCase_) 1019 : gatherType (gatherType_) 1020 , offsetSize (offsetSize_) 1021 , textureFormat (textureFormat_) 1022 , shadowCompareMode (shadowCompareMode_) 1023 , wrapS (wrapS_) 1024 , wrapT (wrapT_) 1025 , textureSwizzle (textureSwizzle_) 1026 , minFilter (minFilter_) 1027 , magFilter (magFilter_) 1028 , baseLevel (baseLevel_) 1029 , flags (flags_) 1030 , textureType (textureType_) 1031 , sparseCase (sparseCase_) 1032 {} 1033 1034 GatherCaseBaseParams (void) 1035 : gatherType (GATHERTYPE_LAST) 1036 , offsetSize (OFFSETSIZE_LAST) 1037 , textureFormat () 1038 , shadowCompareMode (tcu::Sampler::COMPAREMODE_LAST) 1039 , wrapS (tcu::Sampler::WRAPMODE_LAST) 1040 , wrapT (tcu::Sampler::WRAPMODE_LAST) 1041 , textureSwizzle (MaybeTextureSwizzle::createNoneTextureSwizzle()) 1042 , minFilter (tcu::Sampler::FILTERMODE_LAST) 1043 , magFilter (tcu::Sampler::FILTERMODE_LAST) 1044 , baseLevel (0) 1045 , flags (0) 1046 , textureType (TEXTURETYPE_LAST) 1047 , sparseCase (ShaderRenderCaseInstance::IMAGE_BACKING_MODE_REGULAR) 1048 {} 1049 }; 1050 1051 IVec2 getOffsetRange (const OffsetSize offsetSize, const vk::VkPhysicalDeviceLimits& deviceLimits) 1052 { 1053 switch (offsetSize) 1054 { 1055 case OFFSETSIZE_NONE: 1056 return IVec2(0); 1057 1058 case OFFSETSIZE_MINIMUM_REQUIRED: 1059 // \note Defined by spec. 1060 return IVec2(SPEC_MAX_MIN_OFFSET, 1061 SPEC_MIN_MAX_OFFSET); 1062 1063 case OFFSETSIZE_IMPLEMENTATION_MAXIMUM: 1064 return IVec2(deviceLimits.minTexelGatherOffset, deviceLimits.maxTexelGatherOffset); 1065 1066 default: 1067 DE_ASSERT(false); 1068 return IVec2(-1); 1069 } 1070 } 1071 1072 IVec2 getOffsetRange (const OffsetSize offsetSize) 1073 { 1074 switch (offsetSize) 1075 { 1076 case OFFSETSIZE_NONE: 1077 return IVec2(0); 1078 1079 case OFFSETSIZE_MINIMUM_REQUIRED: 1080 // \note Defined by spec. 1081 return IVec2(SPEC_MAX_MIN_OFFSET, 1082 SPEC_MIN_MAX_OFFSET); 1083 1084 case OFFSETSIZE_IMPLEMENTATION_MAXIMUM: 1085 DE_FATAL("Not known"); 1086 return IVec2(-1); 1087 1088 default: 1089 DE_ASSERT(false); 1090 return IVec2(-1); 1091 } 1092 } 1093 1094 class TextureGatherInstance : public ShaderRenderCaseInstance 1095 { 1096 public: 1097 TextureGatherInstance (Context& context, 1098 const GatherCaseBaseParams& baseParams); 1099 virtual ~TextureGatherInstance (void); 1100 1101 virtual tcu::TestStatus iterate (void); 1102 1103 protected: 1104 void init (void); 1105 1106 virtual int getNumIterations (void) const = 0; 1107 virtual GatherArgs getGatherArgs (int iterationNdx) const = 0; 1108 1109 virtual void setupDefaultInputs (void); 1110 virtual void setupUniforms (const tcu::Vec4&); 1111 1112 template <typename TexViewT, typename TexCoordT> 1113 bool verify (const ConstPixelBufferAccess& rendered, 1114 const TexViewT& texture, 1115 const TexCoordT (&bottomLeft)[4], 1116 const GatherArgs& gatherArgs) const; 1117 1118 virtual TextureBindingSp createTexture (void) = 0; 1119 virtual vector<float> computeQuadTexCoord (int iterationNdx) const = 0; 1120 virtual bool verify (int iterationNdx, const ConstPixelBufferAccess& rendered) const = 0; 1121 1122 protected: 1123 static const IVec2 RENDER_SIZE; 1124 1125 const GatherCaseBaseParams m_baseParams; 1126 1127 private: 1128 const tcu::TextureFormat m_colorBufferFormat; 1129 int m_currentIteration; 1130 }; 1131 1132 const IVec2 TextureGatherInstance::RENDER_SIZE = IVec2(64, 64); 1133 1134 TextureGatherInstance::TextureGatherInstance (Context& context, 1135 const GatherCaseBaseParams& baseParams) 1136 : ShaderRenderCaseInstance (context, false, DE_NULL, DE_NULL, DE_NULL, baseParams.sparseCase) 1137 , m_baseParams (baseParams) 1138 , m_colorBufferFormat (tcu::TextureFormat(tcu::TextureFormat::RGBA, 1139 isDepthFormat(baseParams.textureFormat) ? tcu::TextureFormat::UNORM_INT8 : baseParams.textureFormat.type)) 1140 , m_currentIteration (0) 1141 { 1142 DE_ASSERT((m_baseParams.gatherType == GATHERTYPE_BASIC) == (m_baseParams.offsetSize == OFFSETSIZE_NONE)); 1143 DE_ASSERT((m_baseParams.shadowCompareMode != tcu::Sampler::COMPAREMODE_NONE) == isDepthFormat(m_baseParams.textureFormat)); 1144 DE_ASSERT(isUnormFormatType(m_colorBufferFormat.type) || 1145 m_colorBufferFormat.type == tcu::TextureFormat::UNSIGNED_INT8 || 1146 m_colorBufferFormat.type == tcu::TextureFormat::UNSIGNED_INT16 || 1147 m_colorBufferFormat.type == tcu::TextureFormat::SIGNED_INT8 || 1148 m_colorBufferFormat.type == tcu::TextureFormat::SIGNED_INT16); 1149 DE_ASSERT(glu::isGLInternalColorFormatFilterable(glu::getInternalFormat(m_colorBufferFormat)) || 1150 (m_baseParams.magFilter == tcu::Sampler::NEAREST && (m_baseParams.minFilter == tcu::Sampler::NEAREST || m_baseParams.minFilter == tcu::Sampler::NEAREST_MIPMAP_NEAREST))); 1151 DE_ASSERT(m_baseParams.textureType == TEXTURETYPE_CUBE || !(m_baseParams.flags & GATHERCASE_DONT_SAMPLE_CUBE_CORNERS)); 1152 1153 m_renderSize = RENDER_SIZE.asUint(); 1154 m_colorFormat = vk::mapTextureFormat(m_colorBufferFormat); 1155 } 1156 1157 TextureGatherInstance::~TextureGatherInstance (void) 1158 { 1159 } 1160 1161 void TextureGatherInstance::init (void) 1162 { 1163 TestLog& log = m_context.getTestContext().getLog(); 1164 TextureBindingSp textureBinding; 1165 TextureBinding::Parameters textureParams; 1166 1167 // Check prerequisites. 1168 if (requireGpuShader5(m_baseParams.gatherType, m_baseParams.offsetSize)) 1169 { 1170 const vk::VkPhysicalDeviceFeatures& deviceFeatures = m_context.getDeviceFeatures(); 1171 if (!deviceFeatures.shaderImageGatherExtended) 1172 TCU_THROW(NotSupportedError, "Extended set of image gather instructions are not supported"); 1173 } 1174 1175 // Log and check implementation offset limits, if appropriate. 1176 if (m_baseParams.offsetSize == OFFSETSIZE_IMPLEMENTATION_MAXIMUM) 1177 { 1178 const IVec2 offsetRange = getOffsetRange(m_baseParams.offsetSize, m_context.getDeviceProperties().limits); 1179 log << TestLog::Integer("ImplementationMinTextureGatherOffset", "Implementation's value for minTexelGatherOffset", "", QP_KEY_TAG_NONE, offsetRange[0]) 1180 << TestLog::Integer("ImplementationMaxTextureGatherOffset", "Implementation's value for maxTexelGatherOffset", "", QP_KEY_TAG_NONE, offsetRange[1]); 1181 TCU_CHECK_MSG(offsetRange[0] <= SPEC_MAX_MIN_OFFSET, ("minTexelGatherOffset must be at most " + de::toString((int)SPEC_MAX_MIN_OFFSET)).c_str()); 1182 TCU_CHECK_MSG(offsetRange[1] >= SPEC_MIN_MAX_OFFSET, ("maxTexelGatherOffset must be at least " + de::toString((int)SPEC_MIN_MAX_OFFSET)).c_str()); 1183 } 1184 1185 // Initialize texture. 1186 1187 textureBinding = createTexture(); 1188 1189 if (m_baseParams.textureSwizzle.isSome()) 1190 { 1191 const tcu::Vector<TextureSwizzleComponent, 4>& swizzle = m_baseParams.textureSwizzle.getSwizzle(); 1192 1193 const vk::VkComponentMapping components = 1194 { 1195 getTextureSwizzleComponent(swizzle[0]), 1196 getTextureSwizzleComponent(swizzle[1]), 1197 getTextureSwizzleComponent(swizzle[2]), 1198 getTextureSwizzleComponent(swizzle[3]) 1199 }; 1200 1201 textureParams.componentMapping = components; 1202 } 1203 1204 if (m_baseParams.baseLevel != 0) 1205 textureParams.baseMipLevel = m_baseParams.baseLevel; 1206 1207 textureBinding->setParameters(textureParams); 1208 m_textures.push_back(textureBinding); 1209 1210 log << TestLog::Message << "Texture base level is " << m_baseParams.baseLevel << TestLog::EndMessage 1211 << TestLog::Message << "s and t wrap modes are " 1212 << vk::mapWrapMode(m_baseParams.wrapS) << " and " 1213 << vk::mapWrapMode(m_baseParams.wrapT) << ", respectively" << TestLog::EndMessage 1214 << TestLog::Message << "Minification and magnification filter modes are " 1215 << vk::mapFilterMode(m_baseParams.minFilter) << " and " 1216 << vk::mapFilterMode(m_baseParams.magFilter) << ", respectively " 1217 << "(note that they should have no effect on gather result)" 1218 << TestLog::EndMessage 1219 << TestLog::Message << "Using texture swizzle " << m_baseParams.textureSwizzle << TestLog::EndMessage; 1220 1221 if (m_baseParams.shadowCompareMode != tcu::Sampler::COMPAREMODE_NONE) 1222 log << TestLog::Message << "Using texture compare func " << vk::mapCompareMode(m_baseParams.shadowCompareMode) << TestLog::EndMessage; 1223 } 1224 1225 void TextureGatherInstance::setupDefaultInputs (void) 1226 { 1227 const int numVertices = 4; 1228 const float position[4*2] = 1229 { 1230 -1.0f, -1.0f, 1231 -1.0f, +1.0f, 1232 +1.0f, -1.0f, 1233 +1.0f, +1.0f, 1234 }; 1235 const float normalizedCoord[4*2] = 1236 { 1237 0.0f, 0.0f, 1238 0.0f, 1.0f, 1239 1.0f, 0.0f, 1240 1.0f, 1.0f, 1241 }; 1242 const vector<float> texCoord = computeQuadTexCoord(m_currentIteration); 1243 const bool needNormalizedCoordInShader = m_baseParams.gatherType == GATHERTYPE_OFFSET_DYNAMIC || isDepthFormat(m_baseParams.textureFormat); 1244 1245 addAttribute(0u, vk::VK_FORMAT_R32G32_SFLOAT, 2 * (deUint32)sizeof(float), numVertices, position); 1246 1247 if (texCoord.size() == 2*4) 1248 addAttribute(1u, vk::VK_FORMAT_R32G32_SFLOAT, 2 * (deUint32)sizeof(float), numVertices, texCoord.data()); 1249 else if (texCoord.size() == 3*4) 1250 addAttribute(1u, vk::VK_FORMAT_R32G32B32_SFLOAT, 3 * (deUint32)sizeof(float), numVertices, texCoord.data()); 1251 else 1252 DE_ASSERT(false); 1253 1254 if (needNormalizedCoordInShader) 1255 addAttribute(2u, vk::VK_FORMAT_R32G32_SFLOAT, 2 * (deUint32)sizeof(float), numVertices, normalizedCoord); 1256 } 1257 1258 tcu::TestStatus TextureGatherInstance::iterate (void) 1259 { 1260 TestLog& log = m_context.getTestContext().getLog(); 1261 const tcu::ScopedLogSection iterationSection (log, "Iteration" + de::toString(m_currentIteration), "Iteration " + de::toString(m_currentIteration)); 1262 1263 // Render. 1264 1265 { 1266 const deUint32 numVertices = 4; 1267 const deUint32 numTriangles = 2; 1268 const deUint16 indices[6] = { 0, 1, 2, 2, 1, 3 }; 1269 const vector<float> texCoord = computeQuadTexCoord(m_currentIteration); 1270 1271 if (texCoord.size() == 2*4) 1272 { 1273 Vec2 texCoordVec[4]; 1274 computeTexCoordVecs(texCoord, texCoordVec); 1275 log << TestLog::Message << "Texture coordinates run from " << texCoordVec[0] << " to " << texCoordVec[3] << TestLog::EndMessage; 1276 } 1277 else if (texCoord.size() == 3*4) 1278 { 1279 Vec3 texCoordVec[4]; 1280 computeTexCoordVecs(texCoord, texCoordVec); 1281 log << TestLog::Message << "Texture coordinates run from " << texCoordVec[0] << " to " << texCoordVec[3] << TestLog::EndMessage; 1282 } 1283 else 1284 DE_ASSERT(false); 1285 1286 m_vertexShaderName = "vert"; 1287 m_fragmentShaderName = "frag_" + de::toString(m_currentIteration); 1288 1289 setup(); 1290 1291 render(numVertices, numTriangles, indices); 1292 } 1293 1294 // Verify result. 1295 1296 if (!verify(m_currentIteration, getResultImage().getAccess())) 1297 return tcu::TestStatus::fail("Result verification failed"); 1298 1299 m_currentIteration++; 1300 if (m_currentIteration == getNumIterations()) 1301 return tcu::TestStatus::pass("Pass"); 1302 else 1303 return tcu::TestStatus::incomplete(); 1304 } 1305 1306 void TextureGatherInstance::setupUniforms (const tcu::Vec4&) 1307 { 1308 deUint32 binding = 0; 1309 1310 useSampler(binding++, 0u); 1311 1312 if (m_baseParams.gatherType == GATHERTYPE_OFFSET_DYNAMIC) 1313 addUniform(binding++, vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, sizeof(tcu::Vec2), RENDER_SIZE.asFloat().getPtr()); 1314 1315 if (m_baseParams.offsetSize == OFFSETSIZE_IMPLEMENTATION_MAXIMUM) 1316 { 1317 if (m_baseParams.gatherType == GATHERTYPE_OFFSET) 1318 { 1319 const GatherArgs& gatherArgs = getGatherArgs(m_currentIteration); 1320 addUniform(binding++, vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, sizeof(tcu::IVec2), gatherArgs.offsets[0].getPtr()); 1321 } 1322 else if (m_baseParams.gatherType == GATHERTYPE_OFFSET_DYNAMIC) 1323 { 1324 const IVec2& offsetRange = getOffsetRange(m_baseParams.offsetSize, m_context.getDeviceProperties().limits); 1325 addUniform(binding++, vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, sizeof(tcu::IVec2), offsetRange.getPtr()); 1326 } 1327 else 1328 DE_ASSERT(false); 1329 } 1330 } 1331 1332 template <typename TexViewT, typename TexCoordT> 1333 bool TextureGatherInstance::verify (const ConstPixelBufferAccess& rendered, 1334 const TexViewT& texture, 1335 const TexCoordT (&texCoords)[4], 1336 const GatherArgs& gatherArgs) const 1337 { 1338 TestLog& log = m_context.getTestContext().getLog(); 1339 1340 { 1341 DE_ASSERT(m_colorBufferFormat.order == tcu::TextureFormat::RGBA); 1342 DE_ASSERT(m_colorBufferFormat.type == tcu::TextureFormat::UNORM_INT8 || 1343 m_colorBufferFormat.type == tcu::TextureFormat::UNSIGNED_INT8 || 1344 m_colorBufferFormat.type == tcu::TextureFormat::SIGNED_INT8); 1345 1346 const MovePtr<PixelOffsets> pixelOffsets = makePixelOffsetsFunctor(m_baseParams.gatherType, gatherArgs, getOffsetRange(m_baseParams.offsetSize, m_context.getDeviceProperties().limits)); 1347 const tcu::PixelFormat pixelFormat = tcu::PixelFormat(8,8,8,8); 1348 const IVec4 colorBits = tcu::max(TextureTestUtil::getBitsVec(pixelFormat) - 1, tcu::IVec4(0)); 1349 const IVec3 coordBits = m_baseParams.textureType == TEXTURETYPE_2D ? IVec3(20,20,0) 1350 : m_baseParams.textureType == TEXTURETYPE_CUBE ? IVec3(10,10,10) 1351 : m_baseParams.textureType == TEXTURETYPE_2D_ARRAY ? IVec3(20,20,20) 1352 : IVec3(-1); 1353 const IVec3 uvwBits = m_baseParams.textureType == TEXTURETYPE_2D ? IVec3(7,7,0) 1354 : m_baseParams.textureType == TEXTURETYPE_CUBE ? IVec3(6,6,0) 1355 : m_baseParams.textureType == TEXTURETYPE_2D_ARRAY ? IVec3(7,7,7) 1356 : IVec3(-1); 1357 tcu::Sampler sampler; 1358 sampler.wrapS = m_baseParams.wrapS; 1359 sampler.wrapT = m_baseParams.wrapT; 1360 sampler.compare = m_baseParams.shadowCompareMode; 1361 1362 if (isDepthFormat(m_baseParams.textureFormat)) 1363 { 1364 tcu::TexComparePrecision comparePrec; 1365 comparePrec.coordBits = coordBits; 1366 comparePrec.uvwBits = uvwBits; 1367 comparePrec.referenceBits = 16; 1368 comparePrec.resultBits = pixelFormat.redBits-1; 1369 1370 return verifyGatherOffsetsCompare(log, rendered, texture, texCoords, sampler, comparePrec, PixelCompareRefZDefault(RENDER_SIZE), *pixelOffsets); 1371 } 1372 else 1373 { 1374 const int componentNdx = de::max(0, gatherArgs.componentNdx); 1375 1376 if (isUnormFormatType(m_baseParams.textureFormat.type)) 1377 { 1378 tcu::LookupPrecision lookupPrec; 1379 lookupPrec.colorThreshold = tcu::computeFixedPointThreshold(colorBits); 1380 lookupPrec.coordBits = coordBits; 1381 lookupPrec.uvwBits = uvwBits; 1382 lookupPrec.colorMask = TextureTestUtil::getCompareMask(pixelFormat); 1383 return verifyGatherOffsets<float>(log, rendered, texture, texCoords, sampler, lookupPrec, componentNdx, *pixelOffsets); 1384 } 1385 else if (isUIntFormatType(m_baseParams.textureFormat.type) || isSIntFormatType(m_baseParams.textureFormat.type)) 1386 { 1387 tcu::IntLookupPrecision lookupPrec; 1388 lookupPrec.colorThreshold = UVec4(0); 1389 lookupPrec.coordBits = coordBits; 1390 lookupPrec.uvwBits = uvwBits; 1391 lookupPrec.colorMask = TextureTestUtil::getCompareMask(pixelFormat); 1392 1393 if (isUIntFormatType(m_baseParams.textureFormat.type)) 1394 return verifyGatherOffsets<deUint32>(log, rendered, texture, texCoords, sampler, lookupPrec, componentNdx, *pixelOffsets); 1395 else if (isSIntFormatType(m_baseParams.textureFormat.type)) 1396 return verifyGatherOffsets<deInt32>(log, rendered, texture, texCoords, sampler, lookupPrec, componentNdx, *pixelOffsets); 1397 else 1398 { 1399 DE_ASSERT(false); 1400 return false; 1401 } 1402 } 1403 else 1404 { 1405 DE_ASSERT(false); 1406 return false; 1407 } 1408 } 1409 } 1410 } 1411 1412 glu::VertexSource genVertexShaderSource (bool requireGpuShader5, int numTexCoordComponents, bool useNormalizedCoordInput) 1413 { 1414 DE_ASSERT(numTexCoordComponents == 2 || numTexCoordComponents == 3); 1415 1416 const string texCoordType = "vec" + de::toString(numTexCoordComponents); 1417 std::ostringstream vert; 1418 1419 vert << "#version 310 es\n"; 1420 1421 if (requireGpuShader5) 1422 vert << "#extension GL_EXT_gpu_shader5 : require\n"; 1423 1424 vert << "\n" 1425 "layout (location = 0) in highp vec2 a_position;\n" 1426 "layout (location = 1) in highp " << texCoordType << " a_texCoord;\n"; 1427 1428 if (useNormalizedCoordInput) 1429 vert << "layout (location = 2) in highp vec2 a_normalizedCoord; // (0,0) to (1,1)\n"; 1430 1431 vert << "\n" 1432 "layout (location = 0) out highp " << texCoordType << " v_texCoord;\n"; 1433 1434 if (useNormalizedCoordInput) 1435 vert << "layout (location = 1) out highp vec2 v_normalizedCoord;\n"; 1436 1437 vert << "\n" 1438 "void main (void)\n" 1439 "{\n" 1440 " gl_Position = vec4(a_position.x, a_position.y, 0.0, 1.0);\n" 1441 " v_texCoord = a_texCoord;\n"; 1442 1443 if (useNormalizedCoordInput) 1444 vert << " v_normalizedCoord = a_normalizedCoord;\n"; 1445 1446 vert << "}\n"; 1447 1448 return glu::VertexSource(vert.str()); 1449 } 1450 1451 glu::FragmentSource genFragmentShaderSource (bool requireGpuShader5, 1452 int numTexCoordComponents, 1453 glu::DataType samplerType, 1454 const string& funcCall, 1455 bool useNormalizedCoordInput, 1456 bool usePixCoord, 1457 OffsetSize offsetSize, 1458 const ImageBackingMode sparseCase) 1459 { 1460 DE_ASSERT(glu::isDataTypeSampler(samplerType)); 1461 DE_ASSERT(de::inRange(numTexCoordComponents, 2, 3)); 1462 DE_ASSERT(!usePixCoord || useNormalizedCoordInput); 1463 1464 const string texCoordType = "vec" + de::toString(numTexCoordComponents); 1465 deUint32 binding = 0; 1466 std::ostringstream frag; 1467 const string outType = glu::getDataTypeName(getSamplerGatherResultType(samplerType)); 1468 1469 if (sparseCase == ShaderRenderCaseInstance::IMAGE_BACKING_MODE_SPARSE) 1470 frag << "#version 450\n" 1471 << "#extension GL_ARB_sparse_texture2 : require\n"; 1472 else 1473 frag << "#version 310 es\n"; 1474 1475 if (requireGpuShader5) 1476 frag << "#extension GL_EXT_gpu_shader5 : require\n"; 1477 1478 frag << "\n" 1479 "layout (location = 0) out mediump " << outType << " o_color;\n" 1480 "\n" 1481 "layout (location = 0) in highp " << texCoordType << " v_texCoord;\n"; 1482 1483 if (useNormalizedCoordInput) 1484 frag << "layout (location = 1) in highp vec2 v_normalizedCoord;\n"; 1485 1486 frag << "\n" 1487 "layout (binding = " << binding++ << ") uniform highp " << glu::getDataTypeName(samplerType) << " u_sampler;\n"; 1488 1489 if (usePixCoord) 1490 frag << "layout (binding = " << binding++ << ") uniform viewportSize { highp vec2 u_viewportSize; };\n"; 1491 1492 if (offsetSize == OFFSETSIZE_IMPLEMENTATION_MAXIMUM) 1493 frag << "layout (binding = " << binding++ << ") uniform offset { highp ivec2 u_offset; };\n"; 1494 1495 frag << "\n" 1496 "void main(void)\n" 1497 "{\n"; 1498 1499 if (usePixCoord) 1500 frag << " ivec2 pixCoord = ivec2(v_normalizedCoord*u_viewportSize);\n"; 1501 1502 if (sparseCase == ShaderRenderCaseInstance::IMAGE_BACKING_MODE_SPARSE) 1503 { 1504 // Texel declaration 1505 frag << "\t" << outType << " texel;\n"; 1506 frag << "\tint success = " << funcCall << ";\n"; 1507 1508 // Check sparse validity, and handle each case 1509 frag << "\tif (sparseTexelsResidentARB(success))\n" 1510 << "\t\to_color = texel;\n" 1511 << "\telse\n" 1512 << "\t\to_color = " << outType << "(0.0, 0.0, 0.0, 1.0);\n"; 1513 } 1514 else 1515 { 1516 frag << "\t\to_color = " << funcCall << ";\n"; 1517 } 1518 1519 frag << "}\n"; 1520 1521 return glu::FragmentSource(frag.str()); 1522 } 1523 1524 string genGatherFuncCall (GatherType gatherType, 1525 const tcu::TextureFormat& textureFormat, 1526 const GatherArgs& gatherArgs, 1527 const string& refZExpr, 1528 const IVec2& offsetRange, 1529 int indentationDepth, 1530 OffsetSize offsetSize, 1531 const ImageBackingMode sparseCase) 1532 { 1533 string result; 1534 1535 if (sparseCase == ShaderRenderCaseInstance::IMAGE_BACKING_MODE_SPARSE) 1536 { 1537 switch (gatherType) 1538 { 1539 case GATHERTYPE_BASIC: 1540 result += "sparseTextureGatherARB"; 1541 break; 1542 case GATHERTYPE_OFFSET: // \note Fallthrough. 1543 case GATHERTYPE_OFFSET_DYNAMIC: 1544 result += "sparseTextureGatherOffsetARB"; 1545 break; 1546 case GATHERTYPE_OFFSETS: 1547 result += "sparseTextureGatherOffsetsARB"; 1548 break; 1549 default: 1550 DE_ASSERT(false); 1551 } 1552 } 1553 else 1554 { 1555 switch (gatherType) 1556 { 1557 case GATHERTYPE_BASIC: 1558 result += "textureGather"; 1559 break; 1560 case GATHERTYPE_OFFSET: // \note Fallthrough. 1561 case GATHERTYPE_OFFSET_DYNAMIC: 1562 result += "textureGatherOffset"; 1563 break; 1564 case GATHERTYPE_OFFSETS: 1565 result += "textureGatherOffsets"; 1566 break; 1567 default: 1568 DE_ASSERT(false); 1569 } 1570 } 1571 1572 result += "(u_sampler, v_texCoord"; 1573 1574 if (isDepthFormat(textureFormat)) 1575 { 1576 DE_ASSERT(gatherArgs.componentNdx < 0); 1577 result += ", " + refZExpr; 1578 } 1579 1580 if (gatherType == GATHERTYPE_OFFSET || 1581 gatherType == GATHERTYPE_OFFSET_DYNAMIC || 1582 gatherType == GATHERTYPE_OFFSETS) 1583 { 1584 result += ", "; 1585 switch (gatherType) 1586 { 1587 case GATHERTYPE_OFFSET: 1588 if (offsetSize == OFFSETSIZE_IMPLEMENTATION_MAXIMUM) 1589 result += "u_offset"; 1590 else 1591 result += "ivec2" + de::toString(gatherArgs.offsets[0]); 1592 break; 1593 1594 case GATHERTYPE_OFFSET_DYNAMIC: 1595 if (offsetSize == OFFSETSIZE_IMPLEMENTATION_MAXIMUM) 1596 result += "pixCoord.yx % ivec2(u_offset.y - u_offset.x + 1) + u_offset.x"; 1597 else 1598 result += "pixCoord.yx % ivec2(" + de::toString(offsetRange.y() - offsetRange.x() + 1) + ") + " + de::toString(offsetRange.x()); 1599 break; 1600 1601 case GATHERTYPE_OFFSETS: 1602 DE_ASSERT(offsetSize != OFFSETSIZE_IMPLEMENTATION_MAXIMUM); 1603 result += "ivec2[4](\n" 1604 + string(indentationDepth, '\t') + "\tivec2" + de::toString(gatherArgs.offsets[0]) + ",\n" 1605 + string(indentationDepth, '\t') + "\tivec2" + de::toString(gatherArgs.offsets[1]) + ",\n" 1606 + string(indentationDepth, '\t') + "\tivec2" + de::toString(gatherArgs.offsets[2]) + ",\n" 1607 + string(indentationDepth, '\t') + "\tivec2" + de::toString(gatherArgs.offsets[3]) + ")\n" 1608 + string(indentationDepth, '\t') + "\t"; 1609 break; 1610 1611 default: 1612 DE_ASSERT(false); 1613 } 1614 } 1615 1616 if (sparseCase == ShaderRenderCaseInstance::IMAGE_BACKING_MODE_SPARSE) 1617 result += ", texel"; 1618 1619 if (gatherArgs.componentNdx >= 0) 1620 { 1621 DE_ASSERT(gatherArgs.componentNdx < 4); 1622 result += ", " + de::toString(gatherArgs.componentNdx); 1623 } 1624 1625 result += ")"; 1626 1627 return result; 1628 } 1629 1630 // \todo [2016-07-08 pyry] Re-use programs if sources are identical 1631 1632 void genGatherPrograms (vk::SourceCollections& programCollection, const GatherCaseBaseParams& baseParams, const vector<GatherArgs>& iterations) 1633 { 1634 const int numIterations = (int)iterations.size(); 1635 const string refZExpr = "v_normalizedCoord.x"; 1636 const IVec2& offsetRange = baseParams.offsetSize != OFFSETSIZE_IMPLEMENTATION_MAXIMUM ? getOffsetRange(baseParams.offsetSize) : IVec2(0); 1637 const bool usePixCoord = baseParams.gatherType == GATHERTYPE_OFFSET_DYNAMIC; 1638 const bool useNormalizedCoord = usePixCoord || isDepthFormat(baseParams.textureFormat); 1639 const bool isDynamicOffset = baseParams.gatherType == GATHERTYPE_OFFSET_DYNAMIC; 1640 const bool isShadow = isDepthFormat(baseParams.textureFormat); 1641 const glu::DataType samplerType = getSamplerType(baseParams.textureType, baseParams.textureFormat); 1642 const int numDims = getNumTextureSamplingDimensions(baseParams.textureType); 1643 glu::VertexSource vert = genVertexShaderSource(requireGpuShader5(baseParams.gatherType, baseParams.offsetSize), numDims, isDynamicOffset || isShadow); 1644 1645 programCollection.glslSources.add("vert") << vert; 1646 1647 for (int iterNdx = 0; iterNdx < numIterations; iterNdx++) 1648 { 1649 const GatherArgs& gatherArgs = iterations[iterNdx]; 1650 const string funcCall = genGatherFuncCall(baseParams.gatherType, baseParams.textureFormat, gatherArgs, refZExpr, offsetRange, 1, baseParams.offsetSize, baseParams.sparseCase); 1651 glu::FragmentSource frag = genFragmentShaderSource(requireGpuShader5(baseParams.gatherType, baseParams.offsetSize), numDims, samplerType, funcCall, useNormalizedCoord, usePixCoord, baseParams.offsetSize, baseParams.sparseCase); 1652 1653 programCollection.glslSources.add("frag_" + de::toString(iterNdx)) << frag; 1654 } 1655 } 1656 1657 // 2D 1658 1659 class TextureGather2DInstance : public TextureGatherInstance 1660 { 1661 public: 1662 TextureGather2DInstance (Context& context, 1663 const GatherCaseBaseParams& baseParams, 1664 const IVec2& textureSize, 1665 const vector<GatherArgs>& iterations); 1666 virtual ~TextureGather2DInstance (void); 1667 1668 protected: 1669 virtual int getNumIterations (void) const { return (int)m_iterations.size(); } 1670 virtual GatherArgs getGatherArgs (int iterationNdx) const { return m_iterations[iterationNdx];} 1671 1672 virtual TextureBindingSp createTexture (void); 1673 virtual vector<float> computeQuadTexCoord (int iterationNdx) const; 1674 virtual bool verify (int iterationNdx, const ConstPixelBufferAccess& rendered) const; 1675 1676 private: 1677 const IVec2 m_textureSize; 1678 const vector<GatherArgs> m_iterations; 1679 1680 tcu::Texture2D m_swizzledTexture; 1681 }; 1682 1683 TextureGather2DInstance::TextureGather2DInstance (Context& context, 1684 const GatherCaseBaseParams& baseParams, 1685 const IVec2& textureSize, 1686 const vector<GatherArgs>& iterations) 1687 : TextureGatherInstance (context, baseParams) 1688 , m_textureSize (textureSize) 1689 , m_iterations (iterations) 1690 , m_swizzledTexture (tcu::TextureFormat(), 1, 1) 1691 { 1692 init(); 1693 } 1694 1695 TextureGather2DInstance::~TextureGather2DInstance (void) 1696 { 1697 } 1698 1699 vector<float> TextureGather2DInstance::computeQuadTexCoord (int /* iterationNdx */) const 1700 { 1701 vector<float> res; 1702 TextureTestUtil::computeQuadTexCoord2D(res, Vec2(-0.3f, -0.4f), Vec2(1.5f, 1.6f)); 1703 return res; 1704 } 1705 1706 TextureBindingSp TextureGather2DInstance::createTexture (void) 1707 { 1708 TestLog& log = m_context.getTestContext().getLog(); 1709 const tcu::TextureFormatInfo texFmtInfo = tcu::getTextureFormatInfo(m_baseParams.textureFormat); 1710 MovePtr<tcu::Texture2D> texture = MovePtr<tcu::Texture2D>(new tcu::Texture2D(m_baseParams.textureFormat, m_textureSize.x(), m_textureSize.y())); 1711 const tcu::Sampler sampler (m_baseParams.wrapS, m_baseParams.wrapT, tcu::Sampler::REPEAT_GL, 1712 m_baseParams.minFilter, m_baseParams.magFilter, 1713 0.0f /* LOD threshold */, true /* normalized coords */, m_baseParams.shadowCompareMode); 1714 1715 { 1716 const int levelBegin = m_baseParams.baseLevel; 1717 const int levelEnd = texture->getNumLevels(); 1718 DE_ASSERT(m_baseParams.baseLevel < texture->getNumLevels()); 1719 1720 for (int levelNdx = levelBegin; levelNdx < levelEnd; levelNdx++) 1721 { 1722 texture->allocLevel(levelNdx); 1723 const PixelBufferAccess& level = texture->getLevel(levelNdx); 1724 fillWithRandomColorTiles(level, texFmtInfo.valueMin, texFmtInfo.valueMax, (deUint32)m_context.getTestContext().getCommandLine().getBaseSeed()); 1725 log << TestLog::Image("InputTextureLevel" + de::toString(levelNdx), "Input texture, level " + de::toString(levelNdx), level) 1726 << TestLog::Message << "Note: texture level's size is " << IVec2(level.getWidth(), level.getHeight()) << TestLog::EndMessage; 1727 } 1728 1729 swizzleTexture(m_swizzledTexture, *texture, m_baseParams.textureSwizzle); 1730 } 1731 1732 return TextureBindingSp(new TextureBinding(texture.release(), sampler)); 1733 } 1734 1735 bool TextureGather2DInstance::verify (int iterationNdx, const ConstPixelBufferAccess& rendered) const 1736 { 1737 Vec2 texCoords[4]; 1738 computeTexCoordVecs(computeQuadTexCoord(iterationNdx), texCoords); 1739 return TextureGatherInstance::verify(rendered, getOneLevelSubView(tcu::Texture2DView(m_swizzledTexture), m_baseParams.baseLevel), texCoords, m_iterations[iterationNdx]); 1740 } 1741 1742 class TextureGather2DCase : public TestCase 1743 { 1744 public: 1745 TextureGather2DCase (tcu::TestContext& testCtx, 1746 const string& name, 1747 const string& description, 1748 const GatherType gatherType, 1749 const OffsetSize offsetSize, 1750 const tcu::TextureFormat textureFormat, 1751 const tcu::Sampler::CompareMode shadowCompareMode, 1752 const tcu::Sampler::WrapMode wrapS, 1753 const tcu::Sampler::WrapMode wrapT, 1754 const MaybeTextureSwizzle& textureSwizzle, 1755 const tcu::Sampler::FilterMode minFilter, 1756 const tcu::Sampler::FilterMode magFilter, 1757 const int baseLevel, 1758 const deUint32 flags, 1759 const IVec2& textureSize, 1760 const ImageBackingMode sparseCase); 1761 virtual ~TextureGather2DCase (void); 1762 1763 virtual void initPrograms (vk::SourceCollections& dst) const; 1764 virtual TestInstance* createInstance (Context& context) const; 1765 1766 private: 1767 const GatherCaseBaseParams m_baseParams; 1768 const IVec2 m_textureSize; 1769 }; 1770 1771 TextureGather2DCase::TextureGather2DCase (tcu::TestContext& testCtx, 1772 const string& name, 1773 const string& description, 1774 const GatherType gatherType, 1775 const OffsetSize offsetSize, 1776 const tcu::TextureFormat textureFormat, 1777 const tcu::Sampler::CompareMode shadowCompareMode, 1778 const tcu::Sampler::WrapMode wrapS, 1779 const tcu::Sampler::WrapMode wrapT, 1780 const MaybeTextureSwizzle& textureSwizzle, 1781 const tcu::Sampler::FilterMode minFilter, 1782 const tcu::Sampler::FilterMode magFilter, 1783 const int baseLevel, 1784 const deUint32 flags, 1785 const IVec2& textureSize, 1786 const ImageBackingMode sparseCase) 1787 : TestCase (testCtx, name, description) 1788 , m_baseParams (TEXTURETYPE_2D, gatherType, offsetSize, textureFormat, shadowCompareMode, wrapS, wrapT, textureSwizzle, minFilter, magFilter, baseLevel, flags, sparseCase) 1789 , m_textureSize (textureSize) 1790 { 1791 } 1792 1793 TextureGather2DCase::~TextureGather2DCase (void) 1794 { 1795 } 1796 1797 void TextureGather2DCase::initPrograms (vk::SourceCollections& dst) const 1798 { 1799 const vector<GatherArgs> iterations = generateBasic2DCaseIterations(m_baseParams.gatherType, 1800 m_baseParams.textureFormat, 1801 m_baseParams.offsetSize != OFFSETSIZE_IMPLEMENTATION_MAXIMUM ? getOffsetRange(m_baseParams.offsetSize) : IVec2(0)); 1802 1803 genGatherPrograms(dst, m_baseParams, iterations); 1804 } 1805 1806 TestInstance* TextureGather2DCase::createInstance (Context& context) const 1807 { 1808 const vector<GatherArgs> iterations = generateBasic2DCaseIterations(m_baseParams.gatherType, 1809 m_baseParams.textureFormat, 1810 getOffsetRange(m_baseParams.offsetSize, context.getDeviceProperties().limits)); 1811 1812 return new TextureGather2DInstance(context, m_baseParams, m_textureSize, iterations); 1813 } 1814 1815 // 2D array 1816 1817 struct Gather2DArrayArgs 1818 { 1819 GatherArgs gatherArgs; 1820 int layerNdx; 1821 1822 operator GatherArgs() const { return gatherArgs; } 1823 }; 1824 1825 vector<Gather2DArrayArgs> generate2DArrayCaseIterations (GatherType gatherType, 1826 const tcu::TextureFormat& textureFormat, 1827 const IVec2& offsetRange, 1828 const IVec3& textureSize) 1829 { 1830 const vector<GatherArgs> basicIterations = generateBasic2DCaseIterations(gatherType, textureFormat, offsetRange); 1831 vector<Gather2DArrayArgs> iterations; 1832 1833 // \note Out-of-bounds layer indices are tested too. 1834 for (int layerNdx = -1; layerNdx < textureSize.z()+1; layerNdx++) 1835 { 1836 // Don't duplicate all cases for all layers. 1837 if (layerNdx == 0) 1838 { 1839 for (int basicNdx = 0; basicNdx < (int)basicIterations.size(); basicNdx++) 1840 { 1841 iterations.push_back(Gather2DArrayArgs()); 1842 iterations.back().gatherArgs = basicIterations[basicNdx]; 1843 iterations.back().layerNdx = layerNdx; 1844 } 1845 } 1846 else 1847 { 1848 // For other layers than 0, only test one component and one set of offsets per layer. 1849 for (int basicNdx = 0; basicNdx < (int)basicIterations.size(); basicNdx++) 1850 { 1851 if (isDepthFormat(textureFormat) || basicIterations[basicNdx].componentNdx == (layerNdx + 2) % 4) 1852 { 1853 iterations.push_back(Gather2DArrayArgs()); 1854 iterations.back().gatherArgs = basicIterations[basicNdx]; 1855 iterations.back().layerNdx = layerNdx; 1856 break; 1857 } 1858 } 1859 } 1860 } 1861 1862 return iterations; 1863 } 1864 1865 class TextureGather2DArrayInstance : public TextureGatherInstance 1866 { 1867 public: 1868 TextureGather2DArrayInstance (Context& context, 1869 const GatherCaseBaseParams& baseParams, 1870 const IVec3& textureSize, 1871 const vector<Gather2DArrayArgs>& iterations); 1872 virtual ~TextureGather2DArrayInstance (void); 1873 1874 protected: 1875 virtual int getNumIterations (void) const { return (int)m_iterations.size(); } 1876 virtual GatherArgs getGatherArgs (int iterationNdx) const { return m_iterations[iterationNdx].gatherArgs; } 1877 1878 virtual TextureBindingSp createTexture (void); 1879 virtual vector<float> computeQuadTexCoord (int iterationNdx) const; 1880 virtual bool verify (int iterationNdx, const ConstPixelBufferAccess& rendered) const; 1881 1882 private: 1883 const IVec3 m_textureSize; 1884 const vector<Gather2DArrayArgs> m_iterations; 1885 1886 tcu::Texture2DArray m_swizzledTexture; 1887 }; 1888 1889 TextureGather2DArrayInstance::TextureGather2DArrayInstance (Context& context, 1890 const GatherCaseBaseParams& baseParams, 1891 const IVec3& textureSize, 1892 const vector<Gather2DArrayArgs>& iterations) 1893 : TextureGatherInstance (context, baseParams) 1894 , m_textureSize (textureSize) 1895 , m_iterations (iterations) 1896 , m_swizzledTexture (tcu::TextureFormat(), 1, 1, 1) 1897 { 1898 init(); 1899 } 1900 1901 TextureGather2DArrayInstance::~TextureGather2DArrayInstance (void) 1902 { 1903 } 1904 1905 vector<float> TextureGather2DArrayInstance::computeQuadTexCoord (int iterationNdx) const 1906 { 1907 vector<float> res; 1908 TextureTestUtil::computeQuadTexCoord2DArray(res, m_iterations[iterationNdx].layerNdx, Vec2(-0.3f, -0.4f), Vec2(1.5f, 1.6f)); 1909 return res; 1910 } 1911 1912 TextureBindingSp TextureGather2DArrayInstance::createTexture (void) 1913 { 1914 TestLog& log = m_context.getTestContext().getLog(); 1915 const tcu::TextureFormatInfo texFmtInfo = tcu::getTextureFormatInfo(m_baseParams.textureFormat); 1916 MovePtr<tcu::Texture2DArray> texture = MovePtr<tcu::Texture2DArray>(new tcu::Texture2DArray(m_baseParams.textureFormat, m_textureSize.x(), m_textureSize.y(), m_textureSize.z())); 1917 const tcu::Sampler sampler (m_baseParams.wrapS, m_baseParams.wrapT, tcu::Sampler::REPEAT_GL, 1918 m_baseParams.minFilter, m_baseParams.magFilter, 1919 0.0f /* LOD threshold */, true /* normalized coords */, m_baseParams.shadowCompareMode); 1920 1921 { 1922 const int levelBegin = m_baseParams.baseLevel; 1923 const int levelEnd = texture->getNumLevels(); 1924 DE_ASSERT(m_baseParams.baseLevel < texture->getNumLevels()); 1925 1926 for (int levelNdx = levelBegin; levelNdx < levelEnd; levelNdx++) 1927 { 1928 texture->allocLevel(levelNdx); 1929 const PixelBufferAccess& level = texture->getLevel(levelNdx); 1930 fillWithRandomColorTiles(level, texFmtInfo.valueMin, texFmtInfo.valueMax, (deUint32)m_context.getTestContext().getCommandLine().getBaseSeed()); 1931 1932 log << TestLog::ImageSet("InputTextureLevel", "Input texture, level " + de::toString(levelNdx)); 1933 for (int layerNdx = 0; layerNdx < m_textureSize.z(); layerNdx++) 1934 log << TestLog::Image("InputTextureLevel" + de::toString(layerNdx) + "Layer" + de::toString(layerNdx), 1935 "Layer " + de::toString(layerNdx), 1936 tcu::getSubregion(level, 0, 0, layerNdx, level.getWidth(), level.getHeight(), 1)); 1937 log << TestLog::EndImageSet 1938 << TestLog::Message << "Note: texture level's size is " << IVec3(level.getWidth(), level.getHeight(), level.getDepth()) << TestLog::EndMessage; 1939 } 1940 1941 swizzleTexture(m_swizzledTexture, *texture, m_baseParams.textureSwizzle); 1942 } 1943 1944 return TextureBindingSp(new TextureBinding(texture.release(), sampler)); 1945 } 1946 1947 bool TextureGather2DArrayInstance::verify (int iterationNdx, const ConstPixelBufferAccess& rendered) const 1948 { 1949 Vec3 texCoords[4]; 1950 computeTexCoordVecs(computeQuadTexCoord(iterationNdx), texCoords); 1951 return TextureGatherInstance::verify(rendered, getOneLevelSubView(tcu::Texture2DArrayView(m_swizzledTexture), m_baseParams.baseLevel), texCoords, m_iterations[iterationNdx].gatherArgs); 1952 } 1953 1954 class TextureGather2DArrayCase : public TestCase 1955 { 1956 public: 1957 TextureGather2DArrayCase (tcu::TestContext& testCtx, 1958 const string& name, 1959 const string& description, 1960 const GatherType gatherType, 1961 const OffsetSize offsetSize, 1962 const tcu::TextureFormat textureFormat, 1963 const tcu::Sampler::CompareMode shadowCompareMode, 1964 const tcu::Sampler::WrapMode wrapS, 1965 const tcu::Sampler::WrapMode wrapT, 1966 const MaybeTextureSwizzle& textureSwizzle, 1967 const tcu::Sampler::FilterMode minFilter, 1968 const tcu::Sampler::FilterMode magFilter, 1969 const int baseLevel, 1970 const deUint32 flags, 1971 const IVec3& textureSize, 1972 const ImageBackingMode sparseCase); 1973 virtual ~TextureGather2DArrayCase (void); 1974 1975 virtual void initPrograms (vk::SourceCollections& dst) const; 1976 virtual TestInstance* createInstance (Context& context) const; 1977 1978 private: 1979 const GatherCaseBaseParams m_baseParams; 1980 const IVec3 m_textureSize; 1981 }; 1982 1983 TextureGather2DArrayCase::TextureGather2DArrayCase (tcu::TestContext& testCtx, 1984 const string& name, 1985 const string& description, 1986 const GatherType gatherType, 1987 const OffsetSize offsetSize, 1988 const tcu::TextureFormat textureFormat, 1989 const tcu::Sampler::CompareMode shadowCompareMode, 1990 const tcu::Sampler::WrapMode wrapS, 1991 const tcu::Sampler::WrapMode wrapT, 1992 const MaybeTextureSwizzle& textureSwizzle, 1993 const tcu::Sampler::FilterMode minFilter, 1994 const tcu::Sampler::FilterMode magFilter, 1995 const int baseLevel, 1996 const deUint32 flags, 1997 const IVec3& textureSize, 1998 const ImageBackingMode sparseCase) 1999 : TestCase (testCtx, name, description) 2000 , m_baseParams (TEXTURETYPE_2D_ARRAY, gatherType, offsetSize, textureFormat, shadowCompareMode, wrapS, wrapT, textureSwizzle, minFilter, magFilter, baseLevel, flags, sparseCase) 2001 , m_textureSize (textureSize) 2002 { 2003 } 2004 2005 TextureGather2DArrayCase::~TextureGather2DArrayCase (void) 2006 { 2007 } 2008 2009 void TextureGather2DArrayCase::initPrograms (vk::SourceCollections& dst) const 2010 { 2011 const vector<Gather2DArrayArgs> iterations = generate2DArrayCaseIterations(m_baseParams.gatherType, 2012 m_baseParams.textureFormat, 2013 m_baseParams.offsetSize != OFFSETSIZE_IMPLEMENTATION_MAXIMUM ? getOffsetRange(m_baseParams.offsetSize) : IVec2(0), 2014 m_textureSize); 2015 2016 genGatherPrograms(dst, m_baseParams, vector<GatherArgs>(iterations.begin(), iterations.end())); 2017 } 2018 2019 TestInstance* TextureGather2DArrayCase::createInstance (Context& context) const 2020 { 2021 const vector<Gather2DArrayArgs> iterations = generate2DArrayCaseIterations(m_baseParams.gatherType, 2022 m_baseParams.textureFormat, 2023 getOffsetRange(m_baseParams.offsetSize, context.getDeviceProperties().limits), 2024 m_textureSize); 2025 2026 return new TextureGather2DArrayInstance(context, m_baseParams, m_textureSize, iterations); 2027 } 2028 2029 // Cube 2030 2031 struct GatherCubeArgs 2032 { 2033 GatherArgs gatherArgs; 2034 tcu::CubeFace face; 2035 2036 operator GatherArgs() const { return gatherArgs; } 2037 }; 2038 2039 vector<GatherCubeArgs> generateCubeCaseIterations (GatherType gatherType, const tcu::TextureFormat& textureFormat, const IVec2& offsetRange) 2040 { 2041 const vector<GatherArgs> basicIterations = generateBasic2DCaseIterations(gatherType, textureFormat, offsetRange); 2042 vector<GatherCubeArgs> iterations; 2043 2044 for (int cubeFaceI = 0; cubeFaceI < tcu::CUBEFACE_LAST; cubeFaceI++) 2045 { 2046 const tcu::CubeFace cubeFace = (tcu::CubeFace)cubeFaceI; 2047 2048 // Don't duplicate all cases for all faces. 2049 if (cubeFaceI == 0) 2050 { 2051 for (int basicNdx = 0; basicNdx < (int)basicIterations.size(); basicNdx++) 2052 { 2053 iterations.push_back(GatherCubeArgs()); 2054 iterations.back().gatherArgs = basicIterations[basicNdx]; 2055 iterations.back().face = cubeFace; 2056 } 2057 } 2058 else 2059 { 2060 // For other faces than first, only test one component per face. 2061 for (int basicNdx = 0; basicNdx < (int)basicIterations.size(); basicNdx++) 2062 { 2063 if (isDepthFormat(textureFormat) || basicIterations[basicNdx].componentNdx == cubeFaceI % 4) 2064 { 2065 iterations.push_back(GatherCubeArgs()); 2066 iterations.back().gatherArgs = basicIterations[basicNdx]; 2067 iterations.back().face = cubeFace; 2068 break; 2069 } 2070 } 2071 } 2072 } 2073 2074 return iterations; 2075 } 2076 2077 class TextureGatherCubeInstance : public TextureGatherInstance 2078 { 2079 public: 2080 TextureGatherCubeInstance (Context& context, 2081 const GatherCaseBaseParams& baseParams, 2082 const int textureSize, 2083 const vector<GatherCubeArgs>& iterations); 2084 virtual ~TextureGatherCubeInstance (void); 2085 2086 protected: 2087 virtual int getNumIterations (void) const { return (int)m_iterations.size(); } 2088 virtual GatherArgs getGatherArgs (int iterationNdx) const { return m_iterations[iterationNdx].gatherArgs; } 2089 2090 virtual TextureBindingSp createTexture (void); 2091 virtual vector<float> computeQuadTexCoord (int iterationNdx) const; 2092 virtual bool verify (int iterationNdx, const ConstPixelBufferAccess& rendered) const; 2093 2094 private: 2095 const int m_textureSize; 2096 const vector<GatherCubeArgs> m_iterations; 2097 2098 tcu::TextureCube m_swizzledTexture; 2099 }; 2100 2101 TextureGatherCubeInstance::TextureGatherCubeInstance (Context& context, 2102 const GatherCaseBaseParams& baseParams, 2103 const int textureSize, 2104 const vector<GatherCubeArgs>& iterations) 2105 : TextureGatherInstance (context, baseParams) 2106 , m_textureSize (textureSize) 2107 , m_iterations (iterations) 2108 , m_swizzledTexture (tcu::TextureFormat(), 1) 2109 { 2110 init(); 2111 } 2112 2113 TextureGatherCubeInstance::~TextureGatherCubeInstance (void) 2114 { 2115 } 2116 2117 vector<float> TextureGatherCubeInstance::computeQuadTexCoord (int iterationNdx) const 2118 { 2119 const bool corners = (m_baseParams.flags & GATHERCASE_DONT_SAMPLE_CUBE_CORNERS) == 0; 2120 const Vec2 minC = corners ? Vec2(-1.2f) : Vec2(-0.6f, -1.2f); 2121 const Vec2 maxC = corners ? Vec2( 1.2f) : Vec2( 0.6f, 1.2f); 2122 vector<float> res; 2123 TextureTestUtil::computeQuadTexCoordCube(res, m_iterations[iterationNdx].face, minC, maxC); 2124 return res; 2125 } 2126 2127 TextureBindingSp TextureGatherCubeInstance::createTexture (void) 2128 { 2129 TestLog& log = m_context.getTestContext().getLog(); 2130 const tcu::TextureFormatInfo texFmtInfo = tcu::getTextureFormatInfo(m_baseParams.textureFormat); 2131 MovePtr<tcu::TextureCube> texture = MovePtr<tcu::TextureCube>(new tcu::TextureCube(m_baseParams.textureFormat, m_textureSize)); 2132 const tcu::Sampler sampler (m_baseParams.wrapS, m_baseParams.wrapT, tcu::Sampler::REPEAT_GL, 2133 m_baseParams.minFilter, m_baseParams.magFilter, 2134 0.0f /* LOD threshold */, true /* normalized coords */, m_baseParams.shadowCompareMode, 2135 0 /* cmp channel */, tcu::Vec4(0.0f) /* border color */, true /* seamless cube map */); 2136 2137 { 2138 const int levelBegin = m_baseParams.baseLevel; 2139 const int levelEnd = texture->getNumLevels(); 2140 DE_ASSERT(m_baseParams.baseLevel < texture->getNumLevels()); 2141 2142 for (int levelNdx = levelBegin; levelNdx < levelEnd; levelNdx++) 2143 { 2144 log << TestLog::ImageSet("InputTextureLevel" + de::toString(levelNdx), "Input texture, level " + de::toString(levelNdx)); 2145 2146 for (int cubeFaceI = 0; cubeFaceI < tcu::CUBEFACE_LAST; cubeFaceI++) 2147 { 2148 const tcu::CubeFace cubeFace = (tcu::CubeFace)cubeFaceI; 2149 texture->allocLevel(cubeFace, levelNdx); 2150 const PixelBufferAccess& levelFace = texture->getLevelFace(levelNdx, cubeFace); 2151 fillWithRandomColorTiles(levelFace, texFmtInfo.valueMin, texFmtInfo.valueMax, (deUint32)m_context.getTestContext().getCommandLine().getBaseSeed() ^ (deUint32)cubeFaceI); 2152 2153 log << TestLog::Image("InputTextureLevel" + de::toString(levelNdx) + "Face" + de::toString((int)cubeFace), de::toString(cubeFace), levelFace); 2154 } 2155 2156 log << TestLog::EndImageSet 2157 << TestLog::Message << "Note: texture level's size is " << texture->getLevelFace(levelNdx, tcu::CUBEFACE_NEGATIVE_X).getWidth() << TestLog::EndMessage; 2158 } 2159 2160 swizzleTexture(m_swizzledTexture, *texture, m_baseParams.textureSwizzle); 2161 } 2162 2163 return TextureBindingSp(new TextureBinding(texture.release(), sampler)); 2164 } 2165 2166 bool TextureGatherCubeInstance::verify (int iterationNdx, const ConstPixelBufferAccess& rendered) const 2167 { 2168 Vec3 texCoords[4]; 2169 computeTexCoordVecs(computeQuadTexCoord(iterationNdx), texCoords); 2170 return TextureGatherInstance::verify(rendered, getOneLevelSubView(tcu::TextureCubeView(m_swizzledTexture), m_baseParams.baseLevel), texCoords, m_iterations[iterationNdx].gatherArgs); 2171 } 2172 2173 // \note Cube case always uses just basic textureGather(); offset versions are not defined for cube maps. 2174 class TextureGatherCubeCase : public TestCase 2175 { 2176 public: 2177 TextureGatherCubeCase (tcu::TestContext& testCtx, 2178 const string& name, 2179 const string& description, 2180 const tcu::TextureFormat textureFormat, 2181 const tcu::Sampler::CompareMode shadowCompareMode, 2182 const tcu::Sampler::WrapMode wrapS, 2183 const tcu::Sampler::WrapMode wrapT, 2184 const MaybeTextureSwizzle& textureSwizzle, 2185 const tcu::Sampler::FilterMode minFilter, 2186 const tcu::Sampler::FilterMode magFilter, 2187 const int baseLevel, 2188 const deUint32 flags, 2189 const int textureSize, 2190 const ImageBackingMode sparseCase); 2191 virtual ~TextureGatherCubeCase (void); 2192 2193 virtual void initPrograms (vk::SourceCollections& dst) const; 2194 virtual TestInstance* createInstance (Context& context) const; 2195 2196 private: 2197 const GatherCaseBaseParams m_baseParams; 2198 const int m_textureSize; 2199 }; 2200 2201 TextureGatherCubeCase::TextureGatherCubeCase (tcu::TestContext& testCtx, 2202 const string& name, 2203 const string& description, 2204 const tcu::TextureFormat textureFormat, 2205 const tcu::Sampler::CompareMode shadowCompareMode, 2206 const tcu::Sampler::WrapMode wrapS, 2207 const tcu::Sampler::WrapMode wrapT, 2208 const MaybeTextureSwizzle& textureSwizzle, 2209 const tcu::Sampler::FilterMode minFilter, 2210 const tcu::Sampler::FilterMode magFilter, 2211 const int baseLevel, 2212 const deUint32 flags, 2213 const int textureSize, 2214 const ImageBackingMode sparseCase) 2215 : TestCase (testCtx, name, description) 2216 , m_baseParams (TEXTURETYPE_CUBE, GATHERTYPE_BASIC, OFFSETSIZE_NONE, textureFormat, shadowCompareMode, wrapS, wrapT, textureSwizzle, minFilter, magFilter, baseLevel, flags, sparseCase) 2217 , m_textureSize (textureSize) 2218 { 2219 } 2220 2221 TextureGatherCubeCase::~TextureGatherCubeCase (void) 2222 { 2223 } 2224 2225 void TextureGatherCubeCase::initPrograms (vk::SourceCollections& dst) const 2226 { 2227 const vector<GatherCubeArgs> iterations = generateCubeCaseIterations(m_baseParams.gatherType, 2228 m_baseParams.textureFormat, 2229 m_baseParams.offsetSize != OFFSETSIZE_IMPLEMENTATION_MAXIMUM ? getOffsetRange(m_baseParams.offsetSize) : IVec2(0)); 2230 2231 genGatherPrograms(dst, m_baseParams, vector<GatherArgs>(iterations.begin(), iterations.end())); 2232 } 2233 2234 TestInstance* TextureGatherCubeCase::createInstance (Context& context) const 2235 { 2236 const vector<GatherCubeArgs> iterations = generateCubeCaseIterations(m_baseParams.gatherType, 2237 m_baseParams.textureFormat, 2238 getOffsetRange(m_baseParams.offsetSize, context.getDeviceProperties().limits)); 2239 2240 return new TextureGatherCubeInstance(context, m_baseParams, m_textureSize, iterations); 2241 } 2242 2243 class TextureGatherTests : public tcu::TestCaseGroup 2244 { 2245 public: 2246 TextureGatherTests (tcu::TestContext& context); 2247 virtual ~TextureGatherTests (void); 2248 virtual void init (void); 2249 2250 private: 2251 TextureGatherTests (const TextureGatherTests&); // not allowed! 2252 TextureGatherTests& operator= (const TextureGatherTests&); // not allowed! 2253 }; 2254 2255 TextureGatherTests::TextureGatherTests (tcu::TestContext& context) 2256 : TestCaseGroup(context, "texture_gather", "textureGather* tests") 2257 { 2258 } 2259 2260 TextureGatherTests::~TextureGatherTests (void) 2261 { 2262 } 2263 2264 static inline TestCase* makeTextureGatherCase (TextureType textureType, 2265 tcu::TestContext& testCtx, 2266 const string& name, 2267 const string& description, 2268 GatherType gatherType, 2269 OffsetSize offsetSize, 2270 tcu::TextureFormat textureFormat, 2271 tcu::Sampler::CompareMode shadowCompareMode, 2272 tcu::Sampler::WrapMode wrapS, 2273 tcu::Sampler::WrapMode wrapT, 2274 const MaybeTextureSwizzle& texSwizzle, 2275 tcu::Sampler::FilterMode minFilter, 2276 tcu::Sampler::FilterMode magFilter, 2277 int baseLevel, 2278 const IVec3& textureSize, 2279 deUint32 flags = 0, 2280 const ImageBackingMode sparseCase = ShaderRenderCaseInstance::IMAGE_BACKING_MODE_REGULAR) 2281 { 2282 switch (textureType) 2283 { 2284 case TEXTURETYPE_2D: 2285 return new TextureGather2DCase(testCtx, name, description, gatherType, offsetSize, textureFormat, shadowCompareMode, 2286 wrapS, wrapT, texSwizzle, minFilter, magFilter, baseLevel, flags, textureSize.swizzle(0, 1), sparseCase); 2287 2288 case TEXTURETYPE_2D_ARRAY: 2289 return new TextureGather2DArrayCase(testCtx, name, description, gatherType, offsetSize, textureFormat, shadowCompareMode, 2290 wrapS, wrapT, texSwizzle, minFilter, magFilter, baseLevel, flags, textureSize, sparseCase); 2291 2292 case TEXTURETYPE_CUBE: 2293 DE_ASSERT(gatherType == GATHERTYPE_BASIC); 2294 DE_ASSERT(offsetSize == OFFSETSIZE_NONE); 2295 return new TextureGatherCubeCase(testCtx, name, description, textureFormat, shadowCompareMode, 2296 wrapS, wrapT, texSwizzle, minFilter, magFilter, baseLevel, flags, textureSize.x(), sparseCase); 2297 2298 default: 2299 DE_ASSERT(false); 2300 return DE_NULL; 2301 } 2302 } 2303 2304 static inline const char* compareModeName (tcu::Sampler::CompareMode mode) 2305 { 2306 switch (mode) 2307 { 2308 case tcu::Sampler::COMPAREMODE_LESS: return "less"; 2309 case tcu::Sampler::COMPAREMODE_LESS_OR_EQUAL: return "less_or_equal"; 2310 case tcu::Sampler::COMPAREMODE_GREATER: return "greater"; 2311 case tcu::Sampler::COMPAREMODE_GREATER_OR_EQUAL: return "greater_or_equal"; 2312 case tcu::Sampler::COMPAREMODE_EQUAL: return "equal"; 2313 case tcu::Sampler::COMPAREMODE_NOT_EQUAL: return "not_equal"; 2314 case tcu::Sampler::COMPAREMODE_ALWAYS: return "always"; 2315 case tcu::Sampler::COMPAREMODE_NEVER: return "never"; 2316 default: DE_ASSERT(false); return DE_NULL; 2317 } 2318 } 2319 2320 void TextureGatherTests::init (void) 2321 { 2322 const struct 2323 { 2324 const char* name; 2325 TextureType type; 2326 } textureTypes[] = 2327 { 2328 { "2d", TEXTURETYPE_2D }, 2329 { "2d_array", TEXTURETYPE_2D_ARRAY }, 2330 { "cube", TEXTURETYPE_CUBE } 2331 }; 2332 2333 const struct 2334 { 2335 const char* name; 2336 tcu::TextureFormat format; 2337 } formats[] = 2338 { 2339 { "rgba8", tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8) }, 2340 { "rgba8ui", tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNSIGNED_INT8) }, 2341 { "rgba8i", tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::SIGNED_INT8) }, 2342 { "depth32f", tcu::TextureFormat(tcu::TextureFormat::D, tcu::TextureFormat::FLOAT) } 2343 }; 2344 2345 const struct 2346 { 2347 const char* name; 2348 IVec3 size; 2349 } textureSizes[] = 2350 { 2351 { "size_pot", IVec3(64, 64, 3) }, 2352 { "size_npot", IVec3(17, 23, 3) } 2353 }; 2354 2355 const struct 2356 { 2357 const char* name; 2358 tcu::Sampler::WrapMode mode; 2359 } wrapModes[] = 2360 { 2361 { "clamp_to_edge", tcu::Sampler::CLAMP_TO_EDGE }, 2362 { "repeat", tcu::Sampler::REPEAT_GL }, 2363 { "mirrored_repeat", tcu::Sampler::MIRRORED_REPEAT_GL } 2364 }; 2365 2366 for (int gatherTypeI = 0; gatherTypeI < GATHERTYPE_LAST; gatherTypeI++) 2367 { 2368 const GatherType gatherType = (GatherType)gatherTypeI; 2369 TestCaseGroup* const gatherTypeGroup = new TestCaseGroup(m_testCtx, gatherTypeName(gatherType), gatherTypeDescription(gatherType)); 2370 addChild(gatherTypeGroup); 2371 2372 for (int offsetSizeI = 0; offsetSizeI < OFFSETSIZE_LAST; offsetSizeI++) 2373 { 2374 const OffsetSize offsetSize = (OffsetSize)offsetSizeI; 2375 if ((gatherType == GATHERTYPE_BASIC) != (offsetSize == OFFSETSIZE_NONE)) 2376 continue; 2377 2378 if (gatherType == GATHERTYPE_OFFSETS && offsetSize == OFFSETSIZE_IMPLEMENTATION_MAXIMUM) // \note offsets argument must be compile-time constant 2379 continue; 2380 2381 TestCaseGroup* const offsetSizeGroup = offsetSize == OFFSETSIZE_NONE ? 2382 gatherTypeGroup : 2383 new TestCaseGroup(m_testCtx, 2384 offsetSize == OFFSETSIZE_MINIMUM_REQUIRED ? "min_required_offset" 2385 : offsetSize == OFFSETSIZE_IMPLEMENTATION_MAXIMUM ? "implementation_offset" 2386 : DE_NULL, 2387 offsetSize == OFFSETSIZE_MINIMUM_REQUIRED ? "Use offsets within Vulkan minimum required range" 2388 : offsetSize == OFFSETSIZE_IMPLEMENTATION_MAXIMUM ? "Use offsets within the implementation range" 2389 : DE_NULL); 2390 2391 if (offsetSizeGroup != gatherTypeGroup) 2392 gatherTypeGroup->addChild(offsetSizeGroup); 2393 2394 for (int textureTypeNdx = 0; textureTypeNdx < DE_LENGTH_OF_ARRAY(textureTypes); textureTypeNdx++) 2395 { 2396 const TextureType textureType = textureTypes[textureTypeNdx].type; 2397 2398 if (textureType == TEXTURETYPE_CUBE && gatherType != GATHERTYPE_BASIC) 2399 continue; 2400 2401 TestCaseGroup* const textureTypeGroup = new TestCaseGroup(m_testCtx, textureTypes[textureTypeNdx].name, ""); 2402 offsetSizeGroup->addChild(textureTypeGroup); 2403 2404 for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(formats); formatNdx++) 2405 { 2406 const tcu::TextureFormat& format = formats[formatNdx].format; 2407 TestCaseGroup* const formatGroup = new TestCaseGroup(m_testCtx, formats[formatNdx].name, ""); 2408 textureTypeGroup->addChild(formatGroup); 2409 2410 for (int noCornersI = 0; noCornersI <= ((textureType == TEXTURETYPE_CUBE)?1:0); noCornersI++) 2411 { 2412 const bool noCorners = noCornersI!= 0; 2413 TestCaseGroup* const cornersGroup = noCorners 2414 ? new TestCaseGroup(m_testCtx, "no_corners", "Test case variants that don't sample around cube map corners") 2415 : formatGroup; 2416 2417 if (formatGroup != cornersGroup) 2418 formatGroup->addChild(cornersGroup); 2419 2420 for (int textureSizeNdx = 0; textureSizeNdx < DE_LENGTH_OF_ARRAY(textureSizes); textureSizeNdx++) 2421 { 2422 const IVec3& textureSize = textureSizes[textureSizeNdx].size; 2423 TestCaseGroup* const textureSizeGroup = new TestCaseGroup(m_testCtx, textureSizes[textureSizeNdx].name, ""); 2424 cornersGroup->addChild(textureSizeGroup); 2425 2426 for (int compareModeI = 0; compareModeI < tcu::Sampler::COMPAREMODE_LAST; compareModeI++) 2427 { 2428 const tcu::Sampler::CompareMode compareMode = (tcu::Sampler::CompareMode)compareModeI; 2429 2430 if ((compareMode != tcu::Sampler::COMPAREMODE_NONE) != isDepthFormat(format)) 2431 continue; 2432 2433 if (compareMode != tcu::Sampler::COMPAREMODE_NONE && 2434 compareMode != tcu::Sampler::COMPAREMODE_LESS && 2435 compareMode != tcu::Sampler::COMPAREMODE_GREATER) 2436 continue; 2437 2438 TestCaseGroup* const compareModeGroup = compareMode == tcu::Sampler::COMPAREMODE_NONE ? 2439 textureSizeGroup : 2440 new TestCaseGroup(m_testCtx, 2441 (string() + "compare_" + compareModeName(compareMode)).c_str(), 2442 ""); 2443 if (compareModeGroup != textureSizeGroup) 2444 textureSizeGroup->addChild(compareModeGroup); 2445 2446 for (int wrapCaseNdx = 0; wrapCaseNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapCaseNdx++) 2447 { 2448 const int wrapSNdx = wrapCaseNdx; 2449 const int wrapTNdx = (wrapCaseNdx + 1) % DE_LENGTH_OF_ARRAY(wrapModes); 2450 const tcu::Sampler::WrapMode wrapS = wrapModes[wrapSNdx].mode; 2451 const tcu::Sampler::WrapMode wrapT = wrapModes[wrapTNdx].mode; 2452 2453 const string caseName = string() + wrapModes[wrapSNdx].name + "_" + wrapModes[wrapTNdx].name; 2454 2455 compareModeGroup->addChild(makeTextureGatherCase(textureType, m_testCtx, caseName.c_str(), "", gatherType, offsetSize, format, compareMode, wrapS, wrapT, 2456 MaybeTextureSwizzle::createNoneTextureSwizzle(), tcu::Sampler::NEAREST, tcu::Sampler::NEAREST, 0, textureSize, 2457 noCorners ? GATHERCASE_DONT_SAMPLE_CUBE_CORNERS : 0)); 2458 compareModeGroup->addChild(makeTextureGatherCase(textureType, m_testCtx, "sparse_" + caseName, "", gatherType, offsetSize, format, compareMode, wrapS, wrapT, 2459 MaybeTextureSwizzle::createNoneTextureSwizzle(), tcu::Sampler::NEAREST, tcu::Sampler::NEAREST, 0, textureSize, 2460 noCorners ? GATHERCASE_DONT_SAMPLE_CUBE_CORNERS : 0, ShaderRenderCaseInstance::IMAGE_BACKING_MODE_SPARSE)); 2461 } 2462 } 2463 } 2464 } 2465 2466 if (offsetSize != OFFSETSIZE_MINIMUM_REQUIRED || gatherType == GATHERTYPE_OFFSETS) // Don't test all features for both offset size types, as they should be rather orthogonal. 2467 { 2468 if (!isDepthFormat(format)) 2469 { 2470 TestCaseGroup* const swizzleGroup = new TestCaseGroup(m_testCtx, "texture_swizzle", ""); 2471 formatGroup->addChild(swizzleGroup); 2472 2473 DE_STATIC_ASSERT(TEXTURESWIZZLECOMPONENT_R == 0); 2474 for (int swizzleCaseNdx = 0; swizzleCaseNdx < TEXTURESWIZZLECOMPONENT_LAST; swizzleCaseNdx++) 2475 { 2476 MaybeTextureSwizzle swizzle = MaybeTextureSwizzle::createSomeTextureSwizzle(); 2477 string caseName; 2478 2479 for (int i = 0; i < 4; i++) 2480 { 2481 swizzle.getSwizzle()[i] = (TextureSwizzleComponent)((swizzleCaseNdx + i) % (int)TEXTURESWIZZLECOMPONENT_LAST); 2482 caseName += (i > 0 ? "_" : "") + de::toLower(de::toString(swizzle.getSwizzle()[i])); 2483 } 2484 2485 swizzleGroup->addChild(makeTextureGatherCase(textureType, m_testCtx, caseName.c_str(), "", gatherType, offsetSize, format, 2486 tcu::Sampler::COMPAREMODE_NONE, tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL, 2487 swizzle, tcu::Sampler::NEAREST, tcu::Sampler::NEAREST, 0, IVec3(64, 64, 3))); 2488 swizzleGroup->addChild(makeTextureGatherCase(textureType, m_testCtx, "sparse_" + caseName, "", gatherType, offsetSize, format, 2489 tcu::Sampler::COMPAREMODE_NONE, tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL, 2490 swizzle, tcu::Sampler::NEAREST, tcu::Sampler::NEAREST, 0, IVec3(64, 64, 3), 0, ShaderRenderCaseInstance::IMAGE_BACKING_MODE_SPARSE)); 2491 } 2492 } 2493 2494 { 2495 TestCaseGroup* const filterModeGroup = new TestCaseGroup(m_testCtx, "filter_mode", "Test that filter modes have no effect"); 2496 formatGroup->addChild(filterModeGroup); 2497 2498 const struct 2499 { 2500 const char* name; 2501 tcu::Sampler::FilterMode filter; 2502 } magFilters[] = 2503 { 2504 { "linear", tcu::Sampler::LINEAR }, 2505 { "nearest", tcu::Sampler::NEAREST } 2506 }; 2507 2508 const struct 2509 { 2510 const char* name; 2511 tcu::Sampler::FilterMode filter; 2512 } minFilters[] = 2513 { 2514 // \note Don't test NEAREST here, as it's covered by other cases. 2515 { "linear", tcu::Sampler::LINEAR }, 2516 { "nearest_mipmap_nearest", tcu::Sampler::NEAREST_MIPMAP_NEAREST }, 2517 { "nearest_mipmap_linear", tcu::Sampler::NEAREST_MIPMAP_LINEAR }, 2518 { "linear_mipmap_nearest", tcu::Sampler::LINEAR_MIPMAP_NEAREST }, 2519 { "linear_mipmap_linear", tcu::Sampler::LINEAR_MIPMAP_LINEAR }, 2520 }; 2521 2522 for (int minFilterNdx = 0; minFilterNdx < DE_LENGTH_OF_ARRAY(minFilters); minFilterNdx++) 2523 for (int magFilterNdx = 0; magFilterNdx < DE_LENGTH_OF_ARRAY(magFilters); magFilterNdx++) 2524 { 2525 const tcu::Sampler::FilterMode minFilter = minFilters[minFilterNdx].filter; 2526 const tcu::Sampler::FilterMode magFilter = magFilters[magFilterNdx].filter; 2527 const tcu::Sampler::CompareMode compareMode = isDepthFormat(format) ? tcu::Sampler::COMPAREMODE_LESS : tcu::Sampler::COMPAREMODE_NONE; 2528 2529 if ((isUnormFormatType(format.type) || isDepthFormat(format)) && magFilter == tcu::Sampler::NEAREST) 2530 continue; // Covered by other cases. 2531 if ((isUIntFormatType(format.type) || isSIntFormatType(format.type)) && 2532 (magFilter != tcu::Sampler::NEAREST || minFilter != tcu::Sampler::NEAREST_MIPMAP_NEAREST)) 2533 continue; 2534 2535 const string caseName = string() + "min_" + minFilters[minFilterNdx].name + "_mag_" + magFilters[magFilterNdx].name; 2536 2537 filterModeGroup->addChild(makeTextureGatherCase(textureType, m_testCtx, caseName.c_str(), "", gatherType, offsetSize, format, compareMode, 2538 tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL, MaybeTextureSwizzle::createNoneTextureSwizzle(), 2539 minFilter, magFilter, 0, IVec3(64, 64, 3))); 2540 filterModeGroup->addChild(makeTextureGatherCase(textureType, m_testCtx, "sparse_" + caseName, "", gatherType, offsetSize, format, compareMode, 2541 tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL, MaybeTextureSwizzle::createNoneTextureSwizzle(), 2542 minFilter, magFilter, 0, IVec3(64, 64, 3), 0, ShaderRenderCaseInstance::IMAGE_BACKING_MODE_SPARSE)); 2543 } 2544 } 2545 2546 { 2547 TestCaseGroup* const baseLevelGroup = new TestCaseGroup(m_testCtx, "base_level", ""); 2548 formatGroup->addChild(baseLevelGroup); 2549 2550 for (int baseLevel = 1; baseLevel <= 2; baseLevel++) 2551 { 2552 const string caseName = "level_" + de::toString(baseLevel); 2553 const tcu::Sampler::CompareMode compareMode = isDepthFormat(format) ? tcu::Sampler::COMPAREMODE_LESS : tcu::Sampler::COMPAREMODE_NONE; 2554 baseLevelGroup->addChild(makeTextureGatherCase(textureType, m_testCtx, caseName.c_str(), "", gatherType, offsetSize, format, 2555 compareMode, tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL, 2556 MaybeTextureSwizzle::createNoneTextureSwizzle(), tcu::Sampler::NEAREST, tcu::Sampler::NEAREST, 2557 baseLevel, IVec3(64, 64, 3))); 2558 baseLevelGroup->addChild(makeTextureGatherCase(textureType, m_testCtx, "sparse_" + caseName, "", gatherType, offsetSize, format, 2559 compareMode, tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL, 2560 MaybeTextureSwizzle::createNoneTextureSwizzle(), tcu::Sampler::NEAREST, tcu::Sampler::NEAREST, 2561 baseLevel, IVec3(64, 64, 3), 0, ShaderRenderCaseInstance::IMAGE_BACKING_MODE_SPARSE)); 2562 } 2563 } 2564 } 2565 } 2566 } 2567 } 2568 } 2569 } 2570 2571 } // anonymous 2572 2573 tcu::TestCaseGroup* createTextureGatherTests (tcu::TestContext& testCtx) 2574 { 2575 return new TextureGatherTests(testCtx); 2576 } 2577 2578 } // sr 2579 } // vkt 2580