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_ASSERT(!"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 (hash%255)/255.0f;
    208 	else if (glu::isDataTypeBoolOrBVec(adjustedType))
    209 		return float(hash%2);
    210 	else
    211 		DE_ASSERT(!"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 glu::VarType	type		= glu::getVarType(uniformInfo.type, subTypeIter.getPath());
    393 			const string		name		= getUniformName(uniformNdx, uniformInfo.type, subTypeIter.getPath());
    394 			const int			gotLoc		= gl.getUniformLocation(programID, name.c_str());
    395 			const int			expectLoc	= uniformInfo.location >= 0 ? uniformInfo.location+subTypeIndex : -1;
    396 
    397 			if (expectLoc >= 0)
    398 			{
    399 				if (uniformInfo.checkLocation == 0 && gotLoc == -1)
    400 					continue;
    401 
    402 				if (gotLoc != expectLoc)
    403 				{
    404 					log << TestLog::Message << "ERROR: found uniform " << name << " in location " << gotLoc << " when it should have been in " << expectLoc << TestLog::EndMessage;
    405 					m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Incorrect uniform location");
    406 					return false;
    407 				}
    408 
    409 				if (usedLocations.find(expectLoc) != usedLocations.end())
    410 				{
    411 					log << TestLog::Message << "ERROR: expected uniform " << name << " in location " << gotLoc << " but it has already been used" << TestLog::EndMessage;
    412 					m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Overlapping uniform location");
    413 					return false;
    414 				}
    415 
    416 				usedLocations.insert(expectLoc);
    417 			}
    418 			else if (gotLoc >= 0)
    419 			{
    420 				if (usedLocations.count(gotLoc))
    421 				{
    422 					log << TestLog::Message << "ERROR: found uniform " << name << " in location " << gotLoc << " which has already been used" << TestLog::EndMessage;
    423 					m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Overlapping uniform location");
    424 					return false;
    425 				}
    426 
    427 				usedLocations.insert(gotLoc);
    428 			}
    429 		}
    430 	}
    431 
    432 	return true;
    433 }
    434 
    435 // Check that shader output is white (or very close to it)
    436 bool UniformLocationCase::verifyResult (const tcu::ConstPixelBufferAccess& access)
    437 {
    438 	using tcu::Vec4;
    439 
    440 	const Vec4 threshold (0.1f, 0.1f, 0.1f, 0.1f);
    441 	const Vec4 reference (1.0f, 1.0f, 1.0f, 1.0f);
    442 
    443 	for (int y = 0; y < access.getHeight(); y++)
    444 	{
    445 		for (int x = 0; x < access.getWidth(); x++)
    446 		{
    447 			const Vec4 diff = abs(access.getPixel(x, y) - reference);
    448 
    449 			if (!boolAll(lessThanEqual(diff, threshold)))
    450 				return false;
    451 		}
    452 	}
    453 
    454 	return true;
    455 }
    456 
    457 // get a 4 channel 8 bits each texture format that is usable by the given sampler type
    458 deUint32 getTextureFormat (glu::DataType samplerType)
    459 {
    460 	using namespace glu;
    461 
    462 	switch (samplerType)
    463 	{
    464 		case TYPE_SAMPLER_1D:
    465 		case TYPE_SAMPLER_2D:
    466 		case TYPE_SAMPLER_CUBE:
    467 		case TYPE_SAMPLER_2D_ARRAY:
    468 		case TYPE_SAMPLER_3D:
    469 			return GL_RGBA8;
    470 
    471 		case TYPE_INT_SAMPLER_1D:
    472 		case TYPE_INT_SAMPLER_2D:
    473 		case TYPE_INT_SAMPLER_CUBE:
    474 		case TYPE_INT_SAMPLER_2D_ARRAY:
    475 		case TYPE_INT_SAMPLER_3D:
    476 			return GL_RGBA8I;
    477 
    478 		case TYPE_UINT_SAMPLER_1D:
    479 		case TYPE_UINT_SAMPLER_2D:
    480 		case TYPE_UINT_SAMPLER_CUBE:
    481 		case TYPE_UINT_SAMPLER_2D_ARRAY:
    482 		case TYPE_UINT_SAMPLER_3D:
    483 			return GL_RGBA8UI;
    484 
    485 		default:
    486 			DE_ASSERT(!"Unsupported (sampler) type");
    487 			return 0;
    488 	}
    489 }
    490 
    491 // create a texture suitable for sampling by the given sampler type and bind it
    492 de::MovePtr<glu::Texture2D> UniformLocationCase::createTexture (glu::DataType samplerType, float redChannelValue, int binding)
    493 {
    494 	using namespace glu;
    495 
    496 	const glw::Functions&	gl		 = m_renderCtx.getFunctions();
    497 
    498 	const deUint32			format	 = getTextureFormat(samplerType);
    499 	de::MovePtr<Texture2D>	tex;
    500 
    501 	tex = de::MovePtr<Texture2D>(new Texture2D(m_renderCtx, format, 16, 16));
    502 
    503 	tex->getRefTexture().allocLevel(0);
    504 
    505 	if (format == GL_RGBA8I || format == GL_RGBA8UI)
    506 		tcu::clear(tex->getRefTexture().getLevel(0), tcu::IVec4(int(redChannelValue), 0, 0, 0));
    507 	else
    508 		tcu::clear(tex->getRefTexture().getLevel(0), tcu::Vec4(redChannelValue, 0.0f, 0.0f, 1.0f));
    509 
    510 	gl.activeTexture(GL_TEXTURE0 + binding);
    511 	tex->upload();
    512 
    513 	gl.bindTexture(GL_TEXTURE_2D, tex->getGLTexture());
    514 	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    515 	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    516 
    517 	GLU_EXPECT_NO_ERROR(gl.getError(), "UniformLocationCase: texture upload");
    518 
    519 	return tex;
    520 }
    521 
    522 void UniformLocationCase::render (const glu::ShaderProgram& program, const vector<UniformInfo>& uniformList)
    523 {
    524 	using glu::Texture2D;
    525 	using de::MovePtr;
    526 	typedef vector<Texture2D*> TextureList;
    527 
    528 	const glw::Functions&	gl				= m_renderCtx.getFunctions();
    529 	const deUint32			programID		= program.getProgram();
    530 	const deInt32			posLoc			= gl.getAttribLocation(programID, "a_position");
    531 
    532 	// Vertex data.
    533 	const float position[] =
    534 	{
    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 		 1.0f,  1.0f, 0.1f,	1.0f
    539 	};
    540 	const deUint16			indices[]		= { 0, 1, 2, 2, 1, 3 };
    541 
    542 	// some buffers to feed to the GPU, only the first element is relevant since the others are never verified
    543 	float					floatBuf[16]	= {0.0f};
    544 	deInt32					intBuf[4]		= {0};
    545 	deUint32				uintBuf[4]		= {0};
    546 
    547 	TextureList				texList;
    548 
    549 	TCU_CHECK(posLoc >= 0);
    550 	gl.useProgram(programID);
    551 
    552 	try
    553 	{
    554 
    555 		// Set uniforms
    556 		for (unsigned int uniformNdx = 0; uniformNdx < uniformList.size(); uniformNdx++)
    557 		{
    558 			const UniformInfo&	uniformInfo			= uniformList[uniformNdx];
    559 			int					expectedLocation	= uniformInfo.location;
    560 
    561 			for (glu::BasicTypeIterator subTypeIter = glu::BasicTypeIterator::begin(&uniformInfo.type); subTypeIter != glu::BasicTypeIterator::end(&uniformInfo.type); subTypeIter++)
    562 			{
    563 				const glu::VarType	type			= glu::getVarType(uniformInfo.type, subTypeIter.getPath());
    564 				const string		name			= getUniformName(uniformNdx, uniformInfo.type, subTypeIter.getPath());
    565 				const int			gotLoc			= gl.getUniformLocation(programID, name.c_str());
    566 				const glu::DataType	scalarType		= glu::getDataTypeScalarType(type.getBasicType());
    567 				const char*	const	typeName		= glu::getDataTypeName(scalarType);
    568 				const float			expectedValue	= getExpectedValue(scalarType, expectedLocation, typeName);
    569 
    570 				if (glu::isDataTypeSampler(scalarType))
    571 				{
    572 					const int binding = (int)texList.size();
    573 
    574 					texList.push_back(createTexture(scalarType, expectedValue, binding).release());
    575 					gl.uniform1i(gotLoc, binding);
    576 				}
    577 				else if(gotLoc >= 0)
    578 				{
    579 					floatBuf[0] = expectedValue;
    580 					intBuf[0]   = int(expectedValue);
    581 					uintBuf[0]  = deUint32(expectedValue);
    582 
    583 					m_testCtx.getLog() << tcu::TestLog::Message << "Set uniform " << name << " in location " << gotLoc << " to " << expectedValue << tcu::TestLog::EndMessage;
    584 
    585 					switch (type.getBasicType())
    586 					{
    587 						case glu::TYPE_FLOAT:			gl.uniform1fv(gotLoc, 1, floatBuf);					break;
    588 						case glu::TYPE_FLOAT_VEC2:		gl.uniform2fv(gotLoc, 1, floatBuf);					break;
    589 						case glu::TYPE_FLOAT_VEC3:		gl.uniform3fv(gotLoc, 1, floatBuf);					break;
    590 						case glu::TYPE_FLOAT_VEC4:		gl.uniform4fv(gotLoc, 1, floatBuf);					break;
    591 
    592 						case glu::TYPE_INT:				gl.uniform1iv(gotLoc, 1, intBuf);					break;
    593 						case glu::TYPE_INT_VEC2:		gl.uniform2iv(gotLoc, 1, intBuf);					break;
    594 						case glu::TYPE_INT_VEC3:		gl.uniform3iv(gotLoc, 1, intBuf);					break;
    595 						case glu::TYPE_INT_VEC4:		gl.uniform4iv(gotLoc, 1, intBuf);					break;
    596 
    597 						case glu::TYPE_UINT:			gl.uniform1uiv(gotLoc, 1, uintBuf);					break;
    598 						case glu::TYPE_UINT_VEC2:		gl.uniform2uiv(gotLoc, 1, uintBuf);					break;
    599 						case glu::TYPE_UINT_VEC3:		gl.uniform3uiv(gotLoc, 1, uintBuf);					break;
    600 						case glu::TYPE_UINT_VEC4:		gl.uniform4uiv(gotLoc, 1, uintBuf);					break;
    601 
    602 						case glu::TYPE_BOOL:			gl.uniform1iv(gotLoc, 1, intBuf);					break;
    603 						case glu::TYPE_BOOL_VEC2:		gl.uniform2iv(gotLoc, 1, intBuf);					break;
    604 						case glu::TYPE_BOOL_VEC3:		gl.uniform3iv(gotLoc, 1, intBuf);					break;
    605 						case glu::TYPE_BOOL_VEC4:		gl.uniform4iv(gotLoc, 1, intBuf);					break;
    606 
    607 						case glu::TYPE_FLOAT_MAT2:		gl.uniformMatrix2fv(gotLoc, 1, false, floatBuf);	break;
    608 						case glu::TYPE_FLOAT_MAT2X3:	gl.uniformMatrix2x3fv(gotLoc, 1, false, floatBuf);	break;
    609 						case glu::TYPE_FLOAT_MAT2X4:	gl.uniformMatrix2x4fv(gotLoc, 1, false, floatBuf);	break;
    610 
    611 						case glu::TYPE_FLOAT_MAT3X2:	gl.uniformMatrix3x2fv(gotLoc, 1, false, floatBuf);	break;
    612 						case glu::TYPE_FLOAT_MAT3:		gl.uniformMatrix3fv(gotLoc, 1, false, floatBuf);	break;
    613 						case glu::TYPE_FLOAT_MAT3X4:	gl.uniformMatrix3x4fv(gotLoc, 1, false, floatBuf);	break;
    614 
    615 						case glu::TYPE_FLOAT_MAT4X2:	gl.uniformMatrix4x2fv(gotLoc, 1, false, floatBuf);	break;
    616 						case glu::TYPE_FLOAT_MAT4X3:	gl.uniformMatrix4x3fv(gotLoc, 1, false, floatBuf);	break;
    617 						case glu::TYPE_FLOAT_MAT4:		gl.uniformMatrix4fv(gotLoc, 1, false, floatBuf);	break;
    618 						default:
    619 							DE_ASSERT(false);
    620 					}
    621 				}
    622 
    623 				expectedLocation += expectedLocation>=0;
    624 			}
    625 		}
    626 
    627 		gl.enableVertexAttribArray(posLoc);
    628 		gl.vertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, &position[0]);
    629 
    630 		gl.drawElements(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(indices), GL_UNSIGNED_SHORT, &indices[0]);
    631 
    632 		gl.disableVertexAttribArray(posLoc);
    633 	}
    634 	catch(...)
    635 	{
    636 		for (int i = 0; i < int(texList.size()); i++)
    637 			delete texList[i];
    638 
    639 		throw;
    640 	}
    641 
    642 	for (int i = 0; i < int(texList.size()); i++)
    643 		delete texList[i];
    644 }
    645 
    646 class MaxUniformLocationCase : public UniformLocationCase
    647 {
    648 public:
    649 								MaxUniformLocationCase		(tcu::TestContext&			context,
    650 															 glu::RenderContext&		renderContext,
    651 															 const char*				name,
    652 															 const char*				desc,
    653 															 const vector<UniformInfo>&	uniformInfo);
    654 	virtual 					~MaxUniformLocationCase		(void) {}
    655 	virtual IterateResult		iterate						(void);
    656 };
    657 
    658 MaxUniformLocationCase::MaxUniformLocationCase (tcu::TestContext&			context,
    659 												glu::RenderContext&			renderContext,
    660 												const char*					name,
    661 												const char*					desc,
    662 												const vector<UniformInfo>&	uniformInfo)
    663 	: UniformLocationCase(context, renderContext, name, desc, uniformInfo)
    664 {
    665 	DE_ASSERT(!uniformInfo.empty());
    666 }
    667 
    668 UniformLocationCase::IterateResult MaxUniformLocationCase::iterate (void)
    669 {
    670 	int					maxLocation = 1024;
    671 	vector<UniformInfo>	uniformInfo = m_uniformInfo;
    672 
    673 	m_renderCtx.getFunctions().getIntegerv(GL_MAX_UNIFORM_LOCATIONS, &maxLocation);
    674 
    675 	uniformInfo[0].location = maxLocation-1;
    676 
    677 	return UniformLocationCase::run(uniformInfo);
    678 }
    679 
    680 } // Anonymous
    681 
    682 UniformLocationTests::UniformLocationTests (Context& context)
    683 	: TestCaseGroup(context, "uniform_location", "Explicit uniform locations")
    684 {
    685 }
    686 
    687 UniformLocationTests::~UniformLocationTests (void)
    688 {
    689 	for (int i = 0; i < int(structTypes.size()); i++)
    690 		delete structTypes[i];
    691 }
    692 
    693 glu::VarType createVarType (glu::DataType type)
    694 {
    695 	return glu::VarType(type, glu::isDataTypeBoolOrBVec(type) ? glu::PRECISION_LAST : glu::PRECISION_HIGHP);
    696 }
    697 
    698 void UniformLocationTests::init (void)
    699 {
    700 	using namespace glu;
    701 
    702 	const UniformInfo::ShaderStage checkStages[]	= { UniformInfo::SHADERSTAGE_VERTEX, UniformInfo::SHADERSTAGE_FRAGMENT };
    703 	const char*						stageNames[]	= {"vertex", "fragment"};
    704 	const int						maxLocations	= 1024;
    705 	const int						baseSeed		= m_context.getTestContext().getCommandLine().getBaseSeed();
    706 
    707 	const DataType					primitiveTypes[] =
    708 	{
    709 		TYPE_FLOAT,
    710 		TYPE_FLOAT_VEC2,
    711 		TYPE_FLOAT_VEC3,
    712 		TYPE_FLOAT_VEC4,
    713 
    714 		TYPE_INT,
    715 		TYPE_INT_VEC2,
    716 		TYPE_INT_VEC3,
    717 		TYPE_INT_VEC4,
    718 
    719 		TYPE_UINT,
    720 		TYPE_UINT_VEC2,
    721 		TYPE_UINT_VEC3,
    722 		TYPE_UINT_VEC4,
    723 
    724 		TYPE_BOOL,
    725 		TYPE_BOOL_VEC2,
    726 		TYPE_BOOL_VEC3,
    727 		TYPE_BOOL_VEC4,
    728 
    729 		TYPE_FLOAT_MAT2,
    730 		TYPE_FLOAT_MAT2X3,
    731 		TYPE_FLOAT_MAT2X4,
    732 		TYPE_FLOAT_MAT3X2,
    733 		TYPE_FLOAT_MAT3,
    734 		TYPE_FLOAT_MAT3X4,
    735 		TYPE_FLOAT_MAT4X2,
    736 		TYPE_FLOAT_MAT4X3,
    737 		TYPE_FLOAT_MAT4,
    738 
    739 		TYPE_SAMPLER_2D,
    740 		TYPE_INT_SAMPLER_2D,
    741 		TYPE_UINT_SAMPLER_2D,
    742 	};
    743 
    744 	const int maxPrimitiveTypeNdx = DE_LENGTH_OF_ARRAY(primitiveTypes) - 4;
    745 	DE_ASSERT(primitiveTypes[maxPrimitiveTypeNdx] == TYPE_FLOAT_MAT4);
    746 
    747 	// Primitive type cases with trivial linkage
    748 	{
    749 		tcu::TestCaseGroup* const	group	= new tcu::TestCaseGroup(m_testCtx, "basic", "Location specified with use, single shader stage");
    750 		de::Random					rng		(baseSeed + 0x1001);
    751 		addChild(group);
    752 
    753 		for (int primitiveNdx = 0; primitiveNdx < DE_LENGTH_OF_ARRAY(primitiveTypes); primitiveNdx++)
    754 		{
    755 			const DataType		type	= primitiveTypes[primitiveNdx];
    756 
    757 			for (int stageNdx = 0; stageNdx < DE_LENGTH_OF_ARRAY(checkStages); stageNdx++)
    758 			{
    759 				const string		name		= string(getDataTypeName(type)) + "_" + stageNames[stageNdx];
    760 
    761 				vector<UniformInfo> config;
    762 
    763 				UniformInfo			uniform	(createVarType(type),
    764 											 checkStages[stageNdx],
    765 											 checkStages[stageNdx],
    766 											 checkStages[stageNdx],
    767 											 rng.getInt(0, maxLocations-1));
    768 
    769 				config.push_back(uniform);
    770 				group->addChild(new UniformLocationCase (m_testCtx, m_context.getRenderContext(), name.c_str(), name.c_str(), config));
    771 			}
    772 		}
    773 	}
    774 
    775 	// Arrays
    776 	{
    777 		tcu::TestCaseGroup* const	group	= new tcu::TestCaseGroup(m_testCtx, "array", "Array location specified with use, single shader stage");
    778 		de::Random					rng		(baseSeed + 0x2001);
    779 		addChild(group);
    780 
    781 		for (int primitiveNdx = 0; primitiveNdx < DE_LENGTH_OF_ARRAY(primitiveTypes); primitiveNdx++)
    782 		{
    783 			const DataType		type	= primitiveTypes[primitiveNdx];
    784 
    785 			for (int stageNdx = 0; stageNdx < DE_LENGTH_OF_ARRAY(checkStages); stageNdx++)
    786 			{
    787 
    788 				const string		name	= string(getDataTypeName(type)) + "_" + stageNames[stageNdx];
    789 
    790 				vector<UniformInfo> config;
    791 
    792 				UniformInfo			uniform	(VarType(createVarType(type), 8),
    793 												checkStages[stageNdx],
    794 												checkStages[stageNdx],
    795 												checkStages[stageNdx],
    796 												rng.getInt(0, maxLocations-1-8));
    797 
    798 				config.push_back(uniform);
    799 				group->addChild(new UniformLocationCase (m_testCtx, m_context.getRenderContext(), name.c_str(), name.c_str(), config));
    800 			}
    801 		}
    802 	}
    803 
    804 	// Nested Arrays
    805 	{
    806 		tcu::TestCaseGroup* const	group	= new tcu::TestCaseGroup(m_testCtx, "nested_array", "Array location specified with use, single shader stage");
    807 		de::Random					rng		(baseSeed + 0x3001);
    808 		addChild(group);
    809 
    810 		for (int primitiveNdx = 0; primitiveNdx < DE_LENGTH_OF_ARRAY(primitiveTypes); primitiveNdx++)
    811 		{
    812 			const DataType		type	= primitiveTypes[primitiveNdx];
    813 
    814 			for (int stageNdx = 0; stageNdx < DE_LENGTH_OF_ARRAY(checkStages); stageNdx++)
    815 			{
    816 				const string		name		= string(getDataTypeName(type)) + "_" + stageNames[stageNdx];
    817 				// stay comfortably within minimum max uniform component count (896 in fragment) and sampler count with all types
    818 				const int			arraySize	= (getDataTypeScalarSize(type) > 4 || isDataTypeSampler(type)) ? 3 : 7;
    819 
    820 				vector<UniformInfo> config;
    821 
    822 				UniformInfo			uniform	(VarType(VarType(createVarType(type), arraySize), arraySize),
    823 											 checkStages[stageNdx],
    824 											 checkStages[stageNdx],
    825 											 checkStages[stageNdx],
    826 											 rng.getInt(0, maxLocations-1-arraySize*arraySize));
    827 
    828 				config.push_back(uniform);
    829 				group->addChild(new UniformLocationCase (m_testCtx, m_context.getRenderContext(), name.c_str(), name.c_str(), config));
    830 			}
    831 		}
    832 	}
    833 
    834 	// Structs
    835 	{
    836 		tcu::TestCaseGroup* const	group	= new tcu::TestCaseGroup(m_testCtx, "struct", "Struct location, random contents & declaration location");
    837 		de::Random					rng		(baseSeed + 0x4001);
    838 		addChild(group);
    839 
    840 		for (int caseNdx = 0; caseNdx < 16; caseNdx++)
    841 		{
    842 			typedef UniformInfo::ShaderStage Stage;
    843 
    844 			const string	name		= "case_" + de::toString(caseNdx);
    845 
    846 			const Stage		layoutLoc	= Stage(rng.getUint32()&0x3);
    847 			const Stage		declareLoc	= Stage((rng.getUint32()&0x3) | layoutLoc);
    848 			const Stage		verifyLoc	= Stage((rng.getUint32()&0x3) & declareLoc);
    849 			const int		location	= layoutLoc ? rng.getInt(0, maxLocations-1-5) : -1;
    850 
    851 			StructType*		structProto = new StructType("S");
    852 
    853 			structTypes.push_back(structProto);
    854 
    855 			structProto->addMember("a", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
    856 			structProto->addMember("b", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
    857 			structProto->addMember("c", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
    858 			structProto->addMember("d", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
    859 			structProto->addMember("e", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
    860 
    861 			{
    862 				vector<UniformInfo> config;
    863 
    864 				config.push_back(UniformInfo(VarType(structProto),
    865 											 declareLoc,
    866 											 layoutLoc,
    867 											 verifyLoc,
    868 											 location));
    869 				group->addChild(new UniformLocationCase (m_testCtx, m_context.getRenderContext(), name.c_str(), name.c_str(), config));
    870 			}
    871 		}
    872 	}
    873 
    874 	// Nested Structs
    875 	{
    876 		tcu::TestCaseGroup* const	group	= new tcu::TestCaseGroup(m_testCtx, "nested_struct", "Struct location specified with use, single shader stage");
    877 		de::Random					rng		(baseSeed + 0x5001);
    878 
    879 		addChild(group);
    880 
    881 		for (int caseNdx = 0; caseNdx < 16; caseNdx++)
    882 		{
    883 			typedef UniformInfo::ShaderStage Stage;
    884 
    885 			const string	name		= "case_" + de::toString(caseNdx);
    886 			const int		baseLoc		= rng.getInt(0, maxLocations-1-60);
    887 
    888 			// Structs need to be added in the order of their declaration
    889 			const Stage		layoutLocs[]=
    890 			{
    891 				Stage(rng.getUint32()&0x3),
    892 				Stage(rng.getUint32()&0x3),
    893 				Stage(rng.getUint32()&0x3),
    894 				Stage(rng.getUint32()&0x3),
    895 			};
    896 
    897 			const deUint32	tempDecl[] =
    898 			{
    899 				(rng.getUint32()&0x3) | layoutLocs[0],
    900 				(rng.getUint32()&0x3) | layoutLocs[1],
    901 				(rng.getUint32()&0x3) | layoutLocs[2],
    902 				(rng.getUint32()&0x3) | layoutLocs[3],
    903 			};
    904 
    905 			// Component structs need to be declared if anything using them is declared
    906 			const Stage		declareLocs[] =
    907 			{
    908 				Stage(tempDecl[0] | tempDecl[1] | tempDecl[2] | tempDecl[3]),
    909 				Stage(tempDecl[1] | tempDecl[2] | tempDecl[3]),
    910 				Stage(tempDecl[2] | tempDecl[3]),
    911 				Stage(tempDecl[3]),
    912 			};
    913 
    914 			const Stage		verifyLocs[] =
    915 			{
    916 				Stage(rng.getUint32()&0x3 & declareLocs[0]),
    917 				Stage(rng.getUint32()&0x3 & declareLocs[1]),
    918 				Stage(rng.getUint32()&0x3 & declareLocs[2]),
    919 				Stage(rng.getUint32()&0x3 & declareLocs[3]),
    920 			};
    921 
    922 			StructType*		testTypes[]	=
    923 			{
    924 				new StructType("Type0"),
    925 				new StructType("Type1"),
    926 				new StructType("Type2"),
    927 				new StructType("Type3"),
    928 			};
    929 
    930 			structTypes.push_back(testTypes[0]);
    931 			structTypes.push_back(testTypes[1]);
    932 			structTypes.push_back(testTypes[2]);
    933 			structTypes.push_back(testTypes[3]);
    934 
    935 			testTypes[0]->addMember("a", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
    936 			testTypes[0]->addMember("b", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
    937 			testTypes[0]->addMember("c", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
    938 			testTypes[0]->addMember("d", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
    939 			testTypes[0]->addMember("e", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
    940 
    941 			testTypes[1]->addMember("a", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
    942 			testTypes[1]->addMember("b", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
    943 			testTypes[1]->addMember("c", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
    944 			testTypes[1]->addMember("d", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
    945 			testTypes[1]->addMember("e", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
    946 
    947 			testTypes[2]->addMember("a", VarType(testTypes[0]));
    948 			testTypes[2]->addMember("b", VarType(testTypes[1]));
    949 			testTypes[2]->addMember("c", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
    950 
    951 			testTypes[3]->addMember("a", VarType(testTypes[2]));
    952 
    953 			{
    954 				vector<UniformInfo> config;
    955 
    956 				config.push_back(UniformInfo(VarType(testTypes[0]),
    957 											 declareLocs[0],
    958 											 layoutLocs[0],
    959 											 verifyLocs[0],
    960 											 layoutLocs[0] ? baseLoc : -1));
    961 
    962 				config.push_back(UniformInfo(VarType(testTypes[1]),
    963 											 declareLocs[1],
    964 											 layoutLocs[1],
    965 											 verifyLocs[1],
    966 											 layoutLocs[1] ? baseLoc+5 : -1));
    967 
    968 				config.push_back(UniformInfo(VarType(testTypes[2]),
    969 											 declareLocs[2],
    970 											 layoutLocs[2],
    971 											 verifyLocs[2],
    972 											 layoutLocs[2] ? baseLoc+16 : -1));
    973 
    974 				config.push_back(UniformInfo(VarType(testTypes[3]),
    975 											 declareLocs[3],
    976 											 layoutLocs[3],
    977 											 verifyLocs[3],
    978 											 layoutLocs[3] ? baseLoc+27 : -1));
    979 
    980 				group->addChild(new UniformLocationCase (m_testCtx, m_context.getRenderContext(), name.c_str(), name.c_str(), config));
    981 			}
    982 		}
    983 	}
    984 
    985 	// Min/Max location
    986 	{
    987 		tcu::TestCaseGroup* const	group		= new tcu::TestCaseGroup(m_testCtx, "min_max", "Maximum & minimum location");
    988 		de::Random					rng			(baseSeed + 0x1f01);
    989 
    990 		addChild(group);
    991 
    992 		for (int primitiveNdx = 0; primitiveNdx < DE_LENGTH_OF_ARRAY(primitiveTypes); primitiveNdx++)
    993 		{
    994 			const DataType		type	= primitiveTypes[primitiveNdx];
    995 
    996 			for (int stageNdx = 0; stageNdx < DE_LENGTH_OF_ARRAY(checkStages); stageNdx++)
    997 			{
    998 				const string		name		= string(getDataTypeName(type)) + "_" + stageNames[stageNdx];
    999 				vector<UniformInfo> config;
   1000 
   1001 				config.push_back(UniformInfo(createVarType(type),
   1002 											 checkStages[stageNdx],
   1003 											 checkStages[stageNdx],
   1004 											 checkStages[stageNdx],
   1005 											 0));
   1006 
   1007 				group->addChild(new UniformLocationCase (m_testCtx, m_context.getRenderContext(), (name+"_min").c_str(), (name+"_min").c_str(), config));
   1008 
   1009 				group->addChild(new MaxUniformLocationCase (m_testCtx, m_context.getRenderContext(), (name+"_max").c_str(), (name+"_max").c_str(), config));
   1010 			}
   1011 		}
   1012 	}
   1013 
   1014 	// Link
   1015 	{
   1016 		tcu::TestCaseGroup* const	group	= new tcu::TestCaseGroup(m_testCtx, "link", "Location specified independently from use");
   1017 		de::Random					rng		(baseSeed + 0x82e1);
   1018 
   1019 		addChild(group);
   1020 
   1021 		for (int caseNdx = 0; caseNdx < 10; caseNdx++)
   1022 		{
   1023 			const string		name		= "case_" + de::toString(caseNdx);
   1024 			vector<UniformInfo> config;
   1025 
   1026 			vector<int>			locations	= shuffledRange(0, maxLocations, 0x1234 + caseNdx*100);
   1027 
   1028 			for (int count = 0; count < 32; count++)
   1029 			{
   1030 				typedef UniformInfo::ShaderStage Stage;
   1031 
   1032 				const Stage			layoutLoc	= Stage(rng.getUint32()&0x3);
   1033 				const Stage			declareLoc	= Stage((rng.getUint32()&0x3) | layoutLoc);
   1034 				const Stage			verifyLoc	= Stage((rng.getUint32()&0x3) & declareLoc);
   1035 
   1036 				const UniformInfo	uniform		(createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]),
   1037 												 declareLoc,
   1038 												 layoutLoc,
   1039 												 verifyLoc,
   1040 												 (layoutLoc!=0) ? locations.back() : -1);
   1041 
   1042 				config.push_back(uniform);
   1043 				locations.pop_back();
   1044 			}
   1045 			group->addChild(new UniformLocationCase (m_testCtx, m_context.getRenderContext(), name.c_str(), name.c_str(), config));
   1046 		}
   1047 	}
   1048 
   1049 	// Negative
   1050 	{
   1051 		gls::ShaderLibrary			shaderLibrary    (m_testCtx, m_context.getRenderContext(), m_context.getContextInfo());
   1052 		const vector<TestNode*>     negativeCases    = shaderLibrary.loadShaderFile("shaders/uniform_location.test");
   1053 		tcu::TestCaseGroup* const	group			 = new tcu::TestCaseGroup(m_testCtx, "negative", "Negative tests");
   1054 
   1055 		addChild(group);
   1056 
   1057 		for (int ndx = 0; ndx < int(negativeCases.size()); ndx++)
   1058 			group->addChild(negativeCases[ndx]);
   1059 	}
   1060 }
   1061 
   1062 } // Functional
   1063 } // gles31
   1064 } // deqp
   1065