xref: /aosp_15_r20/external/deqp/external/openglcts/modules/common/glcUniformBlockTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
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