Add texture gather tests. Fixes #360.
authorAkos Dirner <adirner.uszeged@partner.samsung.com>
Tue, 26 Apr 2016 20:13:53 +0000 (22:13 +0200)
committerPyry Haulos <phaulos@google.com>
Mon, 13 Jun 2016 17:23:44 +0000 (10:23 -0700)
external/vulkancts/modules/vulkan/shaderrender/CMakeLists.txt
external/vulkancts/modules/vulkan/shaderrender/vktShaderRenderTextureGatherTests.cpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/shaderrender/vktShaderRenderTextureGatherTests.hpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/vktTestPackage.cpp

index 3c3ba07..83fe317 100644 (file)
@@ -23,6 +23,8 @@ set(DEQP_VK_SHADERRENDER_SRCS
        vktShaderRenderSwitchTests.hpp
        vktShaderRenderTextureFunctionTests.cpp
        vktShaderRenderTextureFunctionTests.hpp
+       vktShaderRenderTextureGatherTests.cpp
+       vktShaderRenderTextureGatherTests.hpp
        )
 
 set(DEQP_VK_SHADERRENDER_LIBS
diff --git a/external/vulkancts/modules/vulkan/shaderrender/vktShaderRenderTextureGatherTests.cpp b/external/vulkancts/modules/vulkan/shaderrender/vktShaderRenderTextureGatherTests.cpp
new file mode 100644 (file)
index 0000000..3e7b465
--- /dev/null
@@ -0,0 +1,2731 @@
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2016 The Khronos Group Inc.
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *//*!
+ * \file
+ * \brief GLSL textureGather[Offset[s]] tests.
+ *//*--------------------------------------------------------------------*/
+
+#include "vktShaderRenderTextureGatherTests.hpp"
+#include "vktShaderRender.hpp"
+#include "vkImageUtil.hpp"
+#include "gluTextureUtil.hpp"
+#include "tcuTexture.hpp"
+#include "tcuTextureUtil.hpp"
+#include "tcuSurface.hpp"
+#include "tcuTestLog.hpp"
+#include "tcuVectorUtil.hpp"
+#include "tcuTexLookupVerifier.hpp"
+#include "tcuTexCompareVerifier.hpp"
+#include "tcuPixelFormat.hpp"
+#include "tcuCommandLine.hpp"
+#include "deUniquePtr.hpp"
+#include "deStringUtil.hpp"
+#include "deRandom.hpp"
+
+using tcu::ConstPixelBufferAccess;
+using tcu::PixelBufferAccess;
+using tcu::TestLog;
+using tcu::IVec2;
+using tcu::IVec3;
+using tcu::IVec4;
+using tcu::UVec4;
+using tcu::Vec2;
+using tcu::Vec3;
+using tcu::Vec4;
+using de::MovePtr;
+
+using std::string;
+using std::vector;
+
+namespace vkt
+{
+namespace sr
+{
+namespace
+{
+
+enum TextureType
+{
+       TEXTURETYPE_2D,
+       TEXTURETYPE_2D_ARRAY,
+       TEXTURETYPE_CUBE,
+
+       TEXTURETYPE_LAST
+};
+
+// \note TextureTestUtil functions are copied from glsTextureTestUtil
+namespace TextureTestUtil
+{
+
+inline tcu::IVec4 getBitsVec (const tcu::PixelFormat& format)
+{
+       return tcu::IVec4(format.redBits, format.greenBits, format.blueBits, format.alphaBits);
+}
+
+inline tcu::BVec4 getCompareMask (const tcu::PixelFormat& format)
+{
+       return tcu::BVec4(format.redBits        > 0,
+                                         format.greenBits      > 0,
+                                         format.blueBits       > 0,
+                                         format.alphaBits      > 0);
+}
+
+void computeQuadTexCoord2D (std::vector<float>& dst, const tcu::Vec2& bottomLeft, const tcu::Vec2& topRight)
+{
+       dst.resize(4*2);
+
+       dst[0] = bottomLeft.x();        dst[1] = bottomLeft.y();
+       dst[2] = bottomLeft.x();        dst[3] = topRight.y();
+       dst[4] = topRight.x();          dst[5] = bottomLeft.y();
+       dst[6] = topRight.x();          dst[7] = topRight.y();
+}
+
+void computeQuadTexCoord2DArray (std::vector<float>& dst, int layerNdx, const tcu::Vec2& bottomLeft, const tcu::Vec2& topRight)
+{
+       dst.resize(4*3);
+
+       dst[0] = bottomLeft.x();        dst[ 1] = bottomLeft.y();       dst[ 2] = (float)layerNdx;
+       dst[3] = bottomLeft.x();        dst[ 4] = topRight.y();         dst[ 5] = (float)layerNdx;
+       dst[6] = topRight.x();          dst[ 7] = bottomLeft.y();       dst[ 8] = (float)layerNdx;
+       dst[9] = topRight.x();          dst[10] = topRight.y();         dst[11] = (float)layerNdx;
+}
+
+void computeQuadTexCoordCube (std::vector<float>& dst, tcu::CubeFace face, const tcu::Vec2& bottomLeft, const tcu::Vec2& topRight)
+{
+       int             sRow            = 0;
+       int             tRow            = 0;
+       int             mRow            = 0;
+       float   sSign           = 1.0f;
+       float   tSign           = 1.0f;
+       float   mSign           = 1.0f;
+
+       switch (face)
+       {
+               case tcu::CUBEFACE_NEGATIVE_X: mRow = 0; sRow = 2; tRow = 1; mSign = -1.0f;                                tSign = -1.0f;       break;
+               case tcu::CUBEFACE_POSITIVE_X: mRow = 0; sRow = 2; tRow = 1;                            sSign = -1.0f; tSign = -1.0f;   break;
+               case tcu::CUBEFACE_NEGATIVE_Y: mRow = 1; sRow = 0; tRow = 2; mSign = -1.0f;                                tSign = -1.0f;       break;
+               case tcu::CUBEFACE_POSITIVE_Y: mRow = 1; sRow = 0; tRow = 2;                                                                                            break;
+               case tcu::CUBEFACE_NEGATIVE_Z: mRow = 2; sRow = 0; tRow = 1; mSign = -1.0f; sSign = -1.0f; tSign = -1.0f;       break;
+               case tcu::CUBEFACE_POSITIVE_Z: mRow = 2; sRow = 0; tRow = 1;                                                       tSign = -1.0f;       break;
+               default:
+                       DE_ASSERT(DE_FALSE);
+                       return;
+       }
+
+       dst.resize(3*4);
+
+       dst[0+mRow] = mSign;
+       dst[3+mRow] = mSign;
+       dst[6+mRow] = mSign;
+       dst[9+mRow] = mSign;
+
+       dst[0+sRow] = sSign * bottomLeft.x();
+       dst[3+sRow] = sSign * bottomLeft.x();
+       dst[6+sRow] = sSign * topRight.x();
+       dst[9+sRow] = sSign * topRight.x();
+
+       dst[0+tRow] = tSign * bottomLeft.y();
+       dst[3+tRow] = tSign * topRight.y();
+       dst[6+tRow] = tSign * bottomLeft.y();
+       dst[9+tRow] = tSign * topRight.y();
+}
+
+} // TextureTestUtil
+
+// Round-to-zero int division, because pre-c++11 it's somewhat implementation-defined for negative values.
+static inline int divRoundToZero (int a, int b)
+{
+       return de::abs(a) / de::abs(b) * deSign32(a) * deSign32(b);
+}
+
+static void fillWithRandomColorTiles (const PixelBufferAccess& dst, const Vec4& minVal, const Vec4& maxVal, deUint32 seed)
+{
+       const int       numCols         = dst.getWidth()  >= 7 ? 7 : dst.getWidth();
+       const int       numRows         = dst.getHeight() >= 5 ? 5 : dst.getHeight();
+       de::Random      rnd                     (seed);
+
+       for (int slice = 0; slice < dst.getDepth(); slice++)
+       for (int row = 0; row < numRows; row++)
+       for (int col = 0; col < numCols; col++)
+       {
+               const int       yBegin  = (row+0)*dst.getHeight()/numRows;
+               const int       yEnd    = (row+1)*dst.getHeight()/numRows;
+               const int       xBegin  = (col+0)*dst.getWidth()/numCols;
+               const int       xEnd    = (col+1)*dst.getWidth()/numCols;
+               Vec4            color;
+               for (int i = 0; i < 4; i++)
+                       color[i] = rnd.getFloat(minVal[i], maxVal[i]);
+               tcu::clear(tcu::getSubregion(dst, xBegin, yBegin, slice, xEnd-xBegin, yEnd-yBegin, 1), color);
+       }
+}
+
+static inline bool isDepthFormat (const tcu::TextureFormat& fmt)
+{
+       return fmt.order == tcu::TextureFormat::D || fmt.order == tcu::TextureFormat::DS;
+}
+
+static inline bool isUnormFormatType (tcu::TextureFormat::ChannelType type)
+{
+       return type == tcu::TextureFormat::UNORM_INT8   ||
+                  type == tcu::TextureFormat::UNORM_INT16      ||
+                  type == tcu::TextureFormat::UNORM_INT32;
+}
+
+static inline bool isSIntFormatType (tcu::TextureFormat::ChannelType type)
+{
+       return type == tcu::TextureFormat::SIGNED_INT8  ||
+                  type == tcu::TextureFormat::SIGNED_INT16     ||
+                  type == tcu::TextureFormat::SIGNED_INT32;
+}
+
+static inline bool isUIntFormatType (tcu::TextureFormat::ChannelType type)
+{
+       return type == tcu::TextureFormat::UNSIGNED_INT8        ||
+                  type == tcu::TextureFormat::UNSIGNED_INT16   ||
+                  type == tcu::TextureFormat::UNSIGNED_INT32;
+}
+
+enum TextureSwizzleComponent
+{
+       TEXTURESWIZZLECOMPONENT_R = 0,
+       TEXTURESWIZZLECOMPONENT_G,
+       TEXTURESWIZZLECOMPONENT_B,
+       TEXTURESWIZZLECOMPONENT_A,
+       TEXTURESWIZZLECOMPONENT_ZERO,
+       TEXTURESWIZZLECOMPONENT_ONE,
+
+       TEXTURESWIZZLECOMPONENT_LAST
+};
+
+static std::ostream& operator<< (std::ostream& stream, TextureSwizzleComponent comp)
+{
+       switch (comp)
+       {
+               case TEXTURESWIZZLECOMPONENT_R:         return stream << "RED";
+               case TEXTURESWIZZLECOMPONENT_G:         return stream << "GREEN";
+               case TEXTURESWIZZLECOMPONENT_B:         return stream << "BLUE";
+               case TEXTURESWIZZLECOMPONENT_A:         return stream << "ALPHA";
+               case TEXTURESWIZZLECOMPONENT_ZERO:      return stream << "ZERO";
+               case TEXTURESWIZZLECOMPONENT_ONE:       return stream << "ONE";
+               default: DE_ASSERT(false); return stream;
+       }
+}
+
+struct MaybeTextureSwizzle
+{
+public:
+       static MaybeTextureSwizzle                                              createNoneTextureSwizzle        (void);
+       static MaybeTextureSwizzle                                              createSomeTextureSwizzle        (void);
+
+       bool                                                                                    isSome                                          (void) const;
+       bool                                                                                    isNone                                          (void) const;
+       bool                                                                                    isIdentitySwizzle                       (void) const;
+
+       tcu::Vector<TextureSwizzleComponent, 4>&                getSwizzle                                      (void);
+       const tcu::Vector<TextureSwizzleComponent, 4>&  getSwizzle                                      (void) const;
+
+private:
+                                                                                                       MaybeTextureSwizzle                     (void);
+
+       tcu::Vector<TextureSwizzleComponent, 4>                 m_swizzle;
+       bool                                                                                    m_isSome;
+};
+
+static std::ostream& operator<< (std::ostream& stream, const MaybeTextureSwizzle& comp)
+{
+       if (comp.isNone())
+               stream << "[default swizzle state]";
+       else
+               stream << "(" << comp.getSwizzle()[0]
+                          << ", " << comp.getSwizzle()[1]
+                          << ", " << comp.getSwizzle()[2]
+                          << ", " << comp.getSwizzle()[3]
+                          << ")";
+
+       return stream;
+}
+
+MaybeTextureSwizzle MaybeTextureSwizzle::createNoneTextureSwizzle (void)
+{
+       MaybeTextureSwizzle swizzle;
+
+       swizzle.m_swizzle[0] = TEXTURESWIZZLECOMPONENT_LAST;
+       swizzle.m_swizzle[1] = TEXTURESWIZZLECOMPONENT_LAST;
+       swizzle.m_swizzle[2] = TEXTURESWIZZLECOMPONENT_LAST;
+       swizzle.m_swizzle[3] = TEXTURESWIZZLECOMPONENT_LAST;
+       swizzle.m_isSome = false;
+
+       return swizzle;
+}
+
+MaybeTextureSwizzle MaybeTextureSwizzle::createSomeTextureSwizzle (void)
+{
+       MaybeTextureSwizzle swizzle;
+
+       swizzle.m_swizzle[0] = TEXTURESWIZZLECOMPONENT_R;
+       swizzle.m_swizzle[1] = TEXTURESWIZZLECOMPONENT_G;
+       swizzle.m_swizzle[2] = TEXTURESWIZZLECOMPONENT_B;
+       swizzle.m_swizzle[3] = TEXTURESWIZZLECOMPONENT_A;
+       swizzle.m_isSome = true;
+
+       return swizzle;
+}
+
+bool MaybeTextureSwizzle::isSome (void) const
+{
+       return m_isSome;
+}
+
+bool MaybeTextureSwizzle::isNone (void) const
+{
+       return !m_isSome;
+}
+
+bool MaybeTextureSwizzle::isIdentitySwizzle (void) const
+{
+       return  m_isSome                                                                        &&
+                       m_swizzle[0] == TEXTURESWIZZLECOMPONENT_R       &&
+                       m_swizzle[1] == TEXTURESWIZZLECOMPONENT_G       &&
+                       m_swizzle[2] == TEXTURESWIZZLECOMPONENT_B       &&
+                       m_swizzle[3] == TEXTURESWIZZLECOMPONENT_A;
+}
+
+tcu::Vector<TextureSwizzleComponent, 4>& MaybeTextureSwizzle::getSwizzle (void)
+{
+       return m_swizzle;
+}
+
+const tcu::Vector<TextureSwizzleComponent, 4>& MaybeTextureSwizzle::getSwizzle (void) const
+{
+       return m_swizzle;
+}
+
+MaybeTextureSwizzle::MaybeTextureSwizzle (void)
+       : m_swizzle     (TEXTURESWIZZLECOMPONENT_LAST, TEXTURESWIZZLECOMPONENT_LAST, TEXTURESWIZZLECOMPONENT_LAST, TEXTURESWIZZLECOMPONENT_LAST)
+       , m_isSome      (false)
+{
+}
+
+static vk::VkComponentSwizzle getTextureSwizzleComponent (TextureSwizzleComponent c)
+{
+       switch (c)
+       {
+               case TEXTURESWIZZLECOMPONENT_R:         return vk::VK_COMPONENT_SWIZZLE_R;
+               case TEXTURESWIZZLECOMPONENT_G:         return vk::VK_COMPONENT_SWIZZLE_G;
+               case TEXTURESWIZZLECOMPONENT_B:         return vk::VK_COMPONENT_SWIZZLE_B;
+               case TEXTURESWIZZLECOMPONENT_A:         return vk::VK_COMPONENT_SWIZZLE_A;
+               case TEXTURESWIZZLECOMPONENT_ZERO:      return vk::VK_COMPONENT_SWIZZLE_ZERO;
+               case TEXTURESWIZZLECOMPONENT_ONE:       return vk::VK_COMPONENT_SWIZZLE_ONE;
+               default: DE_ASSERT(false); return (vk::VkComponentSwizzle)0;
+       }
+}
+
+template <typename T>
+static inline T swizzleColorChannel (const tcu::Vector<T, 4>& src, TextureSwizzleComponent swizzle)
+{
+       switch (swizzle)
+       {
+               case TEXTURESWIZZLECOMPONENT_R:         return src[0];
+               case TEXTURESWIZZLECOMPONENT_G:         return src[1];
+               case TEXTURESWIZZLECOMPONENT_B:         return src[2];
+               case TEXTURESWIZZLECOMPONENT_A:         return src[3];
+               case TEXTURESWIZZLECOMPONENT_ZERO:      return (T)0;
+               case TEXTURESWIZZLECOMPONENT_ONE:       return (T)1;
+               default: DE_ASSERT(false); return (T)-1;
+       }
+}
+
+template <typename T>
+static inline tcu::Vector<T, 4> swizzleColor (const tcu::Vector<T, 4>& src, const MaybeTextureSwizzle& swizzle)
+{
+       DE_ASSERT(swizzle.isSome());
+
+       tcu::Vector<T, 4> result;
+       for (int i = 0; i < 4; i++)
+               result[i] = swizzleColorChannel(src, swizzle.getSwizzle()[i]);
+       return result;
+}
+
+template <typename T>
+static void swizzlePixels (const PixelBufferAccess& dst, const ConstPixelBufferAccess& src, const MaybeTextureSwizzle& swizzle)
+{
+       DE_ASSERT(dst.getWidth()  == src.getWidth()  &&
+                         dst.getHeight() == src.getHeight() &&
+                         dst.getDepth()  == src.getDepth());
+       for (int z = 0; z < src.getDepth(); z++)
+       for (int y = 0; y < src.getHeight(); y++)
+       for (int x = 0; x < src.getWidth(); x++)
+               dst.setPixel(swizzleColor(src.getPixelT<T>(x, y, z), swizzle), x, y, z);
+}
+
+static void swizzlePixels (const PixelBufferAccess& dst, const ConstPixelBufferAccess& src, const MaybeTextureSwizzle& swizzle)
+{
+       if (isDepthFormat(dst.getFormat()))
+               DE_ASSERT(swizzle.isNone() || swizzle.isIdentitySwizzle());
+
+       if (swizzle.isNone() || swizzle.isIdentitySwizzle())
+               tcu::copy(dst, src);
+       else if (isUnormFormatType(dst.getFormat().type))
+               swizzlePixels<float>(dst, src, swizzle);
+       else if (isUIntFormatType(dst.getFormat().type))
+               swizzlePixels<deUint32>(dst, src, swizzle);
+       else if (isSIntFormatType(dst.getFormat().type))
+               swizzlePixels<deInt32>(dst, src, swizzle);
+       else
+               DE_ASSERT(false);
+}
+
+static void swizzleTexture (tcu::Texture2D& dst, const tcu::Texture2D& src, const MaybeTextureSwizzle& swizzle)
+{
+       dst = tcu::Texture2D(src.getFormat(), src.getWidth(), src.getHeight());
+       for (int levelNdx = 0; levelNdx < src.getNumLevels(); levelNdx++)
+       {
+               if (src.isLevelEmpty(levelNdx))
+                       continue;
+               dst.allocLevel(levelNdx);
+               swizzlePixels(dst.getLevel(levelNdx), src.getLevel(levelNdx), swizzle);
+       }
+}
+
+static void swizzleTexture (tcu::Texture2DArray& dst, const tcu::Texture2DArray& src, const MaybeTextureSwizzle& swizzle)
+{
+       dst = tcu::Texture2DArray(src.getFormat(), src.getWidth(), src.getHeight(), src.getNumLayers());
+       for (int levelNdx = 0; levelNdx < src.getNumLevels(); levelNdx++)
+       {
+               if (src.isLevelEmpty(levelNdx))
+                       continue;
+               dst.allocLevel(levelNdx);
+               swizzlePixels(dst.getLevel(levelNdx), src.getLevel(levelNdx), swizzle);
+       }
+}
+
+static void swizzleTexture (tcu::TextureCube& dst, const tcu::TextureCube& src, const MaybeTextureSwizzle& swizzle)
+{
+       dst = tcu::TextureCube(src.getFormat(), src.getSize());
+       for (int faceI = 0; faceI < tcu::CUBEFACE_LAST; faceI++)
+       {
+               const tcu::CubeFace face = (tcu::CubeFace)faceI;
+               for (int levelNdx = 0; levelNdx < src.getNumLevels(); levelNdx++)
+               {
+                       if (src.isLevelEmpty(face, levelNdx))
+                               continue;
+                       dst.allocLevel(face, levelNdx);
+                       swizzlePixels(dst.getLevelFace(levelNdx, face), src.getLevelFace(levelNdx, face), swizzle);
+               }
+       }
+}
+
+static tcu::Texture2DView getOneLevelSubView (const tcu::Texture2DView& view, int level)
+{
+       return tcu::Texture2DView(1, view.getLevels() + level);
+}
+
+static tcu::Texture2DArrayView getOneLevelSubView (const tcu::Texture2DArrayView& view, int level)
+{
+       return tcu::Texture2DArrayView(1, view.getLevels() + level);
+}
+
+static tcu::TextureCubeView getOneLevelSubView (const tcu::TextureCubeView& view, int level)
+{
+       const tcu::ConstPixelBufferAccess* levels[tcu::CUBEFACE_LAST];
+
+       for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
+               levels[face] = view.getFaceLevels((tcu::CubeFace)face) + level;
+
+       return tcu::TextureCubeView(1, levels);
+}
+
+class PixelOffsets
+{
+public:
+       virtual void operator() (const IVec2& pixCoord, IVec2 (&dst)[4]) const = 0;
+       virtual ~PixelOffsets (void) {}
+};
+
+class MultiplePixelOffsets : public PixelOffsets
+{
+public:
+       MultiplePixelOffsets (const IVec2& a,
+                                                 const IVec2& b,
+                                                 const IVec2& c,
+                                                 const IVec2& d)
+       {
+               m_offsets[0] = a;
+               m_offsets[1] = b;
+               m_offsets[2] = c;
+               m_offsets[3] = d;
+       }
+
+       void operator() (const IVec2& /* pixCoord */, IVec2 (&dst)[4]) const
+       {
+               for (int i = 0; i < DE_LENGTH_OF_ARRAY(dst); i++)
+                       dst[i] = m_offsets[i];
+       }
+
+private:
+       IVec2 m_offsets[4];
+};
+
+class SinglePixelOffsets : public MultiplePixelOffsets
+{
+public:
+       SinglePixelOffsets (const IVec2& offset)
+               : MultiplePixelOffsets(offset + IVec2(0, 1),
+                                                          offset + IVec2(1, 1),
+                                                          offset + IVec2(1, 0),
+                                                          offset + IVec2(0, 0))
+       {
+       }
+};
+
+class DynamicSinglePixelOffsets : public PixelOffsets
+{
+public:
+       DynamicSinglePixelOffsets (const IVec2& offsetRange) : m_offsetRange(offsetRange) {}
+
+       void operator() (const IVec2& pixCoord, IVec2 (&dst)[4]) const
+       {
+               const int offsetRangeSize = m_offsetRange.y() - m_offsetRange.x() + 1;
+               SinglePixelOffsets(tcu::mod(pixCoord.swizzle(1,0), IVec2(offsetRangeSize)) + m_offsetRange.x())(IVec2(), dst);
+       }
+
+private:
+       IVec2 m_offsetRange;
+};
+
+template <typename T>
+static inline T triQuadInterpolate (const T (&values)[4], float xFactor, float yFactor)
+{
+       if (xFactor + yFactor < 1.0f)
+               return values[0] + (values[2]-values[0])*xFactor                + (values[1]-values[0])*yFactor;
+       else
+               return values[3] + (values[1]-values[3])*(1.0f-xFactor) + (values[2]-values[3])*(1.0f-yFactor);
+}
+
+template <int N>
+static inline void computeTexCoordVecs (const vector<float>& texCoords, tcu::Vector<float, N> (&dst)[4])
+{
+       DE_ASSERT((int)texCoords.size() == 4*N);
+       for (int i = 0; i < 4; i++)
+       for (int j = 0; j < N; j++)
+               dst[i][j] = texCoords[i*N + j];
+}
+
+#if defined(DE_DEBUG)
+// Whether offsets correspond to the sample offsets used with plain textureGather().
+static inline bool isZeroOffsetOffsets (const IVec2 (&offsets)[4])
+{
+       IVec2 ref[4];
+       SinglePixelOffsets(IVec2(0))(IVec2(), ref);
+       return std::equal(DE_ARRAY_BEGIN(offsets),
+                                         DE_ARRAY_END(offsets),
+                                         DE_ARRAY_BEGIN(ref));
+}
+#endif
+
+template <typename ColorScalarType>
+static tcu::Vector<ColorScalarType, 4> gatherOffsets (const tcu::Texture2DView& texture, const tcu::Sampler& sampler, const Vec2& coord, int componentNdx, const IVec2 (&offsets)[4])
+{
+       return texture.gatherOffsets(sampler, coord.x(), coord.y(), componentNdx, offsets).cast<ColorScalarType>();
+}
+
+template <typename ColorScalarType>
+static tcu::Vector<ColorScalarType, 4> gatherOffsets (const tcu::Texture2DArrayView& texture, const tcu::Sampler& sampler, const Vec3& coord, int componentNdx, const IVec2 (&offsets)[4])
+{
+       return texture.gatherOffsets(sampler, coord.x(), coord.y(), coord.z(), componentNdx, offsets).cast<ColorScalarType>();
+}
+
+template <typename ColorScalarType>
+static tcu::Vector<ColorScalarType, 4> gatherOffsets (const tcu::TextureCubeView& texture, const tcu::Sampler& sampler, const Vec3& coord, int componentNdx, const IVec2 (&offsets)[4])
+{
+       DE_ASSERT(isZeroOffsetOffsets(offsets));
+       DE_UNREF(offsets);
+       return texture.gather(sampler, coord.x(), coord.y(), coord.z(), componentNdx).cast<ColorScalarType>();
+}
+
+static Vec4 gatherOffsetsCompare (const tcu::Texture2DView& texture, const tcu::Sampler& sampler, float refZ, const Vec2& coord, const IVec2 (&offsets)[4])
+{
+       return texture.gatherOffsetsCompare(sampler, refZ, coord.x(), coord.y(), offsets);
+}
+
+static Vec4 gatherOffsetsCompare (const tcu::Texture2DArrayView& texture, const tcu::Sampler& sampler, float refZ, const Vec3& coord, const IVec2 (&offsets)[4])
+{
+       return texture.gatherOffsetsCompare(sampler, refZ, coord.x(), coord.y(), coord.z(), offsets);
+}
+
+static Vec4 gatherOffsetsCompare (const tcu::TextureCubeView& texture, const tcu::Sampler& sampler, float refZ, const Vec3& coord, const IVec2 (&offsets)[4])
+{
+       DE_ASSERT(isZeroOffsetOffsets(offsets));
+       DE_UNREF(offsets);
+       return texture.gatherCompare(sampler, refZ, coord.x(), coord.y(), coord.z());
+}
+
+template <typename PrecType, typename ColorScalarT>
+static bool isGatherOffsetsResultValid (const tcu::TextureCubeView&                            texture,
+                                                                               const tcu::Sampler&                                             sampler,
+                                                                               const PrecType&                                                 prec,
+                                                                               const Vec3&                                                             coord,
+                                                                               int                                                                             componentNdx,
+                                                                               const IVec2                                                             (&offsets)[4],
+                                                                               const tcu::Vector<ColorScalarT, 4>&             result)
+{
+       DE_ASSERT(isZeroOffsetOffsets(offsets));
+       DE_UNREF(offsets);
+       return tcu::isGatherResultValid(texture, sampler, prec, coord, componentNdx, result);
+}
+
+static bool isGatherOffsetsCompareResultValid (const tcu::TextureCubeView&             texture,
+                                                                                          const tcu::Sampler&                          sampler,
+                                                                                          const tcu::TexComparePrecision&      prec,
+                                                                                          const Vec3&                                          coord,
+                                                                                          const IVec2                                          (&offsets)[4],
+                                                                                          float                                                        cmpReference,
+                                                                                          const Vec4&                                          result)
+{
+       DE_ASSERT(isZeroOffsetOffsets(offsets));
+       DE_UNREF(offsets);
+       return tcu::isGatherCompareResultValid(texture, sampler, prec, coord, cmpReference, result);
+}
+
+template <typename ColorScalarType, typename PrecType, typename TexViewT, typename TexCoordT>
+static bool verifyGatherOffsets (TestLog&                                              log,
+                                                                const ConstPixelBufferAccess&  result,
+                                                                const TexViewT&                                texture,
+                                                                const TexCoordT                                (&texCoords)[4],
+                                                                const tcu::Sampler&                    sampler,
+                                                                const PrecType&                                lookupPrec,
+                                                                int                                                    componentNdx,
+                                                                const PixelOffsets&                    getPixelOffsets)
+{
+       typedef tcu::Vector<ColorScalarType, 4> ColorVec;
+
+       const int                                       width                   = result.getWidth();
+       const int                                       height                  = result.getWidth();
+       tcu::TextureLevel                       ideal                   (result.getFormat(), width, height);
+       const PixelBufferAccess         idealAccess             = ideal.getAccess();
+       tcu::Surface                            errorMask               (width, height);
+       bool                                            success                 = true;
+
+       tcu::clear(errorMask.getAccess(), tcu::RGBA::green().toVec());
+
+       for (int py = 0; py < height; py++)
+       for (int px = 0; px < width; px++)
+       {
+               IVec2           offsets[4];
+               getPixelOffsets(IVec2(px, py), offsets);
+
+               const Vec2                      viewportCoord   = (Vec2((float)px, (float)py) + 0.5f) / Vec2((float)width, (float)height);
+               const TexCoordT         texCoord                = triQuadInterpolate(texCoords, viewportCoord.x(), viewportCoord.y());
+               const ColorVec          resultPix               = result.getPixelT<ColorScalarType>(px, py);
+               const ColorVec          idealPix                = gatherOffsets<ColorScalarType>(texture, sampler, texCoord, componentNdx, offsets);
+
+               idealAccess.setPixel(idealPix, px, py);
+
+               if (tcu::boolAny(tcu::logicalAnd(lookupPrec.colorMask,
+                                                                                tcu::greaterThan(tcu::absDiff(resultPix, idealPix),
+                                                                                                                 lookupPrec.colorThreshold.template cast<ColorScalarType>()))))
+               {
+                       if (!isGatherOffsetsResultValid(texture, sampler, lookupPrec, texCoord, componentNdx, offsets, resultPix))
+                       {
+                               errorMask.setPixel(px, py, tcu::RGBA::red());
+                               success = false;
+                       }
+               }
+       }
+
+       log << TestLog::ImageSet("VerifyResult", "Verification result")
+               << TestLog::Image("Rendered", "Rendered image", result);
+
+       if (!success)
+       {
+               log << TestLog::Image("Reference", "Ideal reference image", ideal)
+                       << TestLog::Image("ErrorMask", "Error mask", errorMask);
+       }
+
+       log << TestLog::EndImageSet;
+
+       return success;
+}
+
+class PixelCompareRefZ
+{
+public:
+       virtual float operator() (const IVec2& pixCoord) const = 0;
+};
+
+class PixelCompareRefZDefault : public PixelCompareRefZ
+{
+public:
+       PixelCompareRefZDefault (const IVec2& renderSize) : m_renderSize(renderSize) {}
+
+       float operator() (const IVec2& pixCoord) const
+       {
+               return ((float)pixCoord.x() + 0.5f) / (float)m_renderSize.x();
+       }
+
+private:
+       IVec2 m_renderSize;
+};
+
+template <typename TexViewT, typename TexCoordT>
+static bool verifyGatherOffsetsCompare (TestLog&                                                       log,
+                                                                               const ConstPixelBufferAccess&           result,
+                                                                               const TexViewT&                                         texture,
+                                                                               const TexCoordT                                         (&texCoords)[4],
+                                                                               const tcu::Sampler&                                     sampler,
+                                                                               const tcu::TexComparePrecision&         compPrec,
+                                                                               const PixelCompareRefZ&                         getPixelRefZ,
+                                                                               const PixelOffsets&                                     getPixelOffsets)
+{
+       const int                                       width                   = result.getWidth();
+       const int                                       height                  = result.getWidth();
+       tcu::Surface                            ideal                   (width, height);
+       const PixelBufferAccess         idealAccess             = ideal.getAccess();
+       tcu::Surface                            errorMask               (width, height);
+       bool                                            success                 = true;
+
+       tcu::clear(errorMask.getAccess(), tcu::RGBA::green().toVec());
+
+       for (int py = 0; py < height; py++)
+       for (int px = 0; px < width; px++)
+       {
+               IVec2           offsets[4];
+               getPixelOffsets(IVec2(px, py), offsets);
+
+               const Vec2                      viewportCoord   = (Vec2((float)px, (float)py) + 0.5f) / Vec2((float)width, (float)height);
+               const TexCoordT         texCoord                = triQuadInterpolate(texCoords, viewportCoord.x(), viewportCoord.y());
+               const float                     refZ                    = getPixelRefZ(IVec2(px, py));
+               const Vec4                      resultPix               = result.getPixel(px, py);
+               const Vec4                      idealPix                = gatherOffsetsCompare(texture, sampler, refZ, texCoord, offsets);
+
+               idealAccess.setPixel(idealPix, px, py);
+
+               if (!tcu::boolAll(tcu::equal(resultPix, idealPix)))
+               {
+                       if (!isGatherOffsetsCompareResultValid(texture, sampler, compPrec, texCoord, offsets, refZ, resultPix))
+                       {
+                               errorMask.setPixel(px, py, tcu::RGBA::red());
+                               success = false;
+                       }
+               }
+       }
+
+       log << TestLog::ImageSet("VerifyResult", "Verification result")
+               << TestLog::Image("Rendered", "Rendered image", result);
+
+       if (!success)
+       {
+               log << TestLog::Image("Reference", "Ideal reference image", ideal)
+                       << TestLog::Image("ErrorMask", "Error mask", errorMask);
+       }
+
+       log << TestLog::EndImageSet;
+
+       return success;
+}
+
+enum GatherType
+{
+       GATHERTYPE_BASIC = 0,
+       GATHERTYPE_OFFSET,
+       GATHERTYPE_OFFSET_DYNAMIC,
+       GATHERTYPE_OFFSETS,
+
+       GATHERTYPE_LAST
+};
+
+enum GatherCaseFlags
+{
+       GATHERCASE_DONT_SAMPLE_CUBE_CORNERS     = (1<<0)        //!< For cube map cases: do not sample cube corners
+};
+
+enum OffsetSize
+{
+       OFFSETSIZE_NONE = 0,
+       OFFSETSIZE_MINIMUM_REQUIRED,
+       OFFSETSIZE_IMPLEMENTATION_MAXIMUM,
+
+       OFFSETSIZE_LAST
+};
+
+static inline const char* gatherTypeName (GatherType type)
+{
+       switch (type)
+       {
+               case GATHERTYPE_BASIC:                          return "basic";
+               case GATHERTYPE_OFFSET:                         return "offset";
+               case GATHERTYPE_OFFSET_DYNAMIC:         return "offset_dynamic";
+               case GATHERTYPE_OFFSETS:                        return "offsets";
+               default: DE_ASSERT(false); return DE_NULL;
+       }
+}
+
+static inline const char* gatherTypeDescription (GatherType type)
+{
+       switch (type)
+       {
+               case GATHERTYPE_BASIC:                          return "textureGather";
+               case GATHERTYPE_OFFSET:                         return "textureGatherOffset";
+               case GATHERTYPE_OFFSET_DYNAMIC:         return "textureGatherOffset with dynamic offsets";
+               case GATHERTYPE_OFFSETS:                        return "textureGatherOffsets";
+               default: DE_ASSERT(false); return DE_NULL;
+       }
+}
+
+static inline bool requireGpuShader5 (GatherType gatherType, OffsetSize offsetSize)
+{
+       return gatherType == GATHERTYPE_OFFSET_DYNAMIC || gatherType == GATHERTYPE_OFFSETS
+               || offsetSize == OFFSETSIZE_IMPLEMENTATION_MAXIMUM; // \note Implementation limits are not available while generating the shaders, they are passed dynamically at runtime
+}
+
+struct GatherArgs
+{
+       int             componentNdx;   // If negative, implicit component index 0 is used (i.e. the parameter is not given).
+       IVec2   offsets[4];             // \note Unless GATHERTYPE_OFFSETS is used, only offsets[0] is relevant; also, for GATHERTYPE_OFFSET_DYNAMIC, none are relevant.
+
+       GatherArgs (void)
+               : componentNdx(-1)
+       {
+               std::fill(DE_ARRAY_BEGIN(offsets), DE_ARRAY_END(offsets), IVec2());
+       }
+
+       GatherArgs (int comp,
+                               const IVec2& off0 = IVec2(),
+                               const IVec2& off1 = IVec2(),
+                               const IVec2& off2 = IVec2(),
+                               const IVec2& off3 = IVec2())
+               : componentNdx(comp)
+       {
+               offsets[0] = off0;
+               offsets[1] = off1;
+               offsets[2] = off2;
+               offsets[3] = off3;
+       }
+};
+
+static MovePtr<PixelOffsets> makePixelOffsetsFunctor (GatherType gatherType, const GatherArgs& gatherArgs, const IVec2& offsetRange)
+{
+       if (gatherType == GATHERTYPE_BASIC || gatherType == GATHERTYPE_OFFSET)
+       {
+               const IVec2 offset = gatherType == GATHERTYPE_BASIC ? IVec2(0) : gatherArgs.offsets[0];
+               return MovePtr<PixelOffsets>(new SinglePixelOffsets(offset));
+       }
+       else if (gatherType == GATHERTYPE_OFFSET_DYNAMIC)
+       {
+               return MovePtr<PixelOffsets>(new DynamicSinglePixelOffsets(offsetRange));
+       }
+       else if (gatherType == GATHERTYPE_OFFSETS)
+               return MovePtr<PixelOffsets>(new MultiplePixelOffsets(gatherArgs.offsets[0],
+                                                                                                                         gatherArgs.offsets[1],
+                                                                                                                         gatherArgs.offsets[2],
+                                                                                                                         gatherArgs.offsets[3]));
+       else
+       {
+               DE_ASSERT(false);
+               return MovePtr<PixelOffsets>(DE_NULL);
+       }
+}
+
+static inline glu::DataType getSamplerType (TextureType textureType, const tcu::TextureFormat& format)
+{
+       if (isDepthFormat(format))
+       {
+               switch (textureType)
+               {
+                       case TEXTURETYPE_2D:            return glu::TYPE_SAMPLER_2D_SHADOW;
+                       case TEXTURETYPE_2D_ARRAY:      return glu::TYPE_SAMPLER_2D_ARRAY_SHADOW;
+                       case TEXTURETYPE_CUBE:          return glu::TYPE_SAMPLER_CUBE_SHADOW;
+                       default: DE_ASSERT(false); return glu::TYPE_LAST;
+               }
+       }
+       else
+       {
+               switch (textureType)
+               {
+                       case TEXTURETYPE_2D:            return glu::getSampler2DType(format);
+                       case TEXTURETYPE_2D_ARRAY:      return glu::getSampler2DArrayType(format);
+                       case TEXTURETYPE_CUBE:          return glu::getSamplerCubeType(format);
+                       default: DE_ASSERT(false); return glu::TYPE_LAST;
+               }
+       }
+}
+
+static inline glu::DataType getSamplerGatherResultType (glu::DataType samplerType)
+{
+       switch (samplerType)
+       {
+               case glu::TYPE_SAMPLER_2D_SHADOW:
+               case glu::TYPE_SAMPLER_2D_ARRAY_SHADOW:
+               case glu::TYPE_SAMPLER_CUBE_SHADOW:
+               case glu::TYPE_SAMPLER_2D:
+               case glu::TYPE_SAMPLER_2D_ARRAY:
+               case glu::TYPE_SAMPLER_CUBE:
+                       return glu::TYPE_FLOAT_VEC4;
+
+               case glu::TYPE_INT_SAMPLER_2D:
+               case glu::TYPE_INT_SAMPLER_2D_ARRAY:
+               case glu::TYPE_INT_SAMPLER_CUBE:
+                       return glu::TYPE_INT_VEC4;
+
+               case glu::TYPE_UINT_SAMPLER_2D:
+               case glu::TYPE_UINT_SAMPLER_2D_ARRAY:
+               case glu::TYPE_UINT_SAMPLER_CUBE:
+                       return glu::TYPE_UINT_VEC4;
+
+               default:
+                       DE_ASSERT(false);
+                       return glu::TYPE_LAST;
+       }
+}
+
+static inline int getNumTextureSamplingDimensions (TextureType type)
+{
+       switch (type)
+       {
+               case TEXTURETYPE_2D:            return 2;
+               case TEXTURETYPE_2D_ARRAY:      return 3;
+               case TEXTURETYPE_CUBE:          return 3;
+               default: DE_ASSERT(false); return -1;
+       }
+}
+
+vector<GatherArgs> generateBasic2DCaseIterations (GatherType gatherType, const tcu::TextureFormat& textureFormat, const IVec2& offsetRange)
+{
+       const int                       numComponentCases       = isDepthFormat(textureFormat) ? 1 : 4+1; // \note For non-depth textures, test explicit components 0 to 3 and implicit component 0.
+       vector<GatherArgs>      result;
+
+       for (int componentCaseNdx = 0; componentCaseNdx < numComponentCases; componentCaseNdx++)
+       {
+               const int componentNdx = componentCaseNdx - 1;
+
+               switch (gatherType)
+               {
+                       case GATHERTYPE_BASIC:
+                               result.push_back(GatherArgs(componentNdx));
+                               break;
+
+                       case GATHERTYPE_OFFSET:
+                       {
+                               const int min   = offsetRange.x();
+                               const int max   = offsetRange.y();
+                               const int hmin  = divRoundToZero(min, 2);
+                               const int hmax  = divRoundToZero(max, 2);
+
+                               result.push_back(GatherArgs(componentNdx, IVec2(min, max)));
+
+                               if (componentCaseNdx == 0) // Don't test all offsets variants for all color components (they should be pretty orthogonal).
+                               {
+                                       result.push_back(GatherArgs(componentNdx, IVec2(min,    min)));
+                                       result.push_back(GatherArgs(componentNdx, IVec2(max,    min)));
+                                       result.push_back(GatherArgs(componentNdx, IVec2(max,    max)));
+
+                                       result.push_back(GatherArgs(componentNdx, IVec2(0,              hmax)));
+                                       result.push_back(GatherArgs(componentNdx, IVec2(hmin,   0)));
+                                       result.push_back(GatherArgs(componentNdx, IVec2(0,              0)));
+                               }
+
+                               break;
+                       }
+
+                       case GATHERTYPE_OFFSET_DYNAMIC:
+                               result.push_back(GatherArgs(componentNdx));
+                               break;
+
+                       case GATHERTYPE_OFFSETS:
+                       {
+                               const int min   = offsetRange.x();
+                               const int max   = offsetRange.y();
+                               const int hmin  = divRoundToZero(min, 2);
+                               const int hmax  = divRoundToZero(max, 2);
+
+                               result.push_back(GatherArgs(componentNdx,
+                                                                                       IVec2(min,      min),
+                                                                                       IVec2(min,      max),
+                                                                                       IVec2(max,      min),
+                                                                                       IVec2(max,      max)));
+
+                               if (componentCaseNdx == 0) // Don't test all offsets variants for all color components (they should be pretty orthogonal).
+                                       result.push_back(GatherArgs(componentNdx,
+                                                                                               IVec2(min,      hmax),
+                                                                                               IVec2(hmin,     max),
+                                                                                               IVec2(0,        hmax),
+                                                                                               IVec2(hmax,     0)));
+                               break;
+                       }
+
+                       default:
+                               DE_ASSERT(false);
+               }
+       }
+
+       return result;
+}
+
+class TextureGatherBase
+{
+public:
+                                                                               TextureGatherBase                       (const TextureType                                      textureType,
+                                                                                                                                        const GatherType                                       gatherType,
+                                                                                                                                        const OffsetSize                                       offsetSize,
+                                                                                                                                        const tcu::TextureFormat                       textureFormat,
+                                                                                                                                        const tcu::Sampler::CompareMode        shadowCompareMode, //!< Should be COMPAREMODE_NONE if textureFormat is a depth format.
+                                                                                                                                        const tcu::Sampler::WrapMode           wrapS,
+                                                                                                                                        const tcu::Sampler::WrapMode           wrapT,
+                                                                                                                                        const MaybeTextureSwizzle&                     textureSwizzle,
+                                                                                                                                        // \note Filter modes have no effect on gather (except when it comes to
+                                                                                                                                        //               texture completeness); these are supposed to test just that.
+                                                                                                                                        const tcu::Sampler::FilterMode         minFilter,
+                                                                                                                                        const tcu::Sampler::FilterMode         magFilter,
+                                                                                                                                        const int                                                      baseLevel,
+                                                                                                                                        const deUint32                                         flags);
+       virtual                                                         ~TextureGatherBase                      (void);
+
+protected:
+       virtual IVec2                                           getOffsetRange                          (void) const = 0;
+       virtual void                                            generateIterations                      (void) = 0;
+       virtual int                                                     getNumIterations                        (void) const = 0;
+       virtual GatherArgs                                      getGatherArgs                           (int iterationNdx) const = 0;
+
+protected:
+       const GatherType                                        m_gatherType;
+       const OffsetSize                                        m_offsetSize;
+       const tcu::TextureFormat                        m_textureFormat;
+       const tcu::Sampler::CompareMode         m_shadowCompareMode;
+       const tcu::Sampler::WrapMode            m_wrapS;
+       const tcu::Sampler::WrapMode            m_wrapT;
+       const MaybeTextureSwizzle                       m_textureSwizzle;
+       const tcu::Sampler::FilterMode          m_minFilter;
+       const tcu::Sampler::FilterMode          m_magFilter;
+       const int                                                       m_baseLevel;
+       const deUint32                                          m_flags;
+       const TextureType                                       m_textureType;
+
+       enum
+       {
+               SPEC_MAX_MIN_OFFSET = -8,
+               SPEC_MIN_MAX_OFFSET = 7
+       };
+};
+
+TextureGatherBase::TextureGatherBase (const TextureType                                                textureType,
+                                                                         const GatherType                                              gatherType,
+                                                                         const OffsetSize                                              offsetSize,
+                                                                         const tcu::TextureFormat                              textureFormat,
+                                                                         const tcu::Sampler::CompareMode               shadowCompareMode,
+                                                                         const tcu::Sampler::WrapMode                  wrapS,
+                                                                         const tcu::Sampler::WrapMode                  wrapT,
+                                                                         const MaybeTextureSwizzle&                    textureSwizzle,
+                                                                         const tcu::Sampler::FilterMode                minFilter,
+                                                                         const tcu::Sampler::FilterMode                magFilter,
+                                                                         const int                                                             baseLevel,
+                                                                         const deUint32                                                flags)
+       : m_gatherType                          (gatherType)
+       , m_offsetSize                          (offsetSize)
+       , m_textureFormat                       (textureFormat)
+       , m_shadowCompareMode           (shadowCompareMode)
+       , m_wrapS                                       (wrapS)
+       , m_wrapT                                       (wrapT)
+       , m_textureSwizzle                      (textureSwizzle)
+       , m_minFilter                           (minFilter)
+       , m_magFilter                           (magFilter)
+       , m_baseLevel                           (baseLevel)
+       , m_flags                                       (flags)
+       , m_textureType                         (textureType)
+{
+}
+
+TextureGatherBase::~TextureGatherBase (void)
+{
+}
+
+class TextureGatherInstance : public virtual TextureGatherBase, public ShaderRenderCaseInstance
+{
+public:
+                                                                               TextureGatherInstance           (Context&                                                       context,
+                                                                                                                                        const TextureType                                      textureType,
+                                                                                                                                        const GatherType                                       gatherType,
+                                                                                                                                        const OffsetSize                                       offsetSize,
+                                                                                                                                        const tcu::TextureFormat                       textureFormat,
+                                                                                                                                        const tcu::Sampler::CompareMode        shadowCompareMode,
+                                                                                                                                        const tcu::Sampler::WrapMode           wrapS,
+                                                                                                                                        const tcu::Sampler::WrapMode           wrapT,
+                                                                                                                                        const MaybeTextureSwizzle&                     textureSwizzle,
+                                                                                                                                        const tcu::Sampler::FilterMode         minFilter,
+                                                                                                                                        const tcu::Sampler::FilterMode         magFilter,
+                                                                                                                                        const int                                                      baseLevel,
+                                                                                                                                        const deUint32                                         flags);
+       virtual                                                         ~TextureGatherInstance          (void);
+
+       virtual tcu::TestStatus                         iterate                                         (void);
+
+protected:
+       virtual void                                            setupDefaultInputs                      (void);
+       virtual void                                            setupUniforms                           (const tcu::Vec4&);
+
+       void                                                            init                                            (void);
+       virtual IVec2                                           getOffsetRange                          (void) const;
+
+       template <typename TexViewT, typename TexCoordT>
+       bool                                                            verify                                          (const ConstPixelBufferAccess&          rendered,
+                                                                                                                                        const TexViewT&                                        texture,
+                                                                                                                                        const TexCoordT                                        (&bottomLeft)[4],
+                                                                                                                                        const GatherArgs&                                      gatherArgs) const;
+
+       virtual TextureBindingSp                        createTexture                           (void) = 0;
+       virtual vector<float>                           computeQuadTexCoord                     (int iterationNdx) const = 0;
+       virtual bool                                            verify                                          (int iterationNdx, const ConstPixelBufferAccess& rendered) const = 0;
+
+protected:
+       static const IVec2                                      RENDER_SIZE;
+
+private:
+       const tcu::TextureFormat                        m_colorBufferFormat;
+       int                                                                     m_currentIteration;
+};
+
+const IVec2 TextureGatherInstance::RENDER_SIZE = IVec2(64, 64);
+
+TextureGatherInstance::TextureGatherInstance (Context&                                                         context,
+                                                                                         const TextureType                                             textureType,
+                                                                                         const GatherType                                              gatherType,
+                                                                                         const OffsetSize                                              offsetSize,
+                                                                                         const tcu::TextureFormat                              textureFormat,
+                                                                                         const tcu::Sampler::CompareMode               shadowCompareMode,
+                                                                                         const tcu::Sampler::WrapMode                  wrapS,
+                                                                                         const tcu::Sampler::WrapMode                  wrapT,
+                                                                                         const MaybeTextureSwizzle&                    textureSwizzle,
+                                                                                         const tcu::Sampler::FilterMode                minFilter,
+                                                                                         const tcu::Sampler::FilterMode                magFilter,
+                                                                                         const int                                                             baseLevel,
+                                                                                         const deUint32                                                flags)
+       : TextureGatherBase                     (textureType, gatherType, offsetSize, textureFormat, shadowCompareMode, wrapS, wrapT, textureSwizzle, minFilter, magFilter, baseLevel, flags)
+       , ShaderRenderCaseInstance      (context, false, DE_NULL, DE_NULL, DE_NULL)
+       , m_colorBufferFormat           (tcu::TextureFormat(tcu::TextureFormat::RGBA,
+                                                                                                       isDepthFormat(textureFormat) ? tcu::TextureFormat::UNORM_INT8 : textureFormat.type))
+       , m_currentIteration            (0)
+{
+       DE_ASSERT((m_gatherType == GATHERTYPE_BASIC) == (m_offsetSize == OFFSETSIZE_NONE));
+       DE_ASSERT((m_shadowCompareMode != tcu::Sampler::COMPAREMODE_NONE) == isDepthFormat(m_textureFormat));
+       DE_ASSERT(isUnormFormatType(m_colorBufferFormat.type)                                           ||
+                         m_colorBufferFormat.type == tcu::TextureFormat::UNSIGNED_INT8         ||
+                         m_colorBufferFormat.type == tcu::TextureFormat::UNSIGNED_INT16        ||
+                         m_colorBufferFormat.type == tcu::TextureFormat::SIGNED_INT8           ||
+                         m_colorBufferFormat.type == tcu::TextureFormat::SIGNED_INT16);
+       DE_ASSERT(glu::isGLInternalColorFormatFilterable(glu::getInternalFormat(m_colorBufferFormat)) ||
+                         (m_magFilter == tcu::Sampler::NEAREST && (m_minFilter == tcu::Sampler::NEAREST || m_minFilter == tcu::Sampler::NEAREST_MIPMAP_NEAREST)));
+       DE_ASSERT(m_textureType == TEXTURETYPE_CUBE || !(m_flags & GATHERCASE_DONT_SAMPLE_CUBE_CORNERS));
+
+       m_renderSize                            = RENDER_SIZE.asUint();
+       m_colorFormat                           = vk::mapTextureFormat(m_colorBufferFormat);
+}
+
+TextureGatherInstance::~TextureGatherInstance (void)
+{
+}
+
+void TextureGatherInstance::init (void)
+{
+       TestLog&                                                log                                     = m_context.getTestContext().getLog();
+       TextureBindingSp                                textureBinding;
+       TextureBinding::Parameters              textureParams;
+
+       // Check prerequisites.
+       if (requireGpuShader5(m_gatherType, m_offsetSize))
+       {
+               const vk::VkPhysicalDeviceFeatures&             deviceFeatures  = m_context.getDeviceFeatures();
+               if (!deviceFeatures.shaderImageGatherExtended)
+                       TCU_THROW(NotSupportedError, "Extended set of image gather instructions are not supported");
+       }
+
+       // Log and check implementation offset limits, if appropriate.
+       if (m_offsetSize == OFFSETSIZE_IMPLEMENTATION_MAXIMUM)
+       {
+               const IVec2             offsetRange             = getOffsetRange();
+               log << TestLog::Integer("ImplementationMinTextureGatherOffset", "Implementation's value for minTexelGatherOffset", "", QP_KEY_TAG_NONE, offsetRange[0])
+                       << TestLog::Integer("ImplementationMaxTextureGatherOffset", "Implementation's value for maxTexelGatherOffset", "", QP_KEY_TAG_NONE, offsetRange[1]);
+               TCU_CHECK_MSG(offsetRange[0] <= SPEC_MAX_MIN_OFFSET, ("minTexelGatherOffset must be at most " + de::toString((int)SPEC_MAX_MIN_OFFSET)).c_str());
+               TCU_CHECK_MSG(offsetRange[1] >= SPEC_MIN_MAX_OFFSET, ("maxTexelGatherOffset must be at least " + de::toString((int)SPEC_MIN_MAX_OFFSET)).c_str());
+       }
+
+       // Generate subclass-specific iterations.
+
+       generateIterations();
+
+       // Initialize texture.
+
+       textureBinding = createTexture();
+
+       if (m_textureSwizzle.isSome())
+       {
+               const tcu::Vector<TextureSwizzleComponent, 4>&  swizzle         = m_textureSwizzle.getSwizzle();
+
+               const vk::VkComponentMapping                                    components      =
+               {
+                       getTextureSwizzleComponent(swizzle[0]),
+                       getTextureSwizzleComponent(swizzle[1]),
+                       getTextureSwizzleComponent(swizzle[2]),
+                       getTextureSwizzleComponent(swizzle[3])
+               };
+
+               textureParams.componentMapping = components;
+       }
+
+       if (m_baseLevel != 0)
+               textureParams.baseMipLevel = m_baseLevel;
+
+       textureBinding->setParameters(textureParams);
+       m_textures.push_back(textureBinding);
+
+       log << TestLog::Message << "Texture base level is " << m_baseLevel << TestLog::EndMessage
+               << TestLog::Message << "s and t wrap modes are "
+                                                       << vk::mapWrapMode(m_wrapS) << " and "
+                                                       << vk::mapWrapMode(m_wrapT) << ", respectively" << TestLog::EndMessage
+               << TestLog::Message << "Minification and magnification filter modes are "
+                                                       << vk::mapFilterMode(m_minFilter) << " and "
+                                                       << vk::mapFilterMode(m_magFilter) << ", respectively "
+                                                       << "(note that they should have no effect on gather result)"
+                                                       << TestLog::EndMessage
+               << TestLog::Message << "Using texture swizzle " << m_textureSwizzle << TestLog::EndMessage;
+
+       if (m_shadowCompareMode != tcu::Sampler::COMPAREMODE_NONE)
+               log << TestLog::Message << "Using texture compare func " << vk::mapCompareMode(m_shadowCompareMode) << TestLog::EndMessage;
+}
+
+IVec2 TextureGatherInstance::getOffsetRange (void) const
+{
+       switch (m_offsetSize)
+       {
+               case OFFSETSIZE_NONE:
+                       return IVec2(0);
+
+               case OFFSETSIZE_MINIMUM_REQUIRED:
+                       // \note Defined by spec.
+                       return IVec2(SPEC_MAX_MIN_OFFSET,
+                                                SPEC_MIN_MAX_OFFSET);
+
+               case OFFSETSIZE_IMPLEMENTATION_MAXIMUM:
+               {
+                       const vk::VkPhysicalDeviceLimits&       limits  = m_context.getDeviceProperties().limits;
+                       return IVec2(limits.minTexelGatherOffset, limits.maxTexelGatherOffset);
+               }
+
+               default:
+                       DE_ASSERT(false);
+                       return IVec2(-1);
+       }
+}
+
+void TextureGatherInstance::setupDefaultInputs (void)
+{
+       const int                               numVertices                                             = 4;
+       const float                             position[4*2]                                   =
+       {
+               -1.0f, -1.0f,
+               -1.0f, +1.0f,
+               +1.0f, -1.0f,
+               +1.0f, +1.0f,
+       };
+       const float                             normalizedCoord[4*2]                    =
+       {
+               0.0f, 0.0f,
+               0.0f, 1.0f,
+               1.0f, 0.0f,
+               1.0f, 1.0f,
+       };
+       const vector<float>             texCoord                                                = computeQuadTexCoord(m_currentIteration);
+       const bool                              needNormalizedCoordInShader             = m_gatherType == GATHERTYPE_OFFSET_DYNAMIC || isDepthFormat(m_textureFormat);
+
+       addAttribute(0u, vk::VK_FORMAT_R32G32_SFLOAT, 2 * sizeof(float), numVertices, position);
+
+       if (texCoord.size() == 2*4)
+               addAttribute(1u, vk::VK_FORMAT_R32G32_SFLOAT, 2 * sizeof(float), numVertices, texCoord.data());
+       else if (texCoord.size() == 3*4)
+               addAttribute(1u, vk::VK_FORMAT_R32G32B32_SFLOAT, 3 * sizeof(float), numVertices, texCoord.data());
+       else
+               DE_ASSERT(false);
+
+       if (needNormalizedCoordInShader)
+               addAttribute(2u, vk::VK_FORMAT_R32G32_SFLOAT, 2 * sizeof(float), numVertices, normalizedCoord);
+}
+
+tcu::TestStatus TextureGatherInstance::iterate (void)
+{
+       TestLog&                                                log                                             = m_context.getTestContext().getLog();
+       const tcu::ScopedLogSection             iterationSection                (log, "Iteration" + de::toString(m_currentIteration), "Iteration " + de::toString(m_currentIteration));
+
+       // Render.
+
+       {
+               const deUint32                          numVertices             = 4;
+               const deUint32                          numTriangles    = 2;
+               const deUint16                          indices[6]              = { 0, 1, 2, 2, 1, 3 };
+               const vector<float>                     texCoord                = computeQuadTexCoord(m_currentIteration);
+
+               if (texCoord.size() == 2*4)
+               {
+                       Vec2 texCoordVec[4];
+                       computeTexCoordVecs(texCoord, texCoordVec);
+                       log << TestLog::Message << "Texture coordinates run from " << texCoordVec[0] << " to " << texCoordVec[3] << TestLog::EndMessage;
+               }
+               else if (texCoord.size() == 3*4)
+               {
+                       Vec3 texCoordVec[4];
+                       computeTexCoordVecs(texCoord, texCoordVec);
+                       log << TestLog::Message << "Texture coordinates run from " << texCoordVec[0] << " to " << texCoordVec[3] << TestLog::EndMessage;
+               }
+               else
+                       DE_ASSERT(false);
+
+               m_vertexShaderName              = "vert";
+               m_fragmentShaderName    = "frag_" + de::toString(m_currentIteration);
+
+               setup();
+
+               render(numVertices, numTriangles, indices);
+       }
+
+       // Verify result.
+
+       if (!verify(m_currentIteration, getResultImage().getAccess()))
+               return tcu::TestStatus::fail("Result verification failed");
+
+       m_currentIteration++;
+       if (m_currentIteration == getNumIterations())
+               return tcu::TestStatus::pass("Pass");
+       else
+               return tcu::TestStatus::incomplete();
+}
+
+void TextureGatherInstance::setupUniforms (const tcu::Vec4&)
+{
+       deUint32        binding         = 0;
+
+       useSampler(binding++, 0u);
+
+       if (m_gatherType == GATHERTYPE_OFFSET_DYNAMIC)
+               addUniform(binding++, vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, sizeof(tcu::Vec2), RENDER_SIZE.asFloat().getPtr());
+
+       if (m_offsetSize == OFFSETSIZE_IMPLEMENTATION_MAXIMUM)
+       {
+               if (m_gatherType == GATHERTYPE_OFFSET)
+               {
+                       const GatherArgs&       gatherArgs              = getGatherArgs(m_currentIteration);
+                       addUniform(binding++, vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, sizeof(tcu::IVec2), gatherArgs.offsets[0].getPtr());
+               }
+               else if (m_gatherType == GATHERTYPE_OFFSET_DYNAMIC)
+               {
+                       const IVec2&            offsetRange             = getOffsetRange();
+                       addUniform(binding++, vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, sizeof(tcu::IVec2), offsetRange.getPtr());
+               }
+               else
+                       DE_ASSERT(false);
+       }
+}
+
+template <typename TexViewT, typename TexCoordT>
+bool TextureGatherInstance::verify (const ConstPixelBufferAccess&      rendered,
+                                                               const TexViewT&                                 texture,
+                                                               const TexCoordT                                 (&texCoords)[4],
+                                                               const GatherArgs&                               gatherArgs) const
+{
+       TestLog& log = m_context.getTestContext().getLog();
+
+       {
+               DE_ASSERT(m_colorBufferFormat.order == tcu::TextureFormat::RGBA);
+               DE_ASSERT(m_colorBufferFormat.type == tcu::TextureFormat::UNORM_INT8            ||
+                                 m_colorBufferFormat.type == tcu::TextureFormat::UNSIGNED_INT8         ||
+                                 m_colorBufferFormat.type == tcu::TextureFormat::SIGNED_INT8);
+
+               const MovePtr<PixelOffsets>             pixelOffsets    = makePixelOffsetsFunctor(m_gatherType, gatherArgs, getOffsetRange());
+               const tcu::PixelFormat                  pixelFormat             = tcu::PixelFormat(8,8,8,8);
+               const IVec4                                             colorBits               = tcu::max(TextureTestUtil::getBitsVec(pixelFormat) - 1, tcu::IVec4(0));
+               const IVec3                                             coordBits               = m_textureType == TEXTURETYPE_2D                       ? IVec3(20,20,0)
+                                                                                                               : m_textureType == TEXTURETYPE_CUBE                     ? IVec3(10,10,10)
+                                                                                                               : m_textureType == TEXTURETYPE_2D_ARRAY         ? IVec3(20,20,20)
+                                                                                                               : IVec3(-1);
+               const IVec3                                             uvwBits                 = m_textureType == TEXTURETYPE_2D                       ? IVec3(7,7,0)
+                                                                                                               : m_textureType == TEXTURETYPE_CUBE                     ? IVec3(6,6,0)
+                                                                                                               : m_textureType == TEXTURETYPE_2D_ARRAY         ? IVec3(7,7,7)
+                                                                                                               : IVec3(-1);
+               tcu::Sampler                                    sampler;
+               sampler.wrapS           = m_wrapS;
+               sampler.wrapT           = m_wrapT;
+               sampler.compare         = m_shadowCompareMode;
+
+               if (isDepthFormat(m_textureFormat))
+               {
+                       tcu::TexComparePrecision comparePrec;
+                       comparePrec.coordBits           = coordBits;
+                       comparePrec.uvwBits                     = uvwBits;
+                       comparePrec.referenceBits       = 16;
+                       comparePrec.resultBits          = pixelFormat.redBits-1;
+
+                       return verifyGatherOffsetsCompare(log, rendered, texture, texCoords, sampler, comparePrec, PixelCompareRefZDefault(RENDER_SIZE), *pixelOffsets);
+               }
+               else
+               {
+                       const int componentNdx = de::max(0, gatherArgs.componentNdx);
+
+                       if (isUnormFormatType(m_textureFormat.type))
+                       {
+                               tcu::LookupPrecision lookupPrec;
+                               lookupPrec.colorThreshold       = tcu::computeFixedPointThreshold(colorBits);
+                               lookupPrec.coordBits            = coordBits;
+                               lookupPrec.uvwBits                      = uvwBits;
+                               lookupPrec.colorMask            = TextureTestUtil::getCompareMask(pixelFormat);
+                               return verifyGatherOffsets<float>(log, rendered, texture, texCoords, sampler, lookupPrec, componentNdx, *pixelOffsets);
+                       }
+                       else if (isUIntFormatType(m_textureFormat.type) || isSIntFormatType(m_textureFormat.type))
+                       {
+                               tcu::IntLookupPrecision         lookupPrec;
+                               lookupPrec.colorThreshold       = UVec4(0);
+                               lookupPrec.coordBits            = coordBits;
+                               lookupPrec.uvwBits                      = uvwBits;
+                               lookupPrec.colorMask            = TextureTestUtil::getCompareMask(pixelFormat);
+
+                               if (isUIntFormatType(m_textureFormat.type))
+                                       return verifyGatherOffsets<deUint32>(log, rendered, texture, texCoords, sampler, lookupPrec, componentNdx, *pixelOffsets);
+                               else if (isSIntFormatType(m_textureFormat.type))
+                                       return verifyGatherOffsets<deInt32>(log, rendered, texture, texCoords, sampler, lookupPrec, componentNdx, *pixelOffsets);
+                               else
+                               {
+                                       DE_ASSERT(false);
+                                       return false;
+                               }
+                       }
+                       else
+                       {
+                               DE_ASSERT(false);
+                               return false;
+                       }
+               }
+       }
+}
+
+class TextureGatherCase : public virtual TextureGatherBase, public TestCase
+{
+public:
+                                                                       TextureGatherCase                                       (tcu::TestContext&                                      testCtx,
+                                                                                                                                                const string&                                          name,
+                                                                                                                                                const string&                                          description,
+                                                                                                                                                const TextureType                                      textureType,
+                                                                                                                                                const GatherType                                       gatherType,
+                                                                                                                                                const OffsetSize                                       offsetSize,
+                                                                                                                                                const tcu::TextureFormat                       textureFormat,
+                                                                                                                                                const tcu::Sampler::CompareMode        shadowCompareMode,
+                                                                                                                                                const tcu::Sampler::WrapMode           wrapS,
+                                                                                                                                                const tcu::Sampler::WrapMode           wrapT,
+                                                                                                                                                const MaybeTextureSwizzle&                     textureSwizzle,
+                                                                                                                                                const tcu::Sampler::FilterMode         minFilter,
+                                                                                                                                                const tcu::Sampler::FilterMode         magFilter,
+                                                                                                                                                const int                                                      baseLevel,
+                                                                                                                                                const deUint32                                         flags);
+       virtual                                                 ~TextureGatherCase                                      (void);
+
+       virtual void                                    initPrograms                                            (vk::SourceCollections& programCollection) const;
+
+protected:
+       void                                                    init                                                            (void);
+       virtual IVec2                                   getOffsetRange                                          (void) const;
+
+private:
+       static glu::VertexSource                genVertexShaderSource                           (bool                                           requireGpuShader5,
+                                                                                                                                                int                                            numTexCoordComponents,
+                                                                                                                                                bool                                           useNormalizedCoordInput);
+       static glu::FragmentSource              genFragmentShaderSource                         (bool                                           requireGpuShader5,
+                                                                                                                                                int                                            numTexCoordComponents,
+                                                                                                                                                glu::DataType                          samplerType,
+                                                                                                                                                const string&                          funcCall,
+                                                                                                                                                bool                                           useNormalizedCoordInput,
+                                                                                                                                                bool                                           usePixCoord,
+                                                                                                                                                OffsetSize                                     offsetSize);
+       static string                                   genGatherFuncCall                                       (GatherType                                     gatherType,
+                                                                                                                                                const tcu::TextureFormat&      textureFormat,
+                                                                                                                                                const GatherArgs&                      gatherArgs,
+                                                                                                                                                const string&                          refZExpr,
+                                                                                                                                                const IVec2&                           offsetRange,
+                                                                                                                                                int                                            indentationDepth,
+                                                                                                                                                OffsetSize                                     offsetSize);
+};
+
+TextureGatherCase::TextureGatherCase (tcu::TestContext&                                        testCtx,
+                                                                         const string&                                         name,
+                                                                         const string&                                         description,
+                                                                         const TextureType                                     textureType,
+                                                                         const GatherType                                      gatherType,
+                                                                         const OffsetSize                                      offsetSize,
+                                                                         const tcu::TextureFormat                      textureFormat,
+                                                                         const tcu::Sampler::CompareMode       shadowCompareMode,
+                                                                         const tcu::Sampler::WrapMode          wrapS,
+                                                                         const tcu::Sampler::WrapMode          wrapT,
+                                                                         const MaybeTextureSwizzle&            textureSwizzle,
+                                                                         const tcu::Sampler::FilterMode        minFilter,
+                                                                         const tcu::Sampler::FilterMode        magFilter,
+                                                                         const int                                                     baseLevel,
+                                                                         const deUint32                                        flags)
+       : TextureGatherBase             (textureType, gatherType, offsetSize, textureFormat, shadowCompareMode, wrapS, wrapT, textureSwizzle, minFilter, magFilter, baseLevel, flags)
+       , TestCase                              (testCtx, name, description)
+{
+}
+
+TextureGatherCase::~TextureGatherCase (void)
+{
+}
+
+void TextureGatherCase::initPrograms (vk::SourceCollections& programCollection) const
+{
+       const int                                       numIterations           = getNumIterations();
+       const string                            refZExpr                        = "v_normalizedCoord.x";
+       const IVec2&                            offsetRange                     = getOffsetRange();
+       const bool                                      usePixCoord                     = m_gatherType == GATHERTYPE_OFFSET_DYNAMIC;
+       const bool                                      useNormalizedCoord      = usePixCoord || isDepthFormat(m_textureFormat);
+       const bool                                      isDynamicOffset         = m_gatherType == GATHERTYPE_OFFSET_DYNAMIC;
+       const bool                                      isShadow                        = isDepthFormat(m_textureFormat);
+       const glu::DataType                     samplerType                     = getSamplerType(m_textureType, m_textureFormat);
+       const int                                       numDims                         = getNumTextureSamplingDimensions(m_textureType);
+       glu::VertexSource                       vert                            = genVertexShaderSource(requireGpuShader5(m_gatherType, m_offsetSize), numDims, isDynamicOffset || isShadow);
+
+       programCollection.glslSources.add("vert") << vert;
+
+       for (int iterNdx = 0; iterNdx < numIterations; iterNdx++)
+       {
+               const GatherArgs&               gatherArgs                      = getGatherArgs(iterNdx);
+               const string                    funcCall                        = genGatherFuncCall(m_gatherType, m_textureFormat, gatherArgs, refZExpr, offsetRange, 1, m_offsetSize);
+               glu::FragmentSource             frag                            = genFragmentShaderSource(requireGpuShader5(m_gatherType, m_offsetSize), numDims, samplerType, funcCall, useNormalizedCoord, usePixCoord, m_offsetSize);
+
+               programCollection.glslSources.add("frag_" + de::toString(iterNdx)) << frag;
+       }
+}
+
+void TextureGatherCase::init (void)
+{
+       generateIterations();
+}
+
+IVec2 TextureGatherCase::getOffsetRange (void) const
+{
+       switch (m_offsetSize)
+       {
+               case OFFSETSIZE_NONE:
+                       return IVec2(0);
+
+               case OFFSETSIZE_MINIMUM_REQUIRED:
+                       // \note Defined by spec.
+                       return IVec2(SPEC_MAX_MIN_OFFSET,
+                                                SPEC_MIN_MAX_OFFSET);
+
+               case OFFSETSIZE_IMPLEMENTATION_MAXIMUM:
+                       // \note Limits are not available from here, uniform is used in the shader code instead.
+                       return IVec2(0);
+
+               default:
+                       DE_ASSERT(false);
+                       return IVec2(-1);
+       }
+}
+
+glu::VertexSource TextureGatherCase::genVertexShaderSource (bool requireGpuShader5, int numTexCoordComponents, bool useNormalizedCoordInput)
+{
+       DE_ASSERT(numTexCoordComponents == 2 || numTexCoordComponents == 3);
+
+       const string            texCoordType    = "vec" + de::toString(numTexCoordComponents);
+       std::ostringstream      vert;
+
+       vert << "#version 310 es\n";
+
+       if (requireGpuShader5)
+               vert << "#extension GL_EXT_gpu_shader5 : require\n";
+
+       vert << "\n"
+                       "layout (location = 0) in highp vec2 a_position;\n"
+                       "layout (location = 1) in highp " << texCoordType << " a_texCoord;\n";
+
+       if (useNormalizedCoordInput)
+               vert << "layout (location = 2) in highp vec2 a_normalizedCoord; // (0,0) to (1,1)\n";
+
+       vert << "\n"
+                       "layout (location = 0) out highp " << texCoordType << " v_texCoord;\n";
+
+       if (useNormalizedCoordInput)
+               vert << "layout (location = 1) out highp vec2 v_normalizedCoord;\n";
+
+       vert << "\n"
+                       "void main (void)\n"
+                       "{\n"
+                       "       gl_Position = vec4(a_position.x, a_position.y, 0.0, 1.0);\n"
+                       "       v_texCoord = a_texCoord;\n";
+
+       if (useNormalizedCoordInput)
+               vert << "       v_normalizedCoord = a_normalizedCoord;\n";
+
+       vert << "}\n";
+
+       return glu::VertexSource(vert.str());
+}
+
+glu::FragmentSource TextureGatherCase::genFragmentShaderSource (bool                   requireGpuShader5,
+                                                                                                                               int                             numTexCoordComponents,
+                                                                                                                               glu::DataType   samplerType,
+                                                                                                                               const string&   funcCall,
+                                                                                                                               bool                    useNormalizedCoordInput,
+                                                                                                                               bool                    usePixCoord,
+                                                                                                                               OffsetSize              offsetSize)
+{
+       DE_ASSERT(glu::isDataTypeSampler(samplerType));
+       DE_ASSERT(de::inRange(numTexCoordComponents, 2, 3));
+       DE_ASSERT(!usePixCoord || useNormalizedCoordInput);
+
+       const string            texCoordType    = "vec" + de::toString(numTexCoordComponents);
+       deUint32                        binding                 = 0;
+       std::ostringstream      frag;
+
+       frag << "#version 310 es\n";
+
+       if (requireGpuShader5)
+               frag << "#extension GL_EXT_gpu_shader5 : require\n";
+
+       frag << "\n"
+                       "layout (location = 0) out mediump " << glu::getDataTypeName(getSamplerGatherResultType(samplerType)) << " o_color;\n"
+                       "\n"
+                       "layout (location = 0) in highp " << texCoordType << " v_texCoord;\n";
+
+       if (useNormalizedCoordInput)
+               frag << "layout (location = 1) in highp vec2 v_normalizedCoord;\n";
+
+       frag << "\n"
+                       "layout (binding = " << binding++ << ") uniform highp " << glu::getDataTypeName(samplerType) << " u_sampler;\n";
+
+       if (usePixCoord)
+               frag << "layout (binding = " << binding++ << ") uniform viewportSize { highp vec2 u_viewportSize; };\n";
+
+       if (offsetSize == OFFSETSIZE_IMPLEMENTATION_MAXIMUM)
+               frag << "layout (binding = " << binding++ << ") uniform offset { highp ivec2 u_offset; };\n";
+
+       frag << "\n"
+                       "void main(void)\n"
+                       "{\n";
+
+       if (usePixCoord)
+               frag << "       ivec2 pixCoord = ivec2(v_normalizedCoord*u_viewportSize);\n";
+
+       frag << "       o_color = " << funcCall << ";\n"
+                       "}\n";
+
+       return glu::FragmentSource(frag.str());
+}
+
+string TextureGatherCase::genGatherFuncCall (GatherType                                                gatherType,
+                                                                                        const tcu::TextureFormat&              textureFormat,
+                                                                                        const GatherArgs&                              gatherArgs,
+                                                                                        const string&                                  refZExpr,
+                                                                                        const IVec2&                                   offsetRange,
+                                                                                        int                                                    indentationDepth,
+                                                                                        OffsetSize                                             offsetSize)
+{
+       string result;
+
+       switch (gatherType)
+       {
+               case GATHERTYPE_BASIC:
+                       result += "textureGather";
+                       break;
+               case GATHERTYPE_OFFSET: // \note Fallthrough.
+               case GATHERTYPE_OFFSET_DYNAMIC:
+                       result += "textureGatherOffset";
+                       break;
+               case GATHERTYPE_OFFSETS:
+                       result += "textureGatherOffsets";
+                       break;
+               default:
+                       DE_ASSERT(false);
+       }
+
+       result += "(u_sampler, v_texCoord";
+
+       if (isDepthFormat(textureFormat))
+       {
+               DE_ASSERT(gatherArgs.componentNdx < 0);
+               result += ", " + refZExpr;
+       }
+
+       if (gatherType == GATHERTYPE_OFFSET ||
+               gatherType == GATHERTYPE_OFFSET_DYNAMIC ||
+               gatherType == GATHERTYPE_OFFSETS)
+       {
+               result += ", ";
+               switch (gatherType)
+               {
+                       case GATHERTYPE_OFFSET:
+                               if (offsetSize == OFFSETSIZE_IMPLEMENTATION_MAXIMUM)
+                                       result += "u_offset";
+                               else
+                                       result += "ivec2" + de::toString(gatherArgs.offsets[0]);
+                               break;
+
+                       case GATHERTYPE_OFFSET_DYNAMIC:
+                               if (offsetSize == OFFSETSIZE_IMPLEMENTATION_MAXIMUM)
+                                       result += "pixCoord.yx % ivec2(u_offset.y - u_offset.x + 1) + u_offset.x";
+                               else
+                                       result += "pixCoord.yx % ivec2(" + de::toString(offsetRange.y() - offsetRange.x() + 1) + ") + " + de::toString(offsetRange.x());
+                               break;
+
+                       case GATHERTYPE_OFFSETS:
+                               DE_ASSERT(offsetSize != OFFSETSIZE_IMPLEMENTATION_MAXIMUM);
+                               result += "ivec2[4](\n"
+                                                 + string(indentationDepth, '\t') + "\tivec2" + de::toString(gatherArgs.offsets[0]) + ",\n"
+                                                 + string(indentationDepth, '\t') + "\tivec2" + de::toString(gatherArgs.offsets[1]) + ",\n"
+                                                 + string(indentationDepth, '\t') + "\tivec2" + de::toString(gatherArgs.offsets[2]) + ",\n"
+                                                 + string(indentationDepth, '\t') + "\tivec2" + de::toString(gatherArgs.offsets[3]) + ")\n"
+                                                 + string(indentationDepth, '\t') + "\t";
+                               break;
+
+                       default:
+                               DE_ASSERT(false);
+               }
+       }
+
+       if (gatherArgs.componentNdx >= 0)
+       {
+               DE_ASSERT(gatherArgs.componentNdx < 4);
+               result += ", " + de::toString(gatherArgs.componentNdx);
+       }
+
+       result += ")";
+
+       return result;
+}
+
+class TextureGather2DBase : public virtual TextureGatherBase
+{
+public:
+                                                                       TextureGather2DBase                                     (const GatherType                                       gatherType,
+                                                                                                                                                const OffsetSize                                       offsetSize,
+                                                                                                                                                const tcu::TextureFormat                       textureFormat,
+                                                                                                                                                const tcu::Sampler::CompareMode        shadowCompareMode,
+                                                                                                                                                const tcu::Sampler::WrapMode           wrapS,
+                                                                                                                                                const tcu::Sampler::WrapMode           wrapT,
+                                                                                                                                                const MaybeTextureSwizzle&                     textureSwizzle,
+                                                                                                                                                const tcu::Sampler::FilterMode         minFilter,
+                                                                                                                                                const tcu::Sampler::FilterMode         magFilter,
+                                                                                                                                                const int                                                      baseLevel,
+                                                                                                                                                const deUint32                                         flags,
+                                                                                                                                                const IVec2&                                           textureSize);
+       virtual                                                 ~TextureGather2DBase                            (void);
+
+protected:
+       virtual void                                    generateIterations                                      (void);
+       virtual int                                             getNumIterations                                        (void) const { DE_ASSERT(!m_iterations.empty()); return (int)m_iterations.size(); }
+       virtual GatherArgs                              getGatherArgs                                           (int iterationNdx) const { return m_iterations[iterationNdx]; }
+
+protected:
+       const IVec2                                             m_textureSize;
+       vector<GatherArgs>                              m_iterations;
+};
+
+TextureGather2DBase::TextureGather2DBase (const GatherType                                             gatherType,
+                                                                                 const OffsetSize                                              offsetSize,
+                                                                                 const tcu::TextureFormat                              textureFormat,
+                                                                                 const tcu::Sampler::CompareMode               shadowCompareMode,
+                                                                                 const tcu::Sampler::WrapMode                  wrapS,
+                                                                                 const tcu::Sampler::WrapMode                  wrapT,
+                                                                                 const MaybeTextureSwizzle&                    textureSwizzle,
+                                                                                 const tcu::Sampler::FilterMode                minFilter,
+                                                                                 const tcu::Sampler::FilterMode                magFilter,
+                                                                                 const int                                                             baseLevel,
+                                                                                 const deUint32                                                flags,
+                                                                                 const IVec2&                                                  textureSize)
+       : TextureGatherBase                     (TEXTURETYPE_2D, gatherType, offsetSize, textureFormat, shadowCompareMode, wrapS, wrapT, textureSwizzle, minFilter, magFilter, baseLevel, flags)
+       , m_textureSize                         (textureSize)
+{
+}
+
+TextureGather2DBase::~TextureGather2DBase (void)
+{
+}
+
+void TextureGather2DBase::generateIterations (void)
+{
+       DE_ASSERT(m_iterations.empty());
+       m_iterations = generateBasic2DCaseIterations(m_gatherType, m_textureFormat, getOffsetRange());
+}
+
+class TextureGather2DInstance : public TextureGather2DBase, public TextureGatherInstance
+{
+public:
+                                                                       TextureGather2DInstance                         (Context&                                                       context,
+                                                                                                                                                const GatherType                                       gatherType,
+                                                                                                                                                const OffsetSize                                       offsetSize,
+                                                                                                                                                const tcu::TextureFormat                       textureFormat,
+                                                                                                                                                const tcu::Sampler::CompareMode        shadowCompareMode,
+                                                                                                                                                const tcu::Sampler::WrapMode           wrapS,
+                                                                                                                                                const tcu::Sampler::WrapMode           wrapT,
+                                                                                                                                                const MaybeTextureSwizzle&                     textureSwizzle,
+                                                                                                                                                const tcu::Sampler::FilterMode         minFilter,
+                                                                                                                                                const tcu::Sampler::FilterMode         magFilter,
+                                                                                                                                                const int                                                      baseLevel,
+                                                                                                                                                const deUint32                                         flags,
+                                                                                                                                                const IVec2&                                           textureSize);
+       virtual                                                 ~TextureGather2DInstance                        (void);
+
+protected:
+       virtual TextureBindingSp                createTexture                                           (void);
+       virtual vector<float>                   computeQuadTexCoord                                     (int iterationNdx) const;
+       virtual bool                                    verify                                                          (int iterationNdx, const ConstPixelBufferAccess& rendered) const;
+
+private:
+       tcu::Texture2D                                  m_swizzledTexture;
+};
+
+TextureGather2DInstance::TextureGather2DInstance (Context&                                                             context,
+                                                                                                 const GatherType                                              gatherType,
+                                                                                                 const OffsetSize                                              offsetSize,
+                                                                                                 const tcu::TextureFormat                              textureFormat,
+                                                                                                 const tcu::Sampler::CompareMode               shadowCompareMode,
+                                                                                                 const tcu::Sampler::WrapMode                  wrapS,
+                                                                                                 const tcu::Sampler::WrapMode                  wrapT,
+                                                                                                 const MaybeTextureSwizzle&                    textureSwizzle,
+                                                                                                 const tcu::Sampler::FilterMode                minFilter,
+                                                                                                 const tcu::Sampler::FilterMode                magFilter,
+                                                                                                 const int                                                             baseLevel,
+                                                                                                 const deUint32                                                flags,
+                                                                                                 const IVec2&                                                  textureSize)
+       : TextureGatherBase                     (TEXTURETYPE_2D, gatherType, offsetSize, textureFormat, shadowCompareMode, wrapS, wrapT, textureSwizzle, minFilter, magFilter, baseLevel, flags)
+       , TextureGather2DBase           (gatherType, offsetSize, textureFormat, shadowCompareMode, wrapS, wrapT, textureSwizzle, minFilter, magFilter, baseLevel, flags, textureSize)
+       , TextureGatherInstance         (context, TEXTURETYPE_2D, gatherType, offsetSize, textureFormat, shadowCompareMode, wrapS, wrapT, textureSwizzle, minFilter, magFilter, baseLevel, flags)
+       , m_swizzledTexture                     (tcu::TextureFormat(), 1, 1)
+{
+       init();
+}
+
+TextureGather2DInstance::~TextureGather2DInstance (void)
+{
+}
+
+vector<float> TextureGather2DInstance::computeQuadTexCoord (int /* iterationNdx */) const
+{
+       vector<float> res;
+       TextureTestUtil::computeQuadTexCoord2D(res, Vec2(-0.3f, -0.4f), Vec2(1.5f, 1.6f));
+       return res;
+}
+
+TextureBindingSp TextureGather2DInstance::createTexture (void)
+{
+       TestLog&                                                log                     = m_context.getTestContext().getLog();
+       const tcu::TextureFormatInfo    texFmtInfo      = tcu::getTextureFormatInfo(m_textureFormat);
+       MovePtr<tcu::Texture2D>                 texture         = MovePtr<tcu::Texture2D>(new tcu::Texture2D(m_textureFormat, m_textureSize.x(), m_textureSize.y()));
+       const tcu::Sampler                              sampler         (m_wrapS, m_wrapT, tcu::Sampler::REPEAT_GL,
+                                                                                                m_minFilter, m_magFilter,
+                                                                                                0.0f /* LOD threshold */, true /* normalized coords */, m_shadowCompareMode);
+
+       {
+               const int       levelBegin      = m_baseLevel;
+               const int       levelEnd        = texture->getNumLevels();
+               DE_ASSERT(m_baseLevel < texture->getNumLevels());
+
+               for (int levelNdx = levelBegin; levelNdx < levelEnd; levelNdx++)
+               {
+                       texture->allocLevel(levelNdx);
+                       const PixelBufferAccess& level = texture->getLevel(levelNdx);
+                       fillWithRandomColorTiles(level, texFmtInfo.valueMin, texFmtInfo.valueMax, (deUint32)m_context.getTestContext().getCommandLine().getBaseSeed());
+                       log << TestLog::Image("InputTextureLevel" + de::toString(levelNdx), "Input texture, level " + de::toString(levelNdx), level)
+                               << TestLog::Message << "Note: texture level's size is " << IVec2(level.getWidth(), level.getHeight()) << TestLog::EndMessage;
+               }
+
+               swizzleTexture(m_swizzledTexture, *texture, m_textureSwizzle);
+       }
+
+       return TextureBindingSp(new TextureBinding(texture.release(), sampler));
+}
+
+bool TextureGather2DInstance::verify (int iterationNdx, const ConstPixelBufferAccess& rendered) const
+{
+       Vec2 texCoords[4];
+       computeTexCoordVecs(computeQuadTexCoord(iterationNdx), texCoords);
+       return TextureGatherInstance::verify(rendered, getOneLevelSubView(tcu::Texture2DView(m_swizzledTexture), m_baseLevel), texCoords, m_iterations[iterationNdx]);
+}
+
+class TextureGather2DCase : public TextureGather2DBase, public TextureGatherCase
+{
+public:
+                                                                       TextureGather2DCase                                     (tcu::TestContext&                                      testCtx,
+                                                                                                                                                const string&                                          name,
+                                                                                                                                                const string&                                          description,
+                                                                                                                                                const GatherType                                       gatherType,
+                                                                                                                                                const OffsetSize                                       offsetSize,
+                                                                                                                                                const tcu::TextureFormat                       textureFormat,
+                                                                                                                                                const tcu::Sampler::CompareMode        shadowCompareMode,
+                                                                                                                                                const tcu::Sampler::WrapMode           wrapS,
+                                                                                                                                                const tcu::Sampler::WrapMode           wrapT,
+                                                                                                                                                const MaybeTextureSwizzle&                     textureSwizzle,
+                                                                                                                                                const tcu::Sampler::FilterMode         minFilter,
+                                                                                                                                                const tcu::Sampler::FilterMode         magFilter,
+                                                                                                                                                const int                                                      baseLevel,
+                                                                                                                                                const deUint32                                         flags,
+                                                                                                                                                const IVec2&                                           textureSize);
+       virtual                                                 ~TextureGather2DCase                            (void);
+
+       virtual TestInstance*                   createInstance                                          (Context& context) const;
+};
+
+TextureGather2DCase::TextureGather2DCase (tcu::TestContext&                                            testCtx,
+                                                                                 const string&                                                 name,
+                                                                                 const string&                                                 description,
+                                                                                 const GatherType                                              gatherType,
+                                                                                 const OffsetSize                                              offsetSize,
+                                                                                 const tcu::TextureFormat                              textureFormat,
+                                                                                 const tcu::Sampler::CompareMode               shadowCompareMode,
+                                                                                 const tcu::Sampler::WrapMode                  wrapS,
+                                                                                 const tcu::Sampler::WrapMode                  wrapT,
+                                                                                 const MaybeTextureSwizzle&                    textureSwizzle,
+                                                                                 const tcu::Sampler::FilterMode                minFilter,
+                                                                                 const tcu::Sampler::FilterMode                magFilter,
+                                                                                 const int                                                             baseLevel,
+                                                                                 const deUint32                                                flags,
+                                                                                 const IVec2&                                                  textureSize)
+       : TextureGatherBase                     (TEXTURETYPE_2D, gatherType, offsetSize, textureFormat, shadowCompareMode, wrapS, wrapT, textureSwizzle, minFilter, magFilter, baseLevel, flags)
+       , TextureGather2DBase           (gatherType, offsetSize, textureFormat, shadowCompareMode, wrapS, wrapT, textureSwizzle, minFilter, magFilter, baseLevel, flags, textureSize)
+       , TextureGatherCase                     (testCtx, name, description, TEXTURETYPE_2D, gatherType, offsetSize, textureFormat, shadowCompareMode, wrapS, wrapT, textureSwizzle, minFilter, magFilter, baseLevel, flags)
+{
+       init();
+}
+
+TextureGather2DCase::~TextureGather2DCase (void)
+{
+}
+
+TestInstance* TextureGather2DCase::createInstance (Context& context) const
+{
+       return new TextureGather2DInstance(context, m_gatherType, m_offsetSize, m_textureFormat, m_shadowCompareMode,
+                                                                          m_wrapS, m_wrapT, m_textureSwizzle, m_minFilter, m_magFilter, m_baseLevel, m_flags, m_textureSize);
+}
+
+class TextureGather2DArrayBase : public virtual TextureGatherBase
+{
+public:
+                                                                       TextureGather2DArrayBase                        (const GatherType                                       gatherType,
+                                                                                                                                                const OffsetSize                                       offsetSize,
+                                                                                                                                                const tcu::TextureFormat                       textureFormat,
+                                                                                                                                                const tcu::Sampler::CompareMode        shadowCompareMode,
+                                                                                                                                                const tcu::Sampler::WrapMode           wrapS,
+                                                                                                                                                const tcu::Sampler::WrapMode           wrapT,
+                                                                                                                                                const MaybeTextureSwizzle&                     textureSwizzle,
+                                                                                                                                                const tcu::Sampler::FilterMode         minFilter,
+                                                                                                                                                const tcu::Sampler::FilterMode         magFilter,
+                                                                                                                                                const int                                                      baseLevel,
+                                                                                                                                                const deUint32                                         flags,
+                                                                                                                                                const IVec3&                                           textureSize);
+       virtual                                                 ~TextureGather2DArrayBase                       (void);
+
+protected:
+       virtual void                                    generateIterations                                      (void);
+       virtual int                                             getNumIterations                                        (void) const { DE_ASSERT(!m_iterations.empty()); return (int)m_iterations.size(); }
+       virtual GatherArgs                              getGatherArgs                                           (int iterationNdx) const { return m_iterations[iterationNdx].gatherArgs; }
+
+protected:
+       struct Iteration
+       {
+               GatherArgs      gatherArgs;
+               int                     layerNdx;
+       };
+
+       const IVec3                                             m_textureSize;
+       vector<Iteration>                               m_iterations;
+};
+
+TextureGather2DArrayBase::TextureGather2DArrayBase (const GatherType                                   gatherType,
+                                                                                                       const OffsetSize                                        offsetSize,
+                                                                                                       const tcu::TextureFormat                        textureFormat,
+                                                                                                       const tcu::Sampler::CompareMode         shadowCompareMode,
+                                                                                                       const tcu::Sampler::WrapMode            wrapS,
+                                                                                                       const tcu::Sampler::WrapMode            wrapT,
+                                                                                                       const MaybeTextureSwizzle&                      textureSwizzle,
+                                                                                                       const tcu::Sampler::FilterMode          minFilter,
+                                                                                                       const tcu::Sampler::FilterMode          magFilter,
+                                                                                                       const int                                                       baseLevel,
+                                                                                                       const deUint32                                          flags,
+                                                                                                       const IVec3&                                            textureSize)
+       : TextureGatherBase                     (TEXTURETYPE_2D_ARRAY, gatherType, offsetSize, textureFormat, shadowCompareMode, wrapS, wrapT, textureSwizzle, minFilter, magFilter, baseLevel, flags)
+       , m_textureSize                         (textureSize)
+{
+}
+
+TextureGather2DArrayBase::~TextureGather2DArrayBase (void)
+{
+}
+
+void TextureGather2DArrayBase::generateIterations (void)
+{
+       DE_ASSERT(m_iterations.empty());
+
+       const vector<GatherArgs> basicIterations = generateBasic2DCaseIterations(m_gatherType, m_textureFormat, getOffsetRange());
+
+       // \note Out-of-bounds layer indices are tested too.
+       for (int layerNdx = -1; layerNdx < m_textureSize.z()+1; layerNdx++)
+       {
+               // Don't duplicate all cases for all layers.
+               if (layerNdx == 0)
+               {
+                       for (int basicNdx = 0; basicNdx < (int)basicIterations.size(); basicNdx++)
+                       {
+                               m_iterations.push_back(Iteration());
+                               m_iterations.back().gatherArgs = basicIterations[basicNdx];
+                               m_iterations.back().layerNdx = layerNdx;
+                       }
+               }
+               else
+               {
+                       // For other layers than 0, only test one component and one set of offsets per layer.
+                       for (int basicNdx = 0; basicNdx < (int)basicIterations.size(); basicNdx++)
+                       {
+                               if (isDepthFormat(m_textureFormat) || basicIterations[basicNdx].componentNdx == (layerNdx + 2) % 4)
+                               {
+                                       m_iterations.push_back(Iteration());
+                                       m_iterations.back().gatherArgs = basicIterations[basicNdx];
+                                       m_iterations.back().layerNdx = layerNdx;
+                                       break;
+                               }
+                       }
+               }
+       }
+}
+
+class TextureGather2DArrayInstance : public TextureGather2DArrayBase, public TextureGatherInstance
+{
+public:
+                                                                       TextureGather2DArrayInstance            (Context&                                                       context,
+                                                                                                                                                const GatherType                                       gatherType,
+                                                                                                                                                const OffsetSize                                       offsetSize,
+                                                                                                                                                const tcu::TextureFormat                       textureFormat,
+                                                                                                                                                const tcu::Sampler::CompareMode        shadowCompareMode,
+                                                                                                                                                const tcu::Sampler::WrapMode           wrapS,
+                                                                                                                                                const tcu::Sampler::WrapMode           wrapT,
+                                                                                                                                                const MaybeTextureSwizzle&                     textureSwizzle,
+                                                                                                                                                const tcu::Sampler::FilterMode         minFilter,
+                                                                                                                                                const tcu::Sampler::FilterMode         magFilter,
+                                                                                                                                                const int                                                      baseLevel,
+                                                                                                                                                const deUint32                                         flags,
+                                                                                                                                                const IVec3&                                           textureSize);
+       virtual                                                 ~TextureGather2DArrayInstance           (void);
+
+protected:
+       virtual TextureBindingSp                createTexture                                           (void);
+       virtual vector<float>                   computeQuadTexCoord                                     (int iterationNdx) const;
+       virtual bool                                    verify                                                          (int iterationNdx, const ConstPixelBufferAccess& rendered) const;
+
+private:
+       tcu::Texture2DArray                             m_swizzledTexture;
+};
+
+TextureGather2DArrayInstance::TextureGather2DArrayInstance (Context&                                                   context,
+                                                                                                                       const GatherType                                        gatherType,
+                                                                                                                       const OffsetSize                                        offsetSize,
+                                                                                                                       const tcu::TextureFormat                        textureFormat,
+                                                                                                                       const tcu::Sampler::CompareMode         shadowCompareMode,
+                                                                                                                       const tcu::Sampler::WrapMode            wrapS,
+                                                                                                                       const tcu::Sampler::WrapMode            wrapT,
+                                                                                                                       const MaybeTextureSwizzle&                      textureSwizzle,
+                                                                                                                       const tcu::Sampler::FilterMode          minFilter,
+                                                                                                                       const tcu::Sampler::FilterMode          magFilter,
+                                                                                                                       const int                                                       baseLevel,
+                                                                                                                       const deUint32                                          flags,
+                                                                                                                       const IVec3&                                            textureSize)
+       : TextureGatherBase                     (TEXTURETYPE_2D_ARRAY, gatherType, offsetSize, textureFormat, shadowCompareMode, wrapS, wrapT, textureSwizzle, minFilter, magFilter, baseLevel, flags)
+       , TextureGather2DArrayBase      (gatherType, offsetSize, textureFormat, shadowCompareMode, wrapS, wrapT, textureSwizzle, minFilter, magFilter, baseLevel, flags, textureSize)
+       , TextureGatherInstance         (context, TEXTURETYPE_2D_ARRAY, gatherType, offsetSize, textureFormat, shadowCompareMode, wrapS, wrapT, textureSwizzle, minFilter, magFilter, baseLevel, flags)
+       , m_swizzledTexture                     (tcu::TextureFormat(), 1, 1, 1)
+{
+       init();
+}
+
+TextureGather2DArrayInstance::~TextureGather2DArrayInstance (void)
+{
+}
+
+vector<float> TextureGather2DArrayInstance::computeQuadTexCoord (int iterationNdx) const
+{
+       vector<float> res;
+       TextureTestUtil::computeQuadTexCoord2DArray(res, m_iterations[iterationNdx].layerNdx, Vec2(-0.3f, -0.4f), Vec2(1.5f, 1.6f));
+       return res;
+}
+
+TextureBindingSp TextureGather2DArrayInstance::createTexture (void)
+{
+       TestLog&                                                log                     = m_context.getTestContext().getLog();
+       const tcu::TextureFormatInfo    texFmtInfo      = tcu::getTextureFormatInfo(m_textureFormat);
+       MovePtr<tcu::Texture2DArray>    texture         = MovePtr<tcu::Texture2DArray>(new tcu::Texture2DArray(m_textureFormat, m_textureSize.x(), m_textureSize.y(), m_textureSize.z()));
+       const tcu::Sampler                              sampler         (m_wrapS, m_wrapT, tcu::Sampler::REPEAT_GL,
+                                                                                                m_minFilter, m_magFilter,
+                                                                                                0.0f /* LOD threshold */, true /* normalized coords */, m_shadowCompareMode);
+
+       {
+               const int       levelBegin      = m_baseLevel;
+               const int       levelEnd        = texture->getNumLevels();
+               DE_ASSERT(m_baseLevel < texture->getNumLevels());
+
+               for (int levelNdx = levelBegin; levelNdx < levelEnd; levelNdx++)
+               {
+                       texture->allocLevel(levelNdx);
+                       const PixelBufferAccess& level = texture->getLevel(levelNdx);
+                       fillWithRandomColorTiles(level, texFmtInfo.valueMin, texFmtInfo.valueMax, (deUint32)m_context.getTestContext().getCommandLine().getBaseSeed());
+
+                       log << TestLog::ImageSet("InputTextureLevel", "Input texture, level " + de::toString(levelNdx));
+                       for (int layerNdx = 0; layerNdx < m_textureSize.z(); layerNdx++)
+                               log << TestLog::Image("InputTextureLevel" + de::toString(layerNdx) + "Layer" + de::toString(layerNdx),
+                                                                         "Layer " + de::toString(layerNdx),
+                                                                         tcu::getSubregion(level, 0, 0, layerNdx, level.getWidth(), level.getHeight(), 1));
+                       log << TestLog::EndImageSet
+                               << TestLog::Message << "Note: texture level's size is " << IVec3(level.getWidth(), level.getHeight(), level.getDepth()) << TestLog::EndMessage;
+               }
+
+               swizzleTexture(m_swizzledTexture, *texture, m_textureSwizzle);
+       }
+
+       return TextureBindingSp(new TextureBinding(texture.release(), sampler));
+}
+
+bool TextureGather2DArrayInstance::verify (int iterationNdx, const ConstPixelBufferAccess& rendered) const
+{
+       Vec3 texCoords[4];
+       computeTexCoordVecs(computeQuadTexCoord(iterationNdx), texCoords);
+       return TextureGatherInstance::verify(rendered, getOneLevelSubView(tcu::Texture2DArrayView(m_swizzledTexture), m_baseLevel), texCoords, m_iterations[iterationNdx].gatherArgs);
+}
+
+class TextureGather2DArrayCase : public TextureGather2DArrayBase, public TextureGatherCase
+{
+public:
+                                                                       TextureGather2DArrayCase                        (tcu::TestContext&                                      testCtx,
+                                                                                                                                                const string&                                          name,
+                                                                                                                                                const string&                                          description,
+                                                                                                                                                const GatherType                                       gatherType,
+                                                                                                                                                const OffsetSize                                       offsetSize,
+                                                                                                                                                const tcu::TextureFormat                       textureFormat,
+                                                                                                                                                const tcu::Sampler::CompareMode        shadowCompareMode,
+                                                                                                                                                const tcu::Sampler::WrapMode           wrapS,
+                                                                                                                                                const tcu::Sampler::WrapMode           wrapT,
+                                                                                                                                                const MaybeTextureSwizzle&                     textureSwizzle,
+                                                                                                                                                const tcu::Sampler::FilterMode         minFilter,
+                                                                                                                                                const tcu::Sampler::FilterMode         magFilter,
+                                                                                                                                                const int                                                      baseLevel,
+                                                                                                                                                const deUint32                                         flags,
+                                                                                                                                                const IVec3&                                           textureSize);
+       virtual                                                 ~TextureGather2DArrayCase                       (void);
+
+       virtual TestInstance*                   createInstance                                          (Context& context) const;
+};
+
+TextureGather2DArrayCase::TextureGather2DArrayCase (tcu::TestContext&                                  testCtx,
+                                                                                                       const string&                                           name,
+                                                                                                       const string&                                           description,
+                                                                                                       const GatherType                                        gatherType,
+                                                                                                       const OffsetSize                                        offsetSize,
+                                                                                                       const tcu::TextureFormat                        textureFormat,
+                                                                                                       const tcu::Sampler::CompareMode         shadowCompareMode,
+                                                                                                       const tcu::Sampler::WrapMode            wrapS,
+                                                                                                       const tcu::Sampler::WrapMode            wrapT,
+                                                                                                       const MaybeTextureSwizzle&                      textureSwizzle,
+                                                                                                       const tcu::Sampler::FilterMode          minFilter,
+                                                                                                       const tcu::Sampler::FilterMode          magFilter,
+                                                                                                       const int                                                       baseLevel,
+                                                                                                       const deUint32                                          flags,
+                                                                                                       const IVec3&                                            textureSize)
+       : TextureGatherBase                     (TEXTURETYPE_2D_ARRAY, gatherType, offsetSize, textureFormat, shadowCompareMode, wrapS, wrapT, textureSwizzle, minFilter, magFilter, baseLevel, flags)
+       , TextureGather2DArrayBase      (gatherType, offsetSize, textureFormat, shadowCompareMode, wrapS, wrapT, textureSwizzle, minFilter, magFilter, baseLevel, flags, textureSize)
+       , TextureGatherCase                     (testCtx, name, description, TEXTURETYPE_2D_ARRAY, gatherType, offsetSize, textureFormat, shadowCompareMode, wrapS, wrapT, textureSwizzle, minFilter, magFilter, baseLevel, flags)
+{
+       init();
+}
+
+TextureGather2DArrayCase::~TextureGather2DArrayCase (void)
+{
+}
+
+TestInstance* TextureGather2DArrayCase::createInstance (Context& context) const
+{
+       return new TextureGather2DArrayInstance(context, m_gatherType, m_offsetSize, m_textureFormat, m_shadowCompareMode,
+                                                                                       m_wrapS, m_wrapT, m_textureSwizzle, m_minFilter, m_magFilter, m_baseLevel, m_flags, m_textureSize);
+}
+
+class TextureGatherCubeBase : public virtual TextureGatherBase
+{
+public:
+                                                                       TextureGatherCubeBase                           (const tcu::TextureFormat                       textureFormat,
+                                                                                                                                                const tcu::Sampler::CompareMode        shadowCompareMode,
+                                                                                                                                                const tcu::Sampler::WrapMode           wrapS,
+                                                                                                                                                const tcu::Sampler::WrapMode           wrapT,
+                                                                                                                                                const MaybeTextureSwizzle&                     textureSwizzle,
+                                                                                                                                                const tcu::Sampler::FilterMode         minFilter,
+                                                                                                                                                const tcu::Sampler::FilterMode         magFilter,
+                                                                                                                                                const int                                                      baseLevel,
+                                                                                                                                                const deUint32                                         flags,
+                                                                                                                                                const int                                                      textureSize);
+       virtual                                                 ~TextureGatherCubeBase                          (void);
+
+protected:
+       virtual void                                    generateIterations                                      (void);
+       virtual int                                             getNumIterations                                        (void) const { DE_ASSERT(!m_iterations.empty()); return (int)m_iterations.size(); }
+       virtual GatherArgs                              getGatherArgs                                           (int iterationNdx) const { return m_iterations[iterationNdx].gatherArgs; }
+
+protected:
+       struct Iteration
+       {
+               GatherArgs              gatherArgs;
+               tcu::CubeFace   face;
+       };
+
+       const int                                               m_textureSize;
+       vector<Iteration>                               m_iterations;
+};
+
+TextureGatherCubeBase::TextureGatherCubeBase (const tcu::TextureFormat                         textureFormat,
+                                                                                         const tcu::Sampler::CompareMode               shadowCompareMode,
+                                                                                         const tcu::Sampler::WrapMode                  wrapS,
+                                                                                         const tcu::Sampler::WrapMode                  wrapT,
+                                                                                         const MaybeTextureSwizzle&                    textureSwizzle,
+                                                                                         const tcu::Sampler::FilterMode                minFilter,
+                                                                                         const tcu::Sampler::FilterMode                magFilter,
+                                                                                         const int                                                             baseLevel,
+                                                                                         const deUint32                                                flags,
+                                                                                         const int                                                             textureSize)
+       : TextureGatherBase                     (TEXTURETYPE_CUBE, GATHERTYPE_BASIC, OFFSETSIZE_NONE, textureFormat, shadowCompareMode, wrapS, wrapT, textureSwizzle, minFilter, magFilter, baseLevel, flags)
+       , m_textureSize                         (textureSize)
+{
+}
+
+TextureGatherCubeBase::~TextureGatherCubeBase (void)
+{
+}
+
+void TextureGatherCubeBase::generateIterations (void)
+{
+       DE_ASSERT(m_iterations.empty());
+
+       const vector<GatherArgs> basicIterations = generateBasic2DCaseIterations(m_gatherType, m_textureFormat, getOffsetRange());
+
+       for (int cubeFaceI = 0; cubeFaceI < tcu::CUBEFACE_LAST; cubeFaceI++)
+       {
+               const tcu::CubeFace cubeFace = (tcu::CubeFace)cubeFaceI;
+
+               // Don't duplicate all cases for all faces.
+               if (cubeFaceI == 0)
+               {
+                       for (int basicNdx = 0; basicNdx < (int)basicIterations.size(); basicNdx++)
+                       {
+                               m_iterations.push_back(Iteration());
+                               m_iterations.back().gatherArgs = basicIterations[basicNdx];
+                               m_iterations.back().face = cubeFace;
+                       }
+               }
+               else
+               {
+                       // For other faces than first, only test one component per face.
+                       for (int basicNdx = 0; basicNdx < (int)basicIterations.size(); basicNdx++)
+                       {
+                               if (isDepthFormat(m_textureFormat) || basicIterations[basicNdx].componentNdx == cubeFaceI % 4)
+                               {
+                                       m_iterations.push_back(Iteration());
+                                       m_iterations.back().gatherArgs = basicIterations[basicNdx];
+                                       m_iterations.back().face = cubeFace;
+                                       break;
+                               }
+                       }
+               }
+       }
+}
+
+class TextureGatherCubeInstance : public TextureGatherCubeBase, public TextureGatherInstance
+{
+public:
+                                                                       TextureGatherCubeInstance                       (Context&                                                       context,
+                                                                                                                                                const tcu::TextureFormat                       textureFormat,
+                                                                                                                                                const tcu::Sampler::CompareMode        shadowCompareMode,
+                                                                                                                                                const tcu::Sampler::WrapMode           wrapS,
+                                                                                                                                                const tcu::Sampler::WrapMode           wrapT,
+                                                                                                                                                const MaybeTextureSwizzle&                     textureSwizzle,
+                                                                                                                                                const tcu::Sampler::FilterMode         minFilter,
+                                                                                                                                                const tcu::Sampler::FilterMode         magFilter,
+                                                                                                                                                const int                                                      baseLevel,
+                                                                                                                                                const deUint32                                         flags,
+                                                                                                                                                const int                                                      textureSize);
+       virtual                                                 ~TextureGatherCubeInstance                      (void);
+
+protected:
+       virtual TextureBindingSp                createTexture                                           (void);
+       virtual vector<float>                   computeQuadTexCoord                                     (int iterationNdx) const;
+       virtual bool                                    verify                                                          (int iterationNdx, const ConstPixelBufferAccess& rendered) const;
+
+private:
+       tcu::TextureCube                                m_swizzledTexture;
+};
+
+TextureGatherCubeInstance::TextureGatherCubeInstance (Context&                                                         context,
+                                                                                                         const tcu::TextureFormat                              textureFormat,
+                                                                                                         const tcu::Sampler::CompareMode               shadowCompareMode,
+                                                                                                         const tcu::Sampler::WrapMode                  wrapS,
+                                                                                                         const tcu::Sampler::WrapMode                  wrapT,
+                                                                                                         const MaybeTextureSwizzle&                    textureSwizzle,
+                                                                                                         const tcu::Sampler::FilterMode                minFilter,
+                                                                                                         const tcu::Sampler::FilterMode                magFilter,
+                                                                                                         const int                                                             baseLevel,
+                                                                                                         const deUint32                                                flags,
+                                                                                                         const int                                                             textureSize)
+       : TextureGatherBase                     (TEXTURETYPE_CUBE, GATHERTYPE_BASIC, OFFSETSIZE_NONE, textureFormat, shadowCompareMode, wrapS, wrapT, textureSwizzle, minFilter, magFilter, baseLevel, flags)
+       , TextureGatherCubeBase         (textureFormat, shadowCompareMode, wrapS, wrapT, textureSwizzle, minFilter, magFilter, baseLevel, flags, textureSize)
+       , TextureGatherInstance         (context, TEXTURETYPE_CUBE, GATHERTYPE_BASIC, OFFSETSIZE_NONE, textureFormat, shadowCompareMode, wrapS, wrapT, textureSwizzle, minFilter, magFilter, baseLevel, flags)
+       , m_swizzledTexture                     (tcu::TextureFormat(), 1)
+{
+       init();
+}
+
+TextureGatherCubeInstance::~TextureGatherCubeInstance (void)
+{
+}
+
+vector<float> TextureGatherCubeInstance::computeQuadTexCoord (int iterationNdx) const
+{
+       const bool              corners = (m_flags & GATHERCASE_DONT_SAMPLE_CUBE_CORNERS) == 0;
+       const Vec2              minC    = corners ? Vec2(-1.2f) : Vec2(-0.6f, -1.2f);
+       const Vec2              maxC    = corners ? Vec2( 1.2f) : Vec2( 0.6f,  1.2f);
+       vector<float>   res;
+       TextureTestUtil::computeQuadTexCoordCube(res, m_iterations[iterationNdx].face, minC, maxC);
+       return res;
+}
+
+TextureBindingSp TextureGatherCubeInstance::createTexture (void)
+{
+       TestLog&                                                log                     = m_context.getTestContext().getLog();
+       const tcu::TextureFormatInfo    texFmtInfo      = tcu::getTextureFormatInfo(m_textureFormat);
+       MovePtr<tcu::TextureCube>               texture         = MovePtr<tcu::TextureCube>(new tcu::TextureCube(m_textureFormat, m_textureSize));
+       const tcu::Sampler                              sampler         (m_wrapS, m_wrapT, tcu::Sampler::REPEAT_GL,
+                                                                                                m_minFilter, m_magFilter,
+                                                                                                0.0f /* LOD threshold */, true /* normalized coords */, m_shadowCompareMode,
+                                                                                                0 /* cmp channel */, tcu::Vec4(0.0f) /* border color */, true /* seamless cube map */);
+
+       {
+               const int       levelBegin      = m_baseLevel;
+               const int       levelEnd        = texture->getNumLevels();
+               DE_ASSERT(m_baseLevel < texture->getNumLevels());
+
+               for (int levelNdx = levelBegin; levelNdx < levelEnd; levelNdx++)
+               {
+                       log << TestLog::ImageSet("InputTextureLevel" + de::toString(levelNdx), "Input texture, level " + de::toString(levelNdx));
+
+                       for (int cubeFaceI = 0; cubeFaceI < tcu::CUBEFACE_LAST; cubeFaceI++)
+                       {
+                               const tcu::CubeFace                     cubeFace        = (tcu::CubeFace)cubeFaceI;
+                               texture->allocLevel(cubeFace, levelNdx);
+                               const PixelBufferAccess&        levelFace       = texture->getLevelFace(levelNdx, cubeFace);
+                               fillWithRandomColorTiles(levelFace, texFmtInfo.valueMin, texFmtInfo.valueMax, (deUint32)m_context.getTestContext().getCommandLine().getBaseSeed() ^ (deUint32)cubeFaceI);
+
+                               log << TestLog::Image("InputTextureLevel" + de::toString(levelNdx) + "Face" + de::toString((int)cubeFace), de::toString(cubeFace), levelFace);
+                       }
+
+                       log << TestLog::EndImageSet
+                               << TestLog::Message << "Note: texture level's size is " << texture->getLevelFace(levelNdx, tcu::CUBEFACE_NEGATIVE_X).getWidth() << TestLog::EndMessage;
+               }
+
+               swizzleTexture(m_swizzledTexture, *texture, m_textureSwizzle);
+       }
+
+       return TextureBindingSp(new TextureBinding(texture.release(), sampler));
+}
+
+bool TextureGatherCubeInstance::verify (int iterationNdx, const ConstPixelBufferAccess& rendered) const
+{
+       Vec3 texCoords[4];
+       computeTexCoordVecs(computeQuadTexCoord(iterationNdx), texCoords);
+       return TextureGatherInstance::verify(rendered, getOneLevelSubView(tcu::TextureCubeView(m_swizzledTexture), m_baseLevel), texCoords, m_iterations[iterationNdx].gatherArgs);
+}
+
+// \note Cube case always uses just basic textureGather(); offset versions are not defined for cube maps.
+class TextureGatherCubeCase : public TextureGatherCubeBase, public TextureGatherCase
+{
+public:
+                                                                       TextureGatherCubeCase                           (tcu::TestContext&                                      testCtx,
+                                                                                                                                                const string&                                          name,
+                                                                                                                                                const string&                                          description,
+                                                                                                                                                const tcu::TextureFormat                       textureFormat,
+                                                                                                                                                const tcu::Sampler::CompareMode        shadowCompareMode,
+                                                                                                                                                const tcu::Sampler::WrapMode           wrapS,
+                                                                                                                                                const tcu::Sampler::WrapMode           wrapT,
+                                                                                                                                                const MaybeTextureSwizzle&                     textureSwizzle,
+                                                                                                                                                const tcu::Sampler::FilterMode         minFilter,
+                                                                                                                                                const tcu::Sampler::FilterMode         magFilter,
+                                                                                                                                                const int                                                      baseLevel,
+                                                                                                                                                const deUint32                                         flags,
+                                                                                                                                                const int                                                      textureSize);
+       virtual                                                 ~TextureGatherCubeCase                          (void);
+
+       virtual TestInstance*                   createInstance                                          (Context& context) const;
+};
+
+TextureGatherCubeCase::TextureGatherCubeCase (tcu::TestContext&                                                testCtx,
+                                                                                         const string&                                                 name,
+                                                                                         const string&                                                 description,
+                                                                                         const tcu::TextureFormat                              textureFormat,
+                                                                                         const tcu::Sampler::CompareMode               shadowCompareMode,
+                                                                                         const tcu::Sampler::WrapMode                  wrapS,
+                                                                                         const tcu::Sampler::WrapMode                  wrapT,
+                                                                                         const MaybeTextureSwizzle&                    textureSwizzle,
+                                                                                         const tcu::Sampler::FilterMode                minFilter,
+                                                                                         const tcu::Sampler::FilterMode                magFilter,
+                                                                                         const int                                                             baseLevel,
+                                                                                         const deUint32                                                flags,
+                                                                                         const int                                                             textureSize)
+       : TextureGatherBase                     (TEXTURETYPE_CUBE, GATHERTYPE_BASIC, OFFSETSIZE_NONE, textureFormat, shadowCompareMode, wrapS, wrapT, textureSwizzle, minFilter, magFilter, baseLevel, flags)
+       , TextureGatherCubeBase         (textureFormat, shadowCompareMode, wrapS, wrapT, textureSwizzle, minFilter, magFilter, baseLevel, flags, textureSize)
+       , TextureGatherCase                     (testCtx, name, description, TEXTURETYPE_CUBE, GATHERTYPE_BASIC, OFFSETSIZE_NONE, textureFormat, shadowCompareMode, wrapS, wrapT, textureSwizzle, minFilter, magFilter, baseLevel, flags)
+{
+       init();
+}
+
+TextureGatherCubeCase::~TextureGatherCubeCase (void)
+{
+}
+
+TestInstance* TextureGatherCubeCase::createInstance (Context& context) const
+{
+       return new TextureGatherCubeInstance(context, m_textureFormat, m_shadowCompareMode,
+                                                                                m_wrapS, m_wrapT, m_textureSwizzle, m_minFilter, m_magFilter, m_baseLevel, m_flags, m_textureSize);
+}
+
+class TextureGatherTests : public tcu::TestCaseGroup
+{
+public:
+                                                               TextureGatherTests                              (tcu::TestContext& context);
+       virtual                                         ~TextureGatherTests                             (void);
+       virtual void                            init                                                    (void);
+
+private:
+                                                               TextureGatherTests                              (const TextureGatherTests&);            // not allowed!
+       TextureGatherTests&                     operator=                                               (const TextureGatherTests&);            // not allowed!
+};
+
+TextureGatherTests::TextureGatherTests (tcu::TestContext& context)
+       : TestCaseGroup(context, "texture_gather", "textureGather* tests")
+{
+}
+
+TextureGatherTests::~TextureGatherTests (void)
+{
+}
+
+static inline TextureGatherCase* makeTextureGatherCase (TextureType                                    textureType,
+                                                                                                               tcu::TestContext&                       testCtx,
+                                                                                                               const string&                           name,
+                                                                                                               const string&                           description,
+                                                                                                               GatherType                                      gatherType,
+                                                                                                               OffsetSize                                      offsetSize,
+                                                                                                               tcu::TextureFormat                      textureFormat,
+                                                                                                               tcu::Sampler::CompareMode       shadowCompareMode,
+                                                                                                               tcu::Sampler::WrapMode          wrapS,
+                                                                                                               tcu::Sampler::WrapMode          wrapT,
+                                                                                                               const MaybeTextureSwizzle&      texSwizzle,
+                                                                                                               tcu::Sampler::FilterMode        minFilter,
+                                                                                                               tcu::Sampler::FilterMode        magFilter,
+                                                                                                               int                                                     baseLevel,
+                                                                                                               const IVec3&                            textureSize,
+                                                                                                               deUint32                                        flags = 0)
+{
+       switch (textureType)
+       {
+               case TEXTURETYPE_2D:
+                       return new TextureGather2DCase(testCtx, name, description, gatherType, offsetSize, textureFormat, shadowCompareMode,
+                                                                                  wrapS, wrapT, texSwizzle, minFilter, magFilter, baseLevel, flags, textureSize.swizzle(0, 1));
+
+               case TEXTURETYPE_2D_ARRAY:
+                       return new TextureGather2DArrayCase(testCtx, name, description, gatherType, offsetSize, textureFormat, shadowCompareMode,
+                                                                                               wrapS, wrapT, texSwizzle, minFilter, magFilter, baseLevel, flags, textureSize);
+
+               case TEXTURETYPE_CUBE:
+                       DE_ASSERT(gatherType == GATHERTYPE_BASIC);
+                       DE_ASSERT(offsetSize == OFFSETSIZE_NONE);
+                       return new TextureGatherCubeCase(testCtx, name, description, textureFormat, shadowCompareMode,
+                                                                                        wrapS, wrapT, texSwizzle, minFilter, magFilter, baseLevel, flags, textureSize.x());
+
+               default:
+                       DE_ASSERT(false);
+                       return DE_NULL;
+       }
+}
+
+static inline const char* compareModeName (tcu::Sampler::CompareMode mode)
+{
+       switch (mode)
+       {
+               case tcu::Sampler::COMPAREMODE_LESS:                            return "less";
+               case tcu::Sampler::COMPAREMODE_LESS_OR_EQUAL:           return "less_or_equal";
+               case tcu::Sampler::COMPAREMODE_GREATER:                         return "greater";
+               case tcu::Sampler::COMPAREMODE_GREATER_OR_EQUAL:        return "greater_or_equal";
+               case tcu::Sampler::COMPAREMODE_EQUAL:                           return "equal";
+               case tcu::Sampler::COMPAREMODE_NOT_EQUAL:                       return "not_equal";
+               case tcu::Sampler::COMPAREMODE_ALWAYS:                          return "always";
+               case tcu::Sampler::COMPAREMODE_NEVER:                           return "never";
+               default: DE_ASSERT(false); return DE_NULL;
+       }
+}
+
+void TextureGatherTests::init (void)
+{
+       const struct
+       {
+               const char* name;
+               TextureType type;
+       } textureTypes[] =
+       {
+               { "2d",                 TEXTURETYPE_2D                  },
+               { "2d_array",   TEXTURETYPE_2D_ARRAY    },
+               { "cube",               TEXTURETYPE_CUBE                }
+       };
+
+       const struct
+       {
+               const char*                     name;
+               tcu::TextureFormat      format;
+       } formats[] =
+       {
+               { "rgba8",              tcu::TextureFormat(tcu::TextureFormat::RGBA,    tcu::TextureFormat::UNORM_INT8)         },
+               { "rgba8ui",    tcu::TextureFormat(tcu::TextureFormat::RGBA,    tcu::TextureFormat::UNSIGNED_INT8)      },
+               { "rgba8i",             tcu::TextureFormat(tcu::TextureFormat::RGBA,    tcu::TextureFormat::SIGNED_INT8)        },
+               { "depth32f",   tcu::TextureFormat(tcu::TextureFormat::D,               tcu::TextureFormat::FLOAT)                      }
+       };
+
+       const struct
+       {
+               const char*             name;
+               IVec3                   size;
+       } textureSizes[] =
+       {
+               { "size_pot",   IVec3(64, 64, 3) },
+               { "size_npot",  IVec3(17, 23, 3) }
+       };
+
+       const struct
+       {
+               const char*                             name;
+               tcu::Sampler::WrapMode  mode;
+       } wrapModes[] =
+       {
+               { "clamp_to_edge",              tcu::Sampler::CLAMP_TO_EDGE                     },
+               { "repeat",                             tcu::Sampler::REPEAT_GL                         },
+               { "mirrored_repeat",    tcu::Sampler::MIRRORED_REPEAT_GL        }
+       };
+
+       for (int gatherTypeI = 0; gatherTypeI < GATHERTYPE_LAST; gatherTypeI++)
+       {
+               const GatherType                gatherType                      = (GatherType)gatherTypeI;
+               TestCaseGroup* const    gatherTypeGroup         = new TestCaseGroup(m_testCtx, gatherTypeName(gatherType), gatherTypeDescription(gatherType));
+               addChild(gatherTypeGroup);
+
+               for (int offsetSizeI = 0; offsetSizeI < OFFSETSIZE_LAST; offsetSizeI++)
+               {
+                       const OffsetSize offsetSize = (OffsetSize)offsetSizeI;
+                       if ((gatherType == GATHERTYPE_BASIC) != (offsetSize == OFFSETSIZE_NONE))
+                               continue;
+
+                       if (gatherType == GATHERTYPE_OFFSETS && offsetSize == OFFSETSIZE_IMPLEMENTATION_MAXIMUM) // \note offsets argument must be compile-time constant
+                               continue;
+
+                       TestCaseGroup* const offsetSizeGroup = offsetSize == OFFSETSIZE_NONE ?
+                                                                                                       gatherTypeGroup :
+                                                                                                       new TestCaseGroup(m_testCtx,
+                                                                                                                                         offsetSize == OFFSETSIZE_MINIMUM_REQUIRED                             ? "min_required_offset"
+                                                                                                                                         : offsetSize == OFFSETSIZE_IMPLEMENTATION_MAXIMUM             ? "implementation_offset"
+                                                                                                                                         : DE_NULL,
+                                                                                                                                         offsetSize == OFFSETSIZE_MINIMUM_REQUIRED                             ? "Use offsets within Vulkan minimum required range"
+                                                                                                                                         : offsetSize == OFFSETSIZE_IMPLEMENTATION_MAXIMUM             ? "Use offsets within the implementation range"
+                                                                                                                                         : DE_NULL);
+
+                       if (offsetSizeGroup != gatherTypeGroup)
+                               gatherTypeGroup->addChild(offsetSizeGroup);
+
+                       for (int textureTypeNdx = 0; textureTypeNdx < DE_LENGTH_OF_ARRAY(textureTypes); textureTypeNdx++)
+                       {
+                               const TextureType textureType = textureTypes[textureTypeNdx].type;
+
+                               if (textureType == TEXTURETYPE_CUBE && gatherType != GATHERTYPE_BASIC)
+                                       continue;
+
+                               TestCaseGroup* const textureTypeGroup = new TestCaseGroup(m_testCtx, textureTypes[textureTypeNdx].name, "");
+                               offsetSizeGroup->addChild(textureTypeGroup);
+
+                               for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(formats); formatNdx++)
+                               {
+                                       const tcu::TextureFormat&       format                  = formats[formatNdx].format;
+                                       TestCaseGroup* const            formatGroup             = new TestCaseGroup(m_testCtx, formats[formatNdx].name, "");
+                                       textureTypeGroup->addChild(formatGroup);
+
+                                       for (int noCornersI = 0; noCornersI <= ((textureType == TEXTURETYPE_CUBE)?1:0); noCornersI++)
+                                       {
+                                               const bool                              noCorners               = noCornersI!= 0;
+                                               TestCaseGroup* const    cornersGroup    = noCorners
+                                                                                                                               ? new TestCaseGroup(m_testCtx, "no_corners", "Test case variants that don't sample around cube map corners")
+                                                                                                                               : formatGroup;
+
+                                               if (formatGroup != cornersGroup)
+                                                       formatGroup->addChild(cornersGroup);
+
+                                               for (int textureSizeNdx = 0; textureSizeNdx < DE_LENGTH_OF_ARRAY(textureSizes); textureSizeNdx++)
+                                               {
+                                                       const IVec3&                    textureSize                     = textureSizes[textureSizeNdx].size;
+                                                       TestCaseGroup* const    textureSizeGroup        = new TestCaseGroup(m_testCtx, textureSizes[textureSizeNdx].name, "");
+                                                       cornersGroup->addChild(textureSizeGroup);
+
+                                                       for (int compareModeI = 0; compareModeI < tcu::Sampler::COMPAREMODE_LAST; compareModeI++)
+                                                       {
+                                                               const tcu::Sampler::CompareMode compareMode = (tcu::Sampler::CompareMode)compareModeI;
+
+                                                               if ((compareMode != tcu::Sampler::COMPAREMODE_NONE) != isDepthFormat(format))
+                                                                       continue;
+
+                                                               if (compareMode != tcu::Sampler::COMPAREMODE_NONE &&
+                                                                       compareMode != tcu::Sampler::COMPAREMODE_LESS &&
+                                                                       compareMode != tcu::Sampler::COMPAREMODE_GREATER)
+                                                                       continue;
+
+                                                               TestCaseGroup* const compareModeGroup = compareMode == tcu::Sampler::COMPAREMODE_NONE ?
+                                                                                                                                                       textureSizeGroup :
+                                                                                                                                                       new TestCaseGroup(m_testCtx,
+                                                                                                                                                                                         (string() + "compare_" + compareModeName(compareMode)).c_str(),
+                                                                                                                                                                                         "");
+                                                               if (compareModeGroup != textureSizeGroup)
+                                                                       textureSizeGroup->addChild(compareModeGroup);
+
+                                                               for (int wrapCaseNdx = 0; wrapCaseNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapCaseNdx++)
+                                                               {
+                                                                       const int                                               wrapSNdx        = wrapCaseNdx;
+                                                                       const int                                               wrapTNdx        = (wrapCaseNdx + 1) % DE_LENGTH_OF_ARRAY(wrapModes);
+                                                                       const tcu::Sampler::WrapMode    wrapS           = wrapModes[wrapSNdx].mode;
+                                                                       const tcu::Sampler::WrapMode    wrapT           = wrapModes[wrapTNdx].mode;
+
+                                                                       const string caseName = string() + wrapModes[wrapSNdx].name + "_" + wrapModes[wrapTNdx].name;
+
+                                                                       compareModeGroup->addChild(makeTextureGatherCase(textureType, m_testCtx, caseName.c_str(), "", gatherType, offsetSize, format, compareMode, wrapS, wrapT,
+                                                                                                                                                                        MaybeTextureSwizzle::createNoneTextureSwizzle(), tcu::Sampler::NEAREST, tcu::Sampler::NEAREST, 0, textureSize,
+                                                                                                                                                                        noCorners ? GATHERCASE_DONT_SAMPLE_CUBE_CORNERS : 0));
+                                                               }
+                                                       }
+                                               }
+                                       }
+
+                                       if (offsetSize != OFFSETSIZE_MINIMUM_REQUIRED || gatherType == GATHERTYPE_OFFSETS) // Don't test all features for both offset size types, as they should be rather orthogonal.
+                                       {
+                                               if (!isDepthFormat(format))
+                                               {
+                                                       TestCaseGroup* const swizzleGroup = new TestCaseGroup(m_testCtx, "texture_swizzle", "");
+                                                       formatGroup->addChild(swizzleGroup);
+
+                                                       DE_STATIC_ASSERT(TEXTURESWIZZLECOMPONENT_R == 0);
+                                                       for (int swizzleCaseNdx = 0; swizzleCaseNdx < TEXTURESWIZZLECOMPONENT_LAST; swizzleCaseNdx++)
+                                                       {
+                                                               MaybeTextureSwizzle     swizzle = MaybeTextureSwizzle::createSomeTextureSwizzle();
+                                                               string                          caseName;
+
+                                                               for (int i = 0; i < 4; i++)
+                                                               {
+                                                                       swizzle.getSwizzle()[i] = (TextureSwizzleComponent)((swizzleCaseNdx + i) % (int)TEXTURESWIZZLECOMPONENT_LAST);
+                                                                       caseName += (i > 0 ? "_" : "") + de::toLower(de::toString(swizzle.getSwizzle()[i]));
+                                                               }
+
+                                                               swizzleGroup->addChild(makeTextureGatherCase(textureType, m_testCtx, caseName.c_str(), "", gatherType, offsetSize, format,
+                                                                                                                                                        tcu::Sampler::COMPAREMODE_NONE, tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL,
+                                                                                                                                                        swizzle, tcu::Sampler::NEAREST, tcu::Sampler::NEAREST, 0, IVec3(64, 64, 3)));
+                                                       }
+                                               }
+
+                                               {
+                                                       TestCaseGroup* const filterModeGroup = new TestCaseGroup(m_testCtx, "filter_mode", "Test that filter modes have no effect");
+                                                       formatGroup->addChild(filterModeGroup);
+
+                                                       const struct
+                                                       {
+                                                               const char*                                     name;
+                                                               tcu::Sampler::FilterMode        filter;
+                                                       } magFilters[] =
+                                                       {
+                                                               { "linear",             tcu::Sampler::LINEAR    },
+                                                               { "nearest",    tcu::Sampler::NEAREST   }
+                                                       };
+
+                                                       const struct
+                                                       {
+                                                               const char*                                     name;
+                                                               tcu::Sampler::FilterMode        filter;
+                                                       } minFilters[] =
+                                                       {
+                                                               // \note Don't test NEAREST here, as it's covered by other cases.
+                                                               { "linear",                                             tcu::Sampler::LINEAR                                    },
+                                                               { "nearest_mipmap_nearest",             tcu::Sampler::NEAREST_MIPMAP_NEAREST    },
+                                                               { "nearest_mipmap_linear",              tcu::Sampler::NEAREST_MIPMAP_LINEAR             },
+                                                               { "linear_mipmap_nearest",              tcu::Sampler::LINEAR_MIPMAP_NEAREST             },
+                                                               { "linear_mipmap_linear",               tcu::Sampler::LINEAR_MIPMAP_LINEAR              },
+                                                       };
+
+                                                       for (int minFilterNdx = 0; minFilterNdx < DE_LENGTH_OF_ARRAY(minFilters); minFilterNdx++)
+                                                       for (int magFilterNdx = 0; magFilterNdx < DE_LENGTH_OF_ARRAY(magFilters); magFilterNdx++)
+                                                       {
+                                                               const tcu::Sampler::FilterMode          minFilter               = minFilters[minFilterNdx].filter;
+                                                               const tcu::Sampler::FilterMode          magFilter               = magFilters[magFilterNdx].filter;
+                                                               const tcu::Sampler::CompareMode         compareMode             = isDepthFormat(format) ? tcu::Sampler::COMPAREMODE_LESS : tcu::Sampler::COMPAREMODE_NONE;
+
+                                                               if ((isUnormFormatType(format.type) || isDepthFormat(format)) && magFilter == tcu::Sampler::NEAREST)
+                                                                       continue; // Covered by other cases.
+                                                               if ((isUIntFormatType(format.type) || isSIntFormatType(format.type)) &&
+                                                                       (magFilter != tcu::Sampler::NEAREST || minFilter != tcu::Sampler::NEAREST_MIPMAP_NEAREST))
+                                                                       continue;
+
+                                                               const string caseName = string() + "min_" + minFilters[minFilterNdx].name + "_mag_" + magFilters[magFilterNdx].name;
+
+                                                               filterModeGroup->addChild(makeTextureGatherCase(textureType, m_testCtx, caseName.c_str(), "", gatherType, offsetSize, format, compareMode,
+                                                                                                                                                               tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL, MaybeTextureSwizzle::createNoneTextureSwizzle(),
+                                                                                                                                                               minFilter, magFilter, 0, IVec3(64, 64, 3)));
+                                                       }
+                                               }
+
+                                               {
+                                                       TestCaseGroup* const baseLevelGroup = new TestCaseGroup(m_testCtx, "base_level", "");
+                                                       formatGroup->addChild(baseLevelGroup);
+
+                                                       for (int baseLevel = 1; baseLevel <= 2; baseLevel++)
+                                                       {
+                                                               const string                                            caseName                = "level_" + de::toString(baseLevel);
+                                                               const tcu::Sampler::CompareMode         compareMode             = isDepthFormat(format) ? tcu::Sampler::COMPAREMODE_LESS : tcu::Sampler::COMPAREMODE_NONE;
+                                                               baseLevelGroup->addChild(makeTextureGatherCase(textureType, m_testCtx, caseName.c_str(), "", gatherType, offsetSize, format,
+                                                                                                                                                          compareMode, tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL,
+                                                                                                                                                          MaybeTextureSwizzle::createNoneTextureSwizzle(), tcu::Sampler::NEAREST, tcu::Sampler::NEAREST,
+                                                                                                                                                          baseLevel, IVec3(64, 64, 3)));
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+}
+
+} // anonymous
+
+tcu::TestCaseGroup* createTextureGatherTests (tcu::TestContext& testCtx)
+{
+       return new TextureGatherTests(testCtx);
+}
+
+} // sr
+} // vkt
diff --git a/external/vulkancts/modules/vulkan/shaderrender/vktShaderRenderTextureGatherTests.hpp b/external/vulkancts/modules/vulkan/shaderrender/vktShaderRenderTextureGatherTests.hpp
new file mode 100644 (file)
index 0000000..418064f
--- /dev/null
@@ -0,0 +1,41 @@
+#ifndef _VKTSHADERRENDERTEXTUREGATHERTESTS_HPP
+#define _VKTSHADERRENDERTEXTUREGATHERTESTS_HPP
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2016 The Khronos Group Inc.
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *//*!
+ * \file
+ * \brief GLSL textureGather[Offset[s]] tests.
+ *//*--------------------------------------------------------------------*/
+
+#include "tcuDefs.hpp"
+#include "tcuTestCase.hpp"
+
+namespace vkt
+{
+namespace sr
+{
+
+tcu::TestCaseGroup*    createTextureGatherTests        (tcu::TestContext& testCtx);
+
+} // sr
+} // vkt
+
+#endif // _VKTSHADERRENDERTEXTUREGATHERTESTS_HPP
index fb25cae..e4fefcb 100644 (file)
@@ -54,6 +54,7 @@
 #include "vktShaderRenderStructTests.hpp"
 #include "vktShaderRenderSwitchTests.hpp"
 #include "vktShaderRenderTextureFunctionTests.hpp"
+#include "vktShaderRenderTextureGatherTests.hpp"
 #include "vktShaderBuiltinTests.hpp"
 #include "vktOpaqueTypeIndexingTests.hpp"
 #include "vktUniformBlockTests.hpp"
@@ -340,6 +341,7 @@ void createGlslTests (tcu::TestCaseGroup* glslTests)
        glslTests->addChild(sr::createStructTests                       (testCtx));
        glslTests->addChild(sr::createSwitchTests                       (testCtx));
        glslTests->addChild(sr::createTextureFunctionTests      (testCtx));
+       glslTests->addChild(sr::createTextureGatherTests        (testCtx));
 
        // ShaderExecutor-based tests
        glslTests->addChild(shaderexecutor::createBuiltinTests                          (testCtx));