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