• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 char * description,const deUint32 features,const int numCases,deUint32 baseSeed)94 void createRandomCaseGroup (tcu::TestCaseGroup* parentGroup, tcu::TestContext &testCtx, const char *groupName,
95 							const char *description, const deUint32 features, const int numCases, deUint32 baseSeed)
96 {
97 	tcu::TestCaseGroup *group = new tcu::TestCaseGroup(testCtx, groupName, description);
98 	parentGroup->addChild(group);
99 
100 	baseSeed += static_cast<deUint32>(testCtx.getCommandLine().getBaseSeed());
101 
102 	for (int i = 0; i < numCases; i++)
103 		group->addChild(new RandomSharedLayoutCase(testCtx, de::toString(i).c_str(), "", features, static_cast<deUint32>(i + baseSeed)));
104 }
105 } // anonymous
106 
RandomSharedLayoutCase(tcu::TestContext & testCtx,const char * name,const char * description,deUint32 features,deUint32 seed)107 RandomSharedLayoutCase::RandomSharedLayoutCase (tcu::TestContext &testCtx, const char *name, const char *description,
108 												deUint32 features, deUint32 seed)
109 	: SharedLayoutCase(testCtx, name, description)
110 	, m_features(features)
111 	, m_maxArrayLength((features & FEATURE_ARRAYS) ? 3 : 0)
112 	, m_seed(seed)
113 {
114 	de::Random rnd(m_seed);
115 
116 	m_interface.enable16BitTypes(features & FEATURE_16BIT_TYPES);
117 	m_interface.enable8BitTypes(features & FEATURE_8BIT_TYPES);
118 
119 	for (int i = 0; i < rnd.getInt(1, m_maxSharedObjects); i++)
120 		generateSharedMemoryObject(rnd);
121 
122 	init();
123 }
124 
125 /*--------------------------------------------------------------------*//*!
126  * \brief Creates definitions for shared memory structs.
127  * \param rnd Random value generator used for deciding the type of the variable.
128  *
129  * Creates definitions for shared memory structs. Each struct's name starts with
130  * an upper-case S and its instance name with a lower-case s followed by its index
131  * number.
132  *//*--------------------------------------------------------------------*/
generateSharedMemoryObject(de::Random & rnd)133 void RandomSharedLayoutCase::generateSharedMemoryObject (de::Random &rnd)
134 {
135 	const string	name			= "S" + de::toString(m_interface.getNumSharedObjects() + 1);
136 	const string	instanceName	= "s" + de::toString(m_interface.getNumSharedObjects() + 1);
137 	SharedStruct	&object			= m_interface.allocSharedObject(name, instanceName);
138 	const int		numVars			= rnd.getInt(2, m_maxSharedObjectMembers);
139 
140 	for (int i = 0; i < numVars; i++)
141 		generateSharedMemoryVar(rnd, object);
142 }
143 
generateSharedMemoryVar(de::Random & rnd,SharedStruct & object)144 void RandomSharedLayoutCase::generateSharedMemoryVar (de::Random &rnd, SharedStruct &object)
145 {
146 	SharedStructVar var;
147 	var.name = genName('a', 'z', object.getNumMembers() + 1);
148 
149 	if ((m_features & FEATURE_ARRAYS_OF_ARRAYS) != 0 || (m_features & FEATURE_STRUCTS) != 0)
150 		var.type = generateType(rnd, 3, true);
151 	else
152 		var.type = generateType(rnd, 1, true);
153 
154 	var.topLevelArraySize = 1;
155 	if (var.type.isArrayType())
156 		var.topLevelArraySize = var.type.getArraySize() == glu::VarType::UNSIZED_ARRAY ? 0 : var.type.getArraySize();
157 
158 	object.addMember(var);
159 }
160 
generateType(de::Random & rnd,int typeDepth,bool arrayOk)161 glu::VarType RandomSharedLayoutCase::generateType (de::Random &rnd, int typeDepth, bool arrayOk)
162 {
163 	const float structWeight	= 0.7f;
164 	const float arrayWeight		= 0.8f;
165 
166 	if (typeDepth > 0 && rnd.getFloat() < structWeight && (m_features & FEATURE_STRUCTS))
167 	{
168 		vector<glu::VarType>			memberTypes;
169 		const int						numMembers	= rnd.getInt(1, m_maxStructMembers);
170 
171 		// Generate members first so nested struct declarations are in correct order.
172 		for (int i = 0; i < numMembers; i++)
173 			memberTypes.push_back(generateType(rnd, typeDepth - 1, true));
174 
175 		const string					name		= "s" + genName('A', 'Z', m_interface.getNumStructs() + 1);
176 		de::SharedPtr<glu::StructType>	structType	= m_interface.allocStruct(name);
177 
178 		DE_ASSERT(numMembers <= 'Z' - 'A');
179 		for (int i = 0; i < numMembers; i++)
180 			structType.get()->addMember((string("m") + static_cast<char>(('A' + i))).c_str(), memberTypes[i]);
181 
182 		return glu::VarType(structType.get());
183 	}
184 	else if (typeDepth > 0 && m_maxArrayLength > 0 && arrayOk && rnd.getFloat() < arrayWeight)
185 	{
186 		const int			arrayLength		= rnd.getInt(1, m_maxArrayLength);
187 		const bool			childArrayOk	= (m_features & FEATURE_ARRAYS_OF_ARRAYS) != 0;
188 		const glu::VarType	elementType		= generateType(rnd, typeDepth - 1, childArrayOk);
189 
190 		return glu::VarType(elementType, arrayLength);
191 	}
192 	else
193 	{
194 		const float weight8Bit		= (m_features & FEATURE_8BIT_TYPES) ? 0.7f : 0.0f;
195 		const float weight16Bit		= (m_features & FEATURE_16BIT_TYPES) ? 0.7f : 0.0f;
196 		const float weightMatrices	= (m_features & FEATURE_MATRICES) ? 0.3f : 0.0f;
197 
198 		vector<glu::DataType> typeCandidates;
199 		if (rnd.getFloat() < weight16Bit)
200 		{
201 			typeCandidates.push_back(glu::TYPE_UINT16);
202 			typeCandidates.push_back(glu::TYPE_INT16);
203 			typeCandidates.push_back(glu::TYPE_FLOAT16);
204 
205 			if (m_features & FEATURE_VECTORS)
206 			{
207 				typeCandidates.push_back(glu::TYPE_FLOAT16_VEC2);
208 				typeCandidates.push_back(glu::TYPE_FLOAT16_VEC3);
209 				typeCandidates.push_back(glu::TYPE_FLOAT16_VEC4);
210 				typeCandidates.push_back(glu::TYPE_INT16_VEC2);
211 				typeCandidates.push_back(glu::TYPE_INT16_VEC3);
212 				typeCandidates.push_back(glu::TYPE_INT16_VEC4);
213 				typeCandidates.push_back(glu::TYPE_UINT16_VEC2);
214 				typeCandidates.push_back(glu::TYPE_UINT16_VEC3);
215 				typeCandidates.push_back(glu::TYPE_UINT16_VEC4);
216 			}
217 		}
218 		else if (rnd.getFloat() < weight8Bit)
219 		{
220 			typeCandidates.push_back(glu::TYPE_UINT8);
221 			typeCandidates.push_back(glu::TYPE_INT8);
222 
223 			if (m_features & FEATURE_VECTORS)
224 			{
225 				typeCandidates.push_back(glu::TYPE_INT8_VEC2);
226 				typeCandidates.push_back(glu::TYPE_INT8_VEC3);
227 				typeCandidates.push_back(glu::TYPE_INT8_VEC4);
228 				typeCandidates.push_back(glu::TYPE_UINT8_VEC2);
229 				typeCandidates.push_back(glu::TYPE_UINT8_VEC3);
230 				typeCandidates.push_back(glu::TYPE_UINT8_VEC4);
231 			}
232 		}
233 		else
234 		{
235 			typeCandidates.push_back(glu::TYPE_FLOAT);
236 			typeCandidates.push_back(glu::TYPE_INT);
237 			typeCandidates.push_back(glu::TYPE_UINT);
238 			typeCandidates.push_back(glu::TYPE_BOOL);
239 
240 			if (m_features & FEATURE_VECTORS)
241 			{
242 				typeCandidates.push_back(glu::TYPE_FLOAT_VEC2);
243 				typeCandidates.push_back(glu::TYPE_FLOAT_VEC3);
244 				typeCandidates.push_back(glu::TYPE_FLOAT_VEC4);
245 				typeCandidates.push_back(glu::TYPE_INT_VEC2);
246 				typeCandidates.push_back(glu::TYPE_INT_VEC3);
247 				typeCandidates.push_back(glu::TYPE_INT_VEC4);
248 				typeCandidates.push_back(glu::TYPE_UINT_VEC2);
249 				typeCandidates.push_back(glu::TYPE_UINT_VEC3);
250 				typeCandidates.push_back(glu::TYPE_UINT_VEC4);
251 				typeCandidates.push_back(glu::TYPE_BOOL_VEC2);
252 				typeCandidates.push_back(glu::TYPE_BOOL_VEC3);
253 				typeCandidates.push_back(glu::TYPE_BOOL_VEC4);
254 			}
255 		}
256 
257 		if (rnd.getFloat() < weightMatrices)
258 		{
259 			typeCandidates.push_back(glu::TYPE_FLOAT_MAT2);
260 			typeCandidates.push_back(glu::TYPE_FLOAT_MAT2X3);
261 			typeCandidates.push_back(glu::TYPE_FLOAT_MAT3X2);
262 			typeCandidates.push_back(glu::TYPE_FLOAT_MAT3);
263 			typeCandidates.push_back(glu::TYPE_FLOAT_MAT3X4);
264 			typeCandidates.push_back(glu::TYPE_FLOAT_MAT4X2);
265 			typeCandidates.push_back(glu::TYPE_FLOAT_MAT4X3);
266 			typeCandidates.push_back(glu::TYPE_FLOAT_MAT4);
267 		}
268 
269 		glu::DataType	type		= rnd.choose<glu::DataType>(typeCandidates.begin(), typeCandidates.end());
270 		glu::Precision	precision;
271 
272 		if (glu::dataTypeSupportsPrecisionModifier(type))
273 		{
274 			const glu::Precision precisionCandidates[]	= { glu::PRECISION_LOWP, glu::PRECISION_MEDIUMP, glu::PRECISION_HIGHP};
275 			precision									= rnd.choose<glu::Precision>(&precisionCandidates[0],
276 													&precisionCandidates[DE_LENGTH_OF_ARRAY(precisionCandidates)]);
277 		}
278 		else
279 			precision = glu::PRECISION_LAST;
280 
281 		return glu::VarType(type, precision);
282 	}
283 }
284 
createSharedMemoryLayoutTests(tcu::TestContext & testCtx)285 tcu::TestCaseGroup* createSharedMemoryLayoutTests (tcu::TestContext &testCtx)
286 {
287 	de::MovePtr<tcu::TestCaseGroup> sharedMemoryLayoutGroup(new tcu::TestCaseGroup(testCtx, "shared", "Shared memory layout tests"));
288 	tcu::TestCaseGroup *parentGroup = sharedMemoryLayoutGroup.get();
289 	{
290 		const deUint32 allBasicTypes	= FEATURE_VECTORS | FEATURE_MATRICES;
291 		const deUint32 unused			= FEATURE_UNUSED_MEMBERS | FEATURE_UNUSED_VARS;
292 
293 		for (int i = 0; i < 3; ++i)
294 		{
295 			if (i == 1)
296 			{
297 				parentGroup = new tcu::TestCaseGroup(testCtx, "16bit", "16bit");
298 				sharedMemoryLayoutGroup->addChild(parentGroup);
299 			}
300 			else if (i == 2)
301 			{
302 				parentGroup = new tcu::TestCaseGroup(testCtx, "8bit", "8bit");
303 				sharedMemoryLayoutGroup->addChild(parentGroup);
304 			}
305 			const deUint32 use16BitTypes	= i == 1 ? FEATURE_16BIT_TYPES : 0;
306 			const deUint32 use8BitTypes		= i == 2 ? FEATURE_8BIT_TYPES : 0;
307 
308 			createRandomCaseGroup(parentGroup, testCtx, "scalar_types", "Scalar types only",
309 								use8BitTypes | use16BitTypes | unused, 10, 0);
310 			createRandomCaseGroup(parentGroup, testCtx, "vector_types", "Scalar and vector types only",
311 								use8BitTypes | use16BitTypes | unused | FEATURE_VECTORS, 10, 25);
312 			createRandomCaseGroup(parentGroup, testCtx, "basic_types", "All basic types",
313 								use8BitTypes | use16BitTypes | unused | allBasicTypes, 10, 50);
314 			createRandomCaseGroup(parentGroup, testCtx, "basic_arrays", "Arrays",
315 								use8BitTypes | use16BitTypes | unused | allBasicTypes | FEATURE_ARRAYS, 10, 50);
316 			createRandomCaseGroup(parentGroup, testCtx, "arrays_of_arrays", "Arrays of arrays",
317 								use8BitTypes | use16BitTypes | unused | allBasicTypes | FEATURE_ARRAYS |
318 								FEATURE_ARRAYS_OF_ARRAYS, 10, 950);
319 			createRandomCaseGroup(parentGroup, testCtx, "nested_structs", "Nested structs",
320 								use8BitTypes | use16BitTypes | unused | allBasicTypes | FEATURE_STRUCTS, 10, 100);
321 			createRandomCaseGroup(parentGroup, testCtx, "nested_structs_arrays", "Nested structs, arrays",
322 								use8BitTypes | use16BitTypes | unused | allBasicTypes | FEATURE_STRUCTS |
323 								FEATURE_ARRAYS | FEATURE_ARRAYS_OF_ARRAYS, 10, 150);
324 		}
325 	}
326 
327 	return sharedMemoryLayoutGroup.release();
328 }
329 
330 } // MemoryModel
331 } // vkt
332