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