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 Uniform API tests.
     22  *
     23  * \todo [2013-02-26 nuutti] Much duplication between this and ES3.
     24  *							 Utilities to glshared?
     25  *//*--------------------------------------------------------------------*/
     26 
     27 #include "es2fUniformApiTests.hpp"
     28 #include "gluCallLogWrapper.hpp"
     29 #include "gluShaderProgram.hpp"
     30 #include "gluVarType.hpp"
     31 #include "gluPixelTransfer.hpp"
     32 #include "gluTextureUtil.hpp"
     33 #include "gluTexture.hpp"
     34 #include "tcuRenderTarget.hpp"
     35 #include "tcuTestLog.hpp"
     36 #include "tcuSurface.hpp"
     37 #include "tcuCommandLine.hpp"
     38 #include "deRandom.hpp"
     39 #include "deStringUtil.hpp"
     40 #include "deSharedPtr.hpp"
     41 #include "deString.h"
     42 #include "deMemory.h"
     43 
     44 #include "glwEnums.hpp"
     45 #include "glwFunctions.hpp"
     46 
     47 #include <set>
     48 #include <cstring>
     49 
     50 using namespace glw;
     51 
     52 namespace deqp
     53 {
     54 namespace gles2
     55 {
     56 namespace Functional
     57 {
     58 
     59 using std::vector;
     60 using std::string;
     61 using tcu::TestLog;
     62 using tcu::ScopedLogSection;
     63 using glu::ShaderProgram;
     64 using glu::StructType;
     65 using de::Random;
     66 using de::SharedPtr;
     67 
     68 typedef bool (* dataTypePredicate)(glu::DataType);
     69 
     70 static const int MAX_RENDER_WIDTH			= 32;
     71 static const int MAX_RENDER_HEIGHT			= 32;
     72 static const int MAX_NUM_SAMPLER_UNIFORMS	= 16;
     73 
     74 static const glu::DataType s_testDataTypes[] =
     75 {
     76 	glu::TYPE_FLOAT,
     77 	glu::TYPE_FLOAT_VEC2,
     78 	glu::TYPE_FLOAT_VEC3,
     79 	glu::TYPE_FLOAT_VEC4,
     80 	glu::TYPE_FLOAT_MAT2,
     81 	glu::TYPE_FLOAT_MAT3,
     82 	glu::TYPE_FLOAT_MAT4,
     83 
     84 	glu::TYPE_INT,
     85 	glu::TYPE_INT_VEC2,
     86 	glu::TYPE_INT_VEC3,
     87 	glu::TYPE_INT_VEC4,
     88 
     89 	glu::TYPE_BOOL,
     90 	glu::TYPE_BOOL_VEC2,
     91 	glu::TYPE_BOOL_VEC3,
     92 	glu::TYPE_BOOL_VEC4,
     93 
     94 	glu::TYPE_SAMPLER_2D,
     95 	glu::TYPE_SAMPLER_CUBE
     96 };
     97 
     98 static inline int getGLInt (const glw::Functions& funcs, const deUint32 name)
     99 {
    100 	int val = -1;
    101 	funcs.getIntegerv(name, &val);
    102 	return val;
    103 }
    104 
    105 static inline tcu::Vec4 vec4FromPtr (const float* const ptr)
    106 {
    107 	tcu::Vec4 result;
    108 	for (int i = 0; i < 4; i++)
    109 		result[i] = ptr[i];
    110 	return result;
    111 }
    112 
    113 static inline string beforeLast (const string& str, const char c)
    114 {
    115 	return str.substr(0, str.find_last_of(c));
    116 }
    117 
    118 static inline void fillWithColor (const tcu::PixelBufferAccess& access, const tcu::Vec4& color)
    119 {
    120 	for (int z = 0; z < access.getDepth(); z++)
    121 	for (int y = 0; y < access.getHeight(); y++)
    122 	for (int x = 0; x < access.getWidth(); x++)
    123 		access.setPixel(color, x, y, z);
    124 }
    125 
    126 static inline int getSamplerNumLookupDimensions (const glu::DataType type)
    127 {
    128 	switch (type)
    129 	{
    130 		case glu::TYPE_SAMPLER_2D:
    131 			return 2;
    132 
    133 		case glu::TYPE_SAMPLER_CUBE:
    134 			return 3;
    135 
    136 		default: // \note All others than 2d and cube are gles3-only types.
    137 			DE_ASSERT(false);
    138 			return 0;
    139 	}
    140 }
    141 
    142 template<glu::DataType T>
    143 static bool dataTypeEquals (const glu::DataType t)
    144 {
    145 	return t == T;
    146 }
    147 
    148 template<int N>
    149 static bool dataTypeIsMatrixWithNRows (const glu::DataType t)
    150 {
    151 	return glu::isDataTypeMatrix(t) && glu::getDataTypeMatrixNumRows(t) == N;
    152 }
    153 
    154 static bool typeContainsMatchingBasicType (const glu::VarType& type, const dataTypePredicate predicate)
    155 {
    156 	if (type.isBasicType())
    157 		return predicate(type.getBasicType());
    158 	else if (type.isArrayType())
    159 		return typeContainsMatchingBasicType(type.getElementType(), predicate);
    160 	else
    161 	{
    162 		DE_ASSERT(type.isStructType());
    163 		const StructType& structType = *type.getStructPtr();
    164 		for (int i = 0; i < structType.getNumMembers(); i++)
    165 			if (typeContainsMatchingBasicType(structType.getMember(i).getType(), predicate))
    166 				return true;
    167 		return false;
    168 	}
    169 }
    170 
    171 static void getDistinctSamplerTypes (vector<glu::DataType>& dst, const glu::VarType& type)
    172 {
    173 	if (type.isBasicType())
    174 	{
    175 		const glu::DataType basicType = type.getBasicType();
    176 		if (glu::isDataTypeSampler(basicType) && std::find(dst.begin(), dst.end(), basicType) == dst.end())
    177 			dst.push_back(basicType);
    178 	}
    179 	else if (type.isArrayType())
    180 		getDistinctSamplerTypes(dst, type.getElementType());
    181 	else
    182 	{
    183 		DE_ASSERT(type.isStructType());
    184 		const StructType& structType = *type.getStructPtr();
    185 		for (int i = 0; i < structType.getNumMembers(); i++)
    186 			getDistinctSamplerTypes(dst, structType.getMember(i).getType());
    187 	}
    188 }
    189 
    190 static int getNumSamplersInType (const glu::VarType& type)
    191 {
    192 	if (type.isBasicType())
    193 		return glu::isDataTypeSampler(type.getBasicType()) ? 1 : 0;
    194 	else if (type.isArrayType())
    195 		return getNumSamplersInType(type.getElementType()) * type.getArraySize();
    196 	else
    197 	{
    198 		DE_ASSERT(type.isStructType());
    199 		const StructType& structType = *type.getStructPtr();
    200 		int sum = 0;
    201 		for (int i = 0; i < structType.getNumMembers(); i++)
    202 			sum += getNumSamplersInType(structType.getMember(i).getType());
    203 		return sum;
    204 	}
    205 }
    206 
    207 static glu::VarType generateRandomType (const int maxDepth, int& curStructIdx, vector<const StructType*>& structTypesDst, Random& rnd)
    208 {
    209 	const bool isStruct		= maxDepth > 0 && rnd.getFloat() < 0.2f;
    210 	const bool isArray		= rnd.getFloat() < 0.3f;
    211 
    212 	if (isStruct)
    213 	{
    214 		const int			numMembers = rnd.getInt(1, 5);
    215 		StructType* const	structType = new StructType(("structType" + de::toString(curStructIdx++)).c_str());
    216 
    217 		for (int i = 0; i < numMembers; i++)
    218 			structType->addMember(("m" + de::toString(i)).c_str(), generateRandomType(maxDepth-1, curStructIdx, structTypesDst, rnd));
    219 
    220 		structTypesDst.push_back(structType);
    221 		return isArray ? glu::VarType(glu::VarType(structType), rnd.getInt(1, 5)) : glu::VarType(structType);
    222 	}
    223 	else
    224 	{
    225 		const glu::DataType		basicType = (glu::DataType)s_testDataTypes[rnd.getInt(0, DE_LENGTH_OF_ARRAY(s_testDataTypes)-1)];
    226 		const glu::Precision	precision = glu::isDataTypeBoolOrBVec(basicType) ? glu::PRECISION_LAST : glu::PRECISION_MEDIUMP;
    227 		return isArray ? glu::VarType(glu::VarType(basicType, precision), rnd.getInt(1, 5)) : glu::VarType(basicType, precision);
    228 	}
    229 }
    230 
    231 namespace
    232 {
    233 
    234 struct VarValue
    235 {
    236 	glu::DataType type;
    237 
    238 	union
    239 	{
    240 		float		floatV[4*4]; // At most mat4. \note Matrices here are column-major.
    241 		deInt32		intV[4];
    242 		bool		boolV[4];
    243 		struct
    244 		{
    245 			int		unit;
    246 			float	fillColor[4];
    247 		} samplerV;
    248 	} val;
    249 };
    250 
    251 enum CaseShaderType
    252 {
    253 	CASESHADERTYPE_VERTEX = 0,
    254 	CASESHADERTYPE_FRAGMENT,
    255 	CASESHADERTYPE_BOTH,
    256 
    257 	CASESHADERTYPE_LAST
    258 };
    259 
    260 struct Uniform
    261 {
    262 	string			name;
    263 	glu::VarType	type;
    264 
    265 	Uniform (const char* const name_, const glu::VarType& type_) : name(name_), type(type_) {}
    266 };
    267 
    268 // A set of uniforms, along with related struct types.
    269 class UniformCollection
    270 {
    271 public:
    272 	int					getNumUniforms		(void) const					{ return (int)m_uniforms.size();	}
    273 	int					getNumStructTypes	(void) const					{ return (int)m_structTypes.size();	}
    274 	Uniform&			getUniform			(const int ndx)					{ return m_uniforms[ndx];			}
    275 	const Uniform&		getUniform			(const int ndx) const			{ return m_uniforms[ndx];			}
    276 	const StructType*	getStructType		(const int ndx) const			{ return m_structTypes[ndx];		}
    277 	void				addUniform			(const Uniform& uniform)		{ m_uniforms.push_back(uniform);	}
    278 	void				addStructType		(const StructType* const type)	{ m_structTypes.push_back(type);	}
    279 
    280 	UniformCollection	(void) {}
    281 	~UniformCollection	(void)
    282 	{
    283 		for (int i = 0; i < (int)m_structTypes.size(); i++)
    284 			delete m_structTypes[i];
    285 	}
    286 
    287 	// Add the contents of m_uniforms and m_structTypes to receiver, and remove them from this one.
    288 	// \note receiver takes ownership of the struct types.
    289 	void moveContents (UniformCollection& receiver)
    290 	{
    291 		for (int i = 0; i < (int)m_uniforms.size(); i++)
    292 			receiver.addUniform(m_uniforms[i]);
    293 		m_uniforms.clear();
    294 
    295 		for (int i = 0; i < (int)m_structTypes.size(); i++)
    296 			receiver.addStructType(m_structTypes[i]);
    297 		m_structTypes.clear();
    298 	}
    299 
    300 	bool containsMatchingBasicType (const dataTypePredicate predicate) const
    301 	{
    302 		for (int i = 0; i < (int)m_uniforms.size(); i++)
    303 			if (typeContainsMatchingBasicType(m_uniforms[i].type, predicate))
    304 				return true;
    305 		return false;
    306 	}
    307 
    308 	vector<glu::DataType> getSamplerTypes (void) const
    309 	{
    310 		vector<glu::DataType> samplerTypes;
    311 		for (int i = 0; i < (int)m_uniforms.size(); i++)
    312 			getDistinctSamplerTypes(samplerTypes, m_uniforms[i].type);
    313 		return samplerTypes;
    314 	}
    315 
    316 	bool containsSeveralSamplerTypes (void) const
    317 	{
    318 		return getSamplerTypes().size() > 1;
    319 	}
    320 
    321 	int getNumSamplers (void) const
    322 	{
    323 		int sum = 0;
    324 		for (int i = 0; i < (int)m_uniforms.size(); i++)
    325 			sum += getNumSamplersInType(m_uniforms[i].type);
    326 		return sum;
    327 	}
    328 
    329 	static UniformCollection* basic (const glu::DataType type, const char* const nameSuffix = "")
    330 	{
    331 		UniformCollection* const	res		= new UniformCollection;
    332 		const glu::Precision		prec	= glu::isDataTypeBoolOrBVec(type) ? glu::PRECISION_LAST : glu::PRECISION_MEDIUMP;
    333 		res->m_uniforms.push_back(Uniform((string("u_var") + nameSuffix).c_str(), glu::VarType(type, prec)));
    334 		return res;
    335 	}
    336 
    337 	static UniformCollection* basicArray (const glu::DataType type, const char* const nameSuffix = "")
    338 	{
    339 		UniformCollection* const	res		= new UniformCollection;
    340 		const glu::Precision		prec	= glu::isDataTypeBoolOrBVec(type) ? glu::PRECISION_LAST : glu::PRECISION_MEDIUMP;
    341 		res->m_uniforms.push_back(Uniform((string("u_var") + nameSuffix).c_str(), glu::VarType(glu::VarType(type, prec), 3)));
    342 		return res;
    343 	}
    344 
    345 	static UniformCollection* basicStruct (const glu::DataType type0, const glu::DataType type1, const bool containsArrays, const char* const nameSuffix = "")
    346 	{
    347 		UniformCollection* const	res		= new UniformCollection;
    348 		const glu::Precision		prec0	= glu::isDataTypeBoolOrBVec(type0) ? glu::PRECISION_LAST : glu::PRECISION_MEDIUMP;
    349 		const glu::Precision		prec1	= glu::isDataTypeBoolOrBVec(type1) ? glu::PRECISION_LAST : glu::PRECISION_MEDIUMP;
    350 
    351 		StructType* const structType = new StructType((string("structType") + nameSuffix).c_str());
    352 		structType->addMember("m0", glu::VarType(type0, prec0));
    353 		structType->addMember("m1", glu::VarType(type1, prec1));
    354 		if (containsArrays)
    355 		{
    356 			structType->addMember("m2", glu::VarType(glu::VarType(type0, prec0), 3));
    357 			structType->addMember("m3", glu::VarType(glu::VarType(type1, prec1), 3));
    358 		}
    359 
    360 		res->addStructType(structType);
    361 		res->addUniform(Uniform((string("u_var") + nameSuffix).c_str(), glu::VarType(structType)));
    362 
    363 		return res;
    364 	}
    365 
    366 	static UniformCollection* structInArray (const glu::DataType type0, const glu::DataType type1, const bool containsArrays, const char* const nameSuffix = "")
    367 	{
    368 		UniformCollection* const res = basicStruct(type0, type1, containsArrays, nameSuffix);
    369 		res->getUniform(0).type = glu::VarType(res->getUniform(0).type, 3);
    370 		return res;
    371 	}
    372 
    373 	static UniformCollection* nestedArraysStructs (const glu::DataType type0, const glu::DataType type1, const char* const nameSuffix = "")
    374 	{
    375 		UniformCollection* const res		= new UniformCollection;
    376 		const glu::Precision prec0			= glu::isDataTypeBoolOrBVec(type0) ? glu::PRECISION_LAST : glu::PRECISION_MEDIUMP;
    377 		const glu::Precision prec1			= glu::isDataTypeBoolOrBVec(type1) ? glu::PRECISION_LAST : glu::PRECISION_MEDIUMP;
    378 		StructType* const structType		= new StructType((string("structType") + nameSuffix).c_str());
    379 		StructType* const subStructType		= new StructType((string("subStructType") + nameSuffix).c_str());
    380 		StructType* const subSubStructType	= new StructType((string("subSubStructType") + nameSuffix).c_str());
    381 
    382 		subSubStructType->addMember("mss0", glu::VarType(type0, prec0));
    383 		subSubStructType->addMember("mss1", glu::VarType(type1, prec1));
    384 
    385 		subStructType->addMember("ms0", glu::VarType(type1, prec1));
    386 		subStructType->addMember("ms1", glu::VarType(glu::VarType(type0, prec0), 2));
    387 		subStructType->addMember("ms2", glu::VarType(glu::VarType(subSubStructType), 2));
    388 
    389 		structType->addMember("m0", glu::VarType(type0, prec0));
    390 		structType->addMember("m1", glu::VarType(subStructType));
    391 		structType->addMember("m2", glu::VarType(type1, prec1));
    392 
    393 		res->addStructType(subSubStructType);
    394 		res->addStructType(subStructType);
    395 		res->addStructType(structType);
    396 
    397 		res->addUniform(Uniform((string("u_var") + nameSuffix).c_str(), glu::VarType(structType)));
    398 
    399 		return res;
    400 	}
    401 
    402 	static UniformCollection* multipleBasic (const char* const nameSuffix = "")
    403 	{
    404 		static const glu::DataType	types[]	= { glu::TYPE_FLOAT, glu::TYPE_INT_VEC3, glu::TYPE_FLOAT_MAT3, glu::TYPE_BOOL_VEC2 };
    405 		UniformCollection* const	res		= new UniformCollection;
    406 
    407 		for (int i = 0; i < DE_LENGTH_OF_ARRAY(types); i++)
    408 		{
    409 			UniformCollection* const sub = basic(types[i], ("_" + de::toString(i) + nameSuffix).c_str());
    410 			sub->moveContents(*res);
    411 			delete sub;
    412 		}
    413 
    414 		return res;
    415 	}
    416 
    417 	static UniformCollection* multipleBasicArray (const char* const nameSuffix = "")
    418 	{
    419 		static const glu::DataType	types[]	= { glu::TYPE_FLOAT, glu::TYPE_INT_VEC3, glu::TYPE_BOOL_VEC2 };
    420 		UniformCollection* const	res		= new UniformCollection;
    421 
    422 		for (int i = 0; i < DE_LENGTH_OF_ARRAY(types); i++)
    423 		{
    424 			UniformCollection* const sub = basicArray(types[i], ("_" + de::toString(i) + nameSuffix).c_str());
    425 			sub->moveContents(*res);
    426 			delete sub;
    427 		}
    428 
    429 		return res;
    430 	}
    431 
    432 	static UniformCollection* multipleNestedArraysStructs (const char* const nameSuffix = "")
    433 	{
    434 		static const glu::DataType	types0[]	= { glu::TYPE_FLOAT,		glu::TYPE_INT,		glu::TYPE_BOOL_VEC4 };
    435 		static const glu::DataType	types1[]	= { glu::TYPE_FLOAT_VEC4,	glu::TYPE_INT_VEC4,	glu::TYPE_BOOL };
    436 		UniformCollection* const	res			= new UniformCollection;
    437 
    438 		DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(types0) == DE_LENGTH_OF_ARRAY(types1));
    439 
    440 		for (int i = 0; i < DE_LENGTH_OF_ARRAY(types0); i++)
    441 		{
    442 			UniformCollection* const sub = nestedArraysStructs(types0[i], types1[i], ("_" + de::toString(i) + nameSuffix).c_str());
    443 			sub->moveContents(*res);
    444 			delete sub;
    445 		}
    446 
    447 		return res;
    448 	}
    449 
    450 	static UniformCollection* random (const deUint32 seed)
    451 	{
    452 		Random						rnd			(seed);
    453 		const int					numUniforms	= rnd.getInt(1, 5);
    454 		int							structIdx	= 0;
    455 		UniformCollection* const	res			= new UniformCollection;
    456 
    457 		for (int i = 0; i < numUniforms; i++)
    458 		{
    459 			vector<const StructType*>	structTypes;
    460 			Uniform						uniform(("u_var" + de::toString(i)).c_str(), glu::VarType());
    461 
    462 			// \note Discard uniforms that would cause number of samplers to exceed MAX_NUM_SAMPLER_UNIFORMS.
    463 			do
    464 			{
    465 				for (int j = 0; j < (int)structTypes.size(); j++)
    466 					delete structTypes[j];
    467 				structTypes.clear();
    468 				uniform.type = (("u_var" + de::toString(i)).c_str(), generateRandomType(3, structIdx, structTypes, rnd));
    469 			} while (res->getNumSamplers() + getNumSamplersInType(uniform.type) > MAX_NUM_SAMPLER_UNIFORMS);
    470 
    471 			res->addUniform(uniform);
    472 			for (int j = 0; j < (int)structTypes.size(); j++)
    473 				res->addStructType(structTypes[j]);
    474 		}
    475 
    476 		return res;
    477 	}
    478 
    479 private:
    480 	// \note Copying these would be cumbersome, since deep-copying both m_uniforms and m_structTypes
    481 	// would mean that we'd need to update pointers from uniforms to point to the new structTypes.
    482 	// When the same UniformCollection is needed in several places, a SharedPtr is used instead.
    483 								UniformCollection	(const UniformCollection&); // Not allowed.
    484 	UniformCollection&			operator=			(const UniformCollection&); // Not allowed.
    485 
    486 	vector<Uniform>				m_uniforms;
    487 	vector<const StructType*>	m_structTypes;
    488 };
    489 
    490 }; // anonymous
    491 
    492 static VarValue getSamplerFillValue (const VarValue& sampler)
    493 {
    494 	DE_ASSERT(glu::isDataTypeSampler(sampler.type));
    495 
    496 	VarValue result;
    497 	result.type = glu::TYPE_FLOAT_VEC4;
    498 
    499 	for (int i = 0; i < 4; i++)
    500 		result.val.floatV[i] = sampler.val.samplerV.fillColor[i];
    501 
    502 	return result;
    503 }
    504 
    505 static VarValue getSamplerUnitValue (const VarValue& sampler)
    506 {
    507 	DE_ASSERT(glu::isDataTypeSampler(sampler.type));
    508 
    509 	VarValue result;
    510 	result.type = glu::TYPE_INT;
    511 	result.val.intV[0] = sampler.val.samplerV.unit;
    512 
    513 	return result;
    514 }
    515 
    516 static string shaderVarValueStr (const VarValue& value)
    517 {
    518 	const int			numElems = glu::getDataTypeScalarSize(value.type);
    519 	std::ostringstream	result;
    520 
    521 	if (numElems > 1)
    522 		result << glu::getDataTypeName(value.type) << "(";
    523 
    524 	for (int i = 0; i < numElems; i++)
    525 	{
    526 		if (i > 0)
    527 			result << ", ";
    528 
    529 		if (glu::isDataTypeFloatOrVec(value.type) || glu::isDataTypeMatrix(value.type))
    530 			result << de::floatToString(value.val.floatV[i], 2);
    531 		else if (glu::isDataTypeIntOrIVec((value.type)))
    532 			result << de::toString(value.val.intV[i]);
    533 		else if (glu::isDataTypeBoolOrBVec((value.type)))
    534 			result << (value.val.boolV[i] ? "true" : "false");
    535 		else if (glu::isDataTypeSampler((value.type)))
    536 			result << shaderVarValueStr(getSamplerFillValue(value));
    537 		else
    538 			DE_ASSERT(false);
    539 	}
    540 
    541 	if (numElems > 1)
    542 		result << ")";
    543 
    544 	return result.str();
    545 }
    546 
    547 static string apiVarValueStr (const VarValue& value)
    548 {
    549 	const int			numElems = glu::getDataTypeScalarSize(value.type);
    550 	std::ostringstream	result;
    551 
    552 	if (numElems > 1)
    553 		result << "(";
    554 
    555 	for (int i = 0; i < numElems; i++)
    556 	{
    557 		if (i > 0)
    558 			result << ", ";
    559 
    560 		if (glu::isDataTypeFloatOrVec(value.type) || glu::isDataTypeMatrix(value.type))
    561 			result << de::floatToString(value.val.floatV[i], 2);
    562 		else if (glu::isDataTypeIntOrIVec((value.type)))
    563 			result << de::toString(value.val.intV[i]);
    564 		else if (glu::isDataTypeBoolOrBVec((value.type)))
    565 			result << (value.val.boolV[i] ? "true" : "false");
    566 		else if (glu::isDataTypeSampler((value.type)))
    567 			result << value.val.samplerV.unit;
    568 		else
    569 			DE_ASSERT(false);
    570 	}
    571 
    572 	if (numElems > 1)
    573 		result << ")";
    574 
    575 	return result.str();
    576 }
    577 
    578 static VarValue generateRandomVarValue (const glu::DataType type, Random& rnd, int samplerUnit = -1 /* Used if type is a sampler type. \note Samplers' unit numbers are not randomized. */)
    579 {
    580 	const int	numElems = glu::getDataTypeScalarSize(type);
    581 	VarValue	result;
    582 	result.type = type;
    583 
    584 	DE_ASSERT((samplerUnit >= 0) == (glu::isDataTypeSampler(type)));
    585 
    586 	if (glu::isDataTypeFloatOrVec(type) || glu::isDataTypeMatrix(type))
    587 	{
    588 		for (int i = 0; i < numElems; i++)
    589 			result.val.floatV[i] = rnd.getFloat(-10.0f, 10.0f);
    590 	}
    591 	else if (glu::isDataTypeIntOrIVec(type))
    592 	{
    593 		for (int i = 0; i < numElems; i++)
    594 			result.val.intV[i] = rnd.getInt(-10, 10);
    595 	}
    596 	else if (glu::isDataTypeBoolOrBVec(type))
    597 	{
    598 		for (int i = 0; i < numElems; i++)
    599 			result.val.boolV[i] = rnd.getBool();
    600 	}
    601 	else if (glu::isDataTypeSampler(type))
    602 	{
    603 		result.val.samplerV.unit = samplerUnit;
    604 
    605 		for (int i = 0; i < 4; i++)
    606 			result.val.samplerV.fillColor[i] = rnd.getFloat(0.0f, 1.0f);
    607 	}
    608 	else
    609 		DE_ASSERT(false);
    610 
    611 	return result;
    612 }
    613 
    614 static VarValue generateZeroVarValue (const glu::DataType type)
    615 {
    616 	const int	numElems = glu::getDataTypeScalarSize(type);
    617 	VarValue	result;
    618 	result.type = type;
    619 
    620 	if (glu::isDataTypeFloatOrVec(type) || glu::isDataTypeMatrix(type))
    621 	{
    622 		for (int i = 0; i < numElems; i++)
    623 			result.val.floatV[i] = 0.0f;
    624 	}
    625 	else if (glu::isDataTypeIntOrIVec(type))
    626 	{
    627 		for (int i = 0; i < numElems; i++)
    628 			result.val.intV[i] = 0;
    629 	}
    630 	else if (glu::isDataTypeBoolOrBVec(type))
    631 	{
    632 		for (int i = 0; i < numElems; i++)
    633 			result.val.boolV[i] = false;
    634 	}
    635 	else if (glu::isDataTypeSampler(type))
    636 	{
    637 		result.val.samplerV.unit = 0;
    638 
    639 		for (int i = 0; i < 4; i++)
    640 			result.val.samplerV.fillColor[i] = 0.12f * (float)i;
    641 	}
    642 	else
    643 		DE_ASSERT(false);
    644 
    645 	return result;
    646 }
    647 
    648 static bool apiVarValueEquals (const VarValue& a, const VarValue& b)
    649 {
    650 	const int		size			= glu::getDataTypeScalarSize(a.type);
    651 	const float		floatThreshold	= 0.05f;
    652 
    653 	DE_ASSERT(a.type == b.type);
    654 
    655 	if (glu::isDataTypeFloatOrVec(a.type) || glu::isDataTypeMatrix(a.type))
    656 	{
    657 		for (int i = 0; i < size; i++)
    658 			if (de::abs(a.val.floatV[i] - b.val.floatV[i]) >= floatThreshold)
    659 				return false;
    660 	}
    661 	else if (glu::isDataTypeIntOrIVec(a.type))
    662 	{
    663 		for (int i = 0; i < size; i++)
    664 			if (a.val.intV[i] != b.val.intV[i])
    665 				return false;
    666 	}
    667 	else if (glu::isDataTypeBoolOrBVec(a.type))
    668 	{
    669 		for (int i = 0; i < size; i++)
    670 			if (a.val.boolV[i] != b.val.boolV[i])
    671 				return false;
    672 	}
    673 	else if (glu::isDataTypeSampler(a.type))
    674 	{
    675 		if (a.val.samplerV.unit != b.val.samplerV.unit)
    676 			return false;
    677 	}
    678 	else
    679 		DE_ASSERT(false);
    680 
    681 	return true;
    682 }
    683 
    684 static VarValue getRandomBoolRepresentation (const VarValue& boolValue, const glu::DataType targetScalarType, Random& rnd)
    685 {
    686 	DE_ASSERT(glu::isDataTypeBoolOrBVec(boolValue.type));
    687 
    688 	const int				size		= glu::getDataTypeScalarSize(boolValue.type);
    689 	const glu::DataType		targetType	= size == 1 ? targetScalarType : glu::getDataTypeVector(targetScalarType, size);
    690 	VarValue				result;
    691 	result.type = targetType;
    692 
    693 	switch (targetScalarType)
    694 	{
    695 		case glu::TYPE_INT:
    696 			for (int i = 0; i < size; i++)
    697 			{
    698 				if (boolValue.val.boolV[i])
    699 				{
    700 					result.val.intV[i] = rnd.getInt(-10, 10);
    701 					if (result.val.intV[i] == 0)
    702 						result.val.intV[i] = 1;
    703 				}
    704 				else
    705 					result.val.intV[i] = 0;
    706 			}
    707 			break;
    708 
    709 		case glu::TYPE_FLOAT:
    710 			for (int i = 0; i < size; i++)
    711 			{
    712 				if (boolValue.val.boolV[i])
    713 				{
    714 					result.val.floatV[i] = rnd.getFloat(-10.0f, 10.0f);
    715 					if (result.val.floatV[i] == 0.0f)
    716 						result.val.floatV[i] = 1.0f;
    717 				}
    718 				else
    719 					result.val.floatV[i] = 0;
    720 			}
    721 			break;
    722 
    723 		default:
    724 			DE_ASSERT(false);
    725 	}
    726 
    727 	return result;
    728 }
    729 
    730 static const char* getCaseShaderTypeName (const CaseShaderType type)
    731 {
    732 	switch (type)
    733 	{
    734 		case CASESHADERTYPE_VERTEX:		return "vertex";
    735 		case CASESHADERTYPE_FRAGMENT:	return "fragment";
    736 		case CASESHADERTYPE_BOTH:		return "both";
    737 		default:
    738 			DE_ASSERT(false);
    739 			return DE_NULL;
    740 	}
    741 }
    742 
    743 static CaseShaderType randomCaseShaderType (const deUint32 seed)
    744 {
    745 	return (CaseShaderType)Random(seed).getInt(0, CASESHADERTYPE_LAST-1);
    746 }
    747 
    748 class UniformCase : public TestCase, protected glu::CallLogWrapper
    749 {
    750 public:
    751 	enum Feature
    752 	{
    753 		// ARRAYUSAGE_ONLY_MIDDLE_INDEX: only middle index of each array is used in shader. If not given, use all indices.
    754 		FEATURE_ARRAYUSAGE_ONLY_MIDDLE_INDEX	= 1<<0,
    755 
    756 		// UNIFORMFUNC_VALUE: use pass-by-value versions of uniform assignment funcs, e.g. glUniform1f(), where possible. If not given, use pass-by-pointer versions.
    757 		FEATURE_UNIFORMFUNC_VALUE				= 1<<1,
    758 
    759 		// ARRAYASSIGN: how basic-type arrays are assigned with glUniform*(). If none given, assign each element of an array separately.
    760 		FEATURE_ARRAYASSIGN_FULL				= 1<<2, //!< Assign all elements of an array with one glUniform*().
    761 		FEATURE_ARRAYASSIGN_BLOCKS_OF_TWO		= 1<<3, //!< Assign two elements per one glUniform*().
    762 
    763 		// UNIFORMUSAGE_EVERY_OTHER: use about half of the uniforms. If not given, use all uniforms (except that some array indices may be omitted according to ARRAYUSAGE).
    764 		FEATURE_UNIFORMUSAGE_EVERY_OTHER		= 1<<4,
    765 
    766 		// BOOLEANAPITYPE: type used to pass booleans to and from GL api. If none given, use float.
    767 		FEATURE_BOOLEANAPITYPE_INT				= 1<<5,
    768 
    769 		// UNIFORMVALUE_ZERO: use zero-valued uniforms. If not given, use random uniform values.
    770 		FEATURE_UNIFORMVALUE_ZERO				= 1<<6,
    771 
    772 		// ARRAY_FIRST_ELEM_NAME_NO_INDEX: in certain API functions, when referring to the first element of an array, use just the array name without [0] at the end.
    773 		FEATURE_ARRAY_FIRST_ELEM_NAME_NO_INDEX	= 1<<7
    774 	};
    775 
    776 								UniformCase		(Context& context, const char* name, const char* description, CaseShaderType caseType, const SharedPtr<const UniformCollection>& uniformCollection);
    777 								UniformCase		(Context& context, const char* name, const char* description, CaseShaderType caseType, const SharedPtr<const UniformCollection>& uniformCollection, deUint32 features);
    778 								UniformCase		(Context& context, const char* name, const char* description, deUint32 seed); // \note Randomizes caseType, uniformCollection and features.
    779 	virtual						~UniformCase	(void);
    780 
    781 	virtual void				init			(void);
    782 	virtual void				deinit			(void);
    783 
    784 	IterateResult				iterate			(void);
    785 
    786 protected:
    787 	// A basic uniform is a uniform (possibly struct or array member) whose type is a basic type (e.g. float, ivec4, sampler2d).
    788 	struct BasicUniform
    789 	{
    790 		string			name;
    791 		glu::DataType	type;
    792 		bool			isUsedInShader;
    793 		VarValue		finalValue;	//!< The value we ultimately want to set for this uniform.
    794 
    795 		string			rootName;	//!< If this is a member of a basic-typed array, rootName is the name of that array with "[0]" appended. Otherwise it equals name.
    796 		int				elemNdx;	//!< If this is a member of a basic-typed array, elemNdx is the index in that array. Otherwise -1.
    797 		int				rootSize;	//!< If this is a member of a basic-typed array, rootSize is the size of that array. Otherwise 1.
    798 
    799 		BasicUniform (const char* const		name_,
    800 					  const glu::DataType	type_,
    801 					  const bool			isUsedInShader_,
    802 					  const VarValue&		finalValue_,
    803 					  const char* const		rootName_	= DE_NULL,
    804 					  const int				elemNdx_	= -1,
    805 					  const int				rootSize_	= 1)
    806 					  : name			(name_)
    807 					  , type			(type_)
    808 					  , isUsedInShader	(isUsedInShader_)
    809 					  , finalValue		(finalValue_)
    810 					  , rootName		(rootName_ == DE_NULL ? name_ : rootName_)
    811 					  , elemNdx			(elemNdx_)
    812 					  , rootSize		(rootSize_)
    813 					 {
    814 					 }
    815 
    816 		static vector<BasicUniform>::const_iterator findWithName (const vector<BasicUniform>& vec, const char* const name)
    817 		{
    818 			for (vector<BasicUniform>::const_iterator it = vec.begin(); it != vec.end(); it++)
    819 			{
    820 				if (it->name == name)
    821 					return it;
    822 			}
    823 			return vec.end();
    824 		}
    825 	};
    826 
    827 	// Reference values for info that is expected to be reported by glGetActiveUniform().
    828 	struct BasicUniformReportRef
    829 	{
    830 		string			name;
    831 		// \note minSize and maxSize are for arrays and can be distinct since implementations are allowed, but not required, to trim the inactive end indices of arrays.
    832 		int				minSize;
    833 		int				maxSize;
    834 		glu::DataType	type;
    835 		bool			isUsedInShader;
    836 
    837 		BasicUniformReportRef (const char* const name_, const int minS, const int maxS, const glu::DataType type_, const bool used)
    838 			: name(name_), minSize(minS), maxSize(maxS), type(type_), isUsedInShader(used) { DE_ASSERT(minSize <= maxSize); }
    839 		BasicUniformReportRef (const char* const name_, const glu::DataType type_, const bool used)
    840 			: name(name_), minSize(1), maxSize(1), type(type_), isUsedInShader(used) {}
    841 	};
    842 
    843 	// Info that is actually reported by glGetActiveUniform().
    844 	struct BasicUniformReportGL
    845 	{
    846 		string			name;
    847 		int				nameLength;
    848 		int				size;
    849 		glu::DataType	type;
    850 
    851 		int				index;
    852 
    853 		BasicUniformReportGL (const char* const name_, const int nameLength_, const int size_, const glu::DataType type_, const int index_)
    854 			: name(name_), nameLength(nameLength_), size(size_), type(type_), index(index_) {}
    855 
    856 		static vector<BasicUniformReportGL>::const_iterator findWithName (const vector<BasicUniformReportGL>& vec, const char* const name)
    857 		{
    858 			for (vector<BasicUniformReportGL>::const_iterator it = vec.begin(); it != vec.end(); it++)
    859 			{
    860 				if (it->name == name)
    861 					return it;
    862 			}
    863 			return vec.end();
    864 		}
    865 	};
    866 
    867 	// Query info with glGetActiveUniform() and check validity.
    868 	bool						getActiveUniforms						(vector<BasicUniformReportGL>& dst, const vector<BasicUniformReportRef>& ref, deUint32 programGL);
    869 	// Get uniform values with glGetUniform*() and put to valuesDst. Uniforms that get -1 from glGetUniformLocation() get glu::TYPE_INVALID.
    870 	bool						getUniforms								(vector<VarValue>& valuesDst, const vector<BasicUniform>& basicUniforms, deUint32 programGL);
    871 	// Check that every uniform has the default (zero) value.
    872 	bool						checkUniformDefaultValues				(const vector<VarValue>& values, const vector<BasicUniform>& basicUniforms);
    873 	// Assign the basicUniforms[].finalValue values for uniforms. \note rnd parameter is for booleans (true can be any nonzero value).
    874 	void						assignUniforms							(const vector<BasicUniform>& basicUniforms, deUint32 programGL, Random& rnd);
    875 	// Compare the uniform values given in values (obtained with glGetUniform*()) with the basicUniform.finalValue values.
    876 	bool						compareUniformValues					(const vector<VarValue>& values, const vector<BasicUniform>& basicUniforms);
    877 	// Render and check that all pixels are white (i.e. all uniform comparisons passed).
    878 	bool						renderTest								(const vector<BasicUniform>& basicUniforms, const ShaderProgram& program, Random& rnd);
    879 
    880 	virtual bool				test									(const vector<BasicUniform>& basicUniforms, const vector<BasicUniformReportRef>& basicUniformReportsRef, const ShaderProgram& program, Random& rnd) = 0;
    881 
    882 	const deUint32								m_features;
    883 	const SharedPtr<const UniformCollection>	m_uniformCollection;
    884 
    885 private:
    886 	static deUint32				randomFeatures							(deUint32 seed);
    887 
    888 	// Generates the basic uniforms, based on the uniform with name varName and type varType, in the same manner as are expected
    889 	// to be returned by glGetActiveUniform(), e.g. generates a name like var[0] for arrays, and recursively generates struct member names.
    890 	void						generateBasicUniforms					(vector<BasicUniform>&				basicUniformsDst,
    891 																		 vector<BasicUniformReportRef>&		basicUniformReportsDst,
    892 																		 const glu::VarType&				varType,
    893 																		 const char*						varName,
    894 																		 bool								isParentActive,
    895 																		 int&								samplerUnitCounter,
    896 																		 Random&							rnd) const;
    897 
    898 	void						writeUniformDefinitions					(std::ostringstream& dst) const;
    899 	void						writeUniformCompareExpr					(std::ostringstream& dst, const BasicUniform& uniform) const;
    900 	void						writeUniformComparisons					(std::ostringstream& dst, const vector<BasicUniform>& basicUniforms, const char* variableName) const;
    901 
    902 	string						generateVertexSource					(const vector<BasicUniform>& basicUniforms) const;
    903 	string						generateFragmentSource					(const vector<BasicUniform>& basicUniforms) const;
    904 
    905 	void						setupTexture							(const VarValue& value);
    906 
    907 	const CaseShaderType						m_caseShaderType;
    908 
    909 	vector<glu::Texture2D*>						m_textures2d;
    910 	vector<glu::TextureCube*>					m_texturesCube;
    911 	vector<deUint32>							m_filledTextureUnits;
    912 };
    913 
    914 deUint32 UniformCase::randomFeatures (const deUint32 seed)
    915 {
    916 	static const deUint32 arrayUsageChoices[]		= { 0, FEATURE_ARRAYUSAGE_ONLY_MIDDLE_INDEX										};
    917 	static const deUint32 uniformFuncChoices[]		= { 0, FEATURE_UNIFORMFUNC_VALUE												};
    918 	static const deUint32 arrayAssignChoices[]		= { 0, FEATURE_ARRAYASSIGN_FULL,			FEATURE_ARRAYASSIGN_BLOCKS_OF_TWO	};
    919 	static const deUint32 uniformUsageChoices[]		= { 0, FEATURE_UNIFORMUSAGE_EVERY_OTHER											};
    920 	static const deUint32 booleanApiTypeChoices[]	= { 0, FEATURE_BOOLEANAPITYPE_INT												};
    921 	static const deUint32 uniformValueChoices[]		= { 0, FEATURE_UNIFORMVALUE_ZERO												};
    922 
    923 	Random rnd(seed);
    924 
    925 	deUint32 result = 0;
    926 
    927 #define ARRAY_CHOICE(ARR) (ARR[rnd.getInt(0, DE_LENGTH_OF_ARRAY(ARR)-1)])
    928 
    929 	result |= ARRAY_CHOICE(arrayUsageChoices);
    930 	result |= ARRAY_CHOICE(uniformFuncChoices);
    931 	result |= ARRAY_CHOICE(arrayAssignChoices);
    932 	result |= ARRAY_CHOICE(uniformUsageChoices);
    933 	result |= ARRAY_CHOICE(booleanApiTypeChoices);
    934 	result |= ARRAY_CHOICE(uniformValueChoices);
    935 
    936 #undef ARRAY_CHOICE
    937 
    938 	return result;
    939 }
    940 
    941 UniformCase::UniformCase (Context& context, const char* const name, const char* const description, const CaseShaderType caseShaderType, const SharedPtr<const UniformCollection>& uniformCollection, const deUint32 features)
    942 	: TestCase				(context, name, description)
    943 	, CallLogWrapper		(context.getRenderContext().getFunctions(), m_testCtx.getLog())
    944 	, m_features			(features)
    945 	, m_uniformCollection	(uniformCollection)
    946 	, m_caseShaderType		(caseShaderType)
    947 {
    948 }
    949 
    950 UniformCase::UniformCase (Context& context, const char* const name, const char* const description, const CaseShaderType caseShaderType, const SharedPtr<const UniformCollection>& uniformCollection)
    951 	: TestCase				(context, name, description)
    952 	, CallLogWrapper		(context.getRenderContext().getFunctions(), m_testCtx.getLog())
    953 	, m_features			(0)
    954 	, m_uniformCollection	(uniformCollection)
    955 	, m_caseShaderType		(caseShaderType)
    956 {
    957 }
    958 
    959 UniformCase::UniformCase (Context& context, const char* name, const char* description, const deUint32 seed)
    960 	: TestCase				(context, name, description)
    961 	, CallLogWrapper		(context.getRenderContext().getFunctions(), m_testCtx.getLog())
    962 	, m_features			(randomFeatures(seed))
    963 	, m_uniformCollection	(UniformCollection::random(seed))
    964 	, m_caseShaderType		(randomCaseShaderType(seed))
    965 {
    966 }
    967 
    968 void UniformCase::init (void)
    969 {
    970 	{
    971 		const glw::Functions&	funcs						= m_context.getRenderContext().getFunctions();
    972 		const int				numSamplerUniforms			= m_uniformCollection->getNumSamplers();
    973 		const int				vertexTexUnitsRequired		= m_caseShaderType != CASESHADERTYPE_FRAGMENT ? numSamplerUniforms : 0;
    974 		const int				fragmentTexUnitsRequired	= m_caseShaderType != CASESHADERTYPE_VERTEX ? numSamplerUniforms : 0;
    975 		const int				combinedTexUnitsRequired	= vertexTexUnitsRequired + fragmentTexUnitsRequired;
    976 		const int				vertexTexUnitsSupported		= getGLInt(funcs, GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS);
    977 		const int				fragmentTexUnitsSupported	= getGLInt(funcs, GL_MAX_TEXTURE_IMAGE_UNITS);
    978 		const int				combinedTexUnitsSupported	= getGLInt(funcs, GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS);
    979 
    980 		DE_ASSERT(numSamplerUniforms <= MAX_NUM_SAMPLER_UNIFORMS);
    981 
    982 		if (vertexTexUnitsRequired > vertexTexUnitsSupported)
    983 			throw tcu::NotSupportedError(de::toString(vertexTexUnitsRequired) + " vertex texture units required, " + de::toString(vertexTexUnitsSupported) + " supported");
    984 		if (fragmentTexUnitsRequired > fragmentTexUnitsSupported)
    985 			throw tcu::NotSupportedError(de::toString(fragmentTexUnitsRequired) + " fragment texture units required, " + de::toString(fragmentTexUnitsSupported) + " supported");
    986 		if (combinedTexUnitsRequired > combinedTexUnitsSupported)
    987 			throw tcu::NotSupportedError(de::toString(combinedTexUnitsRequired) + " combined texture units required, " + de::toString(combinedTexUnitsSupported) + " supported");
    988 	}
    989 
    990 	enableLogging(true);
    991 }
    992 
    993 void UniformCase::deinit (void)
    994 {
    995 	for (int i = 0; i < (int)m_textures2d.size(); i++)
    996 		delete m_textures2d[i];
    997 	m_textures2d.clear();
    998 
    999 	for (int i = 0; i < (int)m_texturesCube.size(); i++)
   1000 		delete m_texturesCube[i];
   1001 	m_texturesCube.clear();
   1002 
   1003 	m_filledTextureUnits.clear();
   1004 }
   1005 
   1006 UniformCase::~UniformCase (void)
   1007 {
   1008 	UniformCase::deinit();
   1009 }
   1010 
   1011 void UniformCase::generateBasicUniforms (vector<BasicUniform>& basicUniformsDst, vector<BasicUniformReportRef>& basicUniformReportsDst, const glu::VarType& varType, const char* const varName, const bool isParentActive, int& samplerUnitCounter, Random& rnd) const
   1012 {
   1013 	if (varType.isBasicType())
   1014 	{
   1015 		const bool				isActive	= isParentActive && (m_features & FEATURE_UNIFORMUSAGE_EVERY_OTHER ? basicUniformsDst.size() % 2 == 0 : true);
   1016 		const glu::DataType		type		= varType.getBasicType();
   1017 		const VarValue			value		= m_features & FEATURE_UNIFORMVALUE_ZERO	? generateZeroVarValue(type)
   1018 											: glu::isDataTypeSampler(type)				? generateRandomVarValue(type, rnd, samplerUnitCounter++)
   1019 											: generateRandomVarValue(varType.getBasicType(), rnd);
   1020 
   1021 		basicUniformsDst.push_back(BasicUniform(varName, varType.getBasicType(), isActive, value));
   1022 		basicUniformReportsDst.push_back(BasicUniformReportRef(varName, varType.getBasicType(), isActive));
   1023 	}
   1024 	else if (varType.isArrayType())
   1025 	{
   1026 		const int		size			= varType.getArraySize();
   1027 		const string	arrayRootName	= string("") + varName + "[0]";
   1028 		vector<bool>	isElemActive;
   1029 
   1030 		for (int elemNdx = 0; elemNdx < varType.getArraySize(); elemNdx++)
   1031 		{
   1032 			const string	indexedName		= string("") + varName + "[" + de::toString(elemNdx) + "]";
   1033 			const bool		isCurElemActive	= isParentActive																						&&
   1034 											  (m_features & FEATURE_UNIFORMUSAGE_EVERY_OTHER			? basicUniformsDst.size() % 2 == 0	: true)	&&
   1035 											  (m_features & FEATURE_ARRAYUSAGE_ONLY_MIDDLE_INDEX		? elemNdx == size/2					: true);
   1036 
   1037 			isElemActive.push_back(isCurElemActive);
   1038 
   1039 			if (varType.getElementType().isBasicType())
   1040 			{
   1041 				// \note We don't want separate entries in basicUniformReportsDst for elements of basic-type arrays.
   1042 				const glu::DataType	elemBasicType	= varType.getElementType().getBasicType();
   1043 				const VarValue		value			= m_features & FEATURE_UNIFORMVALUE_ZERO	? generateZeroVarValue(elemBasicType)
   1044 													: glu::isDataTypeSampler(elemBasicType)		? generateRandomVarValue(elemBasicType, rnd, samplerUnitCounter++)
   1045 													: generateRandomVarValue(elemBasicType, rnd);
   1046 
   1047 				basicUniformsDst.push_back(BasicUniform(indexedName.c_str(), elemBasicType, isCurElemActive, value, arrayRootName.c_str(), elemNdx, size));
   1048 			}
   1049 			else
   1050 				generateBasicUniforms(basicUniformsDst, basicUniformReportsDst, varType.getElementType(), indexedName.c_str(), isCurElemActive, samplerUnitCounter, rnd);
   1051 		}
   1052 
   1053 		if (varType.getElementType().isBasicType())
   1054 		{
   1055 			int minSize;
   1056 			for (minSize = varType.getArraySize(); minSize > 0 && !isElemActive[minSize-1]; minSize--);
   1057 
   1058 			basicUniformReportsDst.push_back(BasicUniformReportRef(arrayRootName.c_str(), minSize, size, varType.getElementType().getBasicType(), isParentActive && minSize > 0));
   1059 		}
   1060 	}
   1061 	else
   1062 	{
   1063 		DE_ASSERT(varType.isStructType());
   1064 
   1065 		const StructType& structType = *varType.getStructPtr();
   1066 
   1067 		for (int i = 0; i < structType.getNumMembers(); i++)
   1068 		{
   1069 			const glu::StructMember&	member			= structType.getMember(i);
   1070 			const string				memberFullName	= string("") + varName + "." + member.getName();
   1071 
   1072 			generateBasicUniforms(basicUniformsDst, basicUniformReportsDst, member.getType(), memberFullName.c_str(), isParentActive, samplerUnitCounter, rnd);
   1073 		}
   1074 	}
   1075 }
   1076 
   1077 void UniformCase::writeUniformDefinitions (std::ostringstream& dst) const
   1078 {
   1079 	for (int i = 0; i < (int)m_uniformCollection->getNumStructTypes(); i++)
   1080 		dst << glu::declare(m_uniformCollection->getStructType(i)) << ";\n";
   1081 
   1082 	for (int i = 0; i < (int)m_uniformCollection->getNumUniforms(); i++)
   1083 		dst << "uniform " << glu::declare(m_uniformCollection->getUniform(i).type, m_uniformCollection->getUniform(i).name.c_str()) << ";\n";
   1084 
   1085 	dst << "\n";
   1086 
   1087 	{
   1088 		static const struct
   1089 		{
   1090 			dataTypePredicate	requiringTypes[2];
   1091 			const char*			definition;
   1092 		} compareFuncs[] =
   1093 		{
   1094 			{ { glu::isDataTypeFloatOrVec,				glu::isDataTypeMatrix				}, "mediump float compare_float    (mediump float a, mediump float b)  { return abs(a - b) < 0.05 ? 1.0 : 0.0; }"																		},
   1095 			{ { dataTypeEquals<glu::TYPE_FLOAT_VEC2>,	dataTypeIsMatrixWithNRows<2>		}, "mediump float compare_vec2     (mediump vec2 a, mediump vec2 b)    { return compare_float(a.x, b.x)*compare_float(a.y, b.y); }"														},
   1096 			{ { dataTypeEquals<glu::TYPE_FLOAT_VEC3>,	dataTypeIsMatrixWithNRows<3>		}, "mediump float compare_vec3     (mediump vec3 a, mediump vec3 b)    { return compare_float(a.x, b.x)*compare_float(a.y, b.y)*compare_float(a.z, b.z); }"								},
   1097 			{ { dataTypeEquals<glu::TYPE_FLOAT_VEC4>,	dataTypeIsMatrixWithNRows<4>		}, "mediump float compare_vec4     (mediump vec4 a, mediump vec4 b)    { return compare_float(a.x, b.x)*compare_float(a.y, b.y)*compare_float(a.z, b.z)*compare_float(a.w, b.w); }"		},
   1098 			{ { dataTypeEquals<glu::TYPE_FLOAT_MAT2>,	dataTypeEquals<glu::TYPE_INVALID>	}, "mediump float compare_mat2     (mediump mat2 a, mediump mat2 b)    { return compare_vec2(a[0], b[0])*compare_vec2(a[1], b[1]); }"													},
   1099 			{ { dataTypeEquals<glu::TYPE_FLOAT_MAT3>,	dataTypeEquals<glu::TYPE_INVALID>	}, "mediump float compare_mat3     (mediump mat3 a, mediump mat3 b)    { return compare_vec3(a[0], b[0])*compare_vec3(a[1], b[1])*compare_vec3(a[2], b[2]); }"							},
   1100 			{ { dataTypeEquals<glu::TYPE_FLOAT_MAT4>,	dataTypeEquals<glu::TYPE_INVALID>	}, "mediump float compare_mat4     (mediump mat4 a, mediump mat4 b)    { return compare_vec4(a[0], b[0])*compare_vec4(a[1], b[1])*compare_vec4(a[2], b[2])*compare_vec4(a[3], b[3]); }"	},
   1101 			{ { dataTypeEquals<glu::TYPE_INT>,			dataTypeEquals<glu::TYPE_INVALID>	}, "mediump float compare_int      (mediump int a, mediump int b)      { return a == b ? 1.0 : 0.0; }"																					},
   1102 			{ { dataTypeEquals<glu::TYPE_INT_VEC2>,		dataTypeEquals<glu::TYPE_INVALID>	}, "mediump float compare_ivec2    (mediump ivec2 a, mediump ivec2 b)  { return a == b ? 1.0 : 0.0; }"																					},
   1103 			{ { dataTypeEquals<glu::TYPE_INT_VEC3>,		dataTypeEquals<glu::TYPE_INVALID>	}, "mediump float compare_ivec3    (mediump ivec3 a, mediump ivec3 b)  { return a == b ? 1.0 : 0.0; }"																					},
   1104 			{ { dataTypeEquals<glu::TYPE_INT_VEC4>,		dataTypeEquals<glu::TYPE_INVALID>	}, "mediump float compare_ivec4    (mediump ivec4 a, mediump ivec4 b)  { return a == b ? 1.0 : 0.0; }"																					},
   1105 			{ { dataTypeEquals<glu::TYPE_BOOL>,			dataTypeEquals<glu::TYPE_INVALID>	}, "mediump float compare_bool     (bool a, bool b)                    { return a == b ? 1.0 : 0.0; }"																					},
   1106 			{ { dataTypeEquals<glu::TYPE_BOOL_VEC2>,	dataTypeEquals<glu::TYPE_INVALID>	}, "mediump float compare_bvec2    (bvec2 a, bvec2 b)                  { return a == b ? 1.0 : 0.0; }"																					},
   1107 			{ { dataTypeEquals<glu::TYPE_BOOL_VEC3>,	dataTypeEquals<glu::TYPE_INVALID>	}, "mediump float compare_bvec3    (bvec3 a, bvec3 b)                  { return a == b ? 1.0 : 0.0; }"																					},
   1108 			{ { dataTypeEquals<glu::TYPE_BOOL_VEC4>,	dataTypeEquals<glu::TYPE_INVALID>	}, "mediump float compare_bvec4    (bvec4 a, bvec4 b)                  { return a == b ? 1.0 : 0.0; }"																					}
   1109 		};
   1110 
   1111 		const bool containsSamplers = !m_uniformCollection->getSamplerTypes().empty();
   1112 
   1113 		for (int compFuncNdx = 0; compFuncNdx < DE_LENGTH_OF_ARRAY(compareFuncs); compFuncNdx++)
   1114 		{
   1115 			const dataTypePredicate		(&typeReq)[2]			= compareFuncs[compFuncNdx].requiringTypes;
   1116 			const bool					containsTypeSampler		= containsSamplers && (typeReq[0](glu::TYPE_FLOAT_VEC4) || typeReq[1](glu::TYPE_FLOAT_VEC4));
   1117 
   1118 			if (containsTypeSampler || m_uniformCollection->containsMatchingBasicType(typeReq[0]) || m_uniformCollection->containsMatchingBasicType(typeReq[1]))
   1119 				dst << compareFuncs[compFuncNdx].definition << "\n";
   1120 		}
   1121 	}
   1122 }
   1123 
   1124 void UniformCase::writeUniformCompareExpr (std::ostringstream& dst, const BasicUniform& uniform) const
   1125 {
   1126 	if (glu::isDataTypeSampler(uniform.type))
   1127 	{
   1128 		dst << "compare_vec4("
   1129 			<< (uniform.type == glu::TYPE_SAMPLER_2D ? "texture2D" : "textureCube")
   1130 			<< "(" << uniform.name << ", vec" << getSamplerNumLookupDimensions(uniform.type) << "(0.0))";
   1131 	}
   1132 	else
   1133 		dst << "compare_" << glu::getDataTypeName(uniform.type) << "(" << uniform.name;
   1134 
   1135 	dst << ", " << shaderVarValueStr(uniform.finalValue) << ")";
   1136 }
   1137 
   1138 void UniformCase::writeUniformComparisons (std::ostringstream& dst, const vector<BasicUniform>& basicUniforms, const char* const variableName) const
   1139 {
   1140 	for (int i = 0; i < (int)basicUniforms.size(); i++)
   1141 	{
   1142 		const BasicUniform& unif = basicUniforms[i];
   1143 
   1144 		if (unif.isUsedInShader)
   1145 		{
   1146 			dst << "\t" << variableName << " *= ";
   1147 			writeUniformCompareExpr(dst, basicUniforms[i]);
   1148 			dst << ";\n";
   1149 		}
   1150 		else
   1151 			dst << "\t// UNUSED: " << basicUniforms[i].name << "\n";
   1152 	}
   1153 }
   1154 
   1155 string UniformCase::generateVertexSource (const vector<BasicUniform>& basicUniforms) const
   1156 {
   1157 	const bool			isVertexCase = m_caseShaderType == CASESHADERTYPE_VERTEX || m_caseShaderType == CASESHADERTYPE_BOTH;
   1158 	std::ostringstream	result;
   1159 
   1160 	result << "attribute highp vec4 a_position;\n"
   1161 			  "varying mediump float v_vtxOut;\n"
   1162 			  "\n";
   1163 
   1164 	if (isVertexCase)
   1165 		writeUniformDefinitions(result);
   1166 
   1167 	result << "\n"
   1168 			  "void main (void)\n"
   1169 			  "{\n"
   1170 			  "	gl_Position = a_position;\n"
   1171 			  "	v_vtxOut = 1.0;\n";
   1172 
   1173 	if (isVertexCase)
   1174 		writeUniformComparisons(result, basicUniforms, "v_vtxOut");
   1175 
   1176 	result << "}\n";
   1177 
   1178 	return result.str();
   1179 }
   1180 
   1181 string UniformCase::generateFragmentSource (const vector<BasicUniform>& basicUniforms) const
   1182 {
   1183 	const bool			isFragmentCase = m_caseShaderType == CASESHADERTYPE_FRAGMENT || m_caseShaderType == CASESHADERTYPE_BOTH;
   1184 	std::ostringstream	result;
   1185 
   1186 	result << "varying mediump float v_vtxOut;\n"
   1187 			  "\n";
   1188 
   1189 	if (isFragmentCase)
   1190 		writeUniformDefinitions(result);
   1191 
   1192 	result << "\n"
   1193 			  "void main (void)\n"
   1194 			  "{\n"
   1195 			  "	mediump float result = v_vtxOut;\n";
   1196 
   1197 	if (isFragmentCase)
   1198 		writeUniformComparisons(result, basicUniforms, "result");
   1199 
   1200 	result << "	gl_FragColor = vec4(result, result, result, 1.0);\n"
   1201 			  "}\n";
   1202 
   1203 	return result.str();
   1204 }
   1205 
   1206 void UniformCase::setupTexture (const VarValue& value)
   1207 {
   1208 	enableLogging(false);
   1209 
   1210 	const int						width			= 32;
   1211 	const int						height			= 32;
   1212 	const tcu::Vec4					color			= vec4FromPtr(&value.val.samplerV.fillColor[0]);
   1213 
   1214 	if (value.type == glu::TYPE_SAMPLER_2D)
   1215 	{
   1216 		glu::Texture2D* texture		= new glu::Texture2D(m_context.getRenderContext(), GL_RGBA, GL_UNSIGNED_BYTE, width, height);
   1217 		tcu::Texture2D& refTexture	= texture->getRefTexture();
   1218 		m_textures2d.push_back(texture);
   1219 
   1220 		refTexture.allocLevel(0);
   1221 		fillWithColor(refTexture.getLevel(0), color);
   1222 
   1223 		GLU_CHECK_CALL(glActiveTexture(GL_TEXTURE0 + value.val.samplerV.unit));
   1224 		m_filledTextureUnits.push_back(value.val.samplerV.unit);
   1225 		texture->upload();
   1226 		GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
   1227 		GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
   1228 		GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
   1229 		GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
   1230 	}
   1231 	else if (value.type == glu::TYPE_SAMPLER_CUBE)
   1232 	{
   1233 		DE_ASSERT(width == height);
   1234 
   1235 		glu::TextureCube* texture		= new glu::TextureCube(m_context.getRenderContext(), GL_RGBA, GL_UNSIGNED_BYTE, width);
   1236 		tcu::TextureCube& refTexture	= texture->getRefTexture();
   1237 		m_texturesCube.push_back(texture);
   1238 
   1239 		for (int face = 0; face < (int)tcu::CUBEFACE_LAST; face++)
   1240 		{
   1241 			refTexture.allocLevel((tcu::CubeFace)face, 0);
   1242 			fillWithColor(refTexture.getLevelFace(0, (tcu::CubeFace)face), color);
   1243 		}
   1244 
   1245 		GLU_CHECK_CALL(glActiveTexture(GL_TEXTURE0 + value.val.samplerV.unit));
   1246 		m_filledTextureUnits.push_back(value.val.samplerV.unit);
   1247 		texture->upload();
   1248 
   1249 		GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
   1250 		GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
   1251 		GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
   1252 		GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
   1253 
   1254 	}
   1255 	else
   1256 		DE_ASSERT(false);
   1257 
   1258 	enableLogging(true);
   1259 }
   1260 
   1261 bool UniformCase::getActiveUniforms (vector<BasicUniformReportGL>& basicUniformReportsDst, const vector<BasicUniformReportRef>& basicUniformReportsRef, const deUint32 programGL)
   1262 {
   1263 	TestLog&			log						= m_testCtx.getLog();
   1264 	GLint				numActiveUniforms		= 0;
   1265 	GLint				uniformMaxNameLength	= 0;
   1266 	vector<char>		nameBuffer;
   1267 	bool				success					= true;
   1268 
   1269 	GLU_CHECK_CALL(glGetProgramiv(programGL, GL_ACTIVE_UNIFORMS, &numActiveUniforms));
   1270 	log << TestLog::Message << "// Number of active uniforms reported: " << numActiveUniforms << TestLog::EndMessage;
   1271 	GLU_CHECK_CALL(glGetProgramiv(programGL, GL_ACTIVE_UNIFORM_MAX_LENGTH, &uniformMaxNameLength));
   1272 	log << TestLog::Message << "// Maximum uniform name length reported: " << uniformMaxNameLength << TestLog::EndMessage;
   1273 	nameBuffer.resize(uniformMaxNameLength);
   1274 
   1275 	for (int unifNdx = 0; unifNdx < numActiveUniforms; unifNdx++)
   1276 	{
   1277 		GLsizei					reportedNameLength	= 0;
   1278 		GLint					reportedSize		= -1;
   1279 		GLenum					reportedTypeGL		= GL_NONE;
   1280 
   1281 		GLU_CHECK_CALL(glGetActiveUniform(programGL, (GLuint)unifNdx, (GLsizei)uniformMaxNameLength, &reportedNameLength, &reportedSize, &reportedTypeGL, &nameBuffer[0]));
   1282 
   1283 		const glu::DataType		reportedType		= glu::getDataTypeFromGLType(reportedTypeGL);
   1284 		const string			reportedNameStr		(&nameBuffer[0]);
   1285 
   1286 		TCU_CHECK_MSG(reportedType != glu::TYPE_LAST, "Invalid uniform type");
   1287 
   1288 		log << TestLog::Message << "// Got name = " << reportedNameStr << ", name length = " << reportedNameLength << ", size = " << reportedSize << ", type = " << glu::getDataTypeName(reportedType) << TestLog::EndMessage;
   1289 
   1290 		if ((GLsizei)reportedNameStr.length() != reportedNameLength)
   1291 		{
   1292 			log << TestLog::Message << "// FAILURE: wrong name length reported, should be " << reportedNameStr.length() << TestLog::EndMessage;
   1293 			success = false;
   1294 		}
   1295 
   1296 		if (!deStringBeginsWith(reportedNameStr.c_str(), "gl_")) // Ignore built-in uniforms.
   1297 		{
   1298 			int referenceNdx;
   1299 			for (referenceNdx = 0; referenceNdx < (int)basicUniformReportsRef.size(); referenceNdx++)
   1300 			{
   1301 				if (basicUniformReportsRef[referenceNdx].name == reportedNameStr)
   1302 					break;
   1303 			}
   1304 
   1305 			if (referenceNdx >= (int)basicUniformReportsRef.size())
   1306 			{
   1307 				log << TestLog::Message << "// FAILURE: invalid non-built-in uniform name reported" << TestLog::EndMessage;
   1308 				success = false;
   1309 			}
   1310 			else
   1311 			{
   1312 				const BasicUniformReportRef& reference = basicUniformReportsRef[referenceNdx];
   1313 
   1314 				DE_ASSERT(reference.type != glu::TYPE_LAST);
   1315 				DE_ASSERT(reference.minSize >= 1 || (reference.minSize == 0 && !reference.isUsedInShader));
   1316 				DE_ASSERT(reference.minSize <= reference.maxSize);
   1317 
   1318 				if (BasicUniformReportGL::findWithName(basicUniformReportsDst, reportedNameStr.c_str()) != basicUniformReportsDst.end())
   1319 				{
   1320 					log << TestLog::Message << "// FAILURE: same uniform name reported twice" << TestLog::EndMessage;
   1321 					success = false;
   1322 				}
   1323 
   1324 				basicUniformReportsDst.push_back(BasicUniformReportGL(reportedNameStr.c_str(), reportedNameLength, reportedSize, reportedType, unifNdx));
   1325 
   1326 				if (reportedType != reference.type)
   1327 				{
   1328 					log << TestLog::Message << "// FAILURE: wrong type reported, should be " << glu::getDataTypeName(reference.type) << TestLog::EndMessage;
   1329 					success = false;
   1330 				}
   1331 				if (reportedSize < reference.minSize || reportedSize > reference.maxSize)
   1332 				{
   1333 					log << TestLog::Message
   1334 						<< "// FAILURE: wrong size reported, should be "
   1335 						<< (reference.minSize == reference.maxSize ? de::toString(reference.minSize) : "in the range [" + de::toString(reference.minSize) + ", " + de::toString(reference.maxSize) + "]")
   1336 						<< TestLog::EndMessage;
   1337 
   1338 					success = false;
   1339 				}
   1340 			}
   1341 		}
   1342 	}
   1343 
   1344 	for (int i = 0; i < (int)basicUniformReportsRef.size(); i++)
   1345 	{
   1346 		const BasicUniformReportRef& expected = basicUniformReportsRef[i];
   1347 		if (expected.isUsedInShader && BasicUniformReportGL::findWithName(basicUniformReportsDst, expected.name.c_str()) == basicUniformReportsDst.end())
   1348 		{
   1349 			log << TestLog::Message << "// FAILURE: uniform with name " << expected.name << " was not reported by GL" << TestLog::EndMessage;
   1350 			success = false;
   1351 		}
   1352 	}
   1353 
   1354 	return success;
   1355 }
   1356 
   1357 bool UniformCase::getUniforms (vector<VarValue>& valuesDst, const vector<BasicUniform>& basicUniforms, const deUint32 programGL)
   1358 {
   1359 	TestLog&	log			= m_testCtx.getLog();
   1360 	bool		success		= true;
   1361 
   1362 	for (int unifNdx = 0; unifNdx < (int)basicUniforms.size(); unifNdx++)
   1363 	{
   1364 		const BasicUniform&		uniform		= basicUniforms[unifNdx];
   1365 		const string			queryName	= m_features & FEATURE_ARRAY_FIRST_ELEM_NAME_NO_INDEX && uniform.elemNdx == 0 ? beforeLast(uniform.name, '[') : uniform.name;
   1366 		const int				location	= glGetUniformLocation(programGL, queryName.c_str());
   1367 		const int				size		= glu::getDataTypeScalarSize(uniform.type);
   1368 		VarValue				value;
   1369 
   1370 		deMemset(&value, 0xcd, sizeof(value)); // Initialize to known garbage.
   1371 
   1372 		if (location == -1)
   1373 		{
   1374 			value.type = glu::TYPE_INVALID;
   1375 			valuesDst.push_back(value);
   1376 			if (uniform.isUsedInShader)
   1377 			{
   1378 				log << TestLog::Message << "// FAILURE: " << uniform.name << " was used in shader, but has location -1" << TestLog::EndMessage;
   1379 				success = false;
   1380 			}
   1381 			continue;
   1382 		}
   1383 
   1384 		value.type = uniform.type;
   1385 
   1386 		DE_STATIC_ASSERT(sizeof(GLint) == sizeof(value.val.intV[0]));
   1387 		DE_STATIC_ASSERT(sizeof(GLfloat) == sizeof(value.val.floatV[0]));
   1388 
   1389 		if (glu::isDataTypeFloatOrVec(uniform.type) || glu::isDataTypeMatrix(uniform.type))
   1390 			GLU_CHECK_CALL(glGetUniformfv(programGL, location, &value.val.floatV[0]));
   1391 		else if (glu::isDataTypeIntOrIVec(uniform.type))
   1392 			GLU_CHECK_CALL(glGetUniformiv(programGL, location, &value.val.intV[0]));
   1393 		else if (glu::isDataTypeBoolOrBVec(uniform.type))
   1394 		{
   1395 			if (m_features & FEATURE_BOOLEANAPITYPE_INT)
   1396 			{
   1397 				GLU_CHECK_CALL(glGetUniformiv(programGL, location, &value.val.intV[0]));
   1398 				for (int i = 0; i < size; i++)
   1399 					value.val.boolV[i] = value.val.intV[i] != 0;
   1400 			}
   1401 			else // Default: use float.
   1402 			{
   1403 				GLU_CHECK_CALL(glGetUniformfv(programGL, location, &value.val.floatV[0]));
   1404 				for (int i = 0; i < size; i++)
   1405 					value.val.boolV[i] = value.val.floatV[i] != 0.0f;
   1406 			}
   1407 		}
   1408 		else if (glu::isDataTypeSampler(uniform.type))
   1409 		{
   1410 			GLint unit = -1;
   1411 			GLU_CHECK_CALL(glGetUniformiv(programGL, location, &unit));
   1412 			value.val.samplerV.unit = unit;
   1413 		}
   1414 		else
   1415 			DE_ASSERT(false);
   1416 
   1417 		valuesDst.push_back(value);
   1418 
   1419 		log << TestLog::Message << "// Got " << uniform.name << " value " << apiVarValueStr(value) << TestLog::EndMessage;
   1420 	}
   1421 
   1422 	return success;
   1423 }
   1424 
   1425 bool UniformCase::checkUniformDefaultValues (const vector<VarValue>& values, const vector<BasicUniform>& basicUniforms)
   1426 {
   1427 	TestLog&	log			= m_testCtx.getLog();
   1428 	bool		success		= true;
   1429 
   1430 	DE_ASSERT(values.size() == basicUniforms.size());
   1431 
   1432 	for (int unifNdx = 0; unifNdx < (int)basicUniforms.size(); unifNdx++)
   1433 	{
   1434 		const BasicUniform&		uniform		= basicUniforms[unifNdx];
   1435 		const VarValue&			unifValue	= values[unifNdx];
   1436 		const int				valSize		= glu::getDataTypeScalarSize(uniform.type);
   1437 
   1438 		log << TestLog::Message << "// Checking uniform " << uniform.name << TestLog::EndMessage;
   1439 
   1440 		if (unifValue.type == glu::TYPE_INVALID) // This happens when glGetUniformLocation() returned -1.
   1441 			continue;
   1442 
   1443 #define CHECK_UNIFORM(VAR_VALUE_MEMBER, ZERO)																								\
   1444 	do																																		\
   1445 	{																																		\
   1446 		for (int i = 0; i < valSize; i++)																									\
   1447 		{																																	\
   1448 			if (unifValue.val.VAR_VALUE_MEMBER[i] != ZERO)																					\
   1449 			{																																\
   1450 				log << TestLog::Message << "// FAILURE: uniform " << uniform.name << " has non-zero initial value" << TestLog::EndMessage;	\
   1451 				success = false;																											\
   1452 			}																																\
   1453 		}																																	\
   1454 	} while (false)
   1455 
   1456 		if (glu::isDataTypeFloatOrVec(uniform.type) || glu::isDataTypeMatrix(uniform.type))
   1457 			CHECK_UNIFORM(floatV, 0.0f);
   1458 		else if (glu::isDataTypeIntOrIVec(uniform.type))
   1459 			CHECK_UNIFORM(intV, 0);
   1460 		else if (glu::isDataTypeBoolOrBVec(uniform.type))
   1461 			CHECK_UNIFORM(boolV, false);
   1462 		else if (glu::isDataTypeSampler(uniform.type))
   1463 		{
   1464 			if (unifValue.val.samplerV.unit != 0)
   1465 			{
   1466 				log << TestLog::Message << "// FAILURE: uniform " << uniform.name << " has non-zero initial value" << TestLog::EndMessage;
   1467 				success = false;
   1468 			}
   1469 		}
   1470 		else
   1471 			DE_ASSERT(false);
   1472 
   1473 #undef CHECK_UNIFORM
   1474 	}
   1475 
   1476 	return success;
   1477 }
   1478 
   1479 void UniformCase::assignUniforms (const vector<BasicUniform>& basicUniforms, deUint32 programGL, Random& rnd)
   1480 {
   1481 	TestLog&				log				= m_testCtx.getLog();
   1482 	const glu::DataType		boolApiType		= m_features & FEATURE_BOOLEANAPITYPE_INT	? glu::TYPE_INT
   1483 											:											  glu::TYPE_FLOAT;
   1484 
   1485 	for (int unifNdx = 0; unifNdx < (int)basicUniforms.size(); unifNdx++)
   1486 	{
   1487 		const BasicUniform&		uniform				= basicUniforms[unifNdx];
   1488 		const bool				isArrayMember		= uniform.elemNdx >= 0;
   1489 		const string			queryName			= m_features & FEATURE_ARRAY_FIRST_ELEM_NAME_NO_INDEX && uniform.elemNdx == 0 ? beforeLast(uniform.name, '[') : uniform.name;
   1490 		const int				numValuesToAssign	= !isArrayMember									? 1
   1491 													: m_features & FEATURE_ARRAYASSIGN_FULL				? (uniform.elemNdx == 0			? uniform.rootSize	: 0)
   1492 													: m_features & FEATURE_ARRAYASSIGN_BLOCKS_OF_TWO	? (uniform.elemNdx % 2 == 0		? 2					: 0)
   1493 													: /* Default: assign array elements separately */	  1;
   1494 
   1495 		DE_ASSERT(numValuesToAssign >= 0);
   1496 		DE_ASSERT(numValuesToAssign == 1 || isArrayMember);
   1497 
   1498 		if (numValuesToAssign == 0)
   1499 		{
   1500 			log << TestLog::Message << "// Uniform " << uniform.name << " is covered by another glUniform*v() call to the same array" << TestLog::EndMessage;
   1501 			continue;
   1502 		}
   1503 
   1504 		const int			location			= glGetUniformLocation(programGL, queryName.c_str());
   1505 		const int			typeSize			= glu::getDataTypeScalarSize(uniform.type);
   1506 		const bool			assignByValue		= m_features & FEATURE_UNIFORMFUNC_VALUE && !glu::isDataTypeMatrix(uniform.type) && numValuesToAssign == 1;
   1507 		vector<VarValue>	valuesToAssign;
   1508 
   1509 		for (int i = 0; i < numValuesToAssign; i++)
   1510 		{
   1511 			const string	curName = isArrayMember ? beforeLast(uniform.rootName, '[') + "[" + de::toString(uniform.elemNdx+i) + "]" : uniform.name;
   1512 			VarValue		unifValue;
   1513 
   1514 			if (isArrayMember)
   1515 			{
   1516 				const vector<BasicUniform>::const_iterator elemUnif = BasicUniform::findWithName(basicUniforms, curName.c_str());
   1517 				if (elemUnif == basicUniforms.end())
   1518 					continue;
   1519 				unifValue = elemUnif->finalValue;
   1520 			}
   1521 			else
   1522 				unifValue = uniform.finalValue;
   1523 
   1524 			const VarValue apiValue = glu::isDataTypeBoolOrBVec(unifValue.type)	? getRandomBoolRepresentation(unifValue, boolApiType, rnd)
   1525 									: glu::isDataTypeSampler(unifValue.type)	? getSamplerUnitValue(unifValue)
   1526 									: unifValue;
   1527 
   1528 			valuesToAssign.push_back(apiValue);
   1529 
   1530 			if (glu::isDataTypeBoolOrBVec(uniform.type))
   1531 				log << TestLog::Message << "// Using type " << glu::getDataTypeName(boolApiType) << " to set boolean value " << apiVarValueStr(unifValue) << " for " << curName << TestLog::EndMessage;
   1532 			else if (glu::isDataTypeSampler(uniform.type))
   1533 				log << TestLog::Message << "// Texture for the sampler uniform " << curName << " will be filled with color " << apiVarValueStr(getSamplerFillValue(uniform.finalValue)) << TestLog::EndMessage;
   1534 		}
   1535 
   1536 		DE_ASSERT(!valuesToAssign.empty());
   1537 
   1538 		if (glu::isDataTypeFloatOrVec(valuesToAssign[0].type))
   1539 		{
   1540 			if (assignByValue)
   1541 			{
   1542 				const float* const ptr = &valuesToAssign[0].val.floatV[0];
   1543 
   1544 				switch (typeSize)
   1545 				{
   1546 					case 1: GLU_CHECK_CALL(glUniform1f(location, ptr[0]));							break;
   1547 					case 2: GLU_CHECK_CALL(glUniform2f(location, ptr[0], ptr[1]));					break;
   1548 					case 3: GLU_CHECK_CALL(glUniform3f(location, ptr[0], ptr[1], ptr[2]));			break;
   1549 					case 4: GLU_CHECK_CALL(glUniform4f(location, ptr[0], ptr[1], ptr[2], ptr[3]));	break;
   1550 					default:
   1551 						DE_ASSERT(false);
   1552 				}
   1553 			}
   1554 			else
   1555 			{
   1556 				vector<float> buffer(valuesToAssign.size() * typeSize);
   1557 				for (int i = 0; i < (int)buffer.size(); i++)
   1558 					buffer[i] = valuesToAssign[i / typeSize].val.floatV[i % typeSize];
   1559 
   1560 				DE_STATIC_ASSERT(sizeof(GLfloat) == sizeof(buffer[0]));
   1561 				switch (typeSize)
   1562 				{
   1563 					case 1: GLU_CHECK_CALL(glUniform1fv(location, (GLsizei)valuesToAssign.size(), &buffer[0])); break;
   1564 					case 2: GLU_CHECK_CALL(glUniform2fv(location, (GLsizei)valuesToAssign.size(), &buffer[0])); break;
   1565 					case 3: GLU_CHECK_CALL(glUniform3fv(location, (GLsizei)valuesToAssign.size(), &buffer[0])); break;
   1566 					case 4: GLU_CHECK_CALL(glUniform4fv(location, (GLsizei)valuesToAssign.size(), &buffer[0])); break;
   1567 					default:
   1568 						DE_ASSERT(false);
   1569 				}
   1570 			}
   1571 		}
   1572 		else if (glu::isDataTypeMatrix(valuesToAssign[0].type))
   1573 		{
   1574 			DE_ASSERT(!assignByValue);
   1575 
   1576 			vector<float> buffer(valuesToAssign.size() * typeSize);
   1577 			for (int i = 0; i < (int)buffer.size(); i++)
   1578 				buffer[i] = valuesToAssign[i / typeSize].val.floatV[i % typeSize];
   1579 
   1580 			switch (uniform.type)
   1581 			{
   1582 				case glu::TYPE_FLOAT_MAT2: GLU_CHECK_CALL(glUniformMatrix2fv(location, (GLsizei)valuesToAssign.size(), GL_FALSE, &buffer[0])); break;
   1583 				case glu::TYPE_FLOAT_MAT3: GLU_CHECK_CALL(glUniformMatrix3fv(location, (GLsizei)valuesToAssign.size(), GL_FALSE, &buffer[0])); break;
   1584 				case glu::TYPE_FLOAT_MAT4: GLU_CHECK_CALL(glUniformMatrix4fv(location, (GLsizei)valuesToAssign.size(), GL_FALSE, &buffer[0])); break;
   1585 				default:
   1586 					DE_ASSERT(false);
   1587 			}
   1588 		}
   1589 		else if (glu::isDataTypeIntOrIVec(valuesToAssign[0].type))
   1590 		{
   1591 			if (assignByValue)
   1592 			{
   1593 				const deInt32* const ptr = &valuesToAssign[0].val.intV[0];
   1594 
   1595 				switch (typeSize)
   1596 				{
   1597 					case 1: GLU_CHECK_CALL(glUniform1i(location, ptr[0]));							break;
   1598 					case 2: GLU_CHECK_CALL(glUniform2i(location, ptr[0], ptr[1]));					break;
   1599 					case 3: GLU_CHECK_CALL(glUniform3i(location, ptr[0], ptr[1], ptr[2]));			break;
   1600 					case 4: GLU_CHECK_CALL(glUniform4i(location, ptr[0], ptr[1], ptr[2], ptr[3]));	break;
   1601 					default:
   1602 						DE_ASSERT(false);
   1603 				}
   1604 			}
   1605 			else
   1606 			{
   1607 				vector<deInt32> buffer(valuesToAssign.size() * typeSize);
   1608 				for (int i = 0; i < (int)buffer.size(); i++)
   1609 					buffer[i] = valuesToAssign[i / typeSize].val.intV[i % typeSize];
   1610 
   1611 				DE_STATIC_ASSERT(sizeof(GLint) == sizeof(buffer[0]));
   1612 				switch (typeSize)
   1613 				{
   1614 					case 1: GLU_CHECK_CALL(glUniform1iv(location, (GLsizei)valuesToAssign.size(), &buffer[0])); break;
   1615 					case 2: GLU_CHECK_CALL(glUniform2iv(location, (GLsizei)valuesToAssign.size(), &buffer[0])); break;
   1616 					case 3: GLU_CHECK_CALL(glUniform3iv(location, (GLsizei)valuesToAssign.size(), &buffer[0])); break;
   1617 					case 4: GLU_CHECK_CALL(glUniform4iv(location, (GLsizei)valuesToAssign.size(), &buffer[0])); break;
   1618 					default:
   1619 						DE_ASSERT(false);
   1620 				}
   1621 			}
   1622 		}
   1623 		else if (glu::isDataTypeSampler(valuesToAssign[0].type))
   1624 		{
   1625 			if (assignByValue)
   1626 				GLU_CHECK_CALL(glUniform1i(location, uniform.finalValue.val.samplerV.unit));
   1627 			else
   1628 			{
   1629 				const GLint unit = uniform.finalValue.val.samplerV.unit;
   1630 				GLU_CHECK_CALL(glUniform1iv(location, (GLsizei)valuesToAssign.size(), &unit));
   1631 			}
   1632 		}
   1633 		else
   1634 			DE_ASSERT(false);
   1635 	}
   1636 }
   1637 
   1638 bool UniformCase::compareUniformValues (const vector<VarValue>& values, const vector<BasicUniform>& basicUniforms)
   1639 {
   1640 	TestLog&	log			= m_testCtx.getLog();
   1641 	bool		success		= true;
   1642 
   1643 	for (int unifNdx = 0; unifNdx < (int)basicUniforms.size(); unifNdx++)
   1644 	{
   1645 		const BasicUniform&		uniform		= basicUniforms[unifNdx];
   1646 		const VarValue&			unifValue	= values[unifNdx];
   1647 
   1648 		log << TestLog::Message << "// Checking uniform " << uniform.name << TestLog::EndMessage;
   1649 
   1650 		if (unifValue.type == glu::TYPE_INVALID) // This happens when glGetUniformLocation() returned -1.
   1651 			continue;
   1652 
   1653 		if (!apiVarValueEquals(unifValue, uniform.finalValue))
   1654 		{
   1655 			log << TestLog::Message << "// FAILURE: value obtained with glGetUniform*() for uniform " << uniform.name << " differs from value set with glUniform*()" << TestLog::EndMessage;
   1656 			success = false;
   1657 		}
   1658 	}
   1659 
   1660 	return success;
   1661 }
   1662 
   1663 bool UniformCase::renderTest (const vector<BasicUniform>& basicUniforms, const ShaderProgram& program, Random& rnd)
   1664 {
   1665 	TestLog&					log				= m_testCtx.getLog();
   1666 	const tcu::RenderTarget&	renderTarget	= m_context.getRenderTarget();
   1667 	const int					viewportW		= de::min(renderTarget.getWidth(),	MAX_RENDER_WIDTH);
   1668 	const int					viewportH		= de::min(renderTarget.getHeight(),	MAX_RENDER_HEIGHT);
   1669 	const int					viewportX		= rnd.getInt(0, renderTarget.getWidth()		- viewportW);
   1670 	const int					viewportY		= rnd.getInt(0, renderTarget.getHeight()	- viewportH);
   1671 	tcu::Surface				renderedImg		(viewportW, viewportH);
   1672 
   1673 	// Assert that no two samplers of different types have the same texture unit - this is an error in GL.
   1674 	for (int i = 0; i < (int)basicUniforms.size(); i++)
   1675 	{
   1676 		if (glu::isDataTypeSampler(basicUniforms[i].type))
   1677 		{
   1678 			for (int j = 0; j < i; j++)
   1679 			{
   1680 				if (glu::isDataTypeSampler(basicUniforms[j].type) && basicUniforms[i].type != basicUniforms[j].type)
   1681 					DE_ASSERT(basicUniforms[i].finalValue.val.samplerV.unit != basicUniforms[j].finalValue.val.samplerV.unit);
   1682 			}
   1683 		}
   1684 	}
   1685 
   1686 	for (int i = 0; i < (int)basicUniforms.size(); i++)
   1687 	{
   1688 		if (glu::isDataTypeSampler(basicUniforms[i].type) && std::find(m_filledTextureUnits.begin(), m_filledTextureUnits.end(), basicUniforms[i].finalValue.val.samplerV.unit) == m_filledTextureUnits.end())
   1689 		{
   1690 			log << TestLog::Message << "// Filling texture at unit " << apiVarValueStr(basicUniforms[i].finalValue) << " with color " << shaderVarValueStr(basicUniforms[i].finalValue) << TestLog::EndMessage;
   1691 			setupTexture(basicUniforms[i].finalValue);
   1692 		}
   1693 	}
   1694 
   1695 	GLU_CHECK_CALL(glViewport(viewportX, viewportY, viewportW, viewportH));
   1696 
   1697 	{
   1698 		static const float position[] =
   1699 		{
   1700 			-1.0f, -1.0f, 0.0f, 1.0f,
   1701 			-1.0f, +1.0f, 0.0f, 1.0f,
   1702 			+1.0f, -1.0f, 0.0f, 1.0f,
   1703 			+1.0f, +1.0f, 0.0f, 1.0f
   1704 		};
   1705 		static const deUint16 indices[] = { 0, 1, 2, 2, 1, 3 };
   1706 
   1707 		const int posLoc = glGetAttribLocation(program.getProgram(), "a_position");
   1708 
   1709 		glEnableVertexAttribArray(posLoc);
   1710 		glVertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, &position[0]);
   1711 
   1712 		GLU_CHECK_CALL(glDrawElements(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(indices), GL_UNSIGNED_SHORT, &indices[0]));
   1713 	}
   1714 
   1715 	glu::readPixels(m_context.getRenderContext(), viewportX, viewportY, renderedImg.getAccess());
   1716 
   1717 	int numFailedPixels = 0;
   1718 	for (int y = 0; y < renderedImg.getHeight(); y++)
   1719 	{
   1720 		for (int x = 0; x < renderedImg.getWidth(); x++)
   1721 		{
   1722 			if (renderedImg.getPixel(x, y) != tcu::RGBA::white())
   1723 				numFailedPixels += 1;
   1724 		}
   1725 	}
   1726 
   1727 	if (numFailedPixels > 0)
   1728 	{
   1729 		log << TestLog::Image("RenderedImage", "Rendered image", renderedImg);
   1730 		log << TestLog::Message << "FAILURE: image comparison failed, got " << numFailedPixels << " non-white pixels" << TestLog::EndMessage;
   1731 		return false;
   1732 	}
   1733 	else
   1734 	{
   1735 		log << TestLog::Message << "Success: got all-white pixels (all uniforms have correct values)" << TestLog::EndMessage;
   1736 		return true;
   1737 	}
   1738 }
   1739 
   1740 UniformCase::IterateResult UniformCase::iterate (void)
   1741 {
   1742 	Random							rnd				(deStringHash(getName()) ^ (deUint32)m_context.getTestContext().getCommandLine().getBaseSeed());
   1743 	TestLog&						log				= m_testCtx.getLog();
   1744 	vector<BasicUniform>			basicUniforms;
   1745 	vector<BasicUniformReportRef>	basicUniformReportsRef;
   1746 
   1747 	{
   1748 		int samplerUnitCounter = 0;
   1749 		for (int i = 0; i < (int)m_uniformCollection->getNumUniforms(); i++)
   1750 			generateBasicUniforms(basicUniforms, basicUniformReportsRef, m_uniformCollection->getUniform(i).type, m_uniformCollection->getUniform(i).name.c_str(), true, samplerUnitCounter, rnd);
   1751 	}
   1752 
   1753 	const string					vertexSource	= generateVertexSource(basicUniforms);
   1754 	const string					fragmentSource	= generateFragmentSource(basicUniforms);
   1755 	const ShaderProgram				program			(m_context.getRenderContext(), glu::makeVtxFragSources(vertexSource, fragmentSource));
   1756 
   1757 	log << program;
   1758 
   1759 	if (!program.isOk())
   1760 	{
   1761 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Compile failed");
   1762 		return STOP;
   1763 	}
   1764 
   1765 	GLU_CHECK_CALL(glUseProgram(program.getProgram()));
   1766 
   1767 	const bool success = test(basicUniforms, basicUniformReportsRef, program, rnd);
   1768 	m_testCtx.setTestResult(success ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
   1769 							success ? "Passed"				: "Failed");
   1770 
   1771 	return STOP;
   1772 }
   1773 
   1774 class UniformInfoQueryCase : public UniformCase
   1775 {
   1776 public:
   1777 				UniformInfoQueryCase	(Context& context, const char* name, const char* description, CaseShaderType shaderType, const SharedPtr<const UniformCollection>& uniformCollection, deUint32 additionalFeatures = 0);
   1778 	bool		test					(const vector<BasicUniform>& basicUniforms, const vector<BasicUniformReportRef>& basicUniformReportsRef, const ShaderProgram& program, Random& rnd);
   1779 };
   1780 
   1781 UniformInfoQueryCase::UniformInfoQueryCase (Context& context, const char* const name, const char* const description, const CaseShaderType shaderType, const SharedPtr<const UniformCollection>& uniformCollection, const deUint32 additionalFeatures)
   1782 	: UniformCase	(context, name, description, shaderType, uniformCollection, additionalFeatures)
   1783 {
   1784 }
   1785 
   1786 bool UniformInfoQueryCase::test (const vector<BasicUniform>& basicUniforms, const vector<BasicUniformReportRef>& basicUniformReportsRef, const ShaderProgram& program, Random& rnd)
   1787 {
   1788 	DE_UNREF(basicUniforms);
   1789 	DE_UNREF(rnd);
   1790 
   1791 	const deUint32					programGL	= program.getProgram();
   1792 	TestLog&						log			= m_testCtx.getLog();
   1793 	vector<BasicUniformReportGL>	basicUniformReportsUniform;
   1794 
   1795 	const ScopedLogSection section(log, "InfoGetActiveUniform", "Uniform information queries with glGetActiveUniform()");
   1796 	const bool success = getActiveUniforms(basicUniformReportsUniform, basicUniformReportsRef, programGL);
   1797 
   1798 	if (!success)
   1799 		return false;
   1800 
   1801 	return true;
   1802 }
   1803 
   1804 class UniformValueCase : public UniformCase
   1805 {
   1806 public:
   1807 	enum ValueToCheck
   1808 	{
   1809 		VALUETOCHECK_INITIAL = 0,		//!< Verify the initial values of the uniforms (i.e. check that they're zero).
   1810 		VALUETOCHECK_ASSIGNED,			//!< Assign values to uniforms with glUniform*(), and check those.
   1811 
   1812 		VALUETOCHECK_LAST
   1813 	};
   1814 	enum CheckMethod
   1815 	{
   1816 		CHECKMETHOD_GET_UNIFORM = 0,	//!< Check values with glGetUniform*().
   1817 		CHECKMETHOD_RENDER,				//!< Check values by rendering with the value-checking shader.
   1818 
   1819 		CHECKMETHOD_LAST
   1820 	};
   1821 	enum AssignMethod
   1822 	{
   1823 		ASSIGNMETHOD_POINTER = 0,
   1824 		ASSIGNMETHOD_VALUE,
   1825 
   1826 		ASSIGNMETHOD_LAST
   1827 	};
   1828 
   1829 						UniformValueCase			(Context&									context,
   1830 													 const char*								name,
   1831 													 const char*								description,
   1832 													 CaseShaderType								shaderType,
   1833 													 const SharedPtr<const UniformCollection>&	uniformCollection,
   1834 													 ValueToCheck								valueToCheck,
   1835 													 CheckMethod								checkMethod,
   1836 													 AssignMethod								assignMethod,
   1837 													 deUint32									additionalFeatures = 0);
   1838 
   1839 	bool				test						(const vector<BasicUniform>& basicUniforms, const vector<BasicUniformReportRef>& basicUniformReportsRef, const ShaderProgram& program, Random& rnd);
   1840 
   1841 	static const char*	getValueToCheckName			(ValueToCheck valueToCheck);
   1842 	static const char*	getValueToCheckDescription	(ValueToCheck valueToCheck);
   1843 	static const char*	getCheckMethodName			(CheckMethod checkMethod);
   1844 	static const char*	getCheckMethodDescription	(CheckMethod checkMethod);
   1845 	static const char*	getAssignMethodName			(AssignMethod checkMethod);
   1846 	static const char*	getAssignMethodDescription	(AssignMethod checkMethod);
   1847 
   1848 private:
   1849 	const ValueToCheck	m_valueToCheck;
   1850 	const CheckMethod	m_checkMethod;
   1851 };
   1852 
   1853 const char* UniformValueCase::getValueToCheckName (const ValueToCheck valueToCheck)
   1854 {
   1855 	switch (valueToCheck)
   1856 	{
   1857 		case VALUETOCHECK_INITIAL:	return "initial";
   1858 		case VALUETOCHECK_ASSIGNED:	return "assigned";
   1859 		default: DE_ASSERT(false);	return DE_NULL;
   1860 	}
   1861 }
   1862 
   1863 const char* UniformValueCase::getValueToCheckDescription (const ValueToCheck valueToCheck)
   1864 {
   1865 	switch (valueToCheck)
   1866 {
   1867 		case VALUETOCHECK_INITIAL:	return "Check initial uniform values (zeros)";
   1868 		case VALUETOCHECK_ASSIGNED:	return "Check assigned uniform values";
   1869 		default: DE_ASSERT(false);	return DE_NULL;
   1870 	}
   1871 }
   1872 
   1873 const char* UniformValueCase::getCheckMethodName (const CheckMethod checkMethod)
   1874 {
   1875 	switch (checkMethod)
   1876 	{
   1877 		case CHECKMETHOD_GET_UNIFORM:	return "get_uniform";
   1878 		case CHECKMETHOD_RENDER:		return "render";
   1879 		default: DE_ASSERT(false);		return DE_NULL;
   1880 	}
   1881 }
   1882 
   1883 const char* UniformValueCase::getCheckMethodDescription (const CheckMethod checkMethod)
   1884 {
   1885 	switch (checkMethod)
   1886 	{
   1887 		case CHECKMETHOD_GET_UNIFORM:	return "Verify values with glGetUniform*()";
   1888 		case CHECKMETHOD_RENDER:		return "Verify values by rendering";
   1889 		default: DE_ASSERT(false);		return DE_NULL;
   1890 	}
   1891 }
   1892 
   1893 const char* UniformValueCase::getAssignMethodName (const AssignMethod assignMethod)
   1894 {
   1895 	switch (assignMethod)
   1896 	{
   1897 		case ASSIGNMETHOD_POINTER:		return "by_pointer";
   1898 		case ASSIGNMETHOD_VALUE:		return "by_value";
   1899 		default: DE_ASSERT(false);		return DE_NULL;
   1900 	}
   1901 }
   1902 
   1903 const char* UniformValueCase::getAssignMethodDescription (const AssignMethod assignMethod)
   1904 {
   1905 	switch (assignMethod)
   1906 	{
   1907 		case ASSIGNMETHOD_POINTER:		return "Assign values by-pointer";
   1908 		case ASSIGNMETHOD_VALUE:		return "Assign values by-value";
   1909 		default: DE_ASSERT(false);		return DE_NULL;
   1910 	}
   1911 }
   1912 
   1913 UniformValueCase::UniformValueCase (Context&									context,
   1914 									const char* const							name,
   1915 									const char* const							description,
   1916 									const CaseShaderType						shaderType,
   1917 									const SharedPtr<const UniformCollection>&	uniformCollection,
   1918 									const ValueToCheck							valueToCheck,
   1919 									const CheckMethod							checkMethod,
   1920 									const AssignMethod							assignMethod,
   1921 									const deUint32								additionalFeatures)
   1922 	: UniformCase		(context, name, description, shaderType, uniformCollection,
   1923 						 (valueToCheck == VALUETOCHECK_INITIAL ? FEATURE_UNIFORMVALUE_ZERO : 0) | (assignMethod == ASSIGNMETHOD_VALUE ? FEATURE_UNIFORMFUNC_VALUE : 0) | additionalFeatures)
   1924 	, m_valueToCheck	(valueToCheck)
   1925 	, m_checkMethod		(checkMethod)
   1926 {
   1927 	DE_ASSERT(!(assignMethod == ASSIGNMETHOD_LAST && valueToCheck == VALUETOCHECK_ASSIGNED));
   1928 }
   1929 
   1930 bool UniformValueCase::test (const vector<BasicUniform>& basicUniforms, const vector<BasicUniformReportRef>& basicUniformReportsRef, const ShaderProgram& program, Random& rnd)
   1931 {
   1932 	DE_UNREF(basicUniformReportsRef);
   1933 
   1934 	const deUint32	programGL	= program.getProgram();
   1935 	TestLog&		log			= m_testCtx.getLog();
   1936 
   1937 	if (m_valueToCheck == VALUETOCHECK_ASSIGNED)
   1938 	{
   1939 		const ScopedLogSection section(log, "UniformAssign", "Uniform value assignments");
   1940 		assignUniforms(basicUniforms, programGL, rnd);
   1941 	}
   1942 	else
   1943 		DE_ASSERT(m_valueToCheck == VALUETOCHECK_INITIAL);
   1944 
   1945 	if (m_checkMethod == CHECKMETHOD_GET_UNIFORM)
   1946 	{
   1947 		vector<VarValue> values;
   1948 
   1949 		{
   1950 			const ScopedLogSection section(log, "GetUniforms", "Uniform value query");
   1951 			const bool success = getUniforms(values, basicUniforms, program.getProgram());
   1952 
   1953 			if (!success)
   1954 				return false;
   1955 		}
   1956 
   1957 		if (m_valueToCheck == VALUETOCHECK_ASSIGNED)
   1958 		{
   1959 			const ScopedLogSection section(log, "ValueCheck", "Verify that the reported values match the assigned values");
   1960 			const bool success = compareUniformValues(values, basicUniforms);
   1961 
   1962 			if (!success)
   1963 				return false;
   1964 		}
   1965 		else
   1966 		{
   1967 			DE_ASSERT(m_valueToCheck == VALUETOCHECK_INITIAL);
   1968 			const ScopedLogSection section(log, "ValueCheck", "Verify that the uniforms have correct initial values (zeros)");
   1969 			const bool success = checkUniformDefaultValues(values, basicUniforms);
   1970 
   1971 			if (!success)
   1972 				return false;
   1973 		}
   1974 	}
   1975 	else
   1976 	{
   1977 		DE_ASSERT(m_checkMethod == CHECKMETHOD_RENDER);
   1978 
   1979 		const ScopedLogSection section(log, "RenderTest", "Render test");
   1980 		const bool success = renderTest(basicUniforms, program, rnd);
   1981 
   1982 		if (!success)
   1983 			return false;
   1984 	}
   1985 
   1986 	return true;
   1987 }
   1988 
   1989 class RandomUniformCase : public UniformCase
   1990 {
   1991 public:
   1992 						RandomUniformCase		(Context& m_context, const char* name, const char* description, deUint32 seed);
   1993 
   1994 	bool				test					(const vector<BasicUniform>& basicUniforms, const vector<BasicUniformReportRef>& basicUniformReportsRef, const ShaderProgram& program, Random& rnd);
   1995 };
   1996 
   1997 RandomUniformCase::RandomUniformCase (Context& context, const char* const name, const char* const description, const deUint32 seed)
   1998 	: UniformCase (context, name, description, seed ^ (deUint32)context.getTestContext().getCommandLine().getBaseSeed())
   1999 {
   2000 }
   2001 
   2002 bool RandomUniformCase::test (const vector<BasicUniform>& basicUniforms, const vector<BasicUniformReportRef>& basicUniformReportsRef, const ShaderProgram& program, Random& rnd)
   2003 {
   2004 	// \note Different sampler types may not be bound to same unit when rendering.
   2005 	const bool		renderingPossible						= (m_features & FEATURE_UNIFORMVALUE_ZERO) == 0 || !m_uniformCollection->containsSeveralSamplerTypes();
   2006 
   2007 	bool			performGetActiveUniforms			= rnd.getBool();
   2008 	const bool		performGetUniforms					= rnd.getBool();
   2009 	const bool		performCheckUniformDefaultValues	= performGetUniforms && rnd.getBool();
   2010 	const bool		performAssignUniforms				= rnd.getBool();
   2011 	const bool		performCompareUniformValues			= performGetUniforms && performAssignUniforms && rnd.getBool();
   2012 	const bool		performRenderTest					= renderingPossible && performAssignUniforms && rnd.getBool();
   2013 	const deUint32	programGL							= program.getProgram();
   2014 	TestLog&		log									= m_testCtx.getLog();
   2015 
   2016 	if (!(performGetActiveUniforms || performGetUniforms || performCheckUniformDefaultValues || performAssignUniforms || performCompareUniformValues || performRenderTest))
   2017 		performGetActiveUniforms = true; // Do something at least.
   2018 
   2019 #define PERFORM_AND_CHECK(CALL, SECTION_NAME, SECTION_DESCRIPTION)						\
   2020 	do																					\
   2021 	{																					\
   2022 		const ScopedLogSection section(log, (SECTION_NAME), (SECTION_DESCRIPTION));		\
   2023 		const bool success = (CALL);													\
   2024 		if (!success)																	\
   2025 			return false;																\
   2026 	} while (false)
   2027 
   2028 	if (performGetActiveUniforms)
   2029 	{
   2030 		vector<BasicUniformReportGL> reportsUniform;
   2031 		PERFORM_AND_CHECK(getActiveUniforms(reportsUniform, basicUniformReportsRef, programGL), "InfoGetActiveUniform", "Uniform information queries with glGetActiveUniform()");
   2032 	}
   2033 
   2034 	{
   2035 		vector<VarValue> uniformDefaultValues;
   2036 
   2037 		if (performGetUniforms)
   2038 			PERFORM_AND_CHECK(getUniforms(uniformDefaultValues, basicUniforms, programGL), "GetUniformDefaults", "Uniform default value query");
   2039 		if (performCheckUniformDefaultValues)
   2040 			PERFORM_AND_CHECK(checkUniformDefaultValues(uniformDefaultValues, basicUniforms), "DefaultValueCheck", "Verify that the uniforms have correct initial values (zeros)");
   2041 	}
   2042 
   2043 	{
   2044 		vector<VarValue> uniformValues;
   2045 
   2046 		if (performAssignUniforms)
   2047 		{
   2048 			const ScopedLogSection section(log, "UniformAssign", "Uniform value assignments");
   2049 			assignUniforms(basicUniforms, programGL, rnd);
   2050 		}
   2051 		if (performCompareUniformValues)
   2052 		{
   2053 			PERFORM_AND_CHECK(getUniforms(uniformValues, basicUniforms, programGL), "GetUniforms", "Uniform value query");
   2054 			PERFORM_AND_CHECK(compareUniformValues(uniformValues, basicUniforms), "ValueCheck", "Verify that the reported values match the assigned values");
   2055 		}
   2056 	}
   2057 
   2058 	if (performRenderTest)
   2059 		PERFORM_AND_CHECK(renderTest(basicUniforms, program, rnd), "RenderTest", "Render test");
   2060 
   2061 #undef PERFORM_AND_CHECK
   2062 
   2063 	return true;
   2064 }
   2065 
   2066 UniformApiTests::UniformApiTests (Context& context)
   2067 	: TestCaseGroup(context, "uniform_api", "Uniform API Tests")
   2068 {
   2069 }
   2070 
   2071 UniformApiTests::~UniformApiTests (void)
   2072 {
   2073 }
   2074 
   2075 namespace
   2076 {
   2077 
   2078 // \note Although this is only used in UniformApiTest::init, it needs to be defined here as it's used as a template argument.
   2079 struct UniformCollectionCase
   2080 {
   2081 	string								namePrefix;
   2082 	SharedPtr<const UniformCollection>	uniformCollection;
   2083 
   2084 	UniformCollectionCase (const char* const name, const UniformCollection* uniformCollection_)
   2085 		: namePrefix			(name ? name + string("_") : "")
   2086 		, uniformCollection		(uniformCollection_)
   2087 	{
   2088 	}
   2089 };
   2090 
   2091 } // anonymous
   2092 
   2093 void UniformApiTests::init (void)
   2094 {
   2095 	// Generate sets of UniformCollections that are used by several cases.
   2096 
   2097 	enum
   2098 	{
   2099 		UNIFORMCOLLECTIONS_BASIC = 0,
   2100 		UNIFORMCOLLECTIONS_BASIC_ARRAY,
   2101 		UNIFORMCOLLECTIONS_BASIC_STRUCT,
   2102 		UNIFORMCOLLECTIONS_STRUCT_IN_ARRAY,
   2103 		UNIFORMCOLLECTIONS_ARRAY_IN_STRUCT,
   2104 		UNIFORMCOLLECTIONS_NESTED_STRUCTS_ARRAYS,
   2105 		UNIFORMCOLLECTIONS_MULTIPLE_BASIC,
   2106 		UNIFORMCOLLECTIONS_MULTIPLE_BASIC_ARRAY,
   2107 		UNIFORMCOLLECTIONS_MULTIPLE_NESTED_STRUCTS_ARRAYS,
   2108 
   2109 		UNIFORMCOLLECTIONS_LAST
   2110 	};
   2111 
   2112 	struct UniformCollectionGroup
   2113 	{
   2114 		string							name;
   2115 		vector<UniformCollectionCase>	cases;
   2116 	} defaultUniformCollections[UNIFORMCOLLECTIONS_LAST];
   2117 
   2118 	defaultUniformCollections[UNIFORMCOLLECTIONS_BASIC].name							= "basic";
   2119 	defaultUniformCollections[UNIFORMCOLLECTIONS_BASIC_ARRAY].name						= "basic_array";
   2120 	defaultUniformCollections[UNIFORMCOLLECTIONS_BASIC_STRUCT].name						= "basic_struct";
   2121 	defaultUniformCollections[UNIFORMCOLLECTIONS_STRUCT_IN_ARRAY].name					= "struct_in_array";
   2122 	defaultUniformCollections[UNIFORMCOLLECTIONS_ARRAY_IN_STRUCT].name					= "array_in_struct";
   2123 	defaultUniformCollections[UNIFORMCOLLECTIONS_NESTED_STRUCTS_ARRAYS].name			= "nested_structs_arrays";
   2124 	defaultUniformCollections[UNIFORMCOLLECTIONS_MULTIPLE_BASIC].name					= "multiple_basic";
   2125 	defaultUniformCollections[UNIFORMCOLLECTIONS_MULTIPLE_BASIC_ARRAY].name				= "multiple_basic_array";
   2126 	defaultUniformCollections[UNIFORMCOLLECTIONS_MULTIPLE_NESTED_STRUCTS_ARRAYS].name	= "multiple_nested_structs_arrays";
   2127 
   2128 	for (int dataTypeNdx = 0; dataTypeNdx < DE_LENGTH_OF_ARRAY(s_testDataTypes); dataTypeNdx++)
   2129 	{
   2130 		const glu::DataType		dataType	= s_testDataTypes[dataTypeNdx];
   2131 		const char* const		typeName	= glu::getDataTypeName(dataType);
   2132 
   2133 		defaultUniformCollections[UNIFORMCOLLECTIONS_BASIC].cases.push_back(UniformCollectionCase(typeName, UniformCollection::basic(dataType)));
   2134 
   2135 		if (glu::isDataTypeScalar(dataType)													||
   2136 			(glu::isDataTypeVector(dataType) && glu::getDataTypeScalarSize(dataType) == 4)	||
   2137 			dataType == glu::TYPE_FLOAT_MAT4												||
   2138 			dataType == glu::TYPE_SAMPLER_2D)
   2139 			defaultUniformCollections[UNIFORMCOLLECTIONS_BASIC_ARRAY].cases.push_back(UniformCollectionCase(typeName, UniformCollection::basicArray(dataType)));
   2140 
   2141 		if (glu::isDataTypeScalar(dataType)		||
   2142 			dataType == glu::TYPE_FLOAT_MAT4	||
   2143 			dataType == glu::TYPE_SAMPLER_2D)
   2144 		{
   2145 			const glu::DataType		secondDataType	= glu::isDataTypeScalar(dataType)	? glu::getDataTypeVector(dataType, 4)
   2146 													: dataType == glu::TYPE_FLOAT_MAT4	? glu::TYPE_FLOAT_MAT2
   2147 													: dataType == glu::TYPE_SAMPLER_2D	? glu::TYPE_SAMPLER_CUBE
   2148 													: glu::TYPE_LAST;
   2149 			DE_ASSERT(secondDataType != glu::TYPE_LAST);
   2150 			const char* const		secondTypeName	= glu::getDataTypeName(secondDataType);
   2151 			const string			name			= string("") + typeName + "_" + secondTypeName;
   2152 
   2153 			defaultUniformCollections[UNIFORMCOLLECTIONS_BASIC_STRUCT].cases.push_back			(UniformCollectionCase(name.c_str(), UniformCollection::basicStruct(dataType, secondDataType, false)));
   2154 			defaultUniformCollections[UNIFORMCOLLECTIONS_ARRAY_IN_STRUCT].cases.push_back		(UniformCollectionCase(name.c_str(), UniformCollection::basicStruct(dataType, secondDataType, true)));
   2155 			defaultUniformCollections[UNIFORMCOLLECTIONS_STRUCT_IN_ARRAY].cases.push_back		(UniformCollectionCase(name.c_str(), UniformCollection::structInArray(dataType, secondDataType, false)));
   2156 			defaultUniformCollections[UNIFORMCOLLECTIONS_NESTED_STRUCTS_ARRAYS].cases.push_back	(UniformCollectionCase(name.c_str(), UniformCollection::nestedArraysStructs(dataType, secondDataType)));
   2157 		}
   2158 	}
   2159 	defaultUniformCollections[UNIFORMCOLLECTIONS_MULTIPLE_BASIC].cases.push_back					(UniformCollectionCase(DE_NULL, UniformCollection::multipleBasic()));
   2160 	defaultUniformCollections[UNIFORMCOLLECTIONS_MULTIPLE_BASIC_ARRAY].cases.push_back				(UniformCollectionCase(DE_NULL, UniformCollection::multipleBasicArray()));
   2161 	defaultUniformCollections[UNIFORMCOLLECTIONS_MULTIPLE_NESTED_STRUCTS_ARRAYS].cases.push_back	(UniformCollectionCase(DE_NULL, UniformCollection::multipleNestedArraysStructs()));
   2162 
   2163 	// Info-query cases (check info returned by e.g. glGetActiveUniforms()).
   2164 
   2165 	{
   2166 		TestCaseGroup* const infoQueryGroup = new TestCaseGroup(m_context, "info_query", "Test glGetActiveUniform()");
   2167 		addChild(infoQueryGroup);
   2168 
   2169 		for (int collectionGroupNdx = 0; collectionGroupNdx < (int)UNIFORMCOLLECTIONS_LAST; collectionGroupNdx++)
   2170 		{
   2171 			const UniformCollectionGroup&	collectionGroup		= defaultUniformCollections[collectionGroupNdx];
   2172 			TestCaseGroup* const			collectionTestGroup	= new TestCaseGroup(m_context, collectionGroup.name.c_str(), "");
   2173 			infoQueryGroup->addChild(collectionTestGroup);
   2174 
   2175 			for (int collectionNdx = 0; collectionNdx < (int)collectionGroup.cases.size(); collectionNdx++)
   2176 			{
   2177 				const UniformCollectionCase& collectionCase = collectionGroup.cases[collectionNdx];
   2178 
   2179 				for (int shaderType = 0; shaderType < (int)CASESHADERTYPE_LAST; shaderType++)
   2180 				{
   2181 					const string								name				= collectionCase.namePrefix + getCaseShaderTypeName((CaseShaderType)shaderType);
   2182 					const SharedPtr<const UniformCollection>&	uniformCollection	= collectionCase.uniformCollection;
   2183 
   2184 					collectionTestGroup->addChild(new UniformInfoQueryCase(m_context, name.c_str(), "", (CaseShaderType)shaderType, uniformCollection));
   2185 				}
   2186 			}
   2187 		}
   2188 
   2189 		// Info-querying cases when unused uniforms are present.
   2190 
   2191 		{
   2192 			TestCaseGroup* const unusedUniformsGroup = new TestCaseGroup(m_context, "unused_uniforms", "Test with unused uniforms");
   2193 			infoQueryGroup->addChild(unusedUniformsGroup);
   2194 
   2195 			const UniformCollectionGroup& collectionGroup = defaultUniformCollections[UNIFORMCOLLECTIONS_ARRAY_IN_STRUCT];
   2196 
   2197 			for (int collectionNdx = 0; collectionNdx < (int)collectionGroup.cases.size(); collectionNdx++)
   2198 			{
   2199 				const UniformCollectionCase&				collectionCase		= collectionGroup.cases[collectionNdx];
   2200 				const string								collName			= collectionCase.namePrefix;
   2201 				const SharedPtr<const UniformCollection>&	uniformCollection	= collectionCase.uniformCollection;
   2202 
   2203 				for (int shaderType = 0; shaderType < (int)CASESHADERTYPE_LAST; shaderType++)
   2204 				{
   2205 					const string name = collName + getCaseShaderTypeName((CaseShaderType)shaderType);
   2206 					unusedUniformsGroup->addChild(new UniformInfoQueryCase(m_context, name.c_str(), "", (CaseShaderType)shaderType, uniformCollection,
   2207 																			UniformCase::FEATURE_UNIFORMUSAGE_EVERY_OTHER | UniformCase::FEATURE_ARRAYUSAGE_ONLY_MIDDLE_INDEX));
   2208 				}
   2209 			}
   2210 		}
   2211 	}
   2212 
   2213 	// Cases testing uniform values.
   2214 
   2215 	{
   2216 		TestCaseGroup* const valueGroup = new TestCaseGroup(m_context, "value", "Uniform value tests");
   2217 		addChild(valueGroup);
   2218 
   2219 		// Cases checking uniforms' initial values (all must be zeros), with glGetUniform*() or by rendering.
   2220 
   2221 		{
   2222 			TestCaseGroup* const initialValuesGroup = new TestCaseGroup(m_context,
   2223 																		UniformValueCase::getValueToCheckName(UniformValueCase::VALUETOCHECK_INITIAL),
   2224 																		UniformValueCase::getValueToCheckDescription(UniformValueCase::VALUETOCHECK_INITIAL));
   2225 			valueGroup->addChild(initialValuesGroup);
   2226 
   2227 			for (int checkMethodI = 0; checkMethodI < (int)UniformValueCase::CHECKMETHOD_LAST; checkMethodI++)
   2228 			{
   2229 				const UniformValueCase::CheckMethod		checkMethod			= (UniformValueCase::CheckMethod)checkMethodI;
   2230 				TestCaseGroup* const					checkMethodGroup	= new TestCaseGroup(m_context, UniformValueCase::getCheckMethodName(checkMethod), UniformValueCase::getCheckMethodDescription(checkMethod));
   2231 				initialValuesGroup->addChild(checkMethodGroup);
   2232 
   2233 				for (int collectionGroupNdx = 0; collectionGroupNdx < (int)UNIFORMCOLLECTIONS_LAST; collectionGroupNdx++)
   2234 				{
   2235 					const UniformCollectionGroup&	collectionGroup		= defaultUniformCollections[collectionGroupNdx];
   2236 					TestCaseGroup* const			collectionTestGroup	= new TestCaseGroup(m_context, collectionGroup.name.c_str(), "");
   2237 					checkMethodGroup->addChild(collectionTestGroup);
   2238 
   2239 					for (int collectionNdx = 0; collectionNdx < (int)collectionGroup.cases.size(); collectionNdx++)
   2240 					{
   2241 						const UniformCollectionCase&				collectionCase		= collectionGroup.cases[collectionNdx];
   2242 						const string								collName			= collectionCase.namePrefix;
   2243 						const SharedPtr<const UniformCollection>&	uniformCollection	= collectionCase.uniformCollection;
   2244 						const bool									containsBooleans	= uniformCollection->containsMatchingBasicType(glu::isDataTypeBoolOrBVec);
   2245 						const bool									varyBoolApiType		= checkMethod == UniformValueCase::CHECKMETHOD_GET_UNIFORM && containsBooleans &&
   2246 																						  (collectionGroupNdx == UNIFORMCOLLECTIONS_BASIC || collectionGroupNdx == UNIFORMCOLLECTIONS_BASIC_ARRAY);
   2247 						const int									numBoolVariations	= varyBoolApiType ? 2 : 1;
   2248 
   2249 						if (checkMethod == UniformValueCase::CHECKMETHOD_RENDER && uniformCollection->containsSeveralSamplerTypes())
   2250 							continue; // \note Samplers' initial API values (i.e. their texture units) are 0, and no two samplers of different types shall have same unit when rendering.
   2251 
   2252 						for (int booleanTypeI = 0; booleanTypeI < numBoolVariations; booleanTypeI++)
   2253 						{
   2254 							const deUint32		booleanTypeFeat	= booleanTypeI == 1 ? UniformCase::FEATURE_BOOLEANAPITYPE_INT
   2255 																: 0;
   2256 							const char* const	booleanTypeName	= booleanTypeI == 1 ? "int"
   2257 																: "float";
   2258 							const string		nameWithApiType	= varyBoolApiType ? collName + "api_" + booleanTypeName + "_" : collName;
   2259 
   2260 							for (int shaderType = 0; shaderType < (int)CASESHADERTYPE_LAST; shaderType++)
   2261 							{
   2262 								const string name = nameWithApiType + getCaseShaderTypeName((CaseShaderType)shaderType);
   2263 								collectionTestGroup->addChild(new UniformValueCase(m_context, name.c_str(), "", (CaseShaderType)shaderType, uniformCollection,
   2264 																				   UniformValueCase::VALUETOCHECK_INITIAL, checkMethod, UniformValueCase::ASSIGNMETHOD_LAST, booleanTypeFeat));
   2265 							}
   2266 						}
   2267 					}
   2268 				}
   2269 			}
   2270 		}
   2271 
   2272 		// Cases that first assign values to each uniform, then check the values with glGetUniform*() or by rendering.
   2273 
   2274 		{
   2275 			TestCaseGroup* const assignedValuesGroup = new TestCaseGroup(m_context,
   2276 																		UniformValueCase::getValueToCheckName(UniformValueCase::VALUETOCHECK_ASSIGNED),
   2277 																		UniformValueCase::getValueToCheckDescription(UniformValueCase::VALUETOCHECK_ASSIGNED));
   2278 			valueGroup->addChild(assignedValuesGroup);
   2279 
   2280 			for (int assignMethodI = 0; assignMethodI < (int)UniformValueCase::ASSIGNMETHOD_LAST; assignMethodI++)
   2281 			{
   2282 				const UniformValueCase::AssignMethod	assignMethod		= (UniformValueCase::AssignMethod)assignMethodI;
   2283 				TestCaseGroup* const					assignMethodGroup	= new TestCaseGroup(m_context, UniformValueCase::getAssignMethodName(assignMethod), UniformValueCase::getAssignMethodDescription(assignMethod));
   2284 				assignedValuesGroup->addChild(assignMethodGroup);
   2285 
   2286 				for (int checkMethodI = 0; checkMethodI < (int)UniformValueCase::CHECKMETHOD_LAST; checkMethodI++)
   2287 				{
   2288 					const UniformValueCase::CheckMethod		checkMethod			= (UniformValueCase::CheckMethod)checkMethodI;
   2289 					TestCaseGroup* const					checkMethodGroup	= new TestCaseGroup(m_context, UniformValueCase::getCheckMethodName(checkMethod), UniformValueCase::getCheckMethodDescription(checkMethod));
   2290 					assignMethodGroup->addChild(checkMethodGroup);
   2291 
   2292 					for (int collectionGroupNdx = 0; collectionGroupNdx < (int)UNIFORMCOLLECTIONS_LAST; collectionGroupNdx++)
   2293 					{
   2294 						const int numArrayFirstElemNameCases = checkMethod == UniformValueCase::CHECKMETHOD_GET_UNIFORM && collectionGroupNdx == UNIFORMCOLLECTIONS_BASIC_ARRAY ? 2 : 1;
   2295 
   2296 						for (int referToFirstArrayElemWithoutIndexI = 0; referToFirstArrayElemWithoutIndexI < numArrayFirstElemNameCases; referToFirstArrayElemWithoutIndexI++)
   2297 						{
   2298 							const UniformCollectionGroup&	collectionGroup			= defaultUniformCollections[collectionGroupNdx];
   2299 							const string					collectionGroupName		= collectionGroup.name + (referToFirstArrayElemWithoutIndexI == 0 ? "" : "_first_elem_without_brackets");
   2300 							TestCaseGroup*					collectionTestGroup		= DE_NULL;
   2301 
   2302 							for (int collectionNdx = 0; collectionNdx < (int)collectionGroup.cases.size(); collectionNdx++)
   2303 							{
   2304 								const UniformCollectionCase&				collectionCase		= collectionGroup.cases[collectionNdx];
   2305 								const string								collName			= collectionCase.namePrefix;
   2306 								const SharedPtr<const UniformCollection>&	uniformCollection	= collectionCase.uniformCollection;
   2307 								const bool									containsBooleans	= uniformCollection->containsMatchingBasicType(glu::isDataTypeBoolOrBVec);
   2308 								const bool									varyBoolApiType		= checkMethod == UniformValueCase::CHECKMETHOD_GET_UNIFORM && containsBooleans &&
   2309 																								  (collectionGroupNdx == UNIFORMCOLLECTIONS_BASIC || collectionGroupNdx == UNIFORMCOLLECTIONS_BASIC_ARRAY);
   2310 								const int									numBoolVariations	= varyBoolApiType ? 2 : 1;
   2311 								const bool									containsMatrices	= uniformCollection->containsMatchingBasicType(glu::isDataTypeMatrix);
   2312 
   2313 								if (containsMatrices && assignMethod != UniformValueCase::ASSIGNMETHOD_POINTER)
   2314 									continue;
   2315 
   2316 								for (int booleanTypeI = 0; booleanTypeI < numBoolVariations; booleanTypeI++)
   2317 								{
   2318 									const deUint32		booleanTypeFeat		= booleanTypeI == 1 ? UniformCase::FEATURE_BOOLEANAPITYPE_INT
   2319 																			: 0;
   2320 									const char* const	booleanTypeName		= booleanTypeI == 1 ? "int"
   2321 																			: "float";
   2322 									const string		nameWithBoolType	= varyBoolApiType ? collName + "api_" + booleanTypeName + "_" : collName;
   2323 									const string		nameWithMatrixType	= nameWithBoolType;
   2324 
   2325 									for (int shaderType = 0; shaderType < (int)CASESHADERTYPE_LAST; shaderType++)
   2326 									{
   2327 										const string	name							= nameWithMatrixType + getCaseShaderTypeName((CaseShaderType)shaderType);
   2328 										const deUint32	arrayFirstElemNameNoIndexFeat	= referToFirstArrayElemWithoutIndexI == 0 ? 0 : UniformCase::FEATURE_ARRAY_FIRST_ELEM_NAME_NO_INDEX;
   2329 
   2330 										// skip empty groups by creating groups on demand
   2331 										if (!collectionTestGroup)
   2332 										{
   2333 											collectionTestGroup = new TestCaseGroup(m_context, collectionGroupName.c_str(), "");
   2334 											checkMethodGroup->addChild(collectionTestGroup);
   2335 										}
   2336 
   2337 										collectionTestGroup->addChild(new UniformValueCase(m_context, name.c_str(), "", (CaseShaderType)shaderType, uniformCollection,
   2338 																							UniformValueCase::VALUETOCHECK_ASSIGNED, checkMethod, assignMethod,
   2339 																							booleanTypeFeat | arrayFirstElemNameNoIndexFeat));
   2340 									}
   2341 								}
   2342 							}
   2343 						}
   2344 					}
   2345 				}
   2346 			}
   2347 
   2348 			// Cases assign multiple basic-array elements with one glUniform*v() (i.e. the count parameter is bigger than 1).
   2349 
   2350 			{
   2351 				static const struct
   2352 				{
   2353 					UniformCase::Feature	arrayAssignMode;
   2354 					const char*				name;
   2355 					const char*				description;
   2356 				} arrayAssignGroups[] =
   2357 				{
   2358 					{ UniformCase::FEATURE_ARRAYASSIGN_FULL,			"basic_array_assign_full",		"Assign entire basic-type arrays per glUniform*v() call"			},
   2359 					{ UniformCase::FEATURE_ARRAYASSIGN_BLOCKS_OF_TWO,	"basic_array_assign_partial",	"Assign two elements of a basic-type array per glUniform*v() call"	}
   2360 				};
   2361 
   2362 				for (int arrayAssignGroupNdx = 0; arrayAssignGroupNdx < DE_LENGTH_OF_ARRAY(arrayAssignGroups); arrayAssignGroupNdx++)
   2363 				{
   2364 					UniformCase::Feature	arrayAssignMode		= arrayAssignGroups[arrayAssignGroupNdx].arrayAssignMode;
   2365 					const char* const		groupName			= arrayAssignGroups[arrayAssignGroupNdx].name;
   2366 					const char* const		groupDesc			= arrayAssignGroups[arrayAssignGroupNdx].description;
   2367 
   2368 					TestCaseGroup* const curArrayAssignGroup = new TestCaseGroup(m_context, groupName, groupDesc);
   2369 					assignedValuesGroup->addChild(curArrayAssignGroup);
   2370 
   2371 					static const int basicArrayCollectionGroups[] = { UNIFORMCOLLECTIONS_BASIC_ARRAY, UNIFORMCOLLECTIONS_ARRAY_IN_STRUCT, UNIFORMCOLLECTIONS_MULTIPLE_BASIC_ARRAY };
   2372 
   2373 					for (int collectionGroupNdx = 0; collectionGroupNdx < DE_LENGTH_OF_ARRAY(basicArrayCollectionGroups); collectionGroupNdx++)
   2374 					{
   2375 						const UniformCollectionGroup&	collectionGroup		= defaultUniformCollections[basicArrayCollectionGroups[collectionGroupNdx]];
   2376 						TestCaseGroup* const			collectionTestGroup	= new TestCaseGroup(m_context, collectionGroup.name.c_str(), "");
   2377 						curArrayAssignGroup->addChild(collectionTestGroup);
   2378 
   2379 						for (int collectionNdx = 0; collectionNdx < (int)collectionGroup.cases.size(); collectionNdx++)
   2380 						{
   2381 							const UniformCollectionCase&				collectionCase		= collectionGroup.cases[collectionNdx];
   2382 							const string								collName			= collectionCase.namePrefix;
   2383 							const SharedPtr<const UniformCollection>&	uniformCollection	= collectionCase.uniformCollection;
   2384 
   2385 							for (int shaderType = 0; shaderType < (int)CASESHADERTYPE_LAST; shaderType++)
   2386 							{
   2387 								const string name = collName + getCaseShaderTypeName((CaseShaderType)shaderType);
   2388 								collectionTestGroup->addChild(new UniformValueCase(m_context, name.c_str(), "", (CaseShaderType)shaderType, uniformCollection,
   2389 																				   UniformValueCase::VALUETOCHECK_ASSIGNED, UniformValueCase::CHECKMETHOD_GET_UNIFORM, UniformValueCase::ASSIGNMETHOD_POINTER,
   2390 																				   arrayAssignMode));
   2391 							}
   2392 						}
   2393 					}
   2394 				}
   2395 			}
   2396 
   2397 			// Value checking cases when unused uniforms are present.
   2398 
   2399 			{
   2400 				TestCaseGroup* const unusedUniformsGroup = new TestCaseGroup(m_context, "unused_uniforms", "Test with unused uniforms");
   2401 				assignedValuesGroup->addChild(unusedUniformsGroup);
   2402 
   2403 				const UniformCollectionGroup& collectionGroup = defaultUniformCollections[UNIFORMCOLLECTIONS_ARRAY_IN_STRUCT];
   2404 
   2405 				for (int collectionNdx = 0; collectionNdx < (int)collectionGroup.cases.size(); collectionNdx++)
   2406 				{
   2407 					const UniformCollectionCase&				collectionCase		= collectionGroup.cases[collectionNdx];
   2408 					const string								collName			= collectionCase.namePrefix;
   2409 					const SharedPtr<const UniformCollection>&	uniformCollection	= collectionCase.uniformCollection;
   2410 
   2411 					for (int shaderType = 0; shaderType < (int)CASESHADERTYPE_LAST; shaderType++)
   2412 					{
   2413 						const string name = collName + getCaseShaderTypeName((CaseShaderType)shaderType);
   2414 						unusedUniformsGroup->addChild(new UniformValueCase(m_context, name.c_str(), "", (CaseShaderType)shaderType, uniformCollection,
   2415 																		   UniformValueCase::VALUETOCHECK_ASSIGNED, UniformValueCase::CHECKMETHOD_GET_UNIFORM, UniformValueCase::ASSIGNMETHOD_POINTER,
   2416 																		   UniformCase::FEATURE_ARRAYUSAGE_ONLY_MIDDLE_INDEX | UniformCase::FEATURE_UNIFORMUSAGE_EVERY_OTHER));
   2417 					}
   2418 				}
   2419 			}
   2420 		}
   2421 	}
   2422 
   2423 	// Random cases.
   2424 
   2425 	{
   2426 		const int		numRandomCases		= 100;
   2427 		TestCaseGroup*	const randomGroup	= new TestCaseGroup(m_context, "random", "Random cases");
   2428 		addChild(randomGroup);
   2429 
   2430 		for (int ndx = 0; ndx < numRandomCases; ndx++)
   2431 			randomGroup->addChild(new RandomUniformCase(m_context, de::toString(ndx).c_str(), "", (deUint32)ndx));
   2432 	}
   2433 }
   2434 
   2435 } // Functional
   2436 } // gles2
   2437 } // deqp
   2438