From 7f0e65f8c79566140150a12582c63697663073bb Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Wed, 13 Aug 2025 15:18:34 +0800 Subject: [PATCH] [Feat] (MG_Util/ShaderCompiler, MG_State/Program): reflect uniform location --- .../GLState/ProgramState/ProgramObject.cpp | 1 + .../GLState/ProgramState/ShaderObject.cpp | 36 +++++++++++++ .../GLState/ProgramState/ShaderObject.h | 4 +- MobileGL/MG_Test/Buffer/CMakeLists.txt | 1 + MobileGL/MG_Test/Program/CMakeLists.txt | 3 ++ MobileGL/MG_Test/Program/ProgramUtilTest.cpp | 50 +++++++++++++++++++ MobileGL/MG_Test/VertexArray/CMakeLists.txt | 1 + .../glslang/UniformTraverser.cpp | 39 +++++++++++++++ .../glslang/UniformTraverser.h | 24 +++++++++ 9 files changed, 158 insertions(+), 1 deletion(-) create mode 100644 MobileGL/MG_Util/ShaderTranspiler/glslang/UniformTraverser.cpp create mode 100644 MobileGL/MG_Util/ShaderTranspiler/glslang/UniformTraverser.h diff --git a/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp b/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp index db9bc49a..11d66352 100644 --- a/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp +++ b/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp @@ -63,6 +63,7 @@ namespace MobileGL { Vector>& ProgramObject::GetAttachedShaders() { return m_shaders; } + } // namespace GLState } // namespace MG_State } // namespace MobileGL \ No newline at end of file diff --git a/MobileGL/MG_State/GLState/ProgramState/ShaderObject.cpp b/MobileGL/MG_State/GLState/ProgramState/ShaderObject.cpp index f017bd1f..d90f40e9 100644 --- a/MobileGL/MG_State/GLState/ProgramState/ShaderObject.cpp +++ b/MobileGL/MG_State/GLState/ProgramState/ShaderObject.cpp @@ -1,6 +1,8 @@ #include "ShaderObject.h" #include +#include "MG_Util/ShaderTranspiler/glslang/UniformTraverser.h" + namespace MobileGL { namespace MG_State { namespace GLState { @@ -13,6 +15,10 @@ namespace MobileGL { } void ShaderObject::Compile() { + if (!DoReflection()) { + return; + } + using namespace MG_Util::ShaderTranspiler; ShaderAttrib attrib{ .shaderType = GetGLShaderTypeByMGLShaderStage(m_stage), @@ -36,6 +42,36 @@ namespace MobileGL { void ShaderObject::MarkAsDeleted() { m_deleteStatus = true; } + + bool ShaderObject::DoReflection() { + using namespace MG_Util::ShaderTranspiler; + ShaderAttrib attrib{ + .shaderType = GetGLShaderTypeByMGLShaderStage(m_stage), + .sourceStr = m_source, + .flags = ShaderCompileBits::CompileForOpenGL + }; + + auto result = ShaderCompiler::CompileShader(attrib); + if (!result) { + m_compileStatus = false; + m_infoLog = result.error().log; + + const std::string e = std::format("Shader compilation failed: \nerrc: {}\nmsg: {}\n", + result.error().errc, result.error().log); + return false; + } + + auto pShader = result.value(); + auto root = pShader->getIntermediate()->getTreeRoot(); + UniformTraverser traverser; + root->traverse(&traverser); + auto& symbols = traverser.GetCollectedSymbols(); + for (const auto& symbol : symbols) { + m_uniforms[symbol->getName().c_str()] = symbol->getQualifier().layoutLocation; + } + + return true; + } } // namespace GLState } // namespace MG_State } // namespace MobileGL \ No newline at end of file diff --git a/MobileGL/MG_State/GLState/ProgramState/ShaderObject.h b/MobileGL/MG_State/GLState/ProgramState/ShaderObject.h index 0e2df307..60a0285d 100644 --- a/MobileGL/MG_State/GLState/ProgramState/ShaderObject.h +++ b/MobileGL/MG_State/GLState/ProgramState/ShaderObject.h @@ -68,12 +68,14 @@ namespace MobileGL { SharedPtr GetCompiledShader() const { return m_shader; } const String& GetInfoLog() const { return m_infoLog; } private: + bool DoReflection(); const Uint m_id = 0; const ShaderStage m_stage; String m_source; SharedPtr m_shader; - String m_infoLog; + UnorderedMap m_uniforms; + String m_infoLog; Bool m_deleteStatus = false; Bool m_compileStatus = false; }; diff --git a/MobileGL/MG_Test/Buffer/CMakeLists.txt b/MobileGL/MG_Test/Buffer/CMakeLists.txt index 80460495..2aa17712 100644 --- a/MobileGL/MG_Test/Buffer/CMakeLists.txt +++ b/MobileGL/MG_Test/Buffer/CMakeLists.txt @@ -36,6 +36,7 @@ add_executable( ${MGL_ROOT}/MobileGL/MG_Util/ShaderTranspiler/SpvcSession.cpp ${MGL_ROOT}/MobileGL/MG_Backend/Init.cpp ${MGL_ROOT}/MobileGL/MG_Util/Debug/Log.cpp + ${MGL_ROOT}/MobileGL/MG_Util/ShaderTranspiler/glslang/UniformTraverser.cpp ) target_include_directories(BufferTest PRIVATE diff --git a/MobileGL/MG_Test/Program/CMakeLists.txt b/MobileGL/MG_Test/Program/CMakeLists.txt index 95c616f4..38b3d47c 100644 --- a/MobileGL/MG_Test/Program/CMakeLists.txt +++ b/MobileGL/MG_Test/Program/CMakeLists.txt @@ -8,6 +8,7 @@ add_executable( ${MGL_ROOT}/MobileGL/MG_Util/Converters/GLToGlslang/GLShaderLangConverter.cpp ${MGL_ROOT}/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.cpp ${MGL_ROOT}/MobileGL/MG_Util/ShaderTranspiler/SpvcSession.cpp + ${MGL_ROOT}/MobileGL/MG_Util/ShaderTranspiler/glslang/UniformTraverser.cpp ) target_include_directories(ProgramUtilTest PRIVATE @@ -35,6 +36,8 @@ add_executable( ${MGL_ROOT}/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.cpp ${MGL_ROOT}/MobileGL/MG_Util/ShaderTranspiler/SpvcSession.cpp + ${MGL_ROOT}/MobileGL/MG_Util/ShaderTranspiler/glslang/UniformTraverser.cpp + ${MGL_ROOT}/MobileGL/MG_State/GLState/Core.cpp ${MGL_ROOT}/MobileGL/MG_State/GLState/BufferState/BufferState.cpp ${MGL_ROOT}/MobileGL/MG_State/GLState/BufferState/BufferObject.cpp diff --git a/MobileGL/MG_Test/Program/ProgramUtilTest.cpp b/MobileGL/MG_Test/Program/ProgramUtilTest.cpp index b6249bd1..2a278761 100644 --- a/MobileGL/MG_Test/Program/ProgramUtilTest.cpp +++ b/MobileGL/MG_Test/Program/ProgramUtilTest.cpp @@ -7,6 +7,8 @@ #include #include #include + +#include "MG_Util/ShaderTranspiler/glslang/UniformTraverser.h" using namespace MobileGL; class ProgramUtilTest : public ::testing::Test { @@ -165,6 +167,54 @@ TEST_F(ProgramUtilTest, CompileFragmentShaderWithDiscard) { } } +const char* vs_location = R"(#version 460 + +in vec4 Position; + +layout(location = 1) uniform mat4 ProjMat; +layout(location = 20) uniform vec2 InSize; +layout(location = 0) uniform vec2 OutSize; + +out vec2 texCoord; +out vec2 oneTexel; + +void main(){ + vec4 outPos = ProjMat * vec4(Position.xy, 0.0, 1.0); + gl_Position = vec4(outPos.xy, 0.2, 1.0); + + oneTexel = 1.0 / InSize; + + texCoord = Position.xy / OutSize; +})"; + +TEST_F(ProgramUtilTest, CompileVertexShaderWithLocation) { + using namespace MG_Util::ShaderTranspiler; + ShaderAttrib attrib { + .shaderType = GL_VERTEX_SHADER, + .sourceStr = vs_location, + .flags = ShaderCompileBits::CompileForOpenGL + }; + auto res = ShaderCompiler::CompileShader(attrib); + if (!res) { + ASSERT_NE(res.error().errc, 0); + FAIL() << "errc: " << res.error().errc << "\nlog: " << res.error().log; + } + UnorderedMap uniforms; + + auto pShader = res.value(); + auto root = pShader->getIntermediate()->getTreeRoot(); + UniformTraverser traverser; + root->traverse(&traverser); + auto& symbols = traverser.GetCollectedSymbols(); + for (const auto& symbol : symbols) { + uniforms[symbol->getName().c_str()] = symbol->getQualifier().layoutLocation; + } + + EXPECT_EQ(uniforms["ProjMat"], 1); + EXPECT_EQ(uniforms["InSize"], 20); + EXPECT_EQ(uniforms["OutSize"], 0); +} + TEST_F(ProgramUtilTest, CompileAndLinkProgram) { using namespace MG_Util::ShaderTranspiler; ShaderAttrib vs_attrib { diff --git a/MobileGL/MG_Test/VertexArray/CMakeLists.txt b/MobileGL/MG_Test/VertexArray/CMakeLists.txt index 3ab508c3..638c45fd 100644 --- a/MobileGL/MG_Test/VertexArray/CMakeLists.txt +++ b/MobileGL/MG_Test/VertexArray/CMakeLists.txt @@ -36,6 +36,7 @@ add_executable( ${MGL_ROOT}/MobileGL/MG_Util/ShaderTranspiler/SpvcSession.cpp ${MGL_ROOT}/MobileGL/MG_Backend/Init.cpp ${MGL_ROOT}/MobileGL/MG_Util/Debug/Log.cpp + ${MGL_ROOT}/MobileGL/MG_Util/ShaderTranspiler/glslang/UniformTraverser.cpp ) target_include_directories(VertexArrayTest PRIVATE diff --git a/MobileGL/MG_Util/ShaderTranspiler/glslang/UniformTraverser.cpp b/MobileGL/MG_Util/ShaderTranspiler/glslang/UniformTraverser.cpp new file mode 100644 index 00000000..d9804eab --- /dev/null +++ b/MobileGL/MG_Util/ShaderTranspiler/glslang/UniformTraverser.cpp @@ -0,0 +1,39 @@ +// +// Created by Swung 0x48 on 2025/7/20. +// + +#include "UniformTraverser.h" + +namespace MobileGL { +namespace MG_Util { +namespace ShaderTranspiler { + void UniformTraverser::visitSymbol(glslang::TIntermSymbol *symbol) { + auto parent = getParentNode(); + if (!parent) + return; + auto parentAgg = parent->getAsAggregate(); + if (!parentAgg || parentAgg->getOp() != glslang::EOpLinkerObjects) + return; + + const auto &type = symbol->getType(); + if (symbol->getQualifier().isUniform()) { + m_collectedSymbols.emplace_back(symbol); + // auto& name = symbol->getName(); + // auto qualifier = symbol->getQualifier(); + // + // printf("layout(location = %d) uniform %s\n", qualifier.layoutLocation, name.c_str()); + // auto &uniform = uniforms.emplace_back(); + // uniform.name = name; + // uniform.storageQualifier = qualifier.storage; + // uniform.layoutLocation = qualifier.layoutLocation; + // uniform.layoutBinding = qualifier.layoutBinding; + // uniform.layoutPacking = qualifier.layoutPacking; + } else if (type.getBasicType() == glslang::EbtSampler) { + // auto &uniform = samplers.emplace_back(); + // uniform.name = symbol->getName(); + // uniform.sampler = type.getSampler(); + } + } +} +} +} diff --git a/MobileGL/MG_Util/ShaderTranspiler/glslang/UniformTraverser.h b/MobileGL/MG_Util/ShaderTranspiler/glslang/UniformTraverser.h new file mode 100644 index 00000000..bcc5a84a --- /dev/null +++ b/MobileGL/MG_Util/ShaderTranspiler/glslang/UniformTraverser.h @@ -0,0 +1,24 @@ +// +// Created by Swung 0x48 on 2025/7/20. +// + +#ifndef MOBILEGL_UNIFORMTRAVERSER_H +#define MOBILEGL_UNIFORMTRAVERSER_H + +#include "Includes.h" + +namespace MobileGL { +namespace MG_Util { +namespace ShaderTranspiler { + class UniformTraverser : public glslang::TIntermTraverser { + public: + void visitSymbol(glslang::TIntermSymbol *symbol) override; + Vector& GetCollectedSymbols() { return m_collectedSymbols; } + private: + Vector m_collectedSymbols; + }; +} +} +} + +#endif //MOBILEGL_UNIFORMTRAVERSER_H