1 /*-------------------------------------------------------------------------
2 * OpenGL Conformance Test Suite
3 * -----------------------------
4 *
5 * Copyright (c) 2016 Google Inc.
6 * Copyright (c) 2016 The Khronos Group Inc.
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 *
20 */ /*!
21 * \file
22 * \brief Uniform block tests.
23 */ /*-------------------------------------------------------------------*/
24
25 #include "glcUniformBlockTests.hpp"
26 #include "deRandom.hpp"
27 #include "deStringUtil.hpp"
28 #include "glcUniformBlockCase.hpp"
29 #include "glwEnums.hpp"
30 #include "glwFunctions.hpp"
31 #include "tcuCommandLine.hpp"
32 #include "tcuTestLog.hpp"
33
34 namespace deqp
35 {
36
37 using deqp::Context;
38 using std::string;
39 using std::vector;
40
41 using namespace ub;
42
43 enum FeatureBits
44 {
45 FEATURE_VECTORS = (1 << 0),
46 FEATURE_MATRICES = (1 << 1),
47 FEATURE_ARRAYS = (1 << 2),
48 FEATURE_STRUCTS = (1 << 3),
49 FEATURE_NESTED_STRUCTS = (1 << 4),
50 FEATURE_INSTANCE_ARRAYS = (1 << 5),
51 FEATURE_VERTEX_BLOCKS = (1 << 6),
52 FEATURE_FRAGMENT_BLOCKS = (1 << 7),
53 FEATURE_SHARED_BLOCKS = (1 << 8),
54 FEATURE_UNUSED_UNIFORMS = (1 << 9),
55 FEATURE_UNUSED_MEMBERS = (1 << 10),
56 FEATURE_PACKED_LAYOUT = (1 << 11),
57 FEATURE_SHARED_LAYOUT = (1 << 12),
58 FEATURE_STD140_LAYOUT = (1 << 13),
59 FEATURE_MATRIX_LAYOUT = (1 << 14) //!< Matrix layout flags.
60 };
61
62 class RandomUniformBlockCase : public UniformBlockCase
63 {
64 public:
65 RandomUniformBlockCase(Context &context, const char *name, const char *description, glu::GLSLVersion glslVersion,
66 BufferMode bufferMode, uint32_t features, uint32_t seed);
67
68 void init(void);
69
70 private:
71 void generateBlock(de::Random &rnd, uint32_t layoutFlags);
72 void generateUniform(de::Random &rnd, UniformBlock &block);
73 VarType generateType(de::Random &rnd, int typeDepth, bool arrayOk);
74
75 uint32_t m_features;
76 int m_maxVertexBlocks;
77 int m_maxFragmentBlocks;
78 int m_maxSharedBlocks;
79 int m_maxInstances;
80 int m_maxArrayLength;
81 int m_maxStructDepth;
82 int m_maxBlockMembers;
83 int m_maxStructMembers;
84 uint32_t m_seed;
85
86 int m_blockNdx;
87 int m_uniformNdx;
88 int m_structNdx;
89 };
90
RandomUniformBlockCase(Context & context,const char * name,const char * description,glu::GLSLVersion glslVersion,BufferMode bufferMode,uint32_t features,uint32_t seed)91 RandomUniformBlockCase::RandomUniformBlockCase(Context &context, const char *name, const char *description,
92 glu::GLSLVersion glslVersion, BufferMode bufferMode, uint32_t features,
93 uint32_t seed)
94 : UniformBlockCase(context, name, description, glslVersion, bufferMode)
95 , m_features(features)
96 , m_maxVertexBlocks((features & FEATURE_VERTEX_BLOCKS) ? 4 : 0)
97 , m_maxFragmentBlocks((features & FEATURE_FRAGMENT_BLOCKS) ? 4 : 0)
98 , m_maxSharedBlocks((features & FEATURE_SHARED_BLOCKS) ? 4 : 0)
99 , m_maxInstances((features & FEATURE_INSTANCE_ARRAYS) ? 3 : 0)
100 , m_maxArrayLength((features & FEATURE_ARRAYS) ? 8 : 0)
101 , m_maxStructDepth((features & FEATURE_STRUCTS) ? 2 : 0)
102 , m_maxBlockMembers(5)
103 , m_maxStructMembers(4)
104 , m_seed(seed)
105 , m_blockNdx(1)
106 , m_uniformNdx(1)
107 , m_structNdx(1)
108 {
109 }
110
init(void)111 void RandomUniformBlockCase::init(void)
112 {
113 de::Random rnd(m_seed);
114
115 int numShared = m_maxSharedBlocks > 0 ? rnd.getInt(1, m_maxSharedBlocks) : 0;
116 int numVtxBlocks = m_maxVertexBlocks - numShared > 0 ? rnd.getInt(1, m_maxVertexBlocks - numShared) : 0;
117 int numFragBlocks = m_maxFragmentBlocks - numShared > 0 ? rnd.getInt(1, m_maxFragmentBlocks - numShared) : 0;
118
119 for (int ndx = 0; ndx < numShared; ndx++)
120 generateBlock(rnd, DECLARE_VERTEX | DECLARE_FRAGMENT);
121
122 for (int ndx = 0; ndx < numVtxBlocks; ndx++)
123 generateBlock(rnd, DECLARE_VERTEX);
124
125 for (int ndx = 0; ndx < numFragBlocks; ndx++)
126 generateBlock(rnd, DECLARE_FRAGMENT);
127 }
128
generateBlock(de::Random & rnd,uint32_t layoutFlags)129 void RandomUniformBlockCase::generateBlock(de::Random &rnd, uint32_t layoutFlags)
130 {
131 DE_ASSERT(m_blockNdx <= 'z' - 'a');
132
133 const float instanceArrayWeight = 0.3f;
134 UniformBlock &block = m_interface.allocBlock((string("Block") + (char)('A' + m_blockNdx)).c_str());
135 int numInstances = (m_maxInstances > 0 && rnd.getFloat() < instanceArrayWeight) ? rnd.getInt(0, m_maxInstances) : 0;
136 int numUniforms = rnd.getInt(1, m_maxBlockMembers);
137
138 if (numInstances > 0)
139 block.setArraySize(numInstances);
140
141 if (numInstances > 0 || rnd.getBool())
142 block.setInstanceName((string("block") + (char)('A' + m_blockNdx)).c_str());
143
144 // Layout flag candidates.
145 vector<uint32_t> layoutFlagCandidates;
146 layoutFlagCandidates.push_back(0);
147 if (m_features & FEATURE_PACKED_LAYOUT)
148 layoutFlagCandidates.push_back(LAYOUT_SHARED);
149 if ((m_features & FEATURE_SHARED_LAYOUT) && ((layoutFlags & DECLARE_BOTH) != DECLARE_BOTH))
150 layoutFlagCandidates.push_back(LAYOUT_PACKED); // \note packed layout can only be used in a single shader stage.
151 if (m_features & FEATURE_STD140_LAYOUT)
152 layoutFlagCandidates.push_back(LAYOUT_STD140);
153
154 layoutFlags |= rnd.choose<uint32_t>(layoutFlagCandidates.begin(), layoutFlagCandidates.end());
155
156 if (m_features & FEATURE_MATRIX_LAYOUT)
157 {
158 static const uint32_t matrixCandidates[] = {0, LAYOUT_ROW_MAJOR, LAYOUT_COLUMN_MAJOR};
159 layoutFlags |=
160 rnd.choose<uint32_t>(&matrixCandidates[0], &matrixCandidates[DE_LENGTH_OF_ARRAY(matrixCandidates)]);
161 }
162
163 block.setFlags(layoutFlags);
164
165 for (int ndx = 0; ndx < numUniforms; ndx++)
166 generateUniform(rnd, block);
167
168 m_blockNdx += 1;
169 }
170
genName(char first,char last,int ndx)171 static std::string genName(char first, char last, int ndx)
172 {
173 std::string str = "";
174 int alphabetLen = last - first + 1;
175
176 while (ndx > alphabetLen)
177 {
178 str.insert(str.begin(), (char)(first + ((ndx - 1) % alphabetLen)));
179 ndx = ((ndx - 1) / alphabetLen);
180 }
181
182 str.insert(str.begin(), (char)(first + (ndx % (alphabetLen + 1)) - 1));
183
184 return str;
185 }
186
generateUniform(de::Random & rnd,UniformBlock & block)187 void RandomUniformBlockCase::generateUniform(de::Random &rnd, UniformBlock &block)
188 {
189 const float unusedVtxWeight = 0.15f;
190 const float unusedFragWeight = 0.15f;
191 bool unusedOk = (m_features & FEATURE_UNUSED_UNIFORMS) != 0;
192 uint32_t flags = 0;
193 std::string name = genName('a', 'z', m_uniformNdx);
194 VarType type = generateType(rnd, 0, true);
195
196 flags |= (unusedOk && rnd.getFloat() < unusedVtxWeight) ? UNUSED_VERTEX : 0;
197 flags |= (unusedOk && rnd.getFloat() < unusedFragWeight) ? UNUSED_FRAGMENT : 0;
198
199 block.addUniform(Uniform(name.c_str(), type, flags));
200
201 m_uniformNdx += 1;
202 }
203
generateType(de::Random & rnd,int typeDepth,bool arrayOk)204 VarType RandomUniformBlockCase::generateType(de::Random &rnd, int typeDepth, bool arrayOk)
205 {
206 const float structWeight = 0.1f;
207 const float arrayWeight = 0.1f;
208
209 if (typeDepth < m_maxStructDepth && rnd.getFloat() < structWeight)
210 {
211 const float unusedVtxWeight = 0.15f;
212 const float unusedFragWeight = 0.15f;
213 bool unusedOk = (m_features & FEATURE_UNUSED_MEMBERS) != 0;
214 vector<VarType> memberTypes;
215 int numMembers = rnd.getInt(1, m_maxStructMembers);
216
217 // Generate members first so nested struct declarations are in correct order.
218 for (int ndx = 0; ndx < numMembers; ndx++)
219 memberTypes.push_back(generateType(rnd, typeDepth + 1, true));
220
221 StructType &structType = m_interface.allocStruct((string("s") + genName('A', 'Z', m_structNdx)).c_str());
222 m_structNdx += 1;
223
224 DE_ASSERT(numMembers <= 'Z' - 'A');
225 for (int ndx = 0; ndx < numMembers; ndx++)
226 {
227 uint32_t flags = 0;
228
229 flags |= (unusedOk && rnd.getFloat() < unusedVtxWeight) ? UNUSED_VERTEX : 0;
230 flags |= (unusedOk && rnd.getFloat() < unusedFragWeight) ? UNUSED_FRAGMENT : 0;
231
232 structType.addMember((string("m") + (char)('A' + ndx)).c_str(), memberTypes[ndx], flags);
233 }
234
235 return VarType(&structType);
236 }
237 else if (m_maxArrayLength > 0 && arrayOk && rnd.getFloat() < arrayWeight)
238 {
239 int arrayLength = rnd.getInt(1, m_maxArrayLength);
240 VarType elementType = generateType(rnd, typeDepth, false /* nested arrays are not allowed */);
241 return VarType(elementType, arrayLength);
242 }
243 else
244 {
245 vector<glu::DataType> typeCandidates;
246
247 typeCandidates.push_back(glu::TYPE_FLOAT);
248 typeCandidates.push_back(glu::TYPE_INT);
249 typeCandidates.push_back(glu::TYPE_UINT);
250 typeCandidates.push_back(glu::TYPE_BOOL);
251
252 if (m_features & FEATURE_VECTORS)
253 {
254 typeCandidates.push_back(glu::TYPE_FLOAT_VEC2);
255 typeCandidates.push_back(glu::TYPE_FLOAT_VEC3);
256 typeCandidates.push_back(glu::TYPE_FLOAT_VEC4);
257 typeCandidates.push_back(glu::TYPE_INT_VEC2);
258 typeCandidates.push_back(glu::TYPE_INT_VEC3);
259 typeCandidates.push_back(glu::TYPE_INT_VEC4);
260 typeCandidates.push_back(glu::TYPE_UINT_VEC2);
261 typeCandidates.push_back(glu::TYPE_UINT_VEC3);
262 typeCandidates.push_back(glu::TYPE_UINT_VEC4);
263 typeCandidates.push_back(glu::TYPE_BOOL_VEC2);
264 typeCandidates.push_back(glu::TYPE_BOOL_VEC3);
265 typeCandidates.push_back(glu::TYPE_BOOL_VEC4);
266 }
267
268 if (m_features & FEATURE_MATRICES)
269 {
270 typeCandidates.push_back(glu::TYPE_FLOAT_MAT2);
271 typeCandidates.push_back(glu::TYPE_FLOAT_MAT2X3);
272 typeCandidates.push_back(glu::TYPE_FLOAT_MAT3X2);
273 typeCandidates.push_back(glu::TYPE_FLOAT_MAT3);
274 typeCandidates.push_back(glu::TYPE_FLOAT_MAT3X4);
275 typeCandidates.push_back(glu::TYPE_FLOAT_MAT4X2);
276 typeCandidates.push_back(glu::TYPE_FLOAT_MAT4X3);
277 typeCandidates.push_back(glu::TYPE_FLOAT_MAT4);
278 }
279
280 glu::DataType type = rnd.choose<glu::DataType>(typeCandidates.begin(), typeCandidates.end());
281 uint32_t flags = 0;
282
283 if (!glu::isDataTypeBoolOrBVec(type))
284 {
285 // Precision.
286 static const uint32_t precisionCandidates[] = {PRECISION_LOW, PRECISION_MEDIUM, PRECISION_HIGH};
287 flags |= rnd.choose<uint32_t>(&precisionCandidates[0],
288 &precisionCandidates[DE_LENGTH_OF_ARRAY(precisionCandidates)]);
289 }
290
291 return VarType(type, flags);
292 }
293 }
294
295 class BlockBasicTypeCase : public UniformBlockCase
296 {
297 public:
BlockBasicTypeCase(Context & context,const char * name,const char * description,glu::GLSLVersion glslVersion,const VarType & type,uint32_t layoutFlags,int numInstances)298 BlockBasicTypeCase(Context &context, const char *name, const char *description, glu::GLSLVersion glslVersion,
299 const VarType &type, uint32_t layoutFlags, int numInstances)
300 : UniformBlockCase(context, name, description, glslVersion, BUFFERMODE_PER_BLOCK)
301 {
302 UniformBlock &block = m_interface.allocBlock("Block");
303 block.addUniform(Uniform("var", type, 0));
304 block.setFlags(layoutFlags);
305
306 if (numInstances > 0)
307 {
308 block.setArraySize(numInstances);
309 block.setInstanceName("block");
310 }
311 }
312 };
313
createRandomCaseGroup(tcu::TestCaseGroup * parentGroup,Context & context,const char * groupName,const char * description,glu::GLSLVersion glslVersion,UniformBlockCase::BufferMode bufferMode,uint32_t features,int numCases,uint32_t baseSeed)314 static void createRandomCaseGroup(tcu::TestCaseGroup *parentGroup, Context &context, const char *groupName,
315 const char *description, glu::GLSLVersion glslVersion,
316 UniformBlockCase::BufferMode bufferMode, uint32_t features, int numCases,
317 uint32_t baseSeed)
318 {
319 tcu::TestCaseGroup *group = new tcu::TestCaseGroup(context.getTestContext(), groupName, description);
320 parentGroup->addChild(group);
321
322 baseSeed += (uint32_t)context.getTestContext().getCommandLine().getBaseSeed();
323
324 for (int ndx = 0; ndx < numCases; ndx++)
325 group->addChild(new RandomUniformBlockCase(context, de::toString(ndx).c_str(), "", glslVersion, bufferMode,
326 features, (uint32_t)deInt32Hash(ndx + baseSeed)));
327 }
328
329 class BlockSingleStructCase : public UniformBlockCase
330 {
331 public:
BlockSingleStructCase(Context & context,const char * name,const char * description,glu::GLSLVersion glslVersion,uint32_t layoutFlags,BufferMode bufferMode,int numInstances)332 BlockSingleStructCase(Context &context, const char *name, const char *description, glu::GLSLVersion glslVersion,
333 uint32_t layoutFlags, BufferMode bufferMode, int numInstances)
334 : UniformBlockCase(context, name, description, glslVersion, bufferMode)
335 , m_layoutFlags(layoutFlags)
336 , m_numInstances(numInstances)
337 {
338 }
339
init(void)340 void init(void)
341 {
342 StructType &typeS = m_interface.allocStruct("S");
343 typeS.addMember("a", VarType(glu::TYPE_INT_VEC3, PRECISION_HIGH), UNUSED_BOTH); // First member is unused.
344 typeS.addMember("b", VarType(VarType(glu::TYPE_FLOAT_MAT3, PRECISION_MEDIUM), 4));
345 typeS.addMember("c", VarType(glu::TYPE_FLOAT_VEC4, PRECISION_HIGH));
346
347 UniformBlock &block = m_interface.allocBlock("Block");
348 block.addUniform(Uniform("s", VarType(&typeS), 0));
349 block.setFlags(m_layoutFlags);
350
351 if (m_numInstances > 0)
352 {
353 block.setInstanceName("block");
354 block.setArraySize(m_numInstances);
355 }
356 }
357
358 private:
359 uint32_t m_layoutFlags;
360 int m_numInstances;
361 };
362
363 class BlockSingleStructArrayCase : public UniformBlockCase
364 {
365 public:
BlockSingleStructArrayCase(Context & context,const char * name,const char * description,glu::GLSLVersion glslVersion,uint32_t layoutFlags,BufferMode bufferMode,int numInstances)366 BlockSingleStructArrayCase(Context &context, const char *name, const char *description,
367 glu::GLSLVersion glslVersion, uint32_t layoutFlags, BufferMode bufferMode,
368 int numInstances)
369 : UniformBlockCase(context, name, description, glslVersion, bufferMode)
370 , m_layoutFlags(layoutFlags)
371 , m_numInstances(numInstances)
372 {
373 }
374
init(void)375 void init(void)
376 {
377 StructType &typeS = m_interface.allocStruct("S");
378 typeS.addMember("a", VarType(glu::TYPE_INT_VEC3, PRECISION_HIGH), UNUSED_BOTH);
379 typeS.addMember("b", VarType(VarType(glu::TYPE_FLOAT_MAT3, PRECISION_MEDIUM), 4));
380 typeS.addMember("c", VarType(glu::TYPE_FLOAT_VEC4, PRECISION_HIGH));
381
382 UniformBlock &block = m_interface.allocBlock("Block");
383 block.addUniform(Uniform("u", VarType(glu::TYPE_UINT, PRECISION_LOW)));
384 block.addUniform(Uniform("s", VarType(VarType(&typeS), 3)));
385 block.addUniform(Uniform("v", VarType(glu::TYPE_FLOAT_VEC4, PRECISION_MEDIUM)));
386 block.setFlags(m_layoutFlags);
387
388 if (m_numInstances > 0)
389 {
390 block.setInstanceName("block");
391 block.setArraySize(m_numInstances);
392 }
393 }
394
395 private:
396 uint32_t m_layoutFlags;
397 int m_numInstances;
398 };
399
400 class BlockSingleNestedStructCase : public UniformBlockCase
401 {
402 public:
BlockSingleNestedStructCase(Context & context,const char * name,const char * description,glu::GLSLVersion glslVersion,uint32_t layoutFlags,BufferMode bufferMode,int numInstances)403 BlockSingleNestedStructCase(Context &context, const char *name, const char *description,
404 glu::GLSLVersion glslVersion, uint32_t layoutFlags, BufferMode bufferMode,
405 int numInstances)
406 : UniformBlockCase(context, name, description, glslVersion, bufferMode)
407 , m_layoutFlags(layoutFlags)
408 , m_numInstances(numInstances)
409 {
410 }
411
init(void)412 void init(void)
413 {
414 StructType &typeS = m_interface.allocStruct("S");
415 typeS.addMember("a", VarType(glu::TYPE_INT_VEC3, PRECISION_HIGH));
416 typeS.addMember("b", VarType(VarType(glu::TYPE_FLOAT_MAT3, PRECISION_MEDIUM), 4));
417 typeS.addMember("c", VarType(glu::TYPE_FLOAT_VEC4, PRECISION_HIGH), UNUSED_BOTH);
418
419 StructType &typeT = m_interface.allocStruct("T");
420 typeT.addMember("a", VarType(glu::TYPE_FLOAT_MAT3, PRECISION_MEDIUM));
421 typeT.addMember("b", VarType(&typeS));
422
423 UniformBlock &block = m_interface.allocBlock("Block");
424 block.addUniform(Uniform("s", VarType(&typeS), 0));
425 block.addUniform(Uniform("v", VarType(glu::TYPE_FLOAT_VEC2, PRECISION_LOW), UNUSED_BOTH));
426 block.addUniform(Uniform("t", VarType(&typeT), 0));
427 block.addUniform(Uniform("u", VarType(glu::TYPE_UINT, PRECISION_HIGH), 0));
428 block.setFlags(m_layoutFlags);
429
430 if (m_numInstances > 0)
431 {
432 block.setInstanceName("block");
433 block.setArraySize(m_numInstances);
434 }
435 }
436
437 private:
438 uint32_t m_layoutFlags;
439 int m_numInstances;
440 };
441
442 class BlockSingleNestedStructArrayCase : public UniformBlockCase
443 {
444 public:
BlockSingleNestedStructArrayCase(Context & context,const char * name,const char * description,glu::GLSLVersion glslVersion,uint32_t layoutFlags,BufferMode bufferMode,int numInstances)445 BlockSingleNestedStructArrayCase(Context &context, const char *name, const char *description,
446 glu::GLSLVersion glslVersion, uint32_t layoutFlags, BufferMode bufferMode,
447 int numInstances)
448 : UniformBlockCase(context, name, description, glslVersion, bufferMode)
449 , m_layoutFlags(layoutFlags)
450 , m_numInstances(numInstances)
451 {
452 }
453
init(void)454 void init(void)
455 {
456 StructType &typeS = m_interface.allocStruct("S");
457 typeS.addMember("a", VarType(glu::TYPE_INT_VEC3, PRECISION_HIGH));
458 typeS.addMember("b", VarType(VarType(glu::TYPE_INT_VEC2, PRECISION_MEDIUM), 4));
459 typeS.addMember("c", VarType(glu::TYPE_FLOAT_VEC4, PRECISION_HIGH), UNUSED_BOTH);
460
461 StructType &typeT = m_interface.allocStruct("T");
462 typeT.addMember("a", VarType(glu::TYPE_FLOAT_MAT3, PRECISION_MEDIUM));
463 typeT.addMember("b", VarType(VarType(&typeS), 3));
464
465 UniformBlock &block = m_interface.allocBlock("Block");
466 block.addUniform(Uniform("s", VarType(&typeS), 0));
467 block.addUniform(Uniform("v", VarType(glu::TYPE_FLOAT_VEC2, PRECISION_LOW), UNUSED_BOTH));
468 block.addUniform(Uniform("t", VarType(VarType(&typeT), 2), 0));
469 block.addUniform(Uniform("u", VarType(glu::TYPE_UINT, PRECISION_HIGH), 0));
470 block.setFlags(m_layoutFlags);
471
472 if (m_numInstances > 0)
473 {
474 block.setInstanceName("block");
475 block.setArraySize(m_numInstances);
476 }
477 }
478
479 private:
480 uint32_t m_layoutFlags;
481 int m_numInstances;
482 };
483
484 class BlockMultiBasicTypesCase : public UniformBlockCase
485 {
486 public:
BlockMultiBasicTypesCase(Context & context,const char * name,const char * description,glu::GLSLVersion glslVersion,uint32_t flagsA,uint32_t flagsB,BufferMode bufferMode,int numInstances)487 BlockMultiBasicTypesCase(Context &context, const char *name, const char *description, glu::GLSLVersion glslVersion,
488 uint32_t flagsA, uint32_t flagsB, BufferMode bufferMode, int numInstances)
489 : UniformBlockCase(context, name, description, glslVersion, bufferMode)
490 , m_flagsA(flagsA)
491 , m_flagsB(flagsB)
492 , m_numInstances(numInstances)
493 {
494 }
495
init(void)496 void init(void)
497 {
498 UniformBlock &blockA = m_interface.allocBlock("BlockA");
499 blockA.addUniform(Uniform("a", VarType(glu::TYPE_FLOAT, PRECISION_HIGH)));
500 blockA.addUniform(Uniform("b", VarType(glu::TYPE_UINT_VEC3, PRECISION_LOW), UNUSED_BOTH));
501 blockA.addUniform(Uniform("c", VarType(glu::TYPE_FLOAT_MAT2, PRECISION_MEDIUM)));
502 blockA.setInstanceName("blockA");
503 blockA.setFlags(m_flagsA);
504
505 UniformBlock &blockB = m_interface.allocBlock("BlockB");
506 blockB.addUniform(Uniform("a", VarType(glu::TYPE_FLOAT_MAT3, PRECISION_MEDIUM)));
507 blockB.addUniform(Uniform("b", VarType(glu::TYPE_INT_VEC2, PRECISION_LOW)));
508 blockB.addUniform(Uniform("c", VarType(glu::TYPE_FLOAT_VEC4, PRECISION_HIGH), UNUSED_BOTH));
509 blockB.addUniform(Uniform("d", VarType(glu::TYPE_BOOL, 0)));
510 blockB.setInstanceName("blockB");
511 blockB.setFlags(m_flagsB);
512
513 if (m_numInstances > 0)
514 {
515 blockA.setArraySize(m_numInstances);
516 blockB.setArraySize(m_numInstances);
517 }
518 }
519
520 private:
521 uint32_t m_flagsA;
522 uint32_t m_flagsB;
523 int m_numInstances;
524 };
525
526 class BlockMultiNestedStructCase : public UniformBlockCase
527 {
528 public:
BlockMultiNestedStructCase(Context & context,const char * name,const char * description,glu::GLSLVersion glslVersion,uint32_t flagsA,uint32_t flagsB,BufferMode bufferMode,int numInstances)529 BlockMultiNestedStructCase(Context &context, const char *name, const char *description,
530 glu::GLSLVersion glslVersion, uint32_t flagsA, uint32_t flagsB, BufferMode bufferMode,
531 int numInstances)
532 : UniformBlockCase(context, name, description, glslVersion, bufferMode)
533 , m_flagsA(flagsA)
534 , m_flagsB(flagsB)
535 , m_numInstances(numInstances)
536 {
537 }
538
init(void)539 void init(void)
540 {
541 StructType &typeS = m_interface.allocStruct("S");
542 typeS.addMember("a", VarType(glu::TYPE_FLOAT_MAT3, PRECISION_LOW));
543 typeS.addMember("b", VarType(VarType(glu::TYPE_INT_VEC2, PRECISION_MEDIUM), 4));
544 typeS.addMember("c", VarType(glu::TYPE_FLOAT_VEC4, PRECISION_HIGH));
545
546 StructType &typeT = m_interface.allocStruct("T");
547 typeT.addMember("a", VarType(glu::TYPE_UINT, PRECISION_MEDIUM), UNUSED_BOTH);
548 typeT.addMember("b", VarType(&typeS));
549 typeT.addMember("c", VarType(glu::TYPE_BOOL_VEC4, 0));
550
551 UniformBlock &blockA = m_interface.allocBlock("BlockA");
552 blockA.addUniform(Uniform("a", VarType(glu::TYPE_FLOAT, PRECISION_HIGH)));
553 blockA.addUniform(Uniform("b", VarType(&typeS)));
554 blockA.addUniform(Uniform("c", VarType(glu::TYPE_UINT_VEC3, PRECISION_LOW), UNUSED_BOTH));
555 blockA.setInstanceName("blockA");
556 blockA.setFlags(m_flagsA);
557
558 UniformBlock &blockB = m_interface.allocBlock("BlockB");
559 blockB.addUniform(Uniform("a", VarType(glu::TYPE_FLOAT_MAT2, PRECISION_MEDIUM)));
560 blockB.addUniform(Uniform("b", VarType(&typeT)));
561 blockB.addUniform(Uniform("c", VarType(glu::TYPE_BOOL_VEC4, 0), UNUSED_BOTH));
562 blockB.addUniform(Uniform("d", VarType(glu::TYPE_BOOL, 0)));
563 blockB.setInstanceName("blockB");
564 blockB.setFlags(m_flagsB);
565
566 if (m_numInstances > 0)
567 {
568 blockA.setArraySize(m_numInstances);
569 blockB.setArraySize(m_numInstances);
570 }
571 }
572
573 private:
574 uint32_t m_flagsA;
575 uint32_t m_flagsB;
576 int m_numInstances;
577 };
578
579 class UniformBlockPrecisionMatching : public TestCase
580 {
581 public:
UniformBlockPrecisionMatching(Context & context,glu::GLSLVersion glslVersion)582 UniformBlockPrecisionMatching(Context &context, glu::GLSLVersion glslVersion)
583 : TestCase(context, "precision_matching", "")
584 , m_glslVersion(glslVersion)
585 {
586 }
587
iterate(void)588 IterateResult iterate(void)
589 {
590 std::string vs1("layout (std140) uniform Data { lowp float x; } myData;\n"
591 "void main() {\n"
592 " gl_Position = vec4(myData.x, 0.0, 0.0, 1.0);\n"
593 "}");
594 std::string fs1("precision highp float;\n"
595 "out vec4 color;\n"
596 "layout (std140) uniform Data { float x; } myData;\n"
597 "void main() {\n"
598 " color = vec4(myData.x);\n"
599 "}");
600
601 std::string vs2("layout (std140) uniform Data { highp int x; mediump int y; } myData;\n"
602 "void main() {\n"
603 " gl_Position = vec4(float(myData.x), 0.0, 0.0, 1.0);\n"
604 "}");
605 std::string fs2("precision highp float;\n"
606 "out vec4 color;\n"
607 "layout (std140) uniform Data { mediump int x; highp int y; } myData;\n"
608 "void main() {\n"
609 " color = vec4(float(myData.y));\n"
610 "}");
611
612 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
613 if (!Link(vs1, fs1) || !Link(vs2, fs2))
614 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
615 return STOP;
616 }
617
Link(const std::string & vs,const std::string & fs)618 bool Link(const std::string &vs, const std::string &fs)
619 {
620 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
621 const glw::GLuint p = gl.createProgram();
622 const std::string version = glu::getGLSLVersionDeclaration(m_glslVersion);
623
624 const struct
625 {
626 const char *name;
627 const std::string &body;
628 glw::GLenum type;
629 } shaderDefinition[] = {{"VS", vs, GL_VERTEX_SHADER}, {"FS", fs, GL_FRAGMENT_SHADER}};
630
631 for (unsigned int index = 0; index < 2; ++index)
632 {
633 std::string shaderSource = version + "\n" + shaderDefinition[index].body;
634 const char *shaderSourcePtr = shaderSource.c_str();
635
636 glw::GLuint sh = gl.createShader(shaderDefinition[index].type);
637 gl.attachShader(p, sh);
638 gl.deleteShader(sh);
639 gl.shaderSource(sh, 1, &shaderSourcePtr, NULL);
640 gl.compileShader(sh);
641
642 glw::GLint status;
643 gl.getShaderiv(sh, GL_COMPILE_STATUS, &status);
644 if (status == GL_FALSE)
645 {
646 glw::GLint length;
647 gl.getShaderiv(sh, GL_INFO_LOG_LENGTH, &length);
648 if (length > 0)
649 {
650 std::vector<glw::GLchar> log(length);
651 gl.getShaderInfoLog(sh, length, NULL, &log[0]);
652 m_context.getTestContext().getLog() << tcu::TestLog::Message << shaderDefinition[index].name
653 << " compilation should succed. Info Log:\n"
654 << &log[0] << tcu::TestLog::EndMessage;
655 }
656 gl.deleteProgram(p);
657 return false;
658 }
659 }
660
661 gl.linkProgram(p);
662
663 bool result = true;
664 glw::GLint status;
665 gl.getProgramiv(p, GL_LINK_STATUS, &status);
666 if (status == GL_FALSE)
667 {
668 glw::GLchar log[1024];
669 gl.getProgramInfoLog(p, sizeof(log), NULL, log);
670 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Link operation should succed. Info Log:\n"
671 << log << tcu::TestLog::EndMessage;
672 result = false;
673 }
674
675 gl.deleteProgram(p);
676 return result;
677 }
678
679 private:
680 glu::GLSLVersion m_glslVersion;
681 };
682
683 class UniformBlockNameMatching : public TestCase
684 {
685 public:
UniformBlockNameMatching(Context & context,glu::GLSLVersion glslVersion)686 UniformBlockNameMatching(Context &context, glu::GLSLVersion glslVersion)
687 : TestCase(context, "name_matching", "")
688 , m_glslVersion(glslVersion)
689 {
690 }
691
iterate(void)692 IterateResult iterate(void)
693 {
694 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
695
696 std::string vs1("precision highp float;\n"
697 "layout (std140) uniform Data { vec4 v; };\n"
698 "void main() {\n"
699 " gl_Position = v;\n"
700 "}");
701 std::string fs1("precision highp float;\n"
702 "out vec4 color;\n"
703 "layout (std140) uniform Data { vec4 v; } myData;\n"
704 "void main() {\n"
705 " color = vec4(myData.v);\n"
706 "}");
707
708 // check if link error is generated when one of matched blocks has instance name and other doesn't
709 if (!Test(vs1, fs1, GL_FALSE))
710 return STOP;
711
712 std::string vs2("precision highp float;\n"
713 "uniform Data { vec4 v; };\n"
714 "void main() {\n"
715 " gl_Position = v;\n"
716 "}");
717 std::string fs2("precision highp float;\n"
718 "out vec4 color;\n"
719 "uniform Data { vec4 v; };\n"
720 "void main() {\n"
721 " color = v;\n"
722 "}");
723
724 // check if linking succeeds when both matched blocks are lacking an instance name
725 if (!Test(vs2, fs2, GL_TRUE))
726 return STOP;
727
728 std::string vs3("precision highp float;\n"
729 "layout (std140) uniform Data { vec4 v; } a;\n"
730 "void main() {\n"
731 " gl_Position = a.v;\n"
732 "}");
733 std::string fs3("precision highp float;\n"
734 "out vec4 color;\n"
735 "layout (std140) uniform Data { vec4 v; } b;\n"
736 "void main() {\n"
737 " color = b.v;\n"
738 "}");
739
740 // check if linking succeeds when both blocks have a different instance name
741 if (!Test(vs3, fs3, GL_TRUE))
742 return STOP;
743
744 std::string vs4("precision highp float;\n"
745 "layout (std140) uniform Data { float f; };\n"
746 "void main() {\n"
747 " gl_Position = vec4(f);\n"
748 "}\n");
749 std::string fs4("precision highp float;\n"
750 "uniform float f;\n"
751 "out vec4 color;\n"
752 "void main() {\n"
753 " color = vec4(f);\n"
754 "}\n");
755
756 // check if link error is generated when the same name is used for block
757 // with no intance name and non-block uniform
758 if (!Test(vs4, fs4, GL_FALSE))
759 return STOP;
760
761 std::string vs5("precision highp float;\n"
762 "layout (std140) uniform Data { float f; } a;\n"
763 "void main() {\n"
764 " gl_Position = vec4(a.f);\n"
765 "}\n");
766 std::string fs5("precision highp float;\n"
767 "uniform float f;\n"
768 "out vec4 color;\n"
769 "void main() {\n"
770 " color = vec4(f);\n"
771 "}\n");
772
773 // check if link succeeds when the same name is used for block with
774 // instance name and non-block uniform
775 if (!Test(vs5, fs5, GL_TRUE))
776 return STOP;
777
778 std::string vs6("precision highp float;\n"
779 "uniform Data1 { float u; vec4 v; };\n"
780 "void main() {\n"
781 " gl_Position = v;\n"
782 "}");
783 std::string fs6("precision highp float;\n"
784 "out vec4 color;\n"
785 "uniform Data2 { vec4 v; };\n"
786 "void main() {\n"
787 " color = v;\n"
788 "}");
789
790 // check if link error is generated when same name is used in two different blocks
791 if (!Test(vs6, fs6, GL_FALSE))
792 return STOP;
793
794 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
795 return STOP;
796 }
797
Test(const std::string & vs,const std::string & fs,glw::GLint expectedLinkStatus)798 bool Test(const std::string &vs, const std::string &fs, glw::GLint expectedLinkStatus)
799 {
800 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
801 const glw::GLuint p = gl.createProgram();
802 const std::string version = glu::getGLSLVersionDeclaration(m_glslVersion);
803
804 const struct
805 {
806 const char *name;
807 const std::string &body;
808 glw::GLenum type;
809 } shaderDefinition[] = {{"VS", vs, GL_VERTEX_SHADER}, {"FS", fs, GL_FRAGMENT_SHADER}};
810
811 for (unsigned int index = 0; index < 2; ++index)
812 {
813 std::string shaderSource = version + "\n" + shaderDefinition[index].body;
814 const char *shaderSourcePtr = shaderSource.c_str();
815
816 glw::GLuint sh = gl.createShader(shaderDefinition[index].type);
817 gl.attachShader(p, sh);
818 gl.deleteShader(sh);
819 gl.shaderSource(sh, 1, &shaderSourcePtr, NULL);
820 gl.compileShader(sh);
821
822 glw::GLint status;
823 gl.getShaderiv(sh, GL_COMPILE_STATUS, &status);
824 if (status == GL_FALSE)
825 {
826 glw::GLint length;
827 gl.getShaderiv(sh, GL_INFO_LOG_LENGTH, &length);
828 if (length > 0)
829 {
830 std::vector<glw::GLchar> log(length);
831 gl.getShaderInfoLog(sh, length, NULL, &log[0]);
832 m_context.getTestContext().getLog() << tcu::TestLog::Message << shaderDefinition[index].name
833 << " compilation should succed. Info Log:\n"
834 << &log[0] << tcu::TestLog::EndMessage;
835 }
836 gl.deleteProgram(p);
837 return false;
838 }
839 }
840
841 gl.linkProgram(p);
842
843 bool result = true;
844 glw::GLint status;
845 gl.getProgramiv(p, GL_LINK_STATUS, &status);
846 if (status != expectedLinkStatus)
847 {
848 if (status == GL_TRUE)
849 {
850 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Link operation should fail.\n"
851 << tcu::TestLog::EndMessage;
852 }
853 else
854 {
855 glw::GLchar log[1024];
856 gl.getProgramInfoLog(p, sizeof(log), NULL, log);
857 m_context.getTestContext().getLog()
858 << tcu::TestLog::Message << "Link operation should succed. Info Log:\n"
859 << log << tcu::TestLog::EndMessage;
860 }
861 result = false;
862 }
863
864 gl.deleteProgram(p);
865 return result;
866 }
867
868 private:
869 glu::GLSLVersion m_glslVersion;
870 };
871
UniformBlockTests(Context & context,glu::GLSLVersion glslVersion)872 UniformBlockTests::UniformBlockTests(Context &context, glu::GLSLVersion glslVersion)
873 : TestCaseGroup(context, "uniform_block", "Uniform Block tests")
874 , m_glslVersion(glslVersion)
875 {
876 }
877
~UniformBlockTests(void)878 UniformBlockTests::~UniformBlockTests(void)
879 {
880 }
881
init(void)882 void UniformBlockTests::init(void)
883 {
884 static const glu::DataType basicTypes[] = {
885 glu::TYPE_FLOAT, glu::TYPE_FLOAT_VEC2, glu::TYPE_FLOAT_VEC3, glu::TYPE_FLOAT_VEC4,
886 glu::TYPE_INT, glu::TYPE_INT_VEC2, glu::TYPE_INT_VEC3, glu::TYPE_INT_VEC4,
887 glu::TYPE_UINT, glu::TYPE_UINT_VEC2, glu::TYPE_UINT_VEC3, glu::TYPE_UINT_VEC4,
888 glu::TYPE_BOOL, glu::TYPE_BOOL_VEC2, glu::TYPE_BOOL_VEC3, glu::TYPE_BOOL_VEC4,
889 glu::TYPE_FLOAT_MAT2, glu::TYPE_FLOAT_MAT3, glu::TYPE_FLOAT_MAT4, glu::TYPE_FLOAT_MAT2X3,
890 glu::TYPE_FLOAT_MAT2X4, glu::TYPE_FLOAT_MAT3X2, glu::TYPE_FLOAT_MAT3X4, glu::TYPE_FLOAT_MAT4X2,
891 glu::TYPE_FLOAT_MAT4X3};
892
893 static const struct
894 {
895 const char *name;
896 uint32_t flags;
897 } precisionFlags[] = {{"lowp", PRECISION_LOW}, {"mediump", PRECISION_MEDIUM}, {"highp", PRECISION_HIGH}};
898
899 static const struct
900 {
901 const char *name;
902 uint32_t flags;
903 } layoutFlags[] = {{"shared", LAYOUT_SHARED}, {"packed", LAYOUT_PACKED}, {"std140", LAYOUT_STD140}};
904
905 static const struct
906 {
907 const char *name;
908 uint32_t flags;
909 } matrixFlags[] = {{"row_major", LAYOUT_ROW_MAJOR}, {"column_major", LAYOUT_COLUMN_MAJOR}};
910
911 static const struct
912 {
913 const char *name;
914 UniformBlockCase::BufferMode mode;
915 } bufferModes[] = {{"per_block_buffer", UniformBlockCase::BUFFERMODE_PER_BLOCK},
916 {"single_buffer", UniformBlockCase::BUFFERMODE_SINGLE}};
917
918 // ubo.single_basic_type
919 {
920 tcu::TestCaseGroup *singleBasicTypeGroup =
921 new tcu::TestCaseGroup(m_testCtx, "single_basic_type", "Single basic variable in single buffer");
922 addChild(singleBasicTypeGroup);
923
924 for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
925 {
926 tcu::TestCaseGroup *layoutGroup = new tcu::TestCaseGroup(m_testCtx, layoutFlags[layoutFlagNdx].name, "");
927 singleBasicTypeGroup->addChild(layoutGroup);
928
929 for (int basicTypeNdx = 0; basicTypeNdx < DE_LENGTH_OF_ARRAY(basicTypes); basicTypeNdx++)
930 {
931 glu::DataType type = basicTypes[basicTypeNdx];
932 const char *typeName = glu::getDataTypeName(type);
933 uint32_t baseFlags = layoutFlags[layoutFlagNdx].flags;
934 uint32_t flags = baseFlags | ((baseFlags & LAYOUT_PACKED) ?
935 (basicTypeNdx % 2 == 0 ? DECLARE_VERTEX : DECLARE_FRAGMENT) :
936 DECLARE_BOTH);
937
938 if (glu::isDataTypeBoolOrBVec(type))
939 layoutGroup->addChild(new BlockBasicTypeCase(m_context, typeName, "", m_glslVersion,
940 VarType(type, 0), flags, 0 /* no instance array */));
941 else
942 {
943 for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisionFlags); precNdx++)
944 layoutGroup->addChild(new BlockBasicTypeCase(
945 m_context, (string(precisionFlags[precNdx].name) + "_" + typeName).c_str(), "",
946 m_glslVersion, VarType(type, precisionFlags[precNdx].flags), flags,
947 0 /* no instance array */));
948 }
949
950 if (glu::isDataTypeMatrix(type))
951 {
952 for (int matFlagNdx = 0; matFlagNdx < DE_LENGTH_OF_ARRAY(matrixFlags); matFlagNdx++)
953 {
954 for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisionFlags); precNdx++)
955 layoutGroup->addChild(new BlockBasicTypeCase(
956 m_context,
957 (string(matrixFlags[matFlagNdx].name) + "_" + precisionFlags[precNdx].name + "_" +
958 typeName)
959 .c_str(),
960 "", m_glslVersion, VarType(type, precisionFlags[precNdx].flags),
961 flags | matrixFlags[matFlagNdx].flags, 0 /* no instance array */));
962 }
963 }
964 }
965 }
966 }
967
968 // ubo.single_basic_array
969 {
970 tcu::TestCaseGroup *singleBasicArrayGroup =
971 new tcu::TestCaseGroup(m_testCtx, "single_basic_array", "Single basic array variable in single buffer");
972 addChild(singleBasicArrayGroup);
973
974 for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
975 {
976 tcu::TestCaseGroup *layoutGroup = new tcu::TestCaseGroup(m_testCtx, layoutFlags[layoutFlagNdx].name, "");
977 singleBasicArrayGroup->addChild(layoutGroup);
978
979 for (int basicTypeNdx = 0; basicTypeNdx < DE_LENGTH_OF_ARRAY(basicTypes); basicTypeNdx++)
980 {
981 glu::DataType type = basicTypes[basicTypeNdx];
982 const char *typeName = glu::getDataTypeName(type);
983 const int arraySize = 3;
984 uint32_t baseFlags = layoutFlags[layoutFlagNdx].flags;
985 uint32_t flags = baseFlags | ((baseFlags & LAYOUT_PACKED) ?
986 (basicTypeNdx % 2 == 0 ? DECLARE_VERTEX : DECLARE_FRAGMENT) :
987 DECLARE_BOTH);
988
989 layoutGroup->addChild(new BlockBasicTypeCase(
990 m_context, typeName, "", m_glslVersion,
991 VarType(VarType(type, glu::isDataTypeBoolOrBVec(type) ? 0 : PRECISION_HIGH), arraySize), flags,
992 0 /* no instance array */));
993
994 if (glu::isDataTypeMatrix(type))
995 {
996 for (int matFlagNdx = 0; matFlagNdx < DE_LENGTH_OF_ARRAY(matrixFlags); matFlagNdx++)
997 layoutGroup->addChild(new BlockBasicTypeCase(
998 m_context, (string(matrixFlags[matFlagNdx].name) + "_" + typeName).c_str(), "",
999 m_glslVersion, VarType(VarType(type, PRECISION_HIGH), arraySize),
1000 flags | matrixFlags[matFlagNdx].flags, 0 /* no instance array */));
1001 }
1002 }
1003 }
1004 }
1005
1006 // ubo.single_struct
1007 {
1008 tcu::TestCaseGroup *singleStructGroup =
1009 new tcu::TestCaseGroup(m_testCtx, "single_struct", "Single struct in uniform block");
1010 addChild(singleStructGroup);
1011
1012 for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
1013 {
1014 for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
1015 {
1016 for (int isArray = 0; isArray < 2; isArray++)
1017 {
1018 std::string name = std::string(bufferModes[modeNdx].name) + "_" + layoutFlags[layoutFlagNdx].name;
1019 uint32_t baseFlags = layoutFlags[layoutFlagNdx].flags;
1020 uint32_t flags = baseFlags | ((baseFlags & LAYOUT_PACKED) ? DECLARE_VERTEX : DECLARE_BOTH);
1021
1022 if (bufferModes[modeNdx].mode == UniformBlockCase::BUFFERMODE_SINGLE && isArray == 0)
1023 continue; // Doesn't make sense to add this variant.
1024
1025 if (isArray)
1026 name += "_instance_array";
1027
1028 singleStructGroup->addChild(new BlockSingleStructCase(
1029 m_context, name.c_str(), "", m_glslVersion, flags, bufferModes[modeNdx].mode, isArray ? 3 : 0));
1030 }
1031 }
1032 }
1033 }
1034
1035 // ubo.single_struct_array
1036 {
1037 tcu::TestCaseGroup *singleStructArrayGroup =
1038 new tcu::TestCaseGroup(m_testCtx, "single_struct_array", "Struct array in one uniform block");
1039 addChild(singleStructArrayGroup);
1040
1041 for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
1042 {
1043 for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
1044 {
1045 for (int isArray = 0; isArray < 2; isArray++)
1046 {
1047 std::string name = std::string(bufferModes[modeNdx].name) + "_" + layoutFlags[layoutFlagNdx].name;
1048 uint32_t baseFlags = layoutFlags[layoutFlagNdx].flags;
1049 uint32_t flags = baseFlags | ((baseFlags & LAYOUT_PACKED) ? DECLARE_FRAGMENT : DECLARE_BOTH);
1050
1051 if (bufferModes[modeNdx].mode == UniformBlockCase::BUFFERMODE_SINGLE && isArray == 0)
1052 continue; // Doesn't make sense to add this variant.
1053
1054 if (isArray)
1055 name += "_instance_array";
1056
1057 singleStructArrayGroup->addChild(new BlockSingleStructArrayCase(
1058 m_context, name.c_str(), "", m_glslVersion, flags, bufferModes[modeNdx].mode, isArray ? 3 : 0));
1059 }
1060 }
1061 }
1062 }
1063
1064 // ubo.single_nested_struct
1065 {
1066 tcu::TestCaseGroup *singleNestedStructGroup =
1067 new tcu::TestCaseGroup(m_testCtx, "single_nested_struct", "Nested struct in one uniform block");
1068 addChild(singleNestedStructGroup);
1069
1070 for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
1071 {
1072 for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
1073 {
1074 for (int isArray = 0; isArray < 2; isArray++)
1075 {
1076 std::string name = std::string(bufferModes[modeNdx].name) + "_" + layoutFlags[layoutFlagNdx].name;
1077 uint32_t baseFlags = layoutFlags[layoutFlagNdx].flags;
1078 uint32_t flags = baseFlags | ((baseFlags & LAYOUT_PACKED) ? DECLARE_VERTEX : DECLARE_BOTH);
1079
1080 if (bufferModes[modeNdx].mode == UniformBlockCase::BUFFERMODE_SINGLE && isArray == 0)
1081 continue; // Doesn't make sense to add this variant.
1082
1083 if (isArray)
1084 name += "_instance_array";
1085
1086 singleNestedStructGroup->addChild(new BlockSingleNestedStructCase(
1087 m_context, name.c_str(), "", m_glslVersion, flags, bufferModes[modeNdx].mode, isArray ? 3 : 0));
1088 }
1089 }
1090 }
1091 }
1092
1093 // ubo.single_nested_struct_array
1094 {
1095 tcu::TestCaseGroup *singleNestedStructArrayGroup =
1096 new tcu::TestCaseGroup(m_testCtx, "single_nested_struct_array", "Nested struct array in one uniform block");
1097 addChild(singleNestedStructArrayGroup);
1098
1099 for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
1100 {
1101 for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
1102 {
1103 for (int isArray = 0; isArray < 2; isArray++)
1104 {
1105 std::string name = std::string(bufferModes[modeNdx].name) + "_" + layoutFlags[layoutFlagNdx].name;
1106 uint32_t baseFlags = layoutFlags[layoutFlagNdx].flags;
1107 uint32_t flags = baseFlags | ((baseFlags & LAYOUT_PACKED) ? DECLARE_FRAGMENT : DECLARE_BOTH);
1108
1109 if (bufferModes[modeNdx].mode == UniformBlockCase::BUFFERMODE_SINGLE && isArray == 0)
1110 continue; // Doesn't make sense to add this variant.
1111
1112 if (isArray)
1113 name += "_instance_array";
1114
1115 singleNestedStructArrayGroup->addChild(new BlockSingleNestedStructArrayCase(
1116 m_context, name.c_str(), "", m_glslVersion, flags, bufferModes[modeNdx].mode, isArray ? 3 : 0));
1117 }
1118 }
1119 }
1120 }
1121
1122 // ubo.instance_array_basic_type
1123 {
1124 tcu::TestCaseGroup *instanceArrayBasicTypeGroup =
1125 new tcu::TestCaseGroup(m_testCtx, "instance_array_basic_type", "Single basic variable in instance array");
1126 addChild(instanceArrayBasicTypeGroup);
1127
1128 for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
1129 {
1130 tcu::TestCaseGroup *layoutGroup = new tcu::TestCaseGroup(m_testCtx, layoutFlags[layoutFlagNdx].name, "");
1131 instanceArrayBasicTypeGroup->addChild(layoutGroup);
1132
1133 for (int basicTypeNdx = 0; basicTypeNdx < DE_LENGTH_OF_ARRAY(basicTypes); basicTypeNdx++)
1134 {
1135 glu::DataType type = basicTypes[basicTypeNdx];
1136 const char *typeName = glu::getDataTypeName(type);
1137 const int numInstances = 3;
1138 uint32_t baseFlags = layoutFlags[layoutFlagNdx].flags;
1139 uint32_t flags = baseFlags | ((baseFlags & LAYOUT_PACKED) ?
1140 (basicTypeNdx % 2 == 0 ? DECLARE_VERTEX : DECLARE_FRAGMENT) :
1141 DECLARE_BOTH);
1142
1143 layoutGroup->addChild(new BlockBasicTypeCase(
1144 m_context, typeName, "", m_glslVersion,
1145 VarType(type, glu::isDataTypeBoolOrBVec(type) ? 0 : PRECISION_HIGH), flags, numInstances));
1146
1147 if (glu::isDataTypeMatrix(type))
1148 {
1149 for (int matFlagNdx = 0; matFlagNdx < DE_LENGTH_OF_ARRAY(matrixFlags); matFlagNdx++)
1150 layoutGroup->addChild(new BlockBasicTypeCase(
1151 m_context, (string(matrixFlags[matFlagNdx].name) + "_" + typeName).c_str(), "",
1152 m_glslVersion, VarType(type, PRECISION_HIGH), flags | matrixFlags[matFlagNdx].flags,
1153 numInstances));
1154 }
1155 }
1156 }
1157 }
1158
1159 // ubo.multi_basic_types
1160 {
1161 tcu::TestCaseGroup *multiBasicTypesGroup =
1162 new tcu::TestCaseGroup(m_testCtx, "multi_basic_types", "Multiple buffers with basic types");
1163 addChild(multiBasicTypesGroup);
1164
1165 for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
1166 {
1167 tcu::TestCaseGroup *modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, "");
1168 multiBasicTypesGroup->addChild(modeGroup);
1169
1170 for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
1171 {
1172 for (int isArray = 0; isArray < 2; isArray++)
1173 {
1174 std::string baseName = layoutFlags[layoutFlagNdx].name;
1175 uint32_t baseFlags = layoutFlags[layoutFlagNdx].flags;
1176
1177 if (isArray)
1178 baseName += "_instance_array";
1179
1180 modeGroup->addChild(new BlockMultiBasicTypesCase(
1181 m_context, (baseName + "_mixed").c_str(), "", m_glslVersion, baseFlags | DECLARE_VERTEX,
1182 baseFlags | DECLARE_FRAGMENT, bufferModes[modeNdx].mode, isArray ? 3 : 0));
1183
1184 if (!(baseFlags & LAYOUT_PACKED))
1185 modeGroup->addChild(new BlockMultiBasicTypesCase(
1186 m_context, (baseName + "_both").c_str(), "", m_glslVersion,
1187 baseFlags | DECLARE_VERTEX | DECLARE_FRAGMENT,
1188 baseFlags | DECLARE_VERTEX | DECLARE_FRAGMENT, bufferModes[modeNdx].mode, isArray ? 3 : 0));
1189 }
1190 }
1191 }
1192 }
1193
1194 // ubo.multi_nested_struct
1195 {
1196 tcu::TestCaseGroup *multiNestedStructGroup =
1197 new tcu::TestCaseGroup(m_testCtx, "multi_nested_struct", "Multiple buffers with nested structs");
1198 addChild(multiNestedStructGroup);
1199
1200 for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
1201 {
1202 tcu::TestCaseGroup *modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, "");
1203 multiNestedStructGroup->addChild(modeGroup);
1204
1205 for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
1206 {
1207 for (int isArray = 0; isArray < 2; isArray++)
1208 {
1209 std::string baseName = layoutFlags[layoutFlagNdx].name;
1210 uint32_t baseFlags = layoutFlags[layoutFlagNdx].flags;
1211
1212 if (isArray)
1213 baseName += "_instance_array";
1214
1215 modeGroup->addChild(new BlockMultiNestedStructCase(
1216 m_context, (baseName + "_mixed").c_str(), "", m_glslVersion, baseFlags | DECLARE_VERTEX,
1217 baseFlags | DECLARE_FRAGMENT, bufferModes[modeNdx].mode, isArray ? 3 : 0));
1218
1219 if (!(baseFlags & LAYOUT_PACKED))
1220 modeGroup->addChild(new BlockMultiNestedStructCase(
1221 m_context, (baseName + "_both").c_str(), "", m_glslVersion,
1222 baseFlags | DECLARE_VERTEX | DECLARE_FRAGMENT,
1223 baseFlags | DECLARE_VERTEX | DECLARE_FRAGMENT, bufferModes[modeNdx].mode, isArray ? 3 : 0));
1224 }
1225 }
1226 }
1227 }
1228
1229 // ubo.random
1230 {
1231 const uint32_t allShaders = FEATURE_VERTEX_BLOCKS | FEATURE_FRAGMENT_BLOCKS | FEATURE_SHARED_BLOCKS;
1232 const uint32_t allLayouts = FEATURE_PACKED_LAYOUT | FEATURE_SHARED_LAYOUT | FEATURE_STD140_LAYOUT;
1233 const uint32_t allBasicTypes = FEATURE_VECTORS | FEATURE_MATRICES;
1234 const uint32_t unused = FEATURE_UNUSED_MEMBERS | FEATURE_UNUSED_UNIFORMS;
1235 const uint32_t matFlags = FEATURE_MATRIX_LAYOUT;
1236
1237 tcu::TestCaseGroup *randomGroup = new tcu::TestCaseGroup(m_testCtx, "random", "Random Uniform Block cases");
1238 addChild(randomGroup);
1239
1240 // Basic types.
1241 createRandomCaseGroup(randomGroup, m_context, "scalar_types", "Scalar types only, per-block buffers",
1242 m_glslVersion, UniformBlockCase::BUFFERMODE_PER_BLOCK, allShaders | allLayouts | unused,
1243 10, 0);
1244 createRandomCaseGroup(randomGroup, m_context, "vector_types", "Scalar and vector types only, per-block buffers",
1245 m_glslVersion, UniformBlockCase::BUFFERMODE_PER_BLOCK,
1246 allShaders | allLayouts | unused | FEATURE_VECTORS, 10, 25);
1247 createRandomCaseGroup(randomGroup, m_context, "basic_types", "All basic types, per-block buffers",
1248 m_glslVersion, UniformBlockCase::BUFFERMODE_PER_BLOCK,
1249 allShaders | allLayouts | unused | allBasicTypes | matFlags, 10, 50);
1250 createRandomCaseGroup(randomGroup, m_context, "basic_arrays", "Arrays, per-block buffers", m_glslVersion,
1251 UniformBlockCase::BUFFERMODE_PER_BLOCK,
1252 allShaders | allLayouts | unused | allBasicTypes | matFlags | FEATURE_ARRAYS, 10, 50);
1253
1254 createRandomCaseGroup(
1255 randomGroup, m_context, "basic_instance_arrays", "Basic instance arrays, per-block buffers", m_glslVersion,
1256 UniformBlockCase::BUFFERMODE_PER_BLOCK,
1257 allShaders | allLayouts | unused | allBasicTypes | matFlags | FEATURE_INSTANCE_ARRAYS, 10, 75);
1258 createRandomCaseGroup(randomGroup, m_context, "nested_structs", "Nested structs, per-block buffers",
1259 m_glslVersion, UniformBlockCase::BUFFERMODE_PER_BLOCK,
1260 allShaders | allLayouts | unused | allBasicTypes | matFlags | FEATURE_STRUCTS, 10, 100);
1261 createRandomCaseGroup(
1262 randomGroup, m_context, "nested_structs_arrays", "Nested structs, arrays, per-block buffers", m_glslVersion,
1263 UniformBlockCase::BUFFERMODE_PER_BLOCK,
1264 allShaders | allLayouts | unused | allBasicTypes | matFlags | FEATURE_STRUCTS | FEATURE_ARRAYS, 10, 150);
1265 createRandomCaseGroup(
1266 randomGroup, m_context, "nested_structs_instance_arrays",
1267 "Nested structs, instance arrays, per-block buffers", m_glslVersion, UniformBlockCase::BUFFERMODE_PER_BLOCK,
1268 allShaders | allLayouts | unused | allBasicTypes | matFlags | FEATURE_STRUCTS | FEATURE_INSTANCE_ARRAYS, 10,
1269 125);
1270 createRandomCaseGroup(randomGroup, m_context, "nested_structs_arrays_instance_arrays",
1271 "Nested structs, instance arrays, per-block buffers", m_glslVersion,
1272 UniformBlockCase::BUFFERMODE_PER_BLOCK,
1273 allShaders | allLayouts | unused | allBasicTypes | matFlags | FEATURE_STRUCTS |
1274 FEATURE_ARRAYS | FEATURE_INSTANCE_ARRAYS,
1275 10, 175);
1276
1277 createRandomCaseGroup(randomGroup, m_context, "all_per_block_buffers", "All random features, per-block buffers",
1278 m_glslVersion, UniformBlockCase::BUFFERMODE_PER_BLOCK, ~0u, 20, 200);
1279 createRandomCaseGroup(randomGroup, m_context, "all_shared_buffer", "All random features, shared buffer",
1280 m_glslVersion, UniformBlockCase::BUFFERMODE_SINGLE, ~0u, 20, 250);
1281 }
1282
1283 // ubo.common
1284 if (glu::isGLSLVersionSupported(m_context.getRenderContext().getType(), glu::GLSL_VERSION_300_ES))
1285 {
1286 tcu::TestCaseGroup *commonGroup = new tcu::TestCaseGroup(m_testCtx, "common", "Common Uniform Block cases");
1287 addChild(commonGroup);
1288 commonGroup->addChild(new UniformBlockPrecisionMatching(m_context, m_glslVersion));
1289 commonGroup->addChild(new UniformBlockNameMatching(m_context, m_glslVersion));
1290 }
1291 else if (glu::isGLSLVersionSupported(m_context.getRenderContext().getType(), glu::GLSL_VERSION_150))
1292 {
1293 tcu::TestCaseGroup *commonGroup = new tcu::TestCaseGroup(m_testCtx, "common", "Common Uniform Block cases");
1294 addChild(commonGroup);
1295 commonGroup->addChild(new UniformBlockNameMatching(m_context, m_glslVersion));
1296 }
1297 }
1298
1299 } // namespace deqp
1300