1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL (ES) Module
3 * -----------------------------------------------
4 *
5 * Copyright 2014 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief Random uniform block layout case.
22 *//*--------------------------------------------------------------------*/
23
24 #include "glsRandomUniformBlockCase.hpp"
25 #include "tcuCommandLine.hpp"
26 #include "deRandom.hpp"
27 #include "deStringUtil.hpp"
28
29 using std::string;
30 using std::vector;
31
32 namespace deqp
33 {
34 namespace gls
35 {
36
37 using namespace gls::ub;
38
RandomUniformBlockCase(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,glu::GLSLVersion glslVersion,const char * name,const char * description,BufferMode bufferMode,uint32_t features,uint32_t seed)39 RandomUniformBlockCase::RandomUniformBlockCase(tcu::TestContext &testCtx, glu::RenderContext &renderCtx,
40 glu::GLSLVersion glslVersion, const char *name, const char *description,
41 BufferMode bufferMode, uint32_t features, uint32_t seed)
42 : UniformBlockCase(testCtx, renderCtx, name, description, glslVersion, bufferMode)
43 , m_features(features)
44 , m_maxVertexBlocks((features & FEATURE_VERTEX_BLOCKS) ? 4 : 0)
45 , m_maxFragmentBlocks((features & FEATURE_FRAGMENT_BLOCKS) ? 4 : 0)
46 , m_maxSharedBlocks((features & FEATURE_SHARED_BLOCKS) ? 4 : 0)
47 , m_maxInstances((features & FEATURE_INSTANCE_ARRAYS) ? 3 : 0)
48 , m_maxArrayLength((features & FEATURE_ARRAYS) ? 8 : 0)
49 , m_maxStructDepth((features & FEATURE_STRUCTS) ? 2 : 0)
50 , m_maxBlockMembers(5)
51 , m_maxStructMembers(4)
52 , m_seed(seed)
53 , m_blockNdx(1)
54 , m_uniformNdx(1)
55 , m_structNdx(1)
56 {
57 }
58
init(void)59 void RandomUniformBlockCase::init(void)
60 {
61 de::Random rnd(m_seed);
62
63 int numShared = m_maxSharedBlocks > 0 ? rnd.getInt(1, m_maxSharedBlocks) : 0;
64 int numVtxBlocks = m_maxVertexBlocks - numShared > 0 ? rnd.getInt(1, m_maxVertexBlocks - numShared) : 0;
65 int numFragBlocks = m_maxFragmentBlocks - numShared > 0 ? rnd.getInt(1, m_maxFragmentBlocks - numShared) : 0;
66
67 for (int ndx = 0; ndx < numShared; ndx++)
68 generateBlock(rnd, DECLARE_VERTEX | DECLARE_FRAGMENT);
69
70 for (int ndx = 0; ndx < numVtxBlocks; ndx++)
71 generateBlock(rnd, DECLARE_VERTEX);
72
73 for (int ndx = 0; ndx < numFragBlocks; ndx++)
74 generateBlock(rnd, DECLARE_FRAGMENT);
75 }
76
generateBlock(de::Random & rnd,uint32_t layoutFlags)77 void RandomUniformBlockCase::generateBlock(de::Random &rnd, uint32_t layoutFlags)
78 {
79 DE_ASSERT(m_blockNdx <= 'z' - 'a');
80
81 const float instanceArrayWeight = 0.3f;
82 UniformBlock &block = m_interface.allocBlock((string("Block") + (char)('A' + m_blockNdx)).c_str());
83 int numInstances = (m_maxInstances > 0 && rnd.getFloat() < instanceArrayWeight) ? rnd.getInt(0, m_maxInstances) : 0;
84 int numUniforms = rnd.getInt(1, m_maxBlockMembers);
85
86 if (numInstances > 0)
87 block.setArraySize(numInstances);
88
89 if (numInstances > 0 || rnd.getBool())
90 block.setInstanceName((string("block") + (char)('A' + m_blockNdx)).c_str());
91
92 // Layout flag candidates.
93 vector<uint32_t> layoutFlagCandidates;
94 layoutFlagCandidates.push_back(0);
95 if (m_features & FEATURE_PACKED_LAYOUT)
96 layoutFlagCandidates.push_back(LAYOUT_SHARED);
97 if ((m_features & FEATURE_SHARED_LAYOUT) && ((layoutFlags & DECLARE_BOTH) != DECLARE_BOTH))
98 layoutFlagCandidates.push_back(LAYOUT_PACKED); // \note packed layout can only be used in a single shader stage.
99 if (m_features & FEATURE_STD140_LAYOUT)
100 layoutFlagCandidates.push_back(LAYOUT_STD140);
101
102 layoutFlags |= rnd.choose<uint32_t>(layoutFlagCandidates.begin(), layoutFlagCandidates.end());
103
104 if (m_features & FEATURE_MATRIX_LAYOUT)
105 {
106 static const uint32_t matrixCandidates[] = {0, LAYOUT_ROW_MAJOR, LAYOUT_COLUMN_MAJOR};
107 layoutFlags |=
108 rnd.choose<uint32_t>(&matrixCandidates[0], &matrixCandidates[DE_LENGTH_OF_ARRAY(matrixCandidates)]);
109 }
110
111 block.setFlags(layoutFlags);
112
113 for (int ndx = 0; ndx < numUniforms; ndx++)
114 generateUniform(rnd, block);
115
116 m_blockNdx += 1;
117 }
118
genName(char first,char last,int ndx)119 static std::string genName(char first, char last, int ndx)
120 {
121 std::string str = "";
122 int alphabetLen = last - first + 1;
123
124 while (ndx > alphabetLen)
125 {
126 str.insert(str.begin(), (char)(first + ((ndx - 1) % alphabetLen)));
127 ndx = ((ndx - 1) / alphabetLen);
128 }
129
130 str.insert(str.begin(), (char)(first + (ndx % (alphabetLen + 1)) - 1));
131
132 return str;
133 }
134
generateUniform(de::Random & rnd,UniformBlock & block)135 void RandomUniformBlockCase::generateUniform(de::Random &rnd, UniformBlock &block)
136 {
137 const float unusedVtxWeight = 0.15f;
138 const float unusedFragWeight = 0.15f;
139 bool unusedOk = (m_features & FEATURE_UNUSED_UNIFORMS) != 0;
140 uint32_t flags = 0;
141 std::string name = genName('a', 'z', m_uniformNdx);
142 VarType type = generateType(rnd, 0, true);
143
144 flags |= (unusedOk && rnd.getFloat() < unusedVtxWeight) ? UNUSED_VERTEX : 0;
145 flags |= (unusedOk && rnd.getFloat() < unusedFragWeight) ? UNUSED_FRAGMENT : 0;
146
147 block.addUniform(Uniform(name.c_str(), type, flags));
148
149 m_uniformNdx += 1;
150 }
151
generateType(de::Random & rnd,int typeDepth,bool arrayOk)152 VarType RandomUniformBlockCase::generateType(de::Random &rnd, int typeDepth, bool arrayOk)
153 {
154 const float structWeight = 0.1f;
155 const float arrayWeight = 0.1f;
156
157 if (typeDepth < m_maxStructDepth && rnd.getFloat() < structWeight)
158 {
159 const float unusedVtxWeight = 0.15f;
160 const float unusedFragWeight = 0.15f;
161 bool unusedOk = (m_features & FEATURE_UNUSED_MEMBERS) != 0;
162 vector<VarType> memberTypes;
163 int numMembers = rnd.getInt(1, m_maxStructMembers);
164
165 // Generate members first so nested struct declarations are in correct order.
166 for (int ndx = 0; ndx < numMembers; ndx++)
167 memberTypes.push_back(generateType(rnd, typeDepth + 1, true));
168
169 StructType &structType = m_interface.allocStruct((string("s") + genName('A', 'Z', m_structNdx)).c_str());
170 m_structNdx += 1;
171
172 DE_ASSERT(numMembers <= 'Z' - 'A');
173 for (int ndx = 0; ndx < numMembers; ndx++)
174 {
175 uint32_t flags = 0;
176
177 flags |= (unusedOk && rnd.getFloat() < unusedVtxWeight) ? UNUSED_VERTEX : 0;
178 flags |= (unusedOk && rnd.getFloat() < unusedFragWeight) ? UNUSED_FRAGMENT : 0;
179
180 structType.addMember((string("m") + (char)('A' + ndx)).c_str(), memberTypes[ndx], flags);
181 }
182
183 return VarType(&structType);
184 }
185 else if (m_maxArrayLength > 0 && arrayOk && rnd.getFloat() < arrayWeight)
186 {
187 const bool arraysOfArraysOk = (m_features & FEATURE_ARRAYS_OF_ARRAYS) != 0;
188 const int arrayLength = rnd.getInt(1, m_maxArrayLength);
189 VarType elementType = generateType(rnd, typeDepth, arraysOfArraysOk);
190 return VarType(elementType, arrayLength);
191 }
192 else
193 {
194 vector<glu::DataType> typeCandidates;
195
196 typeCandidates.push_back(glu::TYPE_FLOAT);
197 typeCandidates.push_back(glu::TYPE_INT);
198 typeCandidates.push_back(glu::TYPE_UINT);
199 typeCandidates.push_back(glu::TYPE_BOOL);
200
201 if (m_features & FEATURE_VECTORS)
202 {
203 typeCandidates.push_back(glu::TYPE_FLOAT_VEC2);
204 typeCandidates.push_back(glu::TYPE_FLOAT_VEC3);
205 typeCandidates.push_back(glu::TYPE_FLOAT_VEC4);
206 typeCandidates.push_back(glu::TYPE_INT_VEC2);
207 typeCandidates.push_back(glu::TYPE_INT_VEC3);
208 typeCandidates.push_back(glu::TYPE_INT_VEC4);
209 typeCandidates.push_back(glu::TYPE_UINT_VEC2);
210 typeCandidates.push_back(glu::TYPE_UINT_VEC3);
211 typeCandidates.push_back(glu::TYPE_UINT_VEC4);
212 typeCandidates.push_back(glu::TYPE_BOOL_VEC2);
213 typeCandidates.push_back(glu::TYPE_BOOL_VEC3);
214 typeCandidates.push_back(glu::TYPE_BOOL_VEC4);
215 }
216
217 if (m_features & FEATURE_MATRICES)
218 {
219 typeCandidates.push_back(glu::TYPE_FLOAT_MAT2);
220 typeCandidates.push_back(glu::TYPE_FLOAT_MAT2X3);
221 typeCandidates.push_back(glu::TYPE_FLOAT_MAT3X2);
222 typeCandidates.push_back(glu::TYPE_FLOAT_MAT3);
223 typeCandidates.push_back(glu::TYPE_FLOAT_MAT3X4);
224 typeCandidates.push_back(glu::TYPE_FLOAT_MAT4X2);
225 typeCandidates.push_back(glu::TYPE_FLOAT_MAT4X3);
226 typeCandidates.push_back(glu::TYPE_FLOAT_MAT4);
227 }
228
229 glu::DataType type = rnd.choose<glu::DataType>(typeCandidates.begin(), typeCandidates.end());
230 uint32_t flags = 0;
231
232 if (!glu::isDataTypeBoolOrBVec(type))
233 {
234 // Precision.
235 static const uint32_t precisionCandidates[] = {PRECISION_LOW, PRECISION_MEDIUM, PRECISION_HIGH};
236 flags |= rnd.choose<uint32_t>(&precisionCandidates[0],
237 &precisionCandidates[DE_LENGTH_OF_ARRAY(precisionCandidates)]);
238 }
239
240 return VarType(type, flags);
241 }
242 }
243
244 } // namespace gls
245 } // namespace deqp
246