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