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