| /*------------------------------------------------------------------------- |
| * OpenGL Conformance Test Suite |
| * ----------------------------- |
| * |
| * Copyright (c) 2016 Google Inc. |
| * Copyright (c) 2016 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 Uniform block tests. |
| */ /*-------------------------------------------------------------------*/ |
| |
| #include "glcUniformBlockTests.hpp" |
| #include "deRandom.hpp" |
| #include "deStringUtil.hpp" |
| #include "glcUniformBlockCase.hpp" |
| #include "glwEnums.hpp" |
| #include "glwFunctions.hpp" |
| #include "tcuCommandLine.hpp" |
| #include "tcuTestLog.hpp" |
| |
| namespace deqp |
| { |
| |
| using std::string; |
| using std::vector; |
| using deqp::Context; |
| |
| using namespace ub; |
| |
| enum FeatureBits |
| { |
| FEATURE_VECTORS = (1 << 0), |
| FEATURE_MATRICES = (1 << 1), |
| FEATURE_ARRAYS = (1 << 2), |
| FEATURE_STRUCTS = (1 << 3), |
| FEATURE_NESTED_STRUCTS = (1 << 4), |
| FEATURE_INSTANCE_ARRAYS = (1 << 5), |
| FEATURE_VERTEX_BLOCKS = (1 << 6), |
| FEATURE_FRAGMENT_BLOCKS = (1 << 7), |
| FEATURE_SHARED_BLOCKS = (1 << 8), |
| FEATURE_UNUSED_UNIFORMS = (1 << 9), |
| FEATURE_UNUSED_MEMBERS = (1 << 10), |
| FEATURE_PACKED_LAYOUT = (1 << 11), |
| FEATURE_SHARED_LAYOUT = (1 << 12), |
| FEATURE_STD140_LAYOUT = (1 << 13), |
| FEATURE_MATRIX_LAYOUT = (1 << 14) //!< Matrix layout flags. |
| }; |
| |
| class RandomUniformBlockCase : public UniformBlockCase |
| { |
| public: |
| RandomUniformBlockCase(Context& context, const char* name, const char* description, glu::GLSLVersion glslVersion, |
| BufferMode bufferMode, deUint32 features, deUint32 seed); |
| |
| void init(void); |
| |
| private: |
| void generateBlock(de::Random& rnd, deUint32 layoutFlags); |
| void generateUniform(de::Random& rnd, UniformBlock& block); |
| VarType generateType(de::Random& rnd, int typeDepth, bool arrayOk); |
| |
| deUint32 m_features; |
| int m_maxVertexBlocks; |
| int m_maxFragmentBlocks; |
| int m_maxSharedBlocks; |
| int m_maxInstances; |
| int m_maxArrayLength; |
| int m_maxStructDepth; |
| int m_maxBlockMembers; |
| int m_maxStructMembers; |
| deUint32 m_seed; |
| |
| int m_blockNdx; |
| int m_uniformNdx; |
| int m_structNdx; |
| }; |
| |
| RandomUniformBlockCase::RandomUniformBlockCase(Context& context, const char* name, const char* description, |
| glu::GLSLVersion glslVersion, BufferMode bufferMode, deUint32 features, |
| deUint32 seed) |
| : UniformBlockCase(context, name, description, glslVersion, bufferMode) |
| , m_features(features) |
| , m_maxVertexBlocks((features & FEATURE_VERTEX_BLOCKS) ? 4 : 0) |
| , m_maxFragmentBlocks((features & FEATURE_FRAGMENT_BLOCKS) ? 4 : 0) |
| , m_maxSharedBlocks((features & FEATURE_SHARED_BLOCKS) ? 4 : 0) |
| , m_maxInstances((features & FEATURE_INSTANCE_ARRAYS) ? 3 : 0) |
| , m_maxArrayLength((features & FEATURE_ARRAYS) ? 8 : 0) |
| , m_maxStructDepth((features & FEATURE_STRUCTS) ? 2 : 0) |
| , m_maxBlockMembers(5) |
| , m_maxStructMembers(4) |
| , m_seed(seed) |
| , m_blockNdx(1) |
| , m_uniformNdx(1) |
| , m_structNdx(1) |
| { |
| } |
| |
| void RandomUniformBlockCase::init(void) |
| { |
| de::Random rnd(m_seed); |
| |
| int numShared = m_maxSharedBlocks > 0 ? rnd.getInt(1, m_maxSharedBlocks) : 0; |
| int numVtxBlocks = m_maxVertexBlocks - numShared > 0 ? rnd.getInt(1, m_maxVertexBlocks - numShared) : 0; |
| int numFragBlocks = m_maxFragmentBlocks - numShared > 0 ? rnd.getInt(1, m_maxFragmentBlocks - numShared) : 0; |
| |
| for (int ndx = 0; ndx < numShared; ndx++) |
| generateBlock(rnd, DECLARE_VERTEX | DECLARE_FRAGMENT); |
| |
| for (int ndx = 0; ndx < numVtxBlocks; ndx++) |
| generateBlock(rnd, DECLARE_VERTEX); |
| |
| for (int ndx = 0; ndx < numFragBlocks; ndx++) |
| generateBlock(rnd, DECLARE_FRAGMENT); |
| } |
| |
| void RandomUniformBlockCase::generateBlock(de::Random& rnd, deUint32 layoutFlags) |
| { |
| DE_ASSERT(m_blockNdx <= 'z' - 'a'); |
| |
| const float instanceArrayWeight = 0.3f; |
| UniformBlock& block = m_interface.allocBlock((string("Block") + (char)('A' + m_blockNdx)).c_str()); |
| int numInstances = (m_maxInstances > 0 && rnd.getFloat() < instanceArrayWeight) ? rnd.getInt(0, m_maxInstances) : 0; |
| int numUniforms = rnd.getInt(1, m_maxBlockMembers); |
| |
| if (numInstances > 0) |
| block.setArraySize(numInstances); |
| |
| if (numInstances > 0 || rnd.getBool()) |
| block.setInstanceName((string("block") + (char)('A' + m_blockNdx)).c_str()); |
| |
| // Layout flag candidates. |
| vector<deUint32> layoutFlagCandidates; |
| layoutFlagCandidates.push_back(0); |
| if (m_features & FEATURE_PACKED_LAYOUT) |
| layoutFlagCandidates.push_back(LAYOUT_SHARED); |
| if ((m_features & FEATURE_SHARED_LAYOUT) && ((layoutFlags & DECLARE_BOTH) != DECLARE_BOTH)) |
| layoutFlagCandidates.push_back(LAYOUT_PACKED); // \note packed layout can only be used in a single shader stage. |
| if (m_features & FEATURE_STD140_LAYOUT) |
| layoutFlagCandidates.push_back(LAYOUT_STD140); |
| |
| layoutFlags |= rnd.choose<deUint32>(layoutFlagCandidates.begin(), layoutFlagCandidates.end()); |
| |
| if (m_features & FEATURE_MATRIX_LAYOUT) |
| { |
| static const deUint32 matrixCandidates[] = { 0, LAYOUT_ROW_MAJOR, LAYOUT_COLUMN_MAJOR }; |
| layoutFlags |= |
| rnd.choose<deUint32>(&matrixCandidates[0], &matrixCandidates[DE_LENGTH_OF_ARRAY(matrixCandidates)]); |
| } |
| |
| block.setFlags(layoutFlags); |
| |
| for (int ndx = 0; ndx < numUniforms; ndx++) |
| generateUniform(rnd, block); |
| |
| m_blockNdx += 1; |
| } |
| |
| 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; |
| } |
| |
| void RandomUniformBlockCase::generateUniform(de::Random& rnd, UniformBlock& block) |
| { |
| const float unusedVtxWeight = 0.15f; |
| const float unusedFragWeight = 0.15f; |
| bool unusedOk = (m_features & FEATURE_UNUSED_UNIFORMS) != 0; |
| deUint32 flags = 0; |
| std::string name = genName('a', 'z', m_uniformNdx); |
| VarType type = generateType(rnd, 0, true); |
| |
| flags |= (unusedOk && rnd.getFloat() < unusedVtxWeight) ? UNUSED_VERTEX : 0; |
| flags |= (unusedOk && rnd.getFloat() < unusedFragWeight) ? UNUSED_FRAGMENT : 0; |
| |
| block.addUniform(Uniform(name.c_str(), type, flags)); |
| |
| m_uniformNdx += 1; |
| } |
| |
| VarType RandomUniformBlockCase::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 unusedVtxWeight = 0.15f; |
| const float unusedFragWeight = 0.15f; |
| bool unusedOk = (m_features & FEATURE_UNUSED_MEMBERS) != 0; |
| vector<VarType> memberTypes; |
| int numMembers = rnd.getInt(1, m_maxStructMembers); |
| |
| // 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((string("s") + genName('A', 'Z', m_structNdx)).c_str()); |
| m_structNdx += 1; |
| |
| DE_ASSERT(numMembers <= 'Z' - 'A'); |
| for (int ndx = 0; ndx < numMembers; ndx++) |
| { |
| deUint32 flags = 0; |
| |
| flags |= (unusedOk && rnd.getFloat() < unusedVtxWeight) ? UNUSED_VERTEX : 0; |
| flags |= (unusedOk && rnd.getFloat() < unusedFragWeight) ? UNUSED_FRAGMENT : 0; |
| |
| structType.addMember((string("m") + (char)('A' + ndx)).c_str(), memberTypes[ndx], flags); |
| } |
| |
| return VarType(&structType); |
| } |
| else if (m_maxArrayLength > 0 && arrayOk && rnd.getFloat() < arrayWeight) |
| { |
| int arrayLength = rnd.getInt(1, m_maxArrayLength); |
| VarType elementType = generateType(rnd, typeDepth, false /* nested arrays are not allowed */); |
| return VarType(elementType, arrayLength); |
| } |
| else |
| { |
| vector<glu::DataType> typeCandidates; |
| |
| 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 (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); |
| } |
| |
| glu::DataType type = rnd.choose<glu::DataType>(typeCandidates.begin(), typeCandidates.end()); |
| deUint32 flags = 0; |
| |
| if (!glu::isDataTypeBoolOrBVec(type)) |
| { |
| // Precision. |
| static const deUint32 precisionCandidates[] = { PRECISION_LOW, PRECISION_MEDIUM, PRECISION_HIGH }; |
| flags |= rnd.choose<deUint32>(&precisionCandidates[0], |
| &precisionCandidates[DE_LENGTH_OF_ARRAY(precisionCandidates)]); |
| } |
| |
| return VarType(type, flags); |
| } |
| } |
| |
| class BlockBasicTypeCase : public UniformBlockCase |
| { |
| public: |
| BlockBasicTypeCase(Context& context, const char* name, const char* description, glu::GLSLVersion glslVersion, |
| const VarType& type, deUint32 layoutFlags, int numInstances) |
| : UniformBlockCase(context, name, description, glslVersion, BUFFERMODE_PER_BLOCK) |
| { |
| UniformBlock& block = m_interface.allocBlock("Block"); |
| block.addUniform(Uniform("var", type, 0)); |
| block.setFlags(layoutFlags); |
| |
| if (numInstances > 0) |
| { |
| block.setArraySize(numInstances); |
| block.setInstanceName("block"); |
| } |
| } |
| }; |
| |
| static void createRandomCaseGroup(tcu::TestCaseGroup* parentGroup, Context& context, const char* groupName, |
| const char* description, glu::GLSLVersion glslVersion, |
| UniformBlockCase::BufferMode bufferMode, deUint32 features, int numCases, |
| deUint32 baseSeed) |
| { |
| tcu::TestCaseGroup* group = new tcu::TestCaseGroup(context.getTestContext(), groupName, description); |
| parentGroup->addChild(group); |
| |
| baseSeed += (deUint32)context.getTestContext().getCommandLine().getBaseSeed(); |
| |
| for (int ndx = 0; ndx < numCases; ndx++) |
| group->addChild(new RandomUniformBlockCase(context, de::toString(ndx).c_str(), "", glslVersion, bufferMode, |
| features, (deUint32)deInt32Hash(ndx + baseSeed))); |
| } |
| |
| class BlockSingleStructCase : public UniformBlockCase |
| { |
| public: |
| BlockSingleStructCase(Context& context, const char* name, const char* description, glu::GLSLVersion glslVersion, |
| deUint32 layoutFlags, BufferMode bufferMode, int numInstances) |
| : UniformBlockCase(context, name, description, glslVersion, bufferMode) |
| , m_layoutFlags(layoutFlags) |
| , m_numInstances(numInstances) |
| { |
| } |
| |
| void init(void) |
| { |
| StructType& typeS = m_interface.allocStruct("S"); |
| typeS.addMember("a", VarType(glu::TYPE_INT_VEC3, PRECISION_HIGH), UNUSED_BOTH); // First member is unused. |
| typeS.addMember("b", VarType(VarType(glu::TYPE_FLOAT_MAT3, PRECISION_MEDIUM), 4)); |
| typeS.addMember("c", VarType(glu::TYPE_FLOAT_VEC4, PRECISION_HIGH)); |
| |
| UniformBlock& block = m_interface.allocBlock("Block"); |
| block.addUniform(Uniform("s", VarType(&typeS), 0)); |
| block.setFlags(m_layoutFlags); |
| |
| if (m_numInstances > 0) |
| { |
| block.setInstanceName("block"); |
| block.setArraySize(m_numInstances); |
| } |
| } |
| |
| private: |
| deUint32 m_layoutFlags; |
| int m_numInstances; |
| }; |
| |
| class BlockSingleStructArrayCase : public UniformBlockCase |
| { |
| public: |
| BlockSingleStructArrayCase(Context& context, const char* name, const char* description, |
| glu::GLSLVersion glslVersion, deUint32 layoutFlags, BufferMode bufferMode, |
| int numInstances) |
| : UniformBlockCase(context, name, description, glslVersion, bufferMode) |
| , m_layoutFlags(layoutFlags) |
| , m_numInstances(numInstances) |
| { |
| } |
| |
| void init(void) |
| { |
| StructType& typeS = m_interface.allocStruct("S"); |
| typeS.addMember("a", VarType(glu::TYPE_INT_VEC3, PRECISION_HIGH), UNUSED_BOTH); |
| typeS.addMember("b", VarType(VarType(glu::TYPE_FLOAT_MAT3, PRECISION_MEDIUM), 4)); |
| typeS.addMember("c", VarType(glu::TYPE_FLOAT_VEC4, PRECISION_HIGH)); |
| |
| UniformBlock& block = m_interface.allocBlock("Block"); |
| block.addUniform(Uniform("u", VarType(glu::TYPE_UINT, PRECISION_LOW))); |
| block.addUniform(Uniform("s", VarType(VarType(&typeS), 3))); |
| block.addUniform(Uniform("v", VarType(glu::TYPE_FLOAT_VEC4, PRECISION_MEDIUM))); |
| block.setFlags(m_layoutFlags); |
| |
| if (m_numInstances > 0) |
| { |
| block.setInstanceName("block"); |
| block.setArraySize(m_numInstances); |
| } |
| } |
| |
| private: |
| deUint32 m_layoutFlags; |
| int m_numInstances; |
| }; |
| |
| class BlockSingleNestedStructCase : public UniformBlockCase |
| { |
| public: |
| BlockSingleNestedStructCase(Context& context, const char* name, const char* description, |
| glu::GLSLVersion glslVersion, deUint32 layoutFlags, BufferMode bufferMode, |
| int numInstances) |
| : UniformBlockCase(context, name, description, glslVersion, bufferMode) |
| , m_layoutFlags(layoutFlags) |
| , m_numInstances(numInstances) |
| { |
| } |
| |
| void init(void) |
| { |
| StructType& typeS = m_interface.allocStruct("S"); |
| typeS.addMember("a", VarType(glu::TYPE_INT_VEC3, PRECISION_HIGH)); |
| typeS.addMember("b", VarType(VarType(glu::TYPE_FLOAT_MAT3, PRECISION_MEDIUM), 4)); |
| typeS.addMember("c", VarType(glu::TYPE_FLOAT_VEC4, PRECISION_HIGH), UNUSED_BOTH); |
| |
| StructType& typeT = m_interface.allocStruct("T"); |
| typeT.addMember("a", VarType(glu::TYPE_FLOAT_MAT3, PRECISION_MEDIUM)); |
| typeT.addMember("b", VarType(&typeS)); |
| |
| UniformBlock& block = m_interface.allocBlock("Block"); |
| block.addUniform(Uniform("s", VarType(&typeS), 0)); |
| block.addUniform(Uniform("v", VarType(glu::TYPE_FLOAT_VEC2, PRECISION_LOW), UNUSED_BOTH)); |
| block.addUniform(Uniform("t", VarType(&typeT), 0)); |
| block.addUniform(Uniform("u", VarType(glu::TYPE_UINT, PRECISION_HIGH), 0)); |
| block.setFlags(m_layoutFlags); |
| |
| if (m_numInstances > 0) |
| { |
| block.setInstanceName("block"); |
| block.setArraySize(m_numInstances); |
| } |
| } |
| |
| private: |
| deUint32 m_layoutFlags; |
| int m_numInstances; |
| }; |
| |
| class BlockSingleNestedStructArrayCase : public UniformBlockCase |
| { |
| public: |
| BlockSingleNestedStructArrayCase(Context& context, const char* name, const char* description, |
| glu::GLSLVersion glslVersion, deUint32 layoutFlags, BufferMode bufferMode, |
| int numInstances) |
| : UniformBlockCase(context, name, description, glslVersion, bufferMode) |
| , m_layoutFlags(layoutFlags) |
| , m_numInstances(numInstances) |
| { |
| } |
| |
| void init(void) |
| { |
| StructType& typeS = m_interface.allocStruct("S"); |
| typeS.addMember("a", VarType(glu::TYPE_INT_VEC3, PRECISION_HIGH)); |
| typeS.addMember("b", VarType(VarType(glu::TYPE_INT_VEC2, PRECISION_MEDIUM), 4)); |
| typeS.addMember("c", VarType(glu::TYPE_FLOAT_VEC4, PRECISION_HIGH), UNUSED_BOTH); |
| |
| StructType& typeT = m_interface.allocStruct("T"); |
| typeT.addMember("a", VarType(glu::TYPE_FLOAT_MAT3, PRECISION_MEDIUM)); |
| typeT.addMember("b", VarType(VarType(&typeS), 3)); |
| |
| UniformBlock& block = m_interface.allocBlock("Block"); |
| block.addUniform(Uniform("s", VarType(&typeS), 0)); |
| block.addUniform(Uniform("v", VarType(glu::TYPE_FLOAT_VEC2, PRECISION_LOW), UNUSED_BOTH)); |
| block.addUniform(Uniform("t", VarType(VarType(&typeT), 2), 0)); |
| block.addUniform(Uniform("u", VarType(glu::TYPE_UINT, PRECISION_HIGH), 0)); |
| block.setFlags(m_layoutFlags); |
| |
| if (m_numInstances > 0) |
| { |
| block.setInstanceName("block"); |
| block.setArraySize(m_numInstances); |
| } |
| } |
| |
| private: |
| deUint32 m_layoutFlags; |
| int m_numInstances; |
| }; |
| |
| class BlockMultiBasicTypesCase : public UniformBlockCase |
| { |
| public: |
| BlockMultiBasicTypesCase(Context& context, const char* name, const char* description, glu::GLSLVersion glslVersion, |
| deUint32 flagsA, deUint32 flagsB, BufferMode bufferMode, int numInstances) |
| : UniformBlockCase(context, name, description, glslVersion, bufferMode) |
| , m_flagsA(flagsA) |
| , m_flagsB(flagsB) |
| , m_numInstances(numInstances) |
| { |
| } |
| |
| void init(void) |
| { |
| UniformBlock& blockA = m_interface.allocBlock("BlockA"); |
| blockA.addUniform(Uniform("a", VarType(glu::TYPE_FLOAT, PRECISION_HIGH))); |
| blockA.addUniform(Uniform("b", VarType(glu::TYPE_UINT_VEC3, PRECISION_LOW), UNUSED_BOTH)); |
| blockA.addUniform(Uniform("c", VarType(glu::TYPE_FLOAT_MAT2, PRECISION_MEDIUM))); |
| blockA.setInstanceName("blockA"); |
| blockA.setFlags(m_flagsA); |
| |
| UniformBlock& blockB = m_interface.allocBlock("BlockB"); |
| blockB.addUniform(Uniform("a", VarType(glu::TYPE_FLOAT_MAT3, PRECISION_MEDIUM))); |
| blockB.addUniform(Uniform("b", VarType(glu::TYPE_INT_VEC2, PRECISION_LOW))); |
| blockB.addUniform(Uniform("c", VarType(glu::TYPE_FLOAT_VEC4, PRECISION_HIGH), UNUSED_BOTH)); |
| blockB.addUniform(Uniform("d", VarType(glu::TYPE_BOOL, 0))); |
| blockB.setInstanceName("blockB"); |
| blockB.setFlags(m_flagsB); |
| |
| if (m_numInstances > 0) |
| { |
| blockA.setArraySize(m_numInstances); |
| blockB.setArraySize(m_numInstances); |
| } |
| } |
| |
| private: |
| deUint32 m_flagsA; |
| deUint32 m_flagsB; |
| int m_numInstances; |
| }; |
| |
| class BlockMultiNestedStructCase : public UniformBlockCase |
| { |
| public: |
| BlockMultiNestedStructCase(Context& context, const char* name, const char* description, |
| glu::GLSLVersion glslVersion, deUint32 flagsA, deUint32 flagsB, BufferMode bufferMode, |
| int numInstances) |
| : UniformBlockCase(context, name, description, glslVersion, bufferMode) |
| , m_flagsA(flagsA) |
| , m_flagsB(flagsB) |
| , m_numInstances(numInstances) |
| { |
| } |
| |
| void init(void) |
| { |
| StructType& typeS = m_interface.allocStruct("S"); |
| typeS.addMember("a", VarType(glu::TYPE_FLOAT_MAT3, PRECISION_LOW)); |
| typeS.addMember("b", VarType(VarType(glu::TYPE_INT_VEC2, PRECISION_MEDIUM), 4)); |
| typeS.addMember("c", VarType(glu::TYPE_FLOAT_VEC4, PRECISION_HIGH)); |
| |
| StructType& typeT = m_interface.allocStruct("T"); |
| typeT.addMember("a", VarType(glu::TYPE_UINT, PRECISION_MEDIUM), UNUSED_BOTH); |
| typeT.addMember("b", VarType(&typeS)); |
| typeT.addMember("c", VarType(glu::TYPE_BOOL_VEC4, 0)); |
| |
| UniformBlock& blockA = m_interface.allocBlock("BlockA"); |
| blockA.addUniform(Uniform("a", VarType(glu::TYPE_FLOAT, PRECISION_HIGH))); |
| blockA.addUniform(Uniform("b", VarType(&typeS))); |
| blockA.addUniform(Uniform("c", VarType(glu::TYPE_UINT_VEC3, PRECISION_LOW), UNUSED_BOTH)); |
| blockA.setInstanceName("blockA"); |
| blockA.setFlags(m_flagsA); |
| |
| UniformBlock& blockB = m_interface.allocBlock("BlockB"); |
| blockB.addUniform(Uniform("a", VarType(glu::TYPE_FLOAT_MAT2, PRECISION_MEDIUM))); |
| blockB.addUniform(Uniform("b", VarType(&typeT))); |
| blockB.addUniform(Uniform("c", VarType(glu::TYPE_BOOL_VEC4, 0), UNUSED_BOTH)); |
| blockB.addUniform(Uniform("d", VarType(glu::TYPE_BOOL, 0))); |
| blockB.setInstanceName("blockB"); |
| blockB.setFlags(m_flagsB); |
| |
| if (m_numInstances > 0) |
| { |
| blockA.setArraySize(m_numInstances); |
| blockB.setArraySize(m_numInstances); |
| } |
| } |
| |
| private: |
| deUint32 m_flagsA; |
| deUint32 m_flagsB; |
| int m_numInstances; |
| }; |
| |
| class UniformBlockPrecisionMatching : public TestCase |
| { |
| public: |
| UniformBlockPrecisionMatching(Context& context, glu::GLSLVersion glslVersion) |
| : TestCase(context, "precision_matching", ""), m_glslVersion(glslVersion) |
| { |
| } |
| |
| IterateResult iterate(void) |
| { |
| std::string vs1("layout (std140) uniform Data { lowp float x; } myData;\n" |
| "void main() {\n" |
| " gl_Position = vec4(myData.x, 0.0, 0.0, 1.0);\n" |
| "}"); |
| std::string fs1("precision highp float;\n" |
| "out vec4 color;\n" |
| "layout (std140) uniform Data { float x; } myData;\n" |
| "void main() {\n" |
| " color = vec4(myData.x);\n" |
| "}"); |
| |
| std::string vs2("layout (std140) uniform Data { highp int x; mediump int y; } myData;\n" |
| "void main() {\n" |
| " gl_Position = vec4(float(myData.x), 0.0, 0.0, 1.0);\n" |
| "}"); |
| std::string fs2("precision highp float;\n" |
| "out vec4 color;\n" |
| "layout (std140) uniform Data { mediump int x; highp int y; } myData;\n" |
| "void main() {\n" |
| " color = vec4(float(myData.y));\n" |
| "}"); |
| |
| m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); |
| if (!Link(vs1, fs1) || !Link(vs2, fs2)) |
| m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); |
| return STOP; |
| } |
| |
| bool Link(const std::string& vs, const std::string& fs) |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| const glw::GLuint p = gl.createProgram(); |
| const std::string version = glu::getGLSLVersionDeclaration(m_glslVersion); |
| |
| const struct |
| { |
| const char* name; |
| const std::string& body; |
| glw::GLenum type; |
| } shaderDefinition[] = { { "VS", vs, GL_VERTEX_SHADER }, { "FS", fs, GL_FRAGMENT_SHADER } }; |
| |
| for (unsigned int index = 0; index < 2; ++index) |
| { |
| std::string shaderSource = version + "\n" + shaderDefinition[index].body; |
| const char* shaderSourcePtr = shaderSource.c_str(); |
| |
| glw::GLuint sh = gl.createShader(shaderDefinition[index].type); |
| gl.attachShader(p, sh); |
| gl.deleteShader(sh); |
| gl.shaderSource(sh, 1, &shaderSourcePtr, NULL); |
| gl.compileShader(sh); |
| |
| glw::GLint status; |
| gl.getShaderiv(sh, GL_COMPILE_STATUS, &status); |
| if (status == GL_FALSE) |
| { |
| glw::GLint length; |
| gl.getShaderiv(sh, GL_INFO_LOG_LENGTH, &length); |
| if (length > 0) |
| { |
| std::vector<glw::GLchar> log(length); |
| gl.getShaderInfoLog(sh, length, NULL, &log[0]); |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << shaderDefinition[index].name |
| << " compilation should succed. Info Log:\n" |
| << &log[0] << tcu::TestLog::EndMessage; |
| } |
| gl.deleteProgram(p); |
| return false; |
| } |
| } |
| |
| gl.linkProgram(p); |
| |
| bool result = true; |
| glw::GLint status; |
| gl.getProgramiv(p, GL_LINK_STATUS, &status); |
| if (status == GL_FALSE) |
| { |
| glw::GLchar log[1024]; |
| gl.getProgramInfoLog(p, sizeof(log), NULL, log); |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "Link operation should succed. Info Log:\n" |
| << log << tcu::TestLog::EndMessage; |
| result = false; |
| } |
| |
| gl.deleteProgram(p); |
| return result; |
| } |
| |
| private: |
| glu::GLSLVersion m_glslVersion; |
| }; |
| |
| class UniformBlockNameMatching : public TestCase |
| { |
| public: |
| UniformBlockNameMatching(Context& context, glu::GLSLVersion glslVersion) |
| : TestCase(context, "name_matching", ""), m_glslVersion(glslVersion) |
| { |
| } |
| |
| IterateResult iterate(void) |
| { |
| m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); |
| |
| std::string vs1("precision highp float;\n" |
| "layout (std140) uniform Data { vec4 v; };\n" |
| "void main() {\n" |
| " gl_Position = v;\n" |
| "}"); |
| std::string fs1("precision highp float;\n" |
| "out vec4 color;\n" |
| "layout (std140) uniform Data { vec4 v; } myData;\n" |
| "void main() {\n" |
| " color = vec4(myData.v);\n" |
| "}"); |
| |
| // check if link error is generated when one of matched blocks has instance name and other doesn't |
| if (!Test(vs1, fs1, GL_FALSE)) |
| return STOP; |
| |
| std::string vs2("precision highp float;\n" |
| "uniform Data { vec4 v; };\n" |
| "void main() {\n" |
| " gl_Position = v;\n" |
| "}"); |
| std::string fs2("precision highp float;\n" |
| "out vec4 color;\n" |
| "uniform Data { vec4 v; };\n" |
| "void main() {\n" |
| " color = v;\n" |
| "}"); |
| |
| // check if linking succeeds when both matched blocks are lacking an instance name |
| if (!Test(vs2, fs2, GL_TRUE)) |
| return STOP; |
| |
| std::string vs3("precision highp float;\n" |
| "layout (std140) uniform Data { vec4 v; } a;\n" |
| "void main() {\n" |
| " gl_Position = a.v;\n" |
| "}"); |
| std::string fs3("precision highp float;\n" |
| "out vec4 color;\n" |
| "layout (std140) uniform Data { vec4 v; } b;\n" |
| "void main() {\n" |
| " color = b.v;\n" |
| "}"); |
| |
| // check if linking succeeds when both blocks have a different instance name |
| if (!Test(vs3, fs3, GL_TRUE)) |
| return STOP; |
| |
| std::string vs4("precision highp float;\n" |
| "layout (std140) uniform Data { float f; };\n" |
| "void main() {\n" |
| " gl_Position = vec4(f);\n" |
| "}\n"); |
| std::string fs4("precision highp float;\n" |
| "uniform float f;\n" |
| "out vec4 color;\n" |
| "void main() {\n" |
| " color = vec4(f);\n" |
| "}\n"); |
| |
| // check if link error is generated when the same name is used for block |
| // with no intance name and non-block uniform |
| if (!Test(vs4, fs4, GL_FALSE)) |
| return STOP; |
| |
| std::string vs5("precision highp float;\n" |
| "layout (std140) uniform Data { float f; } a;\n" |
| "void main() {\n" |
| " gl_Position = vec4(a.f);\n" |
| "}\n"); |
| std::string fs5("precision highp float;\n" |
| "uniform float f;\n" |
| "out vec4 color;\n" |
| "void main() {\n" |
| " color = vec4(f);\n" |
| "}\n"); |
| |
| // check if link succeeds when the same name is used for block with |
| // instance name and non-block uniform |
| if (!Test(vs5, fs5, GL_TRUE)) |
| return STOP; |
| |
| |
| std::string vs6("precision highp float;\n" |
| "uniform Data1 { float u; vec4 v; };\n" |
| "void main() {\n" |
| " gl_Position = v;\n" |
| "}"); |
| std::string fs6("precision highp float;\n" |
| "out vec4 color;\n" |
| "uniform Data2 { vec4 v; };\n" |
| "void main() {\n" |
| " color = v;\n" |
| "}"); |
| |
| // check if link error is generated when same name is used in two different blocks |
| if (!Test(vs6, fs6, GL_FALSE)) |
| return STOP; |
| |
| m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); |
| return STOP; |
| } |
| |
| bool Test(const std::string& vs, const std::string& fs, glw::GLint expectedLinkStatus) |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| const glw::GLuint p = gl.createProgram(); |
| const std::string version = glu::getGLSLVersionDeclaration(m_glslVersion); |
| |
| const struct |
| { |
| const char* name; |
| const std::string& body; |
| glw::GLenum type; |
| } shaderDefinition[] = { { "VS", vs, GL_VERTEX_SHADER }, { "FS", fs, GL_FRAGMENT_SHADER } }; |
| |
| for (unsigned int index = 0; index < 2; ++index) |
| { |
| std::string shaderSource = version + "\n" + shaderDefinition[index].body; |
| const char* shaderSourcePtr = shaderSource.c_str(); |
| |
| glw::GLuint sh = gl.createShader(shaderDefinition[index].type); |
| gl.attachShader(p, sh); |
| gl.deleteShader(sh); |
| gl.shaderSource(sh, 1, &shaderSourcePtr, NULL); |
| gl.compileShader(sh); |
| |
| glw::GLint status; |
| gl.getShaderiv(sh, GL_COMPILE_STATUS, &status); |
| if (status == GL_FALSE) |
| { |
| glw::GLint length; |
| gl.getShaderiv(sh, GL_INFO_LOG_LENGTH, &length); |
| if (length > 0) |
| { |
| std::vector<glw::GLchar> log(length); |
| gl.getShaderInfoLog(sh, length, NULL, &log[0]); |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << shaderDefinition[index].name |
| << " compilation should succed. Info Log:\n" |
| << &log[0] << tcu::TestLog::EndMessage; |
| } |
| gl.deleteProgram(p); |
| return false; |
| } |
| } |
| |
| gl.linkProgram(p); |
| |
| bool result = true; |
| glw::GLint status; |
| gl.getProgramiv(p, GL_LINK_STATUS, &status); |
| if (status != expectedLinkStatus) |
| { |
| if (status == GL_TRUE) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "Link operation should fail.\n" |
| << tcu::TestLog::EndMessage; |
| } |
| else |
| { |
| glw::GLchar log[1024]; |
| gl.getProgramInfoLog(p, sizeof(log), NULL, log); |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Link operation should succed. Info Log:\n" |
| << log << tcu::TestLog::EndMessage; |
| } |
| result = false; |
| } |
| |
| gl.deleteProgram(p); |
| return result; |
| } |
| |
| private: |
| glu::GLSLVersion m_glslVersion; |
| }; |
| |
| UniformBlockTests::UniformBlockTests(Context& context, glu::GLSLVersion glslVersion) |
| : TestCaseGroup(context, "uniform_block", "Uniform Block tests"), m_glslVersion(glslVersion) |
| { |
| } |
| |
| UniformBlockTests::~UniformBlockTests(void) |
| { |
| } |
| |
| void UniformBlockTests::init(void) |
| { |
| static const glu::DataType basicTypes[] = { glu::TYPE_FLOAT, glu::TYPE_FLOAT_VEC2, glu::TYPE_FLOAT_VEC3, |
| glu::TYPE_FLOAT_VEC4, glu::TYPE_INT, glu::TYPE_INT_VEC2, |
| glu::TYPE_INT_VEC3, glu::TYPE_INT_VEC4, glu::TYPE_UINT, |
| glu::TYPE_UINT_VEC2, glu::TYPE_UINT_VEC3, glu::TYPE_UINT_VEC4, |
| glu::TYPE_BOOL, glu::TYPE_BOOL_VEC2, glu::TYPE_BOOL_VEC3, |
| glu::TYPE_BOOL_VEC4, glu::TYPE_FLOAT_MAT2, glu::TYPE_FLOAT_MAT3, |
| glu::TYPE_FLOAT_MAT4, glu::TYPE_FLOAT_MAT2X3, glu::TYPE_FLOAT_MAT2X4, |
| glu::TYPE_FLOAT_MAT3X2, glu::TYPE_FLOAT_MAT3X4, glu::TYPE_FLOAT_MAT4X2, |
| glu::TYPE_FLOAT_MAT4X3 }; |
| |
| static const struct |
| { |
| const char* name; |
| deUint32 flags; |
| } precisionFlags[] = { { "lowp", PRECISION_LOW }, { "mediump", PRECISION_MEDIUM }, { "highp", PRECISION_HIGH } }; |
| |
| static const struct |
| { |
| const char* name; |
| deUint32 flags; |
| } layoutFlags[] = { { "shared", LAYOUT_SHARED }, { "packed", LAYOUT_PACKED }, { "std140", LAYOUT_STD140 } }; |
| |
| static const struct |
| { |
| const char* name; |
| deUint32 flags; |
| } matrixFlags[] = { { "row_major", LAYOUT_ROW_MAJOR }, { "column_major", LAYOUT_COLUMN_MAJOR } }; |
| |
| static const struct |
| { |
| const char* name; |
| UniformBlockCase::BufferMode mode; |
| } bufferModes[] = { { "per_block_buffer", UniformBlockCase::BUFFERMODE_PER_BLOCK }, |
| { "single_buffer", UniformBlockCase::BUFFERMODE_SINGLE } }; |
| |
| // ubo.single_basic_type |
| { |
| tcu::TestCaseGroup* singleBasicTypeGroup = |
| new tcu::TestCaseGroup(m_testCtx, "single_basic_type", "Single basic variable in single buffer"); |
| addChild(singleBasicTypeGroup); |
| |
| for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++) |
| { |
| tcu::TestCaseGroup* layoutGroup = new tcu::TestCaseGroup(m_testCtx, layoutFlags[layoutFlagNdx].name, ""); |
| singleBasicTypeGroup->addChild(layoutGroup); |
| |
| for (int basicTypeNdx = 0; basicTypeNdx < DE_LENGTH_OF_ARRAY(basicTypes); basicTypeNdx++) |
| { |
| glu::DataType type = basicTypes[basicTypeNdx]; |
| const char* typeName = glu::getDataTypeName(type); |
| deUint32 baseFlags = layoutFlags[layoutFlagNdx].flags; |
| deUint32 flags = baseFlags | ((baseFlags & LAYOUT_PACKED) ? |
| (basicTypeNdx % 2 == 0 ? DECLARE_VERTEX : DECLARE_FRAGMENT) : |
| DECLARE_BOTH); |
| |
| if (glu::isDataTypeBoolOrBVec(type)) |
| layoutGroup->addChild(new BlockBasicTypeCase(m_context, typeName, "", m_glslVersion, |
| VarType(type, 0), flags, 0 /* no instance array */)); |
| else |
| { |
| for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisionFlags); precNdx++) |
| layoutGroup->addChild(new BlockBasicTypeCase( |
| m_context, (string(precisionFlags[precNdx].name) + "_" + typeName).c_str(), "", |
| m_glslVersion, VarType(type, precisionFlags[precNdx].flags), flags, |
| 0 /* no instance array */)); |
| } |
| |
| if (glu::isDataTypeMatrix(type)) |
| { |
| for (int matFlagNdx = 0; matFlagNdx < DE_LENGTH_OF_ARRAY(matrixFlags); matFlagNdx++) |
| { |
| for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisionFlags); precNdx++) |
| layoutGroup->addChild(new BlockBasicTypeCase( |
| m_context, |
| (string(matrixFlags[matFlagNdx].name) + "_" + precisionFlags[precNdx].name + "_" + |
| typeName) |
| .c_str(), |
| "", m_glslVersion, VarType(type, precisionFlags[precNdx].flags), |
| flags | matrixFlags[matFlagNdx].flags, 0 /* no instance array */)); |
| } |
| } |
| } |
| } |
| } |
| |
| // ubo.single_basic_array |
| { |
| tcu::TestCaseGroup* singleBasicArrayGroup = |
| new tcu::TestCaseGroup(m_testCtx, "single_basic_array", "Single basic array variable in single buffer"); |
| addChild(singleBasicArrayGroup); |
| |
| for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++) |
| { |
| tcu::TestCaseGroup* layoutGroup = new tcu::TestCaseGroup(m_testCtx, layoutFlags[layoutFlagNdx].name, ""); |
| singleBasicArrayGroup->addChild(layoutGroup); |
| |
| for (int basicTypeNdx = 0; basicTypeNdx < DE_LENGTH_OF_ARRAY(basicTypes); basicTypeNdx++) |
| { |
| glu::DataType type = basicTypes[basicTypeNdx]; |
| const char* typeName = glu::getDataTypeName(type); |
| const int arraySize = 3; |
| deUint32 baseFlags = layoutFlags[layoutFlagNdx].flags; |
| deUint32 flags = baseFlags | ((baseFlags & LAYOUT_PACKED) ? |
| (basicTypeNdx % 2 == 0 ? DECLARE_VERTEX : DECLARE_FRAGMENT) : |
| DECLARE_BOTH); |
| |
| layoutGroup->addChild(new BlockBasicTypeCase( |
| m_context, typeName, "", m_glslVersion, |
| VarType(VarType(type, glu::isDataTypeBoolOrBVec(type) ? 0 : PRECISION_HIGH), arraySize), flags, |
| 0 /* no instance array */)); |
| |
| if (glu::isDataTypeMatrix(type)) |
| { |
| for (int matFlagNdx = 0; matFlagNdx < DE_LENGTH_OF_ARRAY(matrixFlags); matFlagNdx++) |
| layoutGroup->addChild(new BlockBasicTypeCase( |
| m_context, (string(matrixFlags[matFlagNdx].name) + "_" + typeName).c_str(), "", |
| m_glslVersion, VarType(VarType(type, PRECISION_HIGH), arraySize), |
| flags | matrixFlags[matFlagNdx].flags, 0 /* no instance array */)); |
| } |
| } |
| } |
| } |
| |
| // ubo.single_struct |
| { |
| tcu::TestCaseGroup* singleStructGroup = |
| new tcu::TestCaseGroup(m_testCtx, "single_struct", "Single struct in uniform block"); |
| addChild(singleStructGroup); |
| |
| for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++) |
| { |
| for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++) |
| { |
| for (int isArray = 0; isArray < 2; isArray++) |
| { |
| std::string name = std::string(bufferModes[modeNdx].name) + "_" + layoutFlags[layoutFlagNdx].name; |
| deUint32 baseFlags = layoutFlags[layoutFlagNdx].flags; |
| deUint32 flags = baseFlags | ((baseFlags & LAYOUT_PACKED) ? DECLARE_VERTEX : DECLARE_BOTH); |
| |
| if (bufferModes[modeNdx].mode == UniformBlockCase::BUFFERMODE_SINGLE && isArray == 0) |
| continue; // Doesn't make sense to add this variant. |
| |
| if (isArray) |
| name += "_instance_array"; |
| |
| singleStructGroup->addChild(new BlockSingleStructCase( |
| m_context, name.c_str(), "", m_glslVersion, flags, bufferModes[modeNdx].mode, isArray ? 3 : 0)); |
| } |
| } |
| } |
| } |
| |
| // ubo.single_struct_array |
| { |
| tcu::TestCaseGroup* singleStructArrayGroup = |
| new tcu::TestCaseGroup(m_testCtx, "single_struct_array", "Struct array in one uniform block"); |
| addChild(singleStructArrayGroup); |
| |
| for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++) |
| { |
| for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++) |
| { |
| for (int isArray = 0; isArray < 2; isArray++) |
| { |
| std::string name = std::string(bufferModes[modeNdx].name) + "_" + layoutFlags[layoutFlagNdx].name; |
| deUint32 baseFlags = layoutFlags[layoutFlagNdx].flags; |
| deUint32 flags = baseFlags | ((baseFlags & LAYOUT_PACKED) ? DECLARE_FRAGMENT : DECLARE_BOTH); |
| |
| if (bufferModes[modeNdx].mode == UniformBlockCase::BUFFERMODE_SINGLE && isArray == 0) |
| continue; // Doesn't make sense to add this variant. |
| |
| if (isArray) |
| name += "_instance_array"; |
| |
| singleStructArrayGroup->addChild(new BlockSingleStructArrayCase( |
| m_context, name.c_str(), "", m_glslVersion, flags, bufferModes[modeNdx].mode, isArray ? 3 : 0)); |
| } |
| } |
| } |
| } |
| |
| // ubo.single_nested_struct |
| { |
| tcu::TestCaseGroup* singleNestedStructGroup = |
| new tcu::TestCaseGroup(m_testCtx, "single_nested_struct", "Nested struct in one uniform block"); |
| addChild(singleNestedStructGroup); |
| |
| for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++) |
| { |
| for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++) |
| { |
| for (int isArray = 0; isArray < 2; isArray++) |
| { |
| std::string name = std::string(bufferModes[modeNdx].name) + "_" + layoutFlags[layoutFlagNdx].name; |
| deUint32 baseFlags = layoutFlags[layoutFlagNdx].flags; |
| deUint32 flags = baseFlags | ((baseFlags & LAYOUT_PACKED) ? DECLARE_VERTEX : DECLARE_BOTH); |
| |
| if (bufferModes[modeNdx].mode == UniformBlockCase::BUFFERMODE_SINGLE && isArray == 0) |
| continue; // Doesn't make sense to add this variant. |
| |
| if (isArray) |
| name += "_instance_array"; |
| |
| singleNestedStructGroup->addChild(new BlockSingleNestedStructCase( |
| m_context, name.c_str(), "", m_glslVersion, flags, bufferModes[modeNdx].mode, isArray ? 3 : 0)); |
| } |
| } |
| } |
| } |
| |
| // ubo.single_nested_struct_array |
| { |
| tcu::TestCaseGroup* singleNestedStructArrayGroup = |
| new tcu::TestCaseGroup(m_testCtx, "single_nested_struct_array", "Nested struct array in one uniform block"); |
| addChild(singleNestedStructArrayGroup); |
| |
| for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++) |
| { |
| for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++) |
| { |
| for (int isArray = 0; isArray < 2; isArray++) |
| { |
| std::string name = std::string(bufferModes[modeNdx].name) + "_" + layoutFlags[layoutFlagNdx].name; |
| deUint32 baseFlags = layoutFlags[layoutFlagNdx].flags; |
| deUint32 flags = baseFlags | ((baseFlags & LAYOUT_PACKED) ? DECLARE_FRAGMENT : DECLARE_BOTH); |
| |
| if (bufferModes[modeNdx].mode == UniformBlockCase::BUFFERMODE_SINGLE && isArray == 0) |
| continue; // Doesn't make sense to add this variant. |
| |
| if (isArray) |
| name += "_instance_array"; |
| |
| singleNestedStructArrayGroup->addChild(new BlockSingleNestedStructArrayCase( |
| m_context, name.c_str(), "", m_glslVersion, flags, bufferModes[modeNdx].mode, isArray ? 3 : 0)); |
| } |
| } |
| } |
| } |
| |
| // ubo.instance_array_basic_type |
| { |
| tcu::TestCaseGroup* instanceArrayBasicTypeGroup = |
| new tcu::TestCaseGroup(m_testCtx, "instance_array_basic_type", "Single basic variable in instance array"); |
| addChild(instanceArrayBasicTypeGroup); |
| |
| for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++) |
| { |
| tcu::TestCaseGroup* layoutGroup = new tcu::TestCaseGroup(m_testCtx, layoutFlags[layoutFlagNdx].name, ""); |
| instanceArrayBasicTypeGroup->addChild(layoutGroup); |
| |
| for (int basicTypeNdx = 0; basicTypeNdx < DE_LENGTH_OF_ARRAY(basicTypes); basicTypeNdx++) |
| { |
| glu::DataType type = basicTypes[basicTypeNdx]; |
| const char* typeName = glu::getDataTypeName(type); |
| const int numInstances = 3; |
| deUint32 baseFlags = layoutFlags[layoutFlagNdx].flags; |
| deUint32 flags = baseFlags | ((baseFlags & LAYOUT_PACKED) ? |
| (basicTypeNdx % 2 == 0 ? DECLARE_VERTEX : DECLARE_FRAGMENT) : |
| DECLARE_BOTH); |
| |
| layoutGroup->addChild(new BlockBasicTypeCase( |
| m_context, typeName, "", m_glslVersion, |
| VarType(type, glu::isDataTypeBoolOrBVec(type) ? 0 : PRECISION_HIGH), flags, numInstances)); |
| |
| if (glu::isDataTypeMatrix(type)) |
| { |
| for (int matFlagNdx = 0; matFlagNdx < DE_LENGTH_OF_ARRAY(matrixFlags); matFlagNdx++) |
| layoutGroup->addChild(new BlockBasicTypeCase( |
| m_context, (string(matrixFlags[matFlagNdx].name) + "_" + typeName).c_str(), "", |
| m_glslVersion, VarType(type, PRECISION_HIGH), flags | matrixFlags[matFlagNdx].flags, |
| numInstances)); |
| } |
| } |
| } |
| } |
| |
| // ubo.multi_basic_types |
| { |
| tcu::TestCaseGroup* multiBasicTypesGroup = |
| new tcu::TestCaseGroup(m_testCtx, "multi_basic_types", "Multiple buffers with basic types"); |
| addChild(multiBasicTypesGroup); |
| |
| for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++) |
| { |
| tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, ""); |
| multiBasicTypesGroup->addChild(modeGroup); |
| |
| for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++) |
| { |
| for (int isArray = 0; isArray < 2; isArray++) |
| { |
| std::string baseName = layoutFlags[layoutFlagNdx].name; |
| deUint32 baseFlags = layoutFlags[layoutFlagNdx].flags; |
| |
| if (isArray) |
| baseName += "_instance_array"; |
| |
| modeGroup->addChild(new BlockMultiBasicTypesCase( |
| m_context, (baseName + "_mixed").c_str(), "", m_glslVersion, baseFlags | DECLARE_VERTEX, |
| baseFlags | DECLARE_FRAGMENT, bufferModes[modeNdx].mode, isArray ? 3 : 0)); |
| |
| if (!(baseFlags & LAYOUT_PACKED)) |
| modeGroup->addChild(new BlockMultiBasicTypesCase( |
| m_context, (baseName + "_both").c_str(), "", m_glslVersion, |
| baseFlags | DECLARE_VERTEX | DECLARE_FRAGMENT, |
| baseFlags | DECLARE_VERTEX | DECLARE_FRAGMENT, bufferModes[modeNdx].mode, isArray ? 3 : 0)); |
| } |
| } |
| } |
| } |
| |
| // ubo.multi_nested_struct |
| { |
| tcu::TestCaseGroup* multiNestedStructGroup = |
| new tcu::TestCaseGroup(m_testCtx, "multi_nested_struct", "Multiple buffers with nested structs"); |
| addChild(multiNestedStructGroup); |
| |
| for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++) |
| { |
| tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, ""); |
| multiNestedStructGroup->addChild(modeGroup); |
| |
| for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++) |
| { |
| for (int isArray = 0; isArray < 2; isArray++) |
| { |
| std::string baseName = layoutFlags[layoutFlagNdx].name; |
| deUint32 baseFlags = layoutFlags[layoutFlagNdx].flags; |
| |
| if (isArray) |
| baseName += "_instance_array"; |
| |
| modeGroup->addChild(new BlockMultiNestedStructCase( |
| m_context, (baseName + "_mixed").c_str(), "", m_glslVersion, baseFlags | DECLARE_VERTEX, |
| baseFlags | DECLARE_FRAGMENT, bufferModes[modeNdx].mode, isArray ? 3 : 0)); |
| |
| if (!(baseFlags & LAYOUT_PACKED)) |
| modeGroup->addChild(new BlockMultiNestedStructCase( |
| m_context, (baseName + "_both").c_str(), "", m_glslVersion, |
| baseFlags | DECLARE_VERTEX | DECLARE_FRAGMENT, |
| baseFlags | DECLARE_VERTEX | DECLARE_FRAGMENT, bufferModes[modeNdx].mode, isArray ? 3 : 0)); |
| } |
| } |
| } |
| } |
| |
| // ubo.random |
| { |
| const deUint32 allShaders = FEATURE_VERTEX_BLOCKS | FEATURE_FRAGMENT_BLOCKS | FEATURE_SHARED_BLOCKS; |
| const deUint32 allLayouts = FEATURE_PACKED_LAYOUT | FEATURE_SHARED_LAYOUT | FEATURE_STD140_LAYOUT; |
| const deUint32 allBasicTypes = FEATURE_VECTORS | FEATURE_MATRICES; |
| const deUint32 unused = FEATURE_UNUSED_MEMBERS | FEATURE_UNUSED_UNIFORMS; |
| const deUint32 matFlags = FEATURE_MATRIX_LAYOUT; |
| |
| tcu::TestCaseGroup* randomGroup = new tcu::TestCaseGroup(m_testCtx, "random", "Random Uniform Block cases"); |
| addChild(randomGroup); |
| |
| // Basic types. |
| createRandomCaseGroup(randomGroup, m_context, "scalar_types", "Scalar types only, per-block buffers", |
| m_glslVersion, UniformBlockCase::BUFFERMODE_PER_BLOCK, allShaders | allLayouts | unused, |
| 10, 0); |
| createRandomCaseGroup(randomGroup, m_context, "vector_types", "Scalar and vector types only, per-block buffers", |
| m_glslVersion, UniformBlockCase::BUFFERMODE_PER_BLOCK, |
| allShaders | allLayouts | unused | FEATURE_VECTORS, 10, 25); |
| createRandomCaseGroup(randomGroup, m_context, "basic_types", "All basic types, per-block buffers", |
| m_glslVersion, UniformBlockCase::BUFFERMODE_PER_BLOCK, |
| allShaders | allLayouts | unused | allBasicTypes | matFlags, 10, 50); |
| createRandomCaseGroup(randomGroup, m_context, "basic_arrays", "Arrays, per-block buffers", m_glslVersion, |
| UniformBlockCase::BUFFERMODE_PER_BLOCK, |
| allShaders | allLayouts | unused | allBasicTypes | matFlags | FEATURE_ARRAYS, 10, 50); |
| |
| createRandomCaseGroup( |
| randomGroup, m_context, "basic_instance_arrays", "Basic instance arrays, per-block buffers", m_glslVersion, |
| UniformBlockCase::BUFFERMODE_PER_BLOCK, |
| allShaders | allLayouts | unused | allBasicTypes | matFlags | FEATURE_INSTANCE_ARRAYS, 10, 75); |
| createRandomCaseGroup(randomGroup, m_context, "nested_structs", "Nested structs, per-block buffers", |
| m_glslVersion, UniformBlockCase::BUFFERMODE_PER_BLOCK, |
| allShaders | allLayouts | unused | allBasicTypes | matFlags | FEATURE_STRUCTS, 10, 100); |
| createRandomCaseGroup( |
| randomGroup, m_context, "nested_structs_arrays", "Nested structs, arrays, per-block buffers", m_glslVersion, |
| UniformBlockCase::BUFFERMODE_PER_BLOCK, |
| allShaders | allLayouts | unused | allBasicTypes | matFlags | FEATURE_STRUCTS | FEATURE_ARRAYS, 10, 150); |
| createRandomCaseGroup( |
| randomGroup, m_context, "nested_structs_instance_arrays", |
| "Nested structs, instance arrays, per-block buffers", m_glslVersion, UniformBlockCase::BUFFERMODE_PER_BLOCK, |
| allShaders | allLayouts | unused | allBasicTypes | matFlags | FEATURE_STRUCTS | FEATURE_INSTANCE_ARRAYS, 10, |
| 125); |
| createRandomCaseGroup(randomGroup, m_context, "nested_structs_arrays_instance_arrays", |
| "Nested structs, instance arrays, per-block buffers", m_glslVersion, |
| UniformBlockCase::BUFFERMODE_PER_BLOCK, |
| allShaders | allLayouts | unused | allBasicTypes | matFlags | FEATURE_STRUCTS | |
| FEATURE_ARRAYS | FEATURE_INSTANCE_ARRAYS, |
| 10, 175); |
| |
| createRandomCaseGroup(randomGroup, m_context, "all_per_block_buffers", "All random features, per-block buffers", |
| m_glslVersion, UniformBlockCase::BUFFERMODE_PER_BLOCK, ~0u, 20, 200); |
| createRandomCaseGroup(randomGroup, m_context, "all_shared_buffer", "All random features, shared buffer", |
| m_glslVersion, UniformBlockCase::BUFFERMODE_SINGLE, ~0u, 20, 250); |
| } |
| |
| // ubo.common |
| if (glu::isGLSLVersionSupported(m_context.getRenderContext().getType(), glu::GLSL_VERSION_300_ES)) |
| { |
| tcu::TestCaseGroup* commonGroup = new tcu::TestCaseGroup(m_testCtx, "common", "Common Uniform Block cases"); |
| addChild(commonGroup); |
| commonGroup->addChild(new UniformBlockPrecisionMatching(m_context, m_glslVersion)); |
| commonGroup->addChild(new UniformBlockNameMatching(m_context, m_glslVersion)); |
| } |
| else if (glu::isGLSLVersionSupported(m_context.getRenderContext().getType(), glu::GLSL_VERSION_150)) |
| { |
| tcu::TestCaseGroup* commonGroup = new tcu::TestCaseGroup(m_testCtx, "common", "Common Uniform Block cases"); |
| addChild(commonGroup); |
| commonGroup->addChild(new UniformBlockNameMatching(m_context, m_glslVersion)); |
| } |
| } |
| |
| } // deqp |