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