| // Copyright (c) 2025 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. |
| |
| #include <gtest/gtest.h> |
| |
| #include "TestFixture.h" |
| |
| #include "glslang/MachineIndependent/LiveTraverser.h" |
| |
| namespace glslangtest { |
| namespace { |
| |
| struct LiveTraverserTestParams { |
| std::string fileName; |
| std::vector<std::string> liveVars; |
| }; |
| |
| using LiveTraverserTest = GlslangTest<::testing::TestWithParam<LiveTraverserTestParams>>; |
| |
| TEST_P(LiveTraverserTest, FromFile) |
| { |
| const auto& fileName = GetParam().fileName; |
| const auto& expectedLiveVars = GetParam().liveVars; |
| const EShMessages controls = DeriveOptions(Source::GLSL, Semantics::Vulkan, Target::AST); |
| GlslangResult result; |
| result.validationResult = true; |
| |
| std::string contents; |
| tryLoadFile(GlobalTestSettings.testRoot + "/" + fileName, "input", &contents); |
| std::unique_ptr<glslang::TShader> shader = std::make_unique<glslang::TShader>(GetShaderStage(GetSuffix(fileName))); |
| |
| bool success = compile(shader.get(), contents, "", controls); |
| result.shaderResults.push_back({fileName, shader->getInfoLog(), shader->getInfoDebugLog()}); |
| |
| std::ostringstream stream; |
| outputResultToStream(&stream, result, controls); |
| |
| class TLiveSymbolTraverser : public glslang::TLiveTraverser { |
| public: |
| TLiveSymbolTraverser(const glslang::TIntermediate& i, std::vector<std::string>& liveVars) |
| : glslang::TLiveTraverser(i), liveVars(liveVars) |
| { |
| } |
| |
| virtual void visitSymbol(glslang::TIntermSymbol* symbol) |
| { |
| if (symbol->getAsSymbolNode()->getAccessName().compare(0, 3, "gl_") == 0) |
| return; |
| |
| if (symbol->getQualifier().storage == glslang::TStorageQualifier::EvqVaryingIn || |
| symbol->getQualifier().storage == glslang::TStorageQualifier::EvqVaryingOut || |
| symbol->getQualifier().storage == glslang::TStorageQualifier::EvqUniform || |
| symbol->getQualifier().storage == glslang::TStorageQualifier::EvqBuffer) { |
| liveVars.push_back(symbol->getAccessName().c_str()); |
| } |
| } |
| |
| private: |
| std::vector<std::string>& liveVars; |
| }; |
| |
| if (success) { |
| std::vector<std::string> actualLiveVars; |
| TLiveSymbolTraverser liveTraverser(*shader->getIntermediate(), actualLiveVars); |
| liveTraverser.pushFunction(shader->getIntermediate()->getEntryPointMangledName().c_str()); |
| while (!liveTraverser.destinations.empty()) { |
| TIntermNode* destination = liveTraverser.destinations.back(); |
| liveTraverser.destinations.pop_back(); |
| destination->traverse(&liveTraverser); |
| } |
| |
| for (const auto& expectedVar : expectedLiveVars) { |
| auto it = std::find(actualLiveVars.begin(), actualLiveVars.end(), expectedVar); |
| EXPECT_NE(it, actualLiveVars.end()); |
| if (it != actualLiveVars.end()) |
| actualLiveVars.erase(it); |
| } |
| EXPECT_TRUE(actualLiveVars.empty()); |
| } |
| |
| // Check with expected results. |
| const std::string expectedOutputFname = GlobalTestSettings.testRoot + "/baseResults/" + fileName + ".out"; |
| std::string expectedOutput; |
| tryLoadFile(expectedOutputFname, "expected output", &expectedOutput); |
| |
| checkEqAndUpdateIfRequested(expectedOutput, stream.str(), expectedOutputFname, result.spirvWarningsErrors); |
| } |
| |
| // clang-format off |
| INSTANTIATE_TEST_SUITE_P( |
| Glsl, LiveTraverserTest, |
| ::testing::ValuesIn(std::vector<LiveTraverserTestParams>({ |
| {"liveTraverser.switch.vert", {"a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9", "a10"}}, |
| // TODO: implement test for if statements |
| })) |
| ); |
| // clang-format on |
| |
| } // anonymous namespace |
| } // namespace glslangtest |