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