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