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