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
38namespace deqp
39{
40namespace gles2
41{
42namespace Functional
43{
44
45namespace
46{
47
48enum 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
60inline bool functionHasProj (Function function)
61{
62	return function == FUNCTION_TEXTUREPROJ		||
63		   function == FUNCTION_TEXTUREPROJ3	||
64		   function == FUNCTION_TEXTUREPROJLOD	||
65		   function == FUNCTION_TEXTUREPROJLOD3;
66}
67
68inline bool functionHasLod (Function function)
69{
70	return function == FUNCTION_TEXTURELOD		||
71		   function == FUNCTION_TEXTUREPROJLOD	||
72		   function == FUNCTION_TEXTUREPROJLOD3;
73}
74
75struct 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
89	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
99	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
115enum TextureType
116{
117	TEXTURETYPE_2D,
118	TEXTURETYPE_CUBE_MAP,
119
120	TEXTURETYPE_LAST
121};
122
123struct 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
133	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
143	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
161struct TexLookupParams
162{
163	float				lod;
164	tcu::Vec4			scale;
165	tcu::Vec4			bias;
166
167	TexLookupParams (void)
168		: lod		(0.0f)
169		, scale		(1.0f)
170		, bias		(0.0f)
171	{
172	}
173};
174
175} // anonymous
176
177using tcu::Vec2;
178using tcu::Vec3;
179using tcu::Vec4;
180using tcu::IVec2;
181using tcu::IVec3;
182using tcu::IVec4;
183
184inline 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
190typedef void (*TexEvalFunc) (gls::ShaderEvalContext& c, const TexLookupParams& lookupParams);
191
192inline 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);			}
193inline 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.
196static 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; }
197static 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
199static 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; }
200static 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
202static 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; }
203static 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; }
204static 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; }
205static 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
207static 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; }
208static 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
210static 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; }
211static 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
213class TexLookupEvaluator : public gls::ShaderEvaluator
214{
215public:
216							TexLookupEvaluator		(TexEvalFunc evalFunc, const TexLookupParams& lookupParams) : m_evalFunc(evalFunc), m_lookupParams(lookupParams) {}
217
218	virtual void			evaluate				(gls::ShaderEvalContext& ctx) { m_evalFunc(ctx, m_lookupParams); }
219
220private:
221	TexEvalFunc				m_evalFunc;
222	const TexLookupParams&	m_lookupParams;
223};
224
225class ShaderTextureFunctionCase : public gls::ShaderRenderCase
226{
227public:
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
234protected:
235	void					setupUniforms					(int programID, const tcu::Vec4& constCoords);
236
237private:
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
251ShaderTextureFunctionCase::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
261ShaderTextureFunctionCase::~ShaderTextureFunctionCase (void)
262{
263	delete m_texture2D;
264	delete m_textureCube;
265}
266
267void 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
315void 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
420void 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
528void 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
539void 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
545ShaderTextureFunctionTests::ShaderTextureFunctionTests (Context& context)
546	: TestCaseGroup(context, "texture_functions", "Texture Access Function Tests")
547{
548}
549
550ShaderTextureFunctionTests::~ShaderTextureFunctionTests (void)
551{
552}
553
554struct 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
565static 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
574void 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