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