--- /dev/null
+/*------------------------------------------------------------------------
+ * 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