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);
942								UniformCase		(Context& context, const char* name, const char* description, CaseShaderType caseType, const SharedPtr<const UniformCollection>& uniformCollection, deUint32 features);
943								UniformCase		(Context& context, const char* name, const char* description, deUint32 seed); // \note Randomizes caseType, uniformCollection and features.
944	virtual						~UniformCase	(void);
945
946	virtual void				init			(void);
947	virtual void				deinit			(void);
948
949	IterateResult				iterate			(void);
950
951protected:
952	// A basic uniform is a uniform (possibly struct or array member) whose type is a basic type (e.g. float, ivec4, sampler2d).
953	struct BasicUniform
954	{
955		string			name;
956		glu::DataType	type;
957		bool			isUsedInShader;
958		VarValue		finalValue;	//!< The value we ultimately want to set for this uniform.
959
960		string			rootName;	//!< If this is a member of a basic-typed array, rootName is the name of that array with "[0]" appended. Otherwise it equals name.
961		int				elemNdx;	//!< If this is a member of a basic-typed array, elemNdx is the index in that array. Otherwise -1.
962		int				rootSize;	//!< If this is a member of a basic-typed array, rootSize is the size of that array. Otherwise 1.
963
964		BasicUniform (const char* const		name_,
965					  const glu::DataType	type_,
966					  const bool			isUsedInShader_,
967					  const VarValue&		finalValue_,
968					  const char* const		rootName_	= DE_NULL,
969					  const int				elemNdx_	= -1,
970					  const int				rootSize_	= 1)
971					  : name			(name_)
972					  , type			(type_)
973					  , isUsedInShader	(isUsedInShader_)
974					  , finalValue		(finalValue_)
975					  , rootName		(rootName_ == DE_NULL ? name_ : rootName_)
976					  , elemNdx			(elemNdx_)
977					  , rootSize		(rootSize_)
978					 {
979					 }
980
981		static vector<BasicUniform>::const_iterator findWithName (const vector<BasicUniform>& vec, const char* const name)
982		{
983			for (vector<BasicUniform>::const_iterator it = vec.begin(); it != vec.end(); it++)
984			{
985				if (it->name == name)
986					return it;
987			}
988			return vec.end();
989		}
990	};
991
992	// Reference values for info that is expected to be reported by glGetActiveUniform() or glGetActiveUniformsiv().
993	struct BasicUniformReportRef
994	{
995		string			name;
996		// \note minSize and maxSize are for arrays and can be distinct since implementations are allowed, but not required, to trim the inactive end indices of arrays.
997		int				minSize;
998		int				maxSize;
999		glu::DataType	type;
1000		bool			isUsedInShader;
1001
1002		BasicUniformReportRef (const char* const name_, const int minS, const int maxS, const glu::DataType type_, const bool used)
1003			: name(name_), minSize(minS), maxSize(maxS), type(type_), isUsedInShader(used) { DE_ASSERT(minSize <= maxSize); }
1004		BasicUniformReportRef (const char* const name_, const glu::DataType type_, const bool used)
1005			: name(name_), minSize(1), maxSize(1), type(type_), isUsedInShader(used) {}
1006	};
1007
1008	// Info that is actually reported by glGetActiveUniform() or glGetActiveUniformsiv().
1009	struct BasicUniformReportGL
1010	{
1011		string			name;
1012		int				nameLength; // \note Whether this includes the null byte depends on whether it was queried with glGetActiveUniform() or glGetActiveUniformsiv().
1013		int				size;
1014		glu::DataType	type;
1015
1016		int				index;
1017
1018		BasicUniformReportGL (const char* const name_, const int nameLength_, const int size_, const glu::DataType type_, const int index_)
1019			: name(name_), nameLength(nameLength_), size(size_), type(type_), index(index_) {}
1020
1021		static vector<BasicUniformReportGL>::const_iterator findWithName (const vector<BasicUniformReportGL>& vec, const char* const name)
1022		{
1023			for (vector<BasicUniformReportGL>::const_iterator it = vec.begin(); it != vec.end(); it++)
1024			{
1025				if (it->name == name)
1026					return it;
1027			}
1028			return vec.end();
1029		}
1030	};
1031
1032	// Query info with glGetActiveUniform() and check validity.
1033	bool						getActiveUniforms						(vector<BasicUniformReportGL>& dst, const vector<BasicUniformReportRef>& ref, deUint32 programGL);
1034	// Query info with glGetUniformIndices() + glGetActiveUniformsiv() and check validity.
1035	bool						getActiveUniformsiv						(vector<BasicUniformReportGL>& dst, const vector<BasicUniformReportRef>& ref, deUint32 programGL);
1036	// Compare infos returned by glGetActiveUniform() and glGetUniformIndices() + glGetActiveUniformsiv().
1037	bool						uniformVsUniformsivComparison			(const vector<BasicUniformReportGL>& uniformsResult, const vector<BasicUniformReportGL>& uniformsivResult);
1038	// Get uniform values with glGetUniform*() and put to valuesDst. Uniforms that get -1 from glGetUniformLocation() get glu::TYPE_INVALID.
1039	bool						getUniforms								(vector<VarValue>& valuesDst, const vector<BasicUniform>& basicUniforms, deUint32 programGL);
1040	// Check that every uniform has the default (zero) value.
1041	bool						checkUniformDefaultValues				(const vector<VarValue>& values, const vector<BasicUniform>& basicUniforms);
1042	// Assign the basicUniforms[].finalValue values for uniforms. \note rnd parameter is for booleans (true can be any nonzero value).
1043	void						assignUniforms							(const vector<BasicUniform>& basicUniforms, deUint32 programGL, Random& rnd);
1044	// Compare the uniform values given in values (obtained with glGetUniform*()) with the basicUniform.finalValue values.
1045	bool						compareUniformValues					(const vector<VarValue>& values, const vector<BasicUniform>& basicUniforms);
1046	// Render and check that all pixels are white (i.e. all uniform comparisons passed).
1047	bool						renderTest								(const vector<BasicUniform>& basicUniforms, const ShaderProgram& program, Random& rnd);
1048
1049	virtual bool				test									(const vector<BasicUniform>& basicUniforms, const vector<BasicUniformReportRef>& basicUniformReportsRef, const ShaderProgram& program, Random& rnd) = 0;
1050
1051	const deUint32								m_features;
1052	const SharedPtr<const UniformCollection>	m_uniformCollection;
1053
1054private:
1055	static deUint32				randomFeatures							(deUint32 seed);
1056
1057	// Generates the basic uniforms, based on the uniform with name varName and type varType, in the same manner as are expected
1058	// to be returned by glGetActiveUniform(), e.g. generates a name like var[0] for arrays, and recursively generates struct member names.
1059	void						generateBasicUniforms					(vector<BasicUniform>&				basicUniformsDst,
1060																		 vector<BasicUniformReportRef>&		basicUniformReportsDst,
1061																		 const glu::VarType&				varType,
1062																		 const char*						varName,
1063																		 bool								isParentActive,
1064																		 int&								samplerUnitCounter,
1065																		 Random&							rnd) const;
1066
1067	void						writeUniformDefinitions					(std::ostringstream& dst) const;
1068	void						writeUniformCompareExpr					(std::ostringstream& dst, const BasicUniform& uniform) const;
1069	void						writeUniformComparisons					(std::ostringstream& dst, const vector<BasicUniform>& basicUniforms, const char* variableName) const;
1070
1071	string						generateVertexSource					(const vector<BasicUniform>& basicUniforms) const;
1072	string						generateFragmentSource					(const vector<BasicUniform>& basicUniforms) const;
1073
1074	void						setupTexture							(const VarValue& value);
1075
1076	const CaseShaderType						m_caseShaderType;
1077
1078	vector<glu::Texture2D*>						m_textures2d;
1079	vector<glu::TextureCube*>					m_texturesCube;
1080	vector<deUint32>							m_filledTextureUnits;
1081};
1082
1083deUint32 UniformCase::randomFeatures (const deUint32 seed)
1084{
1085	static const deUint32 arrayUsageChoices[]		= { 0, FEATURE_ARRAYUSAGE_ONLY_MIDDLE_INDEX										};
1086	static const deUint32 uniformFuncChoices[]		= { 0, FEATURE_UNIFORMFUNC_VALUE												};
1087	static const deUint32 matrixModeChoices[]		= { 0, FEATURE_MATRIXMODE_ROWMAJOR												};
1088	static const deUint32 arrayAssignChoices[]		= { 0, FEATURE_ARRAYASSIGN_FULL,			FEATURE_ARRAYASSIGN_BLOCKS_OF_TWO	};
1089	static const deUint32 uniformUsageChoices[]		= { 0, FEATURE_UNIFORMUSAGE_EVERY_OTHER											};
1090	static const deUint32 booleanApiTypeChoices[]	= { 0, FEATURE_BOOLEANAPITYPE_INT,			FEATURE_BOOLEANAPITYPE_UINT			};
1091	static const deUint32 uniformValueChoices[]		= { 0, FEATURE_UNIFORMVALUE_ZERO												};
1092
1093	Random rnd(seed);
1094
1095	deUint32 result = 0;
1096
1097#define ARRAY_CHOICE(ARR) (ARR[rnd.getInt(0, DE_LENGTH_OF_ARRAY(ARR)-1)])
1098
1099	result |= ARRAY_CHOICE(arrayUsageChoices);
1100	result |= ARRAY_CHOICE(uniformFuncChoices);
1101	result |= ARRAY_CHOICE(matrixModeChoices);
1102	result |= ARRAY_CHOICE(arrayAssignChoices);
1103	result |= ARRAY_CHOICE(uniformUsageChoices);
1104	result |= ARRAY_CHOICE(booleanApiTypeChoices);
1105	result |= ARRAY_CHOICE(uniformValueChoices);
1106
1107#undef ARRAY_CHOICE
1108
1109	return result;
1110}
1111
1112UniformCase::UniformCase (Context& context, const char* const name, const char* const description, const CaseShaderType caseShaderType, const SharedPtr<const UniformCollection>& uniformCollection, const deUint32 features)
1113	: TestCase				(context, name, description)
1114	, CallLogWrapper		(context.getRenderContext().getFunctions(), m_testCtx.getLog())
1115	, m_features			(features)
1116	, m_uniformCollection	(uniformCollection)
1117	, m_caseShaderType		(caseShaderType)
1118{
1119}
1120
1121UniformCase::UniformCase (Context& context, const char* const name, const char* const description, const CaseShaderType caseShaderType, const SharedPtr<const UniformCollection>& uniformCollection)
1122	: TestCase				(context, name, description)
1123	, CallLogWrapper		(context.getRenderContext().getFunctions(), m_testCtx.getLog())
1124	, m_features			(0)
1125	, m_uniformCollection	(uniformCollection)
1126	, m_caseShaderType		(caseShaderType)
1127{
1128}
1129
1130UniformCase::UniformCase (Context& context, const char* name, const char* description, const deUint32 seed)
1131	: TestCase				(context, name, description)
1132	, CallLogWrapper		(context.getRenderContext().getFunctions(), m_testCtx.getLog())
1133	, m_features			(randomFeatures(seed))
1134	, m_uniformCollection	(UniformCollection::random(seed))
1135	, m_caseShaderType		(randomCaseShaderType(seed))
1136{
1137}
1138
1139void UniformCase::init (void)
1140{
1141	{
1142		const glw::Functions&	funcs						= m_context.getRenderContext().getFunctions();
1143		const int				numSamplerUniforms			= m_uniformCollection->getNumSamplers();
1144		const int				vertexTexUnitsRequired		= m_caseShaderType != CASESHADERTYPE_FRAGMENT ? numSamplerUniforms : 0;
1145		const int				fragmentTexUnitsRequired	= m_caseShaderType != CASESHADERTYPE_VERTEX ? numSamplerUniforms : 0;
1146		const int				combinedTexUnitsRequired	= vertexTexUnitsRequired + fragmentTexUnitsRequired;
1147		const int				vertexTexUnitsSupported		= getGLInt(funcs, GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS);
1148		const int				fragmentTexUnitsSupported	= getGLInt(funcs, GL_MAX_TEXTURE_IMAGE_UNITS);
1149		const int				combinedTexUnitsSupported	= getGLInt(funcs, GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS);
1150
1151		DE_ASSERT(numSamplerUniforms <= MAX_NUM_SAMPLER_UNIFORMS);
1152
1153		if (vertexTexUnitsRequired > vertexTexUnitsSupported)
1154			throw tcu::NotSupportedError(de::toString(vertexTexUnitsRequired) + " vertex texture units required, " + de::toString(vertexTexUnitsSupported) + " supported");
1155		if (fragmentTexUnitsRequired > fragmentTexUnitsSupported)
1156			throw tcu::NotSupportedError(de::toString(fragmentTexUnitsRequired) + " fragment texture units required, " + de::toString(fragmentTexUnitsSupported) + " supported");
1157		if (combinedTexUnitsRequired > combinedTexUnitsSupported)
1158			throw tcu::NotSupportedError(de::toString(combinedTexUnitsRequired) + " combined texture units required, " + de::toString(combinedTexUnitsSupported) + " supported");
1159	}
1160
1161	enableLogging(true);
1162}
1163
1164void UniformCase::deinit (void)
1165{
1166	for (int i = 0; i < (int)m_textures2d.size(); i++)
1167		delete m_textures2d[i];
1168	m_textures2d.clear();
1169
1170	for (int i = 0; i < (int)m_texturesCube.size(); i++)
1171		delete m_texturesCube[i];
1172	m_texturesCube.clear();
1173
1174	m_filledTextureUnits.clear();
1175}
1176
1177UniformCase::~UniformCase (void)
1178{
1179	UniformCase::deinit();
1180}
1181
1182void UniformCase::generateBasicUniforms (vector<BasicUniform>& basicUniformsDst, vector<BasicUniformReportRef>& basicUniformReportsDst, const glu::VarType& varType, const char* const varName, const bool isParentActive, int& samplerUnitCounter, Random& rnd) const
1183{
1184	if (varType.isBasicType())
1185	{
1186		const bool				isActive	= isParentActive && (m_features & FEATURE_UNIFORMUSAGE_EVERY_OTHER ? basicUniformsDst.size() % 2 == 0 : true);
1187		const glu::DataType		type		= varType.getBasicType();
1188		const VarValue			value		= m_features & FEATURE_UNIFORMVALUE_ZERO	? generateZeroVarValue(type)
1189											: glu::isDataTypeSampler(type)				? generateRandomVarValue(type, rnd, samplerUnitCounter++)
1190											: generateRandomVarValue(varType.getBasicType(), rnd);
1191
1192		basicUniformsDst.push_back(BasicUniform(varName, varType.getBasicType(), isActive, value));
1193		basicUniformReportsDst.push_back(BasicUniformReportRef(varName, varType.getBasicType(), isActive));
1194	}
1195	else if (varType.isArrayType())
1196	{
1197		const int		size			= varType.getArraySize();
1198		const string	arrayRootName	= string("") + varName + "[0]";
1199		vector<bool>	isElemActive;
1200
1201		for (int elemNdx = 0; elemNdx < varType.getArraySize(); elemNdx++)
1202		{
1203			const string	indexedName		= string("") + varName + "[" + de::toString(elemNdx) + "]";
1204			const bool		isCurElemActive	= isParentActive																						&&
1205											  (m_features & FEATURE_UNIFORMUSAGE_EVERY_OTHER			? basicUniformsDst.size() % 2 == 0	: true)	&&
1206											  (m_features & FEATURE_ARRAYUSAGE_ONLY_MIDDLE_INDEX		? elemNdx == size/2					: true);
1207
1208			isElemActive.push_back(isCurElemActive);
1209
1210			if (varType.getElementType().isBasicType())
1211			{
1212				// \note We don't want separate entries in basicUniformReportsDst for elements of basic-type arrays.
1213				const glu::DataType	elemBasicType	= varType.getElementType().getBasicType();
1214				const VarValue		value			= m_features & FEATURE_UNIFORMVALUE_ZERO	? generateZeroVarValue(elemBasicType)
1215													: glu::isDataTypeSampler(elemBasicType)		? generateRandomVarValue(elemBasicType, rnd, samplerUnitCounter++)
1216													: generateRandomVarValue(elemBasicType, rnd);
1217
1218				basicUniformsDst.push_back(BasicUniform(indexedName.c_str(), elemBasicType, isCurElemActive, value, arrayRootName.c_str(), elemNdx, size));
1219			}
1220			else
1221				generateBasicUniforms(basicUniformsDst, basicUniformReportsDst, varType.getElementType(), indexedName.c_str(), isCurElemActive, samplerUnitCounter, rnd);
1222		}
1223
1224		if (varType.getElementType().isBasicType())
1225		{
1226			int minSize;
1227			for (minSize = varType.getArraySize(); minSize > 0 && !isElemActive[minSize-1]; minSize--);
1228
1229			basicUniformReportsDst.push_back(BasicUniformReportRef(arrayRootName.c_str(), minSize, size, varType.getElementType().getBasicType(), isParentActive && minSize > 0));
1230		}
1231	}
1232	else
1233	{
1234		DE_ASSERT(varType.isStructType());
1235
1236		const StructType& structType = *varType.getStructPtr();
1237
1238		for (int i = 0; i < structType.getNumMembers(); i++)
1239		{
1240			const glu::StructMember&	member			= structType.getMember(i);
1241			const string				memberFullName	= string("") + varName + "." + member.getName();
1242
1243			generateBasicUniforms(basicUniformsDst, basicUniformReportsDst, member.getType(), memberFullName.c_str(), isParentActive, samplerUnitCounter, rnd);
1244		}
1245	}
1246}
1247
1248void UniformCase::writeUniformDefinitions (std::ostringstream& dst) const
1249{
1250	for (int i = 0; i < (int)m_uniformCollection->getNumStructTypes(); i++)
1251		dst << glu::declare(m_uniformCollection->getStructType(i)) << ";\n";
1252
1253	for (int i = 0; i < (int)m_uniformCollection->getNumUniforms(); i++)
1254		dst << "uniform " << glu::declare(m_uniformCollection->getUniform(i).type, m_uniformCollection->getUniform(i).name.c_str()) << ";\n";
1255
1256	dst << "\n";
1257
1258	{
1259		static const struct
1260		{
1261			dataTypePredicate	requiringTypes[2];
1262			const char*			definition;
1263		} compareFuncs[] =
1264		{
1265			{ { glu::isDataTypeFloatOrVec,				glu::isDataTypeMatrix				}, "mediump float compare_float    (mediump float a, mediump float b)  { return abs(a - b) < 0.05 ? 1.0 : 0.0; }"																		},
1266			{ { dataTypeEquals<glu::TYPE_FLOAT_VEC2>,	dataTypeIsMatrixWithNRows<2>		}, "mediump float compare_vec2     (mediump vec2 a, mediump vec2 b)    { return compare_float(a.x, b.x)*compare_float(a.y, b.y); }"														},
1267			{ { dataTypeEquals<glu::TYPE_FLOAT_VEC3>,	dataTypeIsMatrixWithNRows<3>		}, "mediump float compare_vec3     (mediump vec3 a, mediump vec3 b)    { return compare_float(a.x, b.x)*compare_float(a.y, b.y)*compare_float(a.z, b.z); }"								},
1268			{ { dataTypeEquals<glu::TYPE_FLOAT_VEC4>,	dataTypeIsMatrixWithNRows<4>		}, "mediump float compare_vec4     (mediump vec4 a, mediump vec4 b)    { return compare_float(a.x, b.x)*compare_float(a.y, b.y)*compare_float(a.z, b.z)*compare_float(a.w, b.w); }"		},
1269			{ { dataTypeEquals<glu::TYPE_FLOAT_MAT2>,	dataTypeEquals<glu::TYPE_INVALID>	}, "mediump float compare_mat2     (mediump mat2 a, mediump mat2 b)    { return compare_vec2(a[0], b[0])*compare_vec2(a[1], b[1]); }"													},
1270			{ { dataTypeEquals<glu::TYPE_FLOAT_MAT2X3>,	dataTypeEquals<glu::TYPE_INVALID>	}, "mediump float compare_mat2x3   (mediump mat2x3 a, mediump mat2x3 b){ return compare_vec3(a[0], b[0])*compare_vec3(a[1], b[1]); }"													},
1271			{ { dataTypeEquals<glu::TYPE_FLOAT_MAT2X4>,	dataTypeEquals<glu::TYPE_INVALID>	}, "mediump float compare_mat2x4   (mediump mat2x4 a, mediump mat2x4 b){ return compare_vec4(a[0], b[0])*compare_vec4(a[1], b[1]); }"													},
1272			{ { dataTypeEquals<glu::TYPE_FLOAT_MAT3X2>,	dataTypeEquals<glu::TYPE_INVALID>	}, "mediump float compare_mat3x2   (mediump mat3x2 a, mediump mat3x2 b){ return compare_vec2(a[0], b[0])*compare_vec2(a[1], b[1])*compare_vec2(a[2], b[2]); }"							},
1273			{ { dataTypeEquals<glu::TYPE_FLOAT_MAT3>,	dataTypeEquals<glu::TYPE_INVALID>	}, "mediump float compare_mat3     (mediump mat3 a, mediump mat3 b)    { return compare_vec3(a[0], b[0])*compare_vec3(a[1], b[1])*compare_vec3(a[2], b[2]); }"							},
1274			{ { dataTypeEquals<glu::TYPE_FLOAT_MAT3X4>,	dataTypeEquals<glu::TYPE_INVALID>	}, "mediump float compare_mat3x4   (mediump mat3x4 a, mediump mat3x4 b){ return compare_vec4(a[0], b[0])*compare_vec4(a[1], b[1])*compare_vec4(a[2], b[2]); }"							},
1275			{ { dataTypeEquals<glu::TYPE_FLOAT_MAT4X2>,	dataTypeEquals<glu::TYPE_INVALID>	}, "mediump float compare_mat4x2   (mediump mat4x2 a, mediump mat4x2 b){ return compare_vec2(a[0], b[0])*compare_vec2(a[1], b[1])*compare_vec2(a[2], b[2])*compare_vec2(a[3], b[3]); }"	},
1276			{ { dataTypeEquals<glu::TYPE_FLOAT_MAT4X3>,	dataTypeEquals<glu::TYPE_INVALID>	}, "mediump float compare_mat4x3   (mediump mat4x3 a, mediump mat4x3 b){ return compare_vec3(a[0], b[0])*compare_vec3(a[1], b[1])*compare_vec3(a[2], b[2])*compare_vec3(a[3], b[3]); }"	},
1277			{ { dataTypeEquals<glu::TYPE_FLOAT_MAT4>,	dataTypeEquals<glu::TYPE_INVALID>	}, "mediump float compare_mat4     (mediump mat4 a, mediump mat4 b)    { return compare_vec4(a[0], b[0])*compare_vec4(a[1], b[1])*compare_vec4(a[2], b[2])*compare_vec4(a[3], b[3]); }"	},
1278			{ { dataTypeEquals<glu::TYPE_INT>,			dataTypeEquals<glu::TYPE_INVALID>	}, "mediump float compare_int      (mediump int a, mediump int b)      { return a == b ? 1.0 : 0.0; }"																					},
1279			{ { dataTypeEquals<glu::TYPE_INT_VEC2>,		dataTypeEquals<glu::TYPE_INVALID>	}, "mediump float compare_ivec2    (mediump ivec2 a, mediump ivec2 b)  { return a == b ? 1.0 : 0.0; }"																					},
1280			{ { dataTypeEquals<glu::TYPE_INT_VEC3>,		dataTypeEquals<glu::TYPE_INVALID>	}, "mediump float compare_ivec3    (mediump ivec3 a, mediump ivec3 b)  { return a == b ? 1.0 : 0.0; }"																					},
1281			{ { dataTypeEquals<glu::TYPE_INT_VEC4>,		dataTypeEquals<glu::TYPE_INVALID>	}, "mediump float compare_ivec4    (mediump ivec4 a, mediump ivec4 b)  { return a == b ? 1.0 : 0.0; }"																					},
1282			{ { dataTypeEquals<glu::TYPE_UINT>,			dataTypeEquals<glu::TYPE_INVALID>	}, "mediump float compare_uint     (mediump uint a, mediump uint b)    { return a == b ? 1.0 : 0.0; }"																					},
1283			{ { dataTypeEquals<glu::TYPE_UINT_VEC2>,	dataTypeEquals<glu::TYPE_INVALID>	}, "mediump float compare_uvec2    (mediump uvec2 a, mediump uvec2 b)  { return a == b ? 1.0 : 0.0; }"																					},
1284			{ { dataTypeEquals<glu::TYPE_UINT_VEC3>,	dataTypeEquals<glu::TYPE_INVALID>	}, "mediump float compare_uvec3    (mediump uvec3 a, mediump uvec3 b)  { return a == b ? 1.0 : 0.0; }"																					},
1285			{ { dataTypeEquals<glu::TYPE_UINT_VEC4>,	dataTypeEquals<glu::TYPE_INVALID>	}, "mediump float compare_uvec4    (mediump uvec4 a, mediump uvec4 b)  { return a == b ? 1.0 : 0.0; }"																					},
1286			{ { dataTypeEquals<glu::TYPE_BOOL>,			dataTypeEquals<glu::TYPE_INVALID>	}, "mediump float compare_bool     (bool a, bool b)                    { return a == b ? 1.0 : 0.0; }"																					},
1287			{ { dataTypeEquals<glu::TYPE_BOOL_VEC2>,	dataTypeEquals<glu::TYPE_INVALID>	}, "mediump float compare_bvec2    (bvec2 a, bvec2 b)                  { return a == b ? 1.0 : 0.0; }"																					},
1288			{ { dataTypeEquals<glu::TYPE_BOOL_VEC3>,	dataTypeEquals<glu::TYPE_INVALID>	}, "mediump float compare_bvec3    (bvec3 a, bvec3 b)                  { return a == b ? 1.0 : 0.0; }"																					},
1289			{ { dataTypeEquals<glu::TYPE_BOOL_VEC4>,	dataTypeEquals<glu::TYPE_INVALID>	}, "mediump float compare_bvec4    (bvec4 a, bvec4 b)                  { return a == b ? 1.0 : 0.0; }"																					}
1290		};
1291
1292		const vector<glu::DataType> samplerTypes = m_uniformCollection->getSamplerTypes();
1293
1294		for (int compFuncNdx = 0; compFuncNdx < DE_LENGTH_OF_ARRAY(compareFuncs); compFuncNdx++)
1295		{
1296			const dataTypePredicate		(&typeReq)[2]			= compareFuncs[compFuncNdx].requiringTypes;
1297			bool						containsTypeSampler		= false;
1298
1299			for (int i = 0; i < (int)samplerTypes.size(); i++)
1300			{
1301				if (glu::isDataTypeSampler(samplerTypes[i]))
1302				{
1303					const glu::DataType retType = getSamplerLookupReturnType(samplerTypes[i]);
1304					if (typeReq[0](retType) || typeReq[1](retType))
1305					{
1306						containsTypeSampler = true;
1307						break;
1308					}
1309				}
1310			}
1311
1312			if (containsTypeSampler || m_uniformCollection->containsMatchingBasicType(typeReq[0]) || m_uniformCollection->containsMatchingBasicType(typeReq[1]))
1313				dst << compareFuncs[compFuncNdx].definition << "\n";
1314		}
1315	}
1316}
1317
1318void UniformCase::writeUniformCompareExpr (std::ostringstream& dst, const BasicUniform& uniform) const
1319{
1320	if (glu::isDataTypeSampler(uniform.type))
1321		dst << "compare_" << glu::getDataTypeName(getSamplerLookupReturnType(uniform.type)) << "(texture(" << uniform.name << ", vec" << getSamplerNumLookupDimensions(uniform.type) << "(0.0))";
1322	else
1323		dst << "compare_" << glu::getDataTypeName(uniform.type) << "(" << uniform.name;
1324
1325	dst << ", " << shaderVarValueStr(uniform.finalValue) << ")";
1326}
1327
1328void UniformCase::writeUniformComparisons (std::ostringstream& dst, const vector<BasicUniform>& basicUniforms, const char* const variableName) const
1329{
1330	for (int i = 0; i < (int)basicUniforms.size(); i++)
1331	{
1332		const BasicUniform& unif = basicUniforms[i];
1333
1334		if (unif.isUsedInShader)
1335		{
1336			dst << "\t" << variableName << " *= ";
1337			writeUniformCompareExpr(dst, basicUniforms[i]);
1338			dst << ";\n";
1339		}
1340		else
1341			dst << "\t// UNUSED: " << basicUniforms[i].name << "\n";
1342	}
1343}
1344
1345string UniformCase::generateVertexSource (const vector<BasicUniform>& basicUniforms) const
1346{
1347	const bool			isVertexCase = m_caseShaderType == CASESHADERTYPE_VERTEX || m_caseShaderType == CASESHADERTYPE_BOTH;
1348	std::ostringstream	result;
1349
1350	result << "#version 300 es\n"
1351			  "in highp vec4 a_position;\n"
1352			  "out mediump float v_vtxOut;\n"
1353			  "\n";
1354
1355	if (isVertexCase)
1356		writeUniformDefinitions(result);
1357
1358	result << "\n"
1359			  "void main (void)\n"
1360			  "{\n"
1361			  "	gl_Position = a_position;\n"
1362			  "	v_vtxOut = 1.0;\n";
1363
1364	if (isVertexCase)
1365		writeUniformComparisons(result, basicUniforms, "v_vtxOut");
1366
1367	result << "}\n";
1368
1369	return result.str();
1370}
1371
1372string UniformCase::generateFragmentSource (const vector<BasicUniform>& basicUniforms) const
1373{
1374	const bool			isFragmentCase = m_caseShaderType == CASESHADERTYPE_FRAGMENT || m_caseShaderType == CASESHADERTYPE_BOTH;
1375	std::ostringstream	result;
1376
1377	result << "#version 300 es\n"
1378			  "in mediump float v_vtxOut;\n"
1379			  "\n";
1380
1381	if (isFragmentCase)
1382		writeUniformDefinitions(result);
1383
1384	result << "\n"
1385			  "layout(location = 0) out mediump vec4 dEQP_FragColor;\n"
1386			  "\n"
1387			  "void main (void)\n"
1388			  "{\n"
1389			  "	mediump float result = v_vtxOut;\n";
1390
1391	if (isFragmentCase)
1392		writeUniformComparisons(result, basicUniforms, "result");
1393
1394	result << "	dEQP_FragColor = vec4(result, result, result, 1.0);\n"
1395			  "}\n";
1396
1397	return result.str();
1398}
1399
1400void UniformCase::setupTexture (const VarValue& value)
1401{
1402	// \note No handling for samplers other than 2D or cube.
1403
1404	enableLogging(false);
1405
1406	DE_ASSERT(getSamplerLookupReturnType(value.type) == glu::TYPE_FLOAT_VEC4);
1407
1408	const int						width			= 32;
1409	const int						height			= 32;
1410	const tcu::Vec4					color			= vec4FromPtr(&value.val.samplerV.fillColor.floatV[0]);
1411
1412	if (value.type == glu::TYPE_SAMPLER_2D)
1413	{
1414		glu::Texture2D* texture		= new glu::Texture2D(m_context.getRenderContext(), GL_RGBA, GL_UNSIGNED_BYTE, width, height);
1415		tcu::Texture2D& refTexture	= texture->getRefTexture();
1416		m_textures2d.push_back(texture);
1417
1418		refTexture.allocLevel(0);
1419		fillWithColor(refTexture.getLevel(0), color);
1420
1421		GLU_CHECK_CALL(glActiveTexture(GL_TEXTURE0 + value.val.samplerV.unit));
1422		m_filledTextureUnits.push_back(value.val.samplerV.unit);
1423		texture->upload();
1424		GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
1425		GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
1426		GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
1427		GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
1428	}
1429	else if (value.type == glu::TYPE_SAMPLER_CUBE)
1430	{
1431		DE_ASSERT(width == height);
1432
1433		glu::TextureCube* texture		= new glu::TextureCube(m_context.getRenderContext(), GL_RGBA, GL_UNSIGNED_BYTE, width);
1434		tcu::TextureCube& refTexture	= texture->getRefTexture();
1435		m_texturesCube.push_back(texture);
1436
1437		for (int face = 0; face < (int)tcu::CUBEFACE_LAST; face++)
1438		{
1439			refTexture.allocLevel((tcu::CubeFace)face, 0);
1440			fillWithColor(refTexture.getLevelFace(0, (tcu::CubeFace)face), color);
1441		}
1442
1443		GLU_CHECK_CALL(glActiveTexture(GL_TEXTURE0 + value.val.samplerV.unit));
1444		m_filledTextureUnits.push_back(value.val.samplerV.unit);
1445		texture->upload();
1446		GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
1447		GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
1448		GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
1449		GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
1450
1451	}
1452	else
1453		DE_ASSERT(false);
1454
1455	enableLogging(true);
1456}
1457
1458bool UniformCase::getActiveUniforms (vector<BasicUniformReportGL>& basicUniformReportsDst, const vector<BasicUniformReportRef>& basicUniformReportsRef, const deUint32 programGL)
1459{
1460	TestLog&			log						= m_testCtx.getLog();
1461	GLint				numActiveUniforms		= 0;
1462	GLint				uniformMaxNameLength	= 0;
1463	vector<char>		nameBuffer;
1464	bool				success					= true;
1465
1466	GLU_CHECK_CALL(glGetProgramiv(programGL, GL_ACTIVE_UNIFORMS, &numActiveUniforms));
1467	log << TestLog::Message << "// Number of active uniforms reported: " << numActiveUniforms << TestLog::EndMessage;
1468	GLU_CHECK_CALL(glGetProgramiv(programGL, GL_ACTIVE_UNIFORM_MAX_LENGTH, &uniformMaxNameLength));
1469	log << TestLog::Message << "// Maximum uniform name length reported: " << uniformMaxNameLength << TestLog::EndMessage;
1470	nameBuffer.resize(uniformMaxNameLength);
1471
1472	for (int unifNdx = 0; unifNdx < numActiveUniforms; unifNdx++)
1473	{
1474		GLsizei					reportedNameLength	= 0;
1475		GLint					reportedSize		= -1;
1476		GLenum					reportedTypeGL		= GL_NONE;
1477
1478		GLU_CHECK_CALL(glGetActiveUniform(programGL, (GLuint)unifNdx, (GLsizei)uniformMaxNameLength, &reportedNameLength, &reportedSize, &reportedTypeGL, &nameBuffer[0]));
1479
1480		const glu::DataType		reportedType		= glu::getDataTypeFromGLType(reportedTypeGL);
1481		const string			reportedNameStr		(&nameBuffer[0]);
1482
1483		TCU_CHECK_MSG(reportedType != glu::TYPE_LAST, "Invalid uniform type");
1484
1485		log << TestLog::Message << "// Got name = " << reportedNameStr << ", name length = " << reportedNameLength << ", size = " << reportedSize << ", type = " << glu::getDataTypeName(reportedType) << TestLog::EndMessage;
1486
1487		if ((GLsizei)reportedNameStr.length() != reportedNameLength)
1488		{
1489			log << TestLog::Message << "// FAILURE: wrong name length reported, should be " << reportedNameStr.length() << TestLog::EndMessage;
1490			success = false;
1491		}
1492
1493		if (!deStringBeginsWith(reportedNameStr.c_str(), "gl_")) // Ignore built-in uniforms.
1494		{
1495			int referenceNdx;
1496			for (referenceNdx = 0; referenceNdx < (int)basicUniformReportsRef.size(); referenceNdx++)
1497			{
1498				if (basicUniformReportsRef[referenceNdx].name == reportedNameStr)
1499					break;
1500			}
1501
1502			if (referenceNdx >= (int)basicUniformReportsRef.size())
1503			{
1504				log << TestLog::Message << "// FAILURE: invalid non-built-in uniform name reported" << TestLog::EndMessage;
1505				success = false;
1506			}
1507			else
1508			{
1509				const BasicUniformReportRef& reference = basicUniformReportsRef[referenceNdx];
1510
1511				DE_ASSERT(reference.type != glu::TYPE_LAST);
1512				DE_ASSERT(reference.minSize >= 1 || (reference.minSize == 0 && !reference.isUsedInShader));
1513				DE_ASSERT(reference.minSize <= reference.maxSize);
1514
1515				if (BasicUniformReportGL::findWithName(basicUniformReportsDst, reportedNameStr.c_str()) != basicUniformReportsDst.end())
1516				{
1517					log << TestLog::Message << "// FAILURE: same uniform name reported twice" << TestLog::EndMessage;
1518					success = false;
1519				}
1520
1521				basicUniformReportsDst.push_back(BasicUniformReportGL(reportedNameStr.c_str(), reportedNameLength, reportedSize, reportedType, unifNdx));
1522
1523				if (reportedType != reference.type)
1524				{
1525					log << TestLog::Message << "// FAILURE: wrong type reported, should be " << glu::getDataTypeName(reference.type) << TestLog::EndMessage;
1526					success = false;
1527				}
1528				if (reportedSize < reference.minSize || reportedSize > reference.maxSize)
1529				{
1530					log << TestLog::Message
1531						<< "// FAILURE: wrong size reported, should be "
1532						<< (reference.minSize == reference.maxSize ? de::toString(reference.minSize) : "in the range [" + de::toString(reference.minSize) + ", " + de::toString(reference.maxSize) + "]")
1533						<< TestLog::EndMessage;
1534
1535					success = false;
1536				}
1537			}
1538		}
1539	}
1540
1541	for (int i = 0; i < (int)basicUniformReportsRef.size(); i++)
1542	{
1543		const BasicUniformReportRef& expected = basicUniformReportsRef[i];
1544		if (expected.isUsedInShader && BasicUniformReportGL::findWithName(basicUniformReportsDst, expected.name.c_str()) == basicUniformReportsDst.end())
1545		{
1546			log << TestLog::Message << "// FAILURE: uniform with name " << expected.name << " was not reported by GL" << TestLog::EndMessage;
1547			success = false;
1548		}
1549	}
1550
1551	return success;
1552}
1553
1554bool UniformCase::getActiveUniformsiv (vector<BasicUniformReportGL>& basicUniformReportsDst, const vector<BasicUniformReportRef>& basicUniformReportsRef, const deUint32 programGL)
1555{
1556	TestLog&				log				= m_testCtx.getLog();
1557	vector<string>			queryNames		(basicUniformReportsRef.size());
1558	vector<const char*>		queryNamesC		(basicUniformReportsRef.size());
1559	vector<GLuint>			uniformIndices	(basicUniformReportsRef.size());
1560	vector<deUint32>		validUniformIndices; // This shall have the same contents, and in same order, as uniformIndices, but with GL_INVALID_INDEX entries removed.
1561	bool					success			= true;
1562
1563	for (int i = 0; i < (int)basicUniformReportsRef.size(); i++)
1564	{
1565		const string& name = basicUniformReportsRef[i].name;
1566		queryNames[i]	= m_features & FEATURE_ARRAY_FIRST_ELEM_NAME_NO_INDEX && name[name.size()-1] == ']' ? beforeLast(name, '[') : name;
1567		queryNamesC[i]	= queryNames[i].c_str();
1568	}
1569
1570	GLU_CHECK_CALL(glGetUniformIndices(programGL, (GLsizei)basicUniformReportsRef.size(), &queryNamesC[0], &uniformIndices[0]));
1571
1572	for (int i = 0; i < (int)uniformIndices.size(); i++)
1573	{
1574		if (uniformIndices[i] != GL_INVALID_INDEX)
1575			validUniformIndices.push_back(uniformIndices[i]);
1576		else
1577		{
1578			if (basicUniformReportsRef[i].isUsedInShader)
1579			{
1580				log << TestLog::Message << "// FAILURE: uniform with name " << basicUniformReportsRef[i].name << " received GL_INVALID_INDEX" << TestLog::EndMessage;
1581				success = false;
1582			}
1583		}
1584	}
1585
1586	if (!validUniformIndices.empty())
1587	{
1588		vector<GLint> uniformNameLengthBuf	(validUniformIndices.size());
1589		vector<GLint> uniformSizeBuf		(validUniformIndices.size());
1590		vector<GLint> uniformTypeBuf		(validUniformIndices.size());
1591
1592		GLU_CHECK_CALL(glGetActiveUniformsiv(programGL, (GLsizei)validUniformIndices.size(), &validUniformIndices[0], GL_UNIFORM_NAME_LENGTH,	&uniformNameLengthBuf[0]));
1593		GLU_CHECK_CALL(glGetActiveUniformsiv(programGL, (GLsizei)validUniformIndices.size(), &validUniformIndices[0], GL_UNIFORM_SIZE,			&uniformSizeBuf[0]));
1594		GLU_CHECK_CALL(glGetActiveUniformsiv(programGL, (GLsizei)validUniformIndices.size(), &validUniformIndices[0], GL_UNIFORM_TYPE,			&uniformTypeBuf[0]));
1595
1596		{
1597			int validNdx = -1; // Keeps the corresponding index to validUniformIndices while unifNdx is the index to uniformIndices.
1598			for (int unifNdx = 0; unifNdx < (int)uniformIndices.size(); unifNdx++)
1599			{
1600				if (uniformIndices[unifNdx] == GL_INVALID_INDEX)
1601					continue;
1602
1603				validNdx++;
1604
1605				const BasicUniformReportRef&	reference			= basicUniformReportsRef[unifNdx];
1606				const int						reportedIndex		= validUniformIndices[validNdx];
1607				const int						reportedNameLength	= (int)uniformNameLengthBuf[validNdx];
1608				const int						reportedSize		= (int)uniformSizeBuf[validNdx];
1609				const glu::DataType				reportedType		= glu::getDataTypeFromGLType((deUint32)uniformTypeBuf[validNdx]);
1610
1611				TCU_CHECK_MSG(reportedType != glu::TYPE_LAST, "Invalid uniform type");
1612
1613				log << TestLog::Message
1614					<< "// Got name length = " << reportedNameLength
1615					<< ", size = " << reportedSize
1616					<< ", type = " << glu::getDataTypeName(reportedType)
1617					<< " for the uniform at index " << reportedIndex << " (" << reference.name << ")"
1618					<< TestLog::EndMessage;
1619
1620				DE_ASSERT(reference.type != glu::TYPE_LAST);
1621				DE_ASSERT(reference.minSize >= 1 || (reference.minSize == 0 && !reference.isUsedInShader));
1622				DE_ASSERT(reference.minSize <= reference.maxSize);
1623				basicUniformReportsDst.push_back(BasicUniformReportGL(reference.name.c_str(), reportedNameLength, reportedSize, reportedType, reportedIndex));
1624
1625				if (reportedNameLength != (int)reference.name.length() + 1)
1626				{
1627					log << TestLog::Message << "// FAILURE: wrong name length reported, should be " << reference.name.length() + 1 << TestLog::EndMessage;
1628					success = false;
1629				}
1630
1631				if (reportedType != reference.type)
1632				{
1633					log << TestLog::Message << "// FAILURE: wrong type reported, should be " << glu::getDataTypeName(reference.type) << TestLog::EndMessage;
1634					success = false;
1635				}
1636
1637				if (reportedSize < reference.minSize || reportedSize > reference.maxSize)
1638				{
1639					log << TestLog::Message
1640						<< "// FAILURE: wrong size reported, should be "
1641						<< (reference.minSize == reference.maxSize ? de::toString(reference.minSize) : "in the range [" + de::toString(reference.minSize) + ", " + de::toString(reference.maxSize) + "]")
1642						<< TestLog::EndMessage;
1643
1644					success = false;
1645				}
1646			}
1647		}
1648	}
1649
1650	return success;
1651}
1652
1653bool UniformCase::uniformVsUniformsivComparison (const vector<BasicUniformReportGL>& uniformResults, const vector<BasicUniformReportGL>& uniformsivResults)
1654{
1655	TestLog&	log			= m_testCtx.getLog();
1656	bool		success		= true;
1657
1658	for (int uniformResultNdx = 0; uniformResultNdx < (int)uniformResults.size(); uniformResultNdx++)
1659	{
1660		const BasicUniformReportGL&							uniformResult		= uniformResults[uniformResultNdx];
1661		const string&										uniformName			= uniformResult.name;
1662		const vector<BasicUniformReportGL>::const_iterator	uniformsivResultIt	= BasicUniformReportGL::findWithName(uniformsivResults, uniformName.c_str());
1663
1664		if (uniformsivResultIt != uniformsivResults.end())
1665		{
1666			const BasicUniformReportGL& uniformsivResult = *uniformsivResultIt;
1667
1668			log << TestLog::Message << "// Checking uniform " << uniformName << TestLog::EndMessage;
1669
1670			if (uniformResult.index != uniformsivResult.index)
1671			{
1672				log << TestLog::Message << "// FAILURE: glGetActiveUniform() and glGetUniformIndices() gave different indices for uniform " << uniformName << TestLog::EndMessage;
1673				success = false;
1674			}
1675			if (uniformResult.nameLength + 1 != uniformsivResult.nameLength)
1676			{
1677				log << TestLog::Message << "// FAILURE: glGetActiveUniform() and glGetActiveUniformsiv() gave incompatible name lengths for uniform " << uniformName << TestLog::EndMessage;
1678				success = false;
1679			}
1680			if (uniformResult.size != uniformsivResult.size)
1681			{
1682				log << TestLog::Message << "// FAILURE: glGetActiveUniform() and glGetActiveUniformsiv() gave different sizes for uniform " << uniformName << TestLog::EndMessage;
1683				success = false;
1684			}
1685			if (uniformResult.type != uniformsivResult.type)
1686			{
1687				log << TestLog::Message << "// FAILURE: glGetActiveUniform() and glGetActiveUniformsiv() gave different types for uniform " << uniformName << TestLog::EndMessage;
1688				success = false;
1689			}
1690		}
1691		else
1692		{
1693			log << TestLog::Message << "// FAILURE: uniform " << uniformName << " was reported active by glGetActiveUniform() but not by glGetUniformIndices()" << TestLog::EndMessage;
1694			success = false;
1695		}
1696	}
1697
1698	for (int uniformsivResultNdx = 0; uniformsivResultNdx < (int)uniformsivResults.size(); uniformsivResultNdx++)
1699	{
1700		const BasicUniformReportGL&							uniformsivResult	= uniformsivResults[uniformsivResultNdx];
1701		const string&										uniformsivName		= uniformsivResult.name;
1702		const vector<BasicUniformReportGL>::const_iterator	uniformsResultIt	= BasicUniformReportGL::findWithName(uniformsivResults, uniformsivName.c_str());
1703
1704		if (uniformsResultIt == uniformsivResults.end())
1705		{
1706			log << TestLog::Message << "// FAILURE: uniform " << uniformsivName << " was reported active by glGetUniformIndices() but not by glGetActiveUniform()" << TestLog::EndMessage;
1707			success = false;
1708		}
1709	}
1710
1711	return success;
1712}
1713
1714bool UniformCase::getUniforms (vector<VarValue>& valuesDst, const vector<BasicUniform>& basicUniforms, const deUint32 programGL)
1715{
1716	TestLog&	log			= m_testCtx.getLog();
1717	bool		success		= true;
1718
1719	for (int unifNdx = 0; unifNdx < (int)basicUniforms.size(); unifNdx++)
1720	{
1721		const BasicUniform&		uniform		= basicUniforms[unifNdx];
1722		const string			queryName	= m_features & FEATURE_ARRAY_FIRST_ELEM_NAME_NO_INDEX && uniform.elemNdx == 0 ? beforeLast(uniform.name, '[') : uniform.name;
1723		const int				location	= glGetUniformLocation(programGL, queryName.c_str());
1724		const int				size		= glu::getDataTypeScalarSize(uniform.type);
1725		VarValue				value;
1726
1727		deMemset(&value, 0xcd, sizeof(value)); // Initialize to known garbage.
1728
1729		if (location == -1)
1730		{
1731			value.type = glu::TYPE_INVALID;
1732			valuesDst.push_back(value);
1733			if (uniform.isUsedInShader)
1734			{
1735				log << TestLog::Message << "// FAILURE: " << uniform.name << " was used in shader, but has location -1" << TestLog::EndMessage;
1736				success = false;
1737			}
1738			continue;
1739		}
1740
1741		value.type = uniform.type;
1742
1743		DE_STATIC_ASSERT(sizeof(GLint) == sizeof(value.val.intV[0]));
1744		DE_STATIC_ASSERT(sizeof(GLuint) == sizeof(value.val.uintV[0]));
1745		DE_STATIC_ASSERT(sizeof(GLfloat) == sizeof(value.val.floatV[0]));
1746
1747		if (glu::isDataTypeFloatOrVec(uniform.type) || glu::isDataTypeMatrix(uniform.type))
1748			GLU_CHECK_CALL(glGetUniformfv(programGL, location, &value.val.floatV[0]));
1749		else if (glu::isDataTypeIntOrIVec(uniform.type))
1750			GLU_CHECK_CALL(glGetUniformiv(programGL, location, &value.val.intV[0]));
1751		else if (glu::isDataTypeUintOrUVec(uniform.type))
1752			GLU_CHECK_CALL(glGetUniformuiv(programGL, location, &value.val.uintV[0]));
1753		else if (glu::isDataTypeBoolOrBVec(uniform.type))
1754		{
1755			if (m_features & FEATURE_BOOLEANAPITYPE_INT)
1756			{
1757				GLU_CHECK_CALL(glGetUniformiv(programGL, location, &value.val.intV[0]));
1758				for (int i = 0; i < size; i++)
1759					value.val.boolV[i] = value.val.intV[i] != 0;
1760			}
1761			else if (m_features & FEATURE_BOOLEANAPITYPE_UINT)
1762			{
1763				GLU_CHECK_CALL(glGetUniformuiv(programGL, location, &value.val.uintV[0]));
1764				for (int i = 0; i < size; i++)
1765					value.val.boolV[i] = value.val.uintV[i] != 0;
1766			}
1767			else // Default: use float.
1768			{
1769				GLU_CHECK_CALL(glGetUniformfv(programGL, location, &value.val.floatV[0]));
1770				for (int i = 0; i < size; i++)
1771					value.val.boolV[i] = value.val.floatV[i] != 0.0f;
1772			}
1773		}
1774		else if (glu::isDataTypeSampler(uniform.type))
1775		{
1776			GLint unit = -1;
1777			GLU_CHECK_CALL(glGetUniformiv(programGL, location, &unit));
1778			value.val.samplerV.unit = unit;
1779		}
1780		else
1781			DE_ASSERT(false);
1782
1783		valuesDst.push_back(value);
1784
1785		log << TestLog::Message << "// Got " << uniform.name << " value " << apiVarValueStr(value) << TestLog::EndMessage;
1786	}
1787
1788	return success;
1789}
1790
1791bool UniformCase::checkUniformDefaultValues (const vector<VarValue>& values, const vector<BasicUniform>& basicUniforms)
1792{
1793	TestLog&	log			= m_testCtx.getLog();
1794	bool		success		= true;
1795
1796	DE_ASSERT(values.size() == basicUniforms.size());
1797
1798	for (int unifNdx = 0; unifNdx < (int)basicUniforms.size(); unifNdx++)
1799	{
1800		const BasicUniform&		uniform		= basicUniforms[unifNdx];
1801		const VarValue&			unifValue	= values[unifNdx];
1802		const int				valSize		= glu::getDataTypeScalarSize(uniform.type);
1803
1804		log << TestLog::Message << "// Checking uniform " << uniform.name << TestLog::EndMessage;
1805
1806		if (unifValue.type == glu::TYPE_INVALID) // This happens when glGetUniformLocation() returned -1.
1807			continue;
1808
1809#define CHECK_UNIFORM(VAR_VALUE_MEMBER, ZERO)																								\
1810	do																																		\
1811	{																																		\
1812		for (int i = 0; i < valSize; i++)																									\
1813		{																																	\
1814			if (unifValue.val.VAR_VALUE_MEMBER[i] != ZERO)																					\
1815			{																																\
1816				log << TestLog::Message << "// FAILURE: uniform " << uniform.name << " has non-zero initial value" << TestLog::EndMessage;	\
1817				success = false;																											\
1818			}																																\
1819		}																																	\
1820	} while (false)
1821
1822		if (glu::isDataTypeFloatOrVec(uniform.type) || glu::isDataTypeMatrix(uniform.type))
1823			CHECK_UNIFORM(floatV, 0.0f);
1824		else if (glu::isDataTypeIntOrIVec(uniform.type))
1825			CHECK_UNIFORM(intV, 0);
1826		else if (glu::isDataTypeUintOrUVec(uniform.type))
1827			CHECK_UNIFORM(uintV, 0);
1828		else if (glu::isDataTypeBoolOrBVec(uniform.type))
1829			CHECK_UNIFORM(boolV, false);
1830		else if (glu::isDataTypeSampler(uniform.type))
1831		{
1832			if (unifValue.val.samplerV.unit != 0)
1833			{
1834				log << TestLog::Message << "// FAILURE: uniform " << uniform.name << " has non-zero initial value" << TestLog::EndMessage;
1835				success = false;
1836			}
1837		}
1838		else
1839			DE_ASSERT(false);
1840
1841#undef CHECK_UNIFORM
1842	}
1843
1844	return success;
1845}
1846
1847void UniformCase::assignUniforms (const vector<BasicUniform>& basicUniforms, deUint32 programGL, Random& rnd)
1848{
1849	TestLog&				log				= m_testCtx.getLog();
1850	const bool				transpose		= (m_features & FEATURE_MATRIXMODE_ROWMAJOR) != 0;
1851	const GLboolean			transposeGL		= transpose ? GL_TRUE : GL_FALSE;
1852	const glu::DataType		boolApiType		= m_features & FEATURE_BOOLEANAPITYPE_INT	? glu::TYPE_INT
1853											: m_features & FEATURE_BOOLEANAPITYPE_UINT	? glu::TYPE_UINT
1854											:											  glu::TYPE_FLOAT;
1855
1856	for (int unifNdx = 0; unifNdx < (int)basicUniforms.size(); unifNdx++)
1857	{
1858		const BasicUniform&		uniform				= basicUniforms[unifNdx];
1859		const bool				isArrayMember		= uniform.elemNdx >= 0;
1860		const string			queryName			= m_features & FEATURE_ARRAY_FIRST_ELEM_NAME_NO_INDEX && uniform.elemNdx == 0 ? beforeLast(uniform.name, '[') : uniform.name;
1861		const int				numValuesToAssign	= !isArrayMember									? 1
1862													: m_features & FEATURE_ARRAYASSIGN_FULL				? (uniform.elemNdx == 0			? uniform.rootSize	: 0)
1863													: m_features & FEATURE_ARRAYASSIGN_BLOCKS_OF_TWO	? (uniform.elemNdx % 2 == 0		? 2					: 0)
1864													: /* Default: assign array elements separately */	  1;
1865
1866		DE_ASSERT(numValuesToAssign >= 0);
1867		DE_ASSERT(numValuesToAssign == 1 || isArrayMember);
1868
1869		if (numValuesToAssign == 0)
1870		{
1871			log << TestLog::Message << "// Uniform " << uniform.name << " is covered by another glUniform*v() call to the same array" << TestLog::EndMessage;
1872			continue;
1873		}
1874
1875		const int			location			= glGetUniformLocation(programGL, queryName.c_str());
1876		const int			typeSize			= glu::getDataTypeScalarSize(uniform.type);
1877		const bool			assignByValue		= m_features & FEATURE_UNIFORMFUNC_VALUE && !glu::isDataTypeMatrix(uniform.type) && numValuesToAssign == 1;
1878		vector<VarValue>	valuesToAssign;
1879
1880		for (int i = 0; i < numValuesToAssign; i++)
1881		{
1882			const string	curName = isArrayMember ? beforeLast(uniform.rootName, '[') + "[" + de::toString(uniform.elemNdx+i) + "]" : uniform.name;
1883			VarValue		unifValue;
1884
1885			if (isArrayMember)
1886			{
1887				const vector<BasicUniform>::const_iterator elemUnif = BasicUniform::findWithName(basicUniforms, curName.c_str());
1888				if (elemUnif == basicUniforms.end())
1889					continue;
1890				unifValue = elemUnif->finalValue;
1891			}
1892			else
1893				unifValue = uniform.finalValue;
1894
1895			const VarValue apiValue = glu::isDataTypeBoolOrBVec(unifValue.type)	? getRandomBoolRepresentation(unifValue, boolApiType, rnd)
1896									: glu::isDataTypeSampler(unifValue.type)	? getSamplerUnitValue(unifValue)
1897									: unifValue;
1898
1899			valuesToAssign.push_back(glu::isDataTypeMatrix(apiValue.type) && transpose ? getTransposeMatrix(apiValue) : apiValue);
1900
1901			if (glu::isDataTypeBoolOrBVec(uniform.type))
1902				log << TestLog::Message << "// Using type " << glu::getDataTypeName(boolApiType) << " to set boolean value " << apiVarValueStr(unifValue) << " for " << curName << TestLog::EndMessage;
1903			else if (glu::isDataTypeSampler(uniform.type))
1904				log << TestLog::Message << "// Texture for the sampler uniform " << curName << " will be filled with color " << apiVarValueStr(getSamplerFillValue(uniform.finalValue)) << TestLog::EndMessage;
1905		}
1906
1907		DE_ASSERT(!valuesToAssign.empty());
1908
1909		if (glu::isDataTypeFloatOrVec(valuesToAssign[0].type))
1910		{
1911			if (assignByValue)
1912			{
1913				const float* const ptr = &valuesToAssign[0].val.floatV[0];
1914
1915				switch (typeSize)
1916				{
1917					case 1: GLU_CHECK_CALL(glUniform1f(location, ptr[0]));							break;
1918					case 2: GLU_CHECK_CALL(glUniform2f(location, ptr[0], ptr[1]));					break;
1919					case 3: GLU_CHECK_CALL(glUniform3f(location, ptr[0], ptr[1], ptr[2]));			break;
1920					case 4: GLU_CHECK_CALL(glUniform4f(location, ptr[0], ptr[1], ptr[2], ptr[3]));	break;
1921					default:
1922						DE_ASSERT(false);
1923				}
1924			}
1925			else
1926			{
1927				vector<float> buffer(valuesToAssign.size() * typeSize);
1928				for (int i = 0; i < (int)buffer.size(); i++)
1929					buffer[i] = valuesToAssign[i / typeSize].val.floatV[i % typeSize];
1930
1931				DE_STATIC_ASSERT(sizeof(GLfloat) == sizeof(buffer[0]));
1932				switch (typeSize)
1933				{
1934					case 1: GLU_CHECK_CALL(glUniform1fv(location, (GLsizei)valuesToAssign.size(), &buffer[0])); break;
1935					case 2: GLU_CHECK_CALL(glUniform2fv(location, (GLsizei)valuesToAssign.size(), &buffer[0])); break;
1936					case 3: GLU_CHECK_CALL(glUniform3fv(location, (GLsizei)valuesToAssign.size(), &buffer[0])); break;
1937					case 4: GLU_CHECK_CALL(glUniform4fv(location, (GLsizei)valuesToAssign.size(), &buffer[0])); break;
1938					default:
1939						DE_ASSERT(false);
1940				}
1941			}
1942		}
1943		else if (glu::isDataTypeMatrix(valuesToAssign[0].type))
1944		{
1945			DE_ASSERT(!assignByValue);
1946
1947			vector<float> buffer(valuesToAssign.size() * typeSize);
1948			for (int i = 0; i < (int)buffer.size(); i++)
1949				buffer[i] = valuesToAssign[i / typeSize].val.floatV[i % typeSize];
1950
1951			DE_STATIC_ASSERT(sizeof(GLfloat) == sizeof(buffer[0]));
1952			switch (uniform.type)
1953			{
1954				case glu::TYPE_FLOAT_MAT2:		GLU_CHECK_CALL(glUniformMatrix2fv	(location, (GLsizei)valuesToAssign.size(), transposeGL, &buffer[0])); break;
1955				case glu::TYPE_FLOAT_MAT3:		GLU_CHECK_CALL(glUniformMatrix3fv	(location, (GLsizei)valuesToAssign.size(), transposeGL, &buffer[0])); break;
1956				case glu::TYPE_FLOAT_MAT4:		GLU_CHECK_CALL(glUniformMatrix4fv	(location, (GLsizei)valuesToAssign.size(), transposeGL, &buffer[0])); break;
1957				case glu::TYPE_FLOAT_MAT2X3:	GLU_CHECK_CALL(glUniformMatrix2x3fv	(location, (GLsizei)valuesToAssign.size(), transposeGL, &buffer[0])); break;
1958				case glu::TYPE_FLOAT_MAT2X4:	GLU_CHECK_CALL(glUniformMatrix2x4fv	(location, (GLsizei)valuesToAssign.size(), transposeGL, &buffer[0])); break;
1959				case glu::TYPE_FLOAT_MAT3X2:	GLU_CHECK_CALL(glUniformMatrix3x2fv	(location, (GLsizei)valuesToAssign.size(), transposeGL, &buffer[0])); break;
1960				case glu::TYPE_FLOAT_MAT3X4:	GLU_CHECK_CALL(glUniformMatrix3x4fv	(location, (GLsizei)valuesToAssign.size(), transposeGL, &buffer[0])); break;
1961				case glu::TYPE_FLOAT_MAT4X2:	GLU_CHECK_CALL(glUniformMatrix4x2fv	(location, (GLsizei)valuesToAssign.size(), transposeGL, &buffer[0])); break;
1962				case glu::TYPE_FLOAT_MAT4X3:	GLU_CHECK_CALL(glUniformMatrix4x3fv	(location, (GLsizei)valuesToAssign.size(), transposeGL, &buffer[0])); break;
1963				default:
1964					DE_ASSERT(false);
1965			}
1966		}
1967		else if (glu::isDataTypeIntOrIVec(valuesToAssign[0].type))
1968		{
1969			if (assignByValue)
1970			{
1971				const deInt32* const ptr = &valuesToAssign[0].val.intV[0];
1972
1973				switch (typeSize)
1974				{
1975					case 1: GLU_CHECK_CALL(glUniform1i(location, ptr[0]));							break;
1976					case 2: GLU_CHECK_CALL(glUniform2i(location, ptr[0], ptr[1]));					break;
1977					case 3: GLU_CHECK_CALL(glUniform3i(location, ptr[0], ptr[1], ptr[2]));			break;
1978					case 4: GLU_CHECK_CALL(glUniform4i(location, ptr[0], ptr[1], ptr[2], ptr[3]));	break;
1979					default:
1980						DE_ASSERT(false);
1981				}
1982			}
1983			else
1984			{
1985				vector<deInt32> buffer(valuesToAssign.size() * typeSize);
1986				for (int i = 0; i < (int)buffer.size(); i++)
1987					buffer[i] = valuesToAssign[i / typeSize].val.intV[i % typeSize];
1988
1989				DE_STATIC_ASSERT(sizeof(GLint) == sizeof(buffer[0]));
1990				switch (typeSize)
1991				{
1992					case 1: GLU_CHECK_CALL(glUniform1iv(location, (GLsizei)valuesToAssign.size(), &buffer[0])); break;
1993					case 2: GLU_CHECK_CALL(glUniform2iv(location, (GLsizei)valuesToAssign.size(), &buffer[0])); break;
1994					case 3: GLU_CHECK_CALL(glUniform3iv(location, (GLsizei)valuesToAssign.size(), &buffer[0])); break;
1995					case 4: GLU_CHECK_CALL(glUniform4iv(location, (GLsizei)valuesToAssign.size(), &buffer[0])); break;
1996					default:
1997						DE_ASSERT(false);
1998				}
1999			}
2000		}
2001		else if (glu::isDataTypeUintOrUVec(valuesToAssign[0].type))
2002		{
2003			if (assignByValue)
2004			{
2005				const deUint32* const ptr = &valuesToAssign[0].val.uintV[0];
2006
2007				switch (typeSize)
2008				{
2009					case 1: GLU_CHECK_CALL(glUniform1ui(location, ptr[0]));							break;
2010					case 2: GLU_CHECK_CALL(glUniform2ui(location, ptr[0], ptr[1]));					break;
2011					case 3: GLU_CHECK_CALL(glUniform3ui(location, ptr[0], ptr[1], ptr[2]));			break;
2012					case 4: GLU_CHECK_CALL(glUniform4ui(location, ptr[0], ptr[1], ptr[2], ptr[3]));	break;
2013					default:
2014						DE_ASSERT(false);
2015				}
2016			}
2017			else
2018			{
2019				vector<deUint32> buffer(valuesToAssign.size() * typeSize);
2020				for (int i = 0; i < (int)buffer.size(); i++)
2021					buffer[i] = valuesToAssign[i / typeSize].val.intV[i % typeSize];
2022
2023				DE_STATIC_ASSERT(sizeof(GLuint) == sizeof(buffer[0]));
2024				switch (typeSize)
2025				{
2026					case 1: GLU_CHECK_CALL(glUniform1uiv(location, (GLsizei)valuesToAssign.size(), &buffer[0])); break;
2027					case 2: GLU_CHECK_CALL(glUniform2uiv(location, (GLsizei)valuesToAssign.size(), &buffer[0])); break;
2028					case 3: GLU_CHECK_CALL(glUniform3uiv(location, (GLsizei)valuesToAssign.size(), &buffer[0])); break;
2029					case 4: GLU_CHECK_CALL(glUniform4uiv(location, (GLsizei)valuesToAssign.size(), &buffer[0])); break;
2030					default:
2031						DE_ASSERT(false);
2032				}
2033			}
2034		}
2035		else if (glu::isDataTypeSampler(valuesToAssign[0].type))
2036		{
2037			if (assignByValue)
2038				GLU_CHECK_CALL(glUniform1i(location, uniform.finalValue.val.samplerV.unit));
2039			else
2040			{
2041				const GLint unit = uniform.finalValue.val.samplerV.unit;
2042				GLU_CHECK_CALL(glUniform1iv(location, (GLsizei)valuesToAssign.size(), &unit));
2043			}
2044		}
2045		else
2046			DE_ASSERT(false);
2047	}
2048}
2049
2050bool UniformCase::compareUniformValues (const vector<VarValue>& values, const vector<BasicUniform>& basicUniforms)
2051{
2052	TestLog&	log			= m_testCtx.getLog();
2053	bool		success		= true;
2054
2055	for (int unifNdx = 0; unifNdx < (int)basicUniforms.size(); unifNdx++)
2056	{
2057		const BasicUniform&		uniform		= basicUniforms[unifNdx];
2058		const VarValue&			unifValue	= values[unifNdx];
2059
2060		log << TestLog::Message << "// Checking uniform " << uniform.name << TestLog::EndMessage;
2061
2062		if (unifValue.type == glu::TYPE_INVALID) // This happens when glGetUniformLocation() returned -1.
2063			continue;
2064
2065		if (!apiVarValueEquals(unifValue, uniform.finalValue))
2066		{
2067			log << TestLog::Message << "// FAILURE: value obtained with glGetUniform*() for uniform " << uniform.name << " differs from value set with glUniform*()" << TestLog::EndMessage;
2068			success = false;
2069		}
2070	}
2071
2072	return success;
2073}
2074
2075bool UniformCase::renderTest (const vector<BasicUniform>& basicUniforms, const ShaderProgram& program, Random& rnd)
2076{
2077	TestLog&					log				= m_testCtx.getLog();
2078	const tcu::RenderTarget&	renderTarget	= m_context.getRenderTarget();
2079	const int					viewportW		= de::min(renderTarget.getWidth(),	MAX_RENDER_WIDTH);
2080	const int					viewportH		= de::min(renderTarget.getHeight(),	MAX_RENDER_HEIGHT);
2081	const int					viewportX		= rnd.getInt(0, renderTarget.getWidth()		- viewportW);
2082	const int					viewportY		= rnd.getInt(0, renderTarget.getHeight()	- viewportH);
2083	tcu::Surface				renderedImg		(viewportW, viewportH);
2084
2085	// Assert that no two samplers of different types have the same texture unit - this is an error in GL.
2086	for (int i = 0; i < (int)basicUniforms.size(); i++)
2087	{
2088		if (glu::isDataTypeSampler(basicUniforms[i].type))
2089		{
2090			for (int j = 0; j < i; j++)
2091			{
2092				if (glu::isDataTypeSampler(basicUniforms[j].type) && basicUniforms[i].type != basicUniforms[j].type)
2093					DE_ASSERT(basicUniforms[i].finalValue.val.samplerV.unit != basicUniforms[j].finalValue.val.samplerV.unit);
2094			}
2095		}
2096	}
2097
2098	for (int i = 0; i < (int)basicUniforms.size(); i++)
2099	{
2100		if (glu::isDataTypeSampler(basicUniforms[i].type) && std::find(m_filledTextureUnits.begin(), m_filledTextureUnits.end(), basicUniforms[i].finalValue.val.samplerV.unit) == m_filledTextureUnits.end())
2101		{
2102			log << TestLog::Message << "// Filling texture at unit " << apiVarValueStr(basicUniforms[i].finalValue) << " with color " << shaderVarValueStr(basicUniforms[i].finalValue) << TestLog::EndMessage;
2103			setupTexture(basicUniforms[i].finalValue);
2104		}
2105	}
2106
2107	GLU_CHECK_CALL(glViewport(viewportX, viewportY, viewportW, viewportH));
2108
2109	{
2110		static const float position[] =
2111		{
2112			-1.0f, -1.0f, 0.0f, 1.0f,
2113			-1.0f, +1.0f, 0.0f, 1.0f,
2114			+1.0f, -1.0f, 0.0f, 1.0f,
2115			+1.0f, +1.0f, 0.0f, 1.0f
2116		};
2117		static const deUint16 indices[] = { 0, 1, 2, 2, 1, 3 };
2118
2119		const int posLoc = glGetAttribLocation(program.getProgram(), "a_position");
2120		glEnableVertexAttribArray(posLoc);
2121		glVertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, &position[0]);
2122		GLU_CHECK_CALL(glDrawElements(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(indices), GL_UNSIGNED_SHORT, &indices[0]));
2123	}
2124
2125	glu::readPixels(m_context.getRenderContext(), viewportX, viewportY, renderedImg.getAccess());
2126
2127	int numFailedPixels = 0;
2128	for (int y = 0; y < renderedImg.getHeight(); y++)
2129	{
2130		for (int x = 0; x < renderedImg.getWidth(); x++)
2131		{
2132			if (renderedImg.getPixel(x, y) != tcu::RGBA::white())
2133				numFailedPixels += 1;
2134		}
2135	}
2136
2137	if (numFailedPixels > 0)
2138	{
2139		log << TestLog::Image("RenderedImage", "Rendered image", renderedImg);
2140		log << TestLog::Message << "FAILURE: image comparison failed, got " << numFailedPixels << " non-white pixels" << TestLog::EndMessage;
2141		return false;
2142	}
2143	else
2144	{
2145		log << TestLog::Message << "Success: got all-white pixels (all uniforms have correct values)" << TestLog::EndMessage;
2146		return true;
2147	}
2148}
2149
2150UniformCase::IterateResult UniformCase::iterate (void)
2151{
2152	Random							rnd				(deStringHash(getName()) ^ (deUint32)m_context.getTestContext().getCommandLine().getBaseSeed());
2153	TestLog&						log				= m_testCtx.getLog();
2154	vector<BasicUniform>			basicUniforms;
2155	vector<BasicUniformReportRef>	basicUniformReportsRef;
2156
2157	{
2158		int samplerUnitCounter = 0;
2159		for (int i = 0; i < (int)m_uniformCollection->getNumUniforms(); i++)
2160			generateBasicUniforms(basicUniforms, basicUniformReportsRef, m_uniformCollection->getUniform(i).type, m_uniformCollection->getUniform(i).name.c_str(), true, samplerUnitCounter, rnd);
2161	}
2162
2163	const string					vertexSource	= generateVertexSource(basicUniforms);
2164	const string					fragmentSource	= generateFragmentSource(basicUniforms);
2165	const ShaderProgram				program			(m_context.getRenderContext(), glu::makeVtxFragSources(vertexSource, fragmentSource));
2166
2167	log << program;
2168
2169	if (!program.isOk())
2170	{
2171		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Compile failed");
2172		return STOP;
2173	}
2174
2175	GLU_CHECK_CALL(glUseProgram(program.getProgram()));
2176
2177	const bool success = test(basicUniforms, basicUniformReportsRef, program, rnd);
2178	m_testCtx.setTestResult(success ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
2179							success ? "Passed"				: "Failed");
2180
2181	return STOP;
2182}
2183
2184class UniformInfoQueryCase : public UniformCase
2185{
2186public:
2187	enum CaseType
2188	{
2189		CASETYPE_UNIFORM = 0,			//!< Check info returned by glGetActiveUniform().
2190		CASETYPE_INDICES_UNIFORMSIV,	//!< Check info returned by glGetUniformIndices() + glGetActiveUniformsiv().
2191		CASETYPE_CONSISTENCY,			//!< Query info with both above methods, and check consistency.
2192
2193		CASETYPE_LAST
2194	};
2195
2196						UniformInfoQueryCase	(Context& context, const char* name, const char* description, CaseShaderType shaderType, const SharedPtr<const UniformCollection>& uniformCollection, CaseType caseType, deUint32 additionalFeatures = 0);
2197	bool				test					(const vector<BasicUniform>& basicUniforms, const vector<BasicUniformReportRef>& basicUniformReportsRef, const ShaderProgram& program, Random& rnd);
2198
2199	static const char*	getCaseTypeName			(CaseType caseType);
2200	static const char*	getCaseTypeDescription	(CaseType caseType);
2201
2202private:
2203	const CaseType		m_caseType;
2204};
2205
2206const char* UniformInfoQueryCase::getCaseTypeName (const CaseType caseType)
2207{
2208	switch (caseType)
2209	{
2210		case CASETYPE_UNIFORM:				return "active_uniform";
2211		case CASETYPE_INDICES_UNIFORMSIV:	return "indices_active_uniformsiv";
2212		case CASETYPE_CONSISTENCY:			return "consistency";
2213		default:
2214			DE_ASSERT(false);
2215			return DE_NULL;
2216	}
2217}
2218
2219const char* UniformInfoQueryCase::getCaseTypeDescription (const CaseType caseType)
2220{
2221	switch (caseType)
2222	{
2223		case CASETYPE_UNIFORM:				return "Test glGetActiveUniform()";
2224		case CASETYPE_INDICES_UNIFORMSIV:	return "Test glGetUniformIndices() along with glGetActiveUniformsiv()";
2225		case CASETYPE_CONSISTENCY:			return "Check consistency between results from glGetActiveUniform() and glGetUniformIndices() + glGetActiveUniformsiv()";
2226		default:
2227			DE_ASSERT(false);
2228			return DE_NULL;
2229	}
2230}
2231
2232UniformInfoQueryCase::UniformInfoQueryCase (Context& context, const char* const name, const char* const description, const CaseShaderType shaderType, const SharedPtr<const UniformCollection>& uniformCollection, const CaseType caseType, const deUint32 additionalFeatures)
2233	: UniformCase	(context, name, description, shaderType, uniformCollection, additionalFeatures)
2234	, m_caseType	(caseType)
2235{
2236}
2237
2238bool UniformInfoQueryCase::test (const vector<BasicUniform>& basicUniforms, const vector<BasicUniformReportRef>& basicUniformReportsRef, const ShaderProgram& program, Random& rnd)
2239{
2240	DE_UNREF(basicUniforms);
2241	DE_UNREF(rnd);
2242
2243	const deUint32					programGL	= program.getProgram();
2244	TestLog&						log			= m_testCtx.getLog();
2245	vector<BasicUniformReportGL>	basicUniformReportsUniform;
2246	vector<BasicUniformReportGL>	basicUniformReportsUniformsiv;
2247
2248	if (m_caseType == CASETYPE_UNIFORM || m_caseType == CASETYPE_CONSISTENCY)
2249	{
2250		bool success = false;
2251
2252		{
2253			const ScopedLogSection section(log, "InfoGetActiveUniform", "Uniform information queries with glGetActiveUniform()");
2254			success = getActiveUniforms(basicUniformReportsUniform, basicUniformReportsRef, programGL);
2255		}
2256
2257		if (!success)
2258		{
2259			if (m_caseType == CASETYPE_UNIFORM)
2260				return false;
2261			else
2262			{
2263				DE_ASSERT(m_caseType == CASETYPE_CONSISTENCY);
2264				log << TestLog::Message << "// Note: this is a consistency case, so ignoring above failure(s)" << TestLog::EndMessage;
2265			}
2266		}
2267	}
2268
2269	if (m_caseType == CASETYPE_INDICES_UNIFORMSIV || m_caseType == CASETYPE_CONSISTENCY)
2270	{
2271		bool success = false;
2272
2273		{
2274			const ScopedLogSection section(log, "InfoGetActiveUniformsiv", "Uniform information queries with glGetUniformIndices() and glGetActiveUniformsiv()");
2275			success = getActiveUniformsiv(basicUniformReportsUniformsiv, basicUniformReportsRef, programGL);
2276		}
2277
2278		if (!success)
2279		{
2280			if (m_caseType == CASETYPE_INDICES_UNIFORMSIV)
2281				return false;
2282			else
2283			{
2284				DE_ASSERT(m_caseType == CASETYPE_CONSISTENCY);
2285				log << TestLog::Message << "// Note: this is a consistency case, so ignoring above failure(s)" << TestLog::EndMessage;
2286			}
2287		}
2288	}
2289
2290	if (m_caseType == CASETYPE_CONSISTENCY)
2291	{
2292		bool success = false;
2293
2294		{
2295			const ScopedLogSection section(log, "CompareUniformVsUniformsiv", "Comparison of results from glGetActiveUniform() and glGetActiveUniformsiv()");
2296			success = uniformVsUniformsivComparison(basicUniformReportsUniform, basicUniformReportsUniformsiv);
2297		}
2298
2299		if (!success)
2300			return false;
2301	}
2302
2303	return true;
2304}
2305
2306class UniformValueCase : public UniformCase
2307{
2308public:
2309	enum ValueToCheck
2310	{
2311		VALUETOCHECK_INITIAL = 0,		//!< Verify the initial values of the uniforms (i.e. check that they're zero).
2312		VALUETOCHECK_ASSIGNED,			//!< Assign values to uniforms with glUniform*(), and check those.
2313
2314		VALUETOCHECK_LAST
2315	};
2316	enum CheckMethod
2317	{
2318		CHECKMETHOD_GET_UNIFORM = 0,	//!< Check values with glGetUniform*().
2319		CHECKMETHOD_RENDER,				//!< Check values by rendering with the value-checking shader.
2320
2321		CHECKMETHOD_LAST
2322	};
2323	enum AssignMethod
2324	{
2325		ASSIGNMETHOD_POINTER = 0,
2326		ASSIGNMETHOD_VALUE,
2327
2328		ASSIGNMETHOD_LAST
2329	};
2330
2331						UniformValueCase			(Context&									context,
2332													 const char*								name,
2333													 const char*								description,
2334													 CaseShaderType								shaderType,
2335													 const SharedPtr<const UniformCollection>&	uniformCollection,
2336													 ValueToCheck								valueToCheck,
2337													 CheckMethod								checkMethod,
2338													 AssignMethod								assignMethod,
2339													 deUint32									additionalFeatures = 0);
2340
2341	bool				test						(const vector<BasicUniform>& basicUniforms, const vector<BasicUniformReportRef>& basicUniformReportsRef, const ShaderProgram& program, Random& rnd);
2342
2343	static const char*	getValueToCheckName			(ValueToCheck valueToCheck);
2344	static const char*	getValueToCheckDescription	(ValueToCheck valueToCheck);
2345	static const char*	getCheckMethodName			(CheckMethod checkMethod);
2346	static const char*	getCheckMethodDescription	(CheckMethod checkMethod);
2347	static const char*	getAssignMethodName			(AssignMethod checkMethod);
2348	static const char*	getAssignMethodDescription	(AssignMethod checkMethod);
2349
2350private:
2351	const ValueToCheck	m_valueToCheck;
2352	const CheckMethod	m_checkMethod;
2353};
2354
2355const char* UniformValueCase::getValueToCheckName (const ValueToCheck valueToCheck)
2356{
2357	switch (valueToCheck)
2358	{
2359		case VALUETOCHECK_INITIAL:	return "initial";
2360		case VALUETOCHECK_ASSIGNED:	return "assigned";
2361		default: DE_ASSERT(false);	return DE_NULL;
2362	}
2363}
2364
2365const char* UniformValueCase::getValueToCheckDescription (const ValueToCheck valueToCheck)
2366{
2367	switch (valueToCheck)
2368{
2369		case VALUETOCHECK_INITIAL:	return "Check initial uniform values (zeros)";
2370		case VALUETOCHECK_ASSIGNED:	return "Check assigned uniform values";
2371		default: DE_ASSERT(false);	return DE_NULL;
2372	}
2373}
2374
2375const char* UniformValueCase::getCheckMethodName (const CheckMethod checkMethod)
2376{
2377	switch (checkMethod)
2378	{
2379		case CHECKMETHOD_GET_UNIFORM:	return "get_uniform";
2380		case CHECKMETHOD_RENDER:		return "render";
2381		default: DE_ASSERT(false);		return DE_NULL;
2382	}
2383}
2384
2385const char* UniformValueCase::getCheckMethodDescription (const CheckMethod checkMethod)
2386{
2387	switch (checkMethod)
2388	{
2389		case CHECKMETHOD_GET_UNIFORM:	return "Verify values with glGetUniform*()";
2390		case CHECKMETHOD_RENDER:		return "Verify values by rendering";
2391		default: DE_ASSERT(false);		return DE_NULL;
2392	}
2393}
2394
2395const char* UniformValueCase::getAssignMethodName (const AssignMethod assignMethod)
2396{
2397	switch (assignMethod)
2398	{
2399		case ASSIGNMETHOD_POINTER:		return "by_pointer";
2400		case ASSIGNMETHOD_VALUE:		return "by_value";
2401		default: DE_ASSERT(false);		return DE_NULL;
2402	}
2403}
2404
2405const char* UniformValueCase::getAssignMethodDescription (const AssignMethod assignMethod)
2406{
2407	switch (assignMethod)
2408	{
2409		case ASSIGNMETHOD_POINTER:		return "Assign values by-pointer";
2410		case ASSIGNMETHOD_VALUE:		return "Assign values by-value";
2411		default: DE_ASSERT(false);		return DE_NULL;
2412	}
2413}
2414
2415UniformValueCase::UniformValueCase (Context&									context,
2416									const char* const							name,
2417									const char* const							description,
2418									const CaseShaderType						shaderType,
2419									const SharedPtr<const UniformCollection>&	uniformCollection,
2420									const ValueToCheck							valueToCheck,
2421									const CheckMethod							checkMethod,
2422									const AssignMethod							assignMethod,
2423									const deUint32								additionalFeatures)
2424	: UniformCase		(context, name, description, shaderType, uniformCollection,
2425						 (valueToCheck == VALUETOCHECK_INITIAL ? FEATURE_UNIFORMVALUE_ZERO : 0) | (assignMethod == ASSIGNMETHOD_VALUE ? FEATURE_UNIFORMFUNC_VALUE : 0) | additionalFeatures)
2426	, m_valueToCheck	(valueToCheck)
2427	, m_checkMethod		(checkMethod)
2428{
2429	DE_ASSERT(!(assignMethod == ASSIGNMETHOD_LAST && valueToCheck == VALUETOCHECK_ASSIGNED));
2430}
2431
2432bool UniformValueCase::test (const vector<BasicUniform>& basicUniforms, const vector<BasicUniformReportRef>& basicUniformReportsRef, const ShaderProgram& program, Random& rnd)
2433{
2434	DE_UNREF(basicUniformReportsRef);
2435
2436	const deUint32	programGL	= program.getProgram();
2437	TestLog&		log			= m_testCtx.getLog();
2438
2439	if (m_valueToCheck == VALUETOCHECK_ASSIGNED)
2440	{
2441		const ScopedLogSection section(log, "UniformAssign", "Uniform value assignments");
2442		assignUniforms(basicUniforms, programGL, rnd);
2443	}
2444	else
2445		DE_ASSERT(m_valueToCheck == VALUETOCHECK_INITIAL);
2446
2447	if (m_checkMethod == CHECKMETHOD_GET_UNIFORM)
2448	{
2449		vector<VarValue> values;
2450
2451		{
2452			const ScopedLogSection section(log, "GetUniforms", "Uniform value query");
2453			const bool success = getUniforms(values, basicUniforms, program.getProgram());
2454
2455			if (!success)
2456				return false;
2457		}
2458
2459		if (m_valueToCheck == VALUETOCHECK_ASSIGNED)
2460		{
2461			const ScopedLogSection section(log, "ValueCheck", "Verify that the reported values match the assigned values");
2462			const bool success = compareUniformValues(values, basicUniforms);
2463
2464			if (!success)
2465				return false;
2466		}
2467		else
2468		{
2469			DE_ASSERT(m_valueToCheck == VALUETOCHECK_INITIAL);
2470
2471			const ScopedLogSection section(log, "ValueCheck", "Verify that the uniforms have correct initial values (zeros)");
2472			const bool success = checkUniformDefaultValues(values, basicUniforms);
2473
2474			if (!success)
2475				return false;
2476		}
2477	}
2478	else
2479	{
2480		DE_ASSERT(m_checkMethod == CHECKMETHOD_RENDER);
2481
2482		const ScopedLogSection section(log, "RenderTest", "Render test");
2483		const bool success = renderTest(basicUniforms, program, rnd);
2484
2485		if (!success)
2486			return false;
2487	}
2488
2489	return true;
2490}
2491
2492class RandomUniformCase : public UniformCase
2493{
2494public:
2495						RandomUniformCase		(Context& m_context, const char* name, const char* description, deUint32 seed);
2496
2497	bool				test					(const vector<BasicUniform>& basicUniforms, const vector<BasicUniformReportRef>& basicUniformReportsRef, const ShaderProgram& program, Random& rnd);
2498};
2499
2500RandomUniformCase::RandomUniformCase (Context& context, const char* const name, const char* const description, const deUint32 seed)
2501	: UniformCase (context, name, description, seed ^ (deUint32)context.getTestContext().getCommandLine().getBaseSeed())
2502{
2503}
2504
2505bool RandomUniformCase::test (const vector<BasicUniform>& basicUniforms, const vector<BasicUniformReportRef>& basicUniformReportsRef, const ShaderProgram& program, Random& rnd)
2506{
2507	// \note Different sampler types may not be bound to same unit when rendering.
2508	const bool		renderingPossible						= (m_features & FEATURE_UNIFORMVALUE_ZERO) == 0 || !m_uniformCollection->containsSeveralSamplerTypes();
2509
2510	bool			performGetActiveUniforms				= rnd.getBool();
2511	const bool		performGetActiveUniformsiv				= rnd.getBool();
2512	const bool		performUniformVsUniformsivComparison	= performGetActiveUniforms && performGetActiveUniformsiv && rnd.getBool();
2513	const bool		performGetUniforms						= rnd.getBool();
2514	const bool		performCheckUniformDefaultValues		= performGetUniforms && rnd.getBool();
2515	const bool		performAssignUniforms					= rnd.getBool();
2516	const bool		performCompareUniformValues				= performGetUniforms && performAssignUniforms && rnd.getBool();
2517	const bool		performRenderTest						= renderingPossible && performAssignUniforms && rnd.getBool();
2518	const deUint32	programGL								= program.getProgram();
2519	TestLog&		log										= m_testCtx.getLog();
2520
2521	if (!(performGetActiveUniforms || performGetActiveUniformsiv || performUniformVsUniformsivComparison || performGetUniforms || performCheckUniformDefaultValues || performAssignUniforms || performCompareUniformValues || performRenderTest))
2522		performGetActiveUniforms = true; // Do something at least.
2523
2524#define PERFORM_AND_CHECK(CALL, SECTION_NAME, SECTION_DESCRIPTION)						\
2525	do																					\
2526	{																					\
2527		const ScopedLogSection section(log, (SECTION_NAME), (SECTION_DESCRIPTION));		\
2528		const bool success = (CALL);													\
2529		if (!success)																	\
2530			return false;																\
2531	} while (false)
2532
2533	{
2534		vector<BasicUniformReportGL> reportsUniform;
2535		vector<BasicUniformReportGL> reportsUniformsiv;
2536
2537		if (performGetActiveUniforms)
2538			PERFORM_AND_CHECK(getActiveUniforms(reportsUniform, basicUniformReportsRef, programGL), "InfoGetActiveUniform", "Uniform information queries with glGetActiveUniform()");
2539		if (performGetActiveUniformsiv)
2540			PERFORM_AND_CHECK(getActiveUniformsiv(reportsUniformsiv, basicUniformReportsRef, programGL), "InfoGetActiveUniformsiv", "Uniform information queries with glGetIndices() and glGetActiveUniformsiv()");
2541		if (performUniformVsUniformsivComparison)
2542			PERFORM_AND_CHECK(uniformVsUniformsivComparison(reportsUniform, reportsUniformsiv), "CompareUniformVsUniformsiv", "Comparison of results from glGetActiveUniform() and glGetActiveUniformsiv()");
2543	}
2544
2545	{
2546		vector<VarValue> uniformDefaultValues;
2547
2548		if (performGetUniforms)
2549			PERFORM_AND_CHECK(getUniforms(uniformDefaultValues, basicUniforms, programGL), "GetUniformDefaults", "Uniform default value query");
2550		if (performCheckUniformDefaultValues)
2551			PERFORM_AND_CHECK(checkUniformDefaultValues(uniformDefaultValues, basicUniforms), "DefaultValueCheck", "Verify that the uniforms have correct initial values (zeros)");
2552	}
2553
2554	{
2555		vector<VarValue> uniformValues;
2556
2557		if (performAssignUniforms)
2558		{
2559			const ScopedLogSection section(log, "UniformAssign", "Uniform value assignments");
2560			assignUniforms(basicUniforms, programGL, rnd);
2561		}
2562		if (performCompareUniformValues)
2563		{
2564			PERFORM_AND_CHECK(getUniforms(uniformValues, basicUniforms, programGL), "GetUniforms", "Uniform value query");
2565			PERFORM_AND_CHECK(compareUniformValues(uniformValues, basicUniforms), "ValueCheck", "Verify that the reported values match the assigned values");
2566		}
2567	}
2568
2569	if (performRenderTest)
2570		PERFORM_AND_CHECK(renderTest(basicUniforms, program, rnd), "RenderTest", "Render test");
2571
2572#undef PERFORM_AND_CHECK
2573
2574	return true;
2575}
2576
2577UniformApiTests::UniformApiTests (Context& context)
2578	: TestCaseGroup(context, "uniform_api", "Uniform API Tests")
2579{
2580}
2581
2582UniformApiTests::~UniformApiTests (void)
2583{
2584}
2585
2586namespace
2587{
2588
2589// \note Although this is only used in UniformApiTest::init, it needs to be defined here as it's used as a template argument.
2590struct UniformCollectionCase
2591{
2592	string								namePrefix;
2593	SharedPtr<const UniformCollection>	uniformCollection;
2594
2595	UniformCollectionCase (const char* const name, const UniformCollection* uniformCollection_)
2596		: namePrefix			(name ? name + string("_") : "")
2597		, uniformCollection		(uniformCollection_)
2598	{
2599	}
2600};
2601
2602} // anonymous
2603
2604void UniformApiTests::init (void)
2605{
2606	// Generate sets of UniformCollections that are used by several cases.
2607
2608	enum
2609	{
2610		UNIFORMCOLLECTIONS_BASIC = 0,
2611		UNIFORMCOLLECTIONS_BASIC_ARRAY,
2612		UNIFORMCOLLECTIONS_BASIC_STRUCT,
2613		UNIFORMCOLLECTIONS_STRUCT_IN_ARRAY,
2614		UNIFORMCOLLECTIONS_ARRAY_IN_STRUCT,
2615		UNIFORMCOLLECTIONS_NESTED_STRUCTS_ARRAYS,
2616		UNIFORMCOLLECTIONS_MULTIPLE_BASIC,
2617		UNIFORMCOLLECTIONS_MULTIPLE_BASIC_ARRAY,
2618		UNIFORMCOLLECTIONS_MULTIPLE_NESTED_STRUCTS_ARRAYS,
2619
2620		UNIFORMCOLLECTIONS_LAST
2621	};
2622
2623	struct UniformCollectionGroup
2624	{
2625		string							name;
2626		vector<UniformCollectionCase>	cases;
2627	} defaultUniformCollections[UNIFORMCOLLECTIONS_LAST];
2628
2629	defaultUniformCollections[UNIFORMCOLLECTIONS_BASIC].name							= "basic";
2630	defaultUniformCollections[UNIFORMCOLLECTIONS_BASIC_ARRAY].name						= "basic_array";
2631	defaultUniformCollections[UNIFORMCOLLECTIONS_BASIC_STRUCT].name						= "basic_struct";
2632	defaultUniformCollections[UNIFORMCOLLECTIONS_STRUCT_IN_ARRAY].name					= "struct_in_array";
2633	defaultUniformCollections[UNIFORMCOLLECTIONS_ARRAY_IN_STRUCT].name					= "array_in_struct";
2634	defaultUniformCollections[UNIFORMCOLLECTIONS_NESTED_STRUCTS_ARRAYS].name			= "nested_structs_arrays";
2635	defaultUniformCollections[UNIFORMCOLLECTIONS_MULTIPLE_BASIC].name					= "multiple_basic";
2636	defaultUniformCollections[UNIFORMCOLLECTIONS_MULTIPLE_BASIC_ARRAY].name				= "multiple_basic_array";
2637	defaultUniformCollections[UNIFORMCOLLECTIONS_MULTIPLE_NESTED_STRUCTS_ARRAYS].name	= "multiple_nested_structs_arrays";
2638
2639	for (int dataTypeNdx = 0; dataTypeNdx < DE_LENGTH_OF_ARRAY(s_testDataTypes); dataTypeNdx++)
2640	{
2641		const glu::DataType		dataType	= s_testDataTypes[dataTypeNdx];
2642		const char* const		typeName	= glu::getDataTypeName(dataType);
2643
2644		defaultUniformCollections[UNIFORMCOLLECTIONS_BASIC].cases.push_back(UniformCollectionCase(typeName, UniformCollection::basic(dataType)));
2645
2646		if (glu::isDataTypeScalar(dataType)													||
2647			(glu::isDataTypeVector(dataType) && glu::getDataTypeScalarSize(dataType) == 4)	||
2648			dataType == glu::TYPE_FLOAT_MAT4												||
2649			dataType == glu::TYPE_SAMPLER_2D)
2650			defaultUniformCollections[UNIFORMCOLLECTIONS_BASIC_ARRAY].cases.push_back(UniformCollectionCase(typeName, UniformCollection::basicArray(dataType)));
2651
2652		if (glu::isDataTypeScalar(dataType)		||
2653			dataType == glu::TYPE_FLOAT_MAT4	||
2654			dataType == glu::TYPE_SAMPLER_2D)
2655		{
2656			const glu::DataType		secondDataType	= glu::isDataTypeScalar(dataType)	? glu::getDataTypeVector(dataType, 4)
2657													: dataType == glu::TYPE_FLOAT_MAT4	? glu::TYPE_FLOAT_MAT2
2658													: dataType == glu::TYPE_SAMPLER_2D	? glu::TYPE_SAMPLER_CUBE
2659													: glu::TYPE_LAST;
2660			DE_ASSERT(secondDataType != glu::TYPE_LAST);
2661			const char* const		secondTypeName	= glu::getDataTypeName(secondDataType);
2662			const string			name			= string("") + typeName + "_" + secondTypeName;
2663
2664			defaultUniformCollections[UNIFORMCOLLECTIONS_BASIC_STRUCT].cases.push_back			(UniformCollectionCase(name.c_str(), UniformCollection::basicStruct(dataType, secondDataType, false)));
2665			defaultUniformCollections[UNIFORMCOLLECTIONS_ARRAY_IN_STRUCT].cases.push_back		(UniformCollectionCase(name.c_str(), UniformCollection::basicStruct(dataType, secondDataType, true)));
2666			defaultUniformCollections[UNIFORMCOLLECTIONS_STRUCT_IN_ARRAY].cases.push_back		(UniformCollectionCase(name.c_str(), UniformCollection::structInArray(dataType, secondDataType, false)));
2667			defaultUniformCollections[UNIFORMCOLLECTIONS_NESTED_STRUCTS_ARRAYS].cases.push_back	(UniformCollectionCase(name.c_str(), UniformCollection::nestedArraysStructs(dataType, secondDataType)));
2668		}
2669	}
2670	defaultUniformCollections[UNIFORMCOLLECTIONS_MULTIPLE_BASIC].cases.push_back					(UniformCollectionCase(DE_NULL, UniformCollection::multipleBasic()));
2671	defaultUniformCollections[UNIFORMCOLLECTIONS_MULTIPLE_BASIC_ARRAY].cases.push_back				(UniformCollectionCase(DE_NULL, UniformCollection::multipleBasicArray()));
2672	defaultUniformCollections[UNIFORMCOLLECTIONS_MULTIPLE_NESTED_STRUCTS_ARRAYS].cases.push_back	(UniformCollectionCase(DE_NULL, UniformCollection::multipleNestedArraysStructs()));
2673
2674	// Info-query cases (check info returned by e.g. glGetActiveUniforms()).
2675
2676	{
2677		TestCaseGroup* const infoQueryGroup = new TestCaseGroup(m_context, "info_query", "Test uniform info querying functions");
2678		addChild(infoQueryGroup);
2679		for (int caseTypeI = 0; caseTypeI < (int)UniformInfoQueryCase::CASETYPE_LAST; caseTypeI++)
2680		{
2681			const UniformInfoQueryCase::CaseType	caseType		= (UniformInfoQueryCase::CaseType)caseTypeI;
2682			TestCaseGroup* const					caseTypeGroup	= new TestCaseGroup(m_context, UniformInfoQueryCase::getCaseTypeName(caseType), UniformInfoQueryCase::getCaseTypeDescription(caseType));
2683			infoQueryGroup->addChild(caseTypeGroup);
2684
2685			for (int collectionGroupNdx = 0; collectionGroupNdx < (int)UNIFORMCOLLECTIONS_LAST; collectionGroupNdx++)
2686			{
2687				const int numArrayFirstElemNameCases = caseType == UniformInfoQueryCase::CASETYPE_INDICES_UNIFORMSIV && collectionGroupNdx == UNIFORMCOLLECTIONS_BASIC_ARRAY ? 2 : 1;
2688
2689				for (int referToFirstArrayElemWithoutIndexI = 0; referToFirstArrayElemWithoutIndexI < numArrayFirstElemNameCases; referToFirstArrayElemWithoutIndexI++)
2690				{
2691					const UniformCollectionGroup&	collectionGroup			= defaultUniformCollections[collectionGroupNdx];
2692					const string					collectionGroupName		= collectionGroup.name + (referToFirstArrayElemWithoutIndexI == 0 ? "" : "_first_elem_without_brackets");
2693					TestCaseGroup* const			collectionTestGroup		= new TestCaseGroup(m_context, collectionGroupName.c_str(), "");
2694					caseTypeGroup->addChild(collectionTestGroup);
2695
2696					for (int collectionNdx = 0; collectionNdx < (int)collectionGroup.cases.size(); collectionNdx++)
2697					{
2698						const UniformCollectionCase& collectionCase = collectionGroup.cases[collectionNdx];
2699
2700						for (int shaderType = 0; shaderType < (int)CASESHADERTYPE_LAST; shaderType++)
2701						{
2702							const string								name				= collectionCase.namePrefix + getCaseShaderTypeName((CaseShaderType)shaderType);
2703							const SharedPtr<const UniformCollection>&	uniformCollection	= collectionCase.uniformCollection;
2704
2705							collectionTestGroup->addChild(new UniformInfoQueryCase(m_context, name.c_str(), "", (CaseShaderType)shaderType, uniformCollection, (UniformInfoQueryCase::CaseType)caseType,
2706																				   referToFirstArrayElemWithoutIndexI == 0 ? 0 : UniformCase::FEATURE_ARRAY_FIRST_ELEM_NAME_NO_INDEX));
2707						}
2708					}
2709				}
2710			}
2711
2712			// Info-querying cases when unused uniforms are present.
2713
2714			{
2715				TestCaseGroup* const unusedUniformsGroup = new TestCaseGroup(m_context, "unused_uniforms", "Test with unused uniforms");
2716				caseTypeGroup->addChild(unusedUniformsGroup);
2717
2718				const UniformCollectionGroup& collectionGroup = defaultUniformCollections[UNIFORMCOLLECTIONS_ARRAY_IN_STRUCT];
2719
2720				for (int collectionNdx = 0; collectionNdx < (int)collectionGroup.cases.size(); collectionNdx++)
2721				{
2722					const UniformCollectionCase&				collectionCase		= collectionGroup.cases[collectionNdx];
2723					const string								collName			= collectionCase.namePrefix;
2724					const SharedPtr<const UniformCollection>&	uniformCollection	= collectionCase.uniformCollection;
2725
2726					for (int shaderType = 0; shaderType < (int)CASESHADERTYPE_LAST; shaderType++)
2727					{
2728						const string name = collName + getCaseShaderTypeName((CaseShaderType)shaderType);
2729						unusedUniformsGroup->addChild(new UniformInfoQueryCase(m_context, name.c_str(), "", (CaseShaderType)shaderType, uniformCollection, (UniformInfoQueryCase::CaseType)caseType,
2730																			   UniformCase::FEATURE_UNIFORMUSAGE_EVERY_OTHER | UniformCase::FEATURE_ARRAYUSAGE_ONLY_MIDDLE_INDEX));
2731					}
2732				}
2733			}
2734		}
2735	}
2736
2737	// Cases testing uniform values.
2738
2739	{
2740		TestCaseGroup* const valueGroup = new TestCaseGroup(m_context, "value", "Uniform value tests");
2741		addChild(valueGroup);
2742
2743		// Cases checking uniforms' initial values (all must be zeros), with glGetUniform*() or by rendering.
2744
2745		{
2746			TestCaseGroup* const initialValuesGroup = new TestCaseGroup(m_context,
2747																		UniformValueCase::getValueToCheckName(UniformValueCase::VALUETOCHECK_INITIAL),
2748																		UniformValueCase::getValueToCheckDescription(UniformValueCase::VALUETOCHECK_INITIAL));
2749			valueGroup->addChild(initialValuesGroup);
2750
2751			for (int checkMethodI = 0; checkMethodI < (int)UniformValueCase::CHECKMETHOD_LAST; checkMethodI++)
2752			{
2753				const UniformValueCase::CheckMethod		checkMethod			= (UniformValueCase::CheckMethod)checkMethodI;
2754				TestCaseGroup* const					checkMethodGroup	= new TestCaseGroup(m_context, UniformValueCase::getCheckMethodName(checkMethod), UniformValueCase::getCheckMethodDescription(checkMethod));
2755				initialValuesGroup->addChild(checkMethodGroup);
2756
2757				for (int collectionGroupNdx = 0; collectionGroupNdx < (int)UNIFORMCOLLECTIONS_LAST; collectionGroupNdx++)
2758				{
2759					const UniformCollectionGroup&	collectionGroup		= defaultUniformCollections[collectionGroupNdx];
2760					TestCaseGroup* const			collectionTestGroup	= new TestCaseGroup(m_context, collectionGroup.name.c_str(), "");
2761					checkMethodGroup->addChild(collectionTestGroup);
2762
2763					for (int collectionNdx = 0; collectionNdx < (int)collectionGroup.cases.size(); collectionNdx++)
2764					{
2765						const UniformCollectionCase&				collectionCase		= collectionGroup.cases[collectionNdx];
2766						const string								collName			= collectionCase.namePrefix;
2767						const SharedPtr<const UniformCollection>&	uniformCollection	= collectionCase.uniformCollection;
2768						const bool									containsBooleans	= uniformCollection->containsMatchingBasicType(glu::isDataTypeBoolOrBVec);
2769						const bool									varyBoolApiType		= checkMethod == UniformValueCase::CHECKMETHOD_GET_UNIFORM && containsBooleans &&
2770																						  (collectionGroupNdx == UNIFORMCOLLECTIONS_BASIC || collectionGroupNdx == UNIFORMCOLLECTIONS_BASIC_ARRAY);
2771						const int									numBoolVariations	= varyBoolApiType ? 3 : 1;
2772
2773						if (checkMethod == UniformValueCase::CHECKMETHOD_RENDER && uniformCollection->containsSeveralSamplerTypes())
2774							continue; // \note Samplers' initial API values (i.e. their texture units) are 0, and no two samplers of different types shall have same unit when rendering.
2775
2776						for (int booleanTypeI = 0; booleanTypeI < numBoolVariations; booleanTypeI++)
2777						{
2778							const deUint32		booleanTypeFeat	= booleanTypeI == 1 ? UniformCase::FEATURE_BOOLEANAPITYPE_INT
2779																: booleanTypeI == 2 ? UniformCase::FEATURE_BOOLEANAPITYPE_UINT
2780																: 0;
2781							const char* const	booleanTypeName	= booleanTypeI == 1 ? "int"
2782																: booleanTypeI == 2 ? "uint"
2783																: "float";
2784							const string		nameWithApiType	= varyBoolApiType ? collName + "api_" + booleanTypeName + "_" : collName;
2785
2786							for (int shaderType = 0; shaderType < (int)CASESHADERTYPE_LAST; shaderType++)
2787							{
2788								const string name = nameWithApiType + getCaseShaderTypeName((CaseShaderType)shaderType);
2789								collectionTestGroup->addChild(new UniformValueCase(m_context, name.c_str(), "", (CaseShaderType)shaderType, uniformCollection,
2790																				   UniformValueCase::VALUETOCHECK_INITIAL, checkMethod, UniformValueCase::ASSIGNMETHOD_LAST, booleanTypeFeat));
2791							}
2792						}
2793					}
2794				}
2795			}
2796		}
2797
2798		// Cases that first assign values to each uniform, then check the values with glGetUniform*() or by rendering.
2799
2800		{
2801			TestCaseGroup* const assignedValuesGroup = new TestCaseGroup(m_context,
2802																		UniformValueCase::getValueToCheckName(UniformValueCase::VALUETOCHECK_ASSIGNED),
2803																		UniformValueCase::getValueToCheckDescription(UniformValueCase::VALUETOCHECK_ASSIGNED));
2804			valueGroup->addChild(assignedValuesGroup);
2805
2806			for (int assignMethodI = 0; assignMethodI < (int)UniformValueCase::ASSIGNMETHOD_LAST; assignMethodI++)
2807			{
2808				const UniformValueCase::AssignMethod	assignMethod		= (UniformValueCase::AssignMethod)assignMethodI;
2809				TestCaseGroup* const					assignMethodGroup	= new TestCaseGroup(m_context, UniformValueCase::getAssignMethodName(assignMethod), UniformValueCase::getAssignMethodDescription(assignMethod));
2810				assignedValuesGroup->addChild(assignMethodGroup);
2811
2812				for (int checkMethodI = 0; checkMethodI < (int)UniformValueCase::CHECKMETHOD_LAST; checkMethodI++)
2813				{
2814					const UniformValueCase::CheckMethod		checkMethod			= (UniformValueCase::CheckMethod)checkMethodI;
2815					TestCaseGroup* const					checkMethodGroup	= new TestCaseGroup(m_context, UniformValueCase::getCheckMethodName(checkMethod), UniformValueCase::getCheckMethodDescription(checkMethod));
2816					assignMethodGroup->addChild(checkMethodGroup);
2817
2818					for (int collectionGroupNdx = 0; collectionGroupNdx < (int)UNIFORMCOLLECTIONS_LAST; collectionGroupNdx++)
2819					{
2820						const int numArrayFirstElemNameCases = checkMethod == UniformValueCase::CHECKMETHOD_GET_UNIFORM && collectionGroupNdx == UNIFORMCOLLECTIONS_BASIC_ARRAY ? 2 : 1;
2821
2822						for (int referToFirstArrayElemWithoutIndexI = 0; referToFirstArrayElemWithoutIndexI < numArrayFirstElemNameCases; referToFirstArrayElemWithoutIndexI++)
2823						{
2824							const UniformCollectionGroup&	collectionGroup			= defaultUniformCollections[collectionGroupNdx];
2825							const string					collectionGroupName		= collectionGroup.name + (referToFirstArrayElemWithoutIndexI == 0 ? "" : "_first_elem_without_brackets");
2826							TestCaseGroup*					collectionTestGroup		= DE_NULL;
2827
2828							for (int collectionNdx = 0; collectionNdx < (int)collectionGroup.cases.size(); collectionNdx++)
2829							{
2830								const UniformCollectionCase&				collectionCase		= collectionGroup.cases[collectionNdx];
2831								const string								collName			= collectionCase.namePrefix;
2832								const SharedPtr<const UniformCollection>&	uniformCollection	= collectionCase.uniformCollection;
2833								const bool									containsBooleans	= uniformCollection->containsMatchingBasicType(glu::isDataTypeBoolOrBVec);
2834								const bool									varyBoolApiType		= checkMethod == UniformValueCase::CHECKMETHOD_GET_UNIFORM && containsBooleans &&
2835																								  (collectionGroupNdx == UNIFORMCOLLECTIONS_BASIC || collectionGroupNdx == UNIFORMCOLLECTIONS_BASIC_ARRAY);
2836								const int									numBoolVariations	= varyBoolApiType ? 3 : 1;
2837								const bool									containsMatrices	= uniformCollection->containsMatchingBasicType(glu::isDataTypeMatrix);
2838								const bool									varyMatrixMode		= containsMatrices &&
2839																								  (collectionGroupNdx == UNIFORMCOLLECTIONS_BASIC || collectionGroupNdx == UNIFORMCOLLECTIONS_BASIC_ARRAY);
2840								const int									numMatVariations	= varyMatrixMode ? 2 : 1;
2841
2842								if (containsMatrices && assignMethod != UniformValueCase::ASSIGNMETHOD_POINTER)
2843									continue;
2844
2845								for (int booleanTypeI = 0; booleanTypeI < numBoolVariations; booleanTypeI++)
2846								{
2847									const deUint32		booleanTypeFeat		= booleanTypeI == 1 ? UniformCase::FEATURE_BOOLEANAPITYPE_INT
2848																			: booleanTypeI == 2 ? UniformCase::FEATURE_BOOLEANAPITYPE_UINT
2849																			: 0;
2850									const char* const	booleanTypeName		= booleanTypeI == 1 ? "int"
2851																			: booleanTypeI == 2 ? "uint"
2852																			: "float";
2853									const string		nameWithBoolType	= varyBoolApiType ? collName + "api_" + booleanTypeName + "_" : collName;
2854
2855									for (int matrixTypeI = 0; matrixTypeI < numMatVariations; matrixTypeI++)
2856									{
2857										const string nameWithMatrixType = nameWithBoolType + (matrixTypeI == 1 ? "row_major_" : "");
2858
2859										for (int shaderType = 0; shaderType < (int)CASESHADERTYPE_LAST; shaderType++)
2860										{
2861											const string	name							= nameWithMatrixType + getCaseShaderTypeName((CaseShaderType)shaderType);
2862											const deUint32	arrayFirstElemNameNoIndexFeat	= referToFirstArrayElemWithoutIndexI == 0 ? 0 : UniformCase::FEATURE_ARRAY_FIRST_ELEM_NAME_NO_INDEX;
2863
2864											// skip empty groups by creating groups on demand
2865											if (!collectionTestGroup)
2866											{
2867												collectionTestGroup = new TestCaseGroup(m_context, collectionGroupName.c_str(), "");
2868												checkMethodGroup->addChild(collectionTestGroup);
2869											}
2870
2871											collectionTestGroup->addChild(new UniformValueCase(m_context, name.c_str(), "", (CaseShaderType)shaderType, uniformCollection,
2872																							   UniformValueCase::VALUETOCHECK_ASSIGNED, checkMethod, assignMethod,
2873																							   booleanTypeFeat | arrayFirstElemNameNoIndexFeat | (matrixTypeI == 1 ? UniformCase::FEATURE_MATRIXMODE_ROWMAJOR : 0)));
2874										}
2875									}
2876								}
2877							}
2878						}
2879					}
2880				}
2881			}
2882
2883			// Cases assign multiple basic-array elements with one glUniform*v() (i.e. the count parameter is bigger than 1).
2884
2885			{
2886				static const struct
2887				{
2888					UniformCase::Feature	arrayAssignMode;
2889					const char*				name;
2890					const char*				description;
2891				} arrayAssignGroups[] =
2892				{
2893					{ UniformCase::FEATURE_ARRAYASSIGN_FULL,			"basic_array_assign_full",		"Assign entire basic-type arrays per glUniform*v() call"			},
2894					{ UniformCase::FEATURE_ARRAYASSIGN_BLOCKS_OF_TWO,	"basic_array_assign_partial",	"Assign two elements of a basic-type array per glUniform*v() call"	}
2895				};
2896
2897				for (int arrayAssignGroupNdx = 0; arrayAssignGroupNdx < DE_LENGTH_OF_ARRAY(arrayAssignGroups); arrayAssignGroupNdx++)
2898				{
2899					UniformCase::Feature	arrayAssignMode		= arrayAssignGroups[arrayAssignGroupNdx].arrayAssignMode;
2900					const char* const		groupName			= arrayAssignGroups[arrayAssignGroupNdx].name;
2901					const char* const		groupDesc			= arrayAssignGroups[arrayAssignGroupNdx].description;
2902
2903					TestCaseGroup* const curArrayAssignGroup = new TestCaseGroup(m_context, groupName, groupDesc);
2904					assignedValuesGroup->addChild(curArrayAssignGroup);
2905
2906					static const int basicArrayCollectionGroups[] = { UNIFORMCOLLECTIONS_BASIC_ARRAY, UNIFORMCOLLECTIONS_ARRAY_IN_STRUCT, UNIFORMCOLLECTIONS_MULTIPLE_BASIC_ARRAY };
2907
2908					for (int collectionGroupNdx = 0; collectionGroupNdx < DE_LENGTH_OF_ARRAY(basicArrayCollectionGroups); collectionGroupNdx++)
2909					{
2910						const UniformCollectionGroup&	collectionGroup		= defaultUniformCollections[basicArrayCollectionGroups[collectionGroupNdx]];
2911						TestCaseGroup* const			collectionTestGroup	= new TestCaseGroup(m_context, collectionGroup.name.c_str(), "");
2912						curArrayAssignGroup->addChild(collectionTestGroup);
2913
2914						for (int collectionNdx = 0; collectionNdx < (int)collectionGroup.cases.size(); collectionNdx++)
2915						{
2916							const UniformCollectionCase&				collectionCase		= collectionGroup.cases[collectionNdx];
2917							const string								collName			= collectionCase.namePrefix;
2918							const SharedPtr<const UniformCollection>&	uniformCollection	= collectionCase.uniformCollection;
2919
2920							for (int shaderType = 0; shaderType < (int)CASESHADERTYPE_LAST; shaderType++)
2921							{
2922								const string name = collName + getCaseShaderTypeName((CaseShaderType)shaderType);
2923								collectionTestGroup->addChild(new UniformValueCase(m_context, name.c_str(), "", (CaseShaderType)shaderType, uniformCollection,
2924																				   UniformValueCase::VALUETOCHECK_ASSIGNED, UniformValueCase::CHECKMETHOD_GET_UNIFORM, UniformValueCase::ASSIGNMETHOD_POINTER,
2925																				   arrayAssignMode));
2926							}
2927						}
2928					}
2929				}
2930			}
2931
2932			// Value checking cases when unused uniforms are present.
2933
2934			{
2935				TestCaseGroup* const unusedUniformsGroup = new TestCaseGroup(m_context, "unused_uniforms", "Test with unused uniforms");
2936				assignedValuesGroup->addChild(unusedUniformsGroup);
2937
2938				const UniformCollectionGroup& collectionGroup = defaultUniformCollections[UNIFORMCOLLECTIONS_ARRAY_IN_STRUCT];
2939
2940				for (int collectionNdx = 0; collectionNdx < (int)collectionGroup.cases.size(); collectionNdx++)
2941				{
2942					const UniformCollectionCase&				collectionCase		= collectionGroup.cases[collectionNdx];
2943					const string								collName			= collectionCase.namePrefix;
2944					const SharedPtr<const UniformCollection>&	uniformCollection	= collectionCase.uniformCollection;
2945
2946					for (int shaderType = 0; shaderType < (int)CASESHADERTYPE_LAST; shaderType++)
2947					{
2948						const string name = collName + getCaseShaderTypeName((CaseShaderType)shaderType);
2949						unusedUniformsGroup->addChild(new UniformValueCase(m_context, name.c_str(), "", (CaseShaderType)shaderType, uniformCollection,
2950																		   UniformValueCase::VALUETOCHECK_ASSIGNED, UniformValueCase::CHECKMETHOD_GET_UNIFORM, UniformValueCase::ASSIGNMETHOD_POINTER,
2951																		   UniformCase::FEATURE_ARRAYUSAGE_ONLY_MIDDLE_INDEX | UniformCase::FEATURE_UNIFORMUSAGE_EVERY_OTHER));
2952					}
2953				}
2954			}
2955		}
2956	}
2957
2958	// Random cases.
2959
2960	{
2961		const int		numRandomCases		= 100;
2962		TestCaseGroup*	const randomGroup	= new TestCaseGroup(m_context, "random", "Random cases");
2963		addChild(randomGroup);
2964
2965		for (int ndx = 0; ndx < numRandomCases; ndx++)
2966			randomGroup->addChild(new RandomUniformCase(m_context, de::toString(ndx).c_str(), "", (deUint32)ndx));
2967	}
2968}
2969
2970} // Functional
2971} // gles3
2972} // deqp
2973