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