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