1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 2.0 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 Texture access function tests.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "es2fShaderTextureFunctionTests.hpp"
25 #include "glsShaderRenderCase.hpp"
26 #include "glsShaderLibrary.hpp"
27 #include "glsTextureTestUtil.hpp"
28 #include "gluTexture.hpp"
29 #include "gluTextureUtil.hpp"
30 #include "tcuTextureUtil.hpp"
31 #include "tcuMatrix.hpp"
32 #include "tcuMatrixUtil.hpp"
33 
34 #include <sstream>
35 
36 #include "glwEnums.hpp"
37 #include "glwFunctions.hpp"
38 
39 namespace deqp
40 {
41 namespace gles2
42 {
43 namespace Functional
44 {
45 
46 namespace
47 {
48 
49 enum Function
50 {
51 	FUNCTION_TEXTURE = 0,		//!< texture(), textureOffset()
52 	FUNCTION_TEXTUREPROJ,		//!< textureProj(), textureProjOffset()
53 	FUNCTION_TEXTUREPROJ3,		//!< textureProj(sampler2D, vec3)
54 	FUNCTION_TEXTURELOD,		// ...
55 	FUNCTION_TEXTUREPROJLOD,
56 	FUNCTION_TEXTUREPROJLOD3,	//!< textureProjLod(sampler2D, vec3)
57 
58 	FUNCTION_LAST
59 };
60 
functionHasProj(Function function)61 inline bool functionHasProj (Function function)
62 {
63 	return function == FUNCTION_TEXTUREPROJ		||
64 		   function == FUNCTION_TEXTUREPROJ3	||
65 		   function == FUNCTION_TEXTUREPROJLOD	||
66 		   function == FUNCTION_TEXTUREPROJLOD3;
67 }
68 
functionHasLod(Function function)69 inline bool functionHasLod (Function function)
70 {
71 	return function == FUNCTION_TEXTURELOD		||
72 		   function == FUNCTION_TEXTUREPROJLOD	||
73 		   function == FUNCTION_TEXTUREPROJLOD3;
74 }
75 
76 struct TextureLookupSpec
77 {
78 	Function		function;
79 
80 	tcu::Vec4		minCoord;
81 	tcu::Vec4		maxCoord;
82 
83 	// Bias
84 	bool			useBias;
85 
86 	// Bias or Lod for *Lod* functions
87 	float			minLodBias;
88 	float			maxLodBias;
89 
TextureLookupSpecdeqp::gles2::Functional::__anonaaf110620111::TextureLookupSpec90 	TextureLookupSpec (void)
91 		: function		(FUNCTION_LAST)
92 		, minCoord		(0.0f)
93 		, maxCoord		(1.0f)
94 		, useBias		(false)
95 		, minLodBias	(0.0f)
96 		, maxLodBias	(0.0f)
97 	{
98 	}
99 
TextureLookupSpecdeqp::gles2::Functional::__anonaaf110620111::TextureLookupSpec100 	TextureLookupSpec (Function				function_,
101 					   const tcu::Vec4&		minCoord_,
102 					   const tcu::Vec4&		maxCoord_,
103 					   bool					useBias_,
104 					   float				minLodBias_,
105 					   float				maxLodBias_)
106 		: function		(function_)
107 		, minCoord		(minCoord_)
108 		, maxCoord		(maxCoord_)
109 		, useBias		(useBias_)
110 		, minLodBias	(minLodBias_)
111 		, maxLodBias	(maxLodBias_)
112 	{
113 	}
114 };
115 
116 enum TextureType
117 {
118 	TEXTURETYPE_2D,
119 	TEXTURETYPE_CUBE_MAP,
120 
121 	TEXTURETYPE_LAST
122 };
123 
124 struct TextureSpec
125 {
126 	TextureType			type;		//!< Texture type (2D, cubemap, ...)
127 	deUint32			format;
128 	deUint32			dataType;
129 	int					width;
130 	int					height;
131 	int					numLevels;
132 	tcu::Sampler		sampler;
133 
TextureSpecdeqp::gles2::Functional::__anonaaf110620111::TextureSpec134 	TextureSpec (void)
135 		: type			(TEXTURETYPE_LAST)
136 		, format		(GL_NONE)
137 		, dataType		(GL_NONE)
138 		, width			(0)
139 		, height		(0)
140 		, numLevels		(0)
141 	{
142 	}
143 
TextureSpecdeqp::gles2::Functional::__anonaaf110620111::TextureSpec144 	TextureSpec (TextureType			type_,
145 				 deUint32				format_,
146 				 deUint32				dataType_,
147 				 int					width_,
148 				 int					height_,
149 				 int					numLevels_,
150 				 const tcu::Sampler&	sampler_)
151 		: type			(type_)
152 		, format		(format_)
153 		, dataType		(dataType_)
154 		, width			(width_)
155 		, height		(height_)
156 		, numLevels		(numLevels_)
157 		, sampler		(sampler_)
158 	{
159 	}
160 };
161 
162 struct TexLookupParams
163 {
164 	float				lod;
165 	tcu::Vec4			scale;
166 	tcu::Vec4			bias;
167 
TexLookupParamsdeqp::gles2::Functional::__anonaaf110620111::TexLookupParams168 	TexLookupParams (void)
169 		: lod		(0.0f)
170 		, scale		(1.0f)
171 		, bias		(0.0f)
172 	{
173 	}
174 };
175 
176 } // anonymous
177 
178 using tcu::Vec2;
179 using tcu::Vec3;
180 using tcu::Vec4;
181 using tcu::IVec2;
182 using tcu::IVec3;
183 using tcu::IVec4;
184 
185 typedef void (*TexEvalFunc) (gls::ShaderEvalContext& c, const TexLookupParams& lookupParams);
186 
texture2D(const gls::ShaderEvalContext & c,float s,float t,float lod)187 inline Vec4 texture2D		(const gls::ShaderEvalContext& c, float s, float t, float lod)			{ return c.textures[0].tex2D->sample(c.textures[0].sampler, s, t, lod);			}
textureCube(const gls::ShaderEvalContext & c,float s,float t,float r,float lod)188 inline Vec4 textureCube		(const gls::ShaderEvalContext& c, float s, float t, float r, float lod)	{ return c.textures[0].texCube->sample(c.textures[0].sampler, s, t, r, lod);	}
189 
190 // Eval functions.
evalTexture2D(gls::ShaderEvalContext & c,const TexLookupParams & p)191 static void		evalTexture2D			(gls::ShaderEvalContext& c, const TexLookupParams& p)	{ c.color = texture2D(c, c.in[0].x(), c.in[0].y(), p.lod)*p.scale + p.bias; }
evalTextureCube(gls::ShaderEvalContext & c,const TexLookupParams & p)192 static void		evalTextureCube			(gls::ShaderEvalContext& c, const TexLookupParams& p)	{ c.color = textureCube(c, c.in[0].x(), c.in[0].y(), c.in[0].z(), p.lod)*p.scale + p.bias; }
193 
evalTexture2DBias(gls::ShaderEvalContext & c,const TexLookupParams & p)194 static void		evalTexture2DBias		(gls::ShaderEvalContext& c, const TexLookupParams& p)	{ c.color = texture2D(c, c.in[0].x(), c.in[0].y(), p.lod+c.in[1].x())*p.scale + p.bias; }
evalTextureCubeBias(gls::ShaderEvalContext & c,const TexLookupParams & p)195 static void		evalTextureCubeBias		(gls::ShaderEvalContext& c, const TexLookupParams& p)	{ c.color = textureCube(c, c.in[0].x(), c.in[0].y(), c.in[0].z(), p.lod+c.in[1].x())*p.scale + p.bias; }
196 
evalTexture2DProj3(gls::ShaderEvalContext & c,const TexLookupParams & p)197 static void		evalTexture2DProj3		(gls::ShaderEvalContext& c, const TexLookupParams& p)	{ c.color = texture2D(c, c.in[0].x()/c.in[0].z(), c.in[0].y()/c.in[0].z(), p.lod)*p.scale + p.bias; }
evalTexture2DProj3Bias(gls::ShaderEvalContext & c,const TexLookupParams & p)198 static void		evalTexture2DProj3Bias	(gls::ShaderEvalContext& c, const TexLookupParams& p)	{ c.color = texture2D(c, c.in[0].x()/c.in[0].z(), c.in[0].y()/c.in[0].z(), p.lod+c.in[1].x())*p.scale + p.bias; }
evalTexture2DProj(gls::ShaderEvalContext & c,const TexLookupParams & p)199 static void		evalTexture2DProj		(gls::ShaderEvalContext& c, const TexLookupParams& p)	{ c.color = texture2D(c, c.in[0].x()/c.in[0].w(), c.in[0].y()/c.in[0].w(), p.lod)*p.scale + p.bias; }
evalTexture2DProjBias(gls::ShaderEvalContext & c,const TexLookupParams & p)200 static void		evalTexture2DProjBias	(gls::ShaderEvalContext& c, const TexLookupParams& p)	{ c.color = texture2D(c, c.in[0].x()/c.in[0].w(), c.in[0].y()/c.in[0].w(), p.lod+c.in[1].x())*p.scale + p.bias; }
201 
evalTexture2DLod(gls::ShaderEvalContext & c,const TexLookupParams & p)202 static void		evalTexture2DLod		(gls::ShaderEvalContext& c, const TexLookupParams& p)	{ c.color = texture2D(c, c.in[0].x(), c.in[0].y(), c.in[1].x())*p.scale + p.bias; }
evalTextureCubeLod(gls::ShaderEvalContext & c,const TexLookupParams & p)203 static void		evalTextureCubeLod		(gls::ShaderEvalContext& c, const TexLookupParams& p)	{ c.color = textureCube(c, c.in[0].x(), c.in[0].y(), c.in[0].z(), c.in[1].x())*p.scale + p.bias; }
204 
evalTexture2DProjLod3(gls::ShaderEvalContext & c,const TexLookupParams & p)205 static void		evalTexture2DProjLod3	(gls::ShaderEvalContext& c, const TexLookupParams& p)	{ c.color = texture2D(c, c.in[0].x()/c.in[0].z(), c.in[0].y()/c.in[0].z(), c.in[1].x())*p.scale + p.bias; }
evalTexture2DProjLod(gls::ShaderEvalContext & c,const TexLookupParams & p)206 static void		evalTexture2DProjLod	(gls::ShaderEvalContext& c, const TexLookupParams& p)	{ c.color = texture2D(c, c.in[0].x()/c.in[0].w(), c.in[0].y()/c.in[0].w(), c.in[1].x())*p.scale + p.bias; }
207 
208 class TexLookupEvaluator : public gls::ShaderEvaluator
209 {
210 public:
TexLookupEvaluator(TexEvalFunc evalFunc,const TexLookupParams & lookupParams)211 							TexLookupEvaluator		(TexEvalFunc evalFunc, const TexLookupParams& lookupParams) : m_evalFunc(evalFunc), m_lookupParams(lookupParams) {}
212 
evaluate(gls::ShaderEvalContext & ctx)213 	virtual void			evaluate				(gls::ShaderEvalContext& ctx) { m_evalFunc(ctx, m_lookupParams); }
214 
215 private:
216 	TexEvalFunc				m_evalFunc;
217 	const TexLookupParams&	m_lookupParams;
218 };
219 
220 class ShaderTextureFunctionCase : public gls::ShaderRenderCase
221 {
222 public:
223 							ShaderTextureFunctionCase		(Context& context, const char* name, const char* desc, const TextureLookupSpec& lookup, const TextureSpec& texture, TexEvalFunc evalFunc, bool isVertexCase);
224 							~ShaderTextureFunctionCase		(void);
225 
226 	void					init							(void);
227 	void					deinit							(void);
228 
229 protected:
230 	void					setupUniforms					(int programID, const tcu::Vec4& constCoords);
231 
232 private:
233 	void					initTexture						(void);
234 	void					initShaderSources				(void);
235 
236 	TextureLookupSpec		m_lookupSpec;
237 	TextureSpec				m_textureSpec;
238 
239 	TexLookupParams			m_lookupParams;
240 	TexLookupEvaluator		m_evaluator;
241 
242 	glu::Texture2D*			m_texture2D;
243 	glu::TextureCube*		m_textureCube;
244 };
245 
ShaderTextureFunctionCase(Context & context,const char * name,const char * desc,const TextureLookupSpec & lookup,const TextureSpec & texture,TexEvalFunc evalFunc,bool isVertexCase)246 ShaderTextureFunctionCase::ShaderTextureFunctionCase (Context& context, const char* name, const char* desc, const TextureLookupSpec& lookup, const TextureSpec& texture, TexEvalFunc evalFunc, bool isVertexCase)
247 	: gls::ShaderRenderCase(context.getTestContext(), context.getRenderContext(), context.getContextInfo(), name, desc, isVertexCase, m_evaluator)
248 	, m_lookupSpec			(lookup)
249 	, m_textureSpec			(texture)
250 	, m_evaluator			(evalFunc, m_lookupParams)
251 	, m_texture2D			(DE_NULL)
252 	, m_textureCube			(DE_NULL)
253 {
254 }
255 
~ShaderTextureFunctionCase(void)256 ShaderTextureFunctionCase::~ShaderTextureFunctionCase (void)
257 {
258 	delete m_texture2D;
259 	delete m_textureCube;
260 }
261 
init(void)262 void ShaderTextureFunctionCase::init (void)
263 {
264 	if (m_isVertexCase)
265 	{
266 		const glw::Functions& gl = m_renderCtx.getFunctions();
267 		int numVertexUnits = 0;
268 		gl.getIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &numVertexUnits);
269 		if (numVertexUnits < 1)
270 			throw tcu::NotSupportedError("Vertex shader texture access is not supported");
271 	}
272 
273 	{
274 		// Base coord scale & bias
275 		Vec4 s = m_lookupSpec.maxCoord-m_lookupSpec.minCoord;
276 		Vec4 b = m_lookupSpec.minCoord;
277 
278 		float baseCoordTrans[] =
279 		{
280 			s.x(),		0.0f,		0.f,	b.x(),
281 			0.f,		s.y(),		0.f,	b.y(),
282 			s.z()/2.f,	-s.z()/2.f,	0.f,	s.z()/2.f + b.z(),
283 			-s.w()/2.f,	s.w()/2.f,	0.f,	s.w()/2.f + b.w()
284 		};
285 
286 		m_userAttribTransforms.push_back(tcu::Mat4(baseCoordTrans));
287 	}
288 
289 	if (functionHasLod(m_lookupSpec.function) || m_lookupSpec.useBias)
290 	{
291 		float s = m_lookupSpec.maxLodBias-m_lookupSpec.minLodBias;
292 		float b = m_lookupSpec.minLodBias;
293 		float lodCoordTrans[] =
294 		{
295 			s/2.0f,		s/2.0f,		0.f,	b,
296 			0.0f,		0.0f,		0.0f,	0.0f,
297 			0.0f,		0.0f,		0.0f,	0.0f,
298 			0.0f,		0.0f,		0.0f,	0.0f
299 		};
300 
301 		m_userAttribTransforms.push_back(tcu::Mat4(lodCoordTrans));
302 	}
303 
304 	initShaderSources();
305 	initTexture();
306 
307 	gls::ShaderRenderCase::init();
308 }
309 
initTexture(void)310 void ShaderTextureFunctionCase::initTexture (void)
311 {
312 	static const IVec4 texCubeSwz[] =
313 	{
314 		IVec4(0,0,1,1),
315 		IVec4(1,1,0,0),
316 		IVec4(0,1,0,1),
317 		IVec4(1,0,1,0),
318 		IVec4(0,1,1,0),
319 		IVec4(1,0,0,1)
320 	};
321 	DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(texCubeSwz) == tcu::CUBEFACE_LAST);
322 
323 	tcu::TextureFormat		texFmt			= glu::mapGLTransferFormat(m_textureSpec.format, m_textureSpec.dataType);
324 	tcu::TextureFormatInfo	fmtInfo			= tcu::getTextureFormatInfo(texFmt);
325 	tcu::IVec2				viewportSize	= getViewportSize();
326 	bool					isProj			= functionHasProj(m_lookupSpec.function);
327 	float					proj			= isProj ? 1.0f/m_lookupSpec.minCoord[m_lookupSpec.function == FUNCTION_TEXTUREPROJ3 ? 2 : 3] : 1.0f;
328 
329 	switch (m_textureSpec.type)
330 	{
331 		case TEXTURETYPE_2D:
332 		{
333 			float	cStep			= 1.0f / (float)de::max(1, m_textureSpec.numLevels-1);
334 			Vec4	cScale			= fmtInfo.valueMax-fmtInfo.valueMin;
335 			Vec4	cBias			= fmtInfo.valueMin;
336 			int		baseCellSize	= de::min(m_textureSpec.width/4, m_textureSpec.height/4);
337 
338 			m_texture2D = new glu::Texture2D(m_renderCtx, m_textureSpec.format, m_textureSpec.dataType, m_textureSpec.width, m_textureSpec.height);
339 			for (int level = 0; level < m_textureSpec.numLevels; level++)
340 			{
341 				float	fA		= float(level)*cStep;
342 				float	fB		= 1.0f-fA;
343 				Vec4	colorA	= cBias + cScale*Vec4(fA, fB, fA, fB);
344 				Vec4	colorB	= cBias + cScale*Vec4(fB, fA, fB, fA);
345 
346 				m_texture2D->getRefTexture().allocLevel(level);
347 				tcu::fillWithGrid(m_texture2D->getRefTexture().getLevel(level), de::max(1, baseCellSize>>level), colorA, colorB);
348 			}
349 			m_texture2D->upload();
350 
351 			// Compute LOD.
352 			float dudx = (m_lookupSpec.maxCoord[0]-m_lookupSpec.minCoord[0])*proj*(float)m_textureSpec.width	/ (float)viewportSize[0];
353 			float dvdy = (m_lookupSpec.maxCoord[1]-m_lookupSpec.minCoord[1])*proj*(float)m_textureSpec.height	/ (float)viewportSize[1];
354 			m_lookupParams.lod = gls::TextureTestUtil::computeLodFromDerivates(gls::TextureTestUtil::LODMODE_EXACT, dudx, 0.0f, 0.0f, dvdy);
355 
356 			// Append to texture list.
357 			m_textures.push_back(gls::TextureBinding(m_texture2D, m_textureSpec.sampler));
358 			break;
359 		}
360 
361 		case TEXTURETYPE_CUBE_MAP:
362 		{
363 			float	cStep			= 1.0f / (float)de::max(1, m_textureSpec.numLevels-1);
364 			Vec4	cScale			= fmtInfo.valueMax-fmtInfo.valueMin;
365 			Vec4	cBias			= fmtInfo.valueMin;
366 			int		baseCellSize	= de::min(m_textureSpec.width/4, m_textureSpec.height/4);
367 
368 			DE_ASSERT(m_textureSpec.width == m_textureSpec.height);
369 			m_textureCube = new glu::TextureCube(m_renderCtx, m_textureSpec.format, m_textureSpec.dataType, m_textureSpec.width);
370 			for (int level = 0; level < m_textureSpec.numLevels; level++)
371 			{
372 				float	fA		= float(level)*cStep;
373 				float	fB		= 1.0f-fA;
374 				Vec2	f		(fA, fB);
375 
376 				for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
377 				{
378 					const IVec4&	swzA	= texCubeSwz[face];
379 					IVec4			swzB	= 1-swzA;
380 					Vec4			colorA	= cBias + cScale*f.swizzle(swzA[0], swzA[1], swzA[2], swzA[3]);
381 					Vec4			colorB	= cBias + cScale*f.swizzle(swzB[0], swzB[1], swzB[2], swzB[3]);
382 
383 					m_textureCube->getRefTexture().allocLevel((tcu::CubeFace)face, level);
384 					tcu::fillWithGrid(m_textureCube->getRefTexture().getLevelFace(level, (tcu::CubeFace)face), de::max(1, baseCellSize>>level), colorA, colorB);
385 				}
386 			}
387 			m_textureCube->upload();
388 
389 			// Compute LOD \note Assumes that only single side is accessed and R is constant major axis.
390 			DE_ASSERT(de::abs(m_lookupSpec.minCoord[2] - m_lookupSpec.maxCoord[2]) < 0.005);
391 			DE_ASSERT(de::abs(m_lookupSpec.minCoord[0]) < de::abs(m_lookupSpec.minCoord[2]) && de::abs(m_lookupSpec.maxCoord[0]) < de::abs(m_lookupSpec.minCoord[2]));
392 			DE_ASSERT(de::abs(m_lookupSpec.minCoord[1]) < de::abs(m_lookupSpec.minCoord[2]) && de::abs(m_lookupSpec.maxCoord[1]) < de::abs(m_lookupSpec.minCoord[2]));
393 
394 			tcu::CubeFaceFloatCoords	c00		= tcu::getCubeFaceCoords(Vec3(m_lookupSpec.minCoord[0]*proj, m_lookupSpec.minCoord[1]*proj, m_lookupSpec.minCoord[2]*proj));
395 			tcu::CubeFaceFloatCoords	c10		= tcu::getCubeFaceCoords(Vec3(m_lookupSpec.maxCoord[0]*proj, m_lookupSpec.minCoord[1]*proj, m_lookupSpec.minCoord[2]*proj));
396 			tcu::CubeFaceFloatCoords	c01		= tcu::getCubeFaceCoords(Vec3(m_lookupSpec.minCoord[0]*proj, m_lookupSpec.maxCoord[1]*proj, m_lookupSpec.minCoord[2]*proj));
397 			float						dudx	= (c10.s - c00.s)*(float)m_textureSpec.width	/ (float)viewportSize[0];
398 			float						dvdy	= (c01.t - c00.t)*(float)m_textureSpec.height	/ (float)viewportSize[1];
399 
400 			m_lookupParams.lod = gls::TextureTestUtil::computeLodFromDerivates(gls::TextureTestUtil::LODMODE_EXACT, dudx, 0.0f, 0.0f, dvdy);
401 
402 			m_textures.push_back(gls::TextureBinding(m_textureCube, m_textureSpec.sampler));
403 			break;
404 		}
405 
406 		default:
407 			DE_ASSERT(DE_FALSE);
408 	}
409 
410 	// Set lookup scale & bias
411 	m_lookupParams.scale	= fmtInfo.lookupScale;
412 	m_lookupParams.bias		= fmtInfo.lookupBias;
413 }
414 
initShaderSources(void)415 void ShaderTextureFunctionCase::initShaderSources (void)
416 {
417 	Function			function			= m_lookupSpec.function;
418 	bool				isVtxCase			= m_isVertexCase;
419 	bool				isProj				= functionHasProj(function);
420 	bool				is2DProj4			= m_textureSpec.type == TEXTURETYPE_2D && (function == FUNCTION_TEXTUREPROJ || function == FUNCTION_TEXTUREPROJLOD);
421 	bool				hasLodBias			= functionHasLod(m_lookupSpec.function) || m_lookupSpec.useBias;
422 	int					texCoordComps		= m_textureSpec.type == TEXTURETYPE_2D ? 2 : 3;
423 	int					extraCoordComps		= isProj ? (is2DProj4 ? 2 : 1) : 0;
424 	glu::DataType		coordType			= glu::getDataTypeFloatVec(texCoordComps+extraCoordComps);
425 	glu::Precision		coordPrec			= glu::PRECISION_MEDIUMP;
426 	const char*			coordTypeName		= glu::getDataTypeName(coordType);
427 	const char*			coordPrecName		= glu::getPrecisionName(coordPrec);
428 	tcu::TextureFormat	texFmt				= glu::mapGLTransferFormat(m_textureSpec.format, m_textureSpec.dataType);
429 	glu::DataType		samplerType			= glu::TYPE_LAST;
430 	const char*			baseFuncName		= m_textureSpec.type == TEXTURETYPE_2D ? "texture2D" : "textureCube";
431 	const char*			funcExt				= DE_NULL;
432 
433 	switch (m_textureSpec.type)
434 	{
435 		case TEXTURETYPE_2D:		samplerType = glu::getSampler2DType(texFmt);		break;
436 		case TEXTURETYPE_CUBE_MAP:	samplerType = glu::getSamplerCubeType(texFmt);		break;
437 		default:
438 			DE_ASSERT(DE_FALSE);
439 	}
440 
441 	switch (m_lookupSpec.function)
442 	{
443 		case FUNCTION_TEXTURE:			funcExt = "";			break;
444 		case FUNCTION_TEXTUREPROJ:		funcExt = "Proj";		break;
445 		case FUNCTION_TEXTUREPROJ3:		funcExt = "Proj";		break;
446 		case FUNCTION_TEXTURELOD:		funcExt = "Lod";		break;
447 		case FUNCTION_TEXTUREPROJLOD:	funcExt = "ProjLod";	break;
448 		case FUNCTION_TEXTUREPROJLOD3:	funcExt = "ProjLod";	break;
449 		default:
450 			DE_ASSERT(DE_FALSE);
451 	}
452 
453 	std::ostringstream	vert;
454 	std::ostringstream	frag;
455 	std::ostringstream&	op		= isVtxCase ? vert : frag;
456 
457 	vert << "attribute highp vec4 a_position;\n"
458 		 << "attribute " << coordPrecName << " " << coordTypeName << " a_in0;\n";
459 
460 	if (hasLodBias)
461 		vert << "attribute " << coordPrecName << " float a_in1;\n";
462 
463 	if (isVtxCase)
464 	{
465 		vert << "varying mediump vec4 v_color;\n";
466 		frag << "varying mediump vec4 v_color;\n";
467 	}
468 	else
469 	{
470 		vert << "varying " << coordPrecName << " " << coordTypeName << " v_texCoord;\n";
471 		frag << "varying " << coordPrecName << " " << coordTypeName << " v_texCoord;\n";
472 
473 		if (hasLodBias)
474 		{
475 			vert << "varying " << coordPrecName << " float v_lodBias;\n";
476 			frag << "varying " << coordPrecName << " float v_lodBias;\n";
477 		}
478 	}
479 
480 	// Uniforms
481 	op << "uniform lowp " << glu::getDataTypeName(samplerType) << " u_sampler;\n";
482 
483 	vert << "\nvoid main()\n{\n"
484 		 << "\tgl_Position = a_position;\n";
485 	frag << "\nvoid main()\n{\n";
486 
487 	if (isVtxCase)
488 		vert << "\tv_color = ";
489 	else
490 		frag << "\tgl_FragColor = ";
491 
492 	// Op.
493 	{
494 		const char*	texCoord	= isVtxCase ? "a_in0" : "v_texCoord";
495 		const char*	lodBias		= isVtxCase ? "a_in1" : "v_lodBias";
496 
497 		op << baseFuncName << funcExt;
498 		op << "(u_sampler, " << texCoord;
499 
500 		if (functionHasLod(function) || m_lookupSpec.useBias)
501 			op << ", " << lodBias;
502 
503 		op << ");\n";
504 	}
505 
506 	if (isVtxCase)
507 		frag << "\tgl_FragColor = v_color;\n";
508 	else
509 	{
510 		vert << "\tv_texCoord = a_in0;\n";
511 
512 		if (hasLodBias)
513 			vert << "\tv_lodBias = a_in1;\n";
514 	}
515 
516 	vert << "}\n";
517 	frag << "}\n";
518 
519 	m_vertShaderSource = vert.str();
520 	m_fragShaderSource = frag.str();
521 }
522 
deinit(void)523 void ShaderTextureFunctionCase::deinit (void)
524 {
525 	gls::ShaderRenderCase::deinit();
526 
527 	delete m_texture2D;
528 	delete m_textureCube;
529 
530 	m_texture2D			= DE_NULL;
531 	m_textureCube		= DE_NULL;
532 }
533 
setupUniforms(int programID,const tcu::Vec4 &)534 void ShaderTextureFunctionCase::setupUniforms (int programID, const tcu::Vec4&)
535 {
536 	const glw::Functions& gl = m_renderCtx.getFunctions();
537 	gl.uniform1i(gl.getUniformLocation(programID, "u_sampler"), 0);
538 }
539 
ShaderTextureFunctionTests(Context & context)540 ShaderTextureFunctionTests::ShaderTextureFunctionTests (Context& context)
541 	: TestCaseGroup(context, "texture_functions", "Texture Access Function Tests")
542 {
543 }
544 
~ShaderTextureFunctionTests(void)545 ShaderTextureFunctionTests::~ShaderTextureFunctionTests (void)
546 {
547 }
548 
549 struct TexFuncCaseSpec
550 {
551 	const char*			name;
552 	TextureLookupSpec	lookupSpec;
553 	TextureSpec			texSpec;
554 	TexEvalFunc			evalFunc;
555 };
556 
557 #define CASE_SPEC(NAME, FUNC, MINCOORD, MAXCOORD, USEBIAS, MINLOD, MAXLOD, TEXSPEC, EVALFUNC) \
558 	{ #NAME, TextureLookupSpec(FUNC, MINCOORD, MAXCOORD, USEBIAS, MINLOD, MAXLOD), TEXSPEC, EVALFUNC }
559 
createCaseGroup(TestCaseGroup * parent,const char * groupName,const char * groupDesc,const TexFuncCaseSpec * cases,int numCases,bool isVertex)560 static void createCaseGroup (TestCaseGroup* parent, const char* groupName, const char* groupDesc, const TexFuncCaseSpec* cases, int numCases, bool isVertex)
561 {
562 	tcu::TestCaseGroup* group = new tcu::TestCaseGroup(parent->getTestContext(), groupName, groupDesc);
563 	parent->addChild(group);
564 
565 	for (int ndx = 0; ndx < numCases; ndx++)
566 		group->addChild(new ShaderTextureFunctionCase(parent->getContext(), cases[ndx].name, "", cases[ndx].lookupSpec, cases[ndx].texSpec, cases[ndx].evalFunc, isVertex));
567 }
568 
init(void)569 void ShaderTextureFunctionTests::init (void)
570 {
571 	// Samplers
572 	static const tcu::Sampler	samplerLinearNoMipmap	(tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL,
573 														 tcu::Sampler::LINEAR, tcu::Sampler::LINEAR);
574 	static const tcu::Sampler	samplerLinearMipmap		(tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL,
575 														 tcu::Sampler::LINEAR_MIPMAP_NEAREST, tcu::Sampler::LINEAR);
576 
577 	// Default textures.
578 	//												Type			Format		DataType			W		H		L	Sampler
579 	static const TextureSpec tex2D			(TEXTURETYPE_2D,		GL_RGBA,	GL_UNSIGNED_BYTE,	256,	256,	1,	samplerLinearNoMipmap);
580 	static const TextureSpec tex2DMipmap	(TEXTURETYPE_2D,		GL_RGBA,	GL_UNSIGNED_BYTE,	256,	256,	9,	samplerLinearMipmap);
581 
582 	static const TextureSpec texCube		(TEXTURETYPE_CUBE_MAP,	GL_RGBA,	GL_UNSIGNED_BYTE,	256,	256,	1,	samplerLinearNoMipmap);
583 	static const TextureSpec texCubeMipmap	(TEXTURETYPE_CUBE_MAP,	GL_RGBA,	GL_UNSIGNED_BYTE,	256,	256,	9,	samplerLinearMipmap);
584 
585 	// Vertex cases
586 	static const TexFuncCaseSpec vertexCases[] =
587 	{
588 		//		  Name						Function					MinCoord							MaxCoord							Bias?	MinLod	MaxLod	Texture			EvalFunc
589 		CASE_SPEC(texture2d,				FUNCTION_TEXTURE,			Vec4(-0.2f, -0.4f,  0.0f,  0.0f),	Vec4( 1.5f,  2.3f,  0.0f,  0.0f),	false,	0.0f,	0.0f,	tex2D,			evalTexture2D),
590 //		CASE_SPEC(texture2d_bias,			FUNCTION_TEXTURE,			Vec4(-0.2f, -0.4f,  0.0f,  0.0f),	Vec4( 1.5f,  2.3f,  0.0f,  0.0f),	true,	-2.0f,	2.0f,	tex2D,			evalTexture2DBias),
591 		CASE_SPEC(texture2dproj_vec3,		FUNCTION_TEXTUREPROJ3,		Vec4(-0.3f, -0.6f,  1.5f,  0.0f),	Vec4(2.25f, 3.45f,  1.5f,  0.0f),	false,	0.0f,	0.0f,	tex2D,			evalTexture2DProj3),
592 		CASE_SPEC(texture2dproj_vec4,		FUNCTION_TEXTUREPROJ,		Vec4(-0.3f, -0.6f,  0.0f,  1.5f),	Vec4(2.25f, 3.45f,  0.0f,  1.5f),	false,	0.0f,	0.0f,	tex2D,			evalTexture2DProj),
593 		CASE_SPEC(texture2dlod,				FUNCTION_TEXTURELOD,		Vec4(-0.2f, -0.4f,  0.0f,  0.0f),	Vec4( 1.5f,  2.3f,  0.0f,  0.0f),	false,	-1.0f,	9.0f,	tex2DMipmap,	evalTexture2DLod),
594 //		CASE_SPEC(texture2dproj_vec3_bias,	FUNCTION_TEXTUREPROJ3,		Vec4(-0.3f, -0.6f,  1.5f,  0.0f),	Vec4(2.25f, 3.45f,  1.5f,  0.0f),	true,	-2.0f,	2.0f,	tex2D,			evalTexture2DProj3Bias),
595 //		CASE_SPEC(texture2dproj_vec4_bias,	FUNCTION_TEXTUREPROJ,		Vec4(-0.3f, -0.6f,  0.0f,  1.5f),	Vec4(2.25f, 3.45f,  0.0f,  1.5f),	true,	-2.0f,	2.0f,	tex2D,			evalTexture2DProjBias),
596 		CASE_SPEC(texture2dprojlod_vec3,	FUNCTION_TEXTUREPROJLOD3,	Vec4(-0.3f, -0.6f,  1.5f,  0.0f),	Vec4(2.25f, 3.45f,  1.5f,  0.0f),	false,	-1.0f,	9.0f,	tex2D,			evalTexture2DProjLod3),
597 		CASE_SPEC(texture2dprojlod_vec4,	FUNCTION_TEXTUREPROJLOD,	Vec4(-0.3f, -0.6f,  0.0f,  1.5f),	Vec4(2.25f, 3.45f,  0.0f,  1.5f),	false,	-1.0f,	9.0f,	tex2D,			evalTexture2DProjLod),
598 		CASE_SPEC(texturecube,				FUNCTION_TEXTURE,			Vec4(-1.0f, -1.0f,  1.01f,  0.0f),	Vec4( 1.0f,  1.0f,  1.01f,  0.0f),	false,	0.0f,	0.0f,	texCube,		evalTextureCube),
599 //		CASE_SPEC(texturecube_bias,			FUNCTION_TEXTURE,			Vec4(-1.0f, -1.0f, -1.01f,  0.0f),	Vec4( 1.0f,  1.0f, -1.01f,  0.0f),	true,	-2.0f,	2.0f,	texCube,		evalTextureCubeBias),
600 		CASE_SPEC(texturecubelod,			FUNCTION_TEXTURELOD,		Vec4(-1.0f, -1.0f,  1.01f,  0.0f),	Vec4( 1.0f,  1.0f,  1.01f,  0.0f),	false,	-1.0f,	9.0f,	texCubeMipmap,	evalTextureCubeLod),
601 	};
602 	createCaseGroup(this, "vertex", "Vertex Shader Texture Lookups", &vertexCases[0], DE_LENGTH_OF_ARRAY(vertexCases), true);
603 
604 	// Fragment cases
605 	static const TexFuncCaseSpec fragmentCases[] =
606 	{
607 		//		  Name						Function				MinCoord							MaxCoord							Bias?	MinLod	MaxLod	Texture			EvalFunc
608 		CASE_SPEC(texture2d,				FUNCTION_TEXTURE,		Vec4(-0.2f, -0.4f,  0.0f,  0.0f),	Vec4( 1.5f,  2.3f,  0.0f,  0.0f),	false,	0.0f,	0.0f,	tex2DMipmap,	evalTexture2D),
609 		CASE_SPEC(texture2d_bias,			FUNCTION_TEXTURE,		Vec4(-0.2f, -0.4f,  0.0f,  0.0f),	Vec4( 1.5f,  2.3f,  0.0f,  0.0f),	true,	-2.0f,	2.0f,	tex2DMipmap,	evalTexture2DBias),
610 		CASE_SPEC(texture2dproj_vec3,		FUNCTION_TEXTUREPROJ3,	Vec4(-0.3f, -0.6f,  1.5f,  0.0f),	Vec4(2.25f, 3.45f,  1.5f,  0.0f),	false,	0.0f,	0.0f,	tex2DMipmap,	evalTexture2DProj3),
611 		CASE_SPEC(texture2dproj_vec4,		FUNCTION_TEXTUREPROJ,	Vec4(-0.3f, -0.6f,  0.0f,  1.5f),	Vec4(2.25f, 3.45f,  0.0f,  1.5f),	false,	0.0f,	0.0f,	tex2DMipmap,	evalTexture2DProj),
612 		CASE_SPEC(texture2dproj_vec3_bias,	FUNCTION_TEXTUREPROJ3,	Vec4(-0.3f, -0.6f,  1.5f,  0.0f),	Vec4(2.25f, 3.45f,  1.5f,  0.0f),	true,	-2.0f,	2.0f,	tex2DMipmap,	evalTexture2DProj3Bias),
613 		CASE_SPEC(texture2dproj_vec4_bias,	FUNCTION_TEXTUREPROJ,	Vec4(-0.3f, -0.6f,  0.0f,  1.5f),	Vec4(2.25f, 3.45f,  0.0f,  1.5f),	true,	-2.0f,	2.0f,	tex2DMipmap,	evalTexture2DProjBias),
614 		CASE_SPEC(texturecube,				FUNCTION_TEXTURE,		Vec4(-1.0f, -1.0f,  1.01f,  0.0f),	Vec4( 1.0f,  1.0f,  1.01f,  0.0f),	false,	0.0f,	0.0f,	texCubeMipmap,	evalTextureCube),
615 		CASE_SPEC(texturecube_bias,			FUNCTION_TEXTURE,		Vec4(-1.0f, -1.0f, -1.01f,  0.0f),	Vec4( 1.0f,  1.0f, -1.01f,  0.0f),	true,	-2.0f,	2.0f,	texCubeMipmap,	evalTextureCubeBias)
616 	};
617 	createCaseGroup(this, "fragment", "Fragment Shader Texture Lookups", &fragmentCases[0], DE_LENGTH_OF_ARRAY(fragmentCases), false);
618 
619 	// Negative cases.
620 	{
621 		gls::ShaderLibrary library(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo());
622 		std::vector<tcu::TestNode*> negativeCases = library.loadShaderFile("shaders/invalid_texture_functions.test");
623 
624 		tcu::TestCaseGroup* group = new tcu::TestCaseGroup(m_testCtx, "invalid", "Invalid texture function usage", negativeCases);
625 		addChild(group);
626 	}
627 }
628 
629 } // Functional
630 } // gles3
631 } // deqp
632