Home | History | Annotate | Download | only in functional
      1 /*-------------------------------------------------------------------------
      2  * drawElements Quality Program OpenGL ES 3.1 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 Explicit uniform location tests
     22  *//*--------------------------------------------------------------------*/
     23 
     24 #include "es31fUniformLocationTests.hpp"
     25 
     26 #include "tcuTestLog.hpp"
     27 #include "tcuTextureUtil.hpp"
     28 #include "tcuVectorUtil.hpp"
     29 #include "tcuCommandLine.hpp"
     30 
     31 #include "glsShaderLibrary.hpp"
     32 #include "glsTextureTestUtil.hpp"
     33 
     34 #include "gluShaderProgram.hpp"
     35 #include "gluTexture.hpp"
     36 #include "gluPixelTransfer.hpp"
     37 #include "gluVarType.hpp"
     38 #include "gluVarTypeUtil.hpp"
     39 
     40 #include "glwFunctions.hpp"
     41 #include "glwEnums.hpp"
     42 #include "sglrContextUtil.hpp"
     43 
     44 #include "deStringUtil.hpp"
     45 #include "deUniquePtr.hpp"
     46 #include "deString.h"
     47 #include "deRandom.hpp"
     48 #include "deInt32.h"
     49 
     50 #include <set>
     51 #include <map>
     52 
     53 namespace deqp
     54 {
     55 namespace gles31
     56 {
     57 namespace Functional
     58 {
     59 namespace
     60 {
     61 
     62 using std::string;
     63 using std::vector;
     64 using std::map;
     65 using de::UniquePtr;
     66 using glu::VarType;
     67 
     68 struct UniformInfo
     69 {
     70 	enum ShaderStage
     71 	{
     72 		SHADERSTAGE_NONE	= 0,
     73 		SHADERSTAGE_VERTEX	= (1<<0),
     74 		SHADERSTAGE_FRAGMENT= (1<<1),
     75 		SHADERSTAGE_BOTH	= (SHADERSTAGE_VERTEX | SHADERSTAGE_FRAGMENT),
     76 	};
     77 
     78 	VarType			type;
     79 	ShaderStage		declareLocation; // support declarations with/without layout qualifiers, needed for linkage testing
     80 	ShaderStage		layoutLocation;
     81 	ShaderStage		checkLocation;
     82 	int				location; // -1 for unset
     83 
     84 	UniformInfo (VarType type_, ShaderStage declareLocation_, ShaderStage layoutLocation_, ShaderStage checkLocation_, int location_ = -1)
     85 		: type				(type_)
     86 		, declareLocation	(declareLocation_)
     87 		, layoutLocation	(layoutLocation_)
     88 		, checkLocation		(checkLocation_)
     89 		, location			(location_)
     90 	{
     91 	}
     92 };
     93 
     94 class UniformLocationCase : public tcu::TestCase
     95 {
     96 public:
     97 								UniformLocationCase		(tcu::TestContext&			context,
     98 														 glu::RenderContext&		renderContext,
     99 														 const char*				name,
    100 														 const char*				desc,
    101 														 const vector<UniformInfo>&	uniformInfo);
    102 	virtual						~UniformLocationCase	(void) {}
    103 
    104 	virtual IterateResult		iterate					(void);
    105 
    106 protected:
    107 	IterateResult				run						(const vector<UniformInfo>& uniformList);
    108 	static glu::ProgramSources	genShaderSources		(const vector<UniformInfo>& uniformList);
    109 	bool						verifyLocations			(const glu::ShaderProgram& program, const vector<UniformInfo>& uniformList);
    110 	void						render					(const glu::ShaderProgram& program, const vector<UniformInfo>& uniformList);
    111 	static bool					verifyResult			(const tcu::ConstPixelBufferAccess& access);
    112 
    113 	static float				getExpectedValue		(glu::DataType type, int id, const char* name);
    114 
    115 	de::MovePtr<glu::Texture2D>	createTexture			(glu::DataType samplerType, float redChannelValue, int binding);
    116 
    117 	glu::RenderContext&			m_renderCtx;
    118 
    119 	const vector<UniformInfo>	m_uniformInfo;
    120 
    121 	enum
    122 	{
    123 		RENDER_SIZE = 16
    124 	};
    125 };
    126 
    127 string getUniformName (int ndx, const glu::VarType& type, const glu::TypeComponentVector& path)
    128 {
    129 	std::ostringstream buff;
    130 	buff << "uni" << ndx << glu::TypeAccessFormat(type, path);
    131 
    132 	return buff.str();
    133 }
    134 
    135 string getFirstComponentName (const glu::VarType& type)
    136 {
    137 	std::ostringstream buff;
    138 	if (glu::isDataTypeVector(type.getBasicType()))
    139 		buff << glu::TypeAccessFormat(type, glu::SubTypeAccess(type).component(0).getPath());
    140 	else if (glu::isDataTypeMatrix(type.getBasicType()))
    141 		buff << glu::TypeAccessFormat(type, glu::SubTypeAccess(type).column(0).component(0).getPath());
    142 
    143 	return buff.str();
    144 }
    145 
    146 UniformLocationCase::UniformLocationCase (tcu::TestContext&				context,
    147 										  glu::RenderContext&			renderContext,
    148 										  const char*					name,
    149 										  const char*					desc,
    150 										  const vector<UniformInfo>&	uniformInfo)
    151 	: TestCase			(context, name, desc)
    152 	, m_renderCtx		(renderContext)
    153 	, m_uniformInfo		(uniformInfo)
    154 {
    155 }
    156 
    157 // [from, to]
    158 std::vector<int> shuffledRange (int from, int to, int seed)
    159 {
    160 	const int	count	= to - from;
    161 
    162 	vector<int> retval	(count);
    163 	de::Random	rng		(seed);
    164 
    165 	DE_ASSERT(count > 0);
    166 
    167 	for (int ndx = 0; ndx < count; ndx++)
    168 		retval[ndx] = ndx + from;
    169 
    170 	rng.shuffle(retval.begin(), retval.end());
    171 	return retval;
    172 }
    173 
    174 glu::DataType getDataTypeSamplerSampleType (glu::DataType type)
    175 {
    176 	using namespace glu;
    177 
    178 	if (type >= TYPE_SAMPLER_1D && type <= TYPE_SAMPLER_3D)
    179 		return TYPE_FLOAT_VEC4;
    180 	else if (type >= TYPE_INT_SAMPLER_1D && type <= TYPE_INT_SAMPLER_3D)
    181 		return TYPE_INT_VEC4;
    182 	else if (type >= TYPE_UINT_SAMPLER_1D && type <= TYPE_UINT_SAMPLER_3D)
    183 		return TYPE_UINT_VEC4;
    184 	else if (type >= TYPE_SAMPLER_1D_SHADOW && type <=	TYPE_SAMPLER_2D_ARRAY_SHADOW)
    185 		return TYPE_FLOAT;
    186 	else
    187 		DE_FATAL("Unknown sampler type");
    188 
    189 	return TYPE_INVALID;
    190 }
    191 
    192 // A (hopefully) unique value for a uniform. For multi-component types creates only one value. Values are in the range [0,1] for floats, [-128, 127] for ints, [0,255] for uints and 0/1 for booleans. Samplers are treated according to the types they return.
    193 float UniformLocationCase::getExpectedValue (glu::DataType type, int id, const char* name)
    194 {
    195 	const deUint32	hash			= deStringHash(name) + deInt32Hash(id);
    196 
    197 	glu::DataType	adjustedType	= type;
    198 
    199 	if (glu::isDataTypeSampler(type))
    200 		adjustedType = getDataTypeSamplerSampleType(type);
    201 
    202 	if (glu::isDataTypeIntOrIVec(adjustedType))
    203 		return float(hash%128);
    204 	else if (glu::isDataTypeUintOrUVec(adjustedType))
    205 		return float(hash%255);
    206 	else if (glu::isDataTypeFloatOrVec(adjustedType))
    207 		return float(hash%255)/255.0f;
    208 	else if (glu::isDataTypeBoolOrBVec(adjustedType))
    209 		return float(hash%2);
    210 	else
    211 		DE_FATAL("Unkown primitive type");
    212 
    213 	return glu::TYPE_INVALID;
    214 }
    215 
    216 UniformLocationCase::IterateResult UniformLocationCase::iterate (void)
    217 {
    218 	return run(m_uniformInfo);
    219 }
    220 
    221 UniformLocationCase::IterateResult UniformLocationCase::run (const vector<UniformInfo>& uniformList)
    222 {
    223 	using gls::TextureTestUtil::RandomViewport;
    224 
    225 	const glu::ProgramSources	sources		= genShaderSources(uniformList);
    226 	const glu::ShaderProgram	program		(m_renderCtx, sources);
    227 	const int					baseSeed	= m_testCtx.getCommandLine().getBaseSeed();
    228 	const glw::Functions&		gl			= m_renderCtx.getFunctions();
    229 	const RandomViewport		viewport	(m_renderCtx.getRenderTarget(), RENDER_SIZE, RENDER_SIZE, deStringHash(getName()) + baseSeed);
    230 
    231 	tcu::Surface				rendered	(RENDER_SIZE, RENDER_SIZE);
    232 
    233 	if (!verifyLocations(program, uniformList))
    234 		return STOP;
    235 
    236 	gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
    237 	gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
    238 	gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
    239 
    240 	render(program, uniformList);
    241 
    242 	glu::readPixels(m_renderCtx, viewport.x, viewport.y, rendered.getAccess());
    243 
    244 	if (!verifyResult(rendered.getAccess()))
    245 	{
    246 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Shader produced incorrect result");
    247 		return STOP;
    248 	}
    249 
    250 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
    251 	return STOP;
    252 }
    253 
    254 glu::ProgramSources UniformLocationCase::genShaderSources (const vector<UniformInfo>& uniformList)
    255 {
    256 	std::ostringstream	vertDecl, vertMain, fragDecl, fragMain;
    257 
    258 	vertDecl << "#version 310 es\n"
    259 			 << "precision highp float;\n"
    260 			 << "precision highp int;\n"
    261 			 << "float verify(float val, float ref) { return float(abs(val-ref) < 0.05); }\n\n"
    262 			 << "in highp vec4 a_position;\n"
    263 			 << "out highp vec4 v_color;\n";
    264 	fragDecl << "#version 310 es\n\n"
    265 			 << "precision highp float;\n"
    266 			 << "precision highp int;\n"
    267 			 << "float verify(float val, float ref) { return float(abs(val-ref) < 0.05); }\n\n"
    268 			 << "in highp vec4 v_color;\n"
    269 			 << "layout(location = 0) out mediump vec4 o_color;\n\n";
    270 
    271 	vertMain << "void main()\n{\n"
    272 			 << "	gl_Position = a_position;\n"
    273 			 << "	v_color = vec4(1.0);\n";
    274 
    275 	fragMain << "void main()\n{\n"
    276 			 << "	o_color = v_color;\n";
    277 
    278 	std::set<const glu::StructType*> declaredStructs;
    279 
    280 	// Declare uniforms
    281 	for (int uniformNdx = 0; uniformNdx < int(uniformList.size()); uniformNdx++)
    282 	{
    283 		const UniformInfo&	uniformInfo = uniformList[uniformNdx];
    284 
    285 		const bool			declareInVert	= (uniformInfo.declareLocation & UniformInfo::SHADERSTAGE_VERTEX)   != 0;
    286 		const bool			declareInFrag	= (uniformInfo.declareLocation & UniformInfo::SHADERSTAGE_FRAGMENT) != 0;
    287 		const bool			layoutInVert    = (uniformInfo.layoutLocation  & UniformInfo::SHADERSTAGE_VERTEX)   != 0;
    288 		const bool			layoutInFrag    = (uniformInfo.layoutLocation  & UniformInfo::SHADERSTAGE_FRAGMENT) != 0;
    289 		const bool			checkInVert		= (uniformInfo.checkLocation   & UniformInfo::SHADERSTAGE_VERTEX)   != 0;
    290 		const bool			checkInFrag		= (uniformInfo.checkLocation   & UniformInfo::SHADERSTAGE_FRAGMENT) != 0;
    291 
    292 		const string		layout			= uniformInfo.location >= 0 ? "layout(location = " + de::toString(uniformInfo.location) + ") " : "";
    293 		const string		uniName			= "uni" + de::toString(uniformNdx);
    294 
    295 		int					location		= uniformInfo.location;
    296 		int					subTypeIndex	= 0;
    297 
    298 		DE_ASSERT((declareInVert && layoutInVert) || !layoutInVert); // Cannot have layout without declaration
    299 		DE_ASSERT((declareInFrag && layoutInFrag) || !layoutInFrag);
    300 		DE_ASSERT(location<0 || (layoutInVert || layoutInFrag)); // Cannot have location without layout
    301 
    302 		// struct definitions
    303 		if (uniformInfo.type.isStructType())
    304 		{
    305 			const glu::StructType* const structType = uniformInfo.type.getStructPtr();
    306 			if (!declaredStructs.count(structType))
    307 			{
    308 				if (declareInVert)
    309 					vertDecl << glu::declare(structType, 0) << ";\n";
    310 
    311 				if (declareInFrag)
    312 					fragDecl << glu::declare(structType, 0) << ";\n";
    313 
    314 				declaredStructs.insert(structType);
    315 			}
    316 		}
    317 
    318 		if (declareInVert)
    319 			vertDecl << "uniform " << (layoutInVert ? layout : "") << glu::declare(uniformInfo.type, uniName) << ";\n";
    320 
    321 		if (declareInFrag)
    322 			fragDecl << "uniform " << (layoutInFrag ? layout : "") << glu::declare(uniformInfo.type, uniName) << ";\n";
    323 
    324 		// Anything that needs to be done for each enclosed primitive type
    325 		for (glu::BasicTypeIterator subTypeIter = glu::BasicTypeIterator::begin(&uniformInfo.type); subTypeIter != glu::BasicTypeIterator::end(&uniformInfo.type); subTypeIter++, subTypeIndex++)
    326 		{
    327 			const glu::VarType	subType		= glu::getVarType(uniformInfo.type, subTypeIter.getPath());
    328 			const glu::DataType	scalarType	= glu::getDataTypeScalarType(subType.getBasicType());
    329 			const char* const	typeName	= glu::getDataTypeName(scalarType);
    330 			const string		expectValue	= de::floatToString(getExpectedValue(scalarType, location >= 0 ? location+subTypeIndex : -1, typeName), 3);
    331 
    332 			if (glu::isDataTypeSampler(scalarType))
    333 			{
    334 				if (checkInVert)
    335 					vertMain << "	v_color.rgb *= verify(float( texture(" << uniName
    336 							 << glu::TypeAccessFormat(uniformInfo.type, subTypeIter.getPath())
    337 							 << ", vec2(0.5)).r), " << expectValue << ");\n";
    338 				if (checkInFrag)
    339 					fragMain << "	o_color.rgb *= verify(float( texture(" << uniName
    340 							 << glu::TypeAccessFormat(uniformInfo.type, subTypeIter.getPath())
    341 							 << ", vec2(0.5)).r), " << expectValue << ");\n";
    342 			}
    343 			else
    344 			{
    345 				if (checkInVert)
    346 					vertMain << "	v_color.rgb *= verify(float(" << uniName
    347 							 << glu::TypeAccessFormat(uniformInfo.type, subTypeIter.getPath())
    348 							 << getFirstComponentName(subType) << "), " << expectValue << ");\n";
    349 				if (checkInFrag)
    350 					fragMain << "	o_color.rgb *= verify(float(" << uniName
    351 							 << glu::TypeAccessFormat(uniformInfo.type, subTypeIter.getPath())
    352 							 << getFirstComponentName(subType) << "), " << expectValue << ");\n";
    353 			}
    354 		}
    355 	}
    356 
    357 	vertMain << "}\n";
    358 	fragMain << "}\n";
    359 
    360 	return glu::makeVtxFragSources(vertDecl.str() + vertMain.str(), fragDecl.str() + fragMain.str());
    361 }
    362 
    363 bool UniformLocationCase::verifyLocations (const glu::ShaderProgram& program, const vector<UniformInfo>& uniformList)
    364 {
    365 	using tcu::TestLog;
    366 
    367 	const glw::Functions&	gl			= m_renderCtx.getFunctions();
    368 	const bool				vertexOk	= program.getShaderInfo(glu::SHADERTYPE_VERTEX).compileOk;
    369 	const bool				fragmentOk	= program.getShaderInfo(glu::SHADERTYPE_FRAGMENT).compileOk;
    370 	const bool				linkOk		= program.getProgramInfo().linkOk;
    371 	const deUint32			programID	= program.getProgram();
    372 
    373 	TestLog&				log			= m_testCtx.getLog();
    374 	std::set<int>			usedLocations;
    375 
    376 	log << program;
    377 
    378 	if (!vertexOk || !fragmentOk || !linkOk)
    379 	{
    380 		log << TestLog::Message << "ERROR: shader failed to compile/link" << TestLog::EndMessage;
    381 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Shader failed to compile/link");
    382 		return false;
    383 	}
    384 
    385 	for (int uniformNdx = 0; uniformNdx < int(uniformList.size()); uniformNdx++)
    386 	{
    387 		const UniformInfo&	uniformInfo		= uniformList[uniformNdx];
    388 		int					subTypeIndex	= 0;
    389 
    390 		for (glu::BasicTypeIterator subTypeIter = glu::BasicTypeIterator::begin(&uniformInfo.type); subTypeIter != glu::BasicTypeIterator::end(&uniformInfo.type); subTypeIter++, subTypeIndex++)
    391 		{
    392 			const string		name		= getUniformName(uniformNdx, uniformInfo.type, subTypeIter.getPath());
    393 			const int			gotLoc		= gl.getUniformLocation(programID, name.c_str());
    394 			const int			expectLoc	= uniformInfo.location >= 0 ? uniformInfo.location+subTypeIndex : -1;
    395 
    396 			if (expectLoc >= 0)
    397 			{
    398 				if (uniformInfo.checkLocation == 0 && gotLoc == -1)
    399 					continue;
    400 
    401 				if (gotLoc != expectLoc)
    402 				{
    403 					log << TestLog::Message << "ERROR: found uniform " << name << " in location " << gotLoc << " when it should have been in " << expectLoc << TestLog::EndMessage;
    404 					m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Incorrect uniform location");
    405 					return false;
    406 				}
    407 
    408 				if (usedLocations.find(expectLoc) != usedLocations.end())
    409 				{
    410 					log << TestLog::Message << "ERROR: expected uniform " << name << " in location " << gotLoc << " but it has already been used" << TestLog::EndMessage;
    411 					m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Overlapping uniform location");
    412 					return false;
    413 				}
    414 
    415 				usedLocations.insert(expectLoc);
    416 			}
    417 			else if (gotLoc >= 0)
    418 			{
    419 				if (usedLocations.count(gotLoc))
    420 				{
    421 					log << TestLog::Message << "ERROR: found uniform " << name << " in location " << gotLoc << " which has already been used" << TestLog::EndMessage;
    422 					m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Overlapping uniform location");
    423 					return false;
    424 				}
    425 
    426 				usedLocations.insert(gotLoc);
    427 			}
    428 		}
    429 	}
    430 
    431 	return true;
    432 }
    433 
    434 // Check that shader output is white (or very close to it)
    435 bool UniformLocationCase::verifyResult (const tcu::ConstPixelBufferAccess& access)
    436 {
    437 	using tcu::Vec4;
    438 
    439 	const Vec4 threshold (0.1f, 0.1f, 0.1f, 0.1f);
    440 	const Vec4 reference (1.0f, 1.0f, 1.0f, 1.0f);
    441 
    442 	for (int y = 0; y < access.getHeight(); y++)
    443 	{
    444 		for (int x = 0; x < access.getWidth(); x++)
    445 		{
    446 			const Vec4 diff = abs(access.getPixel(x, y) - reference);
    447 
    448 			if (!boolAll(lessThanEqual(diff, threshold)))
    449 				return false;
    450 		}
    451 	}
    452 
    453 	return true;
    454 }
    455 
    456 // get a 4 channel 8 bits each texture format that is usable by the given sampler type
    457 deUint32 getTextureFormat (glu::DataType samplerType)
    458 {
    459 	using namespace glu;
    460 
    461 	switch (samplerType)
    462 	{
    463 		case TYPE_SAMPLER_1D:
    464 		case TYPE_SAMPLER_2D:
    465 		case TYPE_SAMPLER_CUBE:
    466 		case TYPE_SAMPLER_2D_ARRAY:
    467 		case TYPE_SAMPLER_3D:
    468 			return GL_RGBA8;
    469 
    470 		case TYPE_INT_SAMPLER_1D:
    471 		case TYPE_INT_SAMPLER_2D:
    472 		case TYPE_INT_SAMPLER_CUBE:
    473 		case TYPE_INT_SAMPLER_2D_ARRAY:
    474 		case TYPE_INT_SAMPLER_3D:
    475 			return GL_RGBA8I;
    476 
    477 		case TYPE_UINT_SAMPLER_1D:
    478 		case TYPE_UINT_SAMPLER_2D:
    479 		case TYPE_UINT_SAMPLER_CUBE:
    480 		case TYPE_UINT_SAMPLER_2D_ARRAY:
    481 		case TYPE_UINT_SAMPLER_3D:
    482 			return GL_RGBA8UI;
    483 
    484 		default:
    485 			DE_FATAL("Unsupported (sampler) type");
    486 			return 0;
    487 	}
    488 }
    489 
    490 // create a texture suitable for sampling by the given sampler type and bind it
    491 de::MovePtr<glu::Texture2D> UniformLocationCase::createTexture (glu::DataType samplerType, float redChannelValue, int binding)
    492 {
    493 	using namespace glu;
    494 
    495 	const glw::Functions&	gl		 = m_renderCtx.getFunctions();
    496 
    497 	const deUint32			format	 = getTextureFormat(samplerType);
    498 	de::MovePtr<Texture2D>	tex;
    499 
    500 	tex = de::MovePtr<Texture2D>(new Texture2D(m_renderCtx, format, 16, 16));
    501 
    502 	tex->getRefTexture().allocLevel(0);
    503 
    504 	if (format == GL_RGBA8I || format == GL_RGBA8UI)
    505 		tcu::clear(tex->getRefTexture().getLevel(0), tcu::IVec4(int(redChannelValue), 0, 0, 0));
    506 	else
    507 		tcu::clear(tex->getRefTexture().getLevel(0), tcu::Vec4(redChannelValue, 0.0f, 0.0f, 1.0f));
    508 
    509 	gl.activeTexture(GL_TEXTURE0 + binding);
    510 	tex->upload();
    511 
    512 	gl.bindTexture(GL_TEXTURE_2D, tex->getGLTexture());
    513 	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    514 	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    515 
    516 	GLU_EXPECT_NO_ERROR(gl.getError(), "UniformLocationCase: texture upload");
    517 
    518 	return tex;
    519 }
    520 
    521 void UniformLocationCase::render (const glu::ShaderProgram& program, const vector<UniformInfo>& uniformList)
    522 {
    523 	using glu::Texture2D;
    524 	using de::MovePtr;
    525 	typedef vector<Texture2D*> TextureList;
    526 
    527 	const glw::Functions&	gl				= m_renderCtx.getFunctions();
    528 	const deUint32			programID		= program.getProgram();
    529 	const deInt32			posLoc			= gl.getAttribLocation(programID, "a_position");
    530 
    531 	// Vertex data.
    532 	const float position[] =
    533 	{
    534 		-1.0f, -1.0f, 0.1f,	1.0f,
    535 		-1.0f,  1.0f, 0.1f,	1.0f,
    536 		 1.0f, -1.0f, 0.1f,	1.0f,
    537 		 1.0f,  1.0f, 0.1f,	1.0f
    538 	};
    539 	const deUint16			indices[]		= { 0, 1, 2, 2, 1, 3 };
    540 
    541 	// some buffers to feed to the GPU, only the first element is relevant since the others are never verified
    542 	float					floatBuf[16]	= {0.0f};
    543 	deInt32					intBuf[4]		= {0};
    544 	deUint32				uintBuf[4]		= {0};
    545 
    546 	TextureList				texList;
    547 
    548 	TCU_CHECK(posLoc >= 0);
    549 	gl.useProgram(programID);
    550 
    551 	try
    552 	{
    553 
    554 		// Set uniforms
    555 		for (unsigned int uniformNdx = 0; uniformNdx < uniformList.size(); uniformNdx++)
    556 		{
    557 			const UniformInfo&	uniformInfo			= uniformList[uniformNdx];
    558 			int					expectedLocation	= uniformInfo.location;
    559 
    560 			for (glu::BasicTypeIterator subTypeIter = glu::BasicTypeIterator::begin(&uniformInfo.type); subTypeIter != glu::BasicTypeIterator::end(&uniformInfo.type); subTypeIter++)
    561 			{
    562 				const glu::VarType	type			= glu::getVarType(uniformInfo.type, subTypeIter.getPath());
    563 				const string		name			= getUniformName(uniformNdx, uniformInfo.type, subTypeIter.getPath());
    564 				const int			gotLoc			= gl.getUniformLocation(programID, name.c_str());
    565 				const glu::DataType	scalarType		= glu::getDataTypeScalarType(type.getBasicType());
    566 				const char*	const	typeName		= glu::getDataTypeName(scalarType);
    567 				const float			expectedValue	= getExpectedValue(scalarType, expectedLocation, typeName);
    568 
    569 				if (glu::isDataTypeSampler(scalarType))
    570 				{
    571 					const int binding = (int)texList.size();
    572 
    573 					texList.push_back(createTexture(scalarType, expectedValue, binding).release());
    574 					gl.uniform1i(gotLoc, binding);
    575 				}
    576 				else if(gotLoc >= 0)
    577 				{
    578 					floatBuf[0] = expectedValue;
    579 					intBuf[0]   = int(expectedValue);
    580 					uintBuf[0]  = deUint32(expectedValue);
    581 
    582 					m_testCtx.getLog() << tcu::TestLog::Message << "Set uniform " << name << " in location " << gotLoc << " to " << expectedValue << tcu::TestLog::EndMessage;
    583 
    584 					switch (type.getBasicType())
    585 					{
    586 						case glu::TYPE_FLOAT:			gl.uniform1fv(gotLoc, 1, floatBuf);					break;
    587 						case glu::TYPE_FLOAT_VEC2:		gl.uniform2fv(gotLoc, 1, floatBuf);					break;
    588 						case glu::TYPE_FLOAT_VEC3:		gl.uniform3fv(gotLoc, 1, floatBuf);					break;
    589 						case glu::TYPE_FLOAT_VEC4:		gl.uniform4fv(gotLoc, 1, floatBuf);					break;
    590 
    591 						case glu::TYPE_INT:				gl.uniform1iv(gotLoc, 1, intBuf);					break;
    592 						case glu::TYPE_INT_VEC2:		gl.uniform2iv(gotLoc, 1, intBuf);					break;
    593 						case glu::TYPE_INT_VEC3:		gl.uniform3iv(gotLoc, 1, intBuf);					break;
    594 						case glu::TYPE_INT_VEC4:		gl.uniform4iv(gotLoc, 1, intBuf);					break;
    595 
    596 						case glu::TYPE_UINT:			gl.uniform1uiv(gotLoc, 1, uintBuf);					break;
    597 						case glu::TYPE_UINT_VEC2:		gl.uniform2uiv(gotLoc, 1, uintBuf);					break;
    598 						case glu::TYPE_UINT_VEC3:		gl.uniform3uiv(gotLoc, 1, uintBuf);					break;
    599 						case glu::TYPE_UINT_VEC4:		gl.uniform4uiv(gotLoc, 1, uintBuf);					break;
    600 
    601 						case glu::TYPE_BOOL:			gl.uniform1iv(gotLoc, 1, intBuf);					break;
    602 						case glu::TYPE_BOOL_VEC2:		gl.uniform2iv(gotLoc, 1, intBuf);					break;
    603 						case glu::TYPE_BOOL_VEC3:		gl.uniform3iv(gotLoc, 1, intBuf);					break;
    604 						case glu::TYPE_BOOL_VEC4:		gl.uniform4iv(gotLoc, 1, intBuf);					break;
    605 
    606 						case glu::TYPE_FLOAT_MAT2:		gl.uniformMatrix2fv(gotLoc, 1, false, floatBuf);	break;
    607 						case glu::TYPE_FLOAT_MAT2X3:	gl.uniformMatrix2x3fv(gotLoc, 1, false, floatBuf);	break;
    608 						case glu::TYPE_FLOAT_MAT2X4:	gl.uniformMatrix2x4fv(gotLoc, 1, false, floatBuf);	break;
    609 
    610 						case glu::TYPE_FLOAT_MAT3X2:	gl.uniformMatrix3x2fv(gotLoc, 1, false, floatBuf);	break;
    611 						case glu::TYPE_FLOAT_MAT3:		gl.uniformMatrix3fv(gotLoc, 1, false, floatBuf);	break;
    612 						case glu::TYPE_FLOAT_MAT3X4:	gl.uniformMatrix3x4fv(gotLoc, 1, false, floatBuf);	break;
    613 
    614 						case glu::TYPE_FLOAT_MAT4X2:	gl.uniformMatrix4x2fv(gotLoc, 1, false, floatBuf);	break;
    615 						case glu::TYPE_FLOAT_MAT4X3:	gl.uniformMatrix4x3fv(gotLoc, 1, false, floatBuf);	break;
    616 						case glu::TYPE_FLOAT_MAT4:		gl.uniformMatrix4fv(gotLoc, 1, false, floatBuf);	break;
    617 						default:
    618 							DE_ASSERT(false);
    619 					}
    620 				}
    621 
    622 				expectedLocation += expectedLocation>=0;
    623 			}
    624 		}
    625 
    626 		gl.enableVertexAttribArray(posLoc);
    627 		gl.vertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, &position[0]);
    628 
    629 		gl.drawElements(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(indices), GL_UNSIGNED_SHORT, &indices[0]);
    630 
    631 		gl.disableVertexAttribArray(posLoc);
    632 	}
    633 	catch(...)
    634 	{
    635 		for (int i = 0; i < int(texList.size()); i++)
    636 			delete texList[i];
    637 
    638 		throw;
    639 	}
    640 
    641 	for (int i = 0; i < int(texList.size()); i++)
    642 		delete texList[i];
    643 }
    644 
    645 class MaxUniformLocationCase : public UniformLocationCase
    646 {
    647 public:
    648 								MaxUniformLocationCase		(tcu::TestContext&			context,
    649 															 glu::RenderContext&		renderContext,
    650 															 const char*				name,
    651 															 const char*				desc,
    652 															 const vector<UniformInfo>&	uniformInfo);
    653 	virtual						~MaxUniformLocationCase		(void) {}
    654 	virtual IterateResult		iterate						(void);
    655 };
    656 
    657 MaxUniformLocationCase::MaxUniformLocationCase (tcu::TestContext&			context,
    658 												glu::RenderContext&			renderContext,
    659 												const char*					name,
    660 												const char*					desc,
    661 												const vector<UniformInfo>&	uniformInfo)
    662 	: UniformLocationCase(context, renderContext, name, desc, uniformInfo)
    663 {
    664 	DE_ASSERT(!uniformInfo.empty());
    665 }
    666 
    667 UniformLocationCase::IterateResult MaxUniformLocationCase::iterate (void)
    668 {
    669 	int					maxLocation = 1024;
    670 	vector<UniformInfo>	uniformInfo = m_uniformInfo;
    671 
    672 	m_renderCtx.getFunctions().getIntegerv(GL_MAX_UNIFORM_LOCATIONS, &maxLocation);
    673 
    674 	uniformInfo[0].location = maxLocation-1;
    675 
    676 	return UniformLocationCase::run(uniformInfo);
    677 }
    678 
    679 } // Anonymous
    680 
    681 UniformLocationTests::UniformLocationTests (Context& context)
    682 	: TestCaseGroup(context, "uniform_location", "Explicit uniform locations")
    683 {
    684 }
    685 
    686 UniformLocationTests::~UniformLocationTests (void)
    687 {
    688 	for (int i = 0; i < int(structTypes.size()); i++)
    689 		delete structTypes[i];
    690 }
    691 
    692 glu::VarType createVarType (glu::DataType type)
    693 {
    694 	return glu::VarType(type, glu::isDataTypeBoolOrBVec(type) ? glu::PRECISION_LAST : glu::PRECISION_HIGHP);
    695 }
    696 
    697 void UniformLocationTests::init (void)
    698 {
    699 	using namespace glu;
    700 
    701 	const UniformInfo::ShaderStage checkStages[]	= { UniformInfo::SHADERSTAGE_VERTEX, UniformInfo::SHADERSTAGE_FRAGMENT };
    702 	const char*						stageNames[]	= {"vertex", "fragment"};
    703 	const int						maxLocations	= 1024;
    704 	const int						baseSeed		= m_context.getTestContext().getCommandLine().getBaseSeed();
    705 
    706 	const DataType					primitiveTypes[] =
    707 	{
    708 		TYPE_FLOAT,
    709 		TYPE_FLOAT_VEC2,
    710 		TYPE_FLOAT_VEC3,
    711 		TYPE_FLOAT_VEC4,
    712 
    713 		TYPE_INT,
    714 		TYPE_INT_VEC2,
    715 		TYPE_INT_VEC3,
    716 		TYPE_INT_VEC4,
    717 
    718 		TYPE_UINT,
    719 		TYPE_UINT_VEC2,
    720 		TYPE_UINT_VEC3,
    721 		TYPE_UINT_VEC4,
    722 
    723 		TYPE_BOOL,
    724 		TYPE_BOOL_VEC2,
    725 		TYPE_BOOL_VEC3,
    726 		TYPE_BOOL_VEC4,
    727 
    728 		TYPE_FLOAT_MAT2,
    729 		TYPE_FLOAT_MAT2X3,
    730 		TYPE_FLOAT_MAT2X4,
    731 		TYPE_FLOAT_MAT3X2,
    732 		TYPE_FLOAT_MAT3,
    733 		TYPE_FLOAT_MAT3X4,
    734 		TYPE_FLOAT_MAT4X2,
    735 		TYPE_FLOAT_MAT4X3,
    736 		TYPE_FLOAT_MAT4,
    737 
    738 		TYPE_SAMPLER_2D,
    739 		TYPE_INT_SAMPLER_2D,
    740 		TYPE_UINT_SAMPLER_2D,
    741 	};
    742 
    743 	const int maxPrimitiveTypeNdx = DE_LENGTH_OF_ARRAY(primitiveTypes) - 4;
    744 	DE_ASSERT(primitiveTypes[maxPrimitiveTypeNdx] == TYPE_FLOAT_MAT4);
    745 
    746 	// Primitive type cases with trivial linkage
    747 	{
    748 		tcu::TestCaseGroup* const	group	= new tcu::TestCaseGroup(m_testCtx, "basic", "Location specified with use, single shader stage");
    749 		de::Random					rng		(baseSeed + 0x1001);
    750 		addChild(group);
    751 
    752 		for (int primitiveNdx = 0; primitiveNdx < DE_LENGTH_OF_ARRAY(primitiveTypes); primitiveNdx++)
    753 		{
    754 			const DataType		type	= primitiveTypes[primitiveNdx];
    755 
    756 			for (int stageNdx = 0; stageNdx < DE_LENGTH_OF_ARRAY(checkStages); stageNdx++)
    757 			{
    758 				const string		name		= string(getDataTypeName(type)) + "_" + stageNames[stageNdx];
    759 
    760 				vector<UniformInfo> config;
    761 
    762 				UniformInfo			uniform	(createVarType(type),
    763 											 checkStages[stageNdx],
    764 											 checkStages[stageNdx],
    765 											 checkStages[stageNdx],
    766 											 rng.getInt(0, maxLocations-1));
    767 
    768 				config.push_back(uniform);
    769 				group->addChild(new UniformLocationCase (m_testCtx, m_context.getRenderContext(), name.c_str(), name.c_str(), config));
    770 			}
    771 		}
    772 	}
    773 
    774 	// Arrays
    775 	{
    776 		tcu::TestCaseGroup* const	group	= new tcu::TestCaseGroup(m_testCtx, "array", "Array location specified with use, single shader stage");
    777 		de::Random					rng		(baseSeed + 0x2001);
    778 		addChild(group);
    779 
    780 		for (int primitiveNdx = 0; primitiveNdx < DE_LENGTH_OF_ARRAY(primitiveTypes); primitiveNdx++)
    781 		{
    782 			const DataType		type	= primitiveTypes[primitiveNdx];
    783 
    784 			for (int stageNdx = 0; stageNdx < DE_LENGTH_OF_ARRAY(checkStages); stageNdx++)
    785 			{
    786 
    787 				const string		name	= string(getDataTypeName(type)) + "_" + stageNames[stageNdx];
    788 
    789 				vector<UniformInfo> config;
    790 
    791 				UniformInfo			uniform	(VarType(createVarType(type), 8),
    792 												checkStages[stageNdx],
    793 												checkStages[stageNdx],
    794 												checkStages[stageNdx],
    795 												rng.getInt(0, maxLocations-1-8));
    796 
    797 				config.push_back(uniform);
    798 				group->addChild(new UniformLocationCase (m_testCtx, m_context.getRenderContext(), name.c_str(), name.c_str(), config));
    799 			}
    800 		}
    801 	}
    802 
    803 	// Nested Arrays
    804 	{
    805 		tcu::TestCaseGroup* const	group	= new tcu::TestCaseGroup(m_testCtx, "nested_array", "Array location specified with use, single shader stage");
    806 		de::Random					rng		(baseSeed + 0x3001);
    807 		addChild(group);
    808 
    809 		for (int primitiveNdx = 0; primitiveNdx < DE_LENGTH_OF_ARRAY(primitiveTypes); primitiveNdx++)
    810 		{
    811 			const DataType		type	= primitiveTypes[primitiveNdx];
    812 
    813 			for (int stageNdx = 0; stageNdx < DE_LENGTH_OF_ARRAY(checkStages); stageNdx++)
    814 			{
    815 				const string		name		= string(getDataTypeName(type)) + "_" + stageNames[stageNdx];
    816 				// stay comfortably within minimum max uniform component count (896 in fragment) and sampler count with all types
    817 				const int			arraySize	= (getDataTypeScalarSize(type) > 4 || isDataTypeSampler(type)) ? 3 : 7;
    818 
    819 				vector<UniformInfo> config;
    820 
    821 				UniformInfo			uniform	(VarType(VarType(createVarType(type), arraySize), arraySize),
    822 											 checkStages[stageNdx],
    823 											 checkStages[stageNdx],
    824 											 checkStages[stageNdx],
    825 											 rng.getInt(0, maxLocations-1-arraySize*arraySize));
    826 
    827 				config.push_back(uniform);
    828 				group->addChild(new UniformLocationCase (m_testCtx, m_context.getRenderContext(), name.c_str(), name.c_str(), config));
    829 			}
    830 		}
    831 	}
    832 
    833 	// Structs
    834 	{
    835 		tcu::TestCaseGroup* const	group	= new tcu::TestCaseGroup(m_testCtx, "struct", "Struct location, random contents & declaration location");
    836 		de::Random					rng		(baseSeed + 0x4001);
    837 		addChild(group);
    838 
    839 		for (int caseNdx = 0; caseNdx < 16; caseNdx++)
    840 		{
    841 			typedef UniformInfo::ShaderStage Stage;
    842 
    843 			const string	name		= "case_" + de::toString(caseNdx);
    844 
    845 			const Stage		layoutLoc	= Stage(rng.getUint32()&0x3);
    846 			const Stage		declareLoc	= Stage((rng.getUint32()&0x3) | layoutLoc);
    847 			const Stage		verifyLoc	= Stage((rng.getUint32()&0x3) & declareLoc);
    848 			const int		location	= layoutLoc ? rng.getInt(0, maxLocations-1-5) : -1;
    849 
    850 			StructType*		structProto = new StructType("S");
    851 
    852 			structTypes.push_back(structProto);
    853 
    854 			structProto->addMember("a", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
    855 			structProto->addMember("b", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
    856 			structProto->addMember("c", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
    857 			structProto->addMember("d", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
    858 			structProto->addMember("e", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
    859 
    860 			{
    861 				vector<UniformInfo> config;
    862 
    863 				config.push_back(UniformInfo(VarType(structProto),
    864 											 declareLoc,
    865 											 layoutLoc,
    866 											 verifyLoc,
    867 											 location));
    868 				group->addChild(new UniformLocationCase (m_testCtx, m_context.getRenderContext(), name.c_str(), name.c_str(), config));
    869 			}
    870 		}
    871 	}
    872 
    873 	// Nested Structs
    874 	{
    875 		tcu::TestCaseGroup* const	group	= new tcu::TestCaseGroup(m_testCtx, "nested_struct", "Struct location specified with use, single shader stage");
    876 		de::Random					rng		(baseSeed + 0x5001);
    877 
    878 		addChild(group);
    879 
    880 		for (int caseNdx = 0; caseNdx < 16; caseNdx++)
    881 		{
    882 			typedef UniformInfo::ShaderStage Stage;
    883 
    884 			const string	name		= "case_" + de::toString(caseNdx);
    885 			const int		baseLoc		= rng.getInt(0, maxLocations-1-60);
    886 
    887 			// Structs need to be added in the order of their declaration
    888 			const Stage		layoutLocs[]=
    889 			{
    890 				Stage(rng.getUint32()&0x3),
    891 				Stage(rng.getUint32()&0x3),
    892 				Stage(rng.getUint32()&0x3),
    893 				Stage(rng.getUint32()&0x3),
    894 			};
    895 
    896 			const deUint32	tempDecl[] =
    897 			{
    898 				(rng.getUint32()&0x3) | layoutLocs[0],
    899 				(rng.getUint32()&0x3) | layoutLocs[1],
    900 				(rng.getUint32()&0x3) | layoutLocs[2],
    901 				(rng.getUint32()&0x3) | layoutLocs[3],
    902 			};
    903 
    904 			// Component structs need to be declared if anything using them is declared
    905 			const Stage		declareLocs[] =
    906 			{
    907 				Stage(tempDecl[0] | tempDecl[1] | tempDecl[2] | tempDecl[3]),
    908 				Stage(tempDecl[1] | tempDecl[2] | tempDecl[3]),
    909 				Stage(tempDecl[2] | tempDecl[3]),
    910 				Stage(tempDecl[3]),
    911 			};
    912 
    913 			const Stage		verifyLocs[] =
    914 			{
    915 				Stage(rng.getUint32()&0x3 & declareLocs[0]),
    916 				Stage(rng.getUint32()&0x3 & declareLocs[1]),
    917 				Stage(rng.getUint32()&0x3 & declareLocs[2]),
    918 				Stage(rng.getUint32()&0x3 & declareLocs[3]),
    919 			};
    920 
    921 			StructType*		testTypes[]	=
    922 			{
    923 				new StructType("Type0"),
    924 				new StructType("Type1"),
    925 				new StructType("Type2"),
    926 				new StructType("Type3"),
    927 			};
    928 
    929 			structTypes.push_back(testTypes[0]);
    930 			structTypes.push_back(testTypes[1]);
    931 			structTypes.push_back(testTypes[2]);
    932 			structTypes.push_back(testTypes[3]);
    933 
    934 			testTypes[0]->addMember("a", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
    935 			testTypes[0]->addMember("b", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
    936 			testTypes[0]->addMember("c", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
    937 			testTypes[0]->addMember("d", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
    938 			testTypes[0]->addMember("e", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
    939 
    940 			testTypes[1]->addMember("a", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
    941 			testTypes[1]->addMember("b", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
    942 			testTypes[1]->addMember("c", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
    943 			testTypes[1]->addMember("d", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
    944 			testTypes[1]->addMember("e", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
    945 
    946 			testTypes[2]->addMember("a", VarType(testTypes[0]));
    947 			testTypes[2]->addMember("b", VarType(testTypes[1]));
    948 			testTypes[2]->addMember("c", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
    949 
    950 			testTypes[3]->addMember("a", VarType(testTypes[2]));
    951 
    952 			{
    953 				vector<UniformInfo> config;
    954 
    955 				config.push_back(UniformInfo(VarType(testTypes[0]),
    956 											 declareLocs[0],
    957 											 layoutLocs[0],
    958 											 verifyLocs[0],
    959 											 layoutLocs[0] ? baseLoc : -1));
    960 
    961 				config.push_back(UniformInfo(VarType(testTypes[1]),
    962 											 declareLocs[1],
    963 											 layoutLocs[1],
    964 											 verifyLocs[1],
    965 											 layoutLocs[1] ? baseLoc+5 : -1));
    966 
    967 				config.push_back(UniformInfo(VarType(testTypes[2]),
    968 											 declareLocs[2],
    969 											 layoutLocs[2],
    970 											 verifyLocs[2],
    971 											 layoutLocs[2] ? baseLoc+16 : -1));
    972 
    973 				config.push_back(UniformInfo(VarType(testTypes[3]),
    974 											 declareLocs[3],
    975 											 layoutLocs[3],
    976 											 verifyLocs[3],
    977 											 layoutLocs[3] ? baseLoc+27 : -1));
    978 
    979 				group->addChild(new UniformLocationCase (m_testCtx, m_context.getRenderContext(), name.c_str(), name.c_str(), config));
    980 			}
    981 		}
    982 	}
    983 
    984 	// Min/Max location
    985 	{
    986 		tcu::TestCaseGroup* const	group		= new tcu::TestCaseGroup(m_testCtx, "min_max", "Maximum & minimum location");
    987 
    988 		addChild(group);
    989 
    990 		for (int primitiveNdx = 0; primitiveNdx < DE_LENGTH_OF_ARRAY(primitiveTypes); primitiveNdx++)
    991 		{
    992 			const DataType		type	= primitiveTypes[primitiveNdx];
    993 
    994 			for (int stageNdx = 0; stageNdx < DE_LENGTH_OF_ARRAY(checkStages); stageNdx++)
    995 			{
    996 				const string		name		= string(getDataTypeName(type)) + "_" + stageNames[stageNdx];
    997 				vector<UniformInfo> config;
    998 
    999 				config.push_back(UniformInfo(createVarType(type),
   1000 											 checkStages[stageNdx],
   1001 											 checkStages[stageNdx],
   1002 											 checkStages[stageNdx],
   1003 											 0));
   1004 
   1005 				group->addChild(new UniformLocationCase (m_testCtx, m_context.getRenderContext(), (name+"_min").c_str(), (name+"_min").c_str(), config));
   1006 
   1007 				group->addChild(new MaxUniformLocationCase (m_testCtx, m_context.getRenderContext(), (name+"_max").c_str(), (name+"_max").c_str(), config));
   1008 			}
   1009 		}
   1010 	}
   1011 
   1012 	// Link
   1013 	{
   1014 		tcu::TestCaseGroup* const	group	= new tcu::TestCaseGroup(m_testCtx, "link", "Location specified independently from use");
   1015 		de::Random					rng		(baseSeed + 0x82e1);
   1016 
   1017 		addChild(group);
   1018 
   1019 		for (int caseNdx = 0; caseNdx < 10; caseNdx++)
   1020 		{
   1021 			const string		name		= "case_" + de::toString(caseNdx);
   1022 			vector<UniformInfo> config;
   1023 
   1024 			vector<int>			locations	= shuffledRange(0, maxLocations, 0x1234 + caseNdx*100);
   1025 
   1026 			for (int count = 0; count < 32; count++)
   1027 			{
   1028 				typedef UniformInfo::ShaderStage Stage;
   1029 
   1030 				const Stage			layoutLoc	= Stage(rng.getUint32()&0x3);
   1031 				const Stage			declareLoc	= Stage((rng.getUint32()&0x3) | layoutLoc);
   1032 				const Stage			verifyLoc	= Stage((rng.getUint32()&0x3) & declareLoc);
   1033 
   1034 				const UniformInfo	uniform		(createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]),
   1035 												 declareLoc,
   1036 												 layoutLoc,
   1037 												 verifyLoc,
   1038 												 (layoutLoc!=0) ? locations.back() : -1);
   1039 
   1040 				config.push_back(uniform);
   1041 				locations.pop_back();
   1042 			}
   1043 			group->addChild(new UniformLocationCase (m_testCtx, m_context.getRenderContext(), name.c_str(), name.c_str(), config));
   1044 		}
   1045 	}
   1046 
   1047 	// Negative
   1048 	{
   1049 		de::MovePtr<tcu::TestCaseGroup>	negativeGroup			(new tcu::TestCaseGroup(m_testCtx, "negative", "Negative tests"));
   1050 
   1051 		{
   1052 			de::MovePtr<tcu::TestCaseGroup>	es31Group		(new tcu::TestCaseGroup(m_testCtx, "es31", "GLSL ES 3.1 Negative tests"));
   1053 			gls::ShaderLibrary				shaderLibrary   (m_testCtx, m_context.getRenderContext(), m_context.getContextInfo());
   1054 			const vector<TestNode*>			negativeCases    = shaderLibrary.loadShaderFile("shaders/es31/uniform_location.test");
   1055 
   1056 			for (int ndx = 0; ndx < int(negativeCases.size()); ndx++)
   1057 				es31Group->addChild(negativeCases[ndx]);
   1058 
   1059 			negativeGroup->addChild(es31Group.release());
   1060 		}
   1061 
   1062 		{
   1063 			de::MovePtr<tcu::TestCaseGroup>	es32Group		(new tcu::TestCaseGroup(m_testCtx, "es32", "GLSL ES 3.2 Negative tests"));
   1064 			gls::ShaderLibrary				shaderLibrary   (m_testCtx, m_context.getRenderContext(), m_context.getContextInfo());
   1065 			const vector<TestNode*>			negativeCases    = shaderLibrary.loadShaderFile("shaders/es32/uniform_location.test");
   1066 
   1067 			for (int ndx = 0; ndx < int(negativeCases.size()); ndx++)
   1068 				es32Group->addChild(negativeCases[ndx]);
   1069 
   1070 			negativeGroup->addChild(es32Group.release());
   1071 		}
   1072 
   1073 		addChild(negativeGroup.release());
   1074 	}
   1075 }
   1076 
   1077 } // Functional
   1078 } // gles31
   1079 } // deqp
   1080