Home | History | Annotate | Download | only in functional
      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 
     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 
     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 
     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 
    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 
    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 
    161 struct 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 
    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 
    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 
    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);			}
    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.
    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; }
    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 
    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; }
    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 
    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; }
    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; }
    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; }
    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 
    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; }
    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 
    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; }
    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:
    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 
    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 
    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 
    261 ShaderTextureFunctionCase::~ShaderTextureFunctionCase (void)
    262 {
    263 	delete m_texture2D;
    264 	delete m_textureCube;
    265 }
    266 
    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 
    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 
    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 
    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 
    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 
    545 ShaderTextureFunctionTests::ShaderTextureFunctionTests (Context& context)
    546 	: TestCaseGroup(context, "texture_functions", "Texture Access Function Tests")
    547 {
    548 }
    549 
    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 
    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 
    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