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 * 9 * Licensed under the Apache License, Version 2.0 (the "License"); 10 * you may not use this file except in compliance with the License. 11 * You may obtain a copy of the License at 12 * 13 * http://www.apache.org/licenses/LICENSE-2.0 14 * 15 * Unless required by applicable law or agreed to in writing, software 16 * distributed under the License is distributed on an "AS IS" BASIS, 17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 * See the License for the specific language governing permissions and 19 * limitations under the License. 20 * 21 *//*! 22 * \file 23 * \brief Random uniform block layout case. 24 *//*--------------------------------------------------------------------*/ 25 26#include "vktRandomUniformBlockCase.hpp" 27#include "deRandom.hpp" 28 29namespace vkt 30{ 31namespace ubo 32{ 33 34namespace 35{ 36 37static std::string genName (char first, char last, int ndx) 38{ 39 std::string str = ""; 40 int alphabetLen = last - first + 1; 41 42 while (ndx > alphabetLen) 43 { 44 str.insert(str.begin(), (char)(first + ((ndx - 1) % alphabetLen))); 45 ndx = (ndx - 1) / alphabetLen; 46 } 47 48 str.insert(str.begin(), (char)(first + (ndx % (alphabetLen + 1)) - 1)); 49 50 return str; 51} 52 53} // anonymous 54 55RandomUniformBlockCase::RandomUniformBlockCase (tcu::TestContext& testCtx, 56 const std::string& name, 57 BufferMode bufferMode, 58 deUint32 features, 59 deUint32 seed) 60 : UniformBlockCase (testCtx, name, bufferMode, LOAD_FULL_MATRIX, (features & FEATURE_OUT_OF_ORDER_OFFSETS) != 0u) 61 , m_features (features) 62 , m_maxVertexBlocks ((features & FEATURE_VERTEX_BLOCKS) ? 4 : 0) 63 , m_maxFragmentBlocks ((features & FEATURE_FRAGMENT_BLOCKS) ? 4 : 0) 64 , m_maxSharedBlocks ((features & FEATURE_SHARED_BLOCKS) ? 4 : 0) 65 , m_maxInstances ((features & FEATURE_INSTANCE_ARRAYS) ? 3 : 0) 66 , m_maxArrayLength ((features & FEATURE_ARRAYS) ? 8 : 0) 67 , m_maxStructDepth ((features & FEATURE_STRUCTS) ? 2 : 0) 68 , m_maxBlockMembers (5) 69 , m_maxStructMembers (4) 70 , m_seed (seed) 71 , m_blockNdx (1) 72 , m_uniformNdx (1) 73 , m_structNdx (1) 74 , m_availableDescriptorUniformBuffers (12) 75{ 76 de::Random rnd(m_seed); 77 78 int numShared = m_maxSharedBlocks > 0 ? rnd.getInt(1, m_maxSharedBlocks) : 0; 79 int numVtxBlocks = m_maxVertexBlocks-numShared > 0 ? rnd.getInt(1, m_maxVertexBlocks - numShared) : 0; 80 int numFragBlocks = m_maxFragmentBlocks-numShared > 0 ? rnd.getInt(1, m_maxFragmentBlocks - numShared): 0; 81 82 // calculate how many additional descriptors we can use for arrays 83 // this is needed for descriptor_indexing testing as we need to take in to account 84 // maxPerStageDescriptorUniformBuffers limit and we can't query it as we need to 85 // generate shaders before Context is created; minimal value of this limit is 12 86 m_availableDescriptorUniformBuffers -= numVtxBlocks + numFragBlocks; 87 88 for (int ndx = 0; ndx < numShared; ndx++) 89 generateBlock(rnd, DECLARE_VERTEX | DECLARE_FRAGMENT); 90 91 for (int ndx = 0; ndx < numVtxBlocks; ndx++) 92 generateBlock(rnd, DECLARE_VERTEX); 93 94 for (int ndx = 0; ndx < numFragBlocks; ndx++) 95 generateBlock(rnd, DECLARE_FRAGMENT); 96 97 init(); 98} 99 100void RandomUniformBlockCase::generateBlock (de::Random& rnd, deUint32 layoutFlags) 101{ 102 DE_ASSERT(m_blockNdx <= 'z' - 'a'); 103 104 const float instanceArrayWeight = 0.3f; 105 UniformBlock& block = m_interface.allocBlock(std::string("Block") + (char)('A' + m_blockNdx)); 106 int numInstances = (m_maxInstances > 0 && rnd.getFloat() < instanceArrayWeight) ? rnd.getInt(0, m_maxInstances) : 0; 107 int numUniforms = rnd.getInt(1, m_maxBlockMembers); 108 109 if (m_features & FEATURE_DESCRIPTOR_INDEXING) 110 { 111 // generate arrays only when we are within the limit 112 if (m_availableDescriptorUniformBuffers > 3) 113 numInstances = rnd.getInt(2, 4); 114 else if (m_availableDescriptorUniformBuffers > 1) 115 numInstances = m_availableDescriptorUniformBuffers; 116 else 117 numInstances = 0; 118 m_availableDescriptorUniformBuffers -= numInstances; 119 } 120 121 if (numInstances > 0) 122 block.setArraySize(numInstances); 123 124 if (numInstances > 0 || rnd.getBool()) 125 block.setInstanceName(std::string("block") + (char)('A' + m_blockNdx)); 126 127 // Layout flag candidates. 128 std::vector<deUint32> layoutFlagCandidates; 129 layoutFlagCandidates.push_back(0); 130 131 if (m_features & FEATURE_STD140_LAYOUT) 132 layoutFlagCandidates.push_back(LAYOUT_STD140); 133 134 if (m_features & FEATURE_STD430_LAYOUT) 135 layoutFlagCandidates.push_back(LAYOUT_STD430); 136 137 if (m_features & FEATURE_SCALAR_LAYOUT) 138 layoutFlagCandidates.push_back(LAYOUT_SCALAR); 139 140 if (m_features & FEATURE_16BIT_STORAGE) 141 layoutFlags |= LAYOUT_16BIT_STORAGE; 142 143 if (m_features & FEATURE_8BIT_STORAGE) 144 layoutFlags |= LAYOUT_8BIT_STORAGE; 145 146 if (m_features & FEATURE_DESCRIPTOR_INDEXING) 147 layoutFlags |= LAYOUT_DESCRIPTOR_INDEXING; 148 149 layoutFlags |= rnd.choose<deUint32>(layoutFlagCandidates.begin(), layoutFlagCandidates.end()); 150 151 if (m_features & FEATURE_MATRIX_LAYOUT) 152 { 153 static const deUint32 matrixCandidates[] = { 0, LAYOUT_ROW_MAJOR, LAYOUT_COLUMN_MAJOR }; 154 layoutFlags |= rnd.choose<deUint32>(&matrixCandidates[0], &matrixCandidates[DE_LENGTH_OF_ARRAY(matrixCandidates)]); 155 } 156 157 block.setFlags(layoutFlags); 158 159 for (int ndx = 0; ndx < numUniforms; ndx++) 160 generateUniform(rnd, block, numInstances ? numInstances : 1); 161 162 m_blockNdx += 1; 163} 164 165void RandomUniformBlockCase::generateUniform (de::Random& rnd, UniformBlock& block, deUint32 complexity) 166{ 167 const float unusedVtxWeight = 0.15f; 168 const float unusedFragWeight = 0.15f; 169 bool unusedOk = (m_features & FEATURE_UNUSED_UNIFORMS) != 0; 170 deUint32 flags = 0; 171 std::string name = genName('a', 'z', m_uniformNdx); 172 VarType type = generateType(rnd, 0, true, complexity); 173 174 flags |= (unusedOk && rnd.getFloat() < unusedVtxWeight) ? UNUSED_VERTEX : 0; 175 flags |= (unusedOk && rnd.getFloat() < unusedFragWeight) ? UNUSED_FRAGMENT : 0; 176 177 block.addUniform(Uniform(name, type, flags)); 178 179 m_uniformNdx += 1; 180} 181 182VarType RandomUniformBlockCase::generateType (de::Random& rnd, int typeDepth, bool arrayOk, deUint32 complexity) 183{ 184 const float structWeight = 0.1f; 185 const float arrayWeight = 0.1f; 186 187 if (typeDepth < m_maxStructDepth && rnd.getFloat() < structWeight) 188 { 189 const float unusedVtxWeight = 0.15f; 190 const float unusedFragWeight = 0.15f; 191 bool unusedOk = (m_features & FEATURE_UNUSED_MEMBERS) != 0; 192 std::vector<VarType> memberTypes; 193 int numMembers = rnd.getInt(1, m_maxStructMembers); 194 195 // Generate members first so nested struct declarations are in correct order. 196 for (int ndx = 0; ndx < numMembers; ndx++) 197 memberTypes.push_back(generateType(rnd, typeDepth+1, true, complexity)); 198 199 StructType& structType = m_interface.allocStruct(std::string("s") + genName('A', 'Z', m_structNdx)); 200 m_structNdx += 1; 201 202 DE_ASSERT(numMembers <= 'Z' - 'A'); 203 for (int ndx = 0; ndx < numMembers; ndx++) 204 { 205 deUint32 flags = 0; 206 207 flags |= (unusedOk && rnd.getFloat() < unusedVtxWeight) ? UNUSED_VERTEX : 0; 208 flags |= (unusedOk && rnd.getFloat() < unusedFragWeight) ? UNUSED_FRAGMENT : 0; 209 210 structType.addMember(std::string("m") + (char)('A' + ndx), memberTypes[ndx], flags); 211 } 212 213 return VarType(&structType, m_shuffleUniformMembers ? static_cast<deUint32>(LAYOUT_OFFSET) : 0u); 214 } 215 else if (m_maxArrayLength > 0 && arrayOk && rnd.getFloat() < arrayWeight) 216 { 217 const bool arraysOfArraysOk = (m_features & FEATURE_ARRAYS_OF_ARRAYS) != 0; 218 int arrayLength = rnd.getInt(1, m_maxArrayLength); 219 220 if (complexity * arrayLength >= 70) 221 { 222 // Trim overly complicated cases (affects 18 cases out of 1576) 223 arrayLength = 1; 224 } 225 226 VarType elementType = generateType(rnd, typeDepth, arraysOfArraysOk, complexity * arrayLength); 227 return VarType(elementType, arrayLength); 228 } 229 else 230 { 231 std::vector<glu::DataType> typeCandidates; 232 233 typeCandidates.push_back(glu::TYPE_FLOAT); 234 typeCandidates.push_back(glu::TYPE_INT); 235 typeCandidates.push_back(glu::TYPE_UINT); 236 typeCandidates.push_back(glu::TYPE_BOOL); 237 238 if (m_features & FEATURE_16BIT_STORAGE) { 239 typeCandidates.push_back(glu::TYPE_UINT16); 240 typeCandidates.push_back(glu::TYPE_INT16); 241 typeCandidates.push_back(glu::TYPE_FLOAT16); 242 } 243 244 if (m_features & FEATURE_8BIT_STORAGE) { 245 typeCandidates.push_back(glu::TYPE_UINT8); 246 typeCandidates.push_back(glu::TYPE_INT8); 247 } 248 249 if (m_features & FEATURE_VECTORS) 250 { 251 typeCandidates.push_back(glu::TYPE_FLOAT_VEC2); 252 typeCandidates.push_back(glu::TYPE_FLOAT_VEC3); 253 typeCandidates.push_back(glu::TYPE_FLOAT_VEC4); 254 typeCandidates.push_back(glu::TYPE_INT_VEC2); 255 typeCandidates.push_back(glu::TYPE_INT_VEC3); 256 typeCandidates.push_back(glu::TYPE_INT_VEC4); 257 typeCandidates.push_back(glu::TYPE_UINT_VEC2); 258 typeCandidates.push_back(glu::TYPE_UINT_VEC3); 259 typeCandidates.push_back(glu::TYPE_UINT_VEC4); 260 typeCandidates.push_back(glu::TYPE_BOOL_VEC2); 261 typeCandidates.push_back(glu::TYPE_BOOL_VEC3); 262 typeCandidates.push_back(glu::TYPE_BOOL_VEC4); 263 if (m_features & FEATURE_16BIT_STORAGE) 264 { 265 typeCandidates.push_back(glu::TYPE_FLOAT16_VEC2); 266 typeCandidates.push_back(glu::TYPE_FLOAT16_VEC3); 267 typeCandidates.push_back(glu::TYPE_FLOAT16_VEC4); 268 typeCandidates.push_back(glu::TYPE_INT16_VEC2); 269 typeCandidates.push_back(glu::TYPE_INT16_VEC3); 270 typeCandidates.push_back(glu::TYPE_INT16_VEC4); 271 typeCandidates.push_back(glu::TYPE_UINT16_VEC2); 272 typeCandidates.push_back(glu::TYPE_UINT16_VEC3); 273 typeCandidates.push_back(glu::TYPE_UINT16_VEC4); 274 } 275 if (m_features & FEATURE_8BIT_STORAGE) 276 { 277 typeCandidates.push_back(glu::TYPE_INT8_VEC2); 278 typeCandidates.push_back(glu::TYPE_INT8_VEC3); 279 typeCandidates.push_back(glu::TYPE_INT8_VEC4); 280 typeCandidates.push_back(glu::TYPE_UINT8_VEC2); 281 typeCandidates.push_back(glu::TYPE_UINT8_VEC3); 282 typeCandidates.push_back(glu::TYPE_UINT8_VEC4); 283 } 284 } 285 286 if (m_features & FEATURE_MATRICES) 287 { 288 typeCandidates.push_back(glu::TYPE_FLOAT_MAT2); 289 typeCandidates.push_back(glu::TYPE_FLOAT_MAT2X3); 290 typeCandidates.push_back(glu::TYPE_FLOAT_MAT3X2); 291 typeCandidates.push_back(glu::TYPE_FLOAT_MAT3); 292 typeCandidates.push_back(glu::TYPE_FLOAT_MAT3X4); 293 typeCandidates.push_back(glu::TYPE_FLOAT_MAT4X2); 294 typeCandidates.push_back(glu::TYPE_FLOAT_MAT4X3); 295 typeCandidates.push_back(glu::TYPE_FLOAT_MAT4); 296 } 297 298 glu::DataType type = rnd.choose<glu::DataType>(typeCandidates.begin(), typeCandidates.end()); 299 deUint32 flags = (m_shuffleUniformMembers ? static_cast<deUint32>(LAYOUT_OFFSET) : 0u); 300 301 if (glu::dataTypeSupportsPrecisionModifier(type)) 302 { 303 // Precision. 304 static const deUint32 precisionCandidates[] = { PRECISION_LOW, PRECISION_MEDIUM, PRECISION_HIGH }; 305 flags |= rnd.choose<deUint32>(&precisionCandidates[0], &precisionCandidates[DE_LENGTH_OF_ARRAY(precisionCandidates)]); 306 } 307 308 return VarType(type, flags); 309 } 310} 311 312} // ubo 313} // vkt 314