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