• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 3.1 Module
3  * -------------------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief GLSL textureGather[Offset[s]] tests.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "es31fTextureGatherTests.hpp"
25 #include "glsTextureTestUtil.hpp"
26 #include "gluShaderProgram.hpp"
27 #include "gluTexture.hpp"
28 #include "gluDrawUtil.hpp"
29 #include "gluPixelTransfer.hpp"
30 #include "gluTextureUtil.hpp"
31 #include "gluStrUtil.hpp"
32 #include "gluObjectWrapper.hpp"
33 #include "tcuTextureUtil.hpp"
34 #include "tcuSurface.hpp"
35 #include "tcuTestLog.hpp"
36 #include "tcuVectorUtil.hpp"
37 #include "tcuTexLookupVerifier.hpp"
38 #include "tcuTexCompareVerifier.hpp"
39 #include "tcuCommandLine.hpp"
40 #include "deUniquePtr.hpp"
41 #include "deStringUtil.hpp"
42 #include "deRandom.hpp"
43 #include "deString.h"
44 
45 #include "glwEnums.hpp"
46 #include "glwFunctions.hpp"
47 
48 using glu::ShaderProgram;
49 using tcu::ConstPixelBufferAccess;
50 using tcu::PixelBufferAccess;
51 using tcu::TestLog;
52 using tcu::IVec2;
53 using tcu::IVec3;
54 using tcu::IVec4;
55 using tcu::UVec4;
56 using tcu::Vec2;
57 using tcu::Vec3;
58 using tcu::Vec4;
59 using de::MovePtr;
60 
61 using std::string;
62 using std::vector;
63 
64 namespace deqp
65 {
66 
67 using glu::TextureTestUtil::TextureType;
68 using glu::TextureTestUtil::TEXTURETYPE_2D;
69 using glu::TextureTestUtil::TEXTURETYPE_2D_ARRAY;
70 using glu::TextureTestUtil::TEXTURETYPE_CUBE;
71 
72 namespace gles31
73 {
74 namespace Functional
75 {
76 
77 namespace
78 {
79 
80 // Round-to-zero int division, because pre-c++11 it's somewhat implementation-defined for negative values.
divRoundToZero(int a,int b)81 static inline int divRoundToZero (int a, int b)
82 {
83 	return de::abs(a) / de::abs(b) * deSign32(a) * deSign32(b);
84 }
85 
fillWithRandomColorTiles(const PixelBufferAccess & dst,const Vec4 & minVal,const Vec4 & maxVal,deUint32 seed)86 static void fillWithRandomColorTiles (const PixelBufferAccess& dst, const Vec4& minVal, const Vec4& maxVal, deUint32 seed)
87 {
88 	const int	numCols		= dst.getWidth()  >= 7 ? 7 : dst.getWidth();
89 	const int	numRows		= dst.getHeight() >= 5 ? 5 : dst.getHeight();
90 	de::Random	rnd			(seed);
91 
92 	for (int slice = 0; slice < dst.getDepth(); slice++)
93 	for (int row = 0; row < numRows; row++)
94 	for (int col = 0; col < numCols; col++)
95 	{
96 		const int	yBegin	= (row+0)*dst.getHeight()/numRows;
97 		const int	yEnd	= (row+1)*dst.getHeight()/numRows;
98 		const int	xBegin	= (col+0)*dst.getWidth()/numCols;
99 		const int	xEnd	= (col+1)*dst.getWidth()/numCols;
100 		Vec4		color;
101 		for (int i = 0; i < 4; i++)
102 			color[i] = rnd.getFloat(minVal[i], maxVal[i]);
103 		tcu::clear(tcu::getSubregion(dst, xBegin, yBegin, slice, xEnd-xBegin, yEnd-yBegin, 1), color);
104 	}
105 }
106 
isDepthFormat(const tcu::TextureFormat & fmt)107 static inline bool isDepthFormat (const tcu::TextureFormat& fmt)
108 {
109 	return fmt.order == tcu::TextureFormat::D || fmt.order == tcu::TextureFormat::DS;
110 }
111 
isUnormFormatType(tcu::TextureFormat::ChannelType type)112 static inline bool isUnormFormatType (tcu::TextureFormat::ChannelType type)
113 {
114 	return type == tcu::TextureFormat::UNORM_INT8	||
115 		   type == tcu::TextureFormat::UNORM_INT16	||
116 		   type == tcu::TextureFormat::UNORM_INT32;
117 }
118 
isSIntFormatType(tcu::TextureFormat::ChannelType type)119 static inline bool isSIntFormatType (tcu::TextureFormat::ChannelType type)
120 {
121 	return type == tcu::TextureFormat::SIGNED_INT8	||
122 		   type == tcu::TextureFormat::SIGNED_INT16	||
123 		   type == tcu::TextureFormat::SIGNED_INT32;
124 }
125 
isUIntFormatType(tcu::TextureFormat::ChannelType type)126 static inline bool isUIntFormatType (tcu::TextureFormat::ChannelType type)
127 {
128 	return type == tcu::TextureFormat::UNSIGNED_INT8	||
129 		   type == tcu::TextureFormat::UNSIGNED_INT16	||
130 		   type == tcu::TextureFormat::UNSIGNED_INT32;
131 }
132 
getPixels(const glu::RenderContext & renderCtx,const IVec2 & size,const tcu::TextureFormat & colorBufferFormat)133 static tcu::TextureLevel getPixels (const glu::RenderContext& renderCtx, const IVec2& size, const tcu::TextureFormat& colorBufferFormat)
134 {
135 	tcu::TextureLevel result(colorBufferFormat, size.x(), size.y());
136 
137 	// only a few pixel formats are guaranteed to be valid targets for readPixels, convert the rest
138 	if (colorBufferFormat.order == tcu::TextureFormat::RGBA &&
139 		(colorBufferFormat.type == tcu::TextureFormat::UNORM_INT8	||
140 		 colorBufferFormat.type == tcu::TextureFormat::SIGNED_INT32	||
141 		 colorBufferFormat.type == tcu::TextureFormat::UNSIGNED_INT32))
142 	{
143 		// valid as is
144 		glu::readPixels(renderCtx, 0, 0, result.getAccess());
145 	}
146 	else if (colorBufferFormat.order == tcu::TextureFormat::RGBA &&
147 			 (isSIntFormatType(colorBufferFormat.type) ||
148 			  isUIntFormatType(colorBufferFormat.type)))
149 	{
150 		// signed and unsigned integers must be read using 32-bit values
151 		const bool			isSigned	= isSIntFormatType(colorBufferFormat.type);
152 		tcu::TextureLevel	readResult	(tcu::TextureFormat(tcu::TextureFormat::RGBA,
153 														    (isSigned) ? (tcu::TextureFormat::SIGNED_INT32) : (tcu::TextureFormat::UNSIGNED_INT32)),
154 										 size.x(),
155 										 size.y());
156 
157 		glu::readPixels(renderCtx, 0, 0, readResult.getAccess());
158 		tcu::copy(result.getAccess(), readResult.getAccess());
159 	}
160 	else
161 	{
162 		// unreadable format
163 		DE_ASSERT(false);
164 	}
165 
166 	return result;
167 }
168 
169 enum TextureSwizzleComponent
170 {
171 	TEXTURESWIZZLECOMPONENT_R = 0,
172 	TEXTURESWIZZLECOMPONENT_G,
173 	TEXTURESWIZZLECOMPONENT_B,
174 	TEXTURESWIZZLECOMPONENT_A,
175 	TEXTURESWIZZLECOMPONENT_ZERO,
176 	TEXTURESWIZZLECOMPONENT_ONE,
177 
178 	TEXTURESWIZZLECOMPONENT_LAST
179 };
180 
operator <<(std::ostream & stream,TextureSwizzleComponent comp)181 static std::ostream& operator<< (std::ostream& stream, TextureSwizzleComponent comp)
182 {
183 	switch (comp)
184 	{
185 		case TEXTURESWIZZLECOMPONENT_R:		return stream << "RED";
186 		case TEXTURESWIZZLECOMPONENT_G:		return stream << "GREEN";
187 		case TEXTURESWIZZLECOMPONENT_B:		return stream << "BLUE";
188 		case TEXTURESWIZZLECOMPONENT_A:		return stream << "ALPHA";
189 		case TEXTURESWIZZLECOMPONENT_ZERO:	return stream << "ZERO";
190 		case TEXTURESWIZZLECOMPONENT_ONE:	return stream << "ONE";
191 		default: DE_ASSERT(false); return stream;
192 	}
193 }
194 
195 struct MaybeTextureSwizzle
196 {
197 public:
198 	static MaybeTextureSwizzle						createNoneTextureSwizzle	(void);
199 	static MaybeTextureSwizzle						createSomeTextureSwizzle	(void);
200 
201 	bool											isSome						(void) const;
202 	bool											isNone						(void) const;
203 	bool											isIdentitySwizzle			(void) const;
204 
205 	tcu::Vector<TextureSwizzleComponent, 4>&		getSwizzle					(void);
206 	const tcu::Vector<TextureSwizzleComponent, 4>&	getSwizzle					(void) const;
207 
208 private:
209 													MaybeTextureSwizzle			(void);
210 
211 	tcu::Vector<TextureSwizzleComponent, 4>			m_swizzle;
212 	bool											m_isSome;
213 };
214 
operator <<(std::ostream & stream,const MaybeTextureSwizzle & comp)215 static std::ostream& operator<< (std::ostream& stream, const MaybeTextureSwizzle& comp)
216 {
217 	if (comp.isNone())
218 		stream << "[default swizzle state]";
219 	else
220 		stream << "(" << comp.getSwizzle()[0]
221 			   << ", " << comp.getSwizzle()[1]
222 			   << ", " << comp.getSwizzle()[2]
223 			   << ", " << comp.getSwizzle()[3]
224 			   << ")";
225 
226 	return stream;
227 }
228 
createNoneTextureSwizzle(void)229 MaybeTextureSwizzle MaybeTextureSwizzle::createNoneTextureSwizzle (void)
230 {
231 	MaybeTextureSwizzle swizzle;
232 
233 	swizzle.m_swizzle[0] = TEXTURESWIZZLECOMPONENT_LAST;
234 	swizzle.m_swizzle[1] = TEXTURESWIZZLECOMPONENT_LAST;
235 	swizzle.m_swizzle[2] = TEXTURESWIZZLECOMPONENT_LAST;
236 	swizzle.m_swizzle[3] = TEXTURESWIZZLECOMPONENT_LAST;
237 	swizzle.m_isSome = false;
238 
239 	return swizzle;
240 }
241 
createSomeTextureSwizzle(void)242 MaybeTextureSwizzle MaybeTextureSwizzle::createSomeTextureSwizzle (void)
243 {
244 	MaybeTextureSwizzle swizzle;
245 
246 	swizzle.m_swizzle[0] = TEXTURESWIZZLECOMPONENT_R;
247 	swizzle.m_swizzle[1] = TEXTURESWIZZLECOMPONENT_G;
248 	swizzle.m_swizzle[2] = TEXTURESWIZZLECOMPONENT_B;
249 	swizzle.m_swizzle[3] = TEXTURESWIZZLECOMPONENT_A;
250 	swizzle.m_isSome = true;
251 
252 	return swizzle;
253 }
254 
isSome(void) const255 bool MaybeTextureSwizzle::isSome (void) const
256 {
257 	return m_isSome;
258 }
259 
isNone(void) const260 bool MaybeTextureSwizzle::isNone (void) const
261 {
262 	return !m_isSome;
263 }
264 
isIdentitySwizzle(void) const265 bool MaybeTextureSwizzle::isIdentitySwizzle (void) const
266 {
267 	return	m_isSome									&&
268 			m_swizzle[0] == TEXTURESWIZZLECOMPONENT_R	&&
269 			m_swizzle[1] == TEXTURESWIZZLECOMPONENT_G	&&
270 			m_swizzle[2] == TEXTURESWIZZLECOMPONENT_B	&&
271 			m_swizzle[3] == TEXTURESWIZZLECOMPONENT_A;
272 }
273 
getSwizzle(void)274 tcu::Vector<TextureSwizzleComponent, 4>& MaybeTextureSwizzle::getSwizzle (void)
275 {
276 	return m_swizzle;
277 }
278 
getSwizzle(void) const279 const tcu::Vector<TextureSwizzleComponent, 4>& MaybeTextureSwizzle::getSwizzle (void) const
280 {
281 	return m_swizzle;
282 }
283 
MaybeTextureSwizzle(void)284 MaybeTextureSwizzle::MaybeTextureSwizzle (void)
285 	: m_swizzle	(TEXTURESWIZZLECOMPONENT_LAST, TEXTURESWIZZLECOMPONENT_LAST, TEXTURESWIZZLECOMPONENT_LAST, TEXTURESWIZZLECOMPONENT_LAST)
286 	, m_isSome	(false)
287 {
288 }
289 
getGLTextureSwizzleComponent(TextureSwizzleComponent c)290 static deUint32 getGLTextureSwizzleComponent (TextureSwizzleComponent c)
291 {
292 	switch (c)
293 	{
294 		case TEXTURESWIZZLECOMPONENT_R:		return GL_RED;
295 		case TEXTURESWIZZLECOMPONENT_G:		return GL_GREEN;
296 		case TEXTURESWIZZLECOMPONENT_B:		return GL_BLUE;
297 		case TEXTURESWIZZLECOMPONENT_A:		return GL_ALPHA;
298 		case TEXTURESWIZZLECOMPONENT_ZERO:	return GL_ZERO;
299 		case TEXTURESWIZZLECOMPONENT_ONE:	return GL_ONE;
300 		default: DE_ASSERT(false); return (deUint32)-1;
301 	}
302 }
303 
304 template <typename T>
swizzleColorChannel(const tcu::Vector<T,4> & src,TextureSwizzleComponent swizzle)305 static inline T swizzleColorChannel (const tcu::Vector<T, 4>& src, TextureSwizzleComponent swizzle)
306 {
307 	switch (swizzle)
308 	{
309 		case TEXTURESWIZZLECOMPONENT_R:		return src[0];
310 		case TEXTURESWIZZLECOMPONENT_G:		return src[1];
311 		case TEXTURESWIZZLECOMPONENT_B:		return src[2];
312 		case TEXTURESWIZZLECOMPONENT_A:		return src[3];
313 		case TEXTURESWIZZLECOMPONENT_ZERO:	return (T)0;
314 		case TEXTURESWIZZLECOMPONENT_ONE:	return (T)1;
315 		default: DE_ASSERT(false); return (T)-1;
316 	}
317 }
318 
319 template <typename T>
swizzleColor(const tcu::Vector<T,4> & src,const MaybeTextureSwizzle & swizzle)320 static inline tcu::Vector<T, 4> swizzleColor (const tcu::Vector<T, 4>& src, const MaybeTextureSwizzle& swizzle)
321 {
322 	DE_ASSERT(swizzle.isSome());
323 
324 	tcu::Vector<T, 4> result;
325 	for (int i = 0; i < 4; i++)
326 		result[i] = swizzleColorChannel(src, swizzle.getSwizzle()[i]);
327 	return result;
328 }
329 
330 template <typename T>
swizzlePixels(const PixelBufferAccess & dst,const ConstPixelBufferAccess & src,const MaybeTextureSwizzle & swizzle)331 static void swizzlePixels (const PixelBufferAccess& dst, const ConstPixelBufferAccess& src, const MaybeTextureSwizzle& swizzle)
332 {
333 	DE_ASSERT(dst.getWidth()  == src.getWidth()  &&
334 			  dst.getHeight() == src.getHeight() &&
335 			  dst.getDepth()  == src.getDepth());
336 	for (int z = 0; z < src.getDepth(); z++)
337 	for (int y = 0; y < src.getHeight(); y++)
338 	for (int x = 0; x < src.getWidth(); x++)
339 		dst.setPixel(swizzleColor(src.getPixelT<T>(x, y, z), swizzle), x, y, z);
340 }
341 
swizzlePixels(const PixelBufferAccess & dst,const ConstPixelBufferAccess & src,const MaybeTextureSwizzle & swizzle)342 static void swizzlePixels (const PixelBufferAccess& dst, const ConstPixelBufferAccess& src, const MaybeTextureSwizzle& swizzle)
343 {
344 	if (isDepthFormat(dst.getFormat()))
345 		DE_ASSERT(swizzle.isNone() || swizzle.isIdentitySwizzle());
346 
347 	if (swizzle.isNone() || swizzle.isIdentitySwizzle())
348 		tcu::copy(dst, src);
349 	else if (isUnormFormatType(dst.getFormat().type))
350 		swizzlePixels<float>(dst, src, swizzle);
351 	else if (isUIntFormatType(dst.getFormat().type))
352 		swizzlePixels<deUint32>(dst, src, swizzle);
353 	else if (isSIntFormatType(dst.getFormat().type))
354 		swizzlePixels<deInt32>(dst, src, swizzle);
355 	else
356 		DE_ASSERT(false);
357 }
358 
swizzleTexture(tcu::Texture2D & dst,const tcu::Texture2D & src,const MaybeTextureSwizzle & swizzle)359 static void swizzleTexture (tcu::Texture2D& dst, const tcu::Texture2D& src, const MaybeTextureSwizzle& swizzle)
360 {
361 	dst = tcu::Texture2D(src.getFormat(), src.getWidth(), src.getHeight());
362 	for (int levelNdx = 0; levelNdx < src.getNumLevels(); levelNdx++)
363 	{
364 		if (src.isLevelEmpty(levelNdx))
365 			continue;
366 		dst.allocLevel(levelNdx);
367 		swizzlePixels(dst.getLevel(levelNdx), src.getLevel(levelNdx), swizzle);
368 	}
369 }
370 
swizzleTexture(tcu::Texture2DArray & dst,const tcu::Texture2DArray & src,const MaybeTextureSwizzle & swizzle)371 static void swizzleTexture (tcu::Texture2DArray& dst, const tcu::Texture2DArray& src, const MaybeTextureSwizzle& swizzle)
372 {
373 	dst = tcu::Texture2DArray(src.getFormat(), src.getWidth(), src.getHeight(), src.getNumLayers());
374 	for (int levelNdx = 0; levelNdx < src.getNumLevels(); levelNdx++)
375 	{
376 		if (src.isLevelEmpty(levelNdx))
377 			continue;
378 		dst.allocLevel(levelNdx);
379 		swizzlePixels(dst.getLevel(levelNdx), src.getLevel(levelNdx), swizzle);
380 	}
381 }
382 
swizzleTexture(tcu::TextureCube & dst,const tcu::TextureCube & src,const MaybeTextureSwizzle & swizzle)383 static void swizzleTexture (tcu::TextureCube& dst, const tcu::TextureCube& src, const MaybeTextureSwizzle& swizzle)
384 {
385 	dst = tcu::TextureCube(src.getFormat(), src.getSize());
386 	for (int faceI = 0; faceI < tcu::CUBEFACE_LAST; faceI++)
387 	{
388 		const tcu::CubeFace face = (tcu::CubeFace)faceI;
389 		for (int levelNdx = 0; levelNdx < src.getNumLevels(); levelNdx++)
390 		{
391 			if (src.isLevelEmpty(face, levelNdx))
392 				continue;
393 			dst.allocLevel(face, levelNdx);
394 			swizzlePixels(dst.getLevelFace(levelNdx, face), src.getLevelFace(levelNdx, face), swizzle);
395 		}
396 	}
397 }
398 
getOneLevelSubView(const tcu::Texture2DView & view,int level)399 static tcu::Texture2DView getOneLevelSubView (const tcu::Texture2DView& view, int level)
400 {
401 	return tcu::Texture2DView(1, view.getLevels() + level);
402 }
403 
getOneLevelSubView(const tcu::Texture2DArrayView & view,int level)404 static tcu::Texture2DArrayView getOneLevelSubView (const tcu::Texture2DArrayView& view, int level)
405 {
406 	return tcu::Texture2DArrayView(1, view.getLevels() + level);
407 }
408 
getOneLevelSubView(const tcu::TextureCubeView & view,int level)409 static tcu::TextureCubeView getOneLevelSubView (const tcu::TextureCubeView& view, int level)
410 {
411 	const tcu::ConstPixelBufferAccess* levels[tcu::CUBEFACE_LAST];
412 
413 	for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
414 		levels[face] = view.getFaceLevels((tcu::CubeFace)face) + level;
415 
416 	return tcu::TextureCubeView(1, levels);
417 }
418 
419 class PixelOffsets
420 {
421 public:
422 	virtual void operator() (const IVec2& pixCoord, IVec2 (&dst)[4]) const = 0;
~PixelOffsets(void)423 	virtual ~PixelOffsets (void) {}
424 };
425 
426 class MultiplePixelOffsets : public PixelOffsets
427 {
428 public:
MultiplePixelOffsets(const IVec2 & a,const IVec2 & b,const IVec2 & c,const IVec2 & d)429 	MultiplePixelOffsets (const IVec2& a,
430 						  const IVec2& b,
431 						  const IVec2& c,
432 						  const IVec2& d)
433 	{
434 		m_offsets[0] = a;
435 		m_offsets[1] = b;
436 		m_offsets[2] = c;
437 		m_offsets[3] = d;
438 	}
439 
operator ()(const IVec2 &,IVec2 (& dst)[4]) const440 	void operator() (const IVec2& /* pixCoord */, IVec2 (&dst)[4]) const
441 	{
442 		for (int i = 0; i < DE_LENGTH_OF_ARRAY(dst); i++)
443 			dst[i] = m_offsets[i];
444 	}
445 
446 private:
447 	IVec2 m_offsets[4];
448 };
449 
450 class SinglePixelOffsets : public MultiplePixelOffsets
451 {
452 public:
SinglePixelOffsets(const IVec2 & offset)453 	SinglePixelOffsets (const IVec2& offset)
454 		: MultiplePixelOffsets(offset + IVec2(0, 1),
455 							   offset + IVec2(1, 1),
456 							   offset + IVec2(1, 0),
457 							   offset + IVec2(0, 0))
458 	{
459 	}
460 };
461 
462 class DynamicSinglePixelOffsets : public PixelOffsets
463 {
464 public:
DynamicSinglePixelOffsets(const IVec2 & offsetRange)465 	DynamicSinglePixelOffsets (const IVec2& offsetRange) : m_offsetRange(offsetRange) {}
466 
operator ()(const IVec2 & pixCoord,IVec2 (& dst)[4]) const467 	void operator() (const IVec2& pixCoord, IVec2 (&dst)[4]) const
468 	{
469 		const int offsetRangeSize = m_offsetRange.y() - m_offsetRange.x() + 1;
470 		SinglePixelOffsets(tcu::mod(pixCoord.swizzle(1,0), IVec2(offsetRangeSize)) + m_offsetRange.x())(IVec2(), dst);
471 	}
472 
473 private:
474 	IVec2 m_offsetRange;
475 };
476 
477 template <typename T>
triQuadInterpolate(const T (& values)[4],float xFactor,float yFactor)478 static inline T triQuadInterpolate (const T (&values)[4], float xFactor, float yFactor)
479 {
480 	if (xFactor + yFactor < 1.0f)
481 		return values[0] + (values[2]-values[0])*xFactor		+ (values[1]-values[0])*yFactor;
482 	else
483 		return values[3] + (values[1]-values[3])*(1.0f-xFactor)	+ (values[2]-values[3])*(1.0f-yFactor);
484 }
485 
486 template <int N>
computeTexCoordVecs(const vector<float> & texCoords,tcu::Vector<float,N> (& dst)[4])487 static inline void computeTexCoordVecs (const vector<float>& texCoords, tcu::Vector<float, N> (&dst)[4])
488 {
489 	DE_ASSERT((int)texCoords.size() == 4*N);
490 	for (int i = 0; i < 4; i++)
491 	for (int j = 0; j < N; j++)
492 		dst[i][j] = texCoords[i*N + j];
493 }
494 
495 #if defined(DE_DEBUG)
496 // Whether offsets correspond to the sample offsets used with plain textureGather().
isZeroOffsetOffsets(const IVec2 (& offsets)[4])497 static inline bool isZeroOffsetOffsets (const IVec2 (&offsets)[4])
498 {
499 	IVec2 ref[4];
500 	SinglePixelOffsets(IVec2(0))(IVec2(), ref);
501 	return std::equal(DE_ARRAY_BEGIN(offsets),
502 					  DE_ARRAY_END(offsets),
503 					  DE_ARRAY_BEGIN(ref));
504 }
505 #endif
506 
507 template <typename ColorScalarType>
gatherOffsets(const tcu::Texture2DView & texture,const tcu::Sampler & sampler,const Vec2 & coord,int componentNdx,const IVec2 (& offsets)[4])508 static tcu::Vector<ColorScalarType, 4> gatherOffsets (const tcu::Texture2DView& texture, const tcu::Sampler& sampler, const Vec2& coord, int componentNdx, const IVec2 (&offsets)[4])
509 {
510 	return texture.gatherOffsets(sampler, coord.x(), coord.y(), componentNdx, offsets).cast<ColorScalarType>();
511 }
512 
513 template <typename ColorScalarType>
gatherOffsets(const tcu::Texture2DArrayView & texture,const tcu::Sampler & sampler,const Vec3 & coord,int componentNdx,const IVec2 (& offsets)[4])514 static tcu::Vector<ColorScalarType, 4> gatherOffsets (const tcu::Texture2DArrayView& texture, const tcu::Sampler& sampler, const Vec3& coord, int componentNdx, const IVec2 (&offsets)[4])
515 {
516 	return texture.gatherOffsets(sampler, coord.x(), coord.y(), coord.z(), componentNdx, offsets).cast<ColorScalarType>();
517 }
518 
519 template <typename ColorScalarType>
gatherOffsets(const tcu::TextureCubeView & texture,const tcu::Sampler & sampler,const Vec3 & coord,int componentNdx,const IVec2 (& offsets)[4])520 static tcu::Vector<ColorScalarType, 4> gatherOffsets (const tcu::TextureCubeView& texture, const tcu::Sampler& sampler, const Vec3& coord, int componentNdx, const IVec2 (&offsets)[4])
521 {
522 	DE_ASSERT(isZeroOffsetOffsets(offsets));
523 	DE_UNREF(offsets);
524 	return texture.gather(sampler, coord.x(), coord.y(), coord.z(), componentNdx).cast<ColorScalarType>();
525 }
526 
gatherOffsetsCompare(const tcu::Texture2DView & texture,const tcu::Sampler & sampler,float refZ,const Vec2 & coord,const IVec2 (& offsets)[4])527 static Vec4 gatherOffsetsCompare (const tcu::Texture2DView& texture, const tcu::Sampler& sampler, float refZ, const Vec2& coord, const IVec2 (&offsets)[4])
528 {
529 	return texture.gatherOffsetsCompare(sampler, refZ, coord.x(), coord.y(), offsets);
530 }
531 
gatherOffsetsCompare(const tcu::Texture2DArrayView & texture,const tcu::Sampler & sampler,float refZ,const Vec3 & coord,const IVec2 (& offsets)[4])532 static Vec4 gatherOffsetsCompare (const tcu::Texture2DArrayView& texture, const tcu::Sampler& sampler, float refZ, const Vec3& coord, const IVec2 (&offsets)[4])
533 {
534 	return texture.gatherOffsetsCompare(sampler, refZ, coord.x(), coord.y(), coord.z(), offsets);
535 }
536 
gatherOffsetsCompare(const tcu::TextureCubeView & texture,const tcu::Sampler & sampler,float refZ,const Vec3 & coord,const IVec2 (& offsets)[4])537 static Vec4 gatherOffsetsCompare (const tcu::TextureCubeView& texture, const tcu::Sampler& sampler, float refZ, const Vec3& coord, const IVec2 (&offsets)[4])
538 {
539 	DE_ASSERT(isZeroOffsetOffsets(offsets));
540 	DE_UNREF(offsets);
541 	return texture.gatherCompare(sampler, refZ, coord.x(), coord.y(), coord.z());
542 }
543 
544 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)545 static bool isGatherOffsetsResultValid (const tcu::TextureCubeView&				texture,
546 										const tcu::Sampler&						sampler,
547 										const PrecType&							prec,
548 										const Vec3&								coord,
549 										int										componentNdx,
550 										const IVec2								(&offsets)[4],
551 										const tcu::Vector<ColorScalarT, 4>&		result)
552 {
553 	DE_ASSERT(isZeroOffsetOffsets(offsets));
554 	DE_UNREF(offsets);
555 	return tcu::isGatherResultValid(texture, sampler, prec, coord, componentNdx, result);
556 }
557 
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)558 static bool isGatherOffsetsCompareResultValid (const tcu::TextureCubeView&		texture,
559 											   const tcu::Sampler&				sampler,
560 											   const tcu::TexComparePrecision&	prec,
561 											   const Vec3&						coord,
562 											   const IVec2						(&offsets)[4],
563 											   float							cmpReference,
564 											   const Vec4&						result)
565 {
566 	DE_ASSERT(isZeroOffsetOffsets(offsets));
567 	DE_UNREF(offsets);
568 	return tcu::isGatherCompareResultValid(texture, sampler, prec, coord, cmpReference, result);
569 }
570 
571 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)572 static bool verifyGatherOffsets (TestLog&						log,
573 								 const ConstPixelBufferAccess&	result,
574 								 const TexViewT&				texture,
575 								 const TexCoordT				(&texCoords)[4],
576 								 const tcu::Sampler&			sampler,
577 								 const PrecType&				lookupPrec,
578 								 int							componentNdx,
579 								 const PixelOffsets&			getPixelOffsets)
580 {
581 	typedef tcu::Vector<ColorScalarType, 4> ColorVec;
582 
583 	const int					width			= result.getWidth();
584 	const int					height			= result.getWidth();
585 	tcu::TextureLevel			ideal			(result.getFormat(), width, height);
586 	const PixelBufferAccess		idealAccess		= ideal.getAccess();
587 	tcu::Surface				errorMask		(width, height);
588 	bool						success			= true;
589 
590 	tcu::clear(errorMask.getAccess(), tcu::RGBA::green().toVec());
591 
592 	for (int py = 0; py < height; py++)
593 	for (int px = 0; px < width; px++)
594 	{
595 		IVec2		offsets[4];
596 		getPixelOffsets(IVec2(px, py), offsets);
597 
598 		const Vec2			viewportCoord	= (Vec2((float)px, (float)py) + 0.5f) / Vec2((float)width, (float)height);
599 		const TexCoordT		texCoord		= triQuadInterpolate(texCoords, viewportCoord.x(), viewportCoord.y());
600 		const ColorVec		resultPix		= result.getPixelT<ColorScalarType>(px, py);
601 		const ColorVec		idealPix		= gatherOffsets<ColorScalarType>(texture, sampler, texCoord, componentNdx, offsets);
602 
603 		idealAccess.setPixel(idealPix, px, py);
604 
605 		if (tcu::boolAny(tcu::logicalAnd(lookupPrec.colorMask,
606 										 tcu::greaterThan(tcu::absDiff(resultPix, idealPix),
607 														  lookupPrec.colorThreshold.template cast<ColorScalarType>()))))
608 		{
609 			if (!isGatherOffsetsResultValid(texture, sampler, lookupPrec, texCoord, componentNdx, offsets, resultPix))
610 			{
611 				errorMask.setPixel(px, py, tcu::RGBA::red());
612 				success = false;
613 			}
614 		}
615 	}
616 
617 	log << TestLog::ImageSet("VerifyResult", "Verification result")
618 		<< TestLog::Image("Rendered", "Rendered image", result);
619 
620 	if (!success)
621 	{
622 		log << TestLog::Image("Reference", "Ideal reference image", ideal)
623 			<< TestLog::Image("ErrorMask", "Error mask", errorMask);
624 	}
625 
626 	log << TestLog::EndImageSet;
627 
628 	return success;
629 }
630 
631 class PixelCompareRefZ
632 {
633 public:
634 	virtual float operator() (const IVec2& pixCoord) const = 0;
635 };
636 
637 class PixelCompareRefZDefault : public PixelCompareRefZ
638 {
639 public:
PixelCompareRefZDefault(const IVec2 & renderSize)640 	PixelCompareRefZDefault (const IVec2& renderSize) : m_renderSize(renderSize) {}
641 
operator ()(const IVec2 & pixCoord) const642 	float operator() (const IVec2& pixCoord) const
643 	{
644 		return ((float)pixCoord.x() + 0.5f) / (float)m_renderSize.x();
645 	}
646 
647 private:
648 	IVec2 m_renderSize;
649 };
650 
651 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)652 static bool verifyGatherOffsetsCompare (TestLog&							log,
653 										const ConstPixelBufferAccess&		result,
654 										const TexViewT&						texture,
655 										const TexCoordT						(&texCoords)[4],
656 										const tcu::Sampler&					sampler,
657 										const tcu::TexComparePrecision&		compPrec,
658 										const PixelCompareRefZ&				getPixelRefZ,
659 										const PixelOffsets&					getPixelOffsets)
660 {
661 	const int					width			= result.getWidth();
662 	const int					height			= result.getWidth();
663 	tcu::Surface				ideal			(width, height);
664 	const PixelBufferAccess		idealAccess		= ideal.getAccess();
665 	tcu::Surface				errorMask		(width, height);
666 	bool						success			= true;
667 
668 	tcu::clear(errorMask.getAccess(), tcu::RGBA::green().toVec());
669 
670 	for (int py = 0; py < height; py++)
671 	for (int px = 0; px < width; px++)
672 	{
673 		IVec2		offsets[4];
674 		getPixelOffsets(IVec2(px, py), offsets);
675 
676 		const Vec2			viewportCoord	= (Vec2((float)px, (float)py) + 0.5f) / Vec2((float)width, (float)height);
677 		const TexCoordT		texCoord		= triQuadInterpolate(texCoords, viewportCoord.x(), viewportCoord.y());
678 		const float			refZ			= getPixelRefZ(IVec2(px, py));
679 		const Vec4			resultPix		= result.getPixel(px, py);
680 		const Vec4			idealPix		= gatherOffsetsCompare(texture, sampler, refZ, texCoord, offsets);
681 
682 		idealAccess.setPixel(idealPix, px, py);
683 
684 		if (!tcu::boolAll(tcu::equal(resultPix, idealPix)))
685 		{
686 			if (!isGatherOffsetsCompareResultValid(texture, sampler, compPrec, texCoord, offsets, refZ, resultPix))
687 			{
688 				errorMask.setPixel(px, py, tcu::RGBA::red());
689 				success = false;
690 			}
691 		}
692 	}
693 
694 	log << TestLog::ImageSet("VerifyResult", "Verification result")
695 		<< TestLog::Image("Rendered", "Rendered image", result);
696 
697 	if (!success)
698 	{
699 		log << TestLog::Image("Reference", "Ideal reference image", ideal)
700 			<< TestLog::Image("ErrorMask", "Error mask", errorMask);
701 	}
702 
703 	log << TestLog::EndImageSet;
704 
705 	return success;
706 }
707 
verifySingleColored(TestLog & log,const ConstPixelBufferAccess & result,const Vec4 & refColor)708 static bool verifySingleColored (TestLog& log, const ConstPixelBufferAccess& result, const Vec4& refColor)
709 {
710 	const int					width			= result.getWidth();
711 	const int					height			= result.getWidth();
712 	tcu::Surface				ideal			(width, height);
713 	const PixelBufferAccess		idealAccess		= ideal.getAccess();
714 	tcu::Surface				errorMask		(width, height);
715 	bool						success			= true;
716 
717 	tcu::clear(errorMask.getAccess(), tcu::RGBA::green().toVec());
718 	tcu::clear(idealAccess, refColor);
719 
720 	for (int py = 0; py < height; py++)
721 	for (int px = 0; px < width; px++)
722 	{
723 		if (result.getPixel(px, py) != refColor)
724 		{
725 			errorMask.setPixel(px, py, tcu::RGBA::red());
726 			success = false;
727 		}
728 	}
729 
730 	log << TestLog::ImageSet("VerifyResult", "Verification result")
731 		<< TestLog::Image("Rendered", "Rendered image", result);
732 
733 	if (!success)
734 	{
735 		log << TestLog::Image("Reference", "Ideal reference image", ideal)
736 			<< TestLog::Image("ErrorMask", "Error mask", errorMask);
737 	}
738 
739 	log << TestLog::EndImageSet;
740 
741 	return success;
742 }
743 
744 enum GatherType
745 {
746 	GATHERTYPE_BASIC = 0,
747 	GATHERTYPE_OFFSET,
748 	GATHERTYPE_OFFSET_DYNAMIC,
749 	GATHERTYPE_OFFSETS,
750 
751 	GATHERTYPE_LAST
752 };
753 
754 enum GatherCaseFlags
755 {
756 	GATHERCASE_MIPMAP_INCOMPLETE		= (1<<0),	//!< Excercise special case of sampling mipmap-incomplete texture
757 	GATHERCASE_DONT_SAMPLE_CUBE_CORNERS	= (1<<1)	//!< For cube map cases: do not sample cube corners
758 };
759 
gatherTypeName(GatherType type)760 static inline const char* gatherTypeName (GatherType type)
761 {
762 	switch (type)
763 	{
764 		case GATHERTYPE_BASIC:				return "basic";
765 		case GATHERTYPE_OFFSET:				return "offset";
766 		case GATHERTYPE_OFFSET_DYNAMIC:		return "offset_dynamic";
767 		case GATHERTYPE_OFFSETS:			return "offsets";
768 		default: DE_ASSERT(false); return DE_NULL;
769 	}
770 }
771 
gatherTypeDescription(GatherType type)772 static inline const char* gatherTypeDescription (GatherType type)
773 {
774 	switch (type)
775 	{
776 		case GATHERTYPE_BASIC:				return "textureGather";
777 		case GATHERTYPE_OFFSET:				return "textureGatherOffset";
778 		case GATHERTYPE_OFFSET_DYNAMIC:		return "textureGatherOffset with dynamic offsets";
779 		case GATHERTYPE_OFFSETS:			return "textureGatherOffsets";
780 		default: DE_ASSERT(false); return DE_NULL;
781 	}
782 }
783 
requireGpuShader5(GatherType gatherType)784 static inline bool requireGpuShader5 (GatherType gatherType)
785 {
786 	return gatherType == GATHERTYPE_OFFSET_DYNAMIC || gatherType == GATHERTYPE_OFFSETS;
787 }
788 
789 struct GatherArgs
790 {
791 	int		componentNdx;	// If negative, implicit component index 0 is used (i.e. the parameter is not given).
792 	IVec2	offsets[4];		// \note Unless GATHERTYPE_OFFSETS is used, only offsets[0] is relevant; also, for GATHERTYPE_OFFSET_DYNAMIC, none are relevant.
793 
GatherArgsdeqp::gles31::Functional::__anoneefa1ca30111::GatherArgs794 	GatherArgs (void)
795 		: componentNdx(-1)
796 	{
797 		std::fill(DE_ARRAY_BEGIN(offsets), DE_ARRAY_END(offsets), IVec2());
798 	}
799 
GatherArgsdeqp::gles31::Functional::__anoneefa1ca30111::GatherArgs800 	GatherArgs (int comp,
801 				const IVec2& off0 = IVec2(),
802 				const IVec2& off1 = IVec2(),
803 				const IVec2& off2 = IVec2(),
804 				const IVec2& off3 = IVec2())
805 		: componentNdx(comp)
806 	{
807 		offsets[0] = off0;
808 		offsets[1] = off1;
809 		offsets[2] = off2;
810 		offsets[3] = off3;
811 	}
812 };
813 
makePixelOffsetsFunctor(GatherType gatherType,const GatherArgs & gatherArgs,const IVec2 & offsetRange)814 static MovePtr<PixelOffsets> makePixelOffsetsFunctor (GatherType gatherType, const GatherArgs& gatherArgs, const IVec2& offsetRange)
815 {
816 	if (gatherType == GATHERTYPE_BASIC || gatherType == GATHERTYPE_OFFSET)
817 	{
818 		const IVec2 offset = gatherType == GATHERTYPE_BASIC ? IVec2(0) : gatherArgs.offsets[0];
819 		return MovePtr<PixelOffsets>(new SinglePixelOffsets(offset));
820 	}
821 	else if (gatherType == GATHERTYPE_OFFSET_DYNAMIC)
822 	{
823 		return MovePtr<PixelOffsets>(new DynamicSinglePixelOffsets(offsetRange));
824 	}
825 	else if (gatherType == GATHERTYPE_OFFSETS)
826 		return MovePtr<PixelOffsets>(new MultiplePixelOffsets(gatherArgs.offsets[0],
827 															  gatherArgs.offsets[1],
828 															  gatherArgs.offsets[2],
829 															  gatherArgs.offsets[3]));
830 	else
831 	{
832 		DE_ASSERT(false);
833 		return MovePtr<PixelOffsets>(DE_NULL);
834 	}
835 }
836 
getSamplerType(TextureType textureType,const tcu::TextureFormat & format)837 static inline glu::DataType getSamplerType (TextureType textureType, const tcu::TextureFormat& format)
838 {
839 	if (isDepthFormat(format))
840 	{
841 		switch (textureType)
842 		{
843 			case TEXTURETYPE_2D:		return glu::TYPE_SAMPLER_2D_SHADOW;
844 			case TEXTURETYPE_2D_ARRAY:	return glu::TYPE_SAMPLER_2D_ARRAY_SHADOW;
845 			case TEXTURETYPE_CUBE:		return glu::TYPE_SAMPLER_CUBE_SHADOW;
846 			default: DE_ASSERT(false); return glu::TYPE_LAST;
847 		}
848 	}
849 	else
850 	{
851 		switch (textureType)
852 		{
853 			case TEXTURETYPE_2D:		return glu::getSampler2DType(format);
854 			case TEXTURETYPE_2D_ARRAY:	return glu::getSampler2DArrayType(format);
855 			case TEXTURETYPE_CUBE:		return glu::getSamplerCubeType(format);
856 			default: DE_ASSERT(false); return glu::TYPE_LAST;
857 		}
858 	}
859 }
860 
getSamplerGatherResultType(glu::DataType samplerType)861 static inline glu::DataType getSamplerGatherResultType (glu::DataType samplerType)
862 {
863 	switch (samplerType)
864 	{
865 		case glu::TYPE_SAMPLER_2D_SHADOW:
866 		case glu::TYPE_SAMPLER_2D_ARRAY_SHADOW:
867 		case glu::TYPE_SAMPLER_CUBE_SHADOW:
868 		case glu::TYPE_SAMPLER_2D:
869 		case glu::TYPE_SAMPLER_2D_ARRAY:
870 		case glu::TYPE_SAMPLER_CUBE:
871 			return glu::TYPE_FLOAT_VEC4;
872 
873 		case glu::TYPE_INT_SAMPLER_2D:
874 		case glu::TYPE_INT_SAMPLER_2D_ARRAY:
875 		case glu::TYPE_INT_SAMPLER_CUBE:
876 			return glu::TYPE_INT_VEC4;
877 
878 		case glu::TYPE_UINT_SAMPLER_2D:
879 		case glu::TYPE_UINT_SAMPLER_2D_ARRAY:
880 		case glu::TYPE_UINT_SAMPLER_CUBE:
881 			return glu::TYPE_UINT_VEC4;
882 
883 		default:
884 			DE_ASSERT(false);
885 			return glu::TYPE_LAST;
886 	}
887 }
888 
getNumTextureSamplingDimensions(TextureType type)889 static inline int getNumTextureSamplingDimensions (TextureType type)
890 {
891 	switch (type)
892 	{
893 		case TEXTURETYPE_2D:		return 2;
894 		case TEXTURETYPE_2D_ARRAY:	return 3;
895 		case TEXTURETYPE_CUBE:		return 3;
896 		default: DE_ASSERT(false); return -1;
897 	}
898 }
899 
getGLTextureType(TextureType type)900 static deUint32 getGLTextureType (TextureType type)
901 {
902 	switch (type)
903 	{
904 		case TEXTURETYPE_2D:		return GL_TEXTURE_2D;
905 		case TEXTURETYPE_2D_ARRAY:	return GL_TEXTURE_2D_ARRAY;
906 		case TEXTURETYPE_CUBE:		return GL_TEXTURE_CUBE_MAP;
907 		default: DE_ASSERT(false); return (deUint32)-1;
908 	}
909 }
910 
911 enum OffsetSize
912 {
913 	OFFSETSIZE_NONE = 0,
914 	OFFSETSIZE_MINIMUM_REQUIRED,
915 	OFFSETSIZE_IMPLEMENTATION_MAXIMUM,
916 
917 	OFFSETSIZE_LAST
918 };
919 
isMipmapFilter(tcu::Sampler::FilterMode filter)920 static inline bool isMipmapFilter (tcu::Sampler::FilterMode filter)
921 {
922 	switch (filter)
923 	{
924 		case tcu::Sampler::NEAREST:
925 		case tcu::Sampler::LINEAR:
926 			return false;
927 
928 		case tcu::Sampler::NEAREST_MIPMAP_NEAREST:
929 		case tcu::Sampler::NEAREST_MIPMAP_LINEAR:
930 		case tcu::Sampler::LINEAR_MIPMAP_NEAREST:
931 		case tcu::Sampler::LINEAR_MIPMAP_LINEAR:
932 			return true;
933 
934 		default:
935 			DE_ASSERT(false);
936 			return false;
937 	}
938 }
939 
940 class TextureGatherCase : public TestCase
941 {
942 public:
943 										TextureGatherCase		(Context&					context,
944 																 const char*				name,
945 																 const char*				description,
946 																 TextureType				textureType,
947 																 GatherType					gatherType,
948 																 OffsetSize					offsetSize,
949 																 tcu::TextureFormat			textureFormat,
950 																 tcu::Sampler::CompareMode	shadowCompareMode, //!< Should be COMPAREMODE_NONE iff textureFormat is a depth format.
951 																 tcu::Sampler::WrapMode		wrapS,
952 																 tcu::Sampler::WrapMode		wrapT,
953 																 const MaybeTextureSwizzle&	texSwizzle,
954 																 // \note Filter modes have no effect on gather (except when it comes to
955 																 //		  texture completeness); these are supposed to test just that.
956 																 tcu::Sampler::FilterMode	minFilter,
957 																 tcu::Sampler::FilterMode	magFilter,
958 																 int						baseLevel,
959 																 deUint32					flags);
960 
961 	void								init					(void);
962 	void								deinit					(void);
963 	IterateResult						iterate					(void);
964 
965 protected:
966 	IVec2								getOffsetRange			(void) const;
967 
968 	template <typename TexViewT, typename TexCoordT>
969 	bool								verify					(const ConstPixelBufferAccess&	rendered,
970 																 const TexViewT&				texture,
971 																 const TexCoordT				(&bottomLeft)[4],
972 																 const GatherArgs&				gatherArgs) const;
973 
974 	virtual void						generateIterations		(void) = 0;
975 	virtual void						createAndUploadTexture	(void) = 0;
976 	virtual int							getNumIterations		(void) const = 0;
977 	virtual GatherArgs					getGatherArgs			(int iterationNdx) const = 0;
978 	virtual vector<float>				computeQuadTexCoord		(int iterationNdx) const = 0;
979 	virtual bool						verify					(int iterationNdx, const ConstPixelBufferAccess& rendered) const = 0;
980 
981 	const GatherType					m_gatherType;
982 	const OffsetSize					m_offsetSize;
983 	const tcu::TextureFormat			m_textureFormat;
984 	const tcu::Sampler::CompareMode		m_shadowCompareMode;
985 	const tcu::Sampler::WrapMode		m_wrapS;
986 	const tcu::Sampler::WrapMode		m_wrapT;
987 	const MaybeTextureSwizzle			m_textureSwizzle;
988 	const tcu::Sampler::FilterMode		m_minFilter;
989 	const tcu::Sampler::FilterMode		m_magFilter;
990 	const int							m_baseLevel;
991 	const deUint32						m_flags;
992 
993 private:
994 	enum
995 	{
996 		SPEC_MAX_MIN_OFFSET = -8,
997 		SPEC_MIN_MAX_OFFSET = 7
998 	};
999 
1000 	static const IVec2					RENDER_SIZE;
1001 
1002 	static glu::VertexSource			genVertexShaderSource		(bool requireGpuShader5, int numTexCoordComponents, bool useNormalizedCoordInput);
1003 	static glu::FragmentSource			genFragmentShaderSource		(bool requireGpuShader5, int numTexCoordComponents, glu::DataType samplerType, const string& funcCall, bool useNormalizedCoordInput, bool usePixCoord);
1004 	static string						genGatherFuncCall			(GatherType, const tcu::TextureFormat&, const GatherArgs&, const string& refZExpr, const IVec2& offsetRange, int indentationDepth);
1005 	static glu::ProgramSources			genProgramSources			(GatherType, TextureType, const tcu::TextureFormat&, const GatherArgs&, const string& refZExpr, const IVec2& offsetRange);
1006 
1007 	const TextureType					m_textureType;
1008 
1009 	const tcu::TextureFormat			m_colorBufferFormat;
1010 	MovePtr<glu::Renderbuffer>			m_colorBuffer;
1011 	MovePtr<glu::Framebuffer>			m_fbo;
1012 
1013 	int									m_currentIteration;
1014 	MovePtr<ShaderProgram>				m_program;
1015 };
1016 
1017 const IVec2 TextureGatherCase::RENDER_SIZE = IVec2(64, 64);
1018 
TextureGatherCase(Context & context,const char * name,const char * description,TextureType textureType,GatherType gatherType,OffsetSize offsetSize,tcu::TextureFormat textureFormat,tcu::Sampler::CompareMode shadowCompareMode,tcu::Sampler::WrapMode wrapS,tcu::Sampler::WrapMode wrapT,const MaybeTextureSwizzle & textureSwizzle,tcu::Sampler::FilterMode minFilter,tcu::Sampler::FilterMode magFilter,int baseLevel,deUint32 flags)1019 TextureGatherCase::TextureGatherCase (Context&						context,
1020 									  const char*					name,
1021 									  const char*					description,
1022 									  TextureType					textureType,
1023 									  GatherType					gatherType,
1024 									  OffsetSize					offsetSize,
1025 									  tcu::TextureFormat			textureFormat,
1026 									  tcu::Sampler::CompareMode		shadowCompareMode, //!< Should be COMPAREMODE_NONE iff textureType == TEXTURETYPE_NORMAL.
1027 									  tcu::Sampler::WrapMode		wrapS,
1028 									  tcu::Sampler::WrapMode		wrapT,
1029 									  const MaybeTextureSwizzle&	textureSwizzle,
1030 									  tcu::Sampler::FilterMode		minFilter,
1031 									  tcu::Sampler::FilterMode		magFilter,
1032 									  int							baseLevel,
1033 									  deUint32						flags)
1034 	: TestCase				(context, name, description)
1035 	, m_gatherType			(gatherType)
1036 	, m_offsetSize			(offsetSize)
1037 	, m_textureFormat		(textureFormat)
1038 	, m_shadowCompareMode	(shadowCompareMode)
1039 	, m_wrapS				(wrapS)
1040 	, m_wrapT				(wrapT)
1041 	, m_textureSwizzle		(textureSwizzle)
1042 	, m_minFilter			(minFilter)
1043 	, m_magFilter			(magFilter)
1044 	, m_baseLevel			(baseLevel)
1045 	, m_flags				(flags)
1046 	, m_textureType			(textureType)
1047 	, m_colorBufferFormat	(tcu::TextureFormat(tcu::TextureFormat::RGBA,
1048 												isDepthFormat(textureFormat) ? tcu::TextureFormat::UNORM_INT8 : textureFormat.type))
1049 	, m_currentIteration	(0)
1050 {
1051 	DE_ASSERT((m_gatherType == GATHERTYPE_BASIC) == (m_offsetSize == OFFSETSIZE_NONE));
1052 	DE_ASSERT((m_shadowCompareMode != tcu::Sampler::COMPAREMODE_NONE) == isDepthFormat(m_textureFormat));
1053 	DE_ASSERT(isUnormFormatType(m_colorBufferFormat.type)						||
1054 			  m_colorBufferFormat.type == tcu::TextureFormat::UNSIGNED_INT8		||
1055 			  m_colorBufferFormat.type == tcu::TextureFormat::UNSIGNED_INT16	||
1056 			  m_colorBufferFormat.type == tcu::TextureFormat::SIGNED_INT8		||
1057 			  m_colorBufferFormat.type == tcu::TextureFormat::SIGNED_INT16);
1058 	DE_ASSERT(glu::isGLInternalColorFormatFilterable(glu::getInternalFormat(m_colorBufferFormat)) ||
1059 			  (m_magFilter == tcu::Sampler::NEAREST && (m_minFilter == tcu::Sampler::NEAREST || m_minFilter == tcu::Sampler::NEAREST_MIPMAP_NEAREST)));
1060 	DE_ASSERT(isMipmapFilter(m_minFilter) || !(m_flags & GATHERCASE_MIPMAP_INCOMPLETE));
1061 	DE_ASSERT(m_textureType == TEXTURETYPE_CUBE || !(m_flags & GATHERCASE_DONT_SAMPLE_CUBE_CORNERS));
1062 	DE_ASSERT(!((m_flags & GATHERCASE_MIPMAP_INCOMPLETE) && isDepthFormat(m_textureFormat))); // It's not clear what shadow textures should return when incomplete.
1063 }
1064 
getOffsetRange(void) const1065 IVec2 TextureGatherCase::getOffsetRange (void) const
1066 {
1067 	switch (m_offsetSize)
1068 	{
1069 		case OFFSETSIZE_NONE:
1070 			return IVec2(0);
1071 			break;
1072 
1073 		case OFFSETSIZE_MINIMUM_REQUIRED:
1074 			// \note Defined by spec.
1075 			return IVec2(SPEC_MAX_MIN_OFFSET,
1076 						 SPEC_MIN_MAX_OFFSET);
1077 			break;
1078 
1079 		case OFFSETSIZE_IMPLEMENTATION_MAXIMUM:
1080 			return IVec2(m_context.getContextInfo().getInt(GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET),
1081 						 m_context.getContextInfo().getInt(GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET));
1082 			break;
1083 
1084 		default:
1085 			DE_ASSERT(false);
1086 			return IVec2(-1);
1087 	}
1088 }
1089 
genVertexShaderSource(bool requireGpuShader5,int numTexCoordComponents,bool useNormalizedCoordInput)1090 glu::VertexSource TextureGatherCase::genVertexShaderSource (bool requireGpuShader5, int numTexCoordComponents, bool useNormalizedCoordInput)
1091 {
1092 	DE_ASSERT(numTexCoordComponents == 2 || numTexCoordComponents == 3);
1093 	const string texCoordType = "vec" + de::toString(numTexCoordComponents);
1094 	return glu::VertexSource("#version 310 es\n"
1095 							 + string(requireGpuShader5 ? "#extension GL_EXT_gpu_shader5 : require\n" : "") +
1096 							 "\n"
1097 							 "in highp vec2 a_position;\n"
1098 							 "in highp " + texCoordType + " a_texCoord;\n"
1099 							 + (useNormalizedCoordInput ? "in highp vec2 a_normalizedCoord; // (0,0) to (1,1)\n" : "") +
1100 							 "\n"
1101 							 "out highp " + texCoordType + " v_texCoord;\n"
1102 							 + (useNormalizedCoordInput ? "out highp vec2 v_normalizedCoord;\n" : "") +
1103 							 "\n"
1104 							 "void main (void)\n"
1105 							 "{\n"
1106 							 "	gl_Position = vec4(a_position.x, a_position.y, 0.0, 1.0);\n"
1107 							 "	v_texCoord = a_texCoord;\n"
1108 							 + (useNormalizedCoordInput ? "\tv_normalizedCoord = a_normalizedCoord;\n" : "") +
1109 							 "}\n");
1110 }
1111 
genFragmentShaderSource(bool requireGpuShader5,int numTexCoordComponents,glu::DataType samplerType,const string & funcCall,bool useNormalizedCoordInput,bool usePixCoord)1112 glu::FragmentSource TextureGatherCase::genFragmentShaderSource (bool			requireGpuShader5,
1113 																int				numTexCoordComponents,
1114 																glu::DataType	samplerType,
1115 																const string&	funcCall,
1116 																bool			useNormalizedCoordInput,
1117 																bool			usePixCoord)
1118 {
1119 	DE_ASSERT(glu::isDataTypeSampler(samplerType));
1120 	DE_ASSERT(de::inRange(numTexCoordComponents, 2, 3));
1121 	DE_ASSERT(!usePixCoord || useNormalizedCoordInput);
1122 
1123 	const string texCoordType = "vec" + de::toString(numTexCoordComponents);
1124 
1125 	return glu::FragmentSource("#version 310 es\n"
1126 							   + string(requireGpuShader5 ? "#extension GL_EXT_gpu_shader5 : require\n" : "") +
1127 							   "\n"
1128 							   "layout (location = 0) out mediump " + glu::getDataTypeName(getSamplerGatherResultType(samplerType)) + " o_color;\n"
1129 							   "\n"
1130 							   "in highp " + texCoordType + " v_texCoord;\n"
1131 							   + (useNormalizedCoordInput ? "in highp vec2 v_normalizedCoord;\n" : "") +
1132 							   "\n"
1133 							   "uniform highp " + string(glu::getDataTypeName(samplerType)) + " u_sampler;\n"
1134 							   + (useNormalizedCoordInput ? "uniform highp vec2 u_viewportSize;\n" : "") +
1135 							   "\n"
1136 							   "void main(void)\n"
1137 							   "{\n"
1138 							   + (usePixCoord ? "\tivec2 pixCoord = ivec2(v_normalizedCoord*u_viewportSize);\n" : "") +
1139 							   "	o_color = " + funcCall + ";\n"
1140 							   "}\n");
1141 }
1142 
genGatherFuncCall(GatherType gatherType,const tcu::TextureFormat & textureFormat,const GatherArgs & gatherArgs,const string & refZExpr,const IVec2 & offsetRange,int indentationDepth)1143 string TextureGatherCase::genGatherFuncCall (GatherType gatherType, const tcu::TextureFormat& textureFormat, const GatherArgs& gatherArgs, const string& refZExpr, const IVec2& offsetRange, int indentationDepth)
1144 {
1145 	string result;
1146 
1147 	switch (gatherType)
1148 	{
1149 		case GATHERTYPE_BASIC:
1150 			result += "textureGather";
1151 			break;
1152 		case GATHERTYPE_OFFSET: // \note Fallthrough.
1153 		case GATHERTYPE_OFFSET_DYNAMIC:
1154 			result += "textureGatherOffset";
1155 			break;
1156 		case GATHERTYPE_OFFSETS:
1157 			result += "textureGatherOffsets";
1158 			break;
1159 		default:
1160 			DE_ASSERT(false);
1161 	}
1162 
1163 	result += "(u_sampler, v_texCoord";
1164 
1165 	if (isDepthFormat(textureFormat))
1166 	{
1167 		DE_ASSERT(gatherArgs.componentNdx < 0);
1168 		result += ", " + refZExpr;
1169 	}
1170 
1171 	if (gatherType == GATHERTYPE_OFFSET ||
1172 		gatherType == GATHERTYPE_OFFSET_DYNAMIC ||
1173 		gatherType == GATHERTYPE_OFFSETS)
1174 	{
1175 		result += ", ";
1176 		switch (gatherType)
1177 		{
1178 			case GATHERTYPE_OFFSET:
1179 				result += "ivec2" + de::toString(gatherArgs.offsets[0]);
1180 				break;
1181 
1182 			case GATHERTYPE_OFFSET_DYNAMIC:
1183 				result += "pixCoord.yx % ivec2(" + de::toString(offsetRange.y() - offsetRange.x() + 1) + ") + " + de::toString(offsetRange.x());
1184 				break;
1185 
1186 			case GATHERTYPE_OFFSETS:
1187 				result += "ivec2[4](\n"
1188 						  + string(indentationDepth, '\t') + "\tivec2" + de::toString(gatherArgs.offsets[0]) + ",\n"
1189 						  + string(indentationDepth, '\t') + "\tivec2" + de::toString(gatherArgs.offsets[1]) + ",\n"
1190 						  + string(indentationDepth, '\t') + "\tivec2" + de::toString(gatherArgs.offsets[2]) + ",\n"
1191 						  + string(indentationDepth, '\t') + "\tivec2" + de::toString(gatherArgs.offsets[3]) + ")\n"
1192 						  + string(indentationDepth, '\t') + "\t";
1193 				break;
1194 
1195 			default:
1196 				DE_ASSERT(false);
1197 		}
1198 	}
1199 
1200 	if (gatherArgs.componentNdx >= 0)
1201 	{
1202 		DE_ASSERT(gatherArgs.componentNdx < 4);
1203 		result += ", " + de::toString(gatherArgs.componentNdx);
1204 	}
1205 
1206 	result += ")";
1207 
1208 	return result;
1209 }
1210 
1211 // \note If componentNdx for genProgramSources() is -1, component index is not specified.
genProgramSources(GatherType gatherType,TextureType textureType,const tcu::TextureFormat & textureFormat,const GatherArgs & gatherArgs,const string & refZExpr,const IVec2 & offsetRange)1212 glu::ProgramSources TextureGatherCase::genProgramSources (GatherType					gatherType,
1213 														  TextureType					textureType,
1214 														  const tcu::TextureFormat&		textureFormat,
1215 														  const GatherArgs&				gatherArgs,
1216 														  const string&					refZExpr,
1217 														  const IVec2&					offsetRange)
1218 {
1219 	const bool				usePixCoord			= gatherType == GATHERTYPE_OFFSET_DYNAMIC;
1220 	const bool				useNormalizedCoord	= usePixCoord || isDepthFormat(textureFormat);
1221 	const bool				isDynamicOffset		= gatherType == GATHERTYPE_OFFSET_DYNAMIC;
1222 	const bool				isShadow			= isDepthFormat(textureFormat);
1223 	const glu::DataType		samplerType			= getSamplerType(textureType, textureFormat);
1224 	const int				numDims				= getNumTextureSamplingDimensions(textureType);
1225 	const string			funcCall			= genGatherFuncCall(gatherType, textureFormat, gatherArgs, refZExpr, offsetRange, 1);
1226 
1227 	return glu::ProgramSources() << genVertexShaderSource(requireGpuShader5(gatherType), numDims, isDynamicOffset || isShadow)
1228 								 << genFragmentShaderSource(requireGpuShader5(gatherType), numDims, samplerType, funcCall, useNormalizedCoord, usePixCoord);
1229 }
1230 
init(void)1231 void TextureGatherCase::init (void)
1232 {
1233 	TestLog&					log			= m_testCtx.getLog();
1234 	const glu::RenderContext&	renderCtx	= m_context.getRenderContext();
1235 	const glw::Functions&		gl			= renderCtx.getFunctions();
1236 	const deUint32				texTypeGL	= getGLTextureType(m_textureType);
1237 
1238 	// Check prerequisites.
1239 	if (requireGpuShader5(m_gatherType) && !m_context.getContextInfo().isExtensionSupported("GL_EXT_gpu_shader5"))
1240 		throw tcu::NotSupportedError("GL_EXT_gpu_shader5 required");
1241 
1242 	// Log and check implementation offset limits, if appropriate.
1243 	if (m_offsetSize == OFFSETSIZE_IMPLEMENTATION_MAXIMUM)
1244 	{
1245 		const IVec2 offsetRange = getOffsetRange();
1246 		log << TestLog::Integer("ImplementationMinTextureGatherOffset", "Implementation's value for GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET", "", QP_KEY_TAG_NONE, offsetRange[0])
1247 			<< TestLog::Integer("ImplementationMaxTextureGatherOffset", "Implementation's value for GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET", "", QP_KEY_TAG_NONE, offsetRange[1]);
1248 		TCU_CHECK_MSG(offsetRange[0] <= SPEC_MAX_MIN_OFFSET, ("GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET must be at most " + de::toString((int)SPEC_MAX_MIN_OFFSET)).c_str());
1249 		TCU_CHECK_MSG(offsetRange[1] >= SPEC_MIN_MAX_OFFSET, ("GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET must be at least " + de::toString((int)SPEC_MIN_MAX_OFFSET)).c_str());
1250 	}
1251 
1252 	// Create rbo and fbo.
1253 
1254 	m_colorBuffer = MovePtr<glu::Renderbuffer>(new glu::Renderbuffer(renderCtx));
1255 	gl.bindRenderbuffer(GL_RENDERBUFFER, **m_colorBuffer);
1256 	gl.renderbufferStorage(GL_RENDERBUFFER, glu::getInternalFormat(m_colorBufferFormat), RENDER_SIZE.x(), RENDER_SIZE.y());
1257 	GLU_EXPECT_NO_ERROR(gl.getError(), "Create and setup renderbuffer object");
1258 
1259 	m_fbo = MovePtr<glu::Framebuffer>(new glu::Framebuffer(renderCtx));
1260 	gl.bindFramebuffer(GL_FRAMEBUFFER, **m_fbo);
1261 	gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, **m_colorBuffer);
1262 	GLU_EXPECT_NO_ERROR(gl.getError(), "Create and setup framebuffer object");
1263 
1264 	log << TestLog::Message << "Using a framebuffer object with renderbuffer with format "
1265 							<< glu::getTextureFormatName(glu::getInternalFormat(m_colorBufferFormat))
1266 							<< " and size " << RENDER_SIZE << TestLog::EndMessage;
1267 
1268 	// Generate subclass-specific iterations.
1269 
1270 	generateIterations();
1271 	m_currentIteration = 0;
1272 
1273 	// Initialize texture.
1274 
1275 	createAndUploadTexture();
1276 	gl.texParameteri(texTypeGL, GL_TEXTURE_WRAP_S,		glu::getGLWrapMode(m_wrapS));
1277 	gl.texParameteri(texTypeGL, GL_TEXTURE_WRAP_T,		glu::getGLWrapMode(m_wrapT));
1278 	gl.texParameteri(texTypeGL, GL_TEXTURE_MIN_FILTER,	glu::getGLFilterMode(m_minFilter));
1279 	gl.texParameteri(texTypeGL, GL_TEXTURE_MAG_FILTER,	glu::getGLFilterMode(m_magFilter));
1280 
1281 	if (m_baseLevel != 0)
1282 		gl.texParameteri(texTypeGL, GL_TEXTURE_BASE_LEVEL, m_baseLevel);
1283 
1284 	if (isDepthFormat(m_textureFormat))
1285 	{
1286 		gl.texParameteri(texTypeGL, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
1287 		gl.texParameteri(texTypeGL, GL_TEXTURE_COMPARE_FUNC, glu::getGLCompareFunc(m_shadowCompareMode));
1288 	}
1289 
1290 	if (m_textureSwizzle.isSome())
1291 	{
1292 		const deUint32 swizzleNamesGL[4] =
1293 		{
1294 			GL_TEXTURE_SWIZZLE_R,
1295 			GL_TEXTURE_SWIZZLE_G,
1296 			GL_TEXTURE_SWIZZLE_B,
1297 			GL_TEXTURE_SWIZZLE_A
1298 		};
1299 
1300 		for (int i = 0; i < 4; i++)
1301 		{
1302 			const deUint32 curGLSwizzle = getGLTextureSwizzleComponent(m_textureSwizzle.getSwizzle()[i]);
1303 			gl.texParameteri(texTypeGL, swizzleNamesGL[i], curGLSwizzle);
1304 		}
1305 	}
1306 
1307 	GLU_EXPECT_NO_ERROR(gl.getError(), "Set texture parameters");
1308 
1309 	log << TestLog::Message << "Texture base level is " << m_baseLevel << TestLog::EndMessage
1310 		<< TestLog::Message << "s and t wrap modes are "
1311 							<< glu::getTextureWrapModeName(glu::getGLWrapMode(m_wrapS)) << " and "
1312 							<< glu::getTextureWrapModeName(glu::getGLWrapMode(m_wrapT)) << ", respectively" << TestLog::EndMessage
1313 		<< TestLog::Message << "Minification and magnification filter modes are "
1314 							<< glu::getTextureFilterName(glu::getGLFilterMode(m_minFilter)) << " and "
1315 							<< glu::getTextureFilterName(glu::getGLFilterMode(m_magFilter)) << ", respectively "
1316 							<< ((m_flags & GATHERCASE_MIPMAP_INCOMPLETE) ?
1317 								"(note that they cause the texture to be incomplete)" :
1318 								"(note that they should have no effect on gather result)")
1319 							<< TestLog::EndMessage
1320 		<< TestLog::Message << "Using texture swizzle " << m_textureSwizzle << TestLog::EndMessage;
1321 
1322 	if (m_shadowCompareMode != tcu::Sampler::COMPAREMODE_NONE)
1323 		log << TestLog::Message << "Using texture compare func " << glu::getCompareFuncName(glu::getGLCompareFunc(m_shadowCompareMode)) << TestLog::EndMessage;
1324 }
1325 
deinit(void)1326 void TextureGatherCase::deinit (void)
1327 {
1328 	m_program		= MovePtr<ShaderProgram>(DE_NULL);
1329 	m_fbo			= MovePtr<glu::Framebuffer>(DE_NULL);
1330 	m_colorBuffer	= MovePtr<glu::Renderbuffer>(DE_NULL);
1331 }
1332 
iterate(void)1333 TextureGatherCase::IterateResult TextureGatherCase::iterate (void)
1334 {
1335 	TestLog&						log								= m_testCtx.getLog();
1336 	const tcu::ScopedLogSection		iterationSection				(log, "Iteration" + de::toString(m_currentIteration), "Iteration " + de::toString(m_currentIteration));
1337 	const glu::RenderContext&		renderCtx						= m_context.getRenderContext();
1338 	const glw::Functions&			gl								= renderCtx.getFunctions();
1339 	const GatherArgs&				gatherArgs						= getGatherArgs(m_currentIteration);
1340 	const string					refZExpr						= "v_normalizedCoord.x";
1341 	const bool						needPixelCoordInShader			= m_gatherType == GATHERTYPE_OFFSET_DYNAMIC;
1342 	const bool						needNormalizedCoordInShader		= needPixelCoordInShader || isDepthFormat(m_textureFormat);
1343 
1344 	// Generate a program appropriate for this iteration.
1345 
1346 	m_program = MovePtr<ShaderProgram>(new ShaderProgram(renderCtx, genProgramSources(m_gatherType, m_textureType, m_textureFormat, gatherArgs, refZExpr, getOffsetRange())));
1347 	if (m_currentIteration == 0)
1348 		m_testCtx.getLog() << *m_program;
1349 	else
1350 		m_testCtx.getLog() << TestLog::Message << "Using a program similar to the previous one, except with a gather function call as follows:\n"
1351 											   << genGatherFuncCall(m_gatherType, m_textureFormat, gatherArgs, refZExpr, getOffsetRange(), 0)
1352 											   << TestLog::EndMessage;
1353 	if (!m_program->isOk())
1354 	{
1355 		if (m_currentIteration != 0)
1356 			m_testCtx.getLog() << *m_program;
1357 		TCU_FAIL("Failed to build program");
1358 	}
1359 
1360 	// Render.
1361 
1362 	gl.viewport(0, 0, RENDER_SIZE.x(), RENDER_SIZE.y());
1363 	gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
1364 	gl.clear(GL_COLOR_BUFFER_BIT);
1365 
1366 	{
1367 		const float position[4*2] =
1368 		{
1369 			-1.0f, -1.0f,
1370 			-1.0f, +1.0f,
1371 			+1.0f, -1.0f,
1372 			+1.0f, +1.0f,
1373 		};
1374 
1375 		const float normalizedCoord[4*2] =
1376 		{
1377 			0.0f, 0.0f,
1378 			0.0f, 1.0f,
1379 			1.0f, 0.0f,
1380 			1.0f, 1.0f,
1381 		};
1382 
1383 		const vector<float> texCoord = computeQuadTexCoord(m_currentIteration);
1384 
1385 		vector<glu::VertexArrayBinding> attrBindings;
1386 		attrBindings.push_back(glu::va::Float("a_position", 2, 4, 0, &position[0]));
1387 		attrBindings.push_back(glu::va::Float("a_texCoord", (int)texCoord.size()/4, 4, 0, &texCoord[0]));
1388 		if (needNormalizedCoordInShader)
1389 			attrBindings.push_back(glu::va::Float("a_normalizedCoord", 2, 4, 0, &normalizedCoord[0]));
1390 
1391 		const deUint16 indices[6] = { 0, 1, 2, 2, 1, 3 };
1392 
1393 		gl.useProgram(m_program->getProgram());
1394 
1395 		{
1396 			const int samplerUniformLocation = gl.getUniformLocation(m_program->getProgram(), "u_sampler");
1397 			TCU_CHECK(samplerUniformLocation >= 0);
1398 			gl.uniform1i(samplerUniformLocation, 0);
1399 		}
1400 
1401 		if (needPixelCoordInShader)
1402 		{
1403 			const int viewportSizeUniformLocation = gl.getUniformLocation(m_program->getProgram(), "u_viewportSize");
1404 			TCU_CHECK(viewportSizeUniformLocation >= 0);
1405 			gl.uniform2f(viewportSizeUniformLocation, (float)RENDER_SIZE.x(), (float)RENDER_SIZE.y());
1406 		}
1407 
1408 		if (texCoord.size() == 2*4)
1409 		{
1410 			Vec2 texCoordVec[4];
1411 			computeTexCoordVecs(texCoord, texCoordVec);
1412 			log << TestLog::Message << "Texture coordinates run from " << texCoordVec[0] << " to " << texCoordVec[3] << TestLog::EndMessage;
1413 		}
1414 		else if (texCoord.size() == 3*4)
1415 		{
1416 			Vec3 texCoordVec[4];
1417 			computeTexCoordVecs(texCoord, texCoordVec);
1418 			log << TestLog::Message << "Texture coordinates run from " << texCoordVec[0] << " to " << texCoordVec[3] << TestLog::EndMessage;
1419 		}
1420 		else
1421 			DE_ASSERT(false);
1422 
1423 		glu::draw(renderCtx, m_program->getProgram(), (int)attrBindings.size(), &attrBindings[0],
1424 			glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indices), &indices[0]));
1425 	}
1426 
1427 	// Verify result.
1428 
1429 	{
1430 		const tcu::TextureLevel rendered = getPixels(renderCtx, RENDER_SIZE, m_colorBufferFormat);
1431 
1432 		if (!verify(m_currentIteration, rendered.getAccess()))
1433 		{
1434 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Result verification failed");
1435 			return STOP;
1436 		}
1437 	}
1438 
1439 	m_currentIteration++;
1440 	if (m_currentIteration == (int)getNumIterations())
1441 	{
1442 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1443 		return STOP;
1444 	}
1445 	else
1446 		return CONTINUE;
1447 }
1448 
1449 template <typename TexViewT, typename TexCoordT>
verify(const ConstPixelBufferAccess & rendered,const TexViewT & texture,const TexCoordT (& texCoords)[4],const GatherArgs & gatherArgs) const1450 bool TextureGatherCase::verify (const ConstPixelBufferAccess&	rendered,
1451 								const TexViewT&					texture,
1452 								const TexCoordT					(&texCoords)[4],
1453 								const GatherArgs&				gatherArgs) const
1454 {
1455 	TestLog& log = m_testCtx.getLog();
1456 
1457 	if (m_flags & GATHERCASE_MIPMAP_INCOMPLETE)
1458 	{
1459 		const int	componentNdx		= de::max(0, gatherArgs.componentNdx);
1460 		const Vec4	incompleteColor		(0.0f, 0.0f, 0.0f, 1.0f);
1461 		const Vec4	refColor			(incompleteColor[componentNdx]);
1462 		const bool	isOk				= verifySingleColored(log, rendered, refColor);
1463 
1464 		if (!isOk)
1465 			log << TestLog::Message << "Note: expected color " << refColor << " for all pixels; "
1466 									<< incompleteColor[componentNdx] << " is component at index " << componentNdx
1467 									<< " in the color " << incompleteColor << ", which is used for incomplete textures" << TestLog::EndMessage;
1468 
1469 		return isOk;
1470 	}
1471 	else
1472 	{
1473 		DE_ASSERT(m_colorBufferFormat.order == tcu::TextureFormat::RGBA);
1474 		DE_ASSERT(m_colorBufferFormat.type == tcu::TextureFormat::UNORM_INT8		||
1475 				  m_colorBufferFormat.type == tcu::TextureFormat::UNSIGNED_INT8		||
1476 				  m_colorBufferFormat.type == tcu::TextureFormat::SIGNED_INT8);
1477 
1478 		const MovePtr<PixelOffsets>		pixelOffsets	= makePixelOffsetsFunctor(m_gatherType, gatherArgs, getOffsetRange());
1479 		const tcu::PixelFormat			pixelFormat		= tcu::PixelFormat(8,8,8,8);
1480 		const IVec4						colorBits		= tcu::max(glu::TextureTestUtil::getBitsVec(pixelFormat) - 1, tcu::IVec4(0));
1481 		const IVec3						coordBits		= m_textureType == TEXTURETYPE_2D			? IVec3(20,20,0)
1482 														: m_textureType == TEXTURETYPE_CUBE			? IVec3(10,10,10)
1483 														: m_textureType == TEXTURETYPE_2D_ARRAY		? IVec3(20,20,20)
1484 														: IVec3(-1);
1485 		const IVec3						uvwBits			= m_textureType == TEXTURETYPE_2D			? IVec3(7,7,0)
1486 														: m_textureType == TEXTURETYPE_CUBE			? IVec3(6,6,0)
1487 														: m_textureType == TEXTURETYPE_2D_ARRAY		? IVec3(7,7,7)
1488 														: IVec3(-1);
1489 		tcu::Sampler					sampler;
1490 		sampler.wrapS		= m_wrapS;
1491 		sampler.wrapT		= m_wrapT;
1492 		sampler.compare		= m_shadowCompareMode;
1493 
1494 		if (isDepthFormat(m_textureFormat))
1495 		{
1496 			tcu::TexComparePrecision comparePrec;
1497 			comparePrec.coordBits		= coordBits;
1498 			comparePrec.uvwBits			= uvwBits;
1499 			comparePrec.referenceBits	= 16;
1500 			comparePrec.resultBits		= pixelFormat.redBits-1;
1501 
1502 			return verifyGatherOffsetsCompare(log, rendered, texture, texCoords, sampler, comparePrec, PixelCompareRefZDefault(RENDER_SIZE), *pixelOffsets);
1503 		}
1504 		else
1505 		{
1506 			const int componentNdx = de::max(0, gatherArgs.componentNdx);
1507 
1508 			if (isUnormFormatType(m_textureFormat.type))
1509 			{
1510 				tcu::LookupPrecision lookupPrec;
1511 				lookupPrec.colorThreshold	= tcu::computeFixedPointThreshold(colorBits);
1512 				lookupPrec.coordBits		= coordBits;
1513 				lookupPrec.uvwBits			= uvwBits;
1514 				lookupPrec.colorMask		= glu::TextureTestUtil::getCompareMask(pixelFormat);
1515 				return verifyGatherOffsets<float>(log, rendered, texture, texCoords, sampler, lookupPrec, componentNdx, *pixelOffsets);
1516 			}
1517 			else if (isUIntFormatType(m_textureFormat.type) || isSIntFormatType(m_textureFormat.type))
1518 			{
1519 				tcu::IntLookupPrecision		lookupPrec;
1520 				lookupPrec.colorThreshold	= UVec4(0);
1521 				lookupPrec.coordBits		= coordBits;
1522 				lookupPrec.uvwBits			= uvwBits;
1523 				lookupPrec.colorMask		= glu::TextureTestUtil::getCompareMask(pixelFormat);
1524 
1525 				if (isUIntFormatType(m_textureFormat.type))
1526 					return verifyGatherOffsets<deUint32>(log, rendered, texture, texCoords, sampler, lookupPrec, componentNdx, *pixelOffsets);
1527 				else if (isSIntFormatType(m_textureFormat.type))
1528 					return verifyGatherOffsets<deInt32>(log, rendered, texture, texCoords, sampler, lookupPrec, componentNdx, *pixelOffsets);
1529 				else
1530 				{
1531 					DE_ASSERT(false);
1532 					return false;
1533 				}
1534 			}
1535 			else
1536 			{
1537 				DE_ASSERT(false);
1538 				return false;
1539 			}
1540 		}
1541 	}
1542 }
1543 
generateBasic2DCaseIterations(GatherType gatherType,const tcu::TextureFormat & textureFormat,const IVec2 & offsetRange)1544 vector<GatherArgs> generateBasic2DCaseIterations (GatherType gatherType, const tcu::TextureFormat& textureFormat, const IVec2& offsetRange)
1545 {
1546 	const int			numComponentCases	= isDepthFormat(textureFormat) ? 1 : 4+1; // \note For non-depth textures, test explicit components 0 to 3 and implicit component 0.
1547 	vector<GatherArgs>	result;
1548 
1549 	for (int componentCaseNdx = 0; componentCaseNdx < numComponentCases; componentCaseNdx++)
1550 	{
1551 		const int componentNdx = componentCaseNdx - 1;
1552 
1553 		switch (gatherType)
1554 		{
1555 			case GATHERTYPE_BASIC:
1556 				result.push_back(GatherArgs(componentNdx));
1557 				break;
1558 
1559 			case GATHERTYPE_OFFSET:
1560 			{
1561 				const int min	= offsetRange.x();
1562 				const int max	= offsetRange.y();
1563 				const int hmin	= divRoundToZero(min, 2);
1564 				const int hmax	= divRoundToZero(max, 2);
1565 
1566 				result.push_back(GatherArgs(componentNdx, IVec2(min, max)));
1567 
1568 				if (componentCaseNdx == 0) // Don't test all offsets variants for all color components (they should be pretty orthogonal).
1569 				{
1570 					result.push_back(GatherArgs(componentNdx, IVec2(min,	min)));
1571 					result.push_back(GatherArgs(componentNdx, IVec2(max,	min)));
1572 					result.push_back(GatherArgs(componentNdx, IVec2(max,	max)));
1573 
1574 					result.push_back(GatherArgs(componentNdx, IVec2(0,		hmax)));
1575 					result.push_back(GatherArgs(componentNdx, IVec2(hmin,	0)));
1576 					result.push_back(GatherArgs(componentNdx, IVec2(0,		0)));
1577 				}
1578 
1579 				break;
1580 			}
1581 
1582 			case GATHERTYPE_OFFSET_DYNAMIC:
1583 				result.push_back(GatherArgs(componentNdx));
1584 				break;
1585 
1586 			case GATHERTYPE_OFFSETS:
1587 			{
1588 				const int min	= offsetRange.x();
1589 				const int max	= offsetRange.y();
1590 				const int hmin	= divRoundToZero(min, 2);
1591 				const int hmax	= divRoundToZero(max, 2);
1592 
1593 				result.push_back(GatherArgs(componentNdx,
1594 											IVec2(min,	min),
1595 											IVec2(min,	max),
1596 											IVec2(max,	min),
1597 											IVec2(max,	max)));
1598 
1599 				if (componentCaseNdx == 0) // Don't test all offsets variants for all color components (they should be pretty orthogonal).
1600 					result.push_back(GatherArgs(componentNdx,
1601 												IVec2(min,	hmax),
1602 												IVec2(hmin,	max),
1603 												IVec2(0,	hmax),
1604 												IVec2(hmax,	0)));
1605 				break;
1606 			}
1607 
1608 			default:
1609 				DE_ASSERT(false);
1610 		}
1611 	}
1612 
1613 	return result;
1614 }
1615 
1616 class TextureGather2DCase : public TextureGatherCase
1617 {
1618 public:
TextureGather2DCase(Context & context,const char * name,const char * 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,deUint32 flags,const IVec2 & textureSize)1619 	TextureGather2DCase (Context&					context,
1620 						 const char*				name,
1621 						 const char*				description,
1622 						 GatherType					gatherType,
1623 						 OffsetSize					offsetSize,
1624 						 tcu::TextureFormat			textureFormat,
1625 						 tcu::Sampler::CompareMode	shadowCompareMode,
1626 						 tcu::Sampler::WrapMode		wrapS,
1627 						 tcu::Sampler::WrapMode		wrapT,
1628 						 const MaybeTextureSwizzle&	texSwizzle,
1629 						 tcu::Sampler::FilterMode	minFilter,
1630 						 tcu::Sampler::FilterMode	magFilter,
1631 						 int						baseLevel,
1632 						 deUint32					flags,
1633 						 const IVec2&				textureSize)
1634 		: TextureGatherCase		(context, name, description, TEXTURETYPE_2D, gatherType, offsetSize, textureFormat, shadowCompareMode, wrapS, wrapT, texSwizzle, minFilter, magFilter, baseLevel, flags)
1635 		, m_textureSize			(textureSize)
1636 		, m_swizzledTexture		(tcu::TextureFormat(), 1, 1)
1637 	{
1638 	}
1639 
1640 protected:
1641 	void						generateIterations		(void);
1642 	void						createAndUploadTexture	(void);
getNumIterations(void) const1643 	int							getNumIterations		(void) const { DE_ASSERT(!m_iterations.empty()); return (int)m_iterations.size(); }
getGatherArgs(int iterationNdx) const1644 	GatherArgs					getGatherArgs			(int iterationNdx) const { return m_iterations[iterationNdx]; }
1645 	vector<float>				computeQuadTexCoord		(int iterationNdx) const;
1646 	bool						verify					(int iterationNdx, const ConstPixelBufferAccess& rendered) const;
1647 
1648 private:
1649 	const IVec2					m_textureSize;
1650 
1651 	MovePtr<glu::Texture2D>		m_texture;
1652 	tcu::Texture2D				m_swizzledTexture;
1653 	vector<GatherArgs>			m_iterations;
1654 };
1655 
computeQuadTexCoord(int) const1656 vector<float> TextureGather2DCase::computeQuadTexCoord (int /* iterationNdx */) const
1657 {
1658 	vector<float> res;
1659 	glu::TextureTestUtil::computeQuadTexCoord2D(res, Vec2(-0.3f, -0.4f), Vec2(1.5f, 1.6f));
1660 	return res;
1661 }
1662 
generateIterations(void)1663 void TextureGather2DCase::generateIterations (void)
1664 {
1665 	DE_ASSERT(m_iterations.empty());
1666 	m_iterations = generateBasic2DCaseIterations(m_gatherType, m_textureFormat, getOffsetRange());
1667 }
1668 
createAndUploadTexture(void)1669 void TextureGather2DCase::createAndUploadTexture (void)
1670 {
1671 	const glu::RenderContext&		renderCtx	= m_context.getRenderContext();
1672 	const glw::Functions&			gl			= renderCtx.getFunctions();
1673 	const tcu::TextureFormatInfo	texFmtInfo	= tcu::getTextureFormatInfo(m_textureFormat);
1674 
1675 	m_texture = MovePtr<glu::Texture2D>(new glu::Texture2D(renderCtx, glu::getInternalFormat(m_textureFormat), m_textureSize.x(), m_textureSize.y()));
1676 
1677 	{
1678 		tcu::Texture2D&		refTexture	= m_texture->getRefTexture();
1679 		const int			levelBegin	= m_baseLevel;
1680 		const int			levelEnd	= isMipmapFilter(m_minFilter) && !(m_flags & GATHERCASE_MIPMAP_INCOMPLETE) ? refTexture.getNumLevels() : m_baseLevel+1;
1681 		DE_ASSERT(m_baseLevel < refTexture.getNumLevels());
1682 
1683 		for (int levelNdx = levelBegin; levelNdx < levelEnd; levelNdx++)
1684 		{
1685 			refTexture.allocLevel(levelNdx);
1686 			const PixelBufferAccess& level = refTexture.getLevel(levelNdx);
1687 			fillWithRandomColorTiles(level, texFmtInfo.valueMin, texFmtInfo.valueMax, (deUint32)m_testCtx.getCommandLine().getBaseSeed());
1688 			m_testCtx.getLog() << TestLog::Image("InputTextureLevel" + de::toString(levelNdx), "Input texture, level " + de::toString(levelNdx), level)
1689 							   << TestLog::Message << "Note: texture level's size is " << IVec2(level.getWidth(), level.getHeight()) << TestLog::EndMessage;
1690 		}
1691 
1692 		swizzleTexture(m_swizzledTexture, refTexture, m_textureSwizzle);
1693 	}
1694 
1695 	gl.activeTexture(GL_TEXTURE0);
1696 	m_texture->upload();
1697 }
1698 
verify(int iterationNdx,const ConstPixelBufferAccess & rendered) const1699 bool TextureGather2DCase::verify (int iterationNdx, const ConstPixelBufferAccess& rendered) const
1700 {
1701 	Vec2 texCoords[4];
1702 	computeTexCoordVecs(computeQuadTexCoord(iterationNdx), texCoords);
1703 	return TextureGatherCase::verify(rendered, getOneLevelSubView(tcu::Texture2DView(m_swizzledTexture), m_baseLevel), texCoords, m_iterations[iterationNdx]);
1704 }
1705 
1706 class TextureGather2DArrayCase : public TextureGatherCase
1707 {
1708 public:
TextureGather2DArrayCase(Context & context,const char * name,const char * 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,deUint32 flags,const IVec3 & textureSize)1709 	TextureGather2DArrayCase (Context&						context,
1710 							  const char*					name,
1711 							  const char*					description,
1712 							  GatherType					gatherType,
1713 							  OffsetSize					offsetSize,
1714 							  tcu::TextureFormat			textureFormat,
1715 							  tcu::Sampler::CompareMode		shadowCompareMode,
1716 							  tcu::Sampler::WrapMode		wrapS,
1717 							  tcu::Sampler::WrapMode		wrapT,
1718 							  const MaybeTextureSwizzle&	texSwizzle,
1719 							  tcu::Sampler::FilterMode		minFilter,
1720 							  tcu::Sampler::FilterMode		magFilter,
1721 							  int							baseLevel,
1722 							  deUint32						flags,
1723 							  const IVec3&					textureSize)
1724 		: TextureGatherCase		(context, name, description, TEXTURETYPE_2D_ARRAY, gatherType, offsetSize, textureFormat, shadowCompareMode, wrapS, wrapT, texSwizzle, minFilter, magFilter, baseLevel, flags)
1725 		, m_textureSize			(textureSize)
1726 		, m_swizzledTexture		(tcu::TextureFormat(), 1, 1, 1)
1727 	{
1728 	}
1729 
1730 protected:
1731 	void							generateIterations		(void);
1732 	void							createAndUploadTexture	(void);
getNumIterations(void) const1733 	int								getNumIterations		(void) const { DE_ASSERT(!m_iterations.empty()); return (int)m_iterations.size(); }
getGatherArgs(int iterationNdx) const1734 	GatherArgs						getGatherArgs			(int iterationNdx) const { return m_iterations[iterationNdx].gatherArgs; }
1735 	vector<float>					computeQuadTexCoord		(int iterationNdx) const;
1736 	bool							verify					(int iterationNdx, const ConstPixelBufferAccess& rendered) const;
1737 
1738 private:
1739 	struct Iteration
1740 	{
1741 		GatherArgs	gatherArgs;
1742 		int			layerNdx;
1743 	};
1744 
1745 	const IVec3						m_textureSize;
1746 
1747 	MovePtr<glu::Texture2DArray>	m_texture;
1748 	tcu::Texture2DArray				m_swizzledTexture;
1749 	vector<Iteration>				m_iterations;
1750 };
1751 
computeQuadTexCoord(int iterationNdx) const1752 vector<float> TextureGather2DArrayCase::computeQuadTexCoord (int iterationNdx) const
1753 {
1754 	vector<float> res;
1755 	glu::TextureTestUtil::computeQuadTexCoord2DArray(res, m_iterations[iterationNdx].layerNdx, Vec2(-0.3f, -0.4f), Vec2(1.5f, 1.6f));
1756 	return res;
1757 }
1758 
generateIterations(void)1759 void TextureGather2DArrayCase::generateIterations (void)
1760 {
1761 	DE_ASSERT(m_iterations.empty());
1762 
1763 	const vector<GatherArgs> basicIterations = generateBasic2DCaseIterations(m_gatherType, m_textureFormat, getOffsetRange());
1764 
1765 	// \note Out-of-bounds layer indices are tested too.
1766 	for (int layerNdx = -1; layerNdx < m_textureSize.z()+1; layerNdx++)
1767 	{
1768 		// Don't duplicate all cases for all layers.
1769 		if (layerNdx == 0)
1770 		{
1771 			for (int basicNdx = 0; basicNdx < (int)basicIterations.size(); basicNdx++)
1772 			{
1773 				m_iterations.push_back(Iteration());
1774 				m_iterations.back().gatherArgs = basicIterations[basicNdx];
1775 				m_iterations.back().layerNdx = layerNdx;
1776 			}
1777 		}
1778 		else
1779 		{
1780 			// For other layers than 0, only test one component and one set of offsets per layer.
1781 			for (int basicNdx = 0; basicNdx < (int)basicIterations.size(); basicNdx++)
1782 			{
1783 				if (isDepthFormat(m_textureFormat) || basicIterations[basicNdx].componentNdx == (layerNdx + 2) % 4)
1784 				{
1785 					m_iterations.push_back(Iteration());
1786 					m_iterations.back().gatherArgs = basicIterations[basicNdx];
1787 					m_iterations.back().layerNdx = layerNdx;
1788 					break;
1789 				}
1790 			}
1791 		}
1792 	}
1793 }
1794 
createAndUploadTexture(void)1795 void TextureGather2DArrayCase::createAndUploadTexture (void)
1796 {
1797 	TestLog&						log			= m_testCtx.getLog();
1798 	const glu::RenderContext&		renderCtx	= m_context.getRenderContext();
1799 	const glw::Functions&			gl			= renderCtx.getFunctions();
1800 	const tcu::TextureFormatInfo	texFmtInfo	= tcu::getTextureFormatInfo(m_textureFormat);
1801 
1802 	m_texture = MovePtr<glu::Texture2DArray>(new glu::Texture2DArray(renderCtx, glu::getInternalFormat(m_textureFormat), m_textureSize.x(), m_textureSize.y(), m_textureSize.z()));
1803 
1804 	{
1805 		tcu::Texture2DArray&	refTexture	= m_texture->getRefTexture();
1806 		const int				levelBegin	= m_baseLevel;
1807 		const int				levelEnd	= isMipmapFilter(m_minFilter) && !(m_flags & GATHERCASE_MIPMAP_INCOMPLETE) ? refTexture.getNumLevels() : m_baseLevel+1;
1808 		DE_ASSERT(m_baseLevel < refTexture.getNumLevels());
1809 
1810 		for (int levelNdx = levelBegin; levelNdx < levelEnd; levelNdx++)
1811 		{
1812 			refTexture.allocLevel(levelNdx);
1813 			const PixelBufferAccess& level = refTexture.getLevel(levelNdx);
1814 			fillWithRandomColorTiles(level, texFmtInfo.valueMin, texFmtInfo.valueMax, (deUint32)m_testCtx.getCommandLine().getBaseSeed());
1815 
1816 			log << TestLog::ImageSet("InputTextureLevel", "Input texture, level " + de::toString(levelNdx));
1817 			for (int layerNdx = 0; layerNdx < m_textureSize.z(); layerNdx++)
1818 				log << TestLog::Image("InputTextureLevel" + de::toString(layerNdx) + "Layer" + de::toString(layerNdx),
1819 									  "Layer " + de::toString(layerNdx),
1820 									  tcu::getSubregion(level, 0, 0, layerNdx, level.getWidth(), level.getHeight(), 1));
1821 			log << TestLog::EndImageSet
1822 				<< TestLog::Message << "Note: texture level's size is " << IVec3(level.getWidth(), level.getHeight(), level.getDepth()) << TestLog::EndMessage;
1823 		}
1824 
1825 		swizzleTexture(m_swizzledTexture, refTexture, m_textureSwizzle);
1826 	}
1827 
1828 	gl.activeTexture(GL_TEXTURE0);
1829 	m_texture->upload();
1830 }
1831 
verify(int iterationNdx,const ConstPixelBufferAccess & rendered) const1832 bool TextureGather2DArrayCase::verify (int iterationNdx, const ConstPixelBufferAccess& rendered) const
1833 {
1834 	Vec3 texCoords[4];
1835 	computeTexCoordVecs(computeQuadTexCoord(iterationNdx), texCoords);
1836 	return TextureGatherCase::verify(rendered, getOneLevelSubView(tcu::Texture2DArrayView(m_swizzledTexture), m_baseLevel), texCoords, m_iterations[iterationNdx].gatherArgs);
1837 }
1838 
1839 // \note Cube case always uses just basic textureGather(); offset versions are not defined for cube maps.
1840 class TextureGatherCubeCase : public TextureGatherCase
1841 {
1842 public:
TextureGatherCubeCase(Context & context,const char * name,const char * description,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,deUint32 flags,int textureSize)1843 	TextureGatherCubeCase (Context&						context,
1844 						   const char*					name,
1845 						   const char*					description,
1846 						   tcu::TextureFormat			textureFormat,
1847 						   tcu::Sampler::CompareMode	shadowCompareMode,
1848 						   tcu::Sampler::WrapMode		wrapS,
1849 						   tcu::Sampler::WrapMode		wrapT,
1850 						   const MaybeTextureSwizzle&	texSwizzle,
1851 						   tcu::Sampler::FilterMode		minFilter,
1852 						   tcu::Sampler::FilterMode		magFilter,
1853 						   int							baseLevel,
1854 						   deUint32						flags,
1855 						   int							textureSize)
1856 		: TextureGatherCase		(context, name, description, TEXTURETYPE_CUBE, GATHERTYPE_BASIC, OFFSETSIZE_NONE, textureFormat, shadowCompareMode, wrapS, wrapT, texSwizzle, minFilter, magFilter, baseLevel, flags)
1857 		, m_textureSize			(textureSize)
1858 		, m_swizzledTexture		(tcu::TextureFormat(), 1)
1859 	{
1860 	}
1861 
1862 protected:
1863 	void						generateIterations		(void);
1864 	void						createAndUploadTexture	(void);
getNumIterations(void) const1865 	int							getNumIterations		(void) const { DE_ASSERT(!m_iterations.empty()); return (int)m_iterations.size(); }
getGatherArgs(int iterationNdx) const1866 	GatherArgs					getGatherArgs			(int iterationNdx) const { return m_iterations[iterationNdx].gatherArgs; }
1867 	vector<float>				computeQuadTexCoord		(int iterationNdx) const;
1868 	bool						verify					(int iterationNdx, const ConstPixelBufferAccess& rendered) const;
1869 
1870 private:
1871 	struct Iteration
1872 	{
1873 		GatherArgs		gatherArgs;
1874 		tcu::CubeFace	face;
1875 	};
1876 
1877 	const int					m_textureSize;
1878 
1879 	MovePtr<glu::TextureCube>	m_texture;
1880 	tcu::TextureCube			m_swizzledTexture;
1881 	vector<Iteration>			m_iterations;
1882 };
1883 
computeQuadTexCoord(int iterationNdx) const1884 vector<float> TextureGatherCubeCase::computeQuadTexCoord (int iterationNdx) const
1885 {
1886 	const bool		corners	= (m_flags & GATHERCASE_DONT_SAMPLE_CUBE_CORNERS) == 0;
1887 	const Vec2		minC	= corners ? Vec2(-1.2f) : Vec2(-0.6f, -1.2f);
1888 	const Vec2		maxC	= corners ? Vec2( 1.2f) : Vec2( 0.6f,  1.2f);
1889 	vector<float>	res;
1890 	glu::TextureTestUtil::computeQuadTexCoordCube(res, m_iterations[iterationNdx].face, minC, maxC);
1891 	return res;
1892 }
1893 
generateIterations(void)1894 void TextureGatherCubeCase::generateIterations (void)
1895 {
1896 	DE_ASSERT(m_iterations.empty());
1897 
1898 	const vector<GatherArgs> basicIterations = generateBasic2DCaseIterations(m_gatherType, m_textureFormat, getOffsetRange());
1899 
1900 	for (int cubeFaceI = 0; cubeFaceI < tcu::CUBEFACE_LAST; cubeFaceI++)
1901 	{
1902 		const tcu::CubeFace cubeFace = (tcu::CubeFace)cubeFaceI;
1903 
1904 		// Don't duplicate all cases for all faces.
1905 		if (cubeFaceI == 0)
1906 		{
1907 			for (int basicNdx = 0; basicNdx < (int)basicIterations.size(); basicNdx++)
1908 			{
1909 				m_iterations.push_back(Iteration());
1910 				m_iterations.back().gatherArgs = basicIterations[basicNdx];
1911 				m_iterations.back().face = cubeFace;
1912 			}
1913 		}
1914 		else
1915 		{
1916 			// For other faces than first, only test one component per face.
1917 			for (int basicNdx = 0; basicNdx < (int)basicIterations.size(); basicNdx++)
1918 			{
1919 				if (isDepthFormat(m_textureFormat) || basicIterations[basicNdx].componentNdx == cubeFaceI % 4)
1920 				{
1921 					m_iterations.push_back(Iteration());
1922 					m_iterations.back().gatherArgs = basicIterations[basicNdx];
1923 					m_iterations.back().face = cubeFace;
1924 					break;
1925 				}
1926 			}
1927 		}
1928 	}
1929 }
1930 
createAndUploadTexture(void)1931 void TextureGatherCubeCase::createAndUploadTexture (void)
1932 {
1933 	TestLog&						log			= m_testCtx.getLog();
1934 	const glu::RenderContext&		renderCtx	= m_context.getRenderContext();
1935 	const glw::Functions&			gl			= renderCtx.getFunctions();
1936 	const tcu::TextureFormatInfo	texFmtInfo	= tcu::getTextureFormatInfo(m_textureFormat);
1937 
1938 	m_texture = MovePtr<glu::TextureCube>(new glu::TextureCube(renderCtx, glu::getInternalFormat(m_textureFormat), m_textureSize));
1939 
1940 	{
1941 		tcu::TextureCube&	refTexture	= m_texture->getRefTexture();
1942 		const int			levelBegin	= m_baseLevel;
1943 		const int			levelEnd	= isMipmapFilter(m_minFilter) && !(m_flags & GATHERCASE_MIPMAP_INCOMPLETE) ? refTexture.getNumLevels() : m_baseLevel+1;
1944 		DE_ASSERT(m_baseLevel < refTexture.getNumLevels());
1945 
1946 		for (int levelNdx = levelBegin; levelNdx < levelEnd; levelNdx++)
1947 		{
1948 			log << TestLog::ImageSet("InputTextureLevel" + de::toString(levelNdx), "Input texture, level " + de::toString(levelNdx));
1949 
1950 			for (int cubeFaceI = 0; cubeFaceI < tcu::CUBEFACE_LAST; cubeFaceI++)
1951 			{
1952 				const tcu::CubeFace			cubeFace	= (tcu::CubeFace)cubeFaceI;
1953 				refTexture.allocLevel(cubeFace, levelNdx);
1954 				const PixelBufferAccess&	levelFace	= refTexture.getLevelFace(levelNdx, cubeFace);
1955 				fillWithRandomColorTiles(levelFace, texFmtInfo.valueMin, texFmtInfo.valueMax, (deUint32)m_testCtx.getCommandLine().getBaseSeed() ^ (deUint32)cubeFaceI);
1956 
1957 				m_testCtx.getLog() << TestLog::Image("InputTextureLevel" + de::toString(levelNdx) + "Face" + de::toString((int)cubeFace),
1958 													 de::toString(cubeFace),
1959 													 levelFace);
1960 			}
1961 
1962 			log << TestLog::EndImageSet
1963 				<< TestLog::Message << "Note: texture level's size is " << refTexture.getLevelFace(levelNdx, tcu::CUBEFACE_NEGATIVE_X).getWidth() << TestLog::EndMessage;
1964 		}
1965 
1966 		swizzleTexture(m_swizzledTexture, refTexture, m_textureSwizzle);
1967 	}
1968 
1969 	gl.activeTexture(GL_TEXTURE0);
1970 	m_texture->upload();
1971 }
1972 
verify(int iterationNdx,const ConstPixelBufferAccess & rendered) const1973 bool TextureGatherCubeCase::verify (int iterationNdx, const ConstPixelBufferAccess& rendered) const
1974 {
1975 	Vec3 texCoords[4];
1976 	computeTexCoordVecs(computeQuadTexCoord(iterationNdx), texCoords);
1977 	return TextureGatherCase::verify(rendered, getOneLevelSubView(tcu::TextureCubeView(m_swizzledTexture), m_baseLevel), texCoords, m_iterations[iterationNdx].gatherArgs);
1978 }
1979 
makeTextureGatherCase(TextureType textureType,Context & context,const char * name,const char * 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)1980 static inline TextureGatherCase* makeTextureGatherCase (TextureType					textureType,
1981 														Context&					context,
1982 														const char*					name,
1983 														const char*					description,
1984 														GatherType					gatherType,
1985 														OffsetSize					offsetSize,
1986 														tcu::TextureFormat			textureFormat,
1987 														tcu::Sampler::CompareMode	shadowCompareMode,
1988 														tcu::Sampler::WrapMode		wrapS,
1989 														tcu::Sampler::WrapMode		wrapT,
1990 														const MaybeTextureSwizzle&	texSwizzle,
1991 														tcu::Sampler::FilterMode	minFilter,
1992 														tcu::Sampler::FilterMode	magFilter,
1993 														int							baseLevel,
1994 														const IVec3&				textureSize,
1995 														deUint32					flags = 0)
1996 {
1997 	switch (textureType)
1998 	{
1999 		case TEXTURETYPE_2D:
2000 			return new TextureGather2DCase(context, name, description, gatherType, offsetSize, textureFormat, shadowCompareMode,
2001 										   wrapS, wrapT, texSwizzle, minFilter, magFilter, baseLevel, flags, textureSize.swizzle(0, 1));
2002 
2003 		case TEXTURETYPE_2D_ARRAY:
2004 			return new TextureGather2DArrayCase(context, name, description, gatherType, offsetSize, textureFormat, shadowCompareMode,
2005 												wrapS, wrapT, texSwizzle, minFilter, magFilter, baseLevel, flags, textureSize);
2006 
2007 		case TEXTURETYPE_CUBE:
2008 			DE_ASSERT(gatherType == GATHERTYPE_BASIC);
2009 			DE_ASSERT(offsetSize == OFFSETSIZE_NONE);
2010 			return new TextureGatherCubeCase(context, name, description, textureFormat, shadowCompareMode,
2011 											 wrapS, wrapT, texSwizzle, minFilter, magFilter, baseLevel, flags, textureSize.x());
2012 
2013 		default:
2014 			DE_ASSERT(false);
2015 			return DE_NULL;
2016 	}
2017 }
2018 
2019 } // anonymous
2020 
TextureGatherTests(Context & context)2021 TextureGatherTests::TextureGatherTests (Context& context)
2022 	: TestCaseGroup(context, "gather", "textureGather* tests")
2023 {
2024 }
2025 
compareModeName(tcu::Sampler::CompareMode mode)2026 static inline const char* compareModeName (tcu::Sampler::CompareMode mode)
2027 {
2028 	switch (mode)
2029 	{
2030 		case tcu::Sampler::COMPAREMODE_LESS:				return "less";
2031 		case tcu::Sampler::COMPAREMODE_LESS_OR_EQUAL:		return "less_or_equal";
2032 		case tcu::Sampler::COMPAREMODE_GREATER:				return "greater";
2033 		case tcu::Sampler::COMPAREMODE_GREATER_OR_EQUAL:	return "greater_or_equal";
2034 		case tcu::Sampler::COMPAREMODE_EQUAL:				return "equal";
2035 		case tcu::Sampler::COMPAREMODE_NOT_EQUAL:			return "not_equal";
2036 		case tcu::Sampler::COMPAREMODE_ALWAYS:				return "always";
2037 		case tcu::Sampler::COMPAREMODE_NEVER:				return "never";
2038 		default: DE_ASSERT(false); return DE_NULL;
2039 	}
2040 }
2041 
init(void)2042 void TextureGatherTests::init (void)
2043 {
2044 	const struct
2045 	{
2046 		const char* name;
2047 		TextureType type;
2048 	} textureTypes[] =
2049 	{
2050 		{ "2d",			TEXTURETYPE_2D			},
2051 		{ "2d_array",	TEXTURETYPE_2D_ARRAY	},
2052 		{ "cube",		TEXTURETYPE_CUBE		}
2053 	};
2054 
2055 	const struct
2056 	{
2057 		const char*			name;
2058 		tcu::TextureFormat	format;
2059 	} formats[] =
2060 	{
2061 		{ "rgba8",		tcu::TextureFormat(tcu::TextureFormat::RGBA,	tcu::TextureFormat::UNORM_INT8)		},
2062 		{ "rgba8ui",	tcu::TextureFormat(tcu::TextureFormat::RGBA,	tcu::TextureFormat::UNSIGNED_INT8)	},
2063 		{ "rgba8i",		tcu::TextureFormat(tcu::TextureFormat::RGBA,	tcu::TextureFormat::SIGNED_INT8)	},
2064 		{ "depth32f",	tcu::TextureFormat(tcu::TextureFormat::D,		tcu::TextureFormat::FLOAT)			}
2065 	};
2066 
2067 	const struct
2068 	{
2069 		const char*		name;
2070 		IVec3			size;
2071 	} textureSizes[] =
2072 	{
2073 		{ "size_pot",	IVec3(64, 64, 3) },
2074 		{ "size_npot",	IVec3(17, 23, 3) }
2075 	};
2076 
2077 	const struct
2078 	{
2079 		const char*				name;
2080 		tcu::Sampler::WrapMode	mode;
2081 	} wrapModes[] =
2082 	{
2083 		{ "clamp_to_edge",		tcu::Sampler::CLAMP_TO_EDGE			},
2084 		{ "repeat",				tcu::Sampler::REPEAT_GL				},
2085 		{ "mirrored_repeat",	tcu::Sampler::MIRRORED_REPEAT_GL	}
2086 	};
2087 
2088 	for (int gatherTypeI = 0; gatherTypeI < GATHERTYPE_LAST; gatherTypeI++)
2089 	{
2090 		const GatherType		gatherType			= (GatherType)gatherTypeI;
2091 		TestCaseGroup* const	gatherTypeGroup		= new TestCaseGroup(m_context, gatherTypeName(gatherType), gatherTypeDescription(gatherType));
2092 		addChild(gatherTypeGroup);
2093 
2094 		for (int offsetSizeI = 0; offsetSizeI < OFFSETSIZE_LAST; offsetSizeI++)
2095 		{
2096 			const OffsetSize offsetSize = (OffsetSize)offsetSizeI;
2097 			if ((gatherType == GATHERTYPE_BASIC) != (offsetSize == OFFSETSIZE_NONE))
2098 				continue;
2099 
2100 			TestCaseGroup* const offsetSizeGroup = offsetSize == OFFSETSIZE_NONE ?
2101 													gatherTypeGroup :
2102 													new TestCaseGroup(m_context,
2103 																	  offsetSize == OFFSETSIZE_MINIMUM_REQUIRED				? "min_required_offset"
2104 																	  : offsetSize == OFFSETSIZE_IMPLEMENTATION_MAXIMUM		? "implementation_offset"
2105 																	  : DE_NULL,
2106 																	  offsetSize == OFFSETSIZE_MINIMUM_REQUIRED				? "Use offsets within GL minimum required range"
2107 																	  : offsetSize == OFFSETSIZE_IMPLEMENTATION_MAXIMUM		? "Use offsets within the implementation range"
2108 																	  : DE_NULL);
2109 			if (offsetSizeGroup != gatherTypeGroup)
2110 				gatherTypeGroup->addChild(offsetSizeGroup);
2111 
2112 			for (int textureTypeNdx = 0; textureTypeNdx < DE_LENGTH_OF_ARRAY(textureTypes); textureTypeNdx++)
2113 			{
2114 				const TextureType textureType = textureTypes[textureTypeNdx].type;
2115 
2116 				if (textureType == TEXTURETYPE_CUBE && gatherType != GATHERTYPE_BASIC)
2117 					continue;
2118 
2119 				TestCaseGroup* const textureTypeGroup = new TestCaseGroup(m_context, textureTypes[textureTypeNdx].name, "");
2120 				offsetSizeGroup->addChild(textureTypeGroup);
2121 
2122 				for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(formats); formatNdx++)
2123 				{
2124 					const tcu::TextureFormat&	format			= formats[formatNdx].format;
2125 					TestCaseGroup* const		formatGroup		= new TestCaseGroup(m_context, formats[formatNdx].name, "");
2126 					textureTypeGroup->addChild(formatGroup);
2127 
2128 					for (int noCornersI = 0; noCornersI <= ((textureType == TEXTURETYPE_CUBE)?1:0); noCornersI++)
2129 					{
2130 						const bool				noCorners		= noCornersI!= 0;
2131 						TestCaseGroup* const	cornersGroup	= noCorners
2132 																? new TestCaseGroup(m_context, "no_corners", "Test case variants that don't sample around cube map corners")
2133 																: formatGroup;
2134 
2135 						if (formatGroup != cornersGroup)
2136 							formatGroup->addChild(cornersGroup);
2137 
2138 						for (int textureSizeNdx = 0; textureSizeNdx < DE_LENGTH_OF_ARRAY(textureSizes); textureSizeNdx++)
2139 						{
2140 							const IVec3&			textureSize			= textureSizes[textureSizeNdx].size;
2141 							TestCaseGroup* const	textureSizeGroup	= new TestCaseGroup(m_context, textureSizes[textureSizeNdx].name, "");
2142 							cornersGroup->addChild(textureSizeGroup);
2143 
2144 							for (int compareModeI = 0; compareModeI < tcu::Sampler::COMPAREMODE_LAST; compareModeI++)
2145 							{
2146 								const tcu::Sampler::CompareMode compareMode = (tcu::Sampler::CompareMode)compareModeI;
2147 
2148 								if ((compareMode != tcu::Sampler::COMPAREMODE_NONE) != isDepthFormat(format))
2149 									continue;
2150 
2151 								if (compareMode != tcu::Sampler::COMPAREMODE_NONE &&
2152 									compareMode != tcu::Sampler::COMPAREMODE_LESS &&
2153 									compareMode != tcu::Sampler::COMPAREMODE_GREATER)
2154 									continue;
2155 
2156 								TestCaseGroup* const compareModeGroup = compareMode == tcu::Sampler::COMPAREMODE_NONE ?
2157 																			textureSizeGroup :
2158 																			new TestCaseGroup(m_context,
2159 																							  (string() + "compare_" + compareModeName(compareMode)).c_str(),
2160 																							  "");
2161 								if (compareModeGroup != textureSizeGroup)
2162 									textureSizeGroup->addChild(compareModeGroup);
2163 
2164 								for (int wrapCaseNdx = 0; wrapCaseNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapCaseNdx++)
2165 								{
2166 									const int						wrapSNdx	= wrapCaseNdx;
2167 									const int						wrapTNdx	= (wrapCaseNdx + 1) % DE_LENGTH_OF_ARRAY(wrapModes);
2168 									const tcu::Sampler::WrapMode	wrapS		= wrapModes[wrapSNdx].mode;
2169 									const tcu::Sampler::WrapMode	wrapT		= wrapModes[wrapTNdx].mode;
2170 
2171 									const string caseName = string() + wrapModes[wrapSNdx].name + "_" + wrapModes[wrapTNdx].name;
2172 
2173 									compareModeGroup->addChild(makeTextureGatherCase(textureType, m_context, caseName.c_str(), "", gatherType, offsetSize, format, compareMode, wrapS, wrapT,
2174 																					 MaybeTextureSwizzle::createNoneTextureSwizzle(), tcu::Sampler::NEAREST, tcu::Sampler::NEAREST, 0, textureSize,
2175 																					 noCorners ? GATHERCASE_DONT_SAMPLE_CUBE_CORNERS : 0));
2176 								}
2177 							}
2178 						}
2179 					}
2180 
2181 					if (offsetSize != OFFSETSIZE_MINIMUM_REQUIRED) // Don't test all features for both offset size types, as they should be rather orthogonal.
2182 					{
2183 						if (!isDepthFormat(format))
2184 						{
2185 							TestCaseGroup* const swizzleGroup = new TestCaseGroup(m_context, "texture_swizzle", "");
2186 							formatGroup->addChild(swizzleGroup);
2187 
2188 							DE_STATIC_ASSERT(TEXTURESWIZZLECOMPONENT_R == 0);
2189 							for (int swizzleCaseNdx = 0; swizzleCaseNdx < TEXTURESWIZZLECOMPONENT_LAST; swizzleCaseNdx++)
2190 							{
2191 								MaybeTextureSwizzle	swizzle	= MaybeTextureSwizzle::createSomeTextureSwizzle();
2192 								string				caseName;
2193 
2194 								for (int i = 0; i < 4; i++)
2195 								{
2196 									swizzle.getSwizzle()[i] = (TextureSwizzleComponent)((swizzleCaseNdx + i) % (int)TEXTURESWIZZLECOMPONENT_LAST);
2197 									caseName += (i > 0 ? "_" : "") + de::toLower(de::toString(swizzle.getSwizzle()[i]));
2198 								}
2199 
2200 								swizzleGroup->addChild(makeTextureGatherCase(textureType, m_context, caseName.c_str(), "", gatherType, offsetSize, format,
2201 																			 tcu::Sampler::COMPAREMODE_NONE, tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL,
2202 																			 swizzle, tcu::Sampler::NEAREST, tcu::Sampler::NEAREST, 0, IVec3(64, 64, 3)));
2203 							}
2204 						}
2205 
2206 						{
2207 							TestCaseGroup* const filterModeGroup = new TestCaseGroup(m_context, "filter_mode", "Test that filter modes have no effect");
2208 							formatGroup->addChild(filterModeGroup);
2209 
2210 							const struct
2211 							{
2212 								const char*					name;
2213 								tcu::Sampler::FilterMode	filter;
2214 							} magFilters[] =
2215 							{
2216 								{ "linear",		tcu::Sampler::LINEAR	},
2217 								{ "nearest",	tcu::Sampler::NEAREST	}
2218 							};
2219 
2220 							const struct
2221 							{
2222 								const char*					name;
2223 								tcu::Sampler::FilterMode	filter;
2224 							} minFilters[] =
2225 							{
2226 								// \note Don't test NEAREST here, as it's covered by other cases.
2227 								{ "linear",						tcu::Sampler::LINEAR					},
2228 								{ "nearest_mipmap_nearest",		tcu::Sampler::NEAREST_MIPMAP_NEAREST	},
2229 								{ "nearest_mipmap_linear",		tcu::Sampler::NEAREST_MIPMAP_LINEAR		},
2230 								{ "linear_mipmap_nearest",		tcu::Sampler::LINEAR_MIPMAP_NEAREST		},
2231 								{ "linear_mipmap_linear",		tcu::Sampler::LINEAR_MIPMAP_LINEAR		},
2232 							};
2233 
2234 							for (int minFilterNdx = 0; minFilterNdx < DE_LENGTH_OF_ARRAY(minFilters); minFilterNdx++)
2235 							for (int magFilterNdx = 0; magFilterNdx < DE_LENGTH_OF_ARRAY(magFilters); magFilterNdx++)
2236 							{
2237 								const tcu::Sampler::FilterMode		minFilter		= minFilters[minFilterNdx].filter;
2238 								const tcu::Sampler::FilterMode		magFilter		= magFilters[magFilterNdx].filter;
2239 								const tcu::Sampler::CompareMode		compareMode		= isDepthFormat(format) ? tcu::Sampler::COMPAREMODE_LESS : tcu::Sampler::COMPAREMODE_NONE;
2240 
2241 								if ((isUnormFormatType(format.type) || isDepthFormat(format)) && magFilter == tcu::Sampler::NEAREST)
2242 									continue; // Covered by other cases.
2243 								if ((isUIntFormatType(format.type) || isSIntFormatType(format.type)) &&
2244 									(magFilter != tcu::Sampler::NEAREST || minFilter != tcu::Sampler::NEAREST_MIPMAP_NEAREST))
2245 									continue;
2246 
2247 								const string caseName = string() + "min_" + minFilters[minFilterNdx].name + "_mag_" + magFilters[magFilterNdx].name;
2248 
2249 								filterModeGroup->addChild(makeTextureGatherCase(textureType, m_context, caseName.c_str(), "", gatherType, offsetSize, format, compareMode,
2250 																				tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL, MaybeTextureSwizzle::createNoneTextureSwizzle(),
2251 																				minFilter, magFilter, 0, IVec3(64, 64, 3)));
2252 							}
2253 						}
2254 
2255 						{
2256 							TestCaseGroup* const baseLevelGroup = new TestCaseGroup(m_context, "base_level", "");
2257 							formatGroup->addChild(baseLevelGroup);
2258 
2259 							for (int baseLevel = 1; baseLevel <= 2; baseLevel++)
2260 							{
2261 								const string						caseName		= "level_" + de::toString(baseLevel);
2262 								const tcu::Sampler::CompareMode		compareMode		= isDepthFormat(format) ? tcu::Sampler::COMPAREMODE_LESS : tcu::Sampler::COMPAREMODE_NONE;
2263 								baseLevelGroup->addChild(makeTextureGatherCase(textureType, m_context, caseName.c_str(), "", gatherType, offsetSize, format,
2264 																			   compareMode, tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL,
2265 																			   MaybeTextureSwizzle::createNoneTextureSwizzle(), tcu::Sampler::NEAREST, tcu::Sampler::NEAREST,
2266 																			   baseLevel, IVec3(64, 64, 3)));
2267 							}
2268 						}
2269 
2270 						// What shadow textures should return for incomplete textures is unclear.
2271 						// Integer and unsigned integer lookups from incomplete textures return undefined values.
2272 						if (!isDepthFormat(format) && !isSIntFormatType(format.type) && !isUIntFormatType(format.type))
2273 						{
2274 							TestCaseGroup* const incompleteGroup = new TestCaseGroup(m_context, "incomplete", "Test that textureGather* takes components from (0,0,0,1) for incomplete textures");
2275 							formatGroup->addChild(incompleteGroup);
2276 
2277 							const tcu::Sampler::CompareMode compareMode = isDepthFormat(format) ? tcu::Sampler::COMPAREMODE_LESS : tcu::Sampler::COMPAREMODE_NONE;
2278 							incompleteGroup->addChild(makeTextureGatherCase(textureType, m_context, "mipmap_incomplete", "", gatherType, offsetSize, format,
2279 																			compareMode, tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL,
2280 																			MaybeTextureSwizzle::createNoneTextureSwizzle(), tcu::Sampler::NEAREST_MIPMAP_NEAREST, tcu::Sampler::NEAREST,
2281 																			0, IVec3(64, 64, 3), GATHERCASE_MIPMAP_INCOMPLETE));
2282 						}
2283 					}
2284 				}
2285 			}
2286 		}
2287 	}
2288 }
2289 
2290 } // Functional
2291 } // gles31
2292 } // deqp
2293