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