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