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 } // namespace
55
RandomInterfaceBlockCase(tcu::TestContext & testCtx,const std::string & name,const TestStageFlags testStageFlags,uint32_t features,uint32_t seed)56 RandomInterfaceBlockCase::RandomInterfaceBlockCase(tcu::TestContext &testCtx, const std::string &name,
57 const TestStageFlags testStageFlags, uint32_t features,
58 uint32_t seed)
59 : InterfaceBlockCase(testCtx, name, LOAD_FULL_MATRIX, testStageFlags,
60 (features & FEATURE_OUT_OF_ORDER_OFFSETS) != 0u)
61 , m_features(features)
62 , m_explicitXfbOffsets((features & (FEATURE_OUT_OF_ORDER_OFFSETS | FEATURE_MISSING_BLOCK_MEMBERS)) != 0u)
63 , m_maxBlocks(3)
64 , m_maxInstances((features & FEATURE_INSTANCE_ARRAYS) ? 3 : 0)
65 , m_maxArrayLength((features & FEATURE_ARRAYS) ? 4 : 0)
66 , m_maxStructDepth((features & FEATURE_STRUCTS) ? 2 : 0)
67 , m_maxBlockMembers(3)
68 , m_maxStructMembers(3)
69 , m_seed(seed)
70 , m_blockNdx(1)
71 , m_interfaceNdx(1)
72 , m_structNdx(1)
73 , m_primitiveTypeCandidates(fillTypeCandidates())
74 {
75 de::Random rnd(m_seed);
76
77 int numBlocks = rnd.getInt(1, m_maxBlocks);
78 InterfaceFlags stage = static_cast<InterfaceFlags>(LAYOUT_XFBBUFFER | LAYOUT_XFBOFFSET);
79
80 for (int ndx = 0; ndx < numBlocks; ndx++)
81 generateBlock(rnd, stage);
82
83 // m_primitiveTypeCandidates is required during generation only
84 m_primitiveTypeCandidates.clear();
85
86 init();
87 }
88
fillTypeCandidates()89 std::vector<glu::DataType> RandomInterfaceBlockCase::fillTypeCandidates()
90 {
91 std::vector<glu::DataType> typeCandidates;
92
93 typeCandidates.reserve(32);
94
95 typeCandidates.push_back(glu::TYPE_FLOAT);
96 typeCandidates.push_back(glu::TYPE_INT);
97 typeCandidates.push_back(glu::TYPE_UINT);
98
99 if (m_features & FEATURE_DOUBLES)
100 typeCandidates.push_back(glu::TYPE_DOUBLE);
101
102 if (m_features & FEATURE_VECTORS)
103 {
104 typeCandidates.push_back(glu::TYPE_FLOAT_VEC2);
105 typeCandidates.push_back(glu::TYPE_FLOAT_VEC3);
106 typeCandidates.push_back(glu::TYPE_FLOAT_VEC4);
107 typeCandidates.push_back(glu::TYPE_INT_VEC2);
108 typeCandidates.push_back(glu::TYPE_INT_VEC3);
109 typeCandidates.push_back(glu::TYPE_INT_VEC4);
110 typeCandidates.push_back(glu::TYPE_UINT_VEC2);
111 typeCandidates.push_back(glu::TYPE_UINT_VEC3);
112 typeCandidates.push_back(glu::TYPE_UINT_VEC4);
113
114 if (m_features & FEATURE_DOUBLES)
115 {
116 typeCandidates.push_back(glu::TYPE_DOUBLE_VEC2);
117 typeCandidates.push_back(glu::TYPE_DOUBLE_VEC3);
118 typeCandidates.push_back(glu::TYPE_DOUBLE_VEC4);
119 }
120 }
121
122 if (m_features & FEATURE_MATRICES)
123 {
124 typeCandidates.push_back(glu::TYPE_FLOAT_MAT2);
125 typeCandidates.push_back(glu::TYPE_FLOAT_MAT2X3);
126 typeCandidates.push_back(glu::TYPE_FLOAT_MAT3X2);
127 typeCandidates.push_back(glu::TYPE_FLOAT_MAT3);
128 typeCandidates.push_back(glu::TYPE_FLOAT_MAT3X4);
129 typeCandidates.push_back(glu::TYPE_FLOAT_MAT4X2);
130 typeCandidates.push_back(glu::TYPE_FLOAT_MAT4X3);
131 typeCandidates.push_back(glu::TYPE_FLOAT_MAT4);
132
133 if (m_features & FEATURE_DOUBLES)
134 {
135 typeCandidates.push_back(glu::TYPE_DOUBLE_MAT2);
136 typeCandidates.push_back(glu::TYPE_DOUBLE_MAT2X3);
137 typeCandidates.push_back(glu::TYPE_DOUBLE_MAT3X2);
138 typeCandidates.push_back(glu::TYPE_DOUBLE_MAT3);
139 typeCandidates.push_back(glu::TYPE_DOUBLE_MAT3X4);
140 typeCandidates.push_back(glu::TYPE_DOUBLE_MAT4X2);
141 typeCandidates.push_back(glu::TYPE_DOUBLE_MAT4X3);
142 typeCandidates.push_back(glu::TYPE_DOUBLE_MAT4);
143 }
144 }
145
146 return typeCandidates;
147 }
148
generateBlock(de::Random & rnd,uint32_t layoutFlags)149 void RandomInterfaceBlockCase::generateBlock(de::Random &rnd, uint32_t layoutFlags)
150 {
151 DE_ASSERT(m_blockNdx <= 'z' - 'a');
152
153 const float instanceArrayWeight = 0.3f;
154 InterfaceBlock &block = m_interface.allocBlock(std::string("Block") + (char)('A' + m_blockNdx));
155 int numInstances = (m_maxInstances > 0 && rnd.getFloat() < instanceArrayWeight) ? rnd.getInt(0, m_maxInstances) : 0;
156 int numBlockMembers = rnd.getInt(1, m_maxBlockMembers);
157 int numUnassignedOrMissing = 0;
158
159 if (numInstances > 0)
160 block.setArraySize(numInstances);
161
162 if (numInstances > 0 || rnd.getBool())
163 block.setInstanceName(std::string("block") + (char)('A' + m_blockNdx));
164
165 block.setFlags(layoutFlags);
166
167 for (int ndx = 0; ndx < numBlockMembers; ndx++)
168 generateBlockMember(rnd, block, numBlockMembers, numUnassignedOrMissing);
169
170 m_blockNdx += 1;
171 }
172
generateBlockMember(de::Random & rnd,InterfaceBlock & block,const int numBlockMembers,int & numUnassignedOrMissing)173 void RandomInterfaceBlockCase::generateBlockMember(de::Random &rnd, InterfaceBlock &block, const int numBlockMembers,
174 int &numUnassignedOrMissing)
175 {
176 const float unassignedBlockMembersWeight = 0.15f;
177 const float missingBlockMembersWeight = 0.15f;
178 const bool unassignedAllowed = (m_features & FEATURE_UNASSIGNED_BLOCK_MEMBERS) != 0;
179 const bool missingAllowed = (m_features & FEATURE_MISSING_BLOCK_MEMBERS) != 0;
180 uint32_t flags = 0;
181 std::string name = genName('a', 'z', m_interfaceNdx);
182 VarType type = generateType(rnd, 0, true);
183
184 if (numUnassignedOrMissing < numBlockMembers - 1)
185 {
186 if (missingAllowed && rnd.getFloat() < missingBlockMembersWeight)
187 {
188 flags |= FIELD_MISSING;
189 numUnassignedOrMissing++;
190 }
191 else if (unassignedAllowed && rnd.getFloat() < unassignedBlockMembersWeight)
192 {
193 flags |= FIELD_UNASSIGNED;
194 numUnassignedOrMissing++;
195 }
196 }
197
198 block.addInterfaceMember(InterfaceBlockMember(name, type, flags));
199
200 m_interfaceNdx += 1;
201 }
202
generateType(de::Random & rnd,int typeDepth,bool arrayOk)203 VarType RandomInterfaceBlockCase::generateType(de::Random &rnd, int typeDepth, bool arrayOk)
204 {
205 const float structWeight = 0.1f;
206 const float arrayWeight = 0.1f;
207
208 if (typeDepth < m_maxStructDepth && rnd.getFloat() < structWeight)
209 {
210 const float unassignedFieldWeight = 0.15f;
211 const bool unassignedOk = (m_features & FEATURE_UNASSIGNED_FIELDS) != 0;
212 const int numMembers = rnd.getInt(1, m_maxStructMembers);
213 std::vector<VarType> memberTypes;
214
215 // Generate members first so nested struct declarations are in correct order.
216 for (int ndx = 0; ndx < numMembers; ndx++)
217 memberTypes.push_back(generateType(rnd, typeDepth + 1, true));
218
219 StructType &structType = m_interface.allocStruct(std::string("s") + genName('A', 'Z', m_structNdx));
220 m_structNdx += 1;
221
222 DE_ASSERT(numMembers <= 'Z' - 'A');
223 for (int ndx = 0; ndx < numMembers; ndx++)
224 {
225 uint32_t flags = 0;
226
227 if (unassignedOk && rnd.getFloat() < unassignedFieldWeight)
228 {
229 flags |= FIELD_UNASSIGNED;
230 }
231
232 structType.addMember(std::string("m") + (char)('A' + ndx), memberTypes[ndx], flags);
233 }
234
235 return VarType(&structType, m_explicitXfbOffsets ? static_cast<uint32_t>(LAYOUT_XFBOFFSET) : 0u);
236 }
237 else if (m_maxArrayLength > 0 && arrayOk && rnd.getFloat() < arrayWeight)
238 {
239 const bool arraysOfArraysOk = (m_features & FEATURE_ARRAYS_OF_ARRAYS) != 0;
240 const int arrayLength = rnd.getInt(1, m_maxArrayLength);
241 VarType elementType = generateType(rnd, typeDepth, arraysOfArraysOk);
242
243 return VarType(elementType, arrayLength);
244 }
245 else
246 {
247 glu::DataType type =
248 rnd.choose<glu::DataType>(m_primitiveTypeCandidates.begin(), m_primitiveTypeCandidates.end());
249 uint32_t flags = (m_explicitXfbOffsets ? static_cast<uint32_t>(LAYOUT_XFBOFFSET) : 0u);
250
251 if (glu::dataTypeSupportsPrecisionModifier(type))
252 {
253 // Precision.
254 static const uint32_t precisionCandidates[] = {PRECISION_LOW, PRECISION_MEDIUM, PRECISION_HIGH};
255 flags |= rnd.choose<uint32_t>(&precisionCandidates[0],
256 &precisionCandidates[DE_LENGTH_OF_ARRAY(precisionCandidates)]);
257 }
258
259 return VarType(type, flags);
260 }
261 }
262
263 } // namespace TransformFeedback
264 } // namespace vkt
265