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