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