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