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