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