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