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