/*------------------------------------------------------------------------ * Vulkan Conformance Tests * ------------------------ * * Copyright (c) 2015 The Khronos Group Inc. * Copyright (c) 2015 Samsung Electronics Co., Ltd. * Copyright (c) 2016 The Android Open Source Project * Copyright (c) 2018 The Khronos Group Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *//*! * \file * \brief Vulkan Transform Feedback Random Layout Tests *//*--------------------------------------------------------------------*/ #include "vktTransformFeedbackRandomLayoutCase.hpp" #include "deRandom.hpp" namespace vkt { namespace TransformFeedback { namespace { static std::string genName (char first, char last, int ndx) { std::string str = ""; int alphabetLen = last - first + 1; while (ndx > alphabetLen) { str.insert(str.begin(), (char)(first + ((ndx - 1) % alphabetLen))); ndx = (ndx - 1) / alphabetLen; } str.insert(str.begin(), (char)(first + (ndx % (alphabetLen + 1)) - 1)); return str; } } // anonymous RandomInterfaceBlockCase::RandomInterfaceBlockCase (tcu::TestContext& testCtx, const std::string& name, const TestStageFlags testStageFlags, deUint32 features, deUint32 seed) : InterfaceBlockCase (testCtx, name, LOAD_FULL_MATRIX, testStageFlags, (features & FEATURE_OUT_OF_ORDER_OFFSETS) != 0u) , m_features (features) , m_explicitXfbOffsets ((features & (FEATURE_OUT_OF_ORDER_OFFSETS | FEATURE_MISSING_BLOCK_MEMBERS)) != 0u) , m_maxBlocks (3) , m_maxInstances ((features & FEATURE_INSTANCE_ARRAYS) ? 3 : 0) , m_maxArrayLength ((features & FEATURE_ARRAYS) ? 4 : 0) , m_maxStructDepth ((features & FEATURE_STRUCTS) ? 2 : 0) , m_maxBlockMembers (3) , m_maxStructMembers (3) , m_seed (seed) , m_blockNdx (1) , m_interfaceNdx (1) , m_structNdx (1) , m_primitiveTypeCandidates (fillTypeCandidates()) { de::Random rnd(m_seed); int numBlocks = rnd.getInt(1, m_maxBlocks); InterfaceFlags stage = static_cast(LAYOUT_XFBBUFFER | LAYOUT_XFBOFFSET); for (int ndx = 0; ndx < numBlocks; ndx++) generateBlock(rnd, stage); // m_primitiveTypeCandidates is required during generation only m_primitiveTypeCandidates.clear(); init(); } std::vector RandomInterfaceBlockCase::fillTypeCandidates() { std::vector typeCandidates; typeCandidates.reserve(32); typeCandidates.push_back(glu::TYPE_FLOAT); typeCandidates.push_back(glu::TYPE_INT); typeCandidates.push_back(glu::TYPE_UINT); if (m_features & FEATURE_DOUBLES) typeCandidates.push_back(glu::TYPE_DOUBLE); if (m_features & FEATURE_VECTORS) { typeCandidates.push_back(glu::TYPE_FLOAT_VEC2); typeCandidates.push_back(glu::TYPE_FLOAT_VEC3); typeCandidates.push_back(glu::TYPE_FLOAT_VEC4); typeCandidates.push_back(glu::TYPE_INT_VEC2); typeCandidates.push_back(glu::TYPE_INT_VEC3); typeCandidates.push_back(glu::TYPE_INT_VEC4); typeCandidates.push_back(glu::TYPE_UINT_VEC2); typeCandidates.push_back(glu::TYPE_UINT_VEC3); typeCandidates.push_back(glu::TYPE_UINT_VEC4); if (m_features & FEATURE_DOUBLES) { typeCandidates.push_back(glu::TYPE_DOUBLE_VEC2); typeCandidates.push_back(glu::TYPE_DOUBLE_VEC3); typeCandidates.push_back(glu::TYPE_DOUBLE_VEC4); } } if (m_features & FEATURE_MATRICES) { typeCandidates.push_back(glu::TYPE_FLOAT_MAT2); typeCandidates.push_back(glu::TYPE_FLOAT_MAT2X3); typeCandidates.push_back(glu::TYPE_FLOAT_MAT3X2); typeCandidates.push_back(glu::TYPE_FLOAT_MAT3); typeCandidates.push_back(glu::TYPE_FLOAT_MAT3X4); typeCandidates.push_back(glu::TYPE_FLOAT_MAT4X2); typeCandidates.push_back(glu::TYPE_FLOAT_MAT4X3); typeCandidates.push_back(glu::TYPE_FLOAT_MAT4); if (m_features & FEATURE_DOUBLES) { typeCandidates.push_back(glu::TYPE_DOUBLE_MAT2); typeCandidates.push_back(glu::TYPE_DOUBLE_MAT2X3); typeCandidates.push_back(glu::TYPE_DOUBLE_MAT3X2); typeCandidates.push_back(glu::TYPE_DOUBLE_MAT3); typeCandidates.push_back(glu::TYPE_DOUBLE_MAT3X4); typeCandidates.push_back(glu::TYPE_DOUBLE_MAT4X2); typeCandidates.push_back(glu::TYPE_DOUBLE_MAT4X3); typeCandidates.push_back(glu::TYPE_DOUBLE_MAT4); } } return typeCandidates; } void RandomInterfaceBlockCase::generateBlock (de::Random& rnd, deUint32 layoutFlags) { DE_ASSERT(m_blockNdx <= 'z' - 'a'); const float instanceArrayWeight = 0.3f; InterfaceBlock& block = m_interface.allocBlock(std::string("Block") + (char)('A' + m_blockNdx)); int numInstances = (m_maxInstances > 0 && rnd.getFloat() < instanceArrayWeight) ? rnd.getInt(0, m_maxInstances) : 0; int numBlockMembers = rnd.getInt(1, m_maxBlockMembers); int numUnassignedOrMissing = 0; if (numInstances > 0) block.setArraySize(numInstances); if (numInstances > 0 || rnd.getBool()) block.setInstanceName(std::string("block") + (char)('A' + m_blockNdx)); block.setFlags(layoutFlags); for (int ndx = 0; ndx < numBlockMembers; ndx++) generateBlockMember(rnd, block, numBlockMembers, numUnassignedOrMissing); m_blockNdx += 1; } void RandomInterfaceBlockCase::generateBlockMember (de::Random& rnd, InterfaceBlock& block, const int numBlockMembers, int& numUnassignedOrMissing) { const float unassignedBlockMembersWeight = 0.15f; const float missingBlockMembersWeight = 0.15f; const bool unassignedAllowed = (m_features & FEATURE_UNASSIGNED_BLOCK_MEMBERS) != 0; const bool missingAllowed = (m_features & FEATURE_MISSING_BLOCK_MEMBERS) != 0; deUint32 flags = 0; std::string name = genName('a', 'z', m_interfaceNdx); VarType type = generateType(rnd, 0, true); if (numUnassignedOrMissing < numBlockMembers - 1) { if (missingAllowed && rnd.getFloat() < missingBlockMembersWeight) { flags |= FIELD_MISSING; numUnassignedOrMissing++; } else if (unassignedAllowed && rnd.getFloat() < unassignedBlockMembersWeight) { flags |= FIELD_UNASSIGNED; numUnassignedOrMissing++; } } block.addInterfaceMember(InterfaceBlockMember(name, type, flags)); m_interfaceNdx += 1; } VarType RandomInterfaceBlockCase::generateType (de::Random& rnd, int typeDepth, bool arrayOk) { const float structWeight = 0.1f; const float arrayWeight = 0.1f; if (typeDepth < m_maxStructDepth && rnd.getFloat() < structWeight) { const float unassignedFieldWeight = 0.15f; const bool unassignedOk = (m_features & FEATURE_UNASSIGNED_FIELDS) != 0; const int numMembers = rnd.getInt(1, m_maxStructMembers); std::vector memberTypes; // Generate members first so nested struct declarations are in correct order. for (int ndx = 0; ndx < numMembers; ndx++) memberTypes.push_back(generateType(rnd, typeDepth+1, true)); StructType& structType = m_interface.allocStruct(std::string("s") + genName('A', 'Z', m_structNdx)); m_structNdx += 1; DE_ASSERT(numMembers <= 'Z' - 'A'); for (int ndx = 0; ndx < numMembers; ndx++) { deUint32 flags = 0; if (unassignedOk && rnd.getFloat() < unassignedFieldWeight) { flags |= FIELD_UNASSIGNED; } structType.addMember(std::string("m") + (char)('A' + ndx), memberTypes[ndx], flags); } return VarType(&structType, m_explicitXfbOffsets ? static_cast(LAYOUT_XFBOFFSET) : 0u); } else if (m_maxArrayLength > 0 && arrayOk && rnd.getFloat() < arrayWeight) { const bool arraysOfArraysOk = (m_features & FEATURE_ARRAYS_OF_ARRAYS) != 0; const int arrayLength = rnd.getInt(1, m_maxArrayLength); VarType elementType = generateType(rnd, typeDepth, arraysOfArraysOk); return VarType(elementType, arrayLength); } else { glu::DataType type = rnd.choose(m_primitiveTypeCandidates.begin(), m_primitiveTypeCandidates.end()); deUint32 flags = (m_explicitXfbOffsets ? static_cast(LAYOUT_XFBOFFSET) : 0u); if (glu::dataTypeSupportsPrecisionModifier(type)) { // Precision. static const deUint32 precisionCandidates[] = { PRECISION_LOW, PRECISION_MEDIUM, PRECISION_HIGH }; flags |= rnd.choose(&precisionCandidates[0], &precisionCandidates[DE_LENGTH_OF_ARRAY(precisionCandidates)]); } return VarType(type, flags); } } } // TransformFeedback } // vkt