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