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