From 1ad2513700783c672cd13e0a3c10f3ee09489f69 Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Mon, 21 Jul 2025 14:37:32 +0800 Subject: [PATCH] [Fix] (MG_Util/Program): program linking --- MobileGL/MG_Test/Program/ProgramTest.cpp | 151 +++++------------- .../ShaderTranspiler/ShaderCompiler.cpp | 55 ++++++- .../MG_Util/ShaderTranspiler/ShaderCompiler.h | 3 +- MobileGL/MG_Util/ShaderTranspiler/Types.h | 16 +- 4 files changed, 94 insertions(+), 131 deletions(-) diff --git a/MobileGL/MG_Test/Program/ProgramTest.cpp b/MobileGL/MG_Test/Program/ProgramTest.cpp index 46d66843..d0be04c2 100644 --- a/MobileGL/MG_Test/Program/ProgramTest.cpp +++ b/MobileGL/MG_Test/Program/ProgramTest.cpp @@ -18,19 +18,19 @@ TEST_F(ProgramTest, Sanity) { const char* vs = R"(#version 150 in vec3 Position; -in vec2 UV; +in vec2 UV0; in vec4 Color; uniform mat4 ModelViewMat; uniform mat4 ProjMat; -out vec2 texCoord; +out vec2 texCoord0; out vec4 vertexColor; void main() { gl_Position = ProjMat * ModelViewMat * vec4(Position, 1.0); - texCoord = UV; + texCoord0 = UV0; vertexColor = Color; })"; @@ -49,19 +49,20 @@ TEST_F(ProgramTest, CompileSimpleVertexShader) { const char* fs = R"(#version 150 -uniform sampler2D DiffuseSampler; +uniform sampler2D Sampler0; uniform vec4 ColorModulator; -in vec2 texCoord; +in vec2 texCoord0; in vec4 vertexColor; out vec4 fragColor; void main() { - vec4 color = texture(DiffuseSampler, texCoord) * vertexColor; - - // blit final output of compositor into displayed back buffer + vec4 color = texture(Sampler0, texCoord0) * vertexColor; + if (color.a == 0.0) { + discard; + } fragColor = color * ColorModulator; })"; @@ -78,116 +79,36 @@ TEST_F(ProgramTest, CompileSimpleFragmentShader) { } } -const char* vs_uniform = R"(#version 150 - -in vec3 Position; -in vec2 UV; -in vec4 Color; - -uniform mat4 ModelViewMat; -uniform mat4 ProjMat; - -out vec2 texCoord; -out vec4 vertexColor; - -void main() { - mat4 mat = ProjMat * ModelViewMat; - gl_Position = ProjMat * ModelViewMat * vec4(Position, 1.0); - - texCoord = UV; - vertexColor = Color; -})"; - - - -TEST_F(ProgramTest, ExtractPlainUniform) { +TEST_F(ProgramTest, CompileAndLinkProgram) { using namespace MG_Util::ShaderTranspiler; - ShaderAttrib attrib { + ShaderAttrib vs_attrib { .shaderType = GL_VERTEX_SHADER, - .sourceStr = vs_uniform + .sourceStr = vs + }; + auto vs_res = ShaderCompiler::CompileShader(vs_attrib); + if (!vs_res) { + ASSERT_NE(vs_res.error().errc, 0); + FAIL() << "errc: " << vs_res.error().errc << "\nlog: " << vs_res.error().log; + } + + ShaderAttrib fs_attrib { + .shaderType = GL_FRAGMENT_SHADER, + .sourceStr = fs +}; + auto fs_res = ShaderCompiler::CompileShader(fs_attrib); + if (!fs_res) { + ASSERT_NE(fs_res.error().errc, 0); + FAIL() << "errc: " << fs_res.error().errc << "\nlog: " << fs_res.error().log; + } + + ProgramAttrib programAttrib { + .shaderTypes = { GL_VERTEX_SHADER, GL_FRAGMENT_SHADER }, + .shaders = { vs_res.value(), fs_res.value() } }; - Vector> uniforms; - Vector> samplers; - - auto res = ShaderCompiler::CompileShader(attrib); - if (res) { - UniformTraverser traverser(uniforms, samplers); - auto root = res->TShader->getIntermediate()->getTreeRoot(); - root->traverse(&traverser); - - ASSERT_EQ(uniforms.size(), 2); - ASSERT_EQ(samplers.size(), 0); - - auto ProjMat_uniform_it = std::find_if(uniforms.begin(), uniforms.end(), [] (TUniform& uniform) { - return uniform.name == "ProjMat"; - }); - ASSERT_TRUE(ProjMat_uniform_it != uniforms.end()); - ASSERT_EQ(ProjMat_uniform_it->storageQualifier, glslang::EvqUniform); - - auto ModelViewMat_uniform_it = std::find_if(uniforms.begin(), uniforms.end(), [] (TUniform& uniform) { - return uniform.name == "ModelViewMat"; - }); - ASSERT_TRUE(ModelViewMat_uniform_it != uniforms.end()); - ASSERT_EQ(ModelViewMat_uniform_it->storageQualifier, glslang::EvqUniform); - } else { - ASSERT_NE(res.error().errc, 0); - FAIL() << "errc: " << res.error().errc << "\nlog: " << res.error().log; + auto program_res = ShaderCompiler::LinkProgram(programAttrib); + if (!program_res) { + ASSERT_NE(program_res.error().errc, 0); + FAIL() << "errc: " << program_res.error().errc << "\nlog: " << program_res.error().log; } } - -const char* fs_uniform = R"(#version 150 - -uniform sampler2D DiffuseSampler; - -uniform vec4 ColorModulator; - -in vec2 texCoord; -in vec4 vertexColor; - -out vec4 fragColor; - -void main() { - vec4 color = texture(DiffuseSampler, texCoord) * vertexColor; - - // blit final output of compositor into displayed back buffer - fragColor = color * ColorModulator; -})"; - -TEST_F(ProgramTest, ExtractSampler) { - using namespace MG_Util::ShaderTranspiler; - ShaderAttrib attrib { - .shaderType = GL_FRAGMENT_SHADER, - .sourceStr = fs_uniform - }; - - Vector> uniforms; - Vector> samplers; - - auto res = ShaderCompiler::CompileShader(attrib); - if (res) { - UniformTraverser traverser(uniforms, samplers); - auto root = res->TShader->getIntermediate()->getTreeRoot(); - root->traverse(&traverser); - - ASSERT_EQ(uniforms.size(), 1); - ASSERT_EQ(samplers.size(), 1); - - auto ColorModulator_uniform_it = std::find_if(uniforms.begin(), uniforms.end(), [] (TUniform& uniform) { - return uniform.name == "ColorModulator"; - }); - ASSERT_TRUE(ColorModulator_uniform_it != uniforms.end()); - ASSERT_EQ(ColorModulator_uniform_it->storageQualifier, glslang::EvqUniform); - - auto DiffuseSampler_uniform_it = std::find_if(samplers.begin(), samplers.end(), [] (TUniform& uniform) { - return uniform.name == "DiffuseSampler"; - }); - ASSERT_TRUE(DiffuseSampler_uniform_it != samplers.end()); - auto& sampler = DiffuseSampler_uniform_it->sampler; - ASSERT_EQ(sampler.type, glslang::EbtFloat); - ASSERT_EQ(sampler.dim, glslang::Esd2D); - } else { - ASSERT_NE(res.error().errc, 0); - FAIL() << "errc: " << res.error().errc << "\nlog: " << res.error().log; - } -} \ No newline at end of file diff --git a/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.cpp b/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.cpp index f4797b6d..50222274 100644 --- a/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.cpp +++ b/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.cpp @@ -116,22 +116,22 @@ namespace MobileGL { return Resources; } - CompilerResult ShaderCompiler::CompileShader(const ShaderAttrib& attrib) { + Result> ShaderCompiler::CompileShader(const ShaderAttrib& attrib) { auto shaderType = attrib.shaderType; auto sourceStr = attrib.sourceStr; auto lang = GetEShLanguageByShaderType(shaderType); if (lang == EShLanguage::EShLangCount) { - ShaderCompileResult r; + ResultInfo r; r.log += "Error: [Preprocess] Unsupported shader type: " + ConvertGLEnumToString(shaderType); r.errc = -1; return std::unexpected(r); } - ShaderCompileResult res; - auto& tshader = res.TShader; - tshader = MakeUnique(lang); + SharedPtr res; + auto& tshader = res; + tshader = MakeShared(lang); const char* src[] = { sourceStr.c_str() }; tshader->setStrings(src, 1); tshader->setInvertY(true); @@ -144,7 +144,7 @@ namespace MobileGL { if (!tshader->parse(&GetTBuiltInResourceInstance(), 150, ECompatibilityProfile, /*forceDefaultVersionAndProfile: */false, /*forwardCompatible: */true, EShMsgDefault)) { - ShaderCompileResult r; + ResultInfo r; r.log += "Error: [glslang] Cannot compile " + ConvertGLEnumToString(shaderType) + ":\n" + std::string(tshader->getInfoLog()); r.errc = -2; @@ -153,6 +153,49 @@ namespace MobileGL { return res; } + + Result>> ShaderCompiler::LinkProgram(const ProgramAttrib& attrib) { + glslang::TProgram program; + for (auto& s : attrib.shaders) { + program.addShader(s.get()); + } + + if (!program.link(EShMsgDefault)) { + ResultInfo r; + r.log = "Error: [glslang] Cannot link the program:\n" + std::string(program.getInfoLog()); + r.errc = -3; + return std::unexpected(r); + } + + UniquePtr resolver; + for (unsigned stage = 0; stage < EShLangCount; stage++) { + auto* pResolver = program.getGlslIoResolver((EShLanguage)stage); + if (pResolver) { + resolver = UniquePtr(pResolver); + break; + } + } + auto ioMapper = UniquePtr(glslang::GetGlslIoMapper()); + + if (!program.mapIO(resolver.get(), ioMapper.get())) { + ResultInfo r; + r.log = "Error: [glslang] Cannot mapIO:\n" + std::string(program.getInfoLog()); + r.errc = -4; + return std::unexpected(r); + } + + glslang::SpvOptions spvOptions; + spvOptions.disableOptimizer = false; + + Vector> allSpirv; + for (auto type : attrib.shaderTypes) { + Vector spirv; + GlslangToSpv(*program.getIntermediate(ConvertGLEnumToEShLanguage(type)), spirv, &spvOptions); + allSpirv.push_back(spirv); + } + + return allSpirv; + } } } } diff --git a/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.h b/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.h index 2d05e0c6..671c6338 100644 --- a/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.h +++ b/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.h @@ -10,7 +10,8 @@ namespace MG_Util { namespace ShaderTranspiler { class ShaderCompiler { public: - static CompilerResult CompileShader(const ShaderAttrib& attrib); + static Result> CompileShader(const ShaderAttrib& attrib); + static Result>> LinkProgram(const ProgramAttrib& attrib); }; } } diff --git a/MobileGL/MG_Util/ShaderTranspiler/Types.h b/MobileGL/MG_Util/ShaderTranspiler/Types.h index 272ebfd3..58a2ad78 100644 --- a/MobileGL/MG_Util/ShaderTranspiler/Types.h +++ b/MobileGL/MG_Util/ShaderTranspiler/Types.h @@ -22,7 +22,7 @@ namespace MobileGL { struct TUniform { String name; - glslang::TStorageQualifier storageQualifier; + // glslang::TType type; Uint layoutLocation = 0; Uint layoutBinding = 0; glslang::TLayoutPacking layoutPacking; @@ -42,20 +42,18 @@ namespace MobileGL { String sourceStr; }; - struct CompiledTShader { - UniquePtr TShader; - Vector> uniforms; - Vector> samplers; + struct ProgramAttrib { + Vector shaderTypes; + Vector> shaders; }; - template - struct ShaderCompileResult: - public std::conditional_t { + struct ResultInfo { Int errc = 0; String log; }; - using CompilerResult = std::expected, ShaderCompileResult>; + template + using Result = std::expected; struct ShaderPayload { // In