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 "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 
     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 
     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 
     90 	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 
    100 	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 
    134 	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 
    144 	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 
    168 	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 
    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);			}
    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.
    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; }
    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 
    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; }
    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 
    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; }
    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; }
    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; }
    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 
    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; }
    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 
    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; }
    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:
    211 							TexLookupEvaluator		(TexEvalFunc evalFunc, const TexLookupParams& lookupParams) : m_evalFunc(evalFunc), m_lookupParams(lookupParams) {}
    212 
    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 
    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 
    256 ShaderTextureFunctionCase::~ShaderTextureFunctionCase (void)
    257 {
    258 	delete m_texture2D;
    259 	delete m_textureCube;
    260 }
    261 
    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 
    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 
    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 
    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 
    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 
    540 ShaderTextureFunctionTests::ShaderTextureFunctionTests (Context& context)
    541 	: TestCaseGroup(context, "texture_functions", "Texture Access Function Tests")
    542 {
    543 }
    544 
    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 
    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 
    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