1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2021 The Khronos Group Inc.
6 * Copyright (c) 2021 Google LLC.
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 Shared memory model layout tests.
23 *//*--------------------------------------------------------------------*/
24
25 #include "vktMemoryModelSharedLayout.hpp"
26 #include "vktMemoryModelSharedLayoutCase.hpp"
27
28 #include "tcuCommandLine.hpp"
29 #include "tcuTestLog.hpp"
30 #include "deRandom.hpp"
31 #include "deStringUtil.hpp"
32 #include "vktTestCaseUtil.hpp"
33 #include "vkMemUtil.hpp"
34
35 namespace vkt
36 {
37 namespace MemoryModel
38 {
39 using std::string;
40 using std::vector;
41
42 namespace
43 {
44
45 enum FeatureBits
46 {
47 FEATURE_VECTORS = (1 << 0),
48 FEATURE_MATRICES = (1 << 1),
49 FEATURE_ARRAYS = (1 << 2),
50 FEATURE_STRUCTS = (1 << 3),
51 FEATURE_UNUSED_VARS = (1 << 4),
52 FEATURE_UNUSED_MEMBERS = (1 << 5),
53 FEATURE_ARRAYS_OF_ARRAYS = (1 << 6),
54 FEATURE_16BIT_TYPES = (1 << 7),
55 FEATURE_8BIT_TYPES = (1 << 8),
56 };
57
58 /*--------------------------------------------------------------------*//*!
59 * \brief Generates names for shared memory structs and their members.
60 * \param first The first character of the alphabet.
61 * \param last The last character of the alphabet.
62 * \param ndx The index of the name in the alphabet.
63 *
64 * If the index lies within the range [1, (last-first)+1], returns
65 * the character represented by the ASCII code 'first + ndx - 1'
66 * as a string.
67 *
68 * E.g. if "first" is 'a', "last" 'z' and "ndx" is 1, returns a. If "ndx"
69 * is 2, returns b and so forth.
70 *
71 * If "ndx" is greater than the range, the function keeps dividing it by
72 * the alphabet length until the index is within the range. In each iteration,
73 * the name is prefixed with the ASCII character represented by the modulo
74 * of the index.
75 *
76 * E.g. if "first" is 'a', "last" 'z' and "ndx" is 28, returns ab. If "ndx"
77 * is 702, returns aaa and so forth.
78 *//*--------------------------------------------------------------------*/
genName(char first,char last,int ndx)79 string genName(char first, char last, int ndx)
80 {
81 string str;
82 int alphabetLen = static_cast<int>(last) - static_cast<int>(first) + 1;
83
84 while (ndx > 0)
85 {
86 const int asciiCode = static_cast<int>(first) + ((ndx - 1) % alphabetLen);
87 str.insert(str.begin(), static_cast<char>(asciiCode));
88 ndx = ((ndx - 1) / alphabetLen);
89 }
90
91 return str;
92 }
93
createRandomCaseGroup(tcu::TestCaseGroup * parentGroup,tcu::TestContext & testCtx,const char * groupName,const uint32_t features,const int numCases,uint32_t baseSeed)94 void createRandomCaseGroup(tcu::TestCaseGroup *parentGroup, tcu::TestContext &testCtx, const char *groupName,
95 const uint32_t features, const int numCases, uint32_t baseSeed)
96 {
97 tcu::TestCaseGroup *group = new tcu::TestCaseGroup(testCtx, groupName);
98 parentGroup->addChild(group);
99
100 baseSeed += static_cast<uint32_t>(testCtx.getCommandLine().getBaseSeed());
101
102 for (int i = 0; i < numCases; i++)
103 group->addChild(new RandomSharedLayoutCase(testCtx, de::toString(i).c_str(), features,
104 static_cast<uint32_t>(i + baseSeed)));
105 }
106 } // namespace
107
RandomSharedLayoutCase(tcu::TestContext & testCtx,const char * name,uint32_t features,uint32_t seed)108 RandomSharedLayoutCase::RandomSharedLayoutCase(tcu::TestContext &testCtx, const char *name, uint32_t features,
109 uint32_t seed)
110 : SharedLayoutCase(testCtx, name)
111 , m_features(features)
112 , m_maxArrayLength((features & FEATURE_ARRAYS) ? 3 : 0)
113 , m_seed(seed)
114 {
115 de::Random rnd(m_seed);
116
117 m_interface.enable16BitTypes(features & FEATURE_16BIT_TYPES);
118 m_interface.enable8BitTypes(features & FEATURE_8BIT_TYPES);
119
120 for (int i = 0; i < rnd.getInt(1, m_maxSharedObjects); i++)
121 generateSharedMemoryObject(rnd);
122
123 init();
124 }
125
126 /*--------------------------------------------------------------------*//*!
127 * \brief Creates definitions for shared memory structs.
128 * \param rnd Random value generator used for deciding the type of the variable.
129 *
130 * Creates definitions for shared memory structs. Each struct's name starts with
131 * an upper-case S and its instance name with a lower-case s followed by its index
132 * number.
133 *//*--------------------------------------------------------------------*/
generateSharedMemoryObject(de::Random & rnd)134 void RandomSharedLayoutCase::generateSharedMemoryObject(de::Random &rnd)
135 {
136 const string name = "S" + de::toString(m_interface.getNumSharedObjects() + 1);
137 const string instanceName = "s" + de::toString(m_interface.getNumSharedObjects() + 1);
138 SharedStruct &object = m_interface.allocSharedObject(name, instanceName);
139 const int numVars = rnd.getInt(2, m_maxSharedObjectMembers);
140
141 for (int i = 0; i < numVars; i++)
142 generateSharedMemoryVar(rnd, object);
143 }
144
generateSharedMemoryVar(de::Random & rnd,SharedStruct & object)145 void RandomSharedLayoutCase::generateSharedMemoryVar(de::Random &rnd, SharedStruct &object)
146 {
147 SharedStructVar var;
148 var.name = genName('a', 'z', object.getNumMembers() + 1);
149
150 if ((m_features & FEATURE_ARRAYS_OF_ARRAYS) != 0 || (m_features & FEATURE_STRUCTS) != 0)
151 var.type = generateType(rnd, 3, true);
152 else
153 var.type = generateType(rnd, 1, true);
154
155 var.topLevelArraySize = 1;
156 if (var.type.isArrayType())
157 var.topLevelArraySize = var.type.getArraySize() == glu::VarType::UNSIZED_ARRAY ? 0 : var.type.getArraySize();
158
159 object.addMember(var);
160 }
161
generateType(de::Random & rnd,int typeDepth,bool arrayOk)162 glu::VarType RandomSharedLayoutCase::generateType(de::Random &rnd, int typeDepth, bool arrayOk)
163 {
164 const float structWeight = 0.7f;
165 const float arrayWeight = 0.8f;
166
167 if (typeDepth > 0 && rnd.getFloat() < structWeight && (m_features & FEATURE_STRUCTS))
168 {
169 vector<glu::VarType> memberTypes;
170 const int numMembers = rnd.getInt(1, m_maxStructMembers);
171
172 // Generate members first so nested struct declarations are in correct order.
173 for (int i = 0; i < numMembers; i++)
174 memberTypes.push_back(generateType(rnd, typeDepth - 1, true));
175
176 const string name = "s" + genName('A', 'Z', m_interface.getNumStructs() + 1);
177 de::SharedPtr<glu::StructType> structType = m_interface.allocStruct(name);
178
179 DE_ASSERT(numMembers <= 'Z' - 'A');
180 for (int i = 0; i < numMembers; i++)
181 structType.get()->addMember((string("m") + static_cast<char>(('A' + i))).c_str(), memberTypes[i]);
182
183 return glu::VarType(structType.get());
184 }
185 else if (typeDepth > 0 && m_maxArrayLength > 0 && arrayOk && rnd.getFloat() < arrayWeight)
186 {
187 const int arrayLength = rnd.getInt(1, m_maxArrayLength);
188 const bool childArrayOk = (m_features & FEATURE_ARRAYS_OF_ARRAYS) != 0;
189 const glu::VarType elementType = generateType(rnd, typeDepth - 1, childArrayOk);
190
191 return glu::VarType(elementType, arrayLength);
192 }
193 else
194 {
195 const float weight8Bit = (m_features & FEATURE_8BIT_TYPES) ? 0.7f : 0.0f;
196 const float weight16Bit = (m_features & FEATURE_16BIT_TYPES) ? 0.7f : 0.0f;
197 const float weightMatrices = (m_features & FEATURE_MATRICES) ? 0.3f : 0.0f;
198
199 vector<glu::DataType> typeCandidates;
200 if (rnd.getFloat() < weight16Bit)
201 {
202 typeCandidates.push_back(glu::TYPE_UINT16);
203 typeCandidates.push_back(glu::TYPE_INT16);
204 typeCandidates.push_back(glu::TYPE_FLOAT16);
205
206 if (m_features & FEATURE_VECTORS)
207 {
208 typeCandidates.push_back(glu::TYPE_FLOAT16_VEC2);
209 typeCandidates.push_back(glu::TYPE_FLOAT16_VEC3);
210 typeCandidates.push_back(glu::TYPE_FLOAT16_VEC4);
211 typeCandidates.push_back(glu::TYPE_INT16_VEC2);
212 typeCandidates.push_back(glu::TYPE_INT16_VEC3);
213 typeCandidates.push_back(glu::TYPE_INT16_VEC4);
214 typeCandidates.push_back(glu::TYPE_UINT16_VEC2);
215 typeCandidates.push_back(glu::TYPE_UINT16_VEC3);
216 typeCandidates.push_back(glu::TYPE_UINT16_VEC4);
217 }
218 }
219 else if (rnd.getFloat() < weight8Bit)
220 {
221 typeCandidates.push_back(glu::TYPE_UINT8);
222 typeCandidates.push_back(glu::TYPE_INT8);
223
224 if (m_features & FEATURE_VECTORS)
225 {
226 typeCandidates.push_back(glu::TYPE_INT8_VEC2);
227 typeCandidates.push_back(glu::TYPE_INT8_VEC3);
228 typeCandidates.push_back(glu::TYPE_INT8_VEC4);
229 typeCandidates.push_back(glu::TYPE_UINT8_VEC2);
230 typeCandidates.push_back(glu::TYPE_UINT8_VEC3);
231 typeCandidates.push_back(glu::TYPE_UINT8_VEC4);
232 }
233 }
234 else
235 {
236 typeCandidates.push_back(glu::TYPE_FLOAT);
237 typeCandidates.push_back(glu::TYPE_INT);
238 typeCandidates.push_back(glu::TYPE_UINT);
239 typeCandidates.push_back(glu::TYPE_BOOL);
240
241 if (m_features & FEATURE_VECTORS)
242 {
243 typeCandidates.push_back(glu::TYPE_FLOAT_VEC2);
244 typeCandidates.push_back(glu::TYPE_FLOAT_VEC3);
245 typeCandidates.push_back(glu::TYPE_FLOAT_VEC4);
246 typeCandidates.push_back(glu::TYPE_INT_VEC2);
247 typeCandidates.push_back(glu::TYPE_INT_VEC3);
248 typeCandidates.push_back(glu::TYPE_INT_VEC4);
249 typeCandidates.push_back(glu::TYPE_UINT_VEC2);
250 typeCandidates.push_back(glu::TYPE_UINT_VEC3);
251 typeCandidates.push_back(glu::TYPE_UINT_VEC4);
252 typeCandidates.push_back(glu::TYPE_BOOL_VEC2);
253 typeCandidates.push_back(glu::TYPE_BOOL_VEC3);
254 typeCandidates.push_back(glu::TYPE_BOOL_VEC4);
255 }
256 }
257
258 if (rnd.getFloat() < weightMatrices)
259 {
260 typeCandidates.push_back(glu::TYPE_FLOAT_MAT2);
261 typeCandidates.push_back(glu::TYPE_FLOAT_MAT2X3);
262 typeCandidates.push_back(glu::TYPE_FLOAT_MAT3X2);
263 typeCandidates.push_back(glu::TYPE_FLOAT_MAT3);
264 typeCandidates.push_back(glu::TYPE_FLOAT_MAT3X4);
265 typeCandidates.push_back(glu::TYPE_FLOAT_MAT4X2);
266 typeCandidates.push_back(glu::TYPE_FLOAT_MAT4X3);
267 typeCandidates.push_back(glu::TYPE_FLOAT_MAT4);
268 }
269
270 glu::DataType type = rnd.choose<glu::DataType>(typeCandidates.begin(), typeCandidates.end());
271 glu::Precision precision;
272
273 if (glu::dataTypeSupportsPrecisionModifier(type))
274 {
275 const glu::Precision precisionCandidates[] = {glu::PRECISION_LOWP, glu::PRECISION_MEDIUMP,
276 glu::PRECISION_HIGHP};
277 precision = rnd.choose<glu::Precision>(&precisionCandidates[0],
278 &precisionCandidates[DE_LENGTH_OF_ARRAY(precisionCandidates)]);
279 }
280 else
281 precision = glu::PRECISION_LAST;
282
283 return glu::VarType(type, precision);
284 }
285 }
286
createSharedMemoryLayoutTests(tcu::TestContext & testCtx)287 tcu::TestCaseGroup *createSharedMemoryLayoutTests(tcu::TestContext &testCtx)
288 {
289 de::MovePtr<tcu::TestCaseGroup> sharedMemoryLayoutGroup(new tcu::TestCaseGroup(testCtx, "shared"));
290 tcu::TestCaseGroup *parentGroup = sharedMemoryLayoutGroup.get();
291 {
292 const uint32_t allBasicTypes = FEATURE_VECTORS | FEATURE_MATRICES;
293 const uint32_t unused = FEATURE_UNUSED_MEMBERS | FEATURE_UNUSED_VARS;
294
295 for (int i = 0; i < 3; ++i)
296 {
297 if (i == 1)
298 {
299 parentGroup = new tcu::TestCaseGroup(testCtx, "16bit");
300 sharedMemoryLayoutGroup->addChild(parentGroup);
301 }
302 else if (i == 2)
303 {
304 parentGroup = new tcu::TestCaseGroup(testCtx, "8bit");
305 sharedMemoryLayoutGroup->addChild(parentGroup);
306 }
307 const uint32_t use16BitTypes = i == 1 ? FEATURE_16BIT_TYPES : 0;
308 const uint32_t use8BitTypes = i == 2 ? FEATURE_8BIT_TYPES : 0;
309
310 createRandomCaseGroup(parentGroup, testCtx, "scalar_types", use8BitTypes | use16BitTypes | unused, 10, 0);
311 createRandomCaseGroup(parentGroup, testCtx, "vector_types",
312 use8BitTypes | use16BitTypes | unused | FEATURE_VECTORS, 10, 25);
313 createRandomCaseGroup(parentGroup, testCtx, "basic_types",
314 use8BitTypes | use16BitTypes | unused | allBasicTypes, 10, 50);
315 createRandomCaseGroup(parentGroup, testCtx, "basic_arrays",
316 use8BitTypes | use16BitTypes | unused | allBasicTypes | FEATURE_ARRAYS, 10, 50);
317 createRandomCaseGroup(parentGroup, testCtx, "arrays_of_arrays",
318 use8BitTypes | use16BitTypes | unused | allBasicTypes | FEATURE_ARRAYS |
319 FEATURE_ARRAYS_OF_ARRAYS,
320 10, 950);
321 createRandomCaseGroup(parentGroup, testCtx, "nested_structs",
322 use8BitTypes | use16BitTypes | unused | allBasicTypes | FEATURE_STRUCTS, 10, 100);
323 createRandomCaseGroup(parentGroup, testCtx, "nested_structs_arrays",
324 use8BitTypes | use16BitTypes | unused | allBasicTypes | FEATURE_STRUCTS |
325 FEATURE_ARRAYS | FEATURE_ARRAYS_OF_ARRAYS,
326 10, 150);
327 }
328 }
329
330 return sharedMemoryLayoutGroup.release();
331 }
332
333 } // namespace MemoryModel
334 } // namespace vkt
335