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