1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2015 The Khronos Group Inc.
6 * Copyright (c) 2015 Samsung Electronics Co., Ltd.
7 * Copyright (c) 2016 The Android Open Source Project
8 *
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
12 *
13 * http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
20 *
21 *//*!
22 * \file
23 * \brief Random uniform block layout case.
24 *//*--------------------------------------------------------------------*/
25
26 #include "vktRandomUniformBlockCase.hpp"
27 #include "deRandom.hpp"
28
29 namespace vkt
30 {
31 namespace ubo
32 {
33
34 namespace
35 {
36
genName(char first,char last,int ndx)37 static std::string genName (char first, char last, int ndx)
38 {
39 std::string str = "";
40 int alphabetLen = last - first + 1;
41
42 while (ndx > alphabetLen)
43 {
44 str.insert(str.begin(), (char)(first + ((ndx - 1) % alphabetLen)));
45 ndx = (ndx - 1) / alphabetLen;
46 }
47
48 str.insert(str.begin(), (char)(first + (ndx % (alphabetLen + 1)) - 1));
49
50 return str;
51 }
52
53 } // anonymous
54
RandomUniformBlockCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,BufferMode bufferMode,deUint32 features,deUint32 seed)55 RandomUniformBlockCase::RandomUniformBlockCase (tcu::TestContext& testCtx,
56 const std::string& name,
57 const std::string& description,
58 BufferMode bufferMode,
59 deUint32 features,
60 deUint32 seed)
61 : UniformBlockCase (testCtx, name, description, bufferMode, LOAD_FULL_MATRIX, (features & FEATURE_OUT_OF_ORDER_OFFSETS) != 0u)
62 , m_features (features)
63 , m_maxVertexBlocks ((features & FEATURE_VERTEX_BLOCKS) ? 4 : 0)
64 , m_maxFragmentBlocks ((features & FEATURE_FRAGMENT_BLOCKS) ? 4 : 0)
65 , m_maxSharedBlocks ((features & FEATURE_SHARED_BLOCKS) ? 4 : 0)
66 , m_maxInstances ((features & FEATURE_INSTANCE_ARRAYS) ? 3 : 0)
67 , m_maxArrayLength ((features & FEATURE_ARRAYS) ? 8 : 0)
68 , m_maxStructDepth ((features & FEATURE_STRUCTS) ? 2 : 0)
69 , m_maxBlockMembers (5)
70 , m_maxStructMembers (4)
71 , m_seed (seed)
72 , m_blockNdx (1)
73 , m_uniformNdx (1)
74 , m_structNdx (1)
75 , m_availableDescriptorUniformBuffers (12)
76 {
77 de::Random rnd(m_seed);
78
79 int numShared = m_maxSharedBlocks > 0 ? rnd.getInt(1, m_maxSharedBlocks) : 0;
80 int numVtxBlocks = m_maxVertexBlocks-numShared > 0 ? rnd.getInt(1, m_maxVertexBlocks - numShared) : 0;
81 int numFragBlocks = m_maxFragmentBlocks-numShared > 0 ? rnd.getInt(1, m_maxFragmentBlocks - numShared): 0;
82
83 // calculate how many additional descriptors we can use for arrays
84 // this is needed for descriptor_indexing testing as we need to take in to account
85 // maxPerStageDescriptorUniformBuffers limit and we can't query it as we need to
86 // generate shaders before Context is created; minimal value of this limit is 12
87 m_availableDescriptorUniformBuffers -= numVtxBlocks + numFragBlocks;
88
89 for (int ndx = 0; ndx < numShared; ndx++)
90 generateBlock(rnd, DECLARE_VERTEX | DECLARE_FRAGMENT);
91
92 for (int ndx = 0; ndx < numVtxBlocks; ndx++)
93 generateBlock(rnd, DECLARE_VERTEX);
94
95 for (int ndx = 0; ndx < numFragBlocks; ndx++)
96 generateBlock(rnd, DECLARE_FRAGMENT);
97
98 init();
99 }
100
generateBlock(de::Random & rnd,deUint32 layoutFlags)101 void RandomUniformBlockCase::generateBlock (de::Random& rnd, deUint32 layoutFlags)
102 {
103 DE_ASSERT(m_blockNdx <= 'z' - 'a');
104
105 const float instanceArrayWeight = 0.3f;
106 UniformBlock& block = m_interface.allocBlock(std::string("Block") + (char)('A' + m_blockNdx));
107 int numInstances = (m_maxInstances > 0 && rnd.getFloat() < instanceArrayWeight) ? rnd.getInt(0, m_maxInstances) : 0;
108 int numUniforms = rnd.getInt(1, m_maxBlockMembers);
109
110 if (m_features & FEATURE_DESCRIPTOR_INDEXING)
111 {
112 // generate arrays only when we are within the limit
113 if (m_availableDescriptorUniformBuffers > 3)
114 numInstances = rnd.getInt(2, 4);
115 else if (m_availableDescriptorUniformBuffers > 1)
116 numInstances = m_availableDescriptorUniformBuffers;
117 else
118 numInstances = 0;
119 m_availableDescriptorUniformBuffers -= numInstances;
120 }
121
122 if (numInstances > 0)
123 block.setArraySize(numInstances);
124
125 if (numInstances > 0 || rnd.getBool())
126 block.setInstanceName(std::string("block") + (char)('A' + m_blockNdx));
127
128 // Layout flag candidates.
129 std::vector<deUint32> layoutFlagCandidates;
130 layoutFlagCandidates.push_back(0);
131
132 if (m_features & FEATURE_STD140_LAYOUT)
133 layoutFlagCandidates.push_back(LAYOUT_STD140);
134
135 if (m_features & FEATURE_STD430_LAYOUT)
136 layoutFlagCandidates.push_back(LAYOUT_STD430);
137
138 if (m_features & FEATURE_SCALAR_LAYOUT)
139 layoutFlagCandidates.push_back(LAYOUT_SCALAR);
140
141 if (m_features & FEATURE_16BIT_STORAGE)
142 layoutFlags |= LAYOUT_16BIT_STORAGE;
143
144 if (m_features & FEATURE_8BIT_STORAGE)
145 layoutFlags |= LAYOUT_8BIT_STORAGE;
146
147 if (m_features & FEATURE_DESCRIPTOR_INDEXING)
148 layoutFlags |= LAYOUT_DESCRIPTOR_INDEXING;
149
150 layoutFlags |= rnd.choose<deUint32>(layoutFlagCandidates.begin(), layoutFlagCandidates.end());
151
152 if (m_features & FEATURE_MATRIX_LAYOUT)
153 {
154 static const deUint32 matrixCandidates[] = { 0, LAYOUT_ROW_MAJOR, LAYOUT_COLUMN_MAJOR };
155 layoutFlags |= rnd.choose<deUint32>(&matrixCandidates[0], &matrixCandidates[DE_LENGTH_OF_ARRAY(matrixCandidates)]);
156 }
157
158 block.setFlags(layoutFlags);
159
160 for (int ndx = 0; ndx < numUniforms; ndx++)
161 generateUniform(rnd, block);
162
163 m_blockNdx += 1;
164 }
165
generateUniform(de::Random & rnd,UniformBlock & block)166 void RandomUniformBlockCase::generateUniform (de::Random& rnd, UniformBlock& block)
167 {
168 const float unusedVtxWeight = 0.15f;
169 const float unusedFragWeight = 0.15f;
170 bool unusedOk = (m_features & FEATURE_UNUSED_UNIFORMS) != 0;
171 deUint32 flags = 0;
172 std::string name = genName('a', 'z', m_uniformNdx);
173 VarType type = generateType(rnd, 0, true);
174
175 flags |= (unusedOk && rnd.getFloat() < unusedVtxWeight) ? UNUSED_VERTEX : 0;
176 flags |= (unusedOk && rnd.getFloat() < unusedFragWeight) ? UNUSED_FRAGMENT : 0;
177
178 block.addUniform(Uniform(name, type, flags));
179
180 m_uniformNdx += 1;
181 }
182
generateType(de::Random & rnd,int typeDepth,bool arrayOk)183 VarType RandomUniformBlockCase::generateType (de::Random& rnd, int typeDepth, bool arrayOk)
184 {
185 const float structWeight = 0.1f;
186 const float arrayWeight = 0.1f;
187
188 if (typeDepth < m_maxStructDepth && rnd.getFloat() < structWeight)
189 {
190 const float unusedVtxWeight = 0.15f;
191 const float unusedFragWeight = 0.15f;
192 bool unusedOk = (m_features & FEATURE_UNUSED_MEMBERS) != 0;
193 std::vector<VarType> memberTypes;
194 int numMembers = rnd.getInt(1, m_maxStructMembers);
195
196 // Generate members first so nested struct declarations are in correct order.
197 for (int ndx = 0; ndx < numMembers; ndx++)
198 memberTypes.push_back(generateType(rnd, typeDepth+1, true));
199
200 StructType& structType = m_interface.allocStruct(std::string("s") + genName('A', 'Z', m_structNdx));
201 m_structNdx += 1;
202
203 DE_ASSERT(numMembers <= 'Z' - 'A');
204 for (int ndx = 0; ndx < numMembers; ndx++)
205 {
206 deUint32 flags = 0;
207
208 flags |= (unusedOk && rnd.getFloat() < unusedVtxWeight) ? UNUSED_VERTEX : 0;
209 flags |= (unusedOk && rnd.getFloat() < unusedFragWeight) ? UNUSED_FRAGMENT : 0;
210
211 structType.addMember(std::string("m") + (char)('A' + ndx), memberTypes[ndx], flags);
212 }
213
214 return VarType(&structType, m_shuffleUniformMembers ? static_cast<deUint32>(LAYOUT_OFFSET) : 0u);
215 }
216 else if (m_maxArrayLength > 0 && arrayOk && rnd.getFloat() < arrayWeight)
217 {
218 const bool arraysOfArraysOk = (m_features & FEATURE_ARRAYS_OF_ARRAYS) != 0;
219 const int arrayLength = rnd.getInt(1, m_maxArrayLength);
220 VarType elementType = generateType(rnd, typeDepth, arraysOfArraysOk);
221 return VarType(elementType, arrayLength);
222 }
223 else
224 {
225 std::vector<glu::DataType> typeCandidates;
226
227 typeCandidates.push_back(glu::TYPE_FLOAT);
228 typeCandidates.push_back(glu::TYPE_INT);
229 typeCandidates.push_back(glu::TYPE_UINT);
230 typeCandidates.push_back(glu::TYPE_BOOL);
231
232 if (m_features & FEATURE_16BIT_STORAGE) {
233 typeCandidates.push_back(glu::TYPE_UINT16);
234 typeCandidates.push_back(glu::TYPE_INT16);
235 typeCandidates.push_back(glu::TYPE_FLOAT16);
236 }
237
238 if (m_features & FEATURE_8BIT_STORAGE) {
239 typeCandidates.push_back(glu::TYPE_UINT8);
240 typeCandidates.push_back(glu::TYPE_INT8);
241 }
242
243 if (m_features & FEATURE_VECTORS)
244 {
245 typeCandidates.push_back(glu::TYPE_FLOAT_VEC2);
246 typeCandidates.push_back(glu::TYPE_FLOAT_VEC3);
247 typeCandidates.push_back(glu::TYPE_FLOAT_VEC4);
248 typeCandidates.push_back(glu::TYPE_INT_VEC2);
249 typeCandidates.push_back(glu::TYPE_INT_VEC3);
250 typeCandidates.push_back(glu::TYPE_INT_VEC4);
251 typeCandidates.push_back(glu::TYPE_UINT_VEC2);
252 typeCandidates.push_back(glu::TYPE_UINT_VEC3);
253 typeCandidates.push_back(glu::TYPE_UINT_VEC4);
254 typeCandidates.push_back(glu::TYPE_BOOL_VEC2);
255 typeCandidates.push_back(glu::TYPE_BOOL_VEC3);
256 typeCandidates.push_back(glu::TYPE_BOOL_VEC4);
257 if (m_features & FEATURE_16BIT_STORAGE)
258 {
259 typeCandidates.push_back(glu::TYPE_FLOAT16_VEC2);
260 typeCandidates.push_back(glu::TYPE_FLOAT16_VEC3);
261 typeCandidates.push_back(glu::TYPE_FLOAT16_VEC4);
262 typeCandidates.push_back(glu::TYPE_INT16_VEC2);
263 typeCandidates.push_back(glu::TYPE_INT16_VEC3);
264 typeCandidates.push_back(glu::TYPE_INT16_VEC4);
265 typeCandidates.push_back(glu::TYPE_UINT16_VEC2);
266 typeCandidates.push_back(glu::TYPE_UINT16_VEC3);
267 typeCandidates.push_back(glu::TYPE_UINT16_VEC4);
268 }
269 if (m_features & FEATURE_8BIT_STORAGE)
270 {
271 typeCandidates.push_back(glu::TYPE_INT8_VEC2);
272 typeCandidates.push_back(glu::TYPE_INT8_VEC3);
273 typeCandidates.push_back(glu::TYPE_INT8_VEC4);
274 typeCandidates.push_back(glu::TYPE_UINT8_VEC2);
275 typeCandidates.push_back(glu::TYPE_UINT8_VEC3);
276 typeCandidates.push_back(glu::TYPE_UINT8_VEC4);
277 }
278 }
279
280 if (m_features & FEATURE_MATRICES)
281 {
282 typeCandidates.push_back(glu::TYPE_FLOAT_MAT2);
283 typeCandidates.push_back(glu::TYPE_FLOAT_MAT2X3);
284 typeCandidates.push_back(glu::TYPE_FLOAT_MAT3X2);
285 typeCandidates.push_back(glu::TYPE_FLOAT_MAT3);
286 typeCandidates.push_back(glu::TYPE_FLOAT_MAT3X4);
287 typeCandidates.push_back(glu::TYPE_FLOAT_MAT4X2);
288 typeCandidates.push_back(glu::TYPE_FLOAT_MAT4X3);
289 typeCandidates.push_back(glu::TYPE_FLOAT_MAT4);
290 }
291
292 glu::DataType type = rnd.choose<glu::DataType>(typeCandidates.begin(), typeCandidates.end());
293 deUint32 flags = (m_shuffleUniformMembers ? static_cast<deUint32>(LAYOUT_OFFSET) : 0u);
294
295 if (glu::dataTypeSupportsPrecisionModifier(type))
296 {
297 // Precision.
298 static const deUint32 precisionCandidates[] = { PRECISION_LOW, PRECISION_MEDIUM, PRECISION_HIGH };
299 flags |= rnd.choose<deUint32>(&precisionCandidates[0], &precisionCandidates[DE_LENGTH_OF_ARRAY(precisionCandidates)]);
300 }
301
302 return VarType(type, flags);
303 }
304 }
305
306 } // ubo
307 } // vkt
308