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