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