/*------------------------------------------------------------------------ * Vulkan Conformance Tests * ------------------------ * * Copyright (c) 2021 The Khronos Group Inc. * Copyright (c) 2021 Google LLC. * * 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 Shared memory model layout tests. *//*--------------------------------------------------------------------*/ #include "vktMemoryModelSharedLayout.hpp" #include "vktMemoryModelSharedLayoutCase.hpp" #include "tcuCommandLine.hpp" #include "tcuTestLog.hpp" #include "deRandom.hpp" #include "deStringUtil.hpp" #include "vktTestCaseUtil.hpp" #include "vkMemUtil.hpp" namespace vkt { namespace MemoryModel { using std::string; using std::vector; namespace { enum FeatureBits { FEATURE_VECTORS = (1 << 0), FEATURE_MATRICES = (1 << 1), FEATURE_ARRAYS = (1 << 2), FEATURE_STRUCTS = (1 << 3), FEATURE_UNUSED_VARS = (1 << 4), FEATURE_UNUSED_MEMBERS = (1 << 5), FEATURE_ARRAYS_OF_ARRAYS = (1 << 6), FEATURE_16BIT_TYPES = (1 << 7), FEATURE_8BIT_TYPES = (1 << 8), }; /*--------------------------------------------------------------------*//*! * \brief Generates names for shared memory structs and their members. * \param first The first character of the alphabet. * \param last The last character of the alphabet. * \param ndx The index of the name in the alphabet. * * If the index lies within the range [1, (last-first)+1], returns * the character represented by the ASCII code 'first + ndx - 1' * as a string. * * E.g. if "first" is 'a', "last" 'z' and "ndx" is 1, returns a. If "ndx" * is 2, returns b and so forth. * * If "ndx" is greater than the range, the function keeps dividing it by * the alphabet length until the index is within the range. In each iteration, * the name is prefixed with the ASCII character represented by the modulo * of the index. * * E.g. if "first" is 'a', "last" 'z' and "ndx" is 28, returns ab. If "ndx" * is 702, returns aaa and so forth. *//*--------------------------------------------------------------------*/ string genName (char first, char last, int ndx) { string str; int alphabetLen = static_cast(last) - static_cast(first) + 1; while (ndx > 0) { const int asciiCode = static_cast(first) + ((ndx - 1) % alphabetLen); str.insert(str.begin(), static_cast(asciiCode)); ndx = ((ndx - 1) / alphabetLen); } return str; } void createRandomCaseGroup (tcu::TestCaseGroup* parentGroup, tcu::TestContext &testCtx, const char *groupName, const deUint32 features, const int numCases, deUint32 baseSeed) { tcu::TestCaseGroup *group = new tcu::TestCaseGroup(testCtx, groupName); parentGroup->addChild(group); baseSeed += static_cast(testCtx.getCommandLine().getBaseSeed()); for (int i = 0; i < numCases; i++) group->addChild(new RandomSharedLayoutCase(testCtx, de::toString(i).c_str(), features, static_cast(i + baseSeed))); } } // anonymous RandomSharedLayoutCase::RandomSharedLayoutCase (tcu::TestContext &testCtx, const char *name, deUint32 features, deUint32 seed) : SharedLayoutCase(testCtx, name) , m_features(features) , m_maxArrayLength((features & FEATURE_ARRAYS) ? 3 : 0) , m_seed(seed) { de::Random rnd(m_seed); m_interface.enable16BitTypes(features & FEATURE_16BIT_TYPES); m_interface.enable8BitTypes(features & FEATURE_8BIT_TYPES); for (int i = 0; i < rnd.getInt(1, m_maxSharedObjects); i++) generateSharedMemoryObject(rnd); init(); } /*--------------------------------------------------------------------*//*! * \brief Creates definitions for shared memory structs. * \param rnd Random value generator used for deciding the type of the variable. * * Creates definitions for shared memory structs. Each struct's name starts with * an upper-case S and its instance name with a lower-case s followed by its index * number. *//*--------------------------------------------------------------------*/ void RandomSharedLayoutCase::generateSharedMemoryObject (de::Random &rnd) { const string name = "S" + de::toString(m_interface.getNumSharedObjects() + 1); const string instanceName = "s" + de::toString(m_interface.getNumSharedObjects() + 1); SharedStruct &object = m_interface.allocSharedObject(name, instanceName); const int numVars = rnd.getInt(2, m_maxSharedObjectMembers); for (int i = 0; i < numVars; i++) generateSharedMemoryVar(rnd, object); } void RandomSharedLayoutCase::generateSharedMemoryVar (de::Random &rnd, SharedStruct &object) { SharedStructVar var; var.name = genName('a', 'z', object.getNumMembers() + 1); if ((m_features & FEATURE_ARRAYS_OF_ARRAYS) != 0 || (m_features & FEATURE_STRUCTS) != 0) var.type = generateType(rnd, 3, true); else var.type = generateType(rnd, 1, true); var.topLevelArraySize = 1; if (var.type.isArrayType()) var.topLevelArraySize = var.type.getArraySize() == glu::VarType::UNSIZED_ARRAY ? 0 : var.type.getArraySize(); object.addMember(var); } glu::VarType RandomSharedLayoutCase::generateType (de::Random &rnd, int typeDepth, bool arrayOk) { const float structWeight = 0.7f; const float arrayWeight = 0.8f; if (typeDepth > 0 && rnd.getFloat() < structWeight && (m_features & FEATURE_STRUCTS)) { vector memberTypes; const int numMembers = rnd.getInt(1, m_maxStructMembers); // Generate members first so nested struct declarations are in correct order. for (int i = 0; i < numMembers; i++) memberTypes.push_back(generateType(rnd, typeDepth - 1, true)); const string name = "s" + genName('A', 'Z', m_interface.getNumStructs() + 1); de::SharedPtr structType = m_interface.allocStruct(name); DE_ASSERT(numMembers <= 'Z' - 'A'); for (int i = 0; i < numMembers; i++) structType.get()->addMember((string("m") + static_cast(('A' + i))).c_str(), memberTypes[i]); return glu::VarType(structType.get()); } else if (typeDepth > 0 && m_maxArrayLength > 0 && arrayOk && rnd.getFloat() < arrayWeight) { const int arrayLength = rnd.getInt(1, m_maxArrayLength); const bool childArrayOk = (m_features & FEATURE_ARRAYS_OF_ARRAYS) != 0; const glu::VarType elementType = generateType(rnd, typeDepth - 1, childArrayOk); return glu::VarType(elementType, arrayLength); } else { const float weight8Bit = (m_features & FEATURE_8BIT_TYPES) ? 0.7f : 0.0f; const float weight16Bit = (m_features & FEATURE_16BIT_TYPES) ? 0.7f : 0.0f; const float weightMatrices = (m_features & FEATURE_MATRICES) ? 0.3f : 0.0f; vector typeCandidates; if (rnd.getFloat() < weight16Bit) { typeCandidates.push_back(glu::TYPE_UINT16); typeCandidates.push_back(glu::TYPE_INT16); typeCandidates.push_back(glu::TYPE_FLOAT16); if (m_features & FEATURE_VECTORS) { typeCandidates.push_back(glu::TYPE_FLOAT16_VEC2); typeCandidates.push_back(glu::TYPE_FLOAT16_VEC3); typeCandidates.push_back(glu::TYPE_FLOAT16_VEC4); typeCandidates.push_back(glu::TYPE_INT16_VEC2); typeCandidates.push_back(glu::TYPE_INT16_VEC3); typeCandidates.push_back(glu::TYPE_INT16_VEC4); typeCandidates.push_back(glu::TYPE_UINT16_VEC2); typeCandidates.push_back(glu::TYPE_UINT16_VEC3); typeCandidates.push_back(glu::TYPE_UINT16_VEC4); } } else if (rnd.getFloat() < weight8Bit) { typeCandidates.push_back(glu::TYPE_UINT8); typeCandidates.push_back(glu::TYPE_INT8); if (m_features & FEATURE_VECTORS) { typeCandidates.push_back(glu::TYPE_INT8_VEC2); typeCandidates.push_back(glu::TYPE_INT8_VEC3); typeCandidates.push_back(glu::TYPE_INT8_VEC4); typeCandidates.push_back(glu::TYPE_UINT8_VEC2); typeCandidates.push_back(glu::TYPE_UINT8_VEC3); typeCandidates.push_back(glu::TYPE_UINT8_VEC4); } } else { typeCandidates.push_back(glu::TYPE_FLOAT); typeCandidates.push_back(glu::TYPE_INT); typeCandidates.push_back(glu::TYPE_UINT); typeCandidates.push_back(glu::TYPE_BOOL); 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); typeCandidates.push_back(glu::TYPE_BOOL_VEC2); typeCandidates.push_back(glu::TYPE_BOOL_VEC3); typeCandidates.push_back(glu::TYPE_BOOL_VEC4); } } if (rnd.getFloat() < weightMatrices) { 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); } glu::DataType type = rnd.choose(typeCandidates.begin(), typeCandidates.end()); glu::Precision precision; if (glu::dataTypeSupportsPrecisionModifier(type)) { const glu::Precision precisionCandidates[] = { glu::PRECISION_LOWP, glu::PRECISION_MEDIUMP, glu::PRECISION_HIGHP}; precision = rnd.choose(&precisionCandidates[0], &precisionCandidates[DE_LENGTH_OF_ARRAY(precisionCandidates)]); } else precision = glu::PRECISION_LAST; return glu::VarType(type, precision); } } tcu::TestCaseGroup* createSharedMemoryLayoutTests (tcu::TestContext &testCtx) { de::MovePtr sharedMemoryLayoutGroup(new tcu::TestCaseGroup(testCtx, "shared")); tcu::TestCaseGroup *parentGroup = sharedMemoryLayoutGroup.get(); { const deUint32 allBasicTypes = FEATURE_VECTORS | FEATURE_MATRICES; const deUint32 unused = FEATURE_UNUSED_MEMBERS | FEATURE_UNUSED_VARS; for (int i = 0; i < 3; ++i) { if (i == 1) { parentGroup = new tcu::TestCaseGroup(testCtx, "16bit"); sharedMemoryLayoutGroup->addChild(parentGroup); } else if (i == 2) { parentGroup = new tcu::TestCaseGroup(testCtx, "8bit"); sharedMemoryLayoutGroup->addChild(parentGroup); } const deUint32 use16BitTypes = i == 1 ? FEATURE_16BIT_TYPES : 0; const deUint32 use8BitTypes = i == 2 ? FEATURE_8BIT_TYPES : 0; createRandomCaseGroup(parentGroup, testCtx, "scalar_types", use8BitTypes | use16BitTypes | unused, 10, 0); createRandomCaseGroup(parentGroup, testCtx, "vector_types", use8BitTypes | use16BitTypes | unused | FEATURE_VECTORS, 10, 25); createRandomCaseGroup(parentGroup, testCtx, "basic_types", use8BitTypes | use16BitTypes | unused | allBasicTypes, 10, 50); createRandomCaseGroup(parentGroup, testCtx, "basic_arrays", use8BitTypes | use16BitTypes | unused | allBasicTypes | FEATURE_ARRAYS, 10, 50); createRandomCaseGroup(parentGroup, testCtx, "arrays_of_arrays", use8BitTypes | use16BitTypes | unused | allBasicTypes | FEATURE_ARRAYS | FEATURE_ARRAYS_OF_ARRAYS, 10, 950); createRandomCaseGroup(parentGroup, testCtx, "nested_structs", use8BitTypes | use16BitTypes | unused | allBasicTypes | FEATURE_STRUCTS, 10, 100); createRandomCaseGroup(parentGroup, testCtx, "nested_structs_arrays", use8BitTypes | use16BitTypes | unused | allBasicTypes | FEATURE_STRUCTS | FEATURE_ARRAYS | FEATURE_ARRAYS_OF_ARRAYS, 10, 150); } } return sharedMemoryLayoutGroup.release(); } } // MemoryModel } // vkt