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  * Copyright (c) 2018 The Khronos Group Inc.
9  *
10  * Licensed under the Apache License, Version 2.0 (the "License");
11  * you may not use this file except in compliance with the License.
12  * You may obtain a copy of the License at
13  *
14  *      http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * Unless required by applicable law or agreed to in writing, software
17  * distributed under the License is distributed on an "AS IS" BASIS,
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19  * See the License for the specific language governing permissions and
20  * limitations under the License.
21  *
22  *//*!
23  * \file
24  * \brief Vulkan Transform Feedback Random Layout Tests
25  *//*--------------------------------------------------------------------*/
26 
27 #include "vktTransformFeedbackRandomLayoutCase.hpp"
28 #include "deRandom.hpp"
29 
30 namespace vkt
31 {
32 namespace TransformFeedback
33 {
34 
35 namespace
36 {
37 
genName(char first,char last,int ndx)38 static std::string genName (char first, char last, int ndx)
39 {
40 	std::string	str			= "";
41 	int			alphabetLen	= last - first + 1;
42 
43 	while (ndx > alphabetLen)
44 	{
45 		str.insert(str.begin(), (char)(first + ((ndx - 1) % alphabetLen)));
46 		ndx = (ndx - 1) / alphabetLen;
47 	}
48 
49 	str.insert(str.begin(), (char)(first + (ndx % (alphabetLen + 1)) - 1));
50 
51 	return str;
52 }
53 
54 } // anonymous
55 
RandomInterfaceBlockCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,const TestStageFlags testStageFlags,deUint32 features,deUint32 seed)56 RandomInterfaceBlockCase::RandomInterfaceBlockCase (tcu::TestContext&		testCtx,
57 													const std::string&		name,
58 													const std::string&		description,
59 													const TestStageFlags	testStageFlags,
60 													deUint32				features,
61 													deUint32				seed)
62 	: InterfaceBlockCase		(testCtx, name, description, LOAD_FULL_MATRIX, testStageFlags, (features & FEATURE_OUT_OF_ORDER_OFFSETS) != 0u)
63 	, m_features				(features)
64 	, m_explicitXfbOffsets		((features & (FEATURE_OUT_OF_ORDER_OFFSETS | FEATURE_MISSING_BLOCK_MEMBERS)) != 0u)
65 	, m_maxBlocks				(3)
66 	, m_maxInstances			((features & FEATURE_INSTANCE_ARRAYS)	? 3 : 0)
67 	, m_maxArrayLength			((features & FEATURE_ARRAYS)			? 4 : 0)
68 	, m_maxStructDepth			((features & FEATURE_STRUCTS)			? 2 : 0)
69 	, m_maxBlockMembers			(3)
70 	, m_maxStructMembers		(3)
71 	, m_seed					(seed)
72 	, m_blockNdx				(1)
73 	, m_interfaceNdx			(1)
74 	, m_structNdx				(1)
75 	, m_primitiveTypeCandidates	(fillTypeCandidates())
76 {
77 	de::Random rnd(m_seed);
78 
79 	int				numBlocks	= rnd.getInt(1, m_maxBlocks);
80 	InterfaceFlags	stage		= static_cast<InterfaceFlags>(LAYOUT_XFBBUFFER | LAYOUT_XFBOFFSET);
81 
82 	for (int ndx = 0; ndx < numBlocks; ndx++)
83 		generateBlock(rnd, stage);
84 
85 	// m_primitiveTypeCandidates is required during generation only
86 	m_primitiveTypeCandidates.clear();
87 
88 	init();
89 }
90 
fillTypeCandidates()91 std::vector<glu::DataType> RandomInterfaceBlockCase::fillTypeCandidates()
92 {
93 	std::vector<glu::DataType> typeCandidates;
94 
95 	typeCandidates.reserve(32);
96 
97 	typeCandidates.push_back(glu::TYPE_FLOAT);
98 	typeCandidates.push_back(glu::TYPE_INT);
99 	typeCandidates.push_back(glu::TYPE_UINT);
100 
101 	if (m_features & FEATURE_DOUBLES)
102 		typeCandidates.push_back(glu::TYPE_DOUBLE);
103 
104 	if (m_features & FEATURE_VECTORS)
105 	{
106 		typeCandidates.push_back(glu::TYPE_FLOAT_VEC2);
107 		typeCandidates.push_back(glu::TYPE_FLOAT_VEC3);
108 		typeCandidates.push_back(glu::TYPE_FLOAT_VEC4);
109 		typeCandidates.push_back(glu::TYPE_INT_VEC2);
110 		typeCandidates.push_back(glu::TYPE_INT_VEC3);
111 		typeCandidates.push_back(glu::TYPE_INT_VEC4);
112 		typeCandidates.push_back(glu::TYPE_UINT_VEC2);
113 		typeCandidates.push_back(glu::TYPE_UINT_VEC3);
114 		typeCandidates.push_back(glu::TYPE_UINT_VEC4);
115 
116 		if (m_features & FEATURE_DOUBLES)
117 		{
118 			typeCandidates.push_back(glu::TYPE_DOUBLE_VEC2);
119 			typeCandidates.push_back(glu::TYPE_DOUBLE_VEC3);
120 			typeCandidates.push_back(glu::TYPE_DOUBLE_VEC4);
121 		}
122 	}
123 
124 	if (m_features & FEATURE_MATRICES)
125 	{
126 		typeCandidates.push_back(glu::TYPE_FLOAT_MAT2);
127 		typeCandidates.push_back(glu::TYPE_FLOAT_MAT2X3);
128 		typeCandidates.push_back(glu::TYPE_FLOAT_MAT3X2);
129 		typeCandidates.push_back(glu::TYPE_FLOAT_MAT3);
130 		typeCandidates.push_back(glu::TYPE_FLOAT_MAT3X4);
131 		typeCandidates.push_back(glu::TYPE_FLOAT_MAT4X2);
132 		typeCandidates.push_back(glu::TYPE_FLOAT_MAT4X3);
133 		typeCandidates.push_back(glu::TYPE_FLOAT_MAT4);
134 
135 		if (m_features & FEATURE_DOUBLES)
136 		{
137 			typeCandidates.push_back(glu::TYPE_DOUBLE_MAT2);
138 			typeCandidates.push_back(glu::TYPE_DOUBLE_MAT2X3);
139 			typeCandidates.push_back(glu::TYPE_DOUBLE_MAT3X2);
140 			typeCandidates.push_back(glu::TYPE_DOUBLE_MAT3);
141 			typeCandidates.push_back(glu::TYPE_DOUBLE_MAT3X4);
142 			typeCandidates.push_back(glu::TYPE_DOUBLE_MAT4X2);
143 			typeCandidates.push_back(glu::TYPE_DOUBLE_MAT4X3);
144 			typeCandidates.push_back(glu::TYPE_DOUBLE_MAT4);
145 		}
146 	}
147 
148 	return typeCandidates;
149 }
150 
generateBlock(de::Random & rnd,deUint32 layoutFlags)151 void RandomInterfaceBlockCase::generateBlock (de::Random& rnd, deUint32 layoutFlags)
152 {
153 	DE_ASSERT(m_blockNdx <= 'z' - 'a');
154 
155 	const float		instanceArrayWeight		= 0.3f;
156 	InterfaceBlock&	block					= m_interface.allocBlock(std::string("Block") + (char)('A' + m_blockNdx));
157 	int				numInstances			= (m_maxInstances > 0 && rnd.getFloat() < instanceArrayWeight) ? rnd.getInt(0, m_maxInstances) : 0;
158 	int				numBlockMembers			= rnd.getInt(1, m_maxBlockMembers);
159 	int				numUnassignedOrMissing	= 0;
160 
161 	if (numInstances > 0)
162 		block.setArraySize(numInstances);
163 
164 	if (numInstances > 0 || rnd.getBool())
165 		block.setInstanceName(std::string("block") + (char)('A' + m_blockNdx));
166 
167 	block.setFlags(layoutFlags);
168 
169 	for (int ndx = 0; ndx < numBlockMembers; ndx++)
170 		generateBlockMember(rnd, block, numBlockMembers, numUnassignedOrMissing);
171 
172 	m_blockNdx += 1;
173 }
174 
generateBlockMember(de::Random & rnd,InterfaceBlock & block,const int numBlockMembers,int & numUnassignedOrMissing)175 void RandomInterfaceBlockCase::generateBlockMember (de::Random& rnd, InterfaceBlock& block, const int numBlockMembers, int& numUnassignedOrMissing)
176 {
177 	const float		unassignedBlockMembersWeight	= 0.15f;
178 	const float		missingBlockMembersWeight		= 0.15f;
179 	const bool		unassignedAllowed				= (m_features & FEATURE_UNASSIGNED_BLOCK_MEMBERS) != 0;
180 	const bool		missingAllowed					= (m_features & FEATURE_MISSING_BLOCK_MEMBERS) != 0;
181 	deUint32		flags							= 0;
182 	std::string		name							= genName('a', 'z', m_interfaceNdx);
183 	VarType			type							= generateType(rnd, 0, true);
184 
185 	if (numUnassignedOrMissing < numBlockMembers - 1)
186 	{
187 		if (missingAllowed && rnd.getFloat() < missingBlockMembersWeight)
188 		{
189 			flags |= FIELD_MISSING;
190 			numUnassignedOrMissing++;
191 		}
192 		else if (unassignedAllowed && rnd.getFloat() < unassignedBlockMembersWeight)
193 		{
194 			flags |= FIELD_UNASSIGNED;
195 			numUnassignedOrMissing++;
196 		}
197 	}
198 
199 	block.addInterfaceMember(InterfaceBlockMember(name, type, flags));
200 
201 	m_interfaceNdx += 1;
202 }
203 
generateType(de::Random & rnd,int typeDepth,bool arrayOk)204 VarType RandomInterfaceBlockCase::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				unassignedFieldWeight	= 0.15f;
212 		const bool				unassignedOk			= (m_features & FEATURE_UNASSIGNED_FIELDS) != 0;
213 		const int				numMembers				= rnd.getInt(1, m_maxStructMembers);
214 		std::vector<VarType>	memberTypes;
215 
216 		// Generate members first so nested struct declarations are in correct order.
217 		for (int ndx = 0; ndx < numMembers; ndx++)
218 			memberTypes.push_back(generateType(rnd, typeDepth+1, true));
219 
220 		StructType& structType = m_interface.allocStruct(std::string("s") + genName('A', 'Z', m_structNdx));
221 		m_structNdx += 1;
222 
223 		DE_ASSERT(numMembers <= 'Z' - 'A');
224 		for (int ndx = 0; ndx < numMembers; ndx++)
225 		{
226 			deUint32 flags = 0;
227 
228 			if (unassignedOk && rnd.getFloat() < unassignedFieldWeight)
229 			{
230 				flags |= FIELD_UNASSIGNED;
231 			}
232 
233 			structType.addMember(std::string("m") + (char)('A' + ndx), memberTypes[ndx], flags);
234 		}
235 
236 		return VarType(&structType, m_explicitXfbOffsets ? static_cast<deUint32>(LAYOUT_XFBOFFSET) : 0u);
237 	}
238 	else if (m_maxArrayLength > 0 && arrayOk && rnd.getFloat() < arrayWeight)
239 	{
240 		const bool	arraysOfArraysOk	= (m_features & FEATURE_ARRAYS_OF_ARRAYS) != 0;
241 		const int	arrayLength			= rnd.getInt(1, m_maxArrayLength);
242 		VarType		elementType			= generateType(rnd, typeDepth, arraysOfArraysOk);
243 
244 		return VarType(elementType, arrayLength);
245 	}
246 	else
247 	{
248 		glu::DataType	type	= rnd.choose<glu::DataType>(m_primitiveTypeCandidates.begin(), m_primitiveTypeCandidates.end());
249 		deUint32		flags	= (m_explicitXfbOffsets ? static_cast<deUint32>(LAYOUT_XFBOFFSET) : 0u);
250 
251 		if (glu::dataTypeSupportsPrecisionModifier(type))
252 		{
253 			// Precision.
254 			static const deUint32 precisionCandidates[] = { PRECISION_LOW, PRECISION_MEDIUM, PRECISION_HIGH };
255 			flags |= rnd.choose<deUint32>(&precisionCandidates[0], &precisionCandidates[DE_LENGTH_OF_ARRAY(precisionCandidates)]);
256 		}
257 
258 		return VarType(type, flags);
259 	}
260 }
261 
262 } // TransformFeedback
263 } // vkt
264