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