Home | History | Annotate | Download | only in functional
      1 /*-------------------------------------------------------------------------
      2  * drawElements Quality Program OpenGL ES 3.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 ES2.
     24  *							 Utilities to glshared?
     25  *//*--------------------------------------------------------------------*/
     26 
     27 #include "es3fUniformApiTests.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 "deString.h"
     41 #include "deSharedPtr.hpp"
     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 gles3
     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_MAT2X3,
     82 	glu::TYPE_FLOAT_MAT2X4,
     83 	glu::TYPE_FLOAT_MAT3X2,
     84 	glu::TYPE_FLOAT_MAT3,
     85 	glu::TYPE_FLOAT_MAT3X4,
     86 	glu::TYPE_FLOAT_MAT4X2,
     87 	glu::TYPE_FLOAT_MAT4X3,
     88 	glu::TYPE_FLOAT_MAT4,
     89 
     90 	glu::TYPE_INT,
     91 	glu::TYPE_INT_VEC2,
     92 	glu::TYPE_INT_VEC3,
     93 	glu::TYPE_INT_VEC4,
     94 
     95 	glu::TYPE_UINT,
     96 	glu::TYPE_UINT_VEC2,
     97 	glu::TYPE_UINT_VEC3,
     98 	glu::TYPE_UINT_VEC4,
     99 
    100 	glu::TYPE_BOOL,
    101 	glu::TYPE_BOOL_VEC2,
    102 	glu::TYPE_BOOL_VEC3,
    103 	glu::TYPE_BOOL_VEC4,
    104 
    105 	glu::TYPE_SAMPLER_2D,
    106 	glu::TYPE_SAMPLER_CUBE
    107 	// \note We don't test all sampler types here.
    108 };
    109 
    110 static inline int getGLInt (const glw::Functions& funcs, const deUint32 name)
    111 {
    112 	int val = -1;
    113 	funcs.getIntegerv(name, &val);
    114 	return val;
    115 }
    116 
    117 static inline tcu::Vec4 vec4FromPtr (const float* const ptr)
    118 {
    119 	tcu::Vec4 result;
    120 	for (int i = 0; i < 4; i++)
    121 		result[i] = ptr[i];
    122 	return result;
    123 }
    124 
    125 static inline string beforeLast (const string& str, const char c)
    126 {
    127 	return str.substr(0, str.find_last_of(c));
    128 }
    129 
    130 static inline void fillWithColor (const tcu::PixelBufferAccess& access, const tcu::Vec4& color)
    131 {
    132 	for (int z = 0; z < access.getDepth(); z++)
    133 	for (int y = 0; y < access.getHeight(); y++)
    134 	for (int x = 0; x < access.getWidth(); x++)
    135 		access.setPixel(color, x, y, z);
    136 }
    137 
    138 static inline int getSamplerNumLookupDimensions (const glu::DataType type)
    139 {
    140 	switch (type)
    141 	{
    142 		case glu::TYPE_SAMPLER_2D:
    143 		case glu::TYPE_INT_SAMPLER_2D:
    144 		case glu::TYPE_UINT_SAMPLER_2D:
    145 			return 2;
    146 
    147 		case glu::TYPE_SAMPLER_3D:
    148 		case glu::TYPE_INT_SAMPLER_3D:
    149 		case glu::TYPE_UINT_SAMPLER_3D:
    150 		case glu::TYPE_SAMPLER_2D_SHADOW:
    151 		case glu::TYPE_SAMPLER_2D_ARRAY:
    152 		case glu::TYPE_INT_SAMPLER_2D_ARRAY:
    153 		case glu::TYPE_UINT_SAMPLER_2D_ARRAY:
    154 		case glu::TYPE_SAMPLER_CUBE:
    155 		case glu::TYPE_INT_SAMPLER_CUBE:
    156 		case glu::TYPE_UINT_SAMPLER_CUBE:
    157 			return 3;
    158 
    159 		case glu::TYPE_SAMPLER_CUBE_SHADOW:
    160 		case glu::TYPE_SAMPLER_2D_ARRAY_SHADOW:
    161 			return 4;
    162 
    163 		default:
    164 			DE_ASSERT(false);
    165 			return 0;
    166 	}
    167 }
    168 
    169 static inline glu::DataType getSamplerLookupReturnType (const glu::DataType type)
    170 {
    171 	switch (type)
    172 	{
    173 		case glu::TYPE_SAMPLER_2D:
    174 		case glu::TYPE_SAMPLER_CUBE:
    175 		case glu::TYPE_SAMPLER_2D_ARRAY:
    176 		case glu::TYPE_SAMPLER_3D:
    177 			return glu::TYPE_FLOAT_VEC4;
    178 
    179 		case glu::TYPE_UINT_SAMPLER_2D:
    180 		case glu::TYPE_UINT_SAMPLER_CUBE:
    181 		case glu::TYPE_UINT_SAMPLER_2D_ARRAY:
    182 		case glu::TYPE_UINT_SAMPLER_3D:
    183 			return glu::TYPE_UINT_VEC4;
    184 
    185 		case glu::TYPE_INT_SAMPLER_2D:
    186 		case glu::TYPE_INT_SAMPLER_CUBE:
    187 		case glu::TYPE_INT_SAMPLER_2D_ARRAY:
    188 		case glu::TYPE_INT_SAMPLER_3D:
    189 			return glu::TYPE_INT_VEC4;
    190 
    191 		case glu::TYPE_SAMPLER_2D_SHADOW:
    192 		case glu::TYPE_SAMPLER_CUBE_SHADOW:
    193 		case glu::TYPE_SAMPLER_2D_ARRAY_SHADOW:
    194 			return glu::TYPE_FLOAT;
    195 
    196 		default:
    197 			DE_ASSERT(false);
    198 			return glu::TYPE_LAST;
    199 	}
    200 }
    201 
    202 template<glu::DataType T>
    203 static bool dataTypeEquals (const glu::DataType t)
    204 {
    205 	return t == T;
    206 }
    207 
    208 template<int N>
    209 static bool dataTypeIsMatrixWithNRows (const glu::DataType t)
    210 {
    211 	return glu::isDataTypeMatrix(t) && glu::getDataTypeMatrixNumRows(t) == N;
    212 }
    213 
    214 static bool typeContainsMatchingBasicType (const glu::VarType& type, const dataTypePredicate predicate)
    215 {
    216 	if (type.isBasicType())
    217 		return predicate(type.getBasicType());
    218 	else if (type.isArrayType())
    219 		return typeContainsMatchingBasicType(type.getElementType(), predicate);
    220 	else
    221 	{
    222 		DE_ASSERT(type.isStructType());
    223 		const StructType& structType = *type.getStructPtr();
    224 		for (int i = 0; i < structType.getNumMembers(); i++)
    225 			if (typeContainsMatchingBasicType(structType.getMember(i).getType(), predicate))
    226 				return true;
    227 		return false;
    228 	}
    229 }
    230 
    231 static void getDistinctSamplerTypes (vector<glu::DataType>& dst, const glu::VarType& type)
    232 {
    233 	if (type.isBasicType())
    234 	{
    235 		const glu::DataType basicType = type.getBasicType();
    236 		if (glu::isDataTypeSampler(basicType) && std::find(dst.begin(), dst.end(), basicType) == dst.end())
    237 			dst.push_back(basicType);
    238 	}
    239 	else if (type.isArrayType())
    240 		getDistinctSamplerTypes(dst, type.getElementType());
    241 	else
    242 	{
    243 		DE_ASSERT(type.isStructType());
    244 		const StructType& structType = *type.getStructPtr();
    245 		for (int i = 0; i < structType.getNumMembers(); i++)
    246 			getDistinctSamplerTypes(dst, structType.getMember(i).getType());
    247 	}
    248 }
    249 
    250 static int getNumSamplersInType (const glu::VarType& type)
    251 {
    252 	if (type.isBasicType())
    253 		return glu::isDataTypeSampler(type.getBasicType()) ? 1 : 0;
    254 	else if (type.isArrayType())
    255 		return getNumSamplersInType(type.getElementType()) * type.getArraySize();
    256 	else
    257 	{
    258 		DE_ASSERT(type.isStructType());
    259 		const StructType& structType = *type.getStructPtr();
    260 		int sum = 0;
    261 		for (int i = 0; i < structType.getNumMembers(); i++)
    262 			sum += getNumSamplersInType(structType.getMember(i).getType());
    263 		return sum;
    264 	}
    265 }
    266 
    267 static glu::VarType generateRandomType (const int maxDepth, int& curStructIdx, vector<const StructType*>& structTypesDst, Random& rnd)
    268 {
    269 	const bool isStruct		= maxDepth > 0 && rnd.getFloat() < 0.2f;
    270 	const bool isArray		= rnd.getFloat() < 0.3f;
    271 
    272 	if (isStruct)
    273 	{
    274 		const int			numMembers = rnd.getInt(1, 5);
    275 		StructType* const	structType = new StructType(("structType" + de::toString(curStructIdx++)).c_str());
    276 
    277 		for (int i = 0; i < numMembers; i++)
    278 			structType->addMember(("m" + de::toString(i)).c_str(), generateRandomType(maxDepth-1, curStructIdx, structTypesDst, rnd));
    279 
    280 		structTypesDst.push_back(structType);
    281 		return isArray ? glu::VarType(glu::VarType(structType), rnd.getInt(1, 5)) : glu::VarType(structType);
    282 	}
    283 	else
    284 	{
    285 		const glu::DataType		basicType = (glu::DataType)s_testDataTypes[rnd.getInt(0, DE_LENGTH_OF_ARRAY(s_testDataTypes)-1)];
    286 		const glu::Precision	precision = glu::isDataTypeBoolOrBVec(basicType) ? glu::PRECISION_LAST : glu::PRECISION_MEDIUMP;
    287 		return isArray ? glu::VarType(glu::VarType(basicType, precision), rnd.getInt(1, 5)) : glu::VarType(basicType, precision);
    288 	}
    289 }
    290 
    291 namespace
    292 {
    293 
    294 struct VarValue
    295 {
    296 	glu::DataType type;
    297 
    298 	union
    299 	{
    300 		float		floatV[4*4]; // At most mat4. \note Matrices here are column-major.
    301 		deInt32		intV[4];
    302 		deUint32	uintV[4];
    303 		bool		boolV[4];
    304 		struct
    305 		{
    306 			int		unit;
    307 			union
    308 			{
    309 				float		floatV[4];
    310 				deInt32		intV[4];
    311 				deUint32	uintV[4];
    312 			} fillColor;
    313 		} samplerV;
    314 	} val;
    315 };
    316 
    317 enum CaseShaderType
    318 {
    319 	CASESHADERTYPE_VERTEX = 0,
    320 	CASESHADERTYPE_FRAGMENT,
    321 	CASESHADERTYPE_BOTH,
    322 
    323 	CASESHADERTYPE_LAST
    324 };
    325 
    326 struct Uniform
    327 {
    328 	string			name;
    329 	glu::VarType	type;
    330 
    331 	Uniform (const char* const name_, const glu::VarType& type_) : name(name_), type(type_) {}
    332 };
    333 
    334 // A set of uniforms, along with related struct types.
    335 class UniformCollection
    336 {
    337 public:
    338 	int					getNumUniforms		(void) const					{ return (int)m_uniforms.size();	}
    339 	int					getNumStructTypes	(void) const					{ return (int)m_structTypes.size();	}
    340 	Uniform&			getUniform			(const int ndx)					{ return m_uniforms[ndx];			}
    341 	const Uniform&		getUniform			(const int ndx) const			{ return m_uniforms[ndx];			}
    342 	const StructType*	getStructType		(const int ndx) const			{ return m_structTypes[ndx];		}
    343 	void				addUniform			(const Uniform& uniform)		{ m_uniforms.push_back(uniform);	}
    344 	void				addStructType		(const StructType* const type)	{ m_structTypes.push_back(type);	}
    345 
    346 	UniformCollection	(void) {}
    347 	~UniformCollection	(void)
    348 	{
    349 		for (int i = 0; i < (int)m_structTypes.size(); i++)
    350 			delete m_structTypes[i];
    351 	}
    352 
    353 	// Add the contents of m_uniforms and m_structTypes to receiver, and remove them from this one.
    354 	// \note receiver takes ownership of the struct types.
    355 	void moveContents (UniformCollection& receiver)
    356 	{
    357 		for (int i = 0; i < (int)m_uniforms.size(); i++)
    358 			receiver.addUniform(m_uniforms[i]);
    359 		m_uniforms.clear();
    360 
    361 		for (int i = 0; i < (int)m_structTypes.size(); i++)
    362 			receiver.addStructType(m_structTypes[i]);
    363 		m_structTypes.clear();
    364 	}
    365 
    366 	bool containsMatchingBasicType (const dataTypePredicate predicate) const
    367 	{
    368 		for (int i = 0; i < (int)m_uniforms.size(); i++)
    369 			if (typeContainsMatchingBasicType(m_uniforms[i].type, predicate))
    370 				return true;
    371 		return false;
    372 	}
    373 
    374 	vector<glu::DataType> getSamplerTypes (void) const
    375 	{
    376 		vector<glu::DataType> samplerTypes;
    377 		for (int i = 0; i < (int)m_uniforms.size(); i++)
    378 			getDistinctSamplerTypes(samplerTypes, m_uniforms[i].type);
    379 		return samplerTypes;
    380 	}
    381 
    382 	bool containsSeveralSamplerTypes (void) const
    383 	{
    384 		return getSamplerTypes().size() > 1;
    385 	}
    386 
    387 	int getNumSamplers (void) const
    388 	{
    389 		int sum = 0;
    390 		for (int i = 0; i < (int)m_uniforms.size(); i++)
    391 			sum += getNumSamplersInType(m_uniforms[i].type);
    392 		return sum;
    393 	}
    394 
    395 	static UniformCollection* basic (const glu::DataType type, const char* const nameSuffix = "")
    396 	{
    397 		UniformCollection* const	res		= new UniformCollection;
    398 		const glu::Precision		prec	= glu::isDataTypeBoolOrBVec(type) ? glu::PRECISION_LAST : glu::PRECISION_MEDIUMP;
    399 		res->m_uniforms.push_back(Uniform((string("u_var") + nameSuffix).c_str(), glu::VarType(type, prec)));
    400 		return res;
    401 	}
    402 
    403 	static UniformCollection* basicArray (const glu::DataType type, const char* const nameSuffix = "")
    404 	{
    405 		UniformCollection* const	res		= new UniformCollection;
    406 		const glu::Precision		prec	= glu::isDataTypeBoolOrBVec(type) ? glu::PRECISION_LAST : glu::PRECISION_MEDIUMP;
    407 		res->m_uniforms.push_back(Uniform((string("u_var") + nameSuffix).c_str(), glu::VarType(glu::VarType(type, prec), 3)));
    408 		return res;
    409 	}
    410 
    411 	static UniformCollection* basicStruct (const glu::DataType type0, const glu::DataType type1, const bool containsArrays, const char* const nameSuffix = "")
    412 	{
    413 		UniformCollection* const	res		= new UniformCollection;
    414 		const glu::Precision		prec0	= glu::isDataTypeBoolOrBVec(type0) ? glu::PRECISION_LAST : glu::PRECISION_MEDIUMP;
    415 		const glu::Precision		prec1	= glu::isDataTypeBoolOrBVec(type1) ? glu::PRECISION_LAST : glu::PRECISION_MEDIUMP;
    416 
    417 		StructType* const structType = new StructType((string("structType") + nameSuffix).c_str());
    418 		structType->addMember("m0", glu::VarType(type0, prec0));
    419 		structType->addMember("m1", glu::VarType(type1, prec1));
    420 		if (containsArrays)
    421 		{
    422 			structType->addMember("m2", glu::VarType(glu::VarType(type0, prec0), 3));
    423 			structType->addMember("m3", glu::VarType(glu::VarType(type1, prec1), 3));
    424 		}
    425 
    426 		res->addStructType(structType);
    427 		res->addUniform(Uniform((string("u_var") + nameSuffix).c_str(), glu::VarType(structType)));
    428 
    429 		return res;
    430 	}
    431 
    432 	static UniformCollection* structInArray (const glu::DataType type0, const glu::DataType type1, const bool containsArrays, const char* const nameSuffix = "")
    433 	{
    434 		UniformCollection* const res = basicStruct(type0, type1, containsArrays, nameSuffix);
    435 		res->getUniform(0).type = glu::VarType(res->getUniform(0).type, 3);
    436 		return res;
    437 	}
    438 
    439 	static UniformCollection* nestedArraysStructs (const glu::DataType type0, const glu::DataType type1, const char* const nameSuffix = "")
    440 	{
    441 		UniformCollection* const res		= new UniformCollection;
    442 		const glu::Precision prec0			= glu::isDataTypeBoolOrBVec(type0) ? glu::PRECISION_LAST : glu::PRECISION_MEDIUMP;
    443 		const glu::Precision prec1			= glu::isDataTypeBoolOrBVec(type1) ? glu::PRECISION_LAST : glu::PRECISION_MEDIUMP;
    444 		StructType* const structType		= new StructType((string("structType") + nameSuffix).c_str());
    445 		StructType* const subStructType		= new StructType((string("subStructType") + nameSuffix).c_str());
    446 		StructType* const subSubStructType	= new StructType((string("subSubStructType") + nameSuffix).c_str());
    447 
    448 		subSubStructType->addMember("mss0", glu::VarType(type0, prec0));
    449 		subSubStructType->addMember("mss1", glu::VarType(type1, prec1));
    450 
    451 		subStructType->addMember("ms0", glu::VarType(type1, prec1));
    452 		subStructType->addMember("ms1", glu::VarType(glu::VarType(type0, prec0), 2));
    453 		subStructType->addMember("ms2", glu::VarType(glu::VarType(subSubStructType), 2));
    454 
    455 		structType->addMember("m0", glu::VarType(type0, prec0));
    456 		structType->addMember("m1", glu::VarType(subStructType));
    457 		structType->addMember("m2", glu::VarType(type1, prec1));
    458 
    459 		res->addStructType(subSubStructType);
    460 		res->addStructType(subStructType);
    461 		res->addStructType(structType);
    462 
    463 		res->addUniform(Uniform((string("u_var") + nameSuffix).c_str(), glu::VarType(structType)));
    464 
    465 		return res;
    466 	}
    467 
    468 	static UniformCollection* multipleBasic (const char* const nameSuffix = "")
    469 	{
    470 		static const glu::DataType	types[]	= { glu::TYPE_FLOAT, glu::TYPE_INT_VEC3, glu::TYPE_UINT_VEC4, glu::TYPE_FLOAT_MAT3, glu::TYPE_BOOL_VEC2 };
    471 		UniformCollection* const	res		= new UniformCollection;
    472 
    473 		for (int i = 0; i < DE_LENGTH_OF_ARRAY(types); i++)
    474 		{
    475 			UniformCollection* const sub = basic(types[i], ("_" + de::toString(i) + nameSuffix).c_str());
    476 			sub->moveContents(*res);
    477 			delete sub;
    478 		}
    479 
    480 		return res;
    481 	}
    482 
    483 	static UniformCollection* multipleBasicArray (const char* const nameSuffix = "")
    484 	{
    485 		static const glu::DataType	types[]	= { glu::TYPE_FLOAT, glu::TYPE_INT_VEC3, glu::TYPE_BOOL_VEC2 };
    486 		UniformCollection* const	res		= new UniformCollection;
    487 
    488 		for (int i = 0; i < DE_LENGTH_OF_ARRAY(types); i++)
    489 		{
    490 			UniformCollection* const sub = basicArray(types[i], ("_" + de::toString(i) + nameSuffix).c_str());
    491 			sub->moveContents(*res);
    492 			delete sub;
    493 		}
    494 
    495 		return res;
    496 	}
    497 
    498 	static UniformCollection* multipleNestedArraysStructs (const char* const nameSuffix = "")
    499 	{
    500 		static const glu::DataType	types0[]	= { glu::TYPE_FLOAT,		glu::TYPE_INT,		glu::TYPE_BOOL_VEC4 };
    501 		static const glu::DataType	types1[]	= { glu::TYPE_FLOAT_VEC4,	glu::TYPE_INT_VEC4,	glu::TYPE_BOOL };
    502 		UniformCollection* const	res			= new UniformCollection;
    503 
    504 		DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(types0) == DE_LENGTH_OF_ARRAY(types1));
    505 
    506 		for (int i = 0; i < DE_LENGTH_OF_ARRAY(types0); i++)
    507 		{
    508 			UniformCollection* const sub = nestedArraysStructs(types0[i], types1[i], ("_" + de::toString(i) + nameSuffix).c_str());
    509 			sub->moveContents(*res);
    510 			delete sub;
    511 		}
    512 
    513 		return res;
    514 	}
    515 
    516 	static UniformCollection* random (const deUint32 seed)
    517 	{
    518 		Random						rnd			(seed);
    519 		const int					numUniforms	= rnd.getInt(1, 5);
    520 		int							structIdx	= 0;
    521 		UniformCollection* const	res			= new UniformCollection;
    522 
    523 		for (int i = 0; i < numUniforms; i++)
    524 		{
    525 			vector<const StructType*>	structTypes;
    526 			Uniform						uniform(("u_var" + de::toString(i)).c_str(), glu::VarType());
    527 
    528 			// \note Discard uniforms that would cause number of samplers to exceed MAX_NUM_SAMPLER_UNIFORMS.
    529 			do
    530 			{
    531 				for (int j = 0; j < (int)structTypes.size(); j++)
    532 					delete structTypes[j];
    533 				structTypes.clear();
    534 				uniform.type = (("u_var" + de::toString(i)).c_str(), generateRandomType(3, structIdx, structTypes, rnd));
    535 			} while (res->getNumSamplers() + getNumSamplersInType(uniform.type) > MAX_NUM_SAMPLER_UNIFORMS);
    536 
    537 			res->addUniform(uniform);
    538 			for (int j = 0; j < (int)structTypes.size(); j++)
    539 				res->addStructType(structTypes[j]);
    540 		}
    541 
    542 		return res;
    543 	}
    544 
    545 private:
    546 	// \note Copying these would be cumbersome, since deep-copying both m_uniforms and m_structTypes
    547 	// would mean that we'd need to update pointers from uniforms to point to the new structTypes.
    548 	// When the same UniformCollection is needed in several places, a SharedPtr is used instead.
    549 								UniformCollection	(const UniformCollection&); // Not allowed.
    550 	UniformCollection&			operator=			(const UniformCollection&); // Not allowed.
    551 
    552 	vector<Uniform>				m_uniforms;
    553 	vector<const StructType*>	m_structTypes;
    554 };
    555 
    556 }; // anonymous
    557 
    558 static VarValue getSamplerFillValue (const VarValue& sampler)
    559 {
    560 	DE_ASSERT(glu::isDataTypeSampler(sampler.type));
    561 
    562 	VarValue result;
    563 	result.type = getSamplerLookupReturnType(sampler.type);
    564 
    565 	switch (result.type)
    566 	{
    567 		case glu::TYPE_FLOAT_VEC4:
    568 			for (int i = 0; i < 4; i++)
    569 				result.val.floatV[i] = sampler.val.samplerV.fillColor.floatV[i];
    570 			break;
    571 		case glu::TYPE_UINT_VEC4:
    572 			for (int i = 0; i < 4; i++)
    573 				result.val.uintV[i] = sampler.val.samplerV.fillColor.uintV[i];
    574 			break;
    575 		case glu::TYPE_INT_VEC4:
    576 			for (int i = 0; i < 4; i++)
    577 				result.val.intV[i] = sampler.val.samplerV.fillColor.intV[i];
    578 			break;
    579 		case glu::TYPE_FLOAT:
    580 			result.val.floatV[0] = sampler.val.samplerV.fillColor.floatV[0];
    581 			break;
    582 		default:
    583 			DE_ASSERT(false);
    584 	}
    585 
    586 	return result;
    587 }
    588 
    589 static VarValue getSamplerUnitValue (const VarValue& sampler)
    590 {
    591 	DE_ASSERT(glu::isDataTypeSampler(sampler.type));
    592 
    593 	VarValue result;
    594 	result.type = glu::TYPE_INT;
    595 	result.val.intV[0] = sampler.val.samplerV.unit;
    596 
    597 	return result;
    598 }
    599 
    600 static glu::DataType getDataTypeTransposedMatrix (const glu::DataType original)
    601 {
    602 	return glu::getDataTypeMatrix(glu::getDataTypeMatrixNumRows(original), glu::getDataTypeMatrixNumColumns(original));
    603 }
    604 
    605 static VarValue getTransposeMatrix (const VarValue& original)
    606 {
    607 	DE_ASSERT(glu::isDataTypeMatrix(original.type));
    608 
    609 	const int	rows = glu::getDataTypeMatrixNumRows(original.type);
    610 	const int	cols = glu::getDataTypeMatrixNumColumns(original.type);
    611 	VarValue	result;
    612 	result.type = getDataTypeTransposedMatrix(original.type);
    613 
    614 	for (int i = 0; i < rows; i++)
    615 	for (int j = 0; j < cols; j++)
    616 		result.val.floatV[i*cols + j] = original.val.floatV[j*rows + i];
    617 
    618 	return result;
    619 }
    620 
    621 static string shaderVarValueStr (const VarValue& value)
    622 {
    623 	const int			numElems = glu::getDataTypeScalarSize(value.type);
    624 	std::ostringstream	result;
    625 
    626 	if (numElems > 1)
    627 		result << glu::getDataTypeName(value.type) << "(";
    628 
    629 	for (int i = 0; i < numElems; i++)
    630 	{
    631 		if (i > 0)
    632 			result << ", ";
    633 
    634 		if (glu::isDataTypeFloatOrVec(value.type) || glu::isDataTypeMatrix(value.type))
    635 			result << de::floatToString(value.val.floatV[i], 2);
    636 		else if (glu::isDataTypeIntOrIVec((value.type)))
    637 			result << de::toString(value.val.intV[i]);
    638 		else if (glu::isDataTypeUintOrUVec((value.type)))
    639 			result << de::toString(value.val.uintV[i]) << "u";
    640 		else if (glu::isDataTypeBoolOrBVec((value.type)))
    641 			result << (value.val.boolV[i] ? "true" : "false");
    642 		else if (glu::isDataTypeSampler((value.type)))
    643 			result << shaderVarValueStr(getSamplerFillValue(value));
    644 		else
    645 			DE_ASSERT(false);
    646 	}
    647 
    648 	if (numElems > 1)
    649 		result << ")";
    650 
    651 	return result.str();
    652 }
    653 
    654 static string apiVarValueStr (const VarValue& value)
    655 {
    656 	const int			numElems = glu::getDataTypeScalarSize(value.type);
    657 	std::ostringstream	result;
    658 
    659 	if (numElems > 1)
    660 		result << "(";
    661 
    662 	for (int i = 0; i < numElems; i++)
    663 	{
    664 		if (i > 0)
    665 			result << ", ";
    666 
    667 		if (glu::isDataTypeFloatOrVec(value.type) || glu::isDataTypeMatrix(value.type))
    668 			result << de::floatToString(value.val.floatV[i], 2);
    669 		else if (glu::isDataTypeIntOrIVec((value.type)))
    670 			result << de::toString(value.val.intV[i]);
    671 		else if (glu::isDataTypeUintOrUVec((value.type)))
    672 			result << de::toString(value.val.uintV[i]);
    673 		else if (glu::isDataTypeBoolOrBVec((value.type)))
    674 			result << (value.val.boolV[i] ? "true" : "false");
    675 		else if (glu::isDataTypeSampler((value.type)))
    676 			result << value.val.samplerV.unit;
    677 		else
    678 			DE_ASSERT(false);
    679 	}
    680 
    681 	if (numElems > 1)
    682 		result << ")";
    683 
    684 	return result.str();
    685 }
    686 
    687 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. */)
    688 {
    689 	const int	numElems = glu::getDataTypeScalarSize(type);
    690 	VarValue	result;
    691 	result.type = type;
    692 
    693 	DE_ASSERT((samplerUnit >= 0) == (glu::isDataTypeSampler(type)));
    694 
    695 	if (glu::isDataTypeFloatOrVec(type) || glu::isDataTypeMatrix(type))
    696 	{
    697 		for (int i = 0; i < numElems; i++)
    698 			result.val.floatV[i] = rnd.getFloat(-10.0f, 10.0f);
    699 	}
    700 	else if (glu::isDataTypeIntOrIVec(type))
    701 	{
    702 		for (int i = 0; i < numElems; i++)
    703 			result.val.intV[i] = rnd.getInt(-10, 10);
    704 	}
    705 	else if (glu::isDataTypeUintOrUVec(type))
    706 	{
    707 		for (int i = 0; i < numElems; i++)
    708 			result.val.uintV[i] = (deUint32)rnd.getInt(0, 10);
    709 	}
    710 	else if (glu::isDataTypeBoolOrBVec(type))
    711 	{
    712 		for (int i = 0; i < numElems; i++)
    713 			result.val.boolV[i] = rnd.getBool();
    714 	}
    715 	else if (glu::isDataTypeSampler(type))
    716 	{
    717 		const glu::DataType		texResultType		= getSamplerLookupReturnType(type);
    718 		const glu::DataType		texResultScalarType	= glu::getDataTypeScalarType(texResultType);
    719 		const int				texResultNumDims	= glu::getDataTypeScalarSize(texResultType);
    720 
    721 		result.val.samplerV.unit = samplerUnit;
    722 
    723 		for (int i = 0; i < texResultNumDims; i++)
    724 		{
    725 			switch (texResultScalarType)
    726 			{
    727 				case glu::TYPE_FLOAT:	result.val.samplerV.fillColor.floatV[i]		= rnd.getFloat(0.0f, 1.0f);		break;
    728 				case glu::TYPE_INT:		result.val.samplerV.fillColor.intV[i]		= rnd.getInt(-10, 10);			break;
    729 				case glu::TYPE_UINT:	result.val.samplerV.fillColor.uintV[i]		= (deUint32)rnd.getInt(0, 10);	break;
    730 				default:
    731 					DE_ASSERT(false);
    732 			}
    733 		}
    734 	}
    735 	else
    736 		DE_ASSERT(false);
    737 
    738 	return result;
    739 }
    740 
    741 static VarValue generateZeroVarValue (const glu::DataType type)
    742 {
    743 	const int	numElems = glu::getDataTypeScalarSize(type);
    744 	VarValue	result;
    745 	result.type = type;
    746 
    747 	if (glu::isDataTypeFloatOrVec(type) || glu::isDataTypeMatrix(type))
    748 	{
    749 		for (int i = 0; i < numElems; i++)
    750 			result.val.floatV[i] = 0.0f;
    751 	}
    752 	else if (glu::isDataTypeIntOrIVec(type))
    753 	{
    754 		for (int i = 0; i < numElems; i++)
    755 			result.val.intV[i] = 0;
    756 	}
    757 	else if (glu::isDataTypeUintOrUVec(type))
    758 	{
    759 		for (int i = 0; i < numElems; i++)
    760 			result.val.uintV[i] = 0u;
    761 	}
    762 	else if (glu::isDataTypeBoolOrBVec(type))
    763 	{
    764 		for (int i = 0; i < numElems; i++)
    765 			result.val.boolV[i] = false;
    766 	}
    767 	else if (glu::isDataTypeSampler(type))
    768 	{
    769 		const glu::DataType		texResultType		= getSamplerLookupReturnType(type);
    770 		const glu::DataType		texResultScalarType	= glu::getDataTypeScalarType(texResultType);
    771 		const int				texResultNumDims	= glu::getDataTypeScalarSize(texResultType);
    772 
    773 		result.val.samplerV.unit = 0;
    774 
    775 		for (int i = 0; i < texResultNumDims; i++)
    776 		{
    777 			switch (texResultScalarType)
    778 			{
    779 				case glu::TYPE_FLOAT:	result.val.samplerV.fillColor.floatV[i]		= 0.12f * (float)i;	break;
    780 				case glu::TYPE_INT:		result.val.samplerV.fillColor.intV[i]		= -2 + i;			break;
    781 				case glu::TYPE_UINT:	result.val.samplerV.fillColor.uintV[i]		= 4 + i;			break;
    782 				default:
    783 					DE_ASSERT(false);
    784 			}
    785 		}
    786 	}
    787 	else
    788 		DE_ASSERT(false);
    789 
    790 	return result;
    791 }
    792 
    793 static bool apiVarValueEquals (const VarValue& a, const VarValue& b)
    794 {
    795 	const int		size			= glu::getDataTypeScalarSize(a.type);
    796 	const float		floatThreshold	= 0.05f;
    797 
    798 	DE_ASSERT(a.type == b.type);
    799 
    800 	if (glu::isDataTypeFloatOrVec(a.type) || glu::isDataTypeMatrix(a.type))
    801 	{
    802 		for (int i = 0; i < size; i++)
    803 			if (de::abs(a.val.floatV[i] - b.val.floatV[i]) >= floatThreshold)
    804 				return false;
    805 	}
    806 	else if (glu::isDataTypeIntOrIVec(a.type))
    807 	{
    808 		for (int i = 0; i < size; i++)
    809 			if (a.val.intV[i] != b.val.intV[i])
    810 				return false;
    811 	}
    812 	else if (glu::isDataTypeUintOrUVec(a.type))
    813 	{
    814 		for (int i = 0; i < size; i++)
    815 			if (a.val.uintV[i] != b.val.uintV[i])
    816 				return false;
    817 	}
    818 	else if (glu::isDataTypeBoolOrBVec(a.type))
    819 	{
    820 		for (int i = 0; i < size; i++)
    821 			if (a.val.boolV[i] != b.val.boolV[i])
    822 				return false;
    823 	}
    824 	else if (glu::isDataTypeSampler(a.type))
    825 	{
    826 		if (a.val.samplerV.unit != b.val.samplerV.unit)
    827 			return false;
    828 	}
    829 	else
    830 		DE_ASSERT(false);
    831 
    832 	return true;
    833 }
    834 
    835 static VarValue getRandomBoolRepresentation (const VarValue& boolValue, const glu::DataType targetScalarType, Random& rnd)
    836 {
    837 	DE_ASSERT(glu::isDataTypeBoolOrBVec(boolValue.type));
    838 
    839 	const int				size		= glu::getDataTypeScalarSize(boolValue.type);
    840 	const glu::DataType		targetType	= size == 1 ? targetScalarType : glu::getDataTypeVector(targetScalarType, size);
    841 	VarValue				result;
    842 	result.type = targetType;
    843 
    844 	switch (targetScalarType)
    845 	{
    846 		case glu::TYPE_INT:
    847 			for (int i = 0; i < size; i++)
    848 			{
    849 				if (boolValue.val.boolV[i])
    850 				{
    851 					result.val.intV[i] = rnd.getInt(-10, 10);
    852 					if (result.val.intV[i] == 0)
    853 						result.val.intV[i] = 1;
    854 				}
    855 				else
    856 					result.val.intV[i] = 0;
    857 			}
    858 			break;
    859 
    860 		case glu::TYPE_UINT:
    861 			for (int i = 0; i < size; i++)
    862 			{
    863 				if (boolValue.val.boolV[i])
    864 					result.val.uintV[i] = rnd.getInt(1, 10);
    865 				else
    866 					result.val.uintV[i] = 0;
    867 			}
    868 			break;
    869 
    870 		case glu::TYPE_FLOAT:
    871 			for (int i = 0; i < size; i++)
    872 			{
    873 				if (boolValue.val.boolV[i])
    874 				{
    875 					result.val.floatV[i] = rnd.getFloat(-10.0f, 10.0f);
    876 					if (result.val.floatV[i] == 0.0f)
    877 						result.val.floatV[i] = 1.0f;
    878 				}
    879 				else
    880 					result.val.floatV[i] = 0;
    881 			}
    882 			break;
    883 
    884 		default:
    885 			DE_ASSERT(false);
    886 	}
    887 
    888 	return result;
    889 }
    890 
    891 static const char* getCaseShaderTypeName (const CaseShaderType type)
    892 {
    893 	switch (type)
    894 	{
    895 		case CASESHADERTYPE_VERTEX:		return "vertex";
    896 		case CASESHADERTYPE_FRAGMENT:	return "fragment";
    897 		case CASESHADERTYPE_BOTH:		return "both";
    898 		default:
    899 			DE_ASSERT(false);
    900 			return DE_NULL;
    901 	}
    902 }
    903 
    904 static CaseShaderType randomCaseShaderType (const deUint32 seed)
    905 {
    906 	return (CaseShaderType)Random(seed).getInt(0, CASESHADERTYPE_LAST-1);
    907 }
    908 
    909 class UniformCase : public TestCase, protected glu::CallLogWrapper
    910 {
    911 public:
    912 	enum Feature
    913 	{
    914 		// ARRAYUSAGE_ONLY_MIDDLE_INDEX: only middle index of each array is used in shader. If not given, use all indices.
    915 		FEATURE_ARRAYUSAGE_ONLY_MIDDLE_INDEX	= 1<<0,
    916 
    917 		// UNIFORMFUNC_VALUE: use pass-by-value versions of uniform assignment funcs, e.g. glUniform1f(), where possible. If not given, use pass-by-pointer versions.
    918 		FEATURE_UNIFORMFUNC_VALUE				= 1<<1,
    919 
    920 		// MATRIXMODE_ROWMAJOR: pass matrices to GL in row major form. If not given, use column major.
    921 		FEATURE_MATRIXMODE_ROWMAJOR				= 1<<2,
    922 
    923 		// ARRAYASSIGN: how basic-type arrays are assigned with glUniform*(). If none given, assign each element of an array separately.
    924 		FEATURE_ARRAYASSIGN_FULL				= 1<<3, //!< Assign all elements of an array with one glUniform*().
    925 		FEATURE_ARRAYASSIGN_BLOCKS_OF_TWO		= 1<<4, //!< Assign two elements per one glUniform*().
    926 
    927 		// 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).
    928 		FEATURE_UNIFORMUSAGE_EVERY_OTHER		= 1<<5,
    929 
    930 		// BOOLEANAPITYPE: type used to pass booleans to and from GL api. If none given, use float.
    931 		FEATURE_BOOLEANAPITYPE_INT				= 1<<6,
    932 		FEATURE_BOOLEANAPITYPE_UINT				= 1<<7,
    933 
    934 		// UNIFORMVALUE_ZERO: use zero-valued uniforms. If not given, use random uniform values.
    935 		FEATURE_UNIFORMVALUE_ZERO				= 1<<8,
    936 
    937 		// 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.
    938 		FEATURE_ARRAY_FIRST_ELEM_NAME_NO_INDEX	= 1<<9
    939 	};
    940 
    941 								UniformCase		(Context& context, const char* name, const char* description, CaseShaderType caseType, const SharedPtr<const UniformCollection>& uniformCollection);
    942 								UniformCase		(Context& context, const char* name, const char* description, CaseShaderType caseType, const SharedPtr<const UniformCollection>& uniformCollection, deUint32 features);
    943 								UniformCase		(Context& context, const char* name, const char* description, deUint32 seed); // \note Randomizes caseType, uniformCollection and features.
    944 	virtual						~UniformCase	(void);
    945 
    946 	virtual void				init			(void);
    947 	virtual void				deinit			(void);
    948 
    949 	IterateResult				iterate			(void);
    950 
    951 protected:
    952 	// A basic uniform is a uniform (possibly struct or array member) whose type is a basic type (e.g. float, ivec4, sampler2d).
    953 	struct BasicUniform
    954 	{
    955 		string			name;
    956 		glu::DataType	type;
    957 		bool			isUsedInShader;
    958 		VarValue		finalValue;	//!< The value we ultimately want to set for this uniform.
    959 
    960 		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.
    961 		int				elemNdx;	//!< If this is a member of a basic-typed array, elemNdx is the index in that array. Otherwise -1.
    962 		int				rootSize;	//!< If this is a member of a basic-typed array, rootSize is the size of that array. Otherwise 1.
    963 
    964 		BasicUniform (const char* const		name_,
    965 					  const glu::DataType	type_,
    966 					  const bool			isUsedInShader_,
    967 					  const VarValue&		finalValue_,
    968 					  const char* const		rootName_	= DE_NULL,
    969 					  const int				elemNdx_	= -1,
    970 					  const int				rootSize_	= 1)
    971 					  : name			(name_)
    972 					  , type			(type_)
    973 					  , isUsedInShader	(isUsedInShader_)
    974 					  , finalValue		(finalValue_)
    975 					  , rootName		(rootName_ == DE_NULL ? name_ : rootName_)
    976 					  , elemNdx			(elemNdx_)
    977 					  , rootSize		(rootSize_)
    978 					 {
    979 					 }
    980 
    981 		static vector<BasicUniform>::const_iterator findWithName (const vector<BasicUniform>& vec, const char* const name)
    982 		{
    983 			for (vector<BasicUniform>::const_iterator it = vec.begin(); it != vec.end(); it++)
    984 			{
    985 				if (it->name == name)
    986 					return it;
    987 			}
    988 			return vec.end();
    989 		}
    990 	};
    991 
    992 	// Reference values for info that is expected to be reported by glGetActiveUniform() or glGetActiveUniformsiv().
    993 	struct BasicUniformReportRef
    994 	{
    995 		string			name;
    996 		// \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.
    997 		int				minSize;
    998 		int				maxSize;
    999 		glu::DataType	type;
   1000 		bool			isUsedInShader;
   1001 
   1002 		BasicUniformReportRef (const char* const name_, const int minS, const int maxS, const glu::DataType type_, const bool used)
   1003 			: name(name_), minSize(minS), maxSize(maxS), type(type_), isUsedInShader(used) { DE_ASSERT(minSize <= maxSize); }
   1004 		BasicUniformReportRef (const char* const name_, const glu::DataType type_, const bool used)
   1005 			: name(name_), minSize(1), maxSize(1), type(type_), isUsedInShader(used) {}
   1006 	};
   1007 
   1008 	// Info that is actually reported by glGetActiveUniform() or glGetActiveUniformsiv().
   1009 	struct BasicUniformReportGL
   1010 	{
   1011 		string			name;
   1012 		int				nameLength; // \note Whether this includes the null byte depends on whether it was queried with glGetActiveUniform() or glGetActiveUniformsiv().
   1013 		int				size;
   1014 		glu::DataType	type;
   1015 
   1016 		int				index;
   1017 
   1018 		BasicUniformReportGL (const char* const name_, const int nameLength_, const int size_, const glu::DataType type_, const int index_)
   1019 			: name(name_), nameLength(nameLength_), size(size_), type(type_), index(index_) {}
   1020 
   1021 		static vector<BasicUniformReportGL>::const_iterator findWithName (const vector<BasicUniformReportGL>& vec, const char* const name)
   1022 		{
   1023 			for (vector<BasicUniformReportGL>::const_iterator it = vec.begin(); it != vec.end(); it++)
   1024 			{
   1025 				if (it->name == name)
   1026 					return it;
   1027 			}
   1028 			return vec.end();
   1029 		}
   1030 	};
   1031 
   1032 	// Query info with glGetActiveUniform() and check validity.
   1033 	bool						getActiveUniforms						(vector<BasicUniformReportGL>& dst, const vector<BasicUniformReportRef>& ref, deUint32 programGL);
   1034 	// Query info with glGetUniformIndices() + glGetActiveUniformsiv() and check validity.
   1035 	bool						getActiveUniformsiv						(vector<BasicUniformReportGL>& dst, const vector<BasicUniformReportRef>& ref, deUint32 programGL);
   1036 	// Compare infos returned by glGetActiveUniform() and glGetUniformIndices() + glGetActiveUniformsiv().
   1037 	bool						uniformVsUniformsivComparison			(const vector<BasicUniformReportGL>& uniformsResult, const vector<BasicUniformReportGL>& uniformsivResult);
   1038 	// Get uniform values with glGetUniform*() and put to valuesDst. Uniforms that get -1 from glGetUniformLocation() get glu::TYPE_INVALID.
   1039 	bool						getUniforms								(vector<VarValue>& valuesDst, const vector<BasicUniform>& basicUniforms, deUint32 programGL);
   1040 	// Check that every uniform has the default (zero) value.
   1041 	bool						checkUniformDefaultValues				(const vector<VarValue>& values, const vector<BasicUniform>& basicUniforms);
   1042 	// Assign the basicUniforms[].finalValue values for uniforms. \note rnd parameter is for booleans (true can be any nonzero value).
   1043 	void						assignUniforms							(const vector<BasicUniform>& basicUniforms, deUint32 programGL, Random& rnd);
   1044 	// Compare the uniform values given in values (obtained with glGetUniform*()) with the basicUniform.finalValue values.
   1045 	bool						compareUniformValues					(const vector<VarValue>& values, const vector<BasicUniform>& basicUniforms);
   1046 	// Render and check that all pixels are white (i.e. all uniform comparisons passed).
   1047 	bool						renderTest								(const vector<BasicUniform>& basicUniforms, const ShaderProgram& program, Random& rnd);
   1048 
   1049 	virtual bool				test									(const vector<BasicUniform>& basicUniforms, const vector<BasicUniformReportRef>& basicUniformReportsRef, const ShaderProgram& program, Random& rnd) = 0;
   1050 
   1051 	const deUint32								m_features;
   1052 	const SharedPtr<const UniformCollection>	m_uniformCollection;
   1053 
   1054 private:
   1055 	static deUint32				randomFeatures							(deUint32 seed);
   1056 
   1057 	// Generates the basic uniforms, based on the uniform with name varName and type varType, in the same manner as are expected
   1058 	// to be returned by glGetActiveUniform(), e.g. generates a name like var[0] for arrays, and recursively generates struct member names.
   1059 	void						generateBasicUniforms					(vector<BasicUniform>&				basicUniformsDst,
   1060 																		 vector<BasicUniformReportRef>&		basicUniformReportsDst,
   1061 																		 const glu::VarType&				varType,
   1062 																		 const char*						varName,
   1063 																		 bool								isParentActive,
   1064 																		 int&								samplerUnitCounter,
   1065 																		 Random&							rnd) const;
   1066 
   1067 	void						writeUniformDefinitions					(std::ostringstream& dst) const;
   1068 	void						writeUniformCompareExpr					(std::ostringstream& dst, const BasicUniform& uniform) const;
   1069 	void						writeUniformComparisons					(std::ostringstream& dst, const vector<BasicUniform>& basicUniforms, const char* variableName) const;
   1070 
   1071 	string						generateVertexSource					(const vector<BasicUniform>& basicUniforms) const;
   1072 	string						generateFragmentSource					(const vector<BasicUniform>& basicUniforms) const;
   1073 
   1074 	void						setupTexture							(const VarValue& value);
   1075 
   1076 	const CaseShaderType						m_caseShaderType;
   1077 
   1078 	vector<glu::Texture2D*>						m_textures2d;
   1079 	vector<glu::TextureCube*>					m_texturesCube;
   1080 	vector<deUint32>							m_filledTextureUnits;
   1081 };
   1082 
   1083 deUint32 UniformCase::randomFeatures (const deUint32 seed)
   1084 {
   1085 	static const deUint32 arrayUsageChoices[]		= { 0, FEATURE_ARRAYUSAGE_ONLY_MIDDLE_INDEX										};
   1086 	static const deUint32 uniformFuncChoices[]		= { 0, FEATURE_UNIFORMFUNC_VALUE												};
   1087 	static const deUint32 matrixModeChoices[]		= { 0, FEATURE_MATRIXMODE_ROWMAJOR												};
   1088 	static const deUint32 arrayAssignChoices[]		= { 0, FEATURE_ARRAYASSIGN_FULL,			FEATURE_ARRAYASSIGN_BLOCKS_OF_TWO	};
   1089 	static const deUint32 uniformUsageChoices[]		= { 0, FEATURE_UNIFORMUSAGE_EVERY_OTHER											};
   1090 	static const deUint32 booleanApiTypeChoices[]	= { 0, FEATURE_BOOLEANAPITYPE_INT,			FEATURE_BOOLEANAPITYPE_UINT			};
   1091 	static const deUint32 uniformValueChoices[]		= { 0, FEATURE_UNIFORMVALUE_ZERO												};
   1092 
   1093 	Random rnd(seed);
   1094 
   1095 	deUint32 result = 0;
   1096 
   1097 #define ARRAY_CHOICE(ARR) (ARR[rnd.getInt(0, DE_LENGTH_OF_ARRAY(ARR)-1)])
   1098 
   1099 	result |= ARRAY_CHOICE(arrayUsageChoices);
   1100 	result |= ARRAY_CHOICE(uniformFuncChoices);
   1101 	result |= ARRAY_CHOICE(matrixModeChoices);
   1102 	result |= ARRAY_CHOICE(arrayAssignChoices);
   1103 	result |= ARRAY_CHOICE(uniformUsageChoices);
   1104 	result |= ARRAY_CHOICE(booleanApiTypeChoices);
   1105 	result |= ARRAY_CHOICE(uniformValueChoices);
   1106 
   1107 #undef ARRAY_CHOICE
   1108 
   1109 	return result;
   1110 }
   1111 
   1112 UniformCase::UniformCase (Context& context, const char* const name, const char* const description, const CaseShaderType caseShaderType, const SharedPtr<const UniformCollection>& uniformCollection, const deUint32 features)
   1113 	: TestCase				(context, name, description)
   1114 	, CallLogWrapper		(context.getRenderContext().getFunctions(), m_testCtx.getLog())
   1115 	, m_features			(features)
   1116 	, m_uniformCollection	(uniformCollection)
   1117 	, m_caseShaderType		(caseShaderType)
   1118 {
   1119 }
   1120 
   1121 UniformCase::UniformCase (Context& context, const char* const name, const char* const description, const CaseShaderType caseShaderType, const SharedPtr<const UniformCollection>& uniformCollection)
   1122 	: TestCase				(context, name, description)
   1123 	, CallLogWrapper		(context.getRenderContext().getFunctions(), m_testCtx.getLog())
   1124 	, m_features			(0)
   1125 	, m_uniformCollection	(uniformCollection)
   1126 	, m_caseShaderType		(caseShaderType)
   1127 {
   1128 }
   1129 
   1130 UniformCase::UniformCase (Context& context, const char* name, const char* description, const deUint32 seed)
   1131 	: TestCase				(context, name, description)
   1132 	, CallLogWrapper		(context.getRenderContext().getFunctions(), m_testCtx.getLog())
   1133 	, m_features			(randomFeatures(seed))
   1134 	, m_uniformCollection	(UniformCollection::random(seed))
   1135 	, m_caseShaderType		(randomCaseShaderType(seed))
   1136 {
   1137 }
   1138 
   1139 void UniformCase::init (void)
   1140 {
   1141 	{
   1142 		const glw::Functions&	funcs						= m_context.getRenderContext().getFunctions();
   1143 		const int				numSamplerUniforms			= m_uniformCollection->getNumSamplers();
   1144 		const int				vertexTexUnitsRequired		= m_caseShaderType != CASESHADERTYPE_FRAGMENT ? numSamplerUniforms : 0;
   1145 		const int				fragmentTexUnitsRequired	= m_caseShaderType != CASESHADERTYPE_VERTEX ? numSamplerUniforms : 0;
   1146 		const int				combinedTexUnitsRequired	= vertexTexUnitsRequired + fragmentTexUnitsRequired;
   1147 		const int				vertexTexUnitsSupported		= getGLInt(funcs, GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS);
   1148 		const int				fragmentTexUnitsSupported	= getGLInt(funcs, GL_MAX_TEXTURE_IMAGE_UNITS);
   1149 		const int				combinedTexUnitsSupported	= getGLInt(funcs, GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS);
   1150 
   1151 		DE_ASSERT(numSamplerUniforms <= MAX_NUM_SAMPLER_UNIFORMS);
   1152 
   1153 		if (vertexTexUnitsRequired > vertexTexUnitsSupported)
   1154 			throw tcu::NotSupportedError(de::toString(vertexTexUnitsRequired) + " vertex texture units required, " + de::toString(vertexTexUnitsSupported) + " supported");
   1155 		if (fragmentTexUnitsRequired > fragmentTexUnitsSupported)
   1156 			throw tcu::NotSupportedError(de::toString(fragmentTexUnitsRequired) + " fragment texture units required, " + de::toString(fragmentTexUnitsSupported) + " supported");
   1157 		if (combinedTexUnitsRequired > combinedTexUnitsSupported)
   1158 			throw tcu::NotSupportedError(de::toString(combinedTexUnitsRequired) + " combined texture units required, " + de::toString(combinedTexUnitsSupported) + " supported");
   1159 	}
   1160 
   1161 	enableLogging(true);
   1162 }
   1163 
   1164 void UniformCase::deinit (void)
   1165 {
   1166 	for (int i = 0; i < (int)m_textures2d.size(); i++)
   1167 		delete m_textures2d[i];
   1168 	m_textures2d.clear();
   1169 
   1170 	for (int i = 0; i < (int)m_texturesCube.size(); i++)
   1171 		delete m_texturesCube[i];
   1172 	m_texturesCube.clear();
   1173 
   1174 	m_filledTextureUnits.clear();
   1175 }
   1176 
   1177 UniformCase::~UniformCase (void)
   1178 {
   1179 	UniformCase::deinit();
   1180 }
   1181 
   1182 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
   1183 {
   1184 	if (varType.isBasicType())
   1185 	{
   1186 		const bool				isActive	= isParentActive && (m_features & FEATURE_UNIFORMUSAGE_EVERY_OTHER ? basicUniformsDst.size() % 2 == 0 : true);
   1187 		const glu::DataType		type		= varType.getBasicType();
   1188 		const VarValue			value		= m_features & FEATURE_UNIFORMVALUE_ZERO	? generateZeroVarValue(type)
   1189 											: glu::isDataTypeSampler(type)				? generateRandomVarValue(type, rnd, samplerUnitCounter++)
   1190 											: generateRandomVarValue(varType.getBasicType(), rnd);
   1191 
   1192 		basicUniformsDst.push_back(BasicUniform(varName, varType.getBasicType(), isActive, value));
   1193 		basicUniformReportsDst.push_back(BasicUniformReportRef(varName, varType.getBasicType(), isActive));
   1194 	}
   1195 	else if (varType.isArrayType())
   1196 	{
   1197 		const int		size			= varType.getArraySize();
   1198 		const string	arrayRootName	= string("") + varName + "[0]";
   1199 		vector<bool>	isElemActive;
   1200 
   1201 		for (int elemNdx = 0; elemNdx < varType.getArraySize(); elemNdx++)
   1202 		{
   1203 			const string	indexedName		= string("") + varName + "[" + de::toString(elemNdx) + "]";
   1204 			const bool		isCurElemActive	= isParentActive																						&&
   1205 											  (m_features & FEATURE_UNIFORMUSAGE_EVERY_OTHER			? basicUniformsDst.size() % 2 == 0	: true)	&&
   1206 											  (m_features & FEATURE_ARRAYUSAGE_ONLY_MIDDLE_INDEX		? elemNdx == size/2					: true);
   1207 
   1208 			isElemActive.push_back(isCurElemActive);
   1209 
   1210 			if (varType.getElementType().isBasicType())
   1211 			{
   1212 				// \note We don't want separate entries in basicUniformReportsDst for elements of basic-type arrays.
   1213 				const glu::DataType	elemBasicType	= varType.getElementType().getBasicType();
   1214 				const VarValue		value			= m_features & FEATURE_UNIFORMVALUE_ZERO	? generateZeroVarValue(elemBasicType)
   1215 													: glu::isDataTypeSampler(elemBasicType)		? generateRandomVarValue(elemBasicType, rnd, samplerUnitCounter++)
   1216 													: generateRandomVarValue(elemBasicType, rnd);
   1217 
   1218 				basicUniformsDst.push_back(BasicUniform(indexedName.c_str(), elemBasicType, isCurElemActive, value, arrayRootName.c_str(), elemNdx, size));
   1219 			}
   1220 			else
   1221 				generateBasicUniforms(basicUniformsDst, basicUniformReportsDst, varType.getElementType(), indexedName.c_str(), isCurElemActive, samplerUnitCounter, rnd);
   1222 		}
   1223 
   1224 		if (varType.getElementType().isBasicType())
   1225 		{
   1226 			int minSize;
   1227 			for (minSize = varType.getArraySize(); minSize > 0 && !isElemActive[minSize-1]; minSize--);
   1228 
   1229 			basicUniformReportsDst.push_back(BasicUniformReportRef(arrayRootName.c_str(), minSize, size, varType.getElementType().getBasicType(), isParentActive && minSize > 0));
   1230 		}
   1231 	}
   1232 	else
   1233 	{
   1234 		DE_ASSERT(varType.isStructType());
   1235 
   1236 		const StructType& structType = *varType.getStructPtr();
   1237 
   1238 		for (int i = 0; i < structType.getNumMembers(); i++)
   1239 		{
   1240 			const glu::StructMember&	member			= structType.getMember(i);
   1241 			const string				memberFullName	= string("") + varName + "." + member.getName();
   1242 
   1243 			generateBasicUniforms(basicUniformsDst, basicUniformReportsDst, member.getType(), memberFullName.c_str(), isParentActive, samplerUnitCounter, rnd);
   1244 		}
   1245 	}
   1246 }
   1247 
   1248 void UniformCase::writeUniformDefinitions (std::ostringstream& dst) const
   1249 {
   1250 	for (int i = 0; i < (int)m_uniformCollection->getNumStructTypes(); i++)
   1251 		dst << glu::declare(m_uniformCollection->getStructType(i)) << ";\n";
   1252 
   1253 	for (int i = 0; i < (int)m_uniformCollection->getNumUniforms(); i++)
   1254 		dst << "uniform " << glu::declare(m_uniformCollection->getUniform(i).type, m_uniformCollection->getUniform(i).name.c_str()) << ";\n";
   1255 
   1256 	dst << "\n";
   1257 
   1258 	{
   1259 		static const struct
   1260 		{
   1261 			dataTypePredicate	requiringTypes[2];
   1262 			const char*			definition;
   1263 		} compareFuncs[] =
   1264 		{
   1265 			{ { glu::isDataTypeFloatOrVec,				glu::isDataTypeMatrix				}, "mediump float compare_float    (mediump float a, mediump float b)  { return abs(a - b) < 0.05 ? 1.0 : 0.0; }"																		},
   1266 			{ { 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); }"														},
   1267 			{ { 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); }"								},
   1268 			{ { 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); }"		},
   1269 			{ { 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]); }"													},
   1270 			{ { dataTypeEquals<glu::TYPE_FLOAT_MAT2X3>,	dataTypeEquals<glu::TYPE_INVALID>	}, "mediump float compare_mat2x3   (mediump mat2x3 a, mediump mat2x3 b){ return compare_vec3(a[0], b[0])*compare_vec3(a[1], b[1]); }"													},
   1271 			{ { dataTypeEquals<glu::TYPE_FLOAT_MAT2X4>,	dataTypeEquals<glu::TYPE_INVALID>	}, "mediump float compare_mat2x4   (mediump mat2x4 a, mediump mat2x4 b){ return compare_vec4(a[0], b[0])*compare_vec4(a[1], b[1]); }"													},
   1272 			{ { dataTypeEquals<glu::TYPE_FLOAT_MAT3X2>,	dataTypeEquals<glu::TYPE_INVALID>	}, "mediump float compare_mat3x2   (mediump mat3x2 a, mediump mat3x2 b){ return compare_vec2(a[0], b[0])*compare_vec2(a[1], b[1])*compare_vec2(a[2], b[2]); }"							},
   1273 			{ { 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]); }"							},
   1274 			{ { dataTypeEquals<glu::TYPE_FLOAT_MAT3X4>,	dataTypeEquals<glu::TYPE_INVALID>	}, "mediump float compare_mat3x4   (mediump mat3x4 a, mediump mat3x4 b){ return compare_vec4(a[0], b[0])*compare_vec4(a[1], b[1])*compare_vec4(a[2], b[2]); }"							},
   1275 			{ { dataTypeEquals<glu::TYPE_FLOAT_MAT4X2>,	dataTypeEquals<glu::TYPE_INVALID>	}, "mediump float compare_mat4x2   (mediump mat4x2 a, mediump mat4x2 b){ return compare_vec2(a[0], b[0])*compare_vec2(a[1], b[1])*compare_vec2(a[2], b[2])*compare_vec2(a[3], b[3]); }"	},
   1276 			{ { dataTypeEquals<glu::TYPE_FLOAT_MAT4X3>,	dataTypeEquals<glu::TYPE_INVALID>	}, "mediump float compare_mat4x3   (mediump mat4x3 a, mediump mat4x3 b){ return compare_vec3(a[0], b[0])*compare_vec3(a[1], b[1])*compare_vec3(a[2], b[2])*compare_vec3(a[3], b[3]); }"	},
   1277 			{ { 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]); }"	},
   1278 			{ { 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; }"																					},
   1279 			{ { 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; }"																					},
   1280 			{ { 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; }"																					},
   1281 			{ { 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; }"																					},
   1282 			{ { dataTypeEquals<glu::TYPE_UINT>,			dataTypeEquals<glu::TYPE_INVALID>	}, "mediump float compare_uint     (mediump uint a, mediump uint b)    { return a == b ? 1.0 : 0.0; }"																					},
   1283 			{ { dataTypeEquals<glu::TYPE_UINT_VEC2>,	dataTypeEquals<glu::TYPE_INVALID>	}, "mediump float compare_uvec2    (mediump uvec2 a, mediump uvec2 b)  { return a == b ? 1.0 : 0.0; }"																					},
   1284 			{ { dataTypeEquals<glu::TYPE_UINT_VEC3>,	dataTypeEquals<glu::TYPE_INVALID>	}, "mediump float compare_uvec3    (mediump uvec3 a, mediump uvec3 b)  { return a == b ? 1.0 : 0.0; }"																					},
   1285 			{ { dataTypeEquals<glu::TYPE_UINT_VEC4>,	dataTypeEquals<glu::TYPE_INVALID>	}, "mediump float compare_uvec4    (mediump uvec4 a, mediump uvec4 b)  { return a == b ? 1.0 : 0.0; }"																					},
   1286 			{ { dataTypeEquals<glu::TYPE_BOOL>,			dataTypeEquals<glu::TYPE_INVALID>	}, "mediump float compare_bool     (bool a, bool b)                    { return a == b ? 1.0 : 0.0; }"																					},
   1287 			{ { dataTypeEquals<glu::TYPE_BOOL_VEC2>,	dataTypeEquals<glu::TYPE_INVALID>	}, "mediump float compare_bvec2    (bvec2 a, bvec2 b)                  { return a == b ? 1.0 : 0.0; }"																					},
   1288 			{ { dataTypeEquals<glu::TYPE_BOOL_VEC3>,	dataTypeEquals<glu::TYPE_INVALID>	}, "mediump float compare_bvec3    (bvec3 a, bvec3 b)                  { return a == b ? 1.0 : 0.0; }"																					},
   1289 			{ { dataTypeEquals<glu::TYPE_BOOL_VEC4>,	dataTypeEquals<glu::TYPE_INVALID>	}, "mediump float compare_bvec4    (bvec4 a, bvec4 b)                  { return a == b ? 1.0 : 0.0; }"																					}
   1290 		};
   1291 
   1292 		const vector<glu::DataType> samplerTypes = m_uniformCollection->getSamplerTypes();
   1293 
   1294 		for (int compFuncNdx = 0; compFuncNdx < DE_LENGTH_OF_ARRAY(compareFuncs); compFuncNdx++)
   1295 		{
   1296 			const dataTypePredicate		(&typeReq)[2]			= compareFuncs[compFuncNdx].requiringTypes;
   1297 			bool						containsTypeSampler		= false;
   1298 
   1299 			for (int i = 0; i < (int)samplerTypes.size(); i++)
   1300 			{
   1301 				if (glu::isDataTypeSampler(samplerTypes[i]))
   1302 				{
   1303 					const glu::DataType retType = getSamplerLookupReturnType(samplerTypes[i]);
   1304 					if (typeReq[0](retType) || typeReq[1](retType))
   1305 					{
   1306 						containsTypeSampler = true;
   1307 						break;
   1308 					}
   1309 				}
   1310 			}
   1311 
   1312 			if (containsTypeSampler || m_uniformCollection->containsMatchingBasicType(typeReq[0]) || m_uniformCollection->containsMatchingBasicType(typeReq[1]))
   1313 				dst << compareFuncs[compFuncNdx].definition << "\n";
   1314 		}
   1315 	}
   1316 }
   1317 
   1318 void UniformCase::writeUniformCompareExpr (std::ostringstream& dst, const BasicUniform& uniform) const
   1319 {
   1320 	if (glu::isDataTypeSampler(uniform.type))
   1321 		dst << "compare_" << glu::getDataTypeName(getSamplerLookupReturnType(uniform.type)) << "(texture(" << uniform.name << ", vec" << getSamplerNumLookupDimensions(uniform.type) << "(0.0))";
   1322 	else
   1323 		dst << "compare_" << glu::getDataTypeName(uniform.type) << "(" << uniform.name;
   1324 
   1325 	dst << ", " << shaderVarValueStr(uniform.finalValue) << ")";
   1326 }
   1327 
   1328 void UniformCase::writeUniformComparisons (std::ostringstream& dst, const vector<BasicUniform>& basicUniforms, const char* const variableName) const
   1329 {
   1330 	for (int i = 0; i < (int)basicUniforms.size(); i++)
   1331 	{
   1332 		const BasicUniform& unif = basicUniforms[i];
   1333 
   1334 		if (unif.isUsedInShader)
   1335 		{
   1336 			dst << "\t" << variableName << " *= ";
   1337 			writeUniformCompareExpr(dst, basicUniforms[i]);
   1338 			dst << ";\n";
   1339 		}
   1340 		else
   1341 			dst << "\t// UNUSED: " << basicUniforms[i].name << "\n";
   1342 	}
   1343 }
   1344 
   1345 string UniformCase::generateVertexSource (const vector<BasicUniform>& basicUniforms) const
   1346 {
   1347 	const bool			isVertexCase = m_caseShaderType == CASESHADERTYPE_VERTEX || m_caseShaderType == CASESHADERTYPE_BOTH;
   1348 	std::ostringstream	result;
   1349 
   1350 	result << "#version 300 es\n"
   1351 			  "in highp vec4 a_position;\n"
   1352 			  "out mediump float v_vtxOut;\n"
   1353 			  "\n";
   1354 
   1355 	if (isVertexCase)
   1356 		writeUniformDefinitions(result);
   1357 
   1358 	result << "\n"
   1359 			  "void main (void)\n"
   1360 			  "{\n"
   1361 			  "	gl_Position = a_position;\n"
   1362 			  "	v_vtxOut = 1.0;\n";
   1363 
   1364 	if (isVertexCase)
   1365 		writeUniformComparisons(result, basicUniforms, "v_vtxOut");
   1366 
   1367 	result << "}\n";
   1368 
   1369 	return result.str();
   1370 }
   1371 
   1372 string UniformCase::generateFragmentSource (const vector<BasicUniform>& basicUniforms) const
   1373 {
   1374 	const bool			isFragmentCase = m_caseShaderType == CASESHADERTYPE_FRAGMENT || m_caseShaderType == CASESHADERTYPE_BOTH;
   1375 	std::ostringstream	result;
   1376 
   1377 	result << "#version 300 es\n"
   1378 			  "in mediump float v_vtxOut;\n"
   1379 			  "\n";
   1380 
   1381 	if (isFragmentCase)
   1382 		writeUniformDefinitions(result);
   1383 
   1384 	result << "\n"
   1385 			  "layout(location = 0) out mediump vec4 dEQP_FragColor;\n"
   1386 			  "\n"
   1387 			  "void main (void)\n"
   1388 			  "{\n"
   1389 			  "	mediump float result = v_vtxOut;\n";
   1390 
   1391 	if (isFragmentCase)
   1392 		writeUniformComparisons(result, basicUniforms, "result");
   1393 
   1394 	result << "	dEQP_FragColor = vec4(result, result, result, 1.0);\n"
   1395 			  "}\n";
   1396 
   1397 	return result.str();
   1398 }
   1399 
   1400 void UniformCase::setupTexture (const VarValue& value)
   1401 {
   1402 	// \note No handling for samplers other than 2D or cube.
   1403 
   1404 	enableLogging(false);
   1405 
   1406 	DE_ASSERT(getSamplerLookupReturnType(value.type) == glu::TYPE_FLOAT_VEC4);
   1407 
   1408 	const int						width			= 32;
   1409 	const int						height			= 32;
   1410 	const tcu::Vec4					color			= vec4FromPtr(&value.val.samplerV.fillColor.floatV[0]);
   1411 
   1412 	if (value.type == glu::TYPE_SAMPLER_2D)
   1413 	{
   1414 		glu::Texture2D* texture		= new glu::Texture2D(m_context.getRenderContext(), GL_RGBA, GL_UNSIGNED_BYTE, width, height);
   1415 		tcu::Texture2D& refTexture	= texture->getRefTexture();
   1416 		m_textures2d.push_back(texture);
   1417 
   1418 		refTexture.allocLevel(0);
   1419 		fillWithColor(refTexture.getLevel(0), color);
   1420 
   1421 		GLU_CHECK_CALL(glActiveTexture(GL_TEXTURE0 + value.val.samplerV.unit));
   1422 		m_filledTextureUnits.push_back(value.val.samplerV.unit);
   1423 		texture->upload();
   1424 		GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
   1425 		GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
   1426 		GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
   1427 		GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
   1428 	}
   1429 	else if (value.type == glu::TYPE_SAMPLER_CUBE)
   1430 	{
   1431 		DE_ASSERT(width == height);
   1432 
   1433 		glu::TextureCube* texture		= new glu::TextureCube(m_context.getRenderContext(), GL_RGBA, GL_UNSIGNED_BYTE, width);
   1434 		tcu::TextureCube& refTexture	= texture->getRefTexture();
   1435 		m_texturesCube.push_back(texture);
   1436 
   1437 		for (int face = 0; face < (int)tcu::CUBEFACE_LAST; face++)
   1438 		{
   1439 			refTexture.allocLevel((tcu::CubeFace)face, 0);
   1440 			fillWithColor(refTexture.getLevelFace(0, (tcu::CubeFace)face), color);
   1441 		}
   1442 
   1443 		GLU_CHECK_CALL(glActiveTexture(GL_TEXTURE0 + value.val.samplerV.unit));
   1444 		m_filledTextureUnits.push_back(value.val.samplerV.unit);
   1445 		texture->upload();
   1446 		GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
   1447 		GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
   1448 		GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
   1449 		GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
   1450 
   1451 	}
   1452 	else
   1453 		DE_ASSERT(false);
   1454 
   1455 	enableLogging(true);
   1456 }
   1457 
   1458 bool UniformCase::getActiveUniforms (vector<BasicUniformReportGL>& basicUniformReportsDst, const vector<BasicUniformReportRef>& basicUniformReportsRef, const deUint32 programGL)
   1459 {
   1460 	TestLog&			log						= m_testCtx.getLog();
   1461 	GLint				numActiveUniforms		= 0;
   1462 	GLint				uniformMaxNameLength	= 0;
   1463 	vector<char>		nameBuffer;
   1464 	bool				success					= true;
   1465 
   1466 	GLU_CHECK_CALL(glGetProgramiv(programGL, GL_ACTIVE_UNIFORMS, &numActiveUniforms));
   1467 	log << TestLog::Message << "// Number of active uniforms reported: " << numActiveUniforms << TestLog::EndMessage;
   1468 	GLU_CHECK_CALL(glGetProgramiv(programGL, GL_ACTIVE_UNIFORM_MAX_LENGTH, &uniformMaxNameLength));
   1469 	log << TestLog::Message << "// Maximum uniform name length reported: " << uniformMaxNameLength << TestLog::EndMessage;
   1470 	nameBuffer.resize(uniformMaxNameLength);
   1471 
   1472 	for (int unifNdx = 0; unifNdx < numActiveUniforms; unifNdx++)
   1473 	{
   1474 		GLsizei					reportedNameLength	= 0;
   1475 		GLint					reportedSize		= -1;
   1476 		GLenum					reportedTypeGL		= GL_NONE;
   1477 
   1478 		GLU_CHECK_CALL(glGetActiveUniform(programGL, (GLuint)unifNdx, (GLsizei)uniformMaxNameLength, &reportedNameLength, &reportedSize, &reportedTypeGL, &nameBuffer[0]));
   1479 
   1480 		const glu::DataType		reportedType		= glu::getDataTypeFromGLType(reportedTypeGL);
   1481 		const string			reportedNameStr		(&nameBuffer[0]);
   1482 
   1483 		TCU_CHECK_MSG(reportedType != glu::TYPE_LAST, "Invalid uniform type");
   1484 
   1485 		log << TestLog::Message << "// Got name = " << reportedNameStr << ", name length = " << reportedNameLength << ", size = " << reportedSize << ", type = " << glu::getDataTypeName(reportedType) << TestLog::EndMessage;
   1486 
   1487 		if ((GLsizei)reportedNameStr.length() != reportedNameLength)
   1488 		{
   1489 			log << TestLog::Message << "// FAILURE: wrong name length reported, should be " << reportedNameStr.length() << TestLog::EndMessage;
   1490 			success = false;
   1491 		}
   1492 
   1493 		if (!deStringBeginsWith(reportedNameStr.c_str(), "gl_")) // Ignore built-in uniforms.
   1494 		{
   1495 			int referenceNdx;
   1496 			for (referenceNdx = 0; referenceNdx < (int)basicUniformReportsRef.size(); referenceNdx++)
   1497 			{
   1498 				if (basicUniformReportsRef[referenceNdx].name == reportedNameStr)
   1499 					break;
   1500 			}
   1501 
   1502 			if (referenceNdx >= (int)basicUniformReportsRef.size())
   1503 			{
   1504 				log << TestLog::Message << "// FAILURE: invalid non-built-in uniform name reported" << TestLog::EndMessage;
   1505 				success = false;
   1506 			}
   1507 			else
   1508 			{
   1509 				const BasicUniformReportRef& reference = basicUniformReportsRef[referenceNdx];
   1510 
   1511 				DE_ASSERT(reference.type != glu::TYPE_LAST);
   1512 				DE_ASSERT(reference.minSize >= 1 || (reference.minSize == 0 && !reference.isUsedInShader));
   1513 				DE_ASSERT(reference.minSize <= reference.maxSize);
   1514 
   1515 				if (BasicUniformReportGL::findWithName(basicUniformReportsDst, reportedNameStr.c_str()) != basicUniformReportsDst.end())
   1516 				{
   1517 					log << TestLog::Message << "// FAILURE: same uniform name reported twice" << TestLog::EndMessage;
   1518 					success = false;
   1519 				}
   1520 
   1521 				basicUniformReportsDst.push_back(BasicUniformReportGL(reportedNameStr.c_str(), reportedNameLength, reportedSize, reportedType, unifNdx));
   1522 
   1523 				if (reportedType != reference.type)
   1524 				{
   1525 					log << TestLog::Message << "// FAILURE: wrong type reported, should be " << glu::getDataTypeName(reference.type) << TestLog::EndMessage;
   1526 					success = false;
   1527 				}
   1528 				if (reportedSize < reference.minSize || reportedSize > reference.maxSize)
   1529 				{
   1530 					log << TestLog::Message
   1531 						<< "// FAILURE: wrong size reported, should be "
   1532 						<< (reference.minSize == reference.maxSize ? de::toString(reference.minSize) : "in the range [" + de::toString(reference.minSize) + ", " + de::toString(reference.maxSize) + "]")
   1533 						<< TestLog::EndMessage;
   1534 
   1535 					success = false;
   1536 				}
   1537 			}
   1538 		}
   1539 	}
   1540 
   1541 	for (int i = 0; i < (int)basicUniformReportsRef.size(); i++)
   1542 	{
   1543 		const BasicUniformReportRef& expected = basicUniformReportsRef[i];
   1544 		if (expected.isUsedInShader && BasicUniformReportGL::findWithName(basicUniformReportsDst, expected.name.c_str()) == basicUniformReportsDst.end())
   1545 		{
   1546 			log << TestLog::Message << "// FAILURE: uniform with name " << expected.name << " was not reported by GL" << TestLog::EndMessage;
   1547 			success = false;
   1548 		}
   1549 	}
   1550 
   1551 	return success;
   1552 }
   1553 
   1554 bool UniformCase::getActiveUniformsiv (vector<BasicUniformReportGL>& basicUniformReportsDst, const vector<BasicUniformReportRef>& basicUniformReportsRef, const deUint32 programGL)
   1555 {
   1556 	TestLog&				log				= m_testCtx.getLog();
   1557 	vector<string>			queryNames		(basicUniformReportsRef.size());
   1558 	vector<const char*>		queryNamesC		(basicUniformReportsRef.size());
   1559 	vector<GLuint>			uniformIndices	(basicUniformReportsRef.size());
   1560 	vector<deUint32>		validUniformIndices; // This shall have the same contents, and in same order, as uniformIndices, but with GL_INVALID_INDEX entries removed.
   1561 	bool					success			= true;
   1562 
   1563 	for (int i = 0; i < (int)basicUniformReportsRef.size(); i++)
   1564 	{
   1565 		const string& name = basicUniformReportsRef[i].name;
   1566 		queryNames[i]	= m_features & FEATURE_ARRAY_FIRST_ELEM_NAME_NO_INDEX && name[name.size()-1] == ']' ? beforeLast(name, '[') : name;
   1567 		queryNamesC[i]	= queryNames[i].c_str();
   1568 	}
   1569 
   1570 	GLU_CHECK_CALL(glGetUniformIndices(programGL, (GLsizei)basicUniformReportsRef.size(), &queryNamesC[0], &uniformIndices[0]));
   1571 
   1572 	for (int i = 0; i < (int)uniformIndices.size(); i++)
   1573 	{
   1574 		if (uniformIndices[i] != GL_INVALID_INDEX)
   1575 			validUniformIndices.push_back(uniformIndices[i]);
   1576 		else
   1577 		{
   1578 			if (basicUniformReportsRef[i].isUsedInShader)
   1579 			{
   1580 				log << TestLog::Message << "// FAILURE: uniform with name " << basicUniformReportsRef[i].name << " received GL_INVALID_INDEX" << TestLog::EndMessage;
   1581 				success = false;
   1582 			}
   1583 		}
   1584 	}
   1585 
   1586 	if (!validUniformIndices.empty())
   1587 	{
   1588 		vector<GLint> uniformNameLengthBuf	(validUniformIndices.size());
   1589 		vector<GLint> uniformSizeBuf		(validUniformIndices.size());
   1590 		vector<GLint> uniformTypeBuf		(validUniformIndices.size());
   1591 
   1592 		GLU_CHECK_CALL(glGetActiveUniformsiv(programGL, (GLsizei)validUniformIndices.size(), &validUniformIndices[0], GL_UNIFORM_NAME_LENGTH,	&uniformNameLengthBuf[0]));
   1593 		GLU_CHECK_CALL(glGetActiveUniformsiv(programGL, (GLsizei)validUniformIndices.size(), &validUniformIndices[0], GL_UNIFORM_SIZE,			&uniformSizeBuf[0]));
   1594 		GLU_CHECK_CALL(glGetActiveUniformsiv(programGL, (GLsizei)validUniformIndices.size(), &validUniformIndices[0], GL_UNIFORM_TYPE,			&uniformTypeBuf[0]));
   1595 
   1596 		{
   1597 			int validNdx = -1; // Keeps the corresponding index to validUniformIndices while unifNdx is the index to uniformIndices.
   1598 			for (int unifNdx = 0; unifNdx < (int)uniformIndices.size(); unifNdx++)
   1599 			{
   1600 				if (uniformIndices[unifNdx] == GL_INVALID_INDEX)
   1601 					continue;
   1602 
   1603 				validNdx++;
   1604 
   1605 				const BasicUniformReportRef&	reference			= basicUniformReportsRef[unifNdx];
   1606 				const int						reportedIndex		= validUniformIndices[validNdx];
   1607 				const int						reportedNameLength	= (int)uniformNameLengthBuf[validNdx];
   1608 				const int						reportedSize		= (int)uniformSizeBuf[validNdx];
   1609 				const glu::DataType				reportedType		= glu::getDataTypeFromGLType((deUint32)uniformTypeBuf[validNdx]);
   1610 
   1611 				TCU_CHECK_MSG(reportedType != glu::TYPE_LAST, "Invalid uniform type");
   1612 
   1613 				log << TestLog::Message
   1614 					<< "// Got name length = " << reportedNameLength
   1615 					<< ", size = " << reportedSize
   1616 					<< ", type = " << glu::getDataTypeName(reportedType)
   1617 					<< " for the uniform at index " << reportedIndex << " (" << reference.name << ")"
   1618 					<< TestLog::EndMessage;
   1619 
   1620 				DE_ASSERT(reference.type != glu::TYPE_LAST);
   1621 				DE_ASSERT(reference.minSize >= 1 || (reference.minSize == 0 && !reference.isUsedInShader));
   1622 				DE_ASSERT(reference.minSize <= reference.maxSize);
   1623 				basicUniformReportsDst.push_back(BasicUniformReportGL(reference.name.c_str(), reportedNameLength, reportedSize, reportedType, reportedIndex));
   1624 
   1625 				if (reportedNameLength != (int)reference.name.length() + 1)
   1626 				{
   1627 					log << TestLog::Message << "// FAILURE: wrong name length reported, should be " << reference.name.length() + 1 << TestLog::EndMessage;
   1628 					success = false;
   1629 				}
   1630 
   1631 				if (reportedType != reference.type)
   1632 				{
   1633 					log << TestLog::Message << "// FAILURE: wrong type reported, should be " << glu::getDataTypeName(reference.type) << TestLog::EndMessage;
   1634 					success = false;
   1635 				}
   1636 
   1637 				if (reportedSize < reference.minSize || reportedSize > reference.maxSize)
   1638 				{
   1639 					log << TestLog::Message
   1640 						<< "// FAILURE: wrong size reported, should be "
   1641 						<< (reference.minSize == reference.maxSize ? de::toString(reference.minSize) : "in the range [" + de::toString(reference.minSize) + ", " + de::toString(reference.maxSize) + "]")
   1642 						<< TestLog::EndMessage;
   1643 
   1644 					success = false;
   1645 				}
   1646 			}
   1647 		}
   1648 	}
   1649 
   1650 	return success;
   1651 }
   1652 
   1653 bool UniformCase::uniformVsUniformsivComparison (const vector<BasicUniformReportGL>& uniformResults, const vector<BasicUniformReportGL>& uniformsivResults)
   1654 {
   1655 	TestLog&	log			= m_testCtx.getLog();
   1656 	bool		success		= true;
   1657 
   1658 	for (int uniformResultNdx = 0; uniformResultNdx < (int)uniformResults.size(); uniformResultNdx++)
   1659 	{
   1660 		const BasicUniformReportGL&							uniformResult		= uniformResults[uniformResultNdx];
   1661 		const string&										uniformName			= uniformResult.name;
   1662 		const vector<BasicUniformReportGL>::const_iterator	uniformsivResultIt	= BasicUniformReportGL::findWithName(uniformsivResults, uniformName.c_str());
   1663 
   1664 		if (uniformsivResultIt != uniformsivResults.end())
   1665 		{
   1666 			const BasicUniformReportGL& uniformsivResult = *uniformsivResultIt;
   1667 
   1668 			log << TestLog::Message << "// Checking uniform " << uniformName << TestLog::EndMessage;
   1669 
   1670 			if (uniformResult.index != uniformsivResult.index)
   1671 			{
   1672 				log << TestLog::Message << "// FAILURE: glGetActiveUniform() and glGetUniformIndices() gave different indices for uniform " << uniformName << TestLog::EndMessage;
   1673 				success = false;
   1674 			}
   1675 			if (uniformResult.nameLength + 1 != uniformsivResult.nameLength)
   1676 			{
   1677 				log << TestLog::Message << "// FAILURE: glGetActiveUniform() and glGetActiveUniformsiv() gave incompatible name lengths for uniform " << uniformName << TestLog::EndMessage;
   1678 				success = false;
   1679 			}
   1680 			if (uniformResult.size != uniformsivResult.size)
   1681 			{
   1682 				log << TestLog::Message << "// FAILURE: glGetActiveUniform() and glGetActiveUniformsiv() gave different sizes for uniform " << uniformName << TestLog::EndMessage;
   1683 				success = false;
   1684 			}
   1685 			if (uniformResult.type != uniformsivResult.type)
   1686 			{
   1687 				log << TestLog::Message << "// FAILURE: glGetActiveUniform() and glGetActiveUniformsiv() gave different types for uniform " << uniformName << TestLog::EndMessage;
   1688 				success = false;
   1689 			}
   1690 		}
   1691 		else
   1692 		{
   1693 			log << TestLog::Message << "// FAILURE: uniform " << uniformName << " was reported active by glGetActiveUniform() but not by glGetUniformIndices()" << TestLog::EndMessage;
   1694 			success = false;
   1695 		}
   1696 	}
   1697 
   1698 	for (int uniformsivResultNdx = 0; uniformsivResultNdx < (int)uniformsivResults.size(); uniformsivResultNdx++)
   1699 	{
   1700 		const BasicUniformReportGL&							uniformsivResult	= uniformsivResults[uniformsivResultNdx];
   1701 		const string&										uniformsivName		= uniformsivResult.name;
   1702 		const vector<BasicUniformReportGL>::const_iterator	uniformsResultIt	= BasicUniformReportGL::findWithName(uniformsivResults, uniformsivName.c_str());
   1703 
   1704 		if (uniformsResultIt == uniformsivResults.end())
   1705 		{
   1706 			log << TestLog::Message << "// FAILURE: uniform " << uniformsivName << " was reported active by glGetUniformIndices() but not by glGetActiveUniform()" << TestLog::EndMessage;
   1707 			success = false;
   1708 		}
   1709 	}
   1710 
   1711 	return success;
   1712 }
   1713 
   1714 bool UniformCase::getUniforms (vector<VarValue>& valuesDst, const vector<BasicUniform>& basicUniforms, const deUint32 programGL)
   1715 {
   1716 	TestLog&	log			= m_testCtx.getLog();
   1717 	bool		success		= true;
   1718 
   1719 	for (int unifNdx = 0; unifNdx < (int)basicUniforms.size(); unifNdx++)
   1720 	{
   1721 		const BasicUniform&		uniform		= basicUniforms[unifNdx];
   1722 		const string			queryName	= m_features & FEATURE_ARRAY_FIRST_ELEM_NAME_NO_INDEX && uniform.elemNdx == 0 ? beforeLast(uniform.name, '[') : uniform.name;
   1723 		const int				location	= glGetUniformLocation(programGL, queryName.c_str());
   1724 		const int				size		= glu::getDataTypeScalarSize(uniform.type);
   1725 		VarValue				value;
   1726 
   1727 		deMemset(&value, 0xcd, sizeof(value)); // Initialize to known garbage.
   1728 
   1729 		if (location == -1)
   1730 		{
   1731 			value.type = glu::TYPE_INVALID;
   1732 			valuesDst.push_back(value);
   1733 			if (uniform.isUsedInShader)
   1734 			{
   1735 				log << TestLog::Message << "// FAILURE: " << uniform.name << " was used in shader, but has location -1" << TestLog::EndMessage;
   1736 				success = false;
   1737 			}
   1738 			continue;
   1739 		}
   1740 
   1741 		value.type = uniform.type;
   1742 
   1743 		DE_STATIC_ASSERT(sizeof(GLint) == sizeof(value.val.intV[0]));
   1744 		DE_STATIC_ASSERT(sizeof(GLuint) == sizeof(value.val.uintV[0]));
   1745 		DE_STATIC_ASSERT(sizeof(GLfloat) == sizeof(value.val.floatV[0]));
   1746 
   1747 		if (glu::isDataTypeFloatOrVec(uniform.type) || glu::isDataTypeMatrix(uniform.type))
   1748 			GLU_CHECK_CALL(glGetUniformfv(programGL, location, &value.val.floatV[0]));
   1749 		else if (glu::isDataTypeIntOrIVec(uniform.type))
   1750 			GLU_CHECK_CALL(glGetUniformiv(programGL, location, &value.val.intV[0]));
   1751 		else if (glu::isDataTypeUintOrUVec(uniform.type))
   1752 			GLU_CHECK_CALL(glGetUniformuiv(programGL, location, &value.val.uintV[0]));
   1753 		else if (glu::isDataTypeBoolOrBVec(uniform.type))
   1754 		{
   1755 			if (m_features & FEATURE_BOOLEANAPITYPE_INT)
   1756 			{
   1757 				GLU_CHECK_CALL(glGetUniformiv(programGL, location, &value.val.intV[0]));
   1758 				for (int i = 0; i < size; i++)
   1759 					value.val.boolV[i] = value.val.intV[i] != 0;
   1760 			}
   1761 			else if (m_features & FEATURE_BOOLEANAPITYPE_UINT)
   1762 			{
   1763 				GLU_CHECK_CALL(glGetUniformuiv(programGL, location, &value.val.uintV[0]));
   1764 				for (int i = 0; i < size; i++)
   1765 					value.val.boolV[i] = value.val.uintV[i] != 0;
   1766 			}
   1767 			else // Default: use float.
   1768 			{
   1769 				GLU_CHECK_CALL(glGetUniformfv(programGL, location, &value.val.floatV[0]));
   1770 				for (int i = 0; i < size; i++)
   1771 					value.val.boolV[i] = value.val.floatV[i] != 0.0f;
   1772 			}
   1773 		}
   1774 		else if (glu::isDataTypeSampler(uniform.type))
   1775 		{
   1776 			GLint unit = -1;
   1777 			GLU_CHECK_CALL(glGetUniformiv(programGL, location, &unit));
   1778 			value.val.samplerV.unit = unit;
   1779 		}
   1780 		else
   1781 			DE_ASSERT(false);
   1782 
   1783 		valuesDst.push_back(value);
   1784 
   1785 		log << TestLog::Message << "// Got " << uniform.name << " value " << apiVarValueStr(value) << TestLog::EndMessage;
   1786 	}
   1787 
   1788 	return success;
   1789 }
   1790 
   1791 bool UniformCase::checkUniformDefaultValues (const vector<VarValue>& values, const vector<BasicUniform>& basicUniforms)
   1792 {
   1793 	TestLog&	log			= m_testCtx.getLog();
   1794 	bool		success		= true;
   1795 
   1796 	DE_ASSERT(values.size() == basicUniforms.size());
   1797 
   1798 	for (int unifNdx = 0; unifNdx < (int)basicUniforms.size(); unifNdx++)
   1799 	{
   1800 		const BasicUniform&		uniform		= basicUniforms[unifNdx];
   1801 		const VarValue&			unifValue	= values[unifNdx];
   1802 		const int				valSize		= glu::getDataTypeScalarSize(uniform.type);
   1803 
   1804 		log << TestLog::Message << "// Checking uniform " << uniform.name << TestLog::EndMessage;
   1805 
   1806 		if (unifValue.type == glu::TYPE_INVALID) // This happens when glGetUniformLocation() returned -1.
   1807 			continue;
   1808 
   1809 #define CHECK_UNIFORM(VAR_VALUE_MEMBER, ZERO)																								\
   1810 	do																																		\
   1811 	{																																		\
   1812 		for (int i = 0; i < valSize; i++)																									\
   1813 		{																																	\
   1814 			if (unifValue.val.VAR_VALUE_MEMBER[i] != ZERO)																					\
   1815 			{																																\
   1816 				log << TestLog::Message << "// FAILURE: uniform " << uniform.name << " has non-zero initial value" << TestLog::EndMessage;	\
   1817 				success = false;																											\
   1818 			}																																\
   1819 		}																																	\
   1820 	} while (false)
   1821 
   1822 		if (glu::isDataTypeFloatOrVec(uniform.type) || glu::isDataTypeMatrix(uniform.type))
   1823 			CHECK_UNIFORM(floatV, 0.0f);
   1824 		else if (glu::isDataTypeIntOrIVec(uniform.type))
   1825 			CHECK_UNIFORM(intV, 0);
   1826 		else if (glu::isDataTypeUintOrUVec(uniform.type))
   1827 			CHECK_UNIFORM(uintV, 0);
   1828 		else if (glu::isDataTypeBoolOrBVec(uniform.type))
   1829 			CHECK_UNIFORM(boolV, false);
   1830 		else if (glu::isDataTypeSampler(uniform.type))
   1831 		{
   1832 			if (unifValue.val.samplerV.unit != 0)
   1833 			{
   1834 				log << TestLog::Message << "// FAILURE: uniform " << uniform.name << " has non-zero initial value" << TestLog::EndMessage;
   1835 				success = false;
   1836 			}
   1837 		}
   1838 		else
   1839 			DE_ASSERT(false);
   1840 
   1841 #undef CHECK_UNIFORM
   1842 	}
   1843 
   1844 	return success;
   1845 }
   1846 
   1847 void UniformCase::assignUniforms (const vector<BasicUniform>& basicUniforms, deUint32 programGL, Random& rnd)
   1848 {
   1849 	TestLog&				log				= m_testCtx.getLog();
   1850 	const bool				transpose		= (m_features & FEATURE_MATRIXMODE_ROWMAJOR) != 0;
   1851 	const GLboolean			transposeGL		= transpose ? GL_TRUE : GL_FALSE;
   1852 	const glu::DataType		boolApiType		= m_features & FEATURE_BOOLEANAPITYPE_INT	? glu::TYPE_INT
   1853 											: m_features & FEATURE_BOOLEANAPITYPE_UINT	? glu::TYPE_UINT
   1854 											:											  glu::TYPE_FLOAT;
   1855 
   1856 	for (int unifNdx = 0; unifNdx < (int)basicUniforms.size(); unifNdx++)
   1857 	{
   1858 		const BasicUniform&		uniform				= basicUniforms[unifNdx];
   1859 		const bool				isArrayMember		= uniform.elemNdx >= 0;
   1860 		const string			queryName			= m_features & FEATURE_ARRAY_FIRST_ELEM_NAME_NO_INDEX && uniform.elemNdx == 0 ? beforeLast(uniform.name, '[') : uniform.name;
   1861 		const int				numValuesToAssign	= !isArrayMember									? 1
   1862 													: m_features & FEATURE_ARRAYASSIGN_FULL				? (uniform.elemNdx == 0			? uniform.rootSize	: 0)
   1863 													: m_features & FEATURE_ARRAYASSIGN_BLOCKS_OF_TWO	? (uniform.elemNdx % 2 == 0		? 2					: 0)
   1864 													: /* Default: assign array elements separately */	  1;
   1865 
   1866 		DE_ASSERT(numValuesToAssign >= 0);
   1867 		DE_ASSERT(numValuesToAssign == 1 || isArrayMember);
   1868 
   1869 		if (numValuesToAssign == 0)
   1870 		{
   1871 			log << TestLog::Message << "// Uniform " << uniform.name << " is covered by another glUniform*v() call to the same array" << TestLog::EndMessage;
   1872 			continue;
   1873 		}
   1874 
   1875 		const int			location			= glGetUniformLocation(programGL, queryName.c_str());
   1876 		const int			typeSize			= glu::getDataTypeScalarSize(uniform.type);
   1877 		const bool			assignByValue		= m_features & FEATURE_UNIFORMFUNC_VALUE && !glu::isDataTypeMatrix(uniform.type) && numValuesToAssign == 1;
   1878 		vector<VarValue>	valuesToAssign;
   1879 
   1880 		for (int i = 0; i < numValuesToAssign; i++)
   1881 		{
   1882 			const string	curName = isArrayMember ? beforeLast(uniform.rootName, '[') + "[" + de::toString(uniform.elemNdx+i) + "]" : uniform.name;
   1883 			VarValue		unifValue;
   1884 
   1885 			if (isArrayMember)
   1886 			{
   1887 				const vector<BasicUniform>::const_iterator elemUnif = BasicUniform::findWithName(basicUniforms, curName.c_str());
   1888 				if (elemUnif == basicUniforms.end())
   1889 					continue;
   1890 				unifValue = elemUnif->finalValue;
   1891 			}
   1892 			else
   1893 				unifValue = uniform.finalValue;
   1894 
   1895 			const VarValue apiValue = glu::isDataTypeBoolOrBVec(unifValue.type)	? getRandomBoolRepresentation(unifValue, boolApiType, rnd)
   1896 									: glu::isDataTypeSampler(unifValue.type)	? getSamplerUnitValue(unifValue)
   1897 									: unifValue;
   1898 
   1899 			valuesToAssign.push_back(glu::isDataTypeMatrix(apiValue.type) && transpose ? getTransposeMatrix(apiValue) : apiValue);
   1900 
   1901 			if (glu::isDataTypeBoolOrBVec(uniform.type))
   1902 				log << TestLog::Message << "// Using type " << glu::getDataTypeName(boolApiType) << " to set boolean value " << apiVarValueStr(unifValue) << " for " << curName << TestLog::EndMessage;
   1903 			else if (glu::isDataTypeSampler(uniform.type))
   1904 				log << TestLog::Message << "// Texture for the sampler uniform " << curName << " will be filled with color " << apiVarValueStr(getSamplerFillValue(uniform.finalValue)) << TestLog::EndMessage;
   1905 		}
   1906 
   1907 		DE_ASSERT(!valuesToAssign.empty());
   1908 
   1909 		if (glu::isDataTypeFloatOrVec(valuesToAssign[0].type))
   1910 		{
   1911 			if (assignByValue)
   1912 			{
   1913 				const float* const ptr = &valuesToAssign[0].val.floatV[0];
   1914 
   1915 				switch (typeSize)
   1916 				{
   1917 					case 1: GLU_CHECK_CALL(glUniform1f(location, ptr[0]));							break;
   1918 					case 2: GLU_CHECK_CALL(glUniform2f(location, ptr[0], ptr[1]));					break;
   1919 					case 3: GLU_CHECK_CALL(glUniform3f(location, ptr[0], ptr[1], ptr[2]));			break;
   1920 					case 4: GLU_CHECK_CALL(glUniform4f(location, ptr[0], ptr[1], ptr[2], ptr[3]));	break;
   1921 					default:
   1922 						DE_ASSERT(false);
   1923 				}
   1924 			}
   1925 			else
   1926 			{
   1927 				vector<float> buffer(valuesToAssign.size() * typeSize);
   1928 				for (int i = 0; i < (int)buffer.size(); i++)
   1929 					buffer[i] = valuesToAssign[i / typeSize].val.floatV[i % typeSize];
   1930 
   1931 				DE_STATIC_ASSERT(sizeof(GLfloat) == sizeof(buffer[0]));
   1932 				switch (typeSize)
   1933 				{
   1934 					case 1: GLU_CHECK_CALL(glUniform1fv(location, (GLsizei)valuesToAssign.size(), &buffer[0])); break;
   1935 					case 2: GLU_CHECK_CALL(glUniform2fv(location, (GLsizei)valuesToAssign.size(), &buffer[0])); break;
   1936 					case 3: GLU_CHECK_CALL(glUniform3fv(location, (GLsizei)valuesToAssign.size(), &buffer[0])); break;
   1937 					case 4: GLU_CHECK_CALL(glUniform4fv(location, (GLsizei)valuesToAssign.size(), &buffer[0])); break;
   1938 					default:
   1939 						DE_ASSERT(false);
   1940 				}
   1941 			}
   1942 		}
   1943 		else if (glu::isDataTypeMatrix(valuesToAssign[0].type))
   1944 		{
   1945 			DE_ASSERT(!assignByValue);
   1946 
   1947 			vector<float> buffer(valuesToAssign.size() * typeSize);
   1948 			for (int i = 0; i < (int)buffer.size(); i++)
   1949 				buffer[i] = valuesToAssign[i / typeSize].val.floatV[i % typeSize];
   1950 
   1951 			DE_STATIC_ASSERT(sizeof(GLfloat) == sizeof(buffer[0]));
   1952 			switch (uniform.type)
   1953 			{
   1954 				case glu::TYPE_FLOAT_MAT2:		GLU_CHECK_CALL(glUniformMatrix2fv	(location, (GLsizei)valuesToAssign.size(), transposeGL, &buffer[0])); break;
   1955 				case glu::TYPE_FLOAT_MAT3:		GLU_CHECK_CALL(glUniformMatrix3fv	(location, (GLsizei)valuesToAssign.size(), transposeGL, &buffer[0])); break;
   1956 				case glu::TYPE_FLOAT_MAT4:		GLU_CHECK_CALL(glUniformMatrix4fv	(location, (GLsizei)valuesToAssign.size(), transposeGL, &buffer[0])); break;
   1957 				case glu::TYPE_FLOAT_MAT2X3:	GLU_CHECK_CALL(glUniformMatrix2x3fv	(location, (GLsizei)valuesToAssign.size(), transposeGL, &buffer[0])); break;
   1958 				case glu::TYPE_FLOAT_MAT2X4:	GLU_CHECK_CALL(glUniformMatrix2x4fv	(location, (GLsizei)valuesToAssign.size(), transposeGL, &buffer[0])); break;
   1959 				case glu::TYPE_FLOAT_MAT3X2:	GLU_CHECK_CALL(glUniformMatrix3x2fv	(location, (GLsizei)valuesToAssign.size(), transposeGL, &buffer[0])); break;
   1960 				case glu::TYPE_FLOAT_MAT3X4:	GLU_CHECK_CALL(glUniformMatrix3x4fv	(location, (GLsizei)valuesToAssign.size(), transposeGL, &buffer[0])); break;
   1961 				case glu::TYPE_FLOAT_MAT4X2:	GLU_CHECK_CALL(glUniformMatrix4x2fv	(location, (GLsizei)valuesToAssign.size(), transposeGL, &buffer[0])); break;
   1962 				case glu::TYPE_FLOAT_MAT4X3:	GLU_CHECK_CALL(glUniformMatrix4x3fv	(location, (GLsizei)valuesToAssign.size(), transposeGL, &buffer[0])); break;
   1963 				default:
   1964 					DE_ASSERT(false);
   1965 			}
   1966 		}
   1967 		else if (glu::isDataTypeIntOrIVec(valuesToAssign[0].type))
   1968 		{
   1969 			if (assignByValue)
   1970 			{
   1971 				const deInt32* const ptr = &valuesToAssign[0].val.intV[0];
   1972 
   1973 				switch (typeSize)
   1974 				{
   1975 					case 1: GLU_CHECK_CALL(glUniform1i(location, ptr[0]));							break;
   1976 					case 2: GLU_CHECK_CALL(glUniform2i(location, ptr[0], ptr[1]));					break;
   1977 					case 3: GLU_CHECK_CALL(glUniform3i(location, ptr[0], ptr[1], ptr[2]));			break;
   1978 					case 4: GLU_CHECK_CALL(glUniform4i(location, ptr[0], ptr[1], ptr[2], ptr[3]));	break;
   1979 					default:
   1980 						DE_ASSERT(false);
   1981 				}
   1982 			}
   1983 			else
   1984 			{
   1985 				vector<deInt32> buffer(valuesToAssign.size() * typeSize);
   1986 				for (int i = 0; i < (int)buffer.size(); i++)
   1987 					buffer[i] = valuesToAssign[i / typeSize].val.intV[i % typeSize];
   1988 
   1989 				DE_STATIC_ASSERT(sizeof(GLint) == sizeof(buffer[0]));
   1990 				switch (typeSize)
   1991 				{
   1992 					case 1: GLU_CHECK_CALL(glUniform1iv(location, (GLsizei)valuesToAssign.size(), &buffer[0])); break;
   1993 					case 2: GLU_CHECK_CALL(glUniform2iv(location, (GLsizei)valuesToAssign.size(), &buffer[0])); break;
   1994 					case 3: GLU_CHECK_CALL(glUniform3iv(location, (GLsizei)valuesToAssign.size(), &buffer[0])); break;
   1995 					case 4: GLU_CHECK_CALL(glUniform4iv(location, (GLsizei)valuesToAssign.size(), &buffer[0])); break;
   1996 					default:
   1997 						DE_ASSERT(false);
   1998 				}
   1999 			}
   2000 		}
   2001 		else if (glu::isDataTypeUintOrUVec(valuesToAssign[0].type))
   2002 		{
   2003 			if (assignByValue)
   2004 			{
   2005 				const deUint32* const ptr = &valuesToAssign[0].val.uintV[0];
   2006 
   2007 				switch (typeSize)
   2008 				{
   2009 					case 1: GLU_CHECK_CALL(glUniform1ui(location, ptr[0]));							break;
   2010 					case 2: GLU_CHECK_CALL(glUniform2ui(location, ptr[0], ptr[1]));					break;
   2011 					case 3: GLU_CHECK_CALL(glUniform3ui(location, ptr[0], ptr[1], ptr[2]));			break;
   2012 					case 4: GLU_CHECK_CALL(glUniform4ui(location, ptr[0], ptr[1], ptr[2], ptr[3]));	break;
   2013 					default:
   2014 						DE_ASSERT(false);
   2015 				}
   2016 			}
   2017 			else
   2018 			{
   2019 				vector<deUint32> buffer(valuesToAssign.size() * typeSize);
   2020 				for (int i = 0; i < (int)buffer.size(); i++)
   2021 					buffer[i] = valuesToAssign[i / typeSize].val.intV[i % typeSize];
   2022 
   2023 				DE_STATIC_ASSERT(sizeof(GLuint) == sizeof(buffer[0]));
   2024 				switch (typeSize)
   2025 				{
   2026 					case 1: GLU_CHECK_CALL(glUniform1uiv(location, (GLsizei)valuesToAssign.size(), &buffer[0])); break;
   2027 					case 2: GLU_CHECK_CALL(glUniform2uiv(location, (GLsizei)valuesToAssign.size(), &buffer[0])); break;
   2028 					case 3: GLU_CHECK_CALL(glUniform3uiv(location, (GLsizei)valuesToAssign.size(), &buffer[0])); break;
   2029 					case 4: GLU_CHECK_CALL(glUniform4uiv(location, (GLsizei)valuesToAssign.size(), &buffer[0])); break;
   2030 					default:
   2031 						DE_ASSERT(false);
   2032 				}
   2033 			}
   2034 		}
   2035 		else if (glu::isDataTypeSampler(valuesToAssign[0].type))
   2036 		{
   2037 			if (assignByValue)
   2038 				GLU_CHECK_CALL(glUniform1i(location, uniform.finalValue.val.samplerV.unit));
   2039 			else
   2040 			{
   2041 				const GLint unit = uniform.finalValue.val.samplerV.unit;
   2042 				GLU_CHECK_CALL(glUniform1iv(location, (GLsizei)valuesToAssign.size(), &unit));
   2043 			}
   2044 		}
   2045 		else
   2046 			DE_ASSERT(false);
   2047 	}
   2048 }
   2049 
   2050 bool UniformCase::compareUniformValues (const vector<VarValue>& values, const vector<BasicUniform>& basicUniforms)
   2051 {
   2052 	TestLog&	log			= m_testCtx.getLog();
   2053 	bool		success		= true;
   2054 
   2055 	for (int unifNdx = 0; unifNdx < (int)basicUniforms.size(); unifNdx++)
   2056 	{
   2057 		const BasicUniform&		uniform		= basicUniforms[unifNdx];
   2058 		const VarValue&			unifValue	= values[unifNdx];
   2059 
   2060 		log << TestLog::Message << "// Checking uniform " << uniform.name << TestLog::EndMessage;
   2061 
   2062 		if (unifValue.type == glu::TYPE_INVALID) // This happens when glGetUniformLocation() returned -1.
   2063 			continue;
   2064 
   2065 		if (!apiVarValueEquals(unifValue, uniform.finalValue))
   2066 		{
   2067 			log << TestLog::Message << "// FAILURE: value obtained with glGetUniform*() for uniform " << uniform.name << " differs from value set with glUniform*()" << TestLog::EndMessage;
   2068 			success = false;
   2069 		}
   2070 	}
   2071 
   2072 	return success;
   2073 }
   2074 
   2075 bool UniformCase::renderTest (const vector<BasicUniform>& basicUniforms, const ShaderProgram& program, Random& rnd)
   2076 {
   2077 	TestLog&					log				= m_testCtx.getLog();
   2078 	const tcu::RenderTarget&	renderTarget	= m_context.getRenderTarget();
   2079 	const int					viewportW		= de::min(renderTarget.getWidth(),	MAX_RENDER_WIDTH);
   2080 	const int					viewportH		= de::min(renderTarget.getHeight(),	MAX_RENDER_HEIGHT);
   2081 	const int					viewportX		= rnd.getInt(0, renderTarget.getWidth()		- viewportW);
   2082 	const int					viewportY		= rnd.getInt(0, renderTarget.getHeight()	- viewportH);
   2083 	tcu::Surface				renderedImg		(viewportW, viewportH);
   2084 
   2085 	// Assert that no two samplers of different types have the same texture unit - this is an error in GL.
   2086 	for (int i = 0; i < (int)basicUniforms.size(); i++)
   2087 	{
   2088 		if (glu::isDataTypeSampler(basicUniforms[i].type))
   2089 		{
   2090 			for (int j = 0; j < i; j++)
   2091 			{
   2092 				if (glu::isDataTypeSampler(basicUniforms[j].type) && basicUniforms[i].type != basicUniforms[j].type)
   2093 					DE_ASSERT(basicUniforms[i].finalValue.val.samplerV.unit != basicUniforms[j].finalValue.val.samplerV.unit);
   2094 			}
   2095 		}
   2096 	}
   2097 
   2098 	for (int i = 0; i < (int)basicUniforms.size(); i++)
   2099 	{
   2100 		if (glu::isDataTypeSampler(basicUniforms[i].type) && std::find(m_filledTextureUnits.begin(), m_filledTextureUnits.end(), basicUniforms[i].finalValue.val.samplerV.unit) == m_filledTextureUnits.end())
   2101 		{
   2102 			log << TestLog::Message << "// Filling texture at unit " << apiVarValueStr(basicUniforms[i].finalValue) << " with color " << shaderVarValueStr(basicUniforms[i].finalValue) << TestLog::EndMessage;
   2103 			setupTexture(basicUniforms[i].finalValue);
   2104 		}
   2105 	}
   2106 
   2107 	GLU_CHECK_CALL(glViewport(viewportX, viewportY, viewportW, viewportH));
   2108 
   2109 	{
   2110 		static const float position[] =
   2111 		{
   2112 			-1.0f, -1.0f, 0.0f, 1.0f,
   2113 			-1.0f, +1.0f, 0.0f, 1.0f,
   2114 			+1.0f, -1.0f, 0.0f, 1.0f,
   2115 			+1.0f, +1.0f, 0.0f, 1.0f
   2116 		};
   2117 		static const deUint16 indices[] = { 0, 1, 2, 2, 1, 3 };
   2118 
   2119 		const int posLoc = glGetAttribLocation(program.getProgram(), "a_position");
   2120 		glEnableVertexAttribArray(posLoc);
   2121 		glVertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, &position[0]);
   2122 		GLU_CHECK_CALL(glDrawElements(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(indices), GL_UNSIGNED_SHORT, &indices[0]));
   2123 	}
   2124 
   2125 	glu::readPixels(m_context.getRenderContext(), viewportX, viewportY, renderedImg.getAccess());
   2126 
   2127 	int numFailedPixels = 0;
   2128 	for (int y = 0; y < renderedImg.getHeight(); y++)
   2129 	{
   2130 		for (int x = 0; x < renderedImg.getWidth(); x++)
   2131 		{
   2132 			if (renderedImg.getPixel(x, y) != tcu::RGBA::white)
   2133 				numFailedPixels += 1;
   2134 		}
   2135 	}
   2136 
   2137 	if (numFailedPixels > 0)
   2138 	{
   2139 		log << TestLog::Image("RenderedImage", "Rendered image", renderedImg);
   2140 		log << TestLog::Message << "FAILURE: image comparison failed, got " << numFailedPixels << " non-white pixels" << TestLog::EndMessage;
   2141 		return false;
   2142 	}
   2143 	else
   2144 	{
   2145 		log << TestLog::Message << "Success: got all-white pixels (all uniforms have correct values)" << TestLog::EndMessage;
   2146 		return true;
   2147 	}
   2148 }
   2149 
   2150 UniformCase::IterateResult UniformCase::iterate (void)
   2151 {
   2152 	Random							rnd				(deStringHash(getName()) ^ (deUint32)m_context.getTestContext().getCommandLine().getBaseSeed());
   2153 	TestLog&						log				= m_testCtx.getLog();
   2154 	vector<BasicUniform>			basicUniforms;
   2155 	vector<BasicUniformReportRef>	basicUniformReportsRef;
   2156 
   2157 	{
   2158 		int samplerUnitCounter = 0;
   2159 		for (int i = 0; i < (int)m_uniformCollection->getNumUniforms(); i++)
   2160 			generateBasicUniforms(basicUniforms, basicUniformReportsRef, m_uniformCollection->getUniform(i).type, m_uniformCollection->getUniform(i).name.c_str(), true, samplerUnitCounter, rnd);
   2161 	}
   2162 
   2163 	const string					vertexSource	= generateVertexSource(basicUniforms);
   2164 	const string					fragmentSource	= generateFragmentSource(basicUniforms);
   2165 	const ShaderProgram				program			(m_context.getRenderContext(), glu::makeVtxFragSources(vertexSource, fragmentSource));
   2166 
   2167 	log << program;
   2168 
   2169 	if (!program.isOk())
   2170 	{
   2171 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Compile failed");
   2172 		return STOP;
   2173 	}
   2174 
   2175 	GLU_CHECK_CALL(glUseProgram(program.getProgram()));
   2176 
   2177 	const bool success = test(basicUniforms, basicUniformReportsRef, program, rnd);
   2178 	m_testCtx.setTestResult(success ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
   2179 							success ? "Passed"				: "Failed");
   2180 
   2181 	return STOP;
   2182 }
   2183 
   2184 class UniformInfoQueryCase : public UniformCase
   2185 {
   2186 public:
   2187 	enum CaseType
   2188 	{
   2189 		CASETYPE_UNIFORM = 0,			//!< Check info returned by glGetActiveUniform().
   2190 		CASETYPE_INDICES_UNIFORMSIV,	//!< Check info returned by glGetUniformIndices() + glGetActiveUniformsiv().
   2191 		CASETYPE_CONSISTENCY,			//!< Query info with both above methods, and check consistency.
   2192 
   2193 		CASETYPE_LAST
   2194 	};
   2195 
   2196 						UniformInfoQueryCase	(Context& context, const char* name, const char* description, CaseShaderType shaderType, const SharedPtr<const UniformCollection>& uniformCollection, CaseType caseType, deUint32 additionalFeatures = 0);
   2197 	bool				test					(const vector<BasicUniform>& basicUniforms, const vector<BasicUniformReportRef>& basicUniformReportsRef, const ShaderProgram& program, Random& rnd);
   2198 
   2199 	static const char*	getCaseTypeName			(CaseType caseType);
   2200 	static const char*	getCaseTypeDescription	(CaseType caseType);
   2201 
   2202 private:
   2203 	const CaseType		m_caseType;
   2204 };
   2205 
   2206 const char* UniformInfoQueryCase::getCaseTypeName (const CaseType caseType)
   2207 {
   2208 	switch (caseType)
   2209 	{
   2210 		case CASETYPE_UNIFORM:				return "active_uniform";
   2211 		case CASETYPE_INDICES_UNIFORMSIV:	return "indices_active_uniformsiv";
   2212 		case CASETYPE_CONSISTENCY:			return "consistency";
   2213 		default:
   2214 			DE_ASSERT(false);
   2215 			return DE_NULL;
   2216 	}
   2217 }
   2218 
   2219 const char* UniformInfoQueryCase::getCaseTypeDescription (const CaseType caseType)
   2220 {
   2221 	switch (caseType)
   2222 	{
   2223 		case CASETYPE_UNIFORM:				return "Test glGetActiveUniform()";
   2224 		case CASETYPE_INDICES_UNIFORMSIV:	return "Test glGetUniformIndices() along with glGetActiveUniformsiv()";
   2225 		case CASETYPE_CONSISTENCY:			return "Check consistency between results from glGetActiveUniform() and glGetUniformIndices() + glGetActiveUniformsiv()";
   2226 		default:
   2227 			DE_ASSERT(false);
   2228 			return DE_NULL;
   2229 	}
   2230 }
   2231 
   2232 UniformInfoQueryCase::UniformInfoQueryCase (Context& context, const char* const name, const char* const description, const CaseShaderType shaderType, const SharedPtr<const UniformCollection>& uniformCollection, const CaseType caseType, const deUint32 additionalFeatures)
   2233 	: UniformCase	(context, name, description, shaderType, uniformCollection, additionalFeatures)
   2234 	, m_caseType	(caseType)
   2235 {
   2236 }
   2237 
   2238 bool UniformInfoQueryCase::test (const vector<BasicUniform>& basicUniforms, const vector<BasicUniformReportRef>& basicUniformReportsRef, const ShaderProgram& program, Random& rnd)
   2239 {
   2240 	DE_UNREF(basicUniforms);
   2241 	DE_UNREF(rnd);
   2242 
   2243 	const deUint32					programGL	= program.getProgram();
   2244 	TestLog&						log			= m_testCtx.getLog();
   2245 	vector<BasicUniformReportGL>	basicUniformReportsUniform;
   2246 	vector<BasicUniformReportGL>	basicUniformReportsUniformsiv;
   2247 
   2248 	if (m_caseType == CASETYPE_UNIFORM || m_caseType == CASETYPE_CONSISTENCY)
   2249 	{
   2250 		bool success = false;
   2251 
   2252 		{
   2253 			const ScopedLogSection section(log, "InfoGetActiveUniform", "Uniform information queries with glGetActiveUniform()");
   2254 			success = getActiveUniforms(basicUniformReportsUniform, basicUniformReportsRef, programGL);
   2255 		}
   2256 
   2257 		if (!success)
   2258 		{
   2259 			if (m_caseType == CASETYPE_UNIFORM)
   2260 				return false;
   2261 			else
   2262 			{
   2263 				DE_ASSERT(m_caseType == CASETYPE_CONSISTENCY);
   2264 				log << TestLog::Message << "// Note: this is a consistency case, so ignoring above failure(s)" << TestLog::EndMessage;
   2265 			}
   2266 		}
   2267 	}
   2268 
   2269 	if (m_caseType == CASETYPE_INDICES_UNIFORMSIV || m_caseType == CASETYPE_CONSISTENCY)
   2270 	{
   2271 		bool success = false;
   2272 
   2273 		{
   2274 			const ScopedLogSection section(log, "InfoGetActiveUniformsiv", "Uniform information queries with glGetUniformIndices() and glGetActiveUniformsiv()");
   2275 			success = getActiveUniformsiv(basicUniformReportsUniformsiv, basicUniformReportsRef, programGL);
   2276 		}
   2277 
   2278 		if (!success)
   2279 		{
   2280 			if (m_caseType == CASETYPE_INDICES_UNIFORMSIV)
   2281 				return false;
   2282 			else
   2283 			{
   2284 				DE_ASSERT(m_caseType == CASETYPE_CONSISTENCY);
   2285 				log << TestLog::Message << "// Note: this is a consistency case, so ignoring above failure(s)" << TestLog::EndMessage;
   2286 			}
   2287 		}
   2288 	}
   2289 
   2290 	if (m_caseType == CASETYPE_CONSISTENCY)
   2291 	{
   2292 		bool success = false;
   2293 
   2294 		{
   2295 			const ScopedLogSection section(log, "CompareUniformVsUniformsiv", "Comparison of results from glGetActiveUniform() and glGetActiveUniformsiv()");
   2296 			success = uniformVsUniformsivComparison(basicUniformReportsUniform, basicUniformReportsUniformsiv);
   2297 		}
   2298 
   2299 		if (!success)
   2300 			return false;
   2301 	}
   2302 
   2303 	return true;
   2304 }
   2305 
   2306 class UniformValueCase : public UniformCase
   2307 {
   2308 public:
   2309 	enum ValueToCheck
   2310 	{
   2311 		VALUETOCHECK_INITIAL = 0,		//!< Verify the initial values of the uniforms (i.e. check that they're zero).
   2312 		VALUETOCHECK_ASSIGNED,			//!< Assign values to uniforms with glUniform*(), and check those.
   2313 
   2314 		VALUETOCHECK_LAST
   2315 	};
   2316 	enum CheckMethod
   2317 	{
   2318 		CHECKMETHOD_GET_UNIFORM = 0,	//!< Check values with glGetUniform*().
   2319 		CHECKMETHOD_RENDER,				//!< Check values by rendering with the value-checking shader.
   2320 
   2321 		CHECKMETHOD_LAST
   2322 	};
   2323 	enum AssignMethod
   2324 	{
   2325 		ASSIGNMETHOD_POINTER = 0,
   2326 		ASSIGNMETHOD_VALUE,
   2327 
   2328 		ASSIGNMETHOD_LAST
   2329 	};
   2330 
   2331 						UniformValueCase			(Context&									context,
   2332 													 const char*								name,
   2333 													 const char*								description,
   2334 													 CaseShaderType								shaderType,
   2335 													 const SharedPtr<const UniformCollection>&	uniformCollection,
   2336 													 ValueToCheck								valueToCheck,
   2337 													 CheckMethod								checkMethod,
   2338 													 AssignMethod								assignMethod,
   2339 													 deUint32									additionalFeatures = 0);
   2340 
   2341 	bool				test						(const vector<BasicUniform>& basicUniforms, const vector<BasicUniformReportRef>& basicUniformReportsRef, const ShaderProgram& program, Random& rnd);
   2342 
   2343 	static const char*	getValueToCheckName			(ValueToCheck valueToCheck);
   2344 	static const char*	getValueToCheckDescription	(ValueToCheck valueToCheck);
   2345 	static const char*	getCheckMethodName			(CheckMethod checkMethod);
   2346 	static const char*	getCheckMethodDescription	(CheckMethod checkMethod);
   2347 	static const char*	getAssignMethodName			(AssignMethod checkMethod);
   2348 	static const char*	getAssignMethodDescription	(AssignMethod checkMethod);
   2349 
   2350 private:
   2351 	const ValueToCheck	m_valueToCheck;
   2352 	const CheckMethod	m_checkMethod;
   2353 };
   2354 
   2355 const char* UniformValueCase::getValueToCheckName (const ValueToCheck valueToCheck)
   2356 {
   2357 	switch (valueToCheck)
   2358 	{
   2359 		case VALUETOCHECK_INITIAL:	return "initial";
   2360 		case VALUETOCHECK_ASSIGNED:	return "assigned";
   2361 		default: DE_ASSERT(false);	return DE_NULL;
   2362 	}
   2363 }
   2364 
   2365 const char* UniformValueCase::getValueToCheckDescription (const ValueToCheck valueToCheck)
   2366 {
   2367 	switch (valueToCheck)
   2368 {
   2369 		case VALUETOCHECK_INITIAL:	return "Check initial uniform values (zeros)";
   2370 		case VALUETOCHECK_ASSIGNED:	return "Check assigned uniform values";
   2371 		default: DE_ASSERT(false);	return DE_NULL;
   2372 	}
   2373 }
   2374 
   2375 const char* UniformValueCase::getCheckMethodName (const CheckMethod checkMethod)
   2376 {
   2377 	switch (checkMethod)
   2378 	{
   2379 		case CHECKMETHOD_GET_UNIFORM:	return "get_uniform";
   2380 		case CHECKMETHOD_RENDER:		return "render";
   2381 		default: DE_ASSERT(false);		return DE_NULL;
   2382 	}
   2383 }
   2384 
   2385 const char* UniformValueCase::getCheckMethodDescription (const CheckMethod checkMethod)
   2386 {
   2387 	switch (checkMethod)
   2388 	{
   2389 		case CHECKMETHOD_GET_UNIFORM:	return "Verify values with glGetUniform*()";
   2390 		case CHECKMETHOD_RENDER:		return "Verify values by rendering";
   2391 		default: DE_ASSERT(false);		return DE_NULL;
   2392 	}
   2393 }
   2394 
   2395 const char* UniformValueCase::getAssignMethodName (const AssignMethod assignMethod)
   2396 {
   2397 	switch (assignMethod)
   2398 	{
   2399 		case ASSIGNMETHOD_POINTER:		return "by_pointer";
   2400 		case ASSIGNMETHOD_VALUE:		return "by_value";
   2401 		default: DE_ASSERT(false);		return DE_NULL;
   2402 	}
   2403 }
   2404 
   2405 const char* UniformValueCase::getAssignMethodDescription (const AssignMethod assignMethod)
   2406 {
   2407 	switch (assignMethod)
   2408 	{
   2409 		case ASSIGNMETHOD_POINTER:		return "Assign values by-pointer";
   2410 		case ASSIGNMETHOD_VALUE:		return "Assign values by-value";
   2411 		default: DE_ASSERT(false);		return DE_NULL;
   2412 	}
   2413 }
   2414 
   2415 UniformValueCase::UniformValueCase (Context&									context,
   2416 									const char* const							name,
   2417 									const char* const							description,
   2418 									const CaseShaderType						shaderType,
   2419 									const SharedPtr<const UniformCollection>&	uniformCollection,
   2420 									const ValueToCheck							valueToCheck,
   2421 									const CheckMethod							checkMethod,
   2422 									const AssignMethod							assignMethod,
   2423 									const deUint32								additionalFeatures)
   2424 	: UniformCase		(context, name, description, shaderType, uniformCollection,
   2425 						 (valueToCheck == VALUETOCHECK_INITIAL ? FEATURE_UNIFORMVALUE_ZERO : 0) | (assignMethod == ASSIGNMETHOD_VALUE ? FEATURE_UNIFORMFUNC_VALUE : 0) | additionalFeatures)
   2426 	, m_valueToCheck	(valueToCheck)
   2427 	, m_checkMethod		(checkMethod)
   2428 {
   2429 	DE_ASSERT(!(assignMethod == ASSIGNMETHOD_LAST && valueToCheck == VALUETOCHECK_ASSIGNED));
   2430 }
   2431 
   2432 bool UniformValueCase::test (const vector<BasicUniform>& basicUniforms, const vector<BasicUniformReportRef>& basicUniformReportsRef, const ShaderProgram& program, Random& rnd)
   2433 {
   2434 	DE_UNREF(basicUniformReportsRef);
   2435 
   2436 	const deUint32	programGL	= program.getProgram();
   2437 	TestLog&		log			= m_testCtx.getLog();
   2438 
   2439 	if (m_valueToCheck == VALUETOCHECK_ASSIGNED)
   2440 	{
   2441 		const ScopedLogSection section(log, "UniformAssign", "Uniform value assignments");
   2442 		assignUniforms(basicUniforms, programGL, rnd);
   2443 	}
   2444 	else
   2445 		DE_ASSERT(m_valueToCheck == VALUETOCHECK_INITIAL);
   2446 
   2447 	if (m_checkMethod == CHECKMETHOD_GET_UNIFORM)
   2448 	{
   2449 		vector<VarValue> values;
   2450 
   2451 		{
   2452 			const ScopedLogSection section(log, "GetUniforms", "Uniform value query");
   2453 			const bool success = getUniforms(values, basicUniforms, program.getProgram());
   2454 
   2455 			if (!success)
   2456 				return false;
   2457 		}
   2458 
   2459 		if (m_valueToCheck == VALUETOCHECK_ASSIGNED)
   2460 		{
   2461 			const ScopedLogSection section(log, "ValueCheck", "Verify that the reported values match the assigned values");
   2462 			const bool success = compareUniformValues(values, basicUniforms);
   2463 
   2464 			if (!success)
   2465 				return false;
   2466 		}
   2467 		else
   2468 		{
   2469 			DE_ASSERT(m_valueToCheck == VALUETOCHECK_INITIAL);
   2470 
   2471 			const ScopedLogSection section(log, "ValueCheck", "Verify that the uniforms have correct initial values (zeros)");
   2472 			const bool success = checkUniformDefaultValues(values, basicUniforms);
   2473 
   2474 			if (!success)
   2475 				return false;
   2476 		}
   2477 	}
   2478 	else
   2479 	{
   2480 		DE_ASSERT(m_checkMethod == CHECKMETHOD_RENDER);
   2481 
   2482 		const ScopedLogSection section(log, "RenderTest", "Render test");
   2483 		const bool success = renderTest(basicUniforms, program, rnd);
   2484 
   2485 		if (!success)
   2486 			return false;
   2487 	}
   2488 
   2489 	return true;
   2490 }
   2491 
   2492 class RandomUniformCase : public UniformCase
   2493 {
   2494 public:
   2495 						RandomUniformCase		(Context& m_context, const char* name, const char* description, deUint32 seed);
   2496 
   2497 	bool				test					(const vector<BasicUniform>& basicUniforms, const vector<BasicUniformReportRef>& basicUniformReportsRef, const ShaderProgram& program, Random& rnd);
   2498 };
   2499 
   2500 RandomUniformCase::RandomUniformCase (Context& context, const char* const name, const char* const description, const deUint32 seed)
   2501 	: UniformCase (context, name, description, seed ^ (deUint32)context.getTestContext().getCommandLine().getBaseSeed())
   2502 {
   2503 }
   2504 
   2505 bool RandomUniformCase::test (const vector<BasicUniform>& basicUniforms, const vector<BasicUniformReportRef>& basicUniformReportsRef, const ShaderProgram& program, Random& rnd)
   2506 {
   2507 	// \note Different sampler types may not be bound to same unit when rendering.
   2508 	const bool		renderingPossible						= (m_features & FEATURE_UNIFORMVALUE_ZERO) == 0 || !m_uniformCollection->containsSeveralSamplerTypes();
   2509 
   2510 	bool			performGetActiveUniforms				= rnd.getBool();
   2511 	const bool		performGetActiveUniformsiv				= rnd.getBool();
   2512 	const bool		performUniformVsUniformsivComparison	= performGetActiveUniforms && performGetActiveUniformsiv && rnd.getBool();
   2513 	const bool		performGetUniforms						= rnd.getBool();
   2514 	const bool		performCheckUniformDefaultValues		= performGetUniforms && rnd.getBool();
   2515 	const bool		performAssignUniforms					= rnd.getBool();
   2516 	const bool		performCompareUniformValues				= performGetUniforms && performAssignUniforms && rnd.getBool();
   2517 	const bool		performRenderTest						= renderingPossible && performAssignUniforms && rnd.getBool();
   2518 	const deUint32	programGL								= program.getProgram();
   2519 	TestLog&		log										= m_testCtx.getLog();
   2520 
   2521 	if (!(performGetActiveUniforms || performGetActiveUniformsiv || performUniformVsUniformsivComparison || performGetUniforms || performCheckUniformDefaultValues || performAssignUniforms || performCompareUniformValues || performRenderTest))
   2522 		performGetActiveUniforms = true; // Do something at least.
   2523 
   2524 #define PERFORM_AND_CHECK(CALL, SECTION_NAME, SECTION_DESCRIPTION)						\
   2525 	do																					\
   2526 	{																					\
   2527 		const ScopedLogSection section(log, (SECTION_NAME), (SECTION_DESCRIPTION));		\
   2528 		const bool success = (CALL);													\
   2529 		if (!success)																	\
   2530 			return false;																\
   2531 	} while (false)
   2532 
   2533 	{
   2534 		vector<BasicUniformReportGL> reportsUniform;
   2535 		vector<BasicUniformReportGL> reportsUniformsiv;
   2536 
   2537 		if (performGetActiveUniforms)
   2538 			PERFORM_AND_CHECK(getActiveUniforms(reportsUniform, basicUniformReportsRef, programGL), "InfoGetActiveUniform", "Uniform information queries with glGetActiveUniform()");
   2539 		if (performGetActiveUniformsiv)
   2540 			PERFORM_AND_CHECK(getActiveUniformsiv(reportsUniformsiv, basicUniformReportsRef, programGL), "InfoGetActiveUniformsiv", "Uniform information queries with glGetIndices() and glGetActiveUniformsiv()");
   2541 		if (performUniformVsUniformsivComparison)
   2542 			PERFORM_AND_CHECK(uniformVsUniformsivComparison(reportsUniform, reportsUniformsiv), "CompareUniformVsUniformsiv", "Comparison of results from glGetActiveUniform() and glGetActiveUniformsiv()");
   2543 	}
   2544 
   2545 	{
   2546 		vector<VarValue> uniformDefaultValues;
   2547 
   2548 		if (performGetUniforms)
   2549 			PERFORM_AND_CHECK(getUniforms(uniformDefaultValues, basicUniforms, programGL), "GetUniformDefaults", "Uniform default value query");
   2550 		if (performCheckUniformDefaultValues)
   2551 			PERFORM_AND_CHECK(checkUniformDefaultValues(uniformDefaultValues, basicUniforms), "DefaultValueCheck", "Verify that the uniforms have correct initial values (zeros)");
   2552 	}
   2553 
   2554 	{
   2555 		vector<VarValue> uniformValues;
   2556 
   2557 		if (performAssignUniforms)
   2558 		{
   2559 			const ScopedLogSection section(log, "UniformAssign", "Uniform value assignments");
   2560 			assignUniforms(basicUniforms, programGL, rnd);
   2561 		}
   2562 		if (performCompareUniformValues)
   2563 		{
   2564 			PERFORM_AND_CHECK(getUniforms(uniformValues, basicUniforms, programGL), "GetUniforms", "Uniform value query");
   2565 			PERFORM_AND_CHECK(compareUniformValues(uniformValues, basicUniforms), "ValueCheck", "Verify that the reported values match the assigned values");
   2566 		}
   2567 	}
   2568 
   2569 	if (performRenderTest)
   2570 		PERFORM_AND_CHECK(renderTest(basicUniforms, program, rnd), "RenderTest", "Render test");
   2571 
   2572 #undef PERFORM_AND_CHECK
   2573 
   2574 	return true;
   2575 }
   2576 
   2577 UniformApiTests::UniformApiTests (Context& context)
   2578 	: TestCaseGroup(context, "uniform_api", "Uniform API Tests")
   2579 {
   2580 }
   2581 
   2582 UniformApiTests::~UniformApiTests (void)
   2583 {
   2584 }
   2585 
   2586 namespace
   2587 {
   2588 
   2589 // \note Although this is only used in UniformApiTest::init, it needs to be defined here as it's used as a template argument.
   2590 struct UniformCollectionCase
   2591 {
   2592 	string								namePrefix;
   2593 	SharedPtr<const UniformCollection>	uniformCollection;
   2594 
   2595 	UniformCollectionCase (const char* const name, const UniformCollection* uniformCollection_)
   2596 		: namePrefix			(name ? name + string("_") : "")
   2597 		, uniformCollection		(uniformCollection_)
   2598 	{
   2599 	}
   2600 };
   2601 
   2602 } // anonymous
   2603 
   2604 void UniformApiTests::init (void)
   2605 {
   2606 	// Generate sets of UniformCollections that are used by several cases.
   2607 
   2608 	enum
   2609 	{
   2610 		UNIFORMCOLLECTIONS_BASIC = 0,
   2611 		UNIFORMCOLLECTIONS_BASIC_ARRAY,
   2612 		UNIFORMCOLLECTIONS_BASIC_STRUCT,
   2613 		UNIFORMCOLLECTIONS_STRUCT_IN_ARRAY,
   2614 		UNIFORMCOLLECTIONS_ARRAY_IN_STRUCT,
   2615 		UNIFORMCOLLECTIONS_NESTED_STRUCTS_ARRAYS,
   2616 		UNIFORMCOLLECTIONS_MULTIPLE_BASIC,
   2617 		UNIFORMCOLLECTIONS_MULTIPLE_BASIC_ARRAY,
   2618 		UNIFORMCOLLECTIONS_MULTIPLE_NESTED_STRUCTS_ARRAYS,
   2619 
   2620 		UNIFORMCOLLECTIONS_LAST
   2621 	};
   2622 
   2623 	struct UniformCollectionGroup
   2624 	{
   2625 		string							name;
   2626 		vector<UniformCollectionCase>	cases;
   2627 	} defaultUniformCollections[UNIFORMCOLLECTIONS_LAST];
   2628 
   2629 	defaultUniformCollections[UNIFORMCOLLECTIONS_BASIC].name							= "basic";
   2630 	defaultUniformCollections[UNIFORMCOLLECTIONS_BASIC_ARRAY].name						= "basic_array";
   2631 	defaultUniformCollections[UNIFORMCOLLECTIONS_BASIC_STRUCT].name						= "basic_struct";
   2632 	defaultUniformCollections[UNIFORMCOLLECTIONS_STRUCT_IN_ARRAY].name					= "struct_in_array";
   2633 	defaultUniformCollections[UNIFORMCOLLECTIONS_ARRAY_IN_STRUCT].name					= "array_in_struct";
   2634 	defaultUniformCollections[UNIFORMCOLLECTIONS_NESTED_STRUCTS_ARRAYS].name			= "nested_structs_arrays";
   2635 	defaultUniformCollections[UNIFORMCOLLECTIONS_MULTIPLE_BASIC].name					= "multiple_basic";
   2636 	defaultUniformCollections[UNIFORMCOLLECTIONS_MULTIPLE_BASIC_ARRAY].name				= "multiple_basic_array";
   2637 	defaultUniformCollections[UNIFORMCOLLECTIONS_MULTIPLE_NESTED_STRUCTS_ARRAYS].name	= "multiple_nested_structs_arrays";
   2638 
   2639 	for (int dataTypeNdx = 0; dataTypeNdx < DE_LENGTH_OF_ARRAY(s_testDataTypes); dataTypeNdx++)
   2640 	{
   2641 		const glu::DataType		dataType	= s_testDataTypes[dataTypeNdx];
   2642 		const char* const		typeName	= glu::getDataTypeName(dataType);
   2643 
   2644 		defaultUniformCollections[UNIFORMCOLLECTIONS_BASIC].cases.push_back(UniformCollectionCase(typeName, UniformCollection::basic(dataType)));
   2645 
   2646 		if (glu::isDataTypeScalar(dataType)													||
   2647 			(glu::isDataTypeVector(dataType) && glu::getDataTypeScalarSize(dataType) == 4)	||
   2648 			dataType == glu::TYPE_FLOAT_MAT4												||
   2649 			dataType == glu::TYPE_SAMPLER_2D)
   2650 			defaultUniformCollections[UNIFORMCOLLECTIONS_BASIC_ARRAY].cases.push_back(UniformCollectionCase(typeName, UniformCollection::basicArray(dataType)));
   2651 
   2652 		if (glu::isDataTypeScalar(dataType)		||
   2653 			dataType == glu::TYPE_FLOAT_MAT4	||
   2654 			dataType == glu::TYPE_SAMPLER_2D)
   2655 		{
   2656 			const glu::DataType		secondDataType	= glu::isDataTypeScalar(dataType)	? glu::getDataTypeVector(dataType, 4)
   2657 													: dataType == glu::TYPE_FLOAT_MAT4	? glu::TYPE_FLOAT_MAT2
   2658 													: dataType == glu::TYPE_SAMPLER_2D	? glu::TYPE_SAMPLER_CUBE
   2659 													: glu::TYPE_LAST;
   2660 			DE_ASSERT(secondDataType != glu::TYPE_LAST);
   2661 			const char* const		secondTypeName	= glu::getDataTypeName(secondDataType);
   2662 			const string			name			= string("") + typeName + "_" + secondTypeName;
   2663 
   2664 			defaultUniformCollections[UNIFORMCOLLECTIONS_BASIC_STRUCT].cases.push_back			(UniformCollectionCase(name.c_str(), UniformCollection::basicStruct(dataType, secondDataType, false)));
   2665 			defaultUniformCollections[UNIFORMCOLLECTIONS_ARRAY_IN_STRUCT].cases.push_back		(UniformCollectionCase(name.c_str(), UniformCollection::basicStruct(dataType, secondDataType, true)));
   2666 			defaultUniformCollections[UNIFORMCOLLECTIONS_STRUCT_IN_ARRAY].cases.push_back		(UniformCollectionCase(name.c_str(), UniformCollection::structInArray(dataType, secondDataType, false)));
   2667 			defaultUniformCollections[UNIFORMCOLLECTIONS_NESTED_STRUCTS_ARRAYS].cases.push_back	(UniformCollectionCase(name.c_str(), UniformCollection::nestedArraysStructs(dataType, secondDataType)));
   2668 		}
   2669 	}
   2670 	defaultUniformCollections[UNIFORMCOLLECTIONS_MULTIPLE_BASIC].cases.push_back					(UniformCollectionCase(DE_NULL, UniformCollection::multipleBasic()));
   2671 	defaultUniformCollections[UNIFORMCOLLECTIONS_MULTIPLE_BASIC_ARRAY].cases.push_back				(UniformCollectionCase(DE_NULL, UniformCollection::multipleBasicArray()));
   2672 	defaultUniformCollections[UNIFORMCOLLECTIONS_MULTIPLE_NESTED_STRUCTS_ARRAYS].cases.push_back	(UniformCollectionCase(DE_NULL, UniformCollection::multipleNestedArraysStructs()));
   2673 
   2674 	// Info-query cases (check info returned by e.g. glGetActiveUniforms()).
   2675 
   2676 	{
   2677 		TestCaseGroup* const infoQueryGroup = new TestCaseGroup(m_context, "info_query", "Test uniform info querying functions");
   2678 		addChild(infoQueryGroup);
   2679 		for (int caseTypeI = 0; caseTypeI < (int)UniformInfoQueryCase::CASETYPE_LAST; caseTypeI++)
   2680 		{
   2681 			const UniformInfoQueryCase::CaseType	caseType		= (UniformInfoQueryCase::CaseType)caseTypeI;
   2682 			TestCaseGroup* const					caseTypeGroup	= new TestCaseGroup(m_context, UniformInfoQueryCase::getCaseTypeName(caseType), UniformInfoQueryCase::getCaseTypeDescription(caseType));
   2683 			infoQueryGroup->addChild(caseTypeGroup);
   2684 
   2685 			for (int collectionGroupNdx = 0; collectionGroupNdx < (int)UNIFORMCOLLECTIONS_LAST; collectionGroupNdx++)
   2686 			{
   2687 				const int numArrayFirstElemNameCases = caseType == UniformInfoQueryCase::CASETYPE_INDICES_UNIFORMSIV && collectionGroupNdx == UNIFORMCOLLECTIONS_BASIC_ARRAY ? 2 : 1;
   2688 
   2689 				for (int referToFirstArrayElemWithoutIndexI = 0; referToFirstArrayElemWithoutIndexI < numArrayFirstElemNameCases; referToFirstArrayElemWithoutIndexI++)
   2690 				{
   2691 					const UniformCollectionGroup&	collectionGroup			= defaultUniformCollections[collectionGroupNdx];
   2692 					const string					collectionGroupName		= collectionGroup.name + (referToFirstArrayElemWithoutIndexI == 0 ? "" : "_first_elem_without_brackets");
   2693 					TestCaseGroup* const			collectionTestGroup		= new TestCaseGroup(m_context, collectionGroupName.c_str(), "");
   2694 					caseTypeGroup->addChild(collectionTestGroup);
   2695 
   2696 					for (int collectionNdx = 0; collectionNdx < (int)collectionGroup.cases.size(); collectionNdx++)
   2697 					{
   2698 						const UniformCollectionCase& collectionCase = collectionGroup.cases[collectionNdx];
   2699 
   2700 						for (int shaderType = 0; shaderType < (int)CASESHADERTYPE_LAST; shaderType++)
   2701 						{
   2702 							const string								name				= collectionCase.namePrefix + getCaseShaderTypeName((CaseShaderType)shaderType);
   2703 							const SharedPtr<const UniformCollection>&	uniformCollection	= collectionCase.uniformCollection;
   2704 
   2705 							collectionTestGroup->addChild(new UniformInfoQueryCase(m_context, name.c_str(), "", (CaseShaderType)shaderType, uniformCollection, (UniformInfoQueryCase::CaseType)caseType,
   2706 																				   referToFirstArrayElemWithoutIndexI == 0 ? 0 : UniformCase::FEATURE_ARRAY_FIRST_ELEM_NAME_NO_INDEX));
   2707 						}
   2708 					}
   2709 				}
   2710 			}
   2711 
   2712 			// Info-querying cases when unused uniforms are present.
   2713 
   2714 			{
   2715 				TestCaseGroup* const unusedUniformsGroup = new TestCaseGroup(m_context, "unused_uniforms", "Test with unused uniforms");
   2716 				caseTypeGroup->addChild(unusedUniformsGroup);
   2717 
   2718 				const UniformCollectionGroup& collectionGroup = defaultUniformCollections[UNIFORMCOLLECTIONS_ARRAY_IN_STRUCT];
   2719 
   2720 				for (int collectionNdx = 0; collectionNdx < (int)collectionGroup.cases.size(); collectionNdx++)
   2721 				{
   2722 					const UniformCollectionCase&				collectionCase		= collectionGroup.cases[collectionNdx];
   2723 					const string								collName			= collectionCase.namePrefix;
   2724 					const SharedPtr<const UniformCollection>&	uniformCollection	= collectionCase.uniformCollection;
   2725 
   2726 					for (int shaderType = 0; shaderType < (int)CASESHADERTYPE_LAST; shaderType++)
   2727 					{
   2728 						const string name = collName + getCaseShaderTypeName((CaseShaderType)shaderType);
   2729 						unusedUniformsGroup->addChild(new UniformInfoQueryCase(m_context, name.c_str(), "", (CaseShaderType)shaderType, uniformCollection, (UniformInfoQueryCase::CaseType)caseType,
   2730 																			   UniformCase::FEATURE_UNIFORMUSAGE_EVERY_OTHER | UniformCase::FEATURE_ARRAYUSAGE_ONLY_MIDDLE_INDEX));
   2731 					}
   2732 				}
   2733 			}
   2734 		}
   2735 	}
   2736 
   2737 	// Cases testing uniform values.
   2738 
   2739 	{
   2740 		TestCaseGroup* const valueGroup = new TestCaseGroup(m_context, "value", "Uniform value tests");
   2741 		addChild(valueGroup);
   2742 
   2743 		// Cases checking uniforms' initial values (all must be zeros), with glGetUniform*() or by rendering.
   2744 
   2745 		{
   2746 			TestCaseGroup* const initialValuesGroup = new TestCaseGroup(m_context,
   2747 																		UniformValueCase::getValueToCheckName(UniformValueCase::VALUETOCHECK_INITIAL),
   2748 																		UniformValueCase::getValueToCheckDescription(UniformValueCase::VALUETOCHECK_INITIAL));
   2749 			valueGroup->addChild(initialValuesGroup);
   2750 
   2751 			for (int checkMethodI = 0; checkMethodI < (int)UniformValueCase::CHECKMETHOD_LAST; checkMethodI++)
   2752 			{
   2753 				const UniformValueCase::CheckMethod		checkMethod			= (UniformValueCase::CheckMethod)checkMethodI;
   2754 				TestCaseGroup* const					checkMethodGroup	= new TestCaseGroup(m_context, UniformValueCase::getCheckMethodName(checkMethod), UniformValueCase::getCheckMethodDescription(checkMethod));
   2755 				initialValuesGroup->addChild(checkMethodGroup);
   2756 
   2757 				for (int collectionGroupNdx = 0; collectionGroupNdx < (int)UNIFORMCOLLECTIONS_LAST; collectionGroupNdx++)
   2758 				{
   2759 					const UniformCollectionGroup&	collectionGroup		= defaultUniformCollections[collectionGroupNdx];
   2760 					TestCaseGroup* const			collectionTestGroup	= new TestCaseGroup(m_context, collectionGroup.name.c_str(), "");
   2761 					checkMethodGroup->addChild(collectionTestGroup);
   2762 
   2763 					for (int collectionNdx = 0; collectionNdx < (int)collectionGroup.cases.size(); collectionNdx++)
   2764 					{
   2765 						const UniformCollectionCase&				collectionCase		= collectionGroup.cases[collectionNdx];
   2766 						const string								collName			= collectionCase.namePrefix;
   2767 						const SharedPtr<const UniformCollection>&	uniformCollection	= collectionCase.uniformCollection;
   2768 						const bool									containsBooleans	= uniformCollection->containsMatchingBasicType(glu::isDataTypeBoolOrBVec);
   2769 						const bool									varyBoolApiType		= checkMethod == UniformValueCase::CHECKMETHOD_GET_UNIFORM && containsBooleans &&
   2770 																						  (collectionGroupNdx == UNIFORMCOLLECTIONS_BASIC || collectionGroupNdx == UNIFORMCOLLECTIONS_BASIC_ARRAY);
   2771 						const int									numBoolVariations	= varyBoolApiType ? 3 : 1;
   2772 
   2773 						if (checkMethod == UniformValueCase::CHECKMETHOD_RENDER && uniformCollection->containsSeveralSamplerTypes())
   2774 							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.
   2775 
   2776 						for (int booleanTypeI = 0; booleanTypeI < numBoolVariations; booleanTypeI++)
   2777 						{
   2778 							const deUint32		booleanTypeFeat	= booleanTypeI == 1 ? UniformCase::FEATURE_BOOLEANAPITYPE_INT
   2779 																: booleanTypeI == 2 ? UniformCase::FEATURE_BOOLEANAPITYPE_UINT
   2780 																: 0;
   2781 							const char* const	booleanTypeName	= booleanTypeI == 1 ? "int"
   2782 																: booleanTypeI == 2 ? "uint"
   2783 																: "float";
   2784 							const string		nameWithApiType	= varyBoolApiType ? collName + "api_" + booleanTypeName + "_" : collName;
   2785 
   2786 							for (int shaderType = 0; shaderType < (int)CASESHADERTYPE_LAST; shaderType++)
   2787 							{
   2788 								const string name = nameWithApiType + getCaseShaderTypeName((CaseShaderType)shaderType);
   2789 								collectionTestGroup->addChild(new UniformValueCase(m_context, name.c_str(), "", (CaseShaderType)shaderType, uniformCollection,
   2790 																				   UniformValueCase::VALUETOCHECK_INITIAL, checkMethod, UniformValueCase::ASSIGNMETHOD_LAST, booleanTypeFeat));
   2791 							}
   2792 						}
   2793 					}
   2794 				}
   2795 			}
   2796 		}
   2797 
   2798 		// Cases that first assign values to each uniform, then check the values with glGetUniform*() or by rendering.
   2799 
   2800 		{
   2801 			TestCaseGroup* const assignedValuesGroup = new TestCaseGroup(m_context,
   2802 																		UniformValueCase::getValueToCheckName(UniformValueCase::VALUETOCHECK_ASSIGNED),
   2803 																		UniformValueCase::getValueToCheckDescription(UniformValueCase::VALUETOCHECK_ASSIGNED));
   2804 			valueGroup->addChild(assignedValuesGroup);
   2805 
   2806 			for (int assignMethodI = 0; assignMethodI < (int)UniformValueCase::ASSIGNMETHOD_LAST; assignMethodI++)
   2807 			{
   2808 				const UniformValueCase::AssignMethod	assignMethod		= (UniformValueCase::AssignMethod)assignMethodI;
   2809 				TestCaseGroup* const					assignMethodGroup	= new TestCaseGroup(m_context, UniformValueCase::getAssignMethodName(assignMethod), UniformValueCase::getAssignMethodDescription(assignMethod));
   2810 				assignedValuesGroup->addChild(assignMethodGroup);
   2811 
   2812 				for (int checkMethodI = 0; checkMethodI < (int)UniformValueCase::CHECKMETHOD_LAST; checkMethodI++)
   2813 				{
   2814 					const UniformValueCase::CheckMethod		checkMethod			= (UniformValueCase::CheckMethod)checkMethodI;
   2815 					TestCaseGroup* const					checkMethodGroup	= new TestCaseGroup(m_context, UniformValueCase::getCheckMethodName(checkMethod), UniformValueCase::getCheckMethodDescription(checkMethod));
   2816 					assignMethodGroup->addChild(checkMethodGroup);
   2817 
   2818 					for (int collectionGroupNdx = 0; collectionGroupNdx < (int)UNIFORMCOLLECTIONS_LAST; collectionGroupNdx++)
   2819 					{
   2820 						const int numArrayFirstElemNameCases = checkMethod == UniformValueCase::CHECKMETHOD_GET_UNIFORM && collectionGroupNdx == UNIFORMCOLLECTIONS_BASIC_ARRAY ? 2 : 1;
   2821 
   2822 						for (int referToFirstArrayElemWithoutIndexI = 0; referToFirstArrayElemWithoutIndexI < numArrayFirstElemNameCases; referToFirstArrayElemWithoutIndexI++)
   2823 						{
   2824 							const UniformCollectionGroup&	collectionGroup			= defaultUniformCollections[collectionGroupNdx];
   2825 							const string					collectionGroupName		= collectionGroup.name + (referToFirstArrayElemWithoutIndexI == 0 ? "" : "_first_elem_without_brackets");
   2826 							TestCaseGroup*					collectionTestGroup		= DE_NULL;
   2827 
   2828 							for (int collectionNdx = 0; collectionNdx < (int)collectionGroup.cases.size(); collectionNdx++)
   2829 							{
   2830 								const UniformCollectionCase&				collectionCase		= collectionGroup.cases[collectionNdx];
   2831 								const string								collName			= collectionCase.namePrefix;
   2832 								const SharedPtr<const UniformCollection>&	uniformCollection	= collectionCase.uniformCollection;
   2833 								const bool									containsBooleans	= uniformCollection->containsMatchingBasicType(glu::isDataTypeBoolOrBVec);
   2834 								const bool									varyBoolApiType		= checkMethod == UniformValueCase::CHECKMETHOD_GET_UNIFORM && containsBooleans &&
   2835 																								  (collectionGroupNdx == UNIFORMCOLLECTIONS_BASIC || collectionGroupNdx == UNIFORMCOLLECTIONS_BASIC_ARRAY);
   2836 								const int									numBoolVariations	= varyBoolApiType ? 3 : 1;
   2837 								const bool									containsMatrices	= uniformCollection->containsMatchingBasicType(glu::isDataTypeMatrix);
   2838 								const bool									varyMatrixMode		= containsMatrices &&
   2839 																								  (collectionGroupNdx == UNIFORMCOLLECTIONS_BASIC || collectionGroupNdx == UNIFORMCOLLECTIONS_BASIC_ARRAY);
   2840 								const int									numMatVariations	= varyMatrixMode ? 2 : 1;
   2841 
   2842 								if (containsMatrices && assignMethod != UniformValueCase::ASSIGNMETHOD_POINTER)
   2843 									continue;
   2844 
   2845 								for (int booleanTypeI = 0; booleanTypeI < numBoolVariations; booleanTypeI++)
   2846 								{
   2847 									const deUint32		booleanTypeFeat		= booleanTypeI == 1 ? UniformCase::FEATURE_BOOLEANAPITYPE_INT
   2848 																			: booleanTypeI == 2 ? UniformCase::FEATURE_BOOLEANAPITYPE_UINT
   2849 																			: 0;
   2850 									const char* const	booleanTypeName		= booleanTypeI == 1 ? "int"
   2851 																			: booleanTypeI == 2 ? "uint"
   2852 																			: "float";
   2853 									const string		nameWithBoolType	= varyBoolApiType ? collName + "api_" + booleanTypeName + "_" : collName;
   2854 
   2855 									for (int matrixTypeI = 0; matrixTypeI < numMatVariations; matrixTypeI++)
   2856 									{
   2857 										const string nameWithMatrixType = nameWithBoolType + (matrixTypeI == 1 ? "row_major_" : "");
   2858 
   2859 										for (int shaderType = 0; shaderType < (int)CASESHADERTYPE_LAST; shaderType++)
   2860 										{
   2861 											const string	name							= nameWithMatrixType + getCaseShaderTypeName((CaseShaderType)shaderType);
   2862 											const deUint32	arrayFirstElemNameNoIndexFeat	= referToFirstArrayElemWithoutIndexI == 0 ? 0 : UniformCase::FEATURE_ARRAY_FIRST_ELEM_NAME_NO_INDEX;
   2863 
   2864 											// skip empty groups by creating groups on demand
   2865 											if (!collectionTestGroup)
   2866 											{
   2867 												collectionTestGroup = new TestCaseGroup(m_context, collectionGroupName.c_str(), "");
   2868 												checkMethodGroup->addChild(collectionTestGroup);
   2869 											}
   2870 
   2871 											collectionTestGroup->addChild(new UniformValueCase(m_context, name.c_str(), "", (CaseShaderType)shaderType, uniformCollection,
   2872 																							   UniformValueCase::VALUETOCHECK_ASSIGNED, checkMethod, assignMethod,
   2873 																							   booleanTypeFeat | arrayFirstElemNameNoIndexFeat | (matrixTypeI == 1 ? UniformCase::FEATURE_MATRIXMODE_ROWMAJOR : 0)));
   2874 										}
   2875 									}
   2876 								}
   2877 							}
   2878 						}
   2879 					}
   2880 				}
   2881 			}
   2882 
   2883 			// Cases assign multiple basic-array elements with one glUniform*v() (i.e. the count parameter is bigger than 1).
   2884 
   2885 			{
   2886 				static const struct
   2887 				{
   2888 					UniformCase::Feature	arrayAssignMode;
   2889 					const char*				name;
   2890 					const char*				description;
   2891 				} arrayAssignGroups[] =
   2892 				{
   2893 					{ UniformCase::FEATURE_ARRAYASSIGN_FULL,			"basic_array_assign_full",		"Assign entire basic-type arrays per glUniform*v() call"			},
   2894 					{ UniformCase::FEATURE_ARRAYASSIGN_BLOCKS_OF_TWO,	"basic_array_assign_partial",	"Assign two elements of a basic-type array per glUniform*v() call"	}
   2895 				};
   2896 
   2897 				for (int arrayAssignGroupNdx = 0; arrayAssignGroupNdx < DE_LENGTH_OF_ARRAY(arrayAssignGroups); arrayAssignGroupNdx++)
   2898 				{
   2899 					UniformCase::Feature	arrayAssignMode		= arrayAssignGroups[arrayAssignGroupNdx].arrayAssignMode;
   2900 					const char* const		groupName			= arrayAssignGroups[arrayAssignGroupNdx].name;
   2901 					const char* const		groupDesc			= arrayAssignGroups[arrayAssignGroupNdx].description;
   2902 
   2903 					TestCaseGroup* const curArrayAssignGroup = new TestCaseGroup(m_context, groupName, groupDesc);
   2904 					assignedValuesGroup->addChild(curArrayAssignGroup);
   2905 
   2906 					static const int basicArrayCollectionGroups[] = { UNIFORMCOLLECTIONS_BASIC_ARRAY, UNIFORMCOLLECTIONS_ARRAY_IN_STRUCT, UNIFORMCOLLECTIONS_MULTIPLE_BASIC_ARRAY };
   2907 
   2908 					for (int collectionGroupNdx = 0; collectionGroupNdx < DE_LENGTH_OF_ARRAY(basicArrayCollectionGroups); collectionGroupNdx++)
   2909 					{
   2910 						const UniformCollectionGroup&	collectionGroup		= defaultUniformCollections[basicArrayCollectionGroups[collectionGroupNdx]];
   2911 						TestCaseGroup* const			collectionTestGroup	= new TestCaseGroup(m_context, collectionGroup.name.c_str(), "");
   2912 						curArrayAssignGroup->addChild(collectionTestGroup);
   2913 
   2914 						for (int collectionNdx = 0; collectionNdx < (int)collectionGroup.cases.size(); collectionNdx++)
   2915 						{
   2916 							const UniformCollectionCase&				collectionCase		= collectionGroup.cases[collectionNdx];
   2917 							const string								collName			= collectionCase.namePrefix;
   2918 							const SharedPtr<const UniformCollection>&	uniformCollection	= collectionCase.uniformCollection;
   2919 
   2920 							for (int shaderType = 0; shaderType < (int)CASESHADERTYPE_LAST; shaderType++)
   2921 							{
   2922 								const string name = collName + getCaseShaderTypeName((CaseShaderType)shaderType);
   2923 								collectionTestGroup->addChild(new UniformValueCase(m_context, name.c_str(), "", (CaseShaderType)shaderType, uniformCollection,
   2924 																				   UniformValueCase::VALUETOCHECK_ASSIGNED, UniformValueCase::CHECKMETHOD_GET_UNIFORM, UniformValueCase::ASSIGNMETHOD_POINTER,
   2925 																				   arrayAssignMode));
   2926 							}
   2927 						}
   2928 					}
   2929 				}
   2930 			}
   2931 
   2932 			// Value checking cases when unused uniforms are present.
   2933 
   2934 			{
   2935 				TestCaseGroup* const unusedUniformsGroup = new TestCaseGroup(m_context, "unused_uniforms", "Test with unused uniforms");
   2936 				assignedValuesGroup->addChild(unusedUniformsGroup);
   2937 
   2938 				const UniformCollectionGroup& collectionGroup = defaultUniformCollections[UNIFORMCOLLECTIONS_ARRAY_IN_STRUCT];
   2939 
   2940 				for (int collectionNdx = 0; collectionNdx < (int)collectionGroup.cases.size(); collectionNdx++)
   2941 				{
   2942 					const UniformCollectionCase&				collectionCase		= collectionGroup.cases[collectionNdx];
   2943 					const string								collName			= collectionCase.namePrefix;
   2944 					const SharedPtr<const UniformCollection>&	uniformCollection	= collectionCase.uniformCollection;
   2945 
   2946 					for (int shaderType = 0; shaderType < (int)CASESHADERTYPE_LAST; shaderType++)
   2947 					{
   2948 						const string name = collName + getCaseShaderTypeName((CaseShaderType)shaderType);
   2949 						unusedUniformsGroup->addChild(new UniformValueCase(m_context, name.c_str(), "", (CaseShaderType)shaderType, uniformCollection,
   2950 																		   UniformValueCase::VALUETOCHECK_ASSIGNED, UniformValueCase::CHECKMETHOD_GET_UNIFORM, UniformValueCase::ASSIGNMETHOD_POINTER,
   2951 																		   UniformCase::FEATURE_ARRAYUSAGE_ONLY_MIDDLE_INDEX | UniformCase::FEATURE_UNIFORMUSAGE_EVERY_OTHER));
   2952 					}
   2953 				}
   2954 			}
   2955 		}
   2956 	}
   2957 
   2958 	// Random cases.
   2959 
   2960 	{
   2961 		const int		numRandomCases		= 100;
   2962 		TestCaseGroup*	const randomGroup	= new TestCaseGroup(m_context, "random", "Random cases");
   2963 		addChild(randomGroup);
   2964 
   2965 		for (int ndx = 0; ndx < numRandomCases; ndx++)
   2966 			randomGroup->addChild(new RandomUniformCase(m_context, de::toString(ndx).c_str(), "", (deUint32)ndx));
   2967 	}
   2968 }
   2969 
   2970 } // Functional
   2971 } // gles3
   2972 } // deqp
   2973