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