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