Home | History | Annotate | Download | only in functional
      1 /*-------------------------------------------------------------------------
      2  * drawElements Quality Program OpenGL ES 3.1 Module
      3  * -------------------------------------------------
      4  *
      5  * Copyright 2014 The Android Open Source Project
      6  *
      7  * Licensed under the Apache License, Version 2.0 (the "License");
      8  * you may not use this file except in compliance with the License.
      9  * You may obtain a copy of the License at
     10  *
     11  *      http://www.apache.org/licenses/LICENSE-2.0
     12  *
     13  * Unless required by applicable law or agreed to in writing, software
     14  * distributed under the License is distributed on an "AS IS" BASIS,
     15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     16  * See the License for the specific language governing permissions and
     17  * limitations under the License.
     18  *
     19  *//*!
     20  * \file
     21  * \brief glProgramUniform*() tests.
     22  *
     23  * \todo [2013-02-26 nuutti] Much duplication between ES2&3 uniform api
     24  *							 tests and this. Utilities to glshared?
     25  *//*--------------------------------------------------------------------*/
     26 
     27 #include "es31fProgramUniformTests.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 "gluDrawUtil.hpp"
     35 #include "tcuRenderTarget.hpp"
     36 #include "tcuTestLog.hpp"
     37 #include "tcuSurface.hpp"
     38 #include "tcuCommandLine.hpp"
     39 #include "deRandom.hpp"
     40 #include "deStringUtil.hpp"
     41 #include "deString.h"
     42 #include "deSharedPtr.hpp"
     43 #include "deMemory.h"
     44 
     45 #include "glwEnums.hpp"
     46 #include "glwFunctions.hpp"
     47 
     48 #include <set>
     49 #include <cstring>
     50 
     51 using namespace glw;
     52 
     53 namespace deqp
     54 {
     55 namespace gles31
     56 {
     57 namespace Functional
     58 {
     59 
     60 using std::vector;
     61 using std::string;
     62 using tcu::TestLog;
     63 using tcu::ScopedLogSection;
     64 using glu::ShaderProgram;
     65 using glu::StructType;
     66 using de::Random;
     67 using de::SharedPtr;
     68 
     69 typedef bool (* dataTypePredicate)(glu::DataType);
     70 
     71 enum
     72 {
     73 	MAX_RENDER_WIDTH			= 32,
     74 	MAX_RENDER_HEIGHT			= 32,
     75 	MAX_NUM_SAMPLER_UNIFORMS	= 16
     76 };
     77 
     78 static const glu::DataType s_testDataTypes[] =
     79 {
     80 	glu::TYPE_FLOAT,
     81 	glu::TYPE_FLOAT_VEC2,
     82 	glu::TYPE_FLOAT_VEC3,
     83 	glu::TYPE_FLOAT_VEC4,
     84 	glu::TYPE_FLOAT_MAT2,
     85 	glu::TYPE_FLOAT_MAT2X3,
     86 	glu::TYPE_FLOAT_MAT2X4,
     87 	glu::TYPE_FLOAT_MAT3X2,
     88 	glu::TYPE_FLOAT_MAT3,
     89 	glu::TYPE_FLOAT_MAT3X4,
     90 	glu::TYPE_FLOAT_MAT4X2,
     91 	glu::TYPE_FLOAT_MAT4X3,
     92 	glu::TYPE_FLOAT_MAT4,
     93 
     94 	glu::TYPE_INT,
     95 	glu::TYPE_INT_VEC2,
     96 	glu::TYPE_INT_VEC3,
     97 	glu::TYPE_INT_VEC4,
     98 
     99 	glu::TYPE_UINT,
    100 	glu::TYPE_UINT_VEC2,
    101 	glu::TYPE_UINT_VEC3,
    102 	glu::TYPE_UINT_VEC4,
    103 
    104 	glu::TYPE_BOOL,
    105 	glu::TYPE_BOOL_VEC2,
    106 	glu::TYPE_BOOL_VEC3,
    107 	glu::TYPE_BOOL_VEC4,
    108 
    109 	glu::TYPE_SAMPLER_2D,
    110 	glu::TYPE_SAMPLER_CUBE
    111 	// \note We don't test all sampler types here.
    112 };
    113 
    114 static inline int getGLInt (const glw::Functions& funcs, const deUint32 name)
    115 {
    116 	int val = -1;
    117 	funcs.getIntegerv(name, &val);
    118 	return val;
    119 }
    120 
    121 static inline tcu::Vec4 vec4FromPtr (const float* const ptr)
    122 {
    123 	tcu::Vec4 result;
    124 	for (int i = 0; i < 4; i++)
    125 		result[i] = ptr[i];
    126 	return result;
    127 }
    128 
    129 static inline string beforeLast (const string& str, const char c)
    130 {
    131 	return str.substr(0, str.find_last_of(c));
    132 }
    133 
    134 static inline void fillWithColor (const tcu::PixelBufferAccess& access, const tcu::Vec4& color)
    135 {
    136 	for (int z = 0; z < access.getDepth(); z++)
    137 	for (int y = 0; y < access.getHeight(); y++)
    138 	for (int x = 0; x < access.getWidth(); x++)
    139 		access.setPixel(color, x, y, z);
    140 }
    141 
    142 static inline int getSamplerNumLookupDimensions (const glu::DataType type)
    143 {
    144 	switch (type)
    145 	{
    146 		case glu::TYPE_SAMPLER_2D:
    147 		case glu::TYPE_INT_SAMPLER_2D:
    148 		case glu::TYPE_UINT_SAMPLER_2D:
    149 			return 2;
    150 
    151 		case glu::TYPE_SAMPLER_3D:
    152 		case glu::TYPE_INT_SAMPLER_3D:
    153 		case glu::TYPE_UINT_SAMPLER_3D:
    154 		case glu::TYPE_SAMPLER_2D_SHADOW:
    155 		case glu::TYPE_SAMPLER_2D_ARRAY:
    156 		case glu::TYPE_INT_SAMPLER_2D_ARRAY:
    157 		case glu::TYPE_UINT_SAMPLER_2D_ARRAY:
    158 		case glu::TYPE_SAMPLER_CUBE:
    159 		case glu::TYPE_INT_SAMPLER_CUBE:
    160 		case glu::TYPE_UINT_SAMPLER_CUBE:
    161 			return 3;
    162 
    163 		case glu::TYPE_SAMPLER_CUBE_SHADOW:
    164 		case glu::TYPE_SAMPLER_2D_ARRAY_SHADOW:
    165 			return 4;
    166 
    167 		default:
    168 			DE_ASSERT(false);
    169 			return 0;
    170 	}
    171 }
    172 
    173 static inline glu::DataType getSamplerLookupReturnType (const glu::DataType type)
    174 {
    175 	switch (type)
    176 	{
    177 		case glu::TYPE_SAMPLER_2D:
    178 		case glu::TYPE_SAMPLER_CUBE:
    179 		case glu::TYPE_SAMPLER_2D_ARRAY:
    180 		case glu::TYPE_SAMPLER_3D:
    181 			return glu::TYPE_FLOAT_VEC4;
    182 
    183 		case glu::TYPE_UINT_SAMPLER_2D:
    184 		case glu::TYPE_UINT_SAMPLER_CUBE:
    185 		case glu::TYPE_UINT_SAMPLER_2D_ARRAY:
    186 		case glu::TYPE_UINT_SAMPLER_3D:
    187 			return glu::TYPE_UINT_VEC4;
    188 
    189 		case glu::TYPE_INT_SAMPLER_2D:
    190 		case glu::TYPE_INT_SAMPLER_CUBE:
    191 		case glu::TYPE_INT_SAMPLER_2D_ARRAY:
    192 		case glu::TYPE_INT_SAMPLER_3D:
    193 			return glu::TYPE_INT_VEC4;
    194 
    195 		case glu::TYPE_SAMPLER_2D_SHADOW:
    196 		case glu::TYPE_SAMPLER_CUBE_SHADOW:
    197 		case glu::TYPE_SAMPLER_2D_ARRAY_SHADOW:
    198 			return glu::TYPE_FLOAT;
    199 
    200 		default:
    201 			DE_ASSERT(false);
    202 			return glu::TYPE_LAST;
    203 	}
    204 }
    205 
    206 template<glu::DataType T>
    207 static bool dataTypeEquals (const glu::DataType t)
    208 {
    209 	return t == T;
    210 }
    211 
    212 template<int N>
    213 static bool dataTypeIsMatrixWithNRows (const glu::DataType t)
    214 {
    215 	return glu::isDataTypeMatrix(t) && glu::getDataTypeMatrixNumRows(t) == N;
    216 }
    217 
    218 static bool typeContainsMatchingBasicType (const glu::VarType& type, const dataTypePredicate predicate)
    219 {
    220 	if (type.isBasicType())
    221 		return predicate(type.getBasicType());
    222 	else if (type.isArrayType())
    223 		return typeContainsMatchingBasicType(type.getElementType(), predicate);
    224 	else
    225 	{
    226 		DE_ASSERT(type.isStructType());
    227 		const StructType& structType = *type.getStructPtr();
    228 		for (int i = 0; i < structType.getNumMembers(); i++)
    229 			if (typeContainsMatchingBasicType(structType.getMember(i).getType(), predicate))
    230 				return true;
    231 		return false;
    232 	}
    233 }
    234 
    235 static void getDistinctSamplerTypes (vector<glu::DataType>& dst, const glu::VarType& type)
    236 {
    237 	if (type.isBasicType())
    238 	{
    239 		const glu::DataType basicType = type.getBasicType();
    240 		if (glu::isDataTypeSampler(basicType) && std::find(dst.begin(), dst.end(), basicType) == dst.end())
    241 			dst.push_back(basicType);
    242 	}
    243 	else if (type.isArrayType())
    244 		getDistinctSamplerTypes(dst, type.getElementType());
    245 	else
    246 	{
    247 		DE_ASSERT(type.isStructType());
    248 		const StructType& structType = *type.getStructPtr();
    249 		for (int i = 0; i < structType.getNumMembers(); i++)
    250 			getDistinctSamplerTypes(dst, structType.getMember(i).getType());
    251 	}
    252 }
    253 
    254 static int getNumSamplersInType (const glu::VarType& type)
    255 {
    256 	if (type.isBasicType())
    257 		return glu::isDataTypeSampler(type.getBasicType()) ? 1 : 0;
    258 	else if (type.isArrayType())
    259 		return getNumSamplersInType(type.getElementType()) * type.getArraySize();
    260 	else
    261 	{
    262 		DE_ASSERT(type.isStructType());
    263 		const StructType& structType = *type.getStructPtr();
    264 		int sum = 0;
    265 		for (int i = 0; i < structType.getNumMembers(); i++)
    266 			sum += getNumSamplersInType(structType.getMember(i).getType());
    267 		return sum;
    268 	}
    269 }
    270 
    271 namespace
    272 {
    273 
    274 struct VarValue
    275 {
    276 	glu::DataType type;
    277 
    278 	union
    279 	{
    280 		float		floatV[4*4]; // At most mat4. \note Matrices here are column-major.
    281 		deInt32		intV[4];
    282 		deUint32	uintV[4];
    283 		bool		boolV[4];
    284 		struct
    285 		{
    286 			int		unit;
    287 			union
    288 			{
    289 				float		floatV[4];
    290 				deInt32		intV[4];
    291 				deUint32	uintV[4];
    292 			} fillColor;
    293 		} samplerV;
    294 	} val;
    295 };
    296 
    297 enum CaseShaderType
    298 {
    299 	CASESHADERTYPE_VERTEX = 0,
    300 	CASESHADERTYPE_FRAGMENT,
    301 	CASESHADERTYPE_BOTH,
    302 
    303 	CASESHADERTYPE_LAST
    304 };
    305 
    306 struct Uniform
    307 {
    308 	string			name;
    309 	glu::VarType	type;
    310 
    311 	Uniform (const char* const name_, const glu::VarType& type_) : name(name_), type(type_) {}
    312 };
    313 
    314 // A set of uniforms, along with related struct types.
    315 class UniformCollection
    316 {
    317 public:
    318 	int					getNumUniforms		(void) const					{ return (int)m_uniforms.size();	}
    319 	int					getNumStructTypes	(void) const					{ return (int)m_structTypes.size();	}
    320 	Uniform&			getUniform			(const int ndx)					{ return m_uniforms[ndx];			}
    321 	const Uniform&		getUniform			(const int ndx) const			{ return m_uniforms[ndx];			}
    322 	const StructType*	getStructType		(const int ndx) const			{ return m_structTypes[ndx];		}
    323 	void				addUniform			(const Uniform& uniform)		{ m_uniforms.push_back(uniform);	}
    324 	void				addStructType		(const StructType* const type)	{ m_structTypes.push_back(type);	}
    325 
    326 	UniformCollection	(void) {}
    327 	~UniformCollection	(void)
    328 	{
    329 		for (int i = 0; i < (int)m_structTypes.size(); i++)
    330 			delete m_structTypes[i];
    331 	}
    332 
    333 	// Add the contents of m_uniforms and m_structTypes to receiver, and remove them from this one.
    334 	// \note receiver takes ownership of the struct types.
    335 	void moveContents (UniformCollection& receiver)
    336 	{
    337 		for (int i = 0; i < (int)m_uniforms.size(); i++)
    338 			receiver.addUniform(m_uniforms[i]);
    339 		m_uniforms.clear();
    340 
    341 		for (int i = 0; i < (int)m_structTypes.size(); i++)
    342 			receiver.addStructType(m_structTypes[i]);
    343 		m_structTypes.clear();
    344 	}
    345 
    346 	bool containsMatchingBasicType (const dataTypePredicate predicate) const
    347 	{
    348 		for (int i = 0; i < (int)m_uniforms.size(); i++)
    349 			if (typeContainsMatchingBasicType(m_uniforms[i].type, predicate))
    350 				return true;
    351 		return false;
    352 	}
    353 
    354 	vector<glu::DataType> getSamplerTypes (void) const
    355 	{
    356 		vector<glu::DataType> samplerTypes;
    357 		for (int i = 0; i < (int)m_uniforms.size(); i++)
    358 			getDistinctSamplerTypes(samplerTypes, m_uniforms[i].type);
    359 		return samplerTypes;
    360 	}
    361 
    362 	bool containsSeveralSamplerTypes (void) const
    363 	{
    364 		return getSamplerTypes().size() > 1;
    365 	}
    366 
    367 	int getNumSamplers (void) const
    368 	{
    369 		int sum = 0;
    370 		for (int i = 0; i < (int)m_uniforms.size(); i++)
    371 			sum += getNumSamplersInType(m_uniforms[i].type);
    372 		return sum;
    373 	}
    374 
    375 	static UniformCollection* basic (const glu::DataType type, const char* const nameSuffix = "")
    376 	{
    377 		UniformCollection* const	res		= new UniformCollection;
    378 		const glu::Precision		prec	= glu::isDataTypeBoolOrBVec(type) ? glu::PRECISION_LAST : glu::PRECISION_MEDIUMP;
    379 		res->m_uniforms.push_back(Uniform((string("u_var") + nameSuffix).c_str(), glu::VarType(type, prec)));
    380 		return res;
    381 	}
    382 
    383 	static UniformCollection* basicArray (const glu::DataType type, const char* const nameSuffix = "")
    384 	{
    385 		UniformCollection* const	res		= new UniformCollection;
    386 		const glu::Precision		prec	= glu::isDataTypeBoolOrBVec(type) ? glu::PRECISION_LAST : glu::PRECISION_MEDIUMP;
    387 		res->m_uniforms.push_back(Uniform((string("u_var") + nameSuffix).c_str(), glu::VarType(glu::VarType(type, prec), 3)));
    388 		return res;
    389 	}
    390 
    391 	static UniformCollection* basicStruct (const glu::DataType type0, const glu::DataType type1, const bool containsArrays, const char* const nameSuffix = "")
    392 	{
    393 		UniformCollection* const	res		= new UniformCollection;
    394 		const glu::Precision		prec0	= glu::isDataTypeBoolOrBVec(type0) ? glu::PRECISION_LAST : glu::PRECISION_MEDIUMP;
    395 		const glu::Precision		prec1	= glu::isDataTypeBoolOrBVec(type1) ? glu::PRECISION_LAST : glu::PRECISION_MEDIUMP;
    396 
    397 		StructType* const structType = new StructType((string("structType") + nameSuffix).c_str());
    398 		structType->addMember("m0", glu::VarType(type0, prec0));
    399 		structType->addMember("m1", glu::VarType(type1, prec1));
    400 		if (containsArrays)
    401 		{
    402 			structType->addMember("m2", glu::VarType(glu::VarType(type0, prec0), 3));
    403 			structType->addMember("m3", glu::VarType(glu::VarType(type1, prec1), 3));
    404 		}
    405 
    406 		res->addStructType(structType);
    407 		res->addUniform(Uniform((string("u_var") + nameSuffix).c_str(), glu::VarType(structType)));
    408 
    409 		return res;
    410 	}
    411 
    412 	static UniformCollection* structInArray (const glu::DataType type0, const glu::DataType type1, const bool containsArrays, const char* const nameSuffix = "")
    413 	{
    414 		UniformCollection* const res = basicStruct(type0, type1, containsArrays, nameSuffix);
    415 		res->getUniform(0).type = glu::VarType(res->getUniform(0).type, 3);
    416 		return res;
    417 	}
    418 
    419 	static UniformCollection* nestedArraysStructs (const glu::DataType type0, const glu::DataType type1, const char* const nameSuffix = "")
    420 	{
    421 		UniformCollection* const res		= new UniformCollection;
    422 		const glu::Precision prec0			= glu::isDataTypeBoolOrBVec(type0) ? glu::PRECISION_LAST : glu::PRECISION_MEDIUMP;
    423 		const glu::Precision prec1			= glu::isDataTypeBoolOrBVec(type1) ? glu::PRECISION_LAST : glu::PRECISION_MEDIUMP;
    424 		StructType* const structType		= new StructType((string("structType") + nameSuffix).c_str());
    425 		StructType* const subStructType		= new StructType((string("subStructType") + nameSuffix).c_str());
    426 		StructType* const subSubStructType	= new StructType((string("subSubStructType") + nameSuffix).c_str());
    427 
    428 		subSubStructType->addMember("mss0", glu::VarType(type0, prec0));
    429 		subSubStructType->addMember("mss1", glu::VarType(type1, prec1));
    430 
    431 		subStructType->addMember("ms0", glu::VarType(type1, prec1));
    432 		subStructType->addMember("ms1", glu::VarType(glu::VarType(type0, prec0), 2));
    433 		subStructType->addMember("ms2", glu::VarType(glu::VarType(subSubStructType), 2));
    434 
    435 		structType->addMember("m0", glu::VarType(type0, prec0));
    436 		structType->addMember("m1", glu::VarType(subStructType));
    437 		structType->addMember("m2", glu::VarType(type1, prec1));
    438 
    439 		res->addStructType(subSubStructType);
    440 		res->addStructType(subStructType);
    441 		res->addStructType(structType);
    442 
    443 		res->addUniform(Uniform((string("u_var") + nameSuffix).c_str(), glu::VarType(structType)));
    444 
    445 		return res;
    446 	}
    447 
    448 	static UniformCollection* multipleBasic (const char* const nameSuffix = "")
    449 	{
    450 		static const glu::DataType	types[]	= { glu::TYPE_FLOAT, glu::TYPE_INT_VEC3, glu::TYPE_UINT_VEC4, glu::TYPE_FLOAT_MAT3, glu::TYPE_BOOL_VEC2 };
    451 		UniformCollection* const	res		= new UniformCollection;
    452 
    453 		for (int i = 0; i < DE_LENGTH_OF_ARRAY(types); i++)
    454 		{
    455 			UniformCollection* const sub = basic(types[i], ("_" + de::toString(i) + nameSuffix).c_str());
    456 			sub->moveContents(*res);
    457 			delete sub;
    458 		}
    459 
    460 		return res;
    461 	}
    462 
    463 	static UniformCollection* multipleBasicArray (const char* const nameSuffix = "")
    464 	{
    465 		static const glu::DataType	types[]	= { glu::TYPE_FLOAT, glu::TYPE_INT_VEC3, glu::TYPE_BOOL_VEC2 };
    466 		UniformCollection* const	res		= new UniformCollection;
    467 
    468 		for (int i = 0; i < DE_LENGTH_OF_ARRAY(types); i++)
    469 		{
    470 			UniformCollection* const sub = basicArray(types[i], ("_" + de::toString(i) + nameSuffix).c_str());
    471 			sub->moveContents(*res);
    472 			delete sub;
    473 		}
    474 
    475 		return res;
    476 	}
    477 
    478 	static UniformCollection* multipleNestedArraysStructs (const char* const nameSuffix = "")
    479 	{
    480 		static const glu::DataType	types0[]	= { glu::TYPE_FLOAT,		glu::TYPE_INT,		glu::TYPE_BOOL_VEC4 };
    481 		static const glu::DataType	types1[]	= { glu::TYPE_FLOAT_VEC4,	glu::TYPE_INT_VEC4,	glu::TYPE_BOOL };
    482 		UniformCollection* const	res			= new UniformCollection;
    483 
    484 		DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(types0) == DE_LENGTH_OF_ARRAY(types1));
    485 
    486 		for (int i = 0; i < DE_LENGTH_OF_ARRAY(types0); i++)
    487 		{
    488 			UniformCollection* const sub = nestedArraysStructs(types0[i], types1[i], ("_" + de::toString(i) + nameSuffix).c_str());
    489 			sub->moveContents(*res);
    490 			delete sub;
    491 		}
    492 
    493 		return res;
    494 	}
    495 
    496 private:
    497 	// \note Copying these would be cumbersome, since deep-copying both m_uniforms and m_structTypes
    498 	// would mean that we'd need to update pointers from uniforms to point to the new structTypes.
    499 	// When the same UniformCollection is needed in several places, a SharedPtr is used instead.
    500 								UniformCollection	(const UniformCollection&); // Not allowed.
    501 	UniformCollection&			operator=			(const UniformCollection&); // Not allowed.
    502 
    503 	vector<Uniform>				m_uniforms;
    504 	vector<const StructType*>	m_structTypes;
    505 };
    506 
    507 }; // anonymous
    508 
    509 static VarValue getSamplerFillValue (const VarValue& sampler)
    510 {
    511 	DE_ASSERT(glu::isDataTypeSampler(sampler.type));
    512 
    513 	VarValue result;
    514 	result.type = getSamplerLookupReturnType(sampler.type);
    515 
    516 	switch (result.type)
    517 	{
    518 		case glu::TYPE_FLOAT_VEC4:
    519 			for (int i = 0; i < 4; i++)
    520 				result.val.floatV[i] = sampler.val.samplerV.fillColor.floatV[i];
    521 			break;
    522 		case glu::TYPE_UINT_VEC4:
    523 			for (int i = 0; i < 4; i++)
    524 				result.val.uintV[i] = sampler.val.samplerV.fillColor.uintV[i];
    525 			break;
    526 		case glu::TYPE_INT_VEC4:
    527 			for (int i = 0; i < 4; i++)
    528 				result.val.intV[i] = sampler.val.samplerV.fillColor.intV[i];
    529 			break;
    530 		case glu::TYPE_FLOAT:
    531 			result.val.floatV[0] = sampler.val.samplerV.fillColor.floatV[0];
    532 			break;
    533 		default:
    534 			DE_ASSERT(false);
    535 	}
    536 
    537 	return result;
    538 }
    539 
    540 static VarValue getSamplerUnitValue (const VarValue& sampler)
    541 {
    542 	DE_ASSERT(glu::isDataTypeSampler(sampler.type));
    543 
    544 	VarValue result;
    545 	result.type = glu::TYPE_INT;
    546 	result.val.intV[0] = sampler.val.samplerV.unit;
    547 
    548 	return result;
    549 }
    550 
    551 static glu::DataType getDataTypeTransposedMatrix (const glu::DataType original)
    552 {
    553 	return glu::getDataTypeMatrix(glu::getDataTypeMatrixNumRows(original), glu::getDataTypeMatrixNumColumns(original));
    554 }
    555 
    556 static VarValue getTransposeMatrix (const VarValue& original)
    557 {
    558 	DE_ASSERT(glu::isDataTypeMatrix(original.type));
    559 
    560 	const int	rows = glu::getDataTypeMatrixNumRows(original.type);
    561 	const int	cols = glu::getDataTypeMatrixNumColumns(original.type);
    562 	VarValue	result;
    563 	result.type = getDataTypeTransposedMatrix(original.type);
    564 
    565 	for (int i = 0; i < rows; i++)
    566 	for (int j = 0; j < cols; j++)
    567 		result.val.floatV[i*cols + j] = original.val.floatV[j*rows + i];
    568 
    569 	return result;
    570 }
    571 
    572 static string shaderVarValueStr (const VarValue& value)
    573 {
    574 	const int			numElems = glu::getDataTypeScalarSize(value.type);
    575 	std::ostringstream	result;
    576 
    577 	if (numElems > 1)
    578 		result << glu::getDataTypeName(value.type) << "(";
    579 
    580 	for (int i = 0; i < numElems; i++)
    581 	{
    582 		if (i > 0)
    583 			result << ", ";
    584 
    585 		if (glu::isDataTypeFloatOrVec(value.type) || glu::isDataTypeMatrix(value.type))
    586 			result << de::floatToString(value.val.floatV[i], 2);
    587 		else if (glu::isDataTypeIntOrIVec((value.type)))
    588 			result << de::toString(value.val.intV[i]);
    589 		else if (glu::isDataTypeUintOrUVec((value.type)))
    590 			result << de::toString(value.val.uintV[i]) << "u";
    591 		else if (glu::isDataTypeBoolOrBVec((value.type)))
    592 			result << (value.val.boolV[i] ? "true" : "false");
    593 		else if (glu::isDataTypeSampler((value.type)))
    594 			result << shaderVarValueStr(getSamplerFillValue(value));
    595 		else
    596 			DE_ASSERT(false);
    597 	}
    598 
    599 	if (numElems > 1)
    600 		result << ")";
    601 
    602 	return result.str();
    603 }
    604 
    605 static string apiVarValueStr (const VarValue& value)
    606 {
    607 	const int			numElems = glu::getDataTypeScalarSize(value.type);
    608 	std::ostringstream	result;
    609 
    610 	if (numElems > 1)
    611 		result << "(";
    612 
    613 	for (int i = 0; i < numElems; i++)
    614 	{
    615 		if (i > 0)
    616 			result << ", ";
    617 
    618 		if (glu::isDataTypeFloatOrVec(value.type) || glu::isDataTypeMatrix(value.type))
    619 			result << de::floatToString(value.val.floatV[i], 2);
    620 		else if (glu::isDataTypeIntOrIVec((value.type)))
    621 			result << de::toString(value.val.intV[i]);
    622 		else if (glu::isDataTypeUintOrUVec((value.type)))
    623 			result << de::toString(value.val.uintV[i]);
    624 		else if (glu::isDataTypeBoolOrBVec((value.type)))
    625 			result << (value.val.boolV[i] ? "true" : "false");
    626 		else if (glu::isDataTypeSampler((value.type)))
    627 			result << value.val.samplerV.unit;
    628 		else
    629 			DE_ASSERT(false);
    630 	}
    631 
    632 	if (numElems > 1)
    633 		result << ")";
    634 
    635 	return result.str();
    636 }
    637 
    638 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. */)
    639 {
    640 	const int	numElems = glu::getDataTypeScalarSize(type);
    641 	VarValue	result;
    642 	result.type = type;
    643 
    644 	DE_ASSERT((samplerUnit >= 0) == (glu::isDataTypeSampler(type)));
    645 
    646 	if (glu::isDataTypeFloatOrVec(type) || glu::isDataTypeMatrix(type))
    647 	{
    648 		for (int i = 0; i < numElems; i++)
    649 			result.val.floatV[i] = rnd.getFloat(-10.0f, 10.0f);
    650 	}
    651 	else if (glu::isDataTypeIntOrIVec(type))
    652 	{
    653 		for (int i = 0; i < numElems; i++)
    654 			result.val.intV[i] = rnd.getInt(-10, 10);
    655 	}
    656 	else if (glu::isDataTypeUintOrUVec(type))
    657 	{
    658 		for (int i = 0; i < numElems; i++)
    659 			result.val.uintV[i] = (deUint32)rnd.getInt(0, 10);
    660 	}
    661 	else if (glu::isDataTypeBoolOrBVec(type))
    662 	{
    663 		for (int i = 0; i < numElems; i++)
    664 			result.val.boolV[i] = rnd.getBool();
    665 	}
    666 	else if (glu::isDataTypeSampler(type))
    667 	{
    668 		const glu::DataType		texResultType		= getSamplerLookupReturnType(type);
    669 		const glu::DataType		texResultScalarType	= glu::getDataTypeScalarType(texResultType);
    670 		const int				texResultNumDims	= glu::getDataTypeScalarSize(texResultType);
    671 
    672 		result.val.samplerV.unit = samplerUnit;
    673 
    674 		for (int i = 0; i < texResultNumDims; i++)
    675 		{
    676 			switch (texResultScalarType)
    677 			{
    678 				case glu::TYPE_FLOAT:	result.val.samplerV.fillColor.floatV[i]		= rnd.getFloat(0.0f, 1.0f);		break;
    679 				case glu::TYPE_INT:		result.val.samplerV.fillColor.intV[i]		= rnd.getInt(-10, 10);			break;
    680 				case glu::TYPE_UINT:	result.val.samplerV.fillColor.uintV[i]		= (deUint32)rnd.getInt(0, 10);	break;
    681 				default:
    682 					DE_ASSERT(false);
    683 			}
    684 		}
    685 	}
    686 	else
    687 		DE_ASSERT(false);
    688 
    689 	return result;
    690 }
    691 
    692 static bool apiVarValueEquals (const VarValue& a, const VarValue& b)
    693 {
    694 	const int		size			= glu::getDataTypeScalarSize(a.type);
    695 	const float		floatThreshold	= 0.05f;
    696 
    697 	DE_ASSERT(a.type == b.type);
    698 
    699 	if (glu::isDataTypeFloatOrVec(a.type) || glu::isDataTypeMatrix(a.type))
    700 	{
    701 		for (int i = 0; i < size; i++)
    702 			if (de::abs(a.val.floatV[i] - b.val.floatV[i]) >= floatThreshold)
    703 				return false;
    704 	}
    705 	else if (glu::isDataTypeIntOrIVec(a.type))
    706 	{
    707 		for (int i = 0; i < size; i++)
    708 			if (a.val.intV[i] != b.val.intV[i])
    709 				return false;
    710 	}
    711 	else if (glu::isDataTypeUintOrUVec(a.type))
    712 	{
    713 		for (int i = 0; i < size; i++)
    714 			if (a.val.uintV[i] != b.val.uintV[i])
    715 				return false;
    716 	}
    717 	else if (glu::isDataTypeBoolOrBVec(a.type))
    718 	{
    719 		for (int i = 0; i < size; i++)
    720 			if (a.val.boolV[i] != b.val.boolV[i])
    721 				return false;
    722 	}
    723 	else if (glu::isDataTypeSampler(a.type))
    724 	{
    725 		if (a.val.samplerV.unit != b.val.samplerV.unit)
    726 			return false;
    727 	}
    728 	else
    729 		DE_ASSERT(false);
    730 
    731 	return true;
    732 }
    733 
    734 static VarValue getRandomBoolRepresentation (const VarValue& boolValue, const glu::DataType targetScalarType, Random& rnd)
    735 {
    736 	DE_ASSERT(glu::isDataTypeBoolOrBVec(boolValue.type));
    737 
    738 	const int				size		= glu::getDataTypeScalarSize(boolValue.type);
    739 	const glu::DataType		targetType	= size == 1 ? targetScalarType : glu::getDataTypeVector(targetScalarType, size);
    740 	VarValue				result;
    741 	result.type = targetType;
    742 
    743 	switch (targetScalarType)
    744 	{
    745 		case glu::TYPE_INT:
    746 			for (int i = 0; i < size; i++)
    747 			{
    748 				if (boolValue.val.boolV[i])
    749 				{
    750 					result.val.intV[i] = rnd.getInt(-10, 10);
    751 					if (result.val.intV[i] == 0)
    752 						result.val.intV[i] = 1;
    753 				}
    754 				else
    755 					result.val.intV[i] = 0;
    756 			}
    757 			break;
    758 
    759 		case glu::TYPE_UINT:
    760 			for (int i = 0; i < size; i++)
    761 			{
    762 				if (boolValue.val.boolV[i])
    763 					result.val.uintV[i] = rnd.getInt(1, 10);
    764 				else
    765 					result.val.uintV[i] = 0;
    766 			}
    767 			break;
    768 
    769 		case glu::TYPE_FLOAT:
    770 			for (int i = 0; i < size; i++)
    771 			{
    772 				if (boolValue.val.boolV[i])
    773 				{
    774 					result.val.floatV[i] = rnd.getFloat(-10.0f, 10.0f);
    775 					if (result.val.floatV[i] == 0.0f)
    776 						result.val.floatV[i] = 1.0f;
    777 				}
    778 				else
    779 					result.val.floatV[i] = 0;
    780 			}
    781 			break;
    782 
    783 		default:
    784 			DE_ASSERT(false);
    785 	}
    786 
    787 	return result;
    788 }
    789 
    790 static const char* getCaseShaderTypeName (const CaseShaderType type)
    791 {
    792 	switch (type)
    793 	{
    794 		case CASESHADERTYPE_VERTEX:		return "vertex";
    795 		case CASESHADERTYPE_FRAGMENT:	return "fragment";
    796 		case CASESHADERTYPE_BOTH:		return "both";
    797 		default:
    798 			DE_ASSERT(false);
    799 			return DE_NULL;
    800 	}
    801 }
    802 
    803 class UniformCase : public TestCase, protected glu::CallLogWrapper
    804 {
    805 public:
    806 	enum Feature
    807 	{
    808 		// ARRAYUSAGE_ONLY_MIDDLE_INDEX: only middle index of each array is used in shader. If not given, use all indices.
    809 		FEATURE_ARRAYUSAGE_ONLY_MIDDLE_INDEX	= 1<<0,
    810 
    811 		// UNIFORMFUNC_VALUE: use pass-by-value versions of uniform assignment funcs, e.g. glProgramUniform1f(), where possible. If not given, use pass-by-pointer versions.
    812 		FEATURE_UNIFORMFUNC_VALUE				= 1<<1,
    813 
    814 		// MATRIXMODE_ROWMAJOR: pass matrices to GL in row major form. If not given, use column major.
    815 		FEATURE_MATRIXMODE_ROWMAJOR				= 1<<2,
    816 
    817 		// ARRAYASSIGN: how basic-type arrays are assigned with glProgramUniform*(). If none given, assign each element of an array separately.
    818 		FEATURE_ARRAYASSIGN_FULL				= 1<<3, //!< Assign all elements of an array with one glProgramUniform*().
    819 		FEATURE_ARRAYASSIGN_BLOCKS_OF_TWO		= 1<<4, //!< Assign two elements per one glProgramUniform*().
    820 
    821 		// 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).
    822 		FEATURE_UNIFORMUSAGE_EVERY_OTHER		= 1<<5,
    823 
    824 		// BOOLEANAPITYPE: type used to pass booleans to and from GL api. If none given, use float.
    825 		FEATURE_BOOLEANAPITYPE_INT				= 1<<6,
    826 		FEATURE_BOOLEANAPITYPE_UINT				= 1<<7,
    827 
    828 		// 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.
    829 		FEATURE_ARRAY_FIRST_ELEM_NAME_NO_INDEX	= 1<<8
    830 	};
    831 
    832 								UniformCase		(Context& context, const char* name, const char* description, CaseShaderType caseType, const SharedPtr<const UniformCollection>& uniformCollection);
    833 								UniformCase		(Context& context, const char* name, const char* description, CaseShaderType caseType, const SharedPtr<const UniformCollection>& uniformCollection, deUint32 features);
    834 	virtual						~UniformCase	(void);
    835 
    836 	virtual void				init			(void);
    837 	virtual void				deinit			(void);
    838 
    839 	IterateResult				iterate			(void);
    840 
    841 protected:
    842 	// A basic uniform is a uniform (possibly struct or array member) whose type is a basic type (e.g. float, ivec4, sampler2d).
    843 	struct BasicUniform
    844 	{
    845 		string			name;
    846 		glu::DataType	type;
    847 		bool			isUsedInShader;
    848 		VarValue		finalValue;	//!< The value we ultimately want to set for this uniform.
    849 
    850 		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.
    851 		int				elemNdx;	//!< If this is a member of a basic-typed array, elemNdx is the index in that array. Otherwise -1.
    852 		int				rootSize;	//!< If this is a member of a basic-typed array, rootSize is the size of that array. Otherwise 1.
    853 
    854 		BasicUniform (const char* const		name_,
    855 					  const glu::DataType	type_,
    856 					  const bool			isUsedInShader_,
    857 					  const VarValue&		finalValue_,
    858 					  const char* const		rootName_	= DE_NULL,
    859 					  const int				elemNdx_	= -1,
    860 					  const int				rootSize_	= 1)
    861 					  : name			(name_)
    862 					  , type			(type_)
    863 					  , isUsedInShader	(isUsedInShader_)
    864 					  , finalValue		(finalValue_)
    865 					  , rootName		(rootName_ == DE_NULL ? name_ : rootName_)
    866 					  , elemNdx			(elemNdx_)
    867 					  , rootSize		(rootSize_)
    868 					 {
    869 					 }
    870 
    871 		static vector<BasicUniform>::const_iterator findWithName (const vector<BasicUniform>& vec, const char* const name)
    872 		{
    873 			for (vector<BasicUniform>::const_iterator it = vec.begin(); it != vec.end(); it++)
    874 			{
    875 				if (it->name == name)
    876 					return it;
    877 			}
    878 			return vec.end();
    879 		}
    880 	};
    881 
    882 	// Reference values for info that is expected to be reported by glGetActiveUniform() or glGetActiveUniformsiv().
    883 	struct BasicUniformReportRef
    884 	{
    885 		string			name;
    886 		// \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.
    887 		int				minSize;
    888 		int				maxSize;
    889 		glu::DataType	type;
    890 		bool			isUsedInShader;
    891 
    892 		BasicUniformReportRef (const char* const name_, const int minS, const int maxS, const glu::DataType type_, const bool used)
    893 			: name(name_), minSize(minS), maxSize(maxS), type(type_), isUsedInShader(used) { DE_ASSERT(minSize <= maxSize); }
    894 		BasicUniformReportRef (const char* const name_, const glu::DataType type_, const bool used)
    895 			: name(name_), minSize(1), maxSize(1), type(type_), isUsedInShader(used) {}
    896 	};
    897 
    898 	// Get uniform values with glGetUniform*() and put to valuesDst. Uniforms that get -1 from glGetUniformLocation() get glu::TYPE_INVALID.
    899 	bool						getUniforms								(vector<VarValue>& valuesDst, const vector<BasicUniform>& basicUniforms, deUint32 programGL);
    900 	// Assign the basicUniforms[].finalValue values for uniforms. \note rnd parameter is for booleans (true can be any nonzero value).
    901 	void						assignUniforms							(const vector<BasicUniform>& basicUniforms, deUint32 programGL, Random& rnd);
    902 	// Compare the uniform values given in values (obtained with glGetUniform*()) with the basicUniform.finalValue values.
    903 	bool						compareUniformValues					(const vector<VarValue>& values, const vector<BasicUniform>& basicUniforms);
    904 	// Render and check that all pixels are green (i.e. all uniform comparisons passed).
    905 	bool						renderTest								(const vector<BasicUniform>& basicUniforms, const ShaderProgram& program, Random& rnd);
    906 
    907 	virtual bool				test									(const vector<BasicUniform>& basicUniforms, const vector<BasicUniformReportRef>& basicUniformReportsRef, const ShaderProgram& program, Random& rnd) = 0;
    908 
    909 	const deUint32								m_features;
    910 	const SharedPtr<const UniformCollection>	m_uniformCollection;
    911 
    912 private:
    913 	// Generates the basic uniforms, based on the uniform with name varName and type varType, in the same manner as are expected
    914 	// to be returned by glGetActiveUniform(), e.g. generates a name like var[0] for arrays, and recursively generates struct member names.
    915 	void						generateBasicUniforms					(vector<BasicUniform>&				basicUniformsDst,
    916 																		 vector<BasicUniformReportRef>&		basicUniformReportsDst,
    917 																		 const glu::VarType&				varType,
    918 																		 const char*						varName,
    919 																		 bool								isParentActive,
    920 																		 int&								samplerUnitCounter,
    921 																		 Random&							rnd) const;
    922 
    923 	void						writeUniformDefinitions					(std::ostringstream& dst) const;
    924 	void						writeUniformCompareExpr					(std::ostringstream& dst, const BasicUniform& uniform) const;
    925 	void						writeUniformComparisons					(std::ostringstream& dst, const vector<BasicUniform>& basicUniforms, const char* variableName) const;
    926 
    927 	string						generateVertexSource					(const vector<BasicUniform>& basicUniforms) const;
    928 	string						generateFragmentSource					(const vector<BasicUniform>& basicUniforms) const;
    929 
    930 	void						setupTexture							(const VarValue& value);
    931 
    932 	const CaseShaderType						m_caseShaderType;
    933 
    934 	vector<glu::Texture2D*>						m_textures2d;
    935 	vector<glu::TextureCube*>					m_texturesCube;
    936 	vector<deUint32>							m_filledTextureUnits;
    937 };
    938 
    939 UniformCase::UniformCase (Context& context, const char* const name, const char* const description, const CaseShaderType caseShaderType, const SharedPtr<const UniformCollection>& uniformCollection, const deUint32 features)
    940 	: TestCase				(context, name, description)
    941 	, CallLogWrapper		(context.getRenderContext().getFunctions(), m_testCtx.getLog())
    942 	, m_features			(features)
    943 	, m_uniformCollection	(uniformCollection)
    944 	, m_caseShaderType		(caseShaderType)
    945 {
    946 }
    947 
    948 UniformCase::UniformCase (Context& context, const char* const name, const char* const description, const CaseShaderType caseShaderType, const SharedPtr<const UniformCollection>& uniformCollection)
    949 	: TestCase				(context, name, description)
    950 	, CallLogWrapper		(context.getRenderContext().getFunctions(), m_testCtx.getLog())
    951 	, m_features			(0)
    952 	, m_uniformCollection	(uniformCollection)
    953 	, m_caseShaderType		(caseShaderType)
    954 {
    955 }
    956 
    957 void UniformCase::init (void)
    958 {
    959 	{
    960 		const glw::Functions&	funcs						= m_context.getRenderContext().getFunctions();
    961 		const int				numSamplerUniforms			= m_uniformCollection->getNumSamplers();
    962 		const int				vertexTexUnitsRequired		= m_caseShaderType != CASESHADERTYPE_FRAGMENT ? numSamplerUniforms : 0;
    963 		const int				fragmentTexUnitsRequired	= m_caseShaderType != CASESHADERTYPE_VERTEX ? numSamplerUniforms : 0;
    964 		const int				combinedTexUnitsRequired	= vertexTexUnitsRequired + fragmentTexUnitsRequired;
    965 		const int				vertexTexUnitsSupported		= getGLInt(funcs, GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS);
    966 		const int				fragmentTexUnitsSupported	= getGLInt(funcs, GL_MAX_TEXTURE_IMAGE_UNITS);
    967 		const int				combinedTexUnitsSupported	= getGLInt(funcs, GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS);
    968 
    969 		DE_ASSERT(numSamplerUniforms <= MAX_NUM_SAMPLER_UNIFORMS);
    970 
    971 		if (vertexTexUnitsRequired > vertexTexUnitsSupported)
    972 			throw tcu::NotSupportedError(de::toString(vertexTexUnitsRequired) + " vertex texture units required, " + de::toString(vertexTexUnitsSupported) + " supported");
    973 		if (fragmentTexUnitsRequired > fragmentTexUnitsSupported)
    974 			throw tcu::NotSupportedError(de::toString(fragmentTexUnitsRequired) + " fragment texture units required, " + de::toString(fragmentTexUnitsSupported) + " supported");
    975 		if (combinedTexUnitsRequired > combinedTexUnitsSupported)
    976 			throw tcu::NotSupportedError(de::toString(combinedTexUnitsRequired) + " combined texture units required, " + de::toString(combinedTexUnitsSupported) + " supported");
    977 	}
    978 
    979 	enableLogging(true);
    980 }
    981 
    982 void UniformCase::deinit (void)
    983 {
    984 	for (int i = 0; i < (int)m_textures2d.size(); i++)
    985 		delete m_textures2d[i];
    986 	m_textures2d.clear();
    987 
    988 	for (int i = 0; i < (int)m_texturesCube.size(); i++)
    989 		delete m_texturesCube[i];
    990 	m_texturesCube.clear();
    991 
    992 	m_filledTextureUnits.clear();
    993 }
    994 
    995 UniformCase::~UniformCase (void)
    996 {
    997 	UniformCase::deinit();
    998 }
    999 
   1000 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
   1001 {
   1002 	if (varType.isBasicType())
   1003 	{
   1004 		const bool				isActive	= isParentActive && (m_features & FEATURE_UNIFORMUSAGE_EVERY_OTHER ? basicUniformsDst.size() % 2 == 0 : true);
   1005 		const glu::DataType		type		= varType.getBasicType();
   1006 		const VarValue			value		= glu::isDataTypeSampler(type) ? generateRandomVarValue(type, rnd, samplerUnitCounter++)
   1007 																		   : generateRandomVarValue(varType.getBasicType(), rnd);
   1008 
   1009 		basicUniformsDst.push_back(BasicUniform(varName, varType.getBasicType(), isActive, value));
   1010 		basicUniformReportsDst.push_back(BasicUniformReportRef(varName, varType.getBasicType(), isActive));
   1011 	}
   1012 	else if (varType.isArrayType())
   1013 	{
   1014 		const int		size			= varType.getArraySize();
   1015 		const string	arrayRootName	= string("") + varName + "[0]";
   1016 		vector<bool>	isElemActive;
   1017 
   1018 		for (int elemNdx = 0; elemNdx < varType.getArraySize(); elemNdx++)
   1019 		{
   1020 			const string	indexedName		= string("") + varName + "[" + de::toString(elemNdx) + "]";
   1021 			const bool		isCurElemActive	= isParentActive																						&&
   1022 											  (m_features & FEATURE_UNIFORMUSAGE_EVERY_OTHER			? basicUniformsDst.size() % 2 == 0	: true)	&&
   1023 											  (m_features & FEATURE_ARRAYUSAGE_ONLY_MIDDLE_INDEX		? elemNdx == size/2					: true);
   1024 
   1025 			isElemActive.push_back(isCurElemActive);
   1026 
   1027 			if (varType.getElementType().isBasicType())
   1028 			{
   1029 				// \note We don't want separate entries in basicUniformReportsDst for elements of basic-type arrays.
   1030 				const glu::DataType	elemBasicType	= varType.getElementType().getBasicType();
   1031 				const VarValue		value			= glu::isDataTypeSampler(elemBasicType) ? generateRandomVarValue(elemBasicType, rnd, samplerUnitCounter++)
   1032 																							: generateRandomVarValue(elemBasicType, rnd);
   1033 
   1034 				basicUniformsDst.push_back(BasicUniform(indexedName.c_str(), elemBasicType, isCurElemActive, value, arrayRootName.c_str(), elemNdx, size));
   1035 			}
   1036 			else
   1037 				generateBasicUniforms(basicUniformsDst, basicUniformReportsDst, varType.getElementType(), indexedName.c_str(), isCurElemActive, samplerUnitCounter, rnd);
   1038 		}
   1039 
   1040 		if (varType.getElementType().isBasicType())
   1041 		{
   1042 			int minSize;
   1043 			for (minSize = varType.getArraySize(); minSize > 0 && !isElemActive[minSize-1]; minSize--);
   1044 
   1045 			basicUniformReportsDst.push_back(BasicUniformReportRef(arrayRootName.c_str(), minSize, size, varType.getElementType().getBasicType(), isParentActive && minSize > 0));
   1046 		}
   1047 	}
   1048 	else
   1049 	{
   1050 		DE_ASSERT(varType.isStructType());
   1051 
   1052 		const StructType& structType = *varType.getStructPtr();
   1053 
   1054 		for (int i = 0; i < structType.getNumMembers(); i++)
   1055 		{
   1056 			const glu::StructMember&	member			= structType.getMember(i);
   1057 			const string				memberFullName	= string("") + varName + "." + member.getName();
   1058 
   1059 			generateBasicUniforms(basicUniformsDst, basicUniformReportsDst, member.getType(), memberFullName.c_str(), isParentActive, samplerUnitCounter, rnd);
   1060 		}
   1061 	}
   1062 }
   1063 
   1064 void UniformCase::writeUniformDefinitions (std::ostringstream& dst) const
   1065 {
   1066 	for (int i = 0; i < (int)m_uniformCollection->getNumStructTypes(); i++)
   1067 		dst << glu::declare(m_uniformCollection->getStructType(i)) << ";\n";
   1068 
   1069 	for (int i = 0; i < (int)m_uniformCollection->getNumUniforms(); i++)
   1070 		dst << "uniform " << glu::declare(m_uniformCollection->getUniform(i).type, m_uniformCollection->getUniform(i).name.c_str()) << ";\n";
   1071 
   1072 	dst << "\n";
   1073 
   1074 	{
   1075 		static const struct
   1076 		{
   1077 			dataTypePredicate	requiringTypes[2];
   1078 			const char*			definition;
   1079 		} compareFuncs[] =
   1080 		{
   1081 			{ { glu::isDataTypeFloatOrVec,				glu::isDataTypeMatrix				}, "mediump float compare_float    (mediump float a, mediump float b)  { return abs(a - b) < 0.05 ? 1.0 : 0.0; }"																		},
   1082 			{ { 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); }"														},
   1083 			{ { 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); }"								},
   1084 			{ { 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); }"		},
   1085 			{ { 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]); }"													},
   1086 			{ { 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]); }"													},
   1087 			{ { 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]); }"													},
   1088 			{ { 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]); }"							},
   1089 			{ { 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]); }"							},
   1090 			{ { 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]); }"							},
   1091 			{ { 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]); }"	},
   1092 			{ { 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]); }"	},
   1093 			{ { 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]); }"	},
   1094 			{ { 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; }"																					},
   1095 			{ { 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; }"																					},
   1096 			{ { 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; }"																					},
   1097 			{ { 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; }"																					},
   1098 			{ { 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; }"																					},
   1099 			{ { 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; }"																					},
   1100 			{ { 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; }"																					},
   1101 			{ { 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; }"																					},
   1102 			{ { dataTypeEquals<glu::TYPE_BOOL>,			dataTypeEquals<glu::TYPE_INVALID>	}, "mediump float compare_bool     (bool a, bool b)                    { return a == b ? 1.0 : 0.0; }"																					},
   1103 			{ { dataTypeEquals<glu::TYPE_BOOL_VEC2>,	dataTypeEquals<glu::TYPE_INVALID>	}, "mediump float compare_bvec2    (bvec2 a, bvec2 b)                  { return a == b ? 1.0 : 0.0; }"																					},
   1104 			{ { dataTypeEquals<glu::TYPE_BOOL_VEC3>,	dataTypeEquals<glu::TYPE_INVALID>	}, "mediump float compare_bvec3    (bvec3 a, bvec3 b)                  { return a == b ? 1.0 : 0.0; }"																					},
   1105 			{ { dataTypeEquals<glu::TYPE_BOOL_VEC4>,	dataTypeEquals<glu::TYPE_INVALID>	}, "mediump float compare_bvec4    (bvec4 a, bvec4 b)                  { return a == b ? 1.0 : 0.0; }"																					}
   1106 		};
   1107 
   1108 		const vector<glu::DataType> samplerTypes = m_uniformCollection->getSamplerTypes();
   1109 
   1110 		for (int compFuncNdx = 0; compFuncNdx < DE_LENGTH_OF_ARRAY(compareFuncs); compFuncNdx++)
   1111 		{
   1112 			const dataTypePredicate		(&typeReq)[2]			= compareFuncs[compFuncNdx].requiringTypes;
   1113 			bool						containsTypeSampler		= false;
   1114 
   1115 			for (int i = 0; i < (int)samplerTypes.size(); i++)
   1116 			{
   1117 				if (glu::isDataTypeSampler(samplerTypes[i]))
   1118 				{
   1119 					const glu::DataType retType = getSamplerLookupReturnType(samplerTypes[i]);
   1120 					if (typeReq[0](retType) || typeReq[1](retType))
   1121 					{
   1122 						containsTypeSampler = true;
   1123 						break;
   1124 					}
   1125 				}
   1126 			}
   1127 
   1128 			if (containsTypeSampler || m_uniformCollection->containsMatchingBasicType(typeReq[0]) || m_uniformCollection->containsMatchingBasicType(typeReq[1]))
   1129 				dst << compareFuncs[compFuncNdx].definition << "\n";
   1130 		}
   1131 	}
   1132 }
   1133 
   1134 void UniformCase::writeUniformCompareExpr (std::ostringstream& dst, const BasicUniform& uniform) const
   1135 {
   1136 	if (glu::isDataTypeSampler(uniform.type))
   1137 		dst << "compare_" << glu::getDataTypeName(getSamplerLookupReturnType(uniform.type)) << "(texture(" << uniform.name << ", vec" << getSamplerNumLookupDimensions(uniform.type) << "(0.0))";
   1138 	else
   1139 		dst << "compare_" << glu::getDataTypeName(uniform.type) << "(" << uniform.name;
   1140 
   1141 	dst << ", " << shaderVarValueStr(uniform.finalValue) << ")";
   1142 }
   1143 
   1144 void UniformCase::writeUniformComparisons (std::ostringstream& dst, const vector<BasicUniform>& basicUniforms, const char* const variableName) const
   1145 {
   1146 	for (int i = 0; i < (int)basicUniforms.size(); i++)
   1147 	{
   1148 		const BasicUniform& unif = basicUniforms[i];
   1149 
   1150 		if (unif.isUsedInShader)
   1151 		{
   1152 			dst << "\t" << variableName << " *= ";
   1153 			writeUniformCompareExpr(dst, basicUniforms[i]);
   1154 			dst << ";\n";
   1155 		}
   1156 		else
   1157 			dst << "\t// UNUSED: " << basicUniforms[i].name << "\n";
   1158 	}
   1159 }
   1160 
   1161 string UniformCase::generateVertexSource (const vector<BasicUniform>& basicUniforms) const
   1162 {
   1163 	const bool			isVertexCase = m_caseShaderType == CASESHADERTYPE_VERTEX || m_caseShaderType == CASESHADERTYPE_BOTH;
   1164 	std::ostringstream	result;
   1165 
   1166 	result << "#version 310 es\n"
   1167 			  "in highp vec4 a_position;\n"
   1168 			  "out mediump float v_vtxOut;\n"
   1169 			  "\n";
   1170 
   1171 	if (isVertexCase)
   1172 		writeUniformDefinitions(result);
   1173 
   1174 	result << "\n"
   1175 			  "void main (void)\n"
   1176 			  "{\n"
   1177 			  "	gl_Position = a_position;\n"
   1178 			  "	v_vtxOut = 1.0;\n";
   1179 
   1180 	if (isVertexCase)
   1181 		writeUniformComparisons(result, basicUniforms, "v_vtxOut");
   1182 
   1183 	result << "}\n";
   1184 
   1185 	return result.str();
   1186 }
   1187 
   1188 string UniformCase::generateFragmentSource (const vector<BasicUniform>& basicUniforms) const
   1189 {
   1190 	const bool			isFragmentCase = m_caseShaderType == CASESHADERTYPE_FRAGMENT || m_caseShaderType == CASESHADERTYPE_BOTH;
   1191 	std::ostringstream	result;
   1192 
   1193 	result << "#version 310 es\n"
   1194 			  "in mediump float v_vtxOut;\n"
   1195 			  "\n";
   1196 
   1197 	if (isFragmentCase)
   1198 		writeUniformDefinitions(result);
   1199 
   1200 	result << "\n"
   1201 			  "layout(location = 0) out mediump vec4 dEQP_FragColor;\n"
   1202 			  "\n"
   1203 			  "void main (void)\n"
   1204 			  "{\n"
   1205 			  "	mediump float result = v_vtxOut;\n";
   1206 
   1207 	if (isFragmentCase)
   1208 		writeUniformComparisons(result, basicUniforms, "result");
   1209 
   1210 	result << "	dEQP_FragColor = vec4(1.0-result, result, 0.0, 1.0);\n"
   1211 			  "}\n";
   1212 
   1213 	return result.str();
   1214 }
   1215 
   1216 void UniformCase::setupTexture (const VarValue& value)
   1217 {
   1218 	// \note No handling for samplers other than 2D or cube.
   1219 
   1220 	enableLogging(false);
   1221 
   1222 	DE_ASSERT(getSamplerLookupReturnType(value.type) == glu::TYPE_FLOAT_VEC4);
   1223 
   1224 	const int						width			= 32;
   1225 	const int						height			= 32;
   1226 	const tcu::Vec4					color			= vec4FromPtr(&value.val.samplerV.fillColor.floatV[0]);
   1227 
   1228 	if (value.type == glu::TYPE_SAMPLER_2D)
   1229 	{
   1230 		glu::Texture2D* texture		= new glu::Texture2D(m_context.getRenderContext(), GL_RGBA, GL_UNSIGNED_BYTE, width, height);
   1231 		tcu::Texture2D& refTexture	= texture->getRefTexture();
   1232 		m_textures2d.push_back(texture);
   1233 
   1234 		refTexture.allocLevel(0);
   1235 		fillWithColor(refTexture.getLevel(0), color);
   1236 
   1237 		GLU_CHECK_CALL(glActiveTexture(GL_TEXTURE0 + value.val.samplerV.unit));
   1238 		m_filledTextureUnits.push_back(value.val.samplerV.unit);
   1239 		texture->upload();
   1240 		GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
   1241 		GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
   1242 		GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
   1243 		GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
   1244 	}
   1245 	else if (value.type == glu::TYPE_SAMPLER_CUBE)
   1246 	{
   1247 		DE_STATIC_ASSERT(width == height);
   1248 		glu::TextureCube* texture		= new glu::TextureCube(m_context.getRenderContext(), GL_RGBA, GL_UNSIGNED_BYTE, width);
   1249 		tcu::TextureCube& refTexture	= texture->getRefTexture();
   1250 		m_texturesCube.push_back(texture);
   1251 
   1252 		for (int face = 0; face < (int)tcu::CUBEFACE_LAST; face++)
   1253 		{
   1254 			refTexture.allocLevel((tcu::CubeFace)face, 0);
   1255 			fillWithColor(refTexture.getLevelFace(0, (tcu::CubeFace)face), color);
   1256 		}
   1257 
   1258 		GLU_CHECK_CALL(glActiveTexture(GL_TEXTURE0 + value.val.samplerV.unit));
   1259 		m_filledTextureUnits.push_back(value.val.samplerV.unit);
   1260 		texture->upload();
   1261 		GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
   1262 		GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
   1263 		GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
   1264 		GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
   1265 
   1266 	}
   1267 	else
   1268 		DE_ASSERT(false);
   1269 
   1270 	enableLogging(true);
   1271 }
   1272 
   1273 bool UniformCase::getUniforms (vector<VarValue>& valuesDst, const vector<BasicUniform>& basicUniforms, const deUint32 programGL)
   1274 {
   1275 	TestLog&	log			= m_testCtx.getLog();
   1276 	bool		success		= true;
   1277 
   1278 	for (int unifNdx = 0; unifNdx < (int)basicUniforms.size(); unifNdx++)
   1279 	{
   1280 		const BasicUniform&		uniform		= basicUniforms[unifNdx];
   1281 		const string			queryName	= m_features & FEATURE_ARRAY_FIRST_ELEM_NAME_NO_INDEX && uniform.elemNdx == 0 ? beforeLast(uniform.name, '[') : uniform.name;
   1282 		const int				location	= glGetUniformLocation(programGL, queryName.c_str());
   1283 		const int				size		= glu::getDataTypeScalarSize(uniform.type);
   1284 		VarValue				value;
   1285 
   1286 		deMemset(&value, 0xcd, sizeof(value)); // Initialize to known garbage.
   1287 
   1288 		if (location == -1)
   1289 		{
   1290 			value.type = glu::TYPE_INVALID;
   1291 			valuesDst.push_back(value);
   1292 			if (uniform.isUsedInShader)
   1293 			{
   1294 				log << TestLog::Message << "// FAILURE: " << uniform.name << " was used in shader, but has location -1" << TestLog::EndMessage;
   1295 				success = false;
   1296 			}
   1297 			continue;
   1298 		}
   1299 
   1300 		value.type = uniform.type;
   1301 
   1302 		DE_STATIC_ASSERT(sizeof(GLint) == sizeof(value.val.intV[0]));
   1303 		DE_STATIC_ASSERT(sizeof(GLuint) == sizeof(value.val.uintV[0]));
   1304 		DE_STATIC_ASSERT(sizeof(GLfloat) == sizeof(value.val.floatV[0]));
   1305 
   1306 		if (glu::isDataTypeFloatOrVec(uniform.type) || glu::isDataTypeMatrix(uniform.type))
   1307 			GLU_CHECK_CALL(glGetUniformfv(programGL, location, &value.val.floatV[0]));
   1308 		else if (glu::isDataTypeIntOrIVec(uniform.type))
   1309 			GLU_CHECK_CALL(glGetUniformiv(programGL, location, &value.val.intV[0]));
   1310 		else if (glu::isDataTypeUintOrUVec(uniform.type))
   1311 			GLU_CHECK_CALL(glGetUniformuiv(programGL, location, &value.val.uintV[0]));
   1312 		else if (glu::isDataTypeBoolOrBVec(uniform.type))
   1313 		{
   1314 			if (m_features & FEATURE_BOOLEANAPITYPE_INT)
   1315 			{
   1316 				GLU_CHECK_CALL(glGetUniformiv(programGL, location, &value.val.intV[0]));
   1317 				for (int i = 0; i < size; i++)
   1318 					value.val.boolV[i] = value.val.intV[i] != 0;
   1319 			}
   1320 			else if (m_features & FEATURE_BOOLEANAPITYPE_UINT)
   1321 			{
   1322 				GLU_CHECK_CALL(glGetUniformuiv(programGL, location, &value.val.uintV[0]));
   1323 				for (int i = 0; i < size; i++)
   1324 					value.val.boolV[i] = value.val.uintV[i] != 0;
   1325 			}
   1326 			else // Default: use float.
   1327 			{
   1328 				GLU_CHECK_CALL(glGetUniformfv(programGL, location, &value.val.floatV[0]));
   1329 				for (int i = 0; i < size; i++)
   1330 					value.val.boolV[i] = value.val.floatV[i] != 0.0f;
   1331 			}
   1332 		}
   1333 		else if (glu::isDataTypeSampler(uniform.type))
   1334 		{
   1335 			GLint unit = -1;
   1336 			GLU_CHECK_CALL(glGetUniformiv(programGL, location, &unit));
   1337 			value.val.samplerV.unit = unit;
   1338 		}
   1339 		else
   1340 			DE_ASSERT(false);
   1341 
   1342 		valuesDst.push_back(value);
   1343 
   1344 		log << TestLog::Message << "// Got " << uniform.name << " value " << apiVarValueStr(value) << TestLog::EndMessage;
   1345 	}
   1346 
   1347 	return success;
   1348 }
   1349 
   1350 void UniformCase::assignUniforms (const vector<BasicUniform>& basicUniforms, deUint32 programGL, Random& rnd)
   1351 {
   1352 	TestLog&				log				= m_testCtx.getLog();
   1353 	const bool				transpose		= (m_features & FEATURE_MATRIXMODE_ROWMAJOR) != 0;
   1354 	const GLboolean			transposeGL		= transpose ? GL_TRUE : GL_FALSE;
   1355 	const glu::DataType		boolApiType		= m_features & FEATURE_BOOLEANAPITYPE_INT	? glu::TYPE_INT
   1356 											: m_features & FEATURE_BOOLEANAPITYPE_UINT	? glu::TYPE_UINT
   1357 											:											  glu::TYPE_FLOAT;
   1358 
   1359 	for (int unifNdx = 0; unifNdx < (int)basicUniforms.size(); unifNdx++)
   1360 	{
   1361 		const BasicUniform&		uniform				= basicUniforms[unifNdx];
   1362 		const bool				isArrayMember		= uniform.elemNdx >= 0;
   1363 		const string			queryName			= m_features & FEATURE_ARRAY_FIRST_ELEM_NAME_NO_INDEX && uniform.elemNdx == 0 ? beforeLast(uniform.name, '[') : uniform.name;
   1364 		const int				numValuesToAssign	= !isArrayMember									? 1
   1365 													: m_features & FEATURE_ARRAYASSIGN_FULL				? (uniform.elemNdx == 0			? uniform.rootSize	: 0)
   1366 													: m_features & FEATURE_ARRAYASSIGN_BLOCKS_OF_TWO	? (uniform.elemNdx % 2 == 0		? 2					: 0)
   1367 													: /* Default: assign array elements separately */	  1;
   1368 
   1369 		DE_ASSERT(numValuesToAssign >= 0);
   1370 		DE_ASSERT(numValuesToAssign == 1 || isArrayMember);
   1371 
   1372 		if (numValuesToAssign == 0)
   1373 		{
   1374 			log << TestLog::Message << "// Uniform " << uniform.name << " is covered by another glProgramUniform*v() call to the same array" << TestLog::EndMessage;
   1375 			continue;
   1376 		}
   1377 
   1378 		const int			location			= glGetUniformLocation(programGL, queryName.c_str());
   1379 		const int			typeSize			= glu::getDataTypeScalarSize(uniform.type);
   1380 		const bool			assignByValue		= m_features & FEATURE_UNIFORMFUNC_VALUE && !glu::isDataTypeMatrix(uniform.type) && numValuesToAssign == 1;
   1381 		vector<VarValue>	valuesToAssign;
   1382 
   1383 		for (int i = 0; i < numValuesToAssign; i++)
   1384 		{
   1385 			const string	curName = isArrayMember ? beforeLast(uniform.rootName, '[') + "[" + de::toString(uniform.elemNdx+i) + "]" : uniform.name;
   1386 			VarValue		unifValue;
   1387 
   1388 			if (isArrayMember)
   1389 			{
   1390 				const vector<BasicUniform>::const_iterator elemUnif = BasicUniform::findWithName(basicUniforms, curName.c_str());
   1391 				if (elemUnif == basicUniforms.end())
   1392 					continue;
   1393 				unifValue = elemUnif->finalValue;
   1394 			}
   1395 			else
   1396 				unifValue = uniform.finalValue;
   1397 
   1398 			const VarValue apiValue = glu::isDataTypeBoolOrBVec(unifValue.type)	? getRandomBoolRepresentation(unifValue, boolApiType, rnd)
   1399 									: glu::isDataTypeSampler(unifValue.type)	? getSamplerUnitValue(unifValue)
   1400 									: unifValue;
   1401 
   1402 			valuesToAssign.push_back(glu::isDataTypeMatrix(apiValue.type) && transpose ? getTransposeMatrix(apiValue) : apiValue);
   1403 
   1404 			if (glu::isDataTypeBoolOrBVec(uniform.type))
   1405 				log << TestLog::Message << "// Using type " << glu::getDataTypeName(boolApiType) << " to set boolean value " << apiVarValueStr(unifValue) << " for " << curName << TestLog::EndMessage;
   1406 			else if (glu::isDataTypeSampler(uniform.type))
   1407 				log << TestLog::Message << "// Texture for the sampler uniform " << curName << " will be filled with color " << apiVarValueStr(getSamplerFillValue(uniform.finalValue)) << TestLog::EndMessage;
   1408 		}
   1409 
   1410 		DE_ASSERT(!valuesToAssign.empty());
   1411 
   1412 		if (glu::isDataTypeFloatOrVec(valuesToAssign[0].type))
   1413 		{
   1414 			if (assignByValue)
   1415 			{
   1416 				const float* const ptr = &valuesToAssign[0].val.floatV[0];
   1417 
   1418 				switch (typeSize)
   1419 				{
   1420 					case 1: GLU_CHECK_CALL(glProgramUniform1f(programGL, location, ptr[0]));							break;
   1421 					case 2: GLU_CHECK_CALL(glProgramUniform2f(programGL, location, ptr[0], ptr[1]));					break;
   1422 					case 3: GLU_CHECK_CALL(glProgramUniform3f(programGL, location, ptr[0], ptr[1], ptr[2]));			break;
   1423 					case 4: GLU_CHECK_CALL(glProgramUniform4f(programGL, location, ptr[0], ptr[1], ptr[2], ptr[3]));	break;
   1424 					default:
   1425 						DE_ASSERT(false);
   1426 				}
   1427 			}
   1428 			else
   1429 			{
   1430 				vector<float> buffer(valuesToAssign.size() * typeSize);
   1431 				for (int i = 0; i < (int)buffer.size(); i++)
   1432 					buffer[i] = valuesToAssign[i / typeSize].val.floatV[i % typeSize];
   1433 
   1434 				DE_STATIC_ASSERT(sizeof(GLfloat) == sizeof(buffer[0]));
   1435 				switch (typeSize)
   1436 				{
   1437 					case 1: GLU_CHECK_CALL(glProgramUniform1fv(programGL, location, (GLsizei)valuesToAssign.size(), &buffer[0])); break;
   1438 					case 2: GLU_CHECK_CALL(glProgramUniform2fv(programGL, location, (GLsizei)valuesToAssign.size(), &buffer[0])); break;
   1439 					case 3: GLU_CHECK_CALL(glProgramUniform3fv(programGL, location, (GLsizei)valuesToAssign.size(), &buffer[0])); break;
   1440 					case 4: GLU_CHECK_CALL(glProgramUniform4fv(programGL, location, (GLsizei)valuesToAssign.size(), &buffer[0])); break;
   1441 					default:
   1442 						DE_ASSERT(false);
   1443 				}
   1444 			}
   1445 		}
   1446 		else if (glu::isDataTypeMatrix(valuesToAssign[0].type))
   1447 		{
   1448 			DE_ASSERT(!assignByValue);
   1449 
   1450 			vector<float> buffer(valuesToAssign.size() * typeSize);
   1451 			for (int i = 0; i < (int)buffer.size(); i++)
   1452 				buffer[i] = valuesToAssign[i / typeSize].val.floatV[i % typeSize];
   1453 
   1454 			DE_STATIC_ASSERT(sizeof(GLfloat) == sizeof(buffer[0]));
   1455 			switch (uniform.type)
   1456 			{
   1457 				case glu::TYPE_FLOAT_MAT2:		GLU_CHECK_CALL(glProgramUniformMatrix2fv	(programGL, location, (GLsizei)valuesToAssign.size(), transposeGL, &buffer[0])); break;
   1458 				case glu::TYPE_FLOAT_MAT3:		GLU_CHECK_CALL(glProgramUniformMatrix3fv	(programGL, location, (GLsizei)valuesToAssign.size(), transposeGL, &buffer[0])); break;
   1459 				case glu::TYPE_FLOAT_MAT4:		GLU_CHECK_CALL(glProgramUniformMatrix4fv	(programGL, location, (GLsizei)valuesToAssign.size(), transposeGL, &buffer[0])); break;
   1460 				case glu::TYPE_FLOAT_MAT2X3:	GLU_CHECK_CALL(glProgramUniformMatrix2x3fv	(programGL, location, (GLsizei)valuesToAssign.size(), transposeGL, &buffer[0])); break;
   1461 				case glu::TYPE_FLOAT_MAT2X4:	GLU_CHECK_CALL(glProgramUniformMatrix2x4fv	(programGL, location, (GLsizei)valuesToAssign.size(), transposeGL, &buffer[0])); break;
   1462 				case glu::TYPE_FLOAT_MAT3X2:	GLU_CHECK_CALL(glProgramUniformMatrix3x2fv	(programGL, location, (GLsizei)valuesToAssign.size(), transposeGL, &buffer[0])); break;
   1463 				case glu::TYPE_FLOAT_MAT3X4:	GLU_CHECK_CALL(glProgramUniformMatrix3x4fv	(programGL, location, (GLsizei)valuesToAssign.size(), transposeGL, &buffer[0])); break;
   1464 				case glu::TYPE_FLOAT_MAT4X2:	GLU_CHECK_CALL(glProgramUniformMatrix4x2fv	(programGL, location, (GLsizei)valuesToAssign.size(), transposeGL, &buffer[0])); break;
   1465 				case glu::TYPE_FLOAT_MAT4X3:	GLU_CHECK_CALL(glProgramUniformMatrix4x3fv	(programGL, location, (GLsizei)valuesToAssign.size(), transposeGL, &buffer[0])); break;
   1466 				default:
   1467 					DE_ASSERT(false);
   1468 			}
   1469 		}
   1470 		else if (glu::isDataTypeIntOrIVec(valuesToAssign[0].type))
   1471 		{
   1472 			if (assignByValue)
   1473 			{
   1474 				const deInt32* const ptr = &valuesToAssign[0].val.intV[0];
   1475 
   1476 				switch (typeSize)
   1477 				{
   1478 					case 1: GLU_CHECK_CALL(glProgramUniform1i(programGL, location, ptr[0]));							break;
   1479 					case 2: GLU_CHECK_CALL(glProgramUniform2i(programGL, location, ptr[0], ptr[1]));					break;
   1480 					case 3: GLU_CHECK_CALL(glProgramUniform3i(programGL, location, ptr[0], ptr[1], ptr[2]));			break;
   1481 					case 4: GLU_CHECK_CALL(glProgramUniform4i(programGL, location, ptr[0], ptr[1], ptr[2], ptr[3]));	break;
   1482 					default:
   1483 						DE_ASSERT(false);
   1484 				}
   1485 			}
   1486 			else
   1487 			{
   1488 				vector<deInt32> buffer(valuesToAssign.size() * typeSize);
   1489 				for (int i = 0; i < (int)buffer.size(); i++)
   1490 					buffer[i] = valuesToAssign[i / typeSize].val.intV[i % typeSize];
   1491 
   1492 				DE_STATIC_ASSERT(sizeof(GLint) == sizeof(buffer[0]));
   1493 				switch (typeSize)
   1494 				{
   1495 					case 1: GLU_CHECK_CALL(glProgramUniform1iv(programGL, location, (GLsizei)valuesToAssign.size(), &buffer[0])); break;
   1496 					case 2: GLU_CHECK_CALL(glProgramUniform2iv(programGL, location, (GLsizei)valuesToAssign.size(), &buffer[0])); break;
   1497 					case 3: GLU_CHECK_CALL(glProgramUniform3iv(programGL, location, (GLsizei)valuesToAssign.size(), &buffer[0])); break;
   1498 					case 4: GLU_CHECK_CALL(glProgramUniform4iv(programGL, location, (GLsizei)valuesToAssign.size(), &buffer[0])); break;
   1499 					default:
   1500 						DE_ASSERT(false);
   1501 				}
   1502 			}
   1503 		}
   1504 		else if (glu::isDataTypeUintOrUVec(valuesToAssign[0].type))
   1505 		{
   1506 			if (assignByValue)
   1507 			{
   1508 				const deUint32* const ptr = &valuesToAssign[0].val.uintV[0];
   1509 
   1510 				switch (typeSize)
   1511 				{
   1512 					case 1: GLU_CHECK_CALL(glProgramUniform1ui(programGL, location, ptr[0]));							break;
   1513 					case 2: GLU_CHECK_CALL(glProgramUniform2ui(programGL, location, ptr[0], ptr[1]));					break;
   1514 					case 3: GLU_CHECK_CALL(glProgramUniform3ui(programGL, location, ptr[0], ptr[1], ptr[2]));			break;
   1515 					case 4: GLU_CHECK_CALL(glProgramUniform4ui(programGL, location, ptr[0], ptr[1], ptr[2], ptr[3]));	break;
   1516 					default:
   1517 						DE_ASSERT(false);
   1518 				}
   1519 			}
   1520 			else
   1521 			{
   1522 				vector<deUint32> buffer(valuesToAssign.size() * typeSize);
   1523 				for (int i = 0; i < (int)buffer.size(); i++)
   1524 					buffer[i] = valuesToAssign[i / typeSize].val.intV[i % typeSize];
   1525 
   1526 				DE_STATIC_ASSERT(sizeof(GLuint) == sizeof(buffer[0]));
   1527 				switch (typeSize)
   1528 				{
   1529 					case 1: GLU_CHECK_CALL(glProgramUniform1uiv(programGL, location, (GLsizei)valuesToAssign.size(), &buffer[0])); break;
   1530 					case 2: GLU_CHECK_CALL(glProgramUniform2uiv(programGL, location, (GLsizei)valuesToAssign.size(), &buffer[0])); break;
   1531 					case 3: GLU_CHECK_CALL(glProgramUniform3uiv(programGL, location, (GLsizei)valuesToAssign.size(), &buffer[0])); break;
   1532 					case 4: GLU_CHECK_CALL(glProgramUniform4uiv(programGL, location, (GLsizei)valuesToAssign.size(), &buffer[0])); break;
   1533 					default:
   1534 						DE_ASSERT(false);
   1535 				}
   1536 			}
   1537 		}
   1538 		else if (glu::isDataTypeSampler(valuesToAssign[0].type))
   1539 		{
   1540 			if (assignByValue)
   1541 				GLU_CHECK_CALL(glProgramUniform1i(programGL, location, uniform.finalValue.val.samplerV.unit));
   1542 			else
   1543 			{
   1544 				const GLint unit = uniform.finalValue.val.samplerV.unit;
   1545 				GLU_CHECK_CALL(glProgramUniform1iv(programGL, location, (GLsizei)valuesToAssign.size(), &unit));
   1546 			}
   1547 		}
   1548 		else
   1549 			DE_ASSERT(false);
   1550 	}
   1551 }
   1552 
   1553 bool UniformCase::compareUniformValues (const vector<VarValue>& values, const vector<BasicUniform>& basicUniforms)
   1554 {
   1555 	TestLog&	log			= m_testCtx.getLog();
   1556 	bool		success		= true;
   1557 
   1558 	for (int unifNdx = 0; unifNdx < (int)basicUniforms.size(); unifNdx++)
   1559 	{
   1560 		const BasicUniform&		uniform		= basicUniforms[unifNdx];
   1561 		const VarValue&			unifValue	= values[unifNdx];
   1562 
   1563 		log << TestLog::Message << "// Checking uniform " << uniform.name << TestLog::EndMessage;
   1564 
   1565 		if (unifValue.type == glu::TYPE_INVALID) // This happens when glGetUniformLocation() returned -1.
   1566 			continue;
   1567 
   1568 		if (!apiVarValueEquals(unifValue, uniform.finalValue))
   1569 		{
   1570 			log << TestLog::Message << "// FAILURE: value obtained with glGetUniform*() for uniform " << uniform.name << " differs from value set with glProgramUniform*()" << TestLog::EndMessage;
   1571 			success = false;
   1572 		}
   1573 	}
   1574 
   1575 	return success;
   1576 }
   1577 
   1578 bool UniformCase::renderTest (const vector<BasicUniform>& basicUniforms, const ShaderProgram& program, Random& rnd)
   1579 {
   1580 	TestLog&					log				= m_testCtx.getLog();
   1581 	const tcu::RenderTarget&	renderTarget	= m_context.getRenderTarget();
   1582 	const int					viewportW		= de::min<int>(renderTarget.getWidth(),		MAX_RENDER_WIDTH);
   1583 	const int					viewportH		= de::min<int>(renderTarget.getHeight(),	MAX_RENDER_HEIGHT);
   1584 	const int					viewportX		= rnd.getInt(0, renderTarget.getWidth()		- viewportW);
   1585 	const int					viewportY		= rnd.getInt(0, renderTarget.getHeight()	- viewportH);
   1586 	tcu::Surface				renderedImg		(viewportW, viewportH);
   1587 
   1588 	// Assert that no two samplers of different types have the same texture unit - this is an error in GL.
   1589 	for (int i = 0; i < (int)basicUniforms.size(); i++)
   1590 	{
   1591 		if (glu::isDataTypeSampler(basicUniforms[i].type))
   1592 		{
   1593 			for (int j = 0; j < i; j++)
   1594 			{
   1595 				if (glu::isDataTypeSampler(basicUniforms[j].type) && basicUniforms[i].type != basicUniforms[j].type)
   1596 					DE_ASSERT(basicUniforms[i].finalValue.val.samplerV.unit != basicUniforms[j].finalValue.val.samplerV.unit);
   1597 			}
   1598 		}
   1599 	}
   1600 
   1601 	for (int i = 0; i < (int)basicUniforms.size(); i++)
   1602 	{
   1603 		if (glu::isDataTypeSampler(basicUniforms[i].type) && std::find(m_filledTextureUnits.begin(), m_filledTextureUnits.end(), basicUniforms[i].finalValue.val.samplerV.unit) == m_filledTextureUnits.end())
   1604 		{
   1605 			log << TestLog::Message << "// Filling texture at unit " << apiVarValueStr(basicUniforms[i].finalValue) << " with color " << shaderVarValueStr(basicUniforms[i].finalValue) << TestLog::EndMessage;
   1606 			setupTexture(basicUniforms[i].finalValue);
   1607 		}
   1608 	}
   1609 
   1610 	GLU_CHECK_CALL(glViewport(viewportX, viewportY, viewportW, viewportH));
   1611 	GLU_CHECK_CALL(glClearColor(0.0f, 0.0f, 0.0f, 1.0f));
   1612 	GLU_CHECK_CALL(glClear(GL_COLOR_BUFFER_BIT));
   1613 	GLU_CHECK_CALL(glUseProgram(program.getProgram()));
   1614 
   1615 	{
   1616 		static const float position[] =
   1617 		{
   1618 			-1.0f, -1.0f, 0.0f, 1.0f,
   1619 			-1.0f, +1.0f, 0.0f, 1.0f,
   1620 			+1.0f, -1.0f, 0.0f, 1.0f,
   1621 			+1.0f, +1.0f, 0.0f, 1.0f
   1622 		};
   1623 		static const deUint16			indices[]	= { 0, 1, 2, 2, 1, 3 };
   1624 		const glu::VertexArrayBinding	binding		= glu::va::Float("a_position", 4, 4, 0, &position[0]);
   1625 
   1626 		glu::draw(m_context.getRenderContext(), program.getProgram(), 1, &binding, glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indices), &indices[0]));
   1627 		glu::readPixels(m_context.getRenderContext(), viewportX, viewportY, renderedImg.getAccess());
   1628 	}
   1629 
   1630 	int numFailedPixels = 0;
   1631 	for (int y = 0; y < renderedImg.getHeight(); y++)
   1632 	{
   1633 		for (int x = 0; x < renderedImg.getWidth(); x++)
   1634 		{
   1635 			if (renderedImg.getPixel(x, y) != tcu::RGBA::green)
   1636 				numFailedPixels += 1;
   1637 		}
   1638 	}
   1639 
   1640 	if (numFailedPixels > 0)
   1641 	{
   1642 		log << TestLog::Image("RenderedImage", "Rendered image", renderedImg);
   1643 		log << TestLog::Message << "FAILURE: image comparison failed, got " << numFailedPixels << " non-green pixels" << TestLog::EndMessage;
   1644 		return false;
   1645 	}
   1646 	else
   1647 	{
   1648 		log << TestLog::Message << "Success: got all-green pixels (all uniforms have correct values)" << TestLog::EndMessage;
   1649 		return true;
   1650 	}
   1651 }
   1652 
   1653 UniformCase::IterateResult UniformCase::iterate (void)
   1654 {
   1655 	Random							rnd				(deStringHash(getName()) ^ (deUint32)m_context.getTestContext().getCommandLine().getBaseSeed());
   1656 	TestLog&						log				= m_testCtx.getLog();
   1657 	vector<BasicUniform>			basicUniforms;
   1658 	vector<BasicUniformReportRef>	basicUniformReportsRef;
   1659 
   1660 	{
   1661 		int samplerUnitCounter = 0;
   1662 		for (int i = 0; i < (int)m_uniformCollection->getNumUniforms(); i++)
   1663 			generateBasicUniforms(basicUniforms, basicUniformReportsRef, m_uniformCollection->getUniform(i).type, m_uniformCollection->getUniform(i).name.c_str(), true, samplerUnitCounter, rnd);
   1664 	}
   1665 
   1666 	const string					vertexSource	= generateVertexSource(basicUniforms);
   1667 	const string					fragmentSource	= generateFragmentSource(basicUniforms);
   1668 	const ShaderProgram				program			(m_context.getRenderContext(), glu::makeVtxFragSources(vertexSource, fragmentSource));
   1669 
   1670 	// A dummy program that we'll give to glUseProgram before we actually need
   1671 	// the real program above, to see if an implementation tries to use the
   1672 	// currently active program for something inappropriate (instead of the
   1673 	// program given as argument to, say, glProgramUniform*).
   1674 	const ShaderProgram				dummyProgram	(m_context.getRenderContext(), glu::makeVtxFragSources("#version 310 es\n"
   1675 																										   "void main (void) { gl_Position = vec4(1.0); }\n",
   1676 
   1677 																										   "#version 310 es\n"
   1678 																										   "layout(location = 0) out mediump vec4 dEQP_FragColor;\n"
   1679 																										   "void main (void) { dEQP_FragColor = vec4(0.0, 0.0, 1.0, 1.0); }\n"));
   1680 
   1681 	log << program;
   1682 
   1683 	if (!program.isOk())
   1684 	{
   1685 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Compile failed");
   1686 		return STOP;
   1687 	}
   1688 
   1689 	if (!dummyProgram.isOk())
   1690 	{
   1691 		log << dummyProgram;
   1692 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Compilation of dummy program failed");
   1693 		return STOP;
   1694 	}
   1695 
   1696 	log << TestLog::Message << "// Note: calling glUseProgram with a dummy program (will only use the real program once it's needed for rendering)" << TestLog::EndMessage;
   1697 	glUseProgram(dummyProgram.getProgram());
   1698 
   1699 	const bool success = test(basicUniforms, basicUniformReportsRef, program, rnd);
   1700 	m_testCtx.setTestResult(success ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
   1701 							success ? "Passed"				: "Failed");
   1702 
   1703 	return STOP;
   1704 }
   1705 
   1706 class UniformAssignCase : public UniformCase
   1707 {
   1708 public:
   1709 	enum CheckMethod
   1710 	{
   1711 		CHECKMETHOD_GET_UNIFORM = 0,	//!< Check values with glGetUniform*().
   1712 		CHECKMETHOD_RENDER,				//!< Check values by rendering with the value-checking shader.
   1713 
   1714 		CHECKMETHOD_LAST
   1715 	};
   1716 	enum AssignMethod
   1717 	{
   1718 		ASSIGNMETHOD_POINTER = 0,
   1719 		ASSIGNMETHOD_VALUE,
   1720 
   1721 		ASSIGNMETHOD_LAST
   1722 	};
   1723 
   1724 						UniformAssignCase			(Context&									context,
   1725 													 const char*								name,
   1726 													 const char*								description,
   1727 													 CaseShaderType								shaderType,
   1728 													 const SharedPtr<const UniformCollection>&	uniformCollection,
   1729 													 CheckMethod								checkMethod,
   1730 													 AssignMethod								assignMethod,
   1731 													 deUint32									additionalFeatures = 0);
   1732 
   1733 	bool				test						(const vector<BasicUniform>& basicUniforms, const vector<BasicUniformReportRef>& basicUniformReportsRef, const ShaderProgram& program, Random& rnd);
   1734 
   1735 	static const char*	getCheckMethodName			(CheckMethod checkMethod);
   1736 	static const char*	getCheckMethodDescription	(CheckMethod checkMethod);
   1737 	static const char*	getAssignMethodName			(AssignMethod checkMethod);
   1738 	static const char*	getAssignMethodDescription	(AssignMethod checkMethod);
   1739 
   1740 private:
   1741 	const CheckMethod m_checkMethod;
   1742 };
   1743 
   1744 const char* UniformAssignCase::getCheckMethodName (const CheckMethod checkMethod)
   1745 {
   1746 	switch (checkMethod)
   1747 	{
   1748 		case CHECKMETHOD_GET_UNIFORM:	return "get_uniform";
   1749 		case CHECKMETHOD_RENDER:		return "render";
   1750 		default: DE_ASSERT(false);		return DE_NULL;
   1751 	}
   1752 }
   1753 
   1754 const char* UniformAssignCase::getCheckMethodDescription (const CheckMethod checkMethod)
   1755 {
   1756 	switch (checkMethod)
   1757 	{
   1758 		case CHECKMETHOD_GET_UNIFORM:	return "Verify values with glGetUniform*()";
   1759 		case CHECKMETHOD_RENDER:		return "Verify values by rendering";
   1760 		default: DE_ASSERT(false);		return DE_NULL;
   1761 	}
   1762 }
   1763 
   1764 const char* UniformAssignCase::getAssignMethodName (const AssignMethod assignMethod)
   1765 {
   1766 	switch (assignMethod)
   1767 	{
   1768 		case ASSIGNMETHOD_POINTER:		return "by_pointer";
   1769 		case ASSIGNMETHOD_VALUE:		return "by_value";
   1770 		default: DE_ASSERT(false);		return DE_NULL;
   1771 	}
   1772 }
   1773 
   1774 const char* UniformAssignCase::getAssignMethodDescription (const AssignMethod assignMethod)
   1775 {
   1776 	switch (assignMethod)
   1777 	{
   1778 		case ASSIGNMETHOD_POINTER:		return "Assign values by-pointer";
   1779 		case ASSIGNMETHOD_VALUE:		return "Assign values by-value";
   1780 		default: DE_ASSERT(false);		return DE_NULL;
   1781 	}
   1782 }
   1783 
   1784 UniformAssignCase::UniformAssignCase (Context&									context,
   1785 									  const char* const							name,
   1786 									  const char* const							description,
   1787 									  const CaseShaderType						shaderType,
   1788 									  const SharedPtr<const UniformCollection>&	uniformCollection,
   1789 									  const CheckMethod							checkMethod,
   1790 									  const AssignMethod						assignMethod,
   1791 									  const deUint32							additionalFeatures)
   1792 	: UniformCase		(context, name, description, shaderType, uniformCollection,
   1793 						 (assignMethod == ASSIGNMETHOD_VALUE ? FEATURE_UNIFORMFUNC_VALUE : 0) | additionalFeatures)
   1794 	, m_checkMethod		(checkMethod)
   1795 {
   1796 	DE_ASSERT(assignMethod != ASSIGNMETHOD_LAST);
   1797 }
   1798 
   1799 bool UniformAssignCase::test (const vector<BasicUniform>& basicUniforms, const vector<BasicUniformReportRef>& basicUniformReportsRef, const ShaderProgram& program, Random& rnd)
   1800 {
   1801 	DE_UNREF(basicUniformReportsRef);
   1802 
   1803 	const deUint32	programGL	= program.getProgram();
   1804 	TestLog&		log			= m_testCtx.getLog();
   1805 
   1806 	{
   1807 		const ScopedLogSection section(log, "UniformAssign", "Uniform value assignments");
   1808 		assignUniforms(basicUniforms, programGL, rnd);
   1809 	}
   1810 
   1811 	if (m_checkMethod == CHECKMETHOD_GET_UNIFORM)
   1812 	{
   1813 		vector<VarValue> values;
   1814 
   1815 		{
   1816 			const ScopedLogSection section(log, "GetUniforms", "Uniform value query");
   1817 			const bool success = getUniforms(values, basicUniforms, program.getProgram());
   1818 
   1819 			if (!success)
   1820 				return false;
   1821 		}
   1822 
   1823 		{
   1824 			const ScopedLogSection section(log, "ValueCheck", "Verify that the reported values match the assigned values");
   1825 			const bool success = compareUniformValues(values, basicUniforms);
   1826 
   1827 			if (!success)
   1828 				return false;
   1829 		}
   1830 	}
   1831 	else
   1832 	{
   1833 		DE_ASSERT(m_checkMethod == CHECKMETHOD_RENDER);
   1834 
   1835 		const ScopedLogSection section(log, "RenderTest", "Render test");
   1836 		const bool success = renderTest(basicUniforms, program, rnd);
   1837 
   1838 		if (!success)
   1839 			return false;
   1840 	}
   1841 
   1842 	return true;
   1843 }
   1844 
   1845 ProgramUniformTests::ProgramUniformTests (Context& context)
   1846 	: TestCaseGroup(context, "program_uniform", "glProgramUniform*() tests")
   1847 {
   1848 }
   1849 
   1850 ProgramUniformTests::~ProgramUniformTests (void)
   1851 {
   1852 }
   1853 
   1854 namespace
   1855 {
   1856 
   1857 // \note Although this is only used in ProgramUniformTests::init, it needs to be defined here as it's used as a template argument.
   1858 struct UniformCollectionCase
   1859 {
   1860 	string								namePrefix;
   1861 	SharedPtr<const UniformCollection>	uniformCollection;
   1862 
   1863 	UniformCollectionCase (const char* const name, const UniformCollection* uniformCollection_)
   1864 		: namePrefix			(name ? name + string("_") : "")
   1865 		, uniformCollection		(uniformCollection_)
   1866 	{
   1867 	}
   1868 };
   1869 
   1870 } // anonymous
   1871 
   1872 void ProgramUniformTests::init (void)
   1873 {
   1874 	// Generate sets of UniformCollections that are used by several cases.
   1875 
   1876 	enum
   1877 	{
   1878 		UNIFORMCOLLECTIONS_BASIC = 0,
   1879 		UNIFORMCOLLECTIONS_BASIC_ARRAY,
   1880 		UNIFORMCOLLECTIONS_BASIC_STRUCT,
   1881 		UNIFORMCOLLECTIONS_STRUCT_IN_ARRAY,
   1882 		UNIFORMCOLLECTIONS_ARRAY_IN_STRUCT,
   1883 		UNIFORMCOLLECTIONS_NESTED_STRUCTS_ARRAYS,
   1884 		UNIFORMCOLLECTIONS_MULTIPLE_BASIC,
   1885 		UNIFORMCOLLECTIONS_MULTIPLE_BASIC_ARRAY,
   1886 		UNIFORMCOLLECTIONS_MULTIPLE_NESTED_STRUCTS_ARRAYS,
   1887 
   1888 		UNIFORMCOLLECTIONS_LAST
   1889 	};
   1890 
   1891 	struct UniformCollectionGroup
   1892 	{
   1893 		string							name;
   1894 		vector<UniformCollectionCase>	cases;
   1895 	} defaultUniformCollections[UNIFORMCOLLECTIONS_LAST];
   1896 
   1897 	defaultUniformCollections[UNIFORMCOLLECTIONS_BASIC].name							= "basic";
   1898 	defaultUniformCollections[UNIFORMCOLLECTIONS_BASIC_ARRAY].name						= "basic_array";
   1899 	defaultUniformCollections[UNIFORMCOLLECTIONS_BASIC_STRUCT].name						= "basic_struct";
   1900 	defaultUniformCollections[UNIFORMCOLLECTIONS_STRUCT_IN_ARRAY].name					= "struct_in_array";
   1901 	defaultUniformCollections[UNIFORMCOLLECTIONS_ARRAY_IN_STRUCT].name					= "array_in_struct";
   1902 	defaultUniformCollections[UNIFORMCOLLECTIONS_NESTED_STRUCTS_ARRAYS].name			= "nested_structs_arrays";
   1903 	defaultUniformCollections[UNIFORMCOLLECTIONS_MULTIPLE_BASIC].name					= "multiple_basic";
   1904 	defaultUniformCollections[UNIFORMCOLLECTIONS_MULTIPLE_BASIC_ARRAY].name				= "multiple_basic_array";
   1905 	defaultUniformCollections[UNIFORMCOLLECTIONS_MULTIPLE_NESTED_STRUCTS_ARRAYS].name	= "multiple_nested_structs_arrays";
   1906 
   1907 	for (int dataTypeNdx = 0; dataTypeNdx < DE_LENGTH_OF_ARRAY(s_testDataTypes); dataTypeNdx++)
   1908 	{
   1909 		const glu::DataType		dataType	= s_testDataTypes[dataTypeNdx];
   1910 		const char* const		typeName	= glu::getDataTypeName(dataType);
   1911 
   1912 		defaultUniformCollections[UNIFORMCOLLECTIONS_BASIC].cases.push_back(UniformCollectionCase(typeName, UniformCollection::basic(dataType)));
   1913 
   1914 		if (glu::isDataTypeScalar(dataType)													||
   1915 			(glu::isDataTypeVector(dataType) && glu::getDataTypeScalarSize(dataType) == 4)	||
   1916 			dataType == glu::TYPE_FLOAT_MAT4												||
   1917 			dataType == glu::TYPE_SAMPLER_2D)
   1918 			defaultUniformCollections[UNIFORMCOLLECTIONS_BASIC_ARRAY].cases.push_back(UniformCollectionCase(typeName, UniformCollection::basicArray(dataType)));
   1919 
   1920 		if (glu::isDataTypeScalar(dataType)		||
   1921 			dataType == glu::TYPE_FLOAT_MAT4	||
   1922 			dataType == glu::TYPE_SAMPLER_2D)
   1923 		{
   1924 			const glu::DataType		secondDataType	= glu::isDataTypeScalar(dataType)	? glu::getDataTypeVector(dataType, 4)
   1925 													: dataType == glu::TYPE_FLOAT_MAT4	? glu::TYPE_FLOAT_MAT2
   1926 													: dataType == glu::TYPE_SAMPLER_2D	? glu::TYPE_SAMPLER_CUBE
   1927 													: glu::TYPE_LAST;
   1928 			DE_ASSERT(secondDataType != glu::TYPE_LAST);
   1929 			const char* const		secondTypeName	= glu::getDataTypeName(secondDataType);
   1930 			const string			name			= string("") + typeName + "_" + secondTypeName;
   1931 
   1932 			defaultUniformCollections[UNIFORMCOLLECTIONS_BASIC_STRUCT].cases.push_back			(UniformCollectionCase(name.c_str(), UniformCollection::basicStruct(dataType, secondDataType, false)));
   1933 			defaultUniformCollections[UNIFORMCOLLECTIONS_ARRAY_IN_STRUCT].cases.push_back		(UniformCollectionCase(name.c_str(), UniformCollection::basicStruct(dataType, secondDataType, true)));
   1934 			defaultUniformCollections[UNIFORMCOLLECTIONS_STRUCT_IN_ARRAY].cases.push_back		(UniformCollectionCase(name.c_str(), UniformCollection::structInArray(dataType, secondDataType, false)));
   1935 			defaultUniformCollections[UNIFORMCOLLECTIONS_NESTED_STRUCTS_ARRAYS].cases.push_back	(UniformCollectionCase(name.c_str(), UniformCollection::nestedArraysStructs(dataType, secondDataType)));
   1936 		}
   1937 	}
   1938 	defaultUniformCollections[UNIFORMCOLLECTIONS_MULTIPLE_BASIC].cases.push_back					(UniformCollectionCase(DE_NULL, UniformCollection::multipleBasic()));
   1939 	defaultUniformCollections[UNIFORMCOLLECTIONS_MULTIPLE_BASIC_ARRAY].cases.push_back				(UniformCollectionCase(DE_NULL, UniformCollection::multipleBasicArray()));
   1940 	defaultUniformCollections[UNIFORMCOLLECTIONS_MULTIPLE_NESTED_STRUCTS_ARRAYS].cases.push_back	(UniformCollectionCase(DE_NULL, UniformCollection::multipleNestedArraysStructs()));
   1941 
   1942 	// Basic by-pointer or by-value uniform assignment cases.
   1943 
   1944 	for (int assignMethodI = 0; assignMethodI < (int)UniformAssignCase::ASSIGNMETHOD_LAST; assignMethodI++)
   1945 	{
   1946 		const UniformAssignCase::AssignMethod	assignMethod		= (UniformAssignCase::AssignMethod)assignMethodI;
   1947 		TestCaseGroup* const					assignMethodGroup	= new TestCaseGroup(m_context, UniformAssignCase::getAssignMethodName(assignMethod), UniformAssignCase::getAssignMethodDescription(assignMethod));
   1948 		addChild(assignMethodGroup);
   1949 
   1950 		for (int checkMethodI = 0; checkMethodI < (int)UniformAssignCase::CHECKMETHOD_LAST; checkMethodI++)
   1951 		{
   1952 			const UniformAssignCase::CheckMethod	checkMethod			= (UniformAssignCase::CheckMethod)checkMethodI;
   1953 			TestCaseGroup* const					checkMethodGroup	= new TestCaseGroup(m_context, UniformAssignCase::getCheckMethodName(checkMethod), UniformAssignCase::getCheckMethodDescription(checkMethod));
   1954 			assignMethodGroup->addChild(checkMethodGroup);
   1955 
   1956 			for (int collectionGroupNdx = 0; collectionGroupNdx < (int)UNIFORMCOLLECTIONS_LAST; collectionGroupNdx++)
   1957 			{
   1958 				const int numArrayFirstElemNameCases = checkMethod == UniformAssignCase::CHECKMETHOD_GET_UNIFORM && collectionGroupNdx == UNIFORMCOLLECTIONS_BASIC_ARRAY ? 2 : 1;
   1959 
   1960 				for (int referToFirstArrayElemWithoutIndexI = 0; referToFirstArrayElemWithoutIndexI < numArrayFirstElemNameCases; referToFirstArrayElemWithoutIndexI++)
   1961 				{
   1962 					const UniformCollectionGroup&	collectionGroup			= defaultUniformCollections[collectionGroupNdx];
   1963 					const string					collectionGroupName		= collectionGroup.name + (referToFirstArrayElemWithoutIndexI == 0 ? "" : "_first_elem_without_brackets");
   1964 					TestCaseGroup* const			collectionTestGroup		= new TestCaseGroup(m_context, collectionGroupName.c_str(), "");
   1965 					checkMethodGroup->addChild(collectionTestGroup);
   1966 
   1967 					for (int collectionNdx = 0; collectionNdx < (int)collectionGroup.cases.size(); collectionNdx++)
   1968 					{
   1969 						const UniformCollectionCase&				collectionCase		= collectionGroup.cases[collectionNdx];
   1970 						const string								collName			= collectionCase.namePrefix;
   1971 						const SharedPtr<const UniformCollection>&	uniformCollection	= collectionCase.uniformCollection;
   1972 						const bool									containsBooleans	= uniformCollection->containsMatchingBasicType(glu::isDataTypeBoolOrBVec);
   1973 						const bool									varyBoolApiType		= checkMethod == UniformAssignCase::CHECKMETHOD_GET_UNIFORM && containsBooleans &&
   1974 																							(collectionGroupNdx == UNIFORMCOLLECTIONS_BASIC || collectionGroupNdx == UNIFORMCOLLECTIONS_BASIC_ARRAY);
   1975 						const int									numBoolVariations	= varyBoolApiType ? 3 : 1;
   1976 						const bool									containsMatrices	= uniformCollection->containsMatchingBasicType(glu::isDataTypeMatrix);
   1977 						const bool									varyMatrixMode		= containsMatrices &&
   1978 																							(collectionGroupNdx == UNIFORMCOLLECTIONS_BASIC || collectionGroupNdx == UNIFORMCOLLECTIONS_BASIC_ARRAY);
   1979 						const int									numMatVariations	= varyMatrixMode ? 2 : 1;
   1980 
   1981 						if (containsMatrices && assignMethod != UniformAssignCase::ASSIGNMETHOD_POINTER)
   1982 							continue;
   1983 
   1984 						for (int booleanTypeI = 0; booleanTypeI < numBoolVariations; booleanTypeI++)
   1985 						{
   1986 							const deUint32		booleanTypeFeat		= booleanTypeI == 1 ? UniformCase::FEATURE_BOOLEANAPITYPE_INT
   1987 																	: booleanTypeI == 2 ? UniformCase::FEATURE_BOOLEANAPITYPE_UINT
   1988 																	: 0;
   1989 							const char* const	booleanTypeName		= booleanTypeI == 1 ? "int"
   1990 																	: booleanTypeI == 2 ? "uint"
   1991 																	: "float";
   1992 							const string		nameWithBoolType	= varyBoolApiType ? collName + "api_" + booleanTypeName + "_" : collName;
   1993 
   1994 							for (int matrixTypeI = 0; matrixTypeI < numMatVariations; matrixTypeI++)
   1995 							{
   1996 								const string nameWithMatrixType = nameWithBoolType + (matrixTypeI == 1 ? "row_major_" : "");
   1997 
   1998 								for (int shaderType = 0; shaderType < (int)CASESHADERTYPE_LAST; shaderType++)
   1999 								{
   2000 									const string	name							= nameWithMatrixType + getCaseShaderTypeName((CaseShaderType)shaderType);
   2001 									const deUint32	arrayFirstElemNameNoIndexFeat	= referToFirstArrayElemWithoutIndexI == 0 ? 0 : UniformCase::FEATURE_ARRAY_FIRST_ELEM_NAME_NO_INDEX;
   2002 
   2003 									collectionTestGroup->addChild(new UniformAssignCase(m_context, name.c_str(), "", (CaseShaderType)shaderType, uniformCollection,
   2004 																						checkMethod, assignMethod,
   2005 																						booleanTypeFeat | arrayFirstElemNameNoIndexFeat | (matrixTypeI == 1 ? UniformCase::FEATURE_MATRIXMODE_ROWMAJOR : 0)));
   2006 								}
   2007 							}
   2008 						}
   2009 					}
   2010 				}
   2011 			}
   2012 		}
   2013 	}
   2014 
   2015 	// Cases that assign multiple basic-array elements with one glProgramUniform*v() (i.e. the count parameter is bigger than 1).
   2016 
   2017 	{
   2018 		static const struct
   2019 		{
   2020 			UniformCase::Feature	arrayAssignMode;
   2021 			const char*				name;
   2022 			const char*				description;
   2023 		} arrayAssignGroups[] =
   2024 		{
   2025 			{ UniformCase::FEATURE_ARRAYASSIGN_FULL,			"basic_array_assign_full",		"Assign entire basic-type arrays per glProgramUniform*v() call"				},
   2026 			{ UniformCase::FEATURE_ARRAYASSIGN_BLOCKS_OF_TWO,	"basic_array_assign_partial",	"Assign two elements of a basic-type array per glProgramUniform*v() call"	}
   2027 		};
   2028 
   2029 		for (int arrayAssignGroupNdx = 0; arrayAssignGroupNdx < DE_LENGTH_OF_ARRAY(arrayAssignGroups); arrayAssignGroupNdx++)
   2030 		{
   2031 			UniformCase::Feature	arrayAssignMode		= arrayAssignGroups[arrayAssignGroupNdx].arrayAssignMode;
   2032 			const char* const		groupName			= arrayAssignGroups[arrayAssignGroupNdx].name;
   2033 			const char* const		groupDesc			= arrayAssignGroups[arrayAssignGroupNdx].description;
   2034 
   2035 			TestCaseGroup* const curArrayAssignGroup = new TestCaseGroup(m_context, groupName, groupDesc);
   2036 			addChild(curArrayAssignGroup);
   2037 
   2038 			static const int basicArrayCollectionGroups[] = { UNIFORMCOLLECTIONS_BASIC_ARRAY, UNIFORMCOLLECTIONS_ARRAY_IN_STRUCT, UNIFORMCOLLECTIONS_MULTIPLE_BASIC_ARRAY };
   2039 
   2040 			for (int collectionGroupNdx = 0; collectionGroupNdx < DE_LENGTH_OF_ARRAY(basicArrayCollectionGroups); collectionGroupNdx++)
   2041 			{
   2042 				const UniformCollectionGroup&	collectionGroup		= defaultUniformCollections[basicArrayCollectionGroups[collectionGroupNdx]];
   2043 				TestCaseGroup* const			collectionTestGroup	= new TestCaseGroup(m_context, collectionGroup.name.c_str(), "");
   2044 				curArrayAssignGroup->addChild(collectionTestGroup);
   2045 
   2046 				for (int collectionNdx = 0; collectionNdx < (int)collectionGroup.cases.size(); collectionNdx++)
   2047 				{
   2048 					const UniformCollectionCase&				collectionCase		= collectionGroup.cases[collectionNdx];
   2049 					const string								collName			= collectionCase.namePrefix;
   2050 					const SharedPtr<const UniformCollection>&	uniformCollection	= collectionCase.uniformCollection;
   2051 
   2052 					for (int shaderType = 0; shaderType < (int)CASESHADERTYPE_LAST; shaderType++)
   2053 					{
   2054 						const string name = collName + getCaseShaderTypeName((CaseShaderType)shaderType);
   2055 						collectionTestGroup->addChild(new UniformAssignCase(m_context, name.c_str(), "", (CaseShaderType)shaderType, uniformCollection,
   2056 																			UniformAssignCase::CHECKMETHOD_GET_UNIFORM, UniformAssignCase::ASSIGNMETHOD_POINTER,
   2057 																			arrayAssignMode));
   2058 					}
   2059 				}
   2060 			}
   2061 		}
   2062 	}
   2063 
   2064 	// Cases with unused uniforms.
   2065 
   2066 	{
   2067 		TestCaseGroup* const unusedUniformsGroup = new TestCaseGroup(m_context, "unused_uniforms", "Test with unused uniforms");
   2068 		addChild(unusedUniformsGroup);
   2069 
   2070 		const UniformCollectionGroup& collectionGroup = defaultUniformCollections[UNIFORMCOLLECTIONS_ARRAY_IN_STRUCT];
   2071 
   2072 		for (int collectionNdx = 0; collectionNdx < (int)collectionGroup.cases.size(); collectionNdx++)
   2073 		{
   2074 			const UniformCollectionCase&				collectionCase		= collectionGroup.cases[collectionNdx];
   2075 			const string								collName			= collectionCase.namePrefix;
   2076 			const SharedPtr<const UniformCollection>&	uniformCollection	= collectionCase.uniformCollection;
   2077 
   2078 			for (int shaderType = 0; shaderType < (int)CASESHADERTYPE_LAST; shaderType++)
   2079 			{
   2080 				const string name = collName + getCaseShaderTypeName((CaseShaderType)shaderType);
   2081 				unusedUniformsGroup->addChild(new UniformAssignCase(m_context, name.c_str(), "", (CaseShaderType)shaderType, uniformCollection,
   2082 																	UniformAssignCase::CHECKMETHOD_GET_UNIFORM, UniformAssignCase::ASSIGNMETHOD_POINTER,
   2083 																	UniformCase::FEATURE_ARRAYUSAGE_ONLY_MIDDLE_INDEX | UniformCase::FEATURE_UNIFORMUSAGE_EVERY_OTHER));
   2084 			}
   2085 		}
   2086 	}
   2087 }
   2088 
   2089 } // Functional
   2090 } // gles31
   2091 } // deqp
   2092