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