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