f3470ebb2bf57c57a580ffef2add4d01d60aca5c
[platform/upstream/VK-GL-CTS.git] / modules / gles2 / functional / es2fUniformApiTests.cpp
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
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
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
113 static inline string beforeLast (const string& str, const char c)
114 {
115         return str.substr(0, str.find_last_of(c));
116 }
117
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
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>
143 static bool dataTypeEquals (const glu::DataType t)
144 {
145         return t == T;
146 }
147
148 template<int N>
149 static bool dataTypeIsMatrixWithNRows (const glu::DataType t)
150 {
151         return glu::isDataTypeMatrix(t) && glu::getDataTypeMatrixNumRows(t) == N;
152 }
153
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
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
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
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
265         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:
272         int                                     getNumUniforms          (void) const                                    { return (int)m_uniforms.size();        }
273         int                                     getNumStructTypes       (void) const                                    { return (int)m_structTypes.size();     }
274         Uniform&                        getUniform                      (const int ndx)                                 { return m_uniforms[ndx];                       }
275         const Uniform&          getUniform                      (const int ndx) const                   { return m_uniforms[ndx];                       }
276         const StructType*       getStructType           (const int ndx) const                   { return m_structTypes[ndx];            }
277         void                            addUniform                      (const Uniform& uniform)                { m_uniforms.push_back(uniform);        }
278         void                            addStructType           (const StructType* const type)  { m_structTypes.push_back(type);        }
279
280         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.
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
300         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
308         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
316         bool containsSeveralSamplerTypes (void) const
317         {
318                 return getSamplerTypes().size() > 1;
319         }
320
321         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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
799                 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
816                 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
837                 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); }
839                 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
853                 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
856                 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
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
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
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
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
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
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
1006 UniformCase::~UniformCase (void)
1007 {
1008         UniformCase::deinit();
1009 }
1010
1011 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
1077 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
1124 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
1138 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
1155 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
1181 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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
2066 UniformApiTests::UniformApiTests (Context& context)
2067         : TestCaseGroup(context, "uniform_api", "Uniform API Tests")
2068 {
2069 }
2070
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
2084         UniformCollectionCase (const char* const name, const UniformCollection* uniformCollection_)
2085                 : namePrefix                    (name ? name + string("_") : "")
2086                 , uniformCollection             (uniformCollection_)
2087         {
2088         }
2089 };
2090
2091 } // anonymous
2092
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