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