From 7bece3f8c913a730340b472ec2728863df35f9af Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Fri, 15 Aug 2025 09:00:40 +0800 Subject: [PATCH 1/8] [Chore] (MG_Test): get rid of `-g -O0` --- MobileGL/MG_Test/CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/MobileGL/MG_Test/CMakeLists.txt b/MobileGL/MG_Test/CMakeLists.txt index 1b669467..b4efe926 100644 --- a/MobileGL/MG_Test/CMakeLists.txt +++ b/MobileGL/MG_Test/CMakeLists.txt @@ -3,8 +3,6 @@ project(MobileGLTest) set(CMAKE_CXX_STANDARD 23) set(CMAKE_CXX_STANDARD_REQUIRED ON) -set(CMAKE_BUILD_TYPE Debug) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0") include(FetchContent) FetchContent_Declare( From a4769996c37a653f3e21ce89c3662c4ba0b20bcc Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Fri, 15 Aug 2025 09:35:05 +0800 Subject: [PATCH 2/8] [Feat] (MG_Util/ShaderCompiler): separates GetSpirvBinaryFromProgram() from LinkProgram() --- .../GLState/ProgramState/ProgramObject.cpp | 64 +++++++++---------- .../GLState/ProgramState/ProgramObject.h | 4 +- MobileGL/MG_Test/Program/ProgramTest.cpp | 3 + MobileGL/MG_Test/Program/ProgramUtilTest.cpp | 17 ++++- .../ShaderTranspiler/ShaderCompiler.cpp | 22 ++++--- .../MG_Util/ShaderTranspiler/ShaderCompiler.h | 3 +- MobileGL/MG_Util/ShaderTranspiler/Types.h | 5 ++ 7 files changed, 72 insertions(+), 46 deletions(-) diff --git a/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp b/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp index 99a06c5b..c1a6eaed 100644 --- a/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp +++ b/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp @@ -26,7 +26,7 @@ namespace MobileGL { } void ProgramObject::Link() { - PreLink(); + // PreLink(); Vector shaderTypes(m_shaders.size()); Vector> shaders(m_shaders.size()); @@ -43,7 +43,7 @@ namespace MobileGL { auto result = MG_Util::ShaderTranspiler::ShaderCompiler::LinkProgram(attrib); if (result) { m_linkStatus = true; - m_programBinary = Move(result.value()); + m_program = result.value(); } else { m_linkStatus = false; m_infoLog = result.error().log; @@ -53,7 +53,7 @@ namespace MobileGL { THROW_EXCEPTION(e); } - PostLink(); + // PostLink(); } void ProgramObject::MarkAsDeleted() { @@ -127,35 +127,35 @@ namespace MobileGL { } void ProgramObject::PostLink() { - if (m_programBinary.empty()) { - assert(false); - return; - } - MG_Util::ShaderTranspiler::SpvcSession session(m_programBinary[0]); - const char* src = nullptr; // we don't care the source atm - auto result = session.Compile(&src); - if (result != SPVC_SUCCESS) { - assert(false); - return; - } - m_metadata = session.GetMetadata(); - auto& uniformOffsets = m_metadata.plainUniformOffsetsInUBO; - for (const auto& [name, offset] : uniformOffsets) { - assert(m_uniforms.find(name) != m_uniforms.end()); - assert(m_uniforms[name] < m_uniformOffsets.size()); - m_uniformOffsets[m_uniforms[name]] = offset; - } - m_uboScratch.resize(m_metadata.uboSize, 0); - - auto& types = m_metadata.plainUniformMemberTypes; - - assert(types.size() == m_uniformOffsets.size()); - m_uniformTypes.resize(m_uniformOffsets.size()); - for (const auto& [name, type] : types) { - auto gltype = MG_Util::ConvertSpvcTypeToGLEnum(type); - auto location = m_uniforms[name]; - m_uniformTypes[location] = gltype; - } + // if (m_programBinary.empty()) { + // assert(false); + // return; + // } + // MG_Util::ShaderTranspiler::SpvcSession session(m_programBinary[0]); + // const char* src = nullptr; // we don't care the source atm + // auto result = session.Compile(&src); + // if (result != SPVC_SUCCESS) { + // assert(false); + // return; + // } + // m_metadata = session.GetMetadata(); + // auto& uniformOffsets = m_metadata.plainUniformOffsetsInUBO; + // for (const auto& [name, offset] : uniformOffsets) { + // assert(m_uniforms.find(name) != m_uniforms.end()); + // assert(m_uniforms[name] < m_uniformOffsets.size()); + // m_uniformOffsets[m_uniforms[name]] = offset; + // } + // m_uboScratch.resize(m_metadata.uboSize, 0); + // + // auto& types = m_metadata.plainUniformMemberTypes; + // + // assert(types.size() == m_uniformOffsets.size()); + // m_uniformTypes.resize(m_uniformOffsets.size()); + // for (const auto& [name, type] : types) { + // auto gltype = MG_Util::ConvertSpvcTypeToGLEnum(type); + // auto location = m_uniforms[name]; + // m_uniformTypes[location] = gltype; + // } } } // namespace GLState } // namespace MG_State diff --git a/MobileGL/MG_State/GLState/ProgramState/ProgramObject.h b/MobileGL/MG_State/GLState/ProgramState/ProgramObject.h index 6309da71..1133460f 100644 --- a/MobileGL/MG_State/GLState/ProgramState/ProgramObject.h +++ b/MobileGL/MG_State/GLState/ProgramState/ProgramObject.h @@ -35,8 +35,8 @@ namespace MobileGL { const Uint m_id = 0; Vector> m_shaders; - // basically this contains SPIR-V in binary format - Vector> m_programBinary; + + SharedPtr m_program; // Uniforms MG_Util::ShaderTranspiler::SpvcMetadata m_metadata; diff --git a/MobileGL/MG_Test/Program/ProgramTest.cpp b/MobileGL/MG_Test/Program/ProgramTest.cpp index 3504e45a..fba40d91 100644 --- a/MobileGL/MG_Test/Program/ProgramTest.cpp +++ b/MobileGL/MG_Test/Program/ProgramTest.cpp @@ -113,6 +113,9 @@ TEST_F(ProgramTest, CompileAndLink) { LinkProgram(program); printf("Program linked.\n"); + // FIXME: fix these later, refactoring uniform location reflection stuff + FAIL() << "GetUniformLocation not implemented yet!"; + EXPECT_EQ(GetUniformLocation(program, "ProjMat"), 0); EXPECT_EQ(GetUniformLocation(program, "Gray"), 1); EXPECT_EQ(GetUniformLocation(program, "Saturation"), 6); diff --git a/MobileGL/MG_Test/Program/ProgramUtilTest.cpp b/MobileGL/MG_Test/Program/ProgramUtilTest.cpp index 58f650fb..da2d5506 100644 --- a/MobileGL/MG_Test/Program/ProgramUtilTest.cpp +++ b/MobileGL/MG_Test/Program/ProgramUtilTest.cpp @@ -143,8 +143,15 @@ TEST_F(ProgramUtilTest, CompileFragmentShaderWithDiscard) { FAIL() << "errc: " << program_res.error().errc << "\nlog: " << program_res.error().log; } + auto program = program_res.value(); - auto spirvs = program_res.value(); + ProgramBinaryAttrib binaryAttrib { + .shaderTypes = { GL_FRAGMENT_SHADER }, + .program = *program, + }; + auto bin_res = ShaderCompiler::GetSpirvBinaryFromProgram(binaryAttrib); + + auto spirvs = bin_res.value(); Vector sessions(spirvs.size()); for (SizeT i = 0; i < spirvs.size(); ++i) { @@ -282,7 +289,13 @@ TEST_F(ProgramUtilTest, DecompProgram) { FAIL() << "errc: " << program_res.error().errc << "\nlog: " << program_res.error().log; } - auto spirvs = program_res.value(); + ProgramBinaryAttrib binaryAttrib { + .shaderTypes = { GL_VERTEX_SHADER, GL_FRAGMENT_SHADER }, + .program = *program_res.value(), + }; + auto bin_res = ShaderCompiler::GetSpirvBinaryFromProgram(binaryAttrib); + + auto spirvs = bin_res.value(); Vector sessions(spirvs.size()); for (SizeT i = 0; i < spirvs.size(); ++i) { diff --git a/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.cpp b/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.cpp index f98faf69..f9971ea3 100644 --- a/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.cpp +++ b/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.cpp @@ -159,22 +159,22 @@ namespace MobileGL { return res; } - Result>> ShaderCompiler::LinkProgram(const ProgramAttrib& attrib) { - glslang::TProgram program; + Result> ShaderCompiler::LinkProgram(const ProgramAttrib& attrib) { + SharedPtr program = MakeShared(); for (auto& s : attrib.shaders) { - program.addShader(s.get()); + program->addShader(s.get()); } - if (!program.link(EShMsgDefault)) { + if (!program->link(EShMsgDefault)) { ResultInfo r; - r.log = "Error: [glslang] Cannot link the program:\n" + std::string(program.getInfoLog()); + 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); + auto* pResolver = program->getGlslIoResolver((EShLanguage)stage); if (pResolver) { resolver = UniquePtr(pResolver); break; @@ -182,20 +182,24 @@ namespace MobileGL { } auto ioMapper = UniquePtr(glslang::GetGlslIoMapper()); - if (!program.mapIO(resolver.get(), ioMapper.get())) { + if (!program->mapIO(resolver.get(), ioMapper.get())) { ResultInfo r; - r.log = "Error: [glslang] Cannot mapIO:\n" + std::string(program.getInfoLog()); + r.log = "Error: [glslang] Cannot mapIO:\n" + std::string(program->getInfoLog()); r.errc = -4; return std::unexpected(r); } + return program; + } + + Result>> ShaderCompiler::GetSpirvBinaryFromProgram(const ProgramBinaryAttrib &attrib) { glslang::SpvOptions spvOptions; spvOptions.disableOptimizer = false; Vector> allSpirv; for (auto type : attrib.shaderTypes) { Vector spirv; - GlslangToSpv(*program.getIntermediate(ConvertGLEnumToEShLanguage(type)), spirv, &spvOptions); + GlslangToSpv(*attrib.program.getIntermediate(ConvertGLEnumToEShLanguage(type)), spirv, &spvOptions); allSpirv.push_back(spirv); } diff --git a/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.h b/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.h index 0fadb5de..6c6ef566 100644 --- a/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.h +++ b/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.h @@ -8,7 +8,8 @@ namespace MobileGL { class ShaderCompiler { public: static Result> CompileShader(const ShaderAttrib& attrib); - static Result>> LinkProgram(const ProgramAttrib& attrib); + static Result> LinkProgram(const ProgramAttrib& attrib); + static Result>> GetSpirvBinaryFromProgram(const ProgramBinaryAttrib& attrib); static Result DecompileShader(SpvcSession& session); }; } // namespace ShaderTranspiler diff --git a/MobileGL/MG_Util/ShaderTranspiler/Types.h b/MobileGL/MG_Util/ShaderTranspiler/Types.h index dc0fc2c8..c4c90ef1 100644 --- a/MobileGL/MG_Util/ShaderTranspiler/Types.h +++ b/MobileGL/MG_Util/ShaderTranspiler/Types.h @@ -24,6 +24,11 @@ namespace MobileGL { Vector> shaders; }; + struct ProgramBinaryAttrib { + Vector shaderTypes; + const glslang::TProgram& program; + }; + struct ResultInfo { Int errc = 0; String log; From 4aa70fda65e9bb33e15a4968904092c6ce656e30 Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Fri, 15 Aug 2025 15:49:31 +0800 Subject: [PATCH 3/8] [Refactor] (MG_State/Program): refractor uniform reflection using glslang reflection API --- .../GLState/ProgramState/ProgramObject.cpp | 145 ++++++++++-------- .../GLState/ProgramState/ProgramObject.h | 17 +- .../GLState/ProgramState/ShaderObject.cpp | 72 ++++----- .../GLState/ProgramState/ShaderObject.h | 2 +- MobileGL/MG_Test/Program/ProgramTest.cpp | 3 - 5 files changed, 132 insertions(+), 107 deletions(-) diff --git a/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp b/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp index c1a6eaed..71e3f767 100644 --- a/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp +++ b/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp @@ -47,13 +47,11 @@ namespace MobileGL { } else { m_linkStatus = false; m_infoLog = result.error().log; - - const std::string e = std::format("Shader link failed: \nerrc: {}\nmsg: {}\n", result.error().errc, - result.error().log); - THROW_EXCEPTION(e); } // PostLink(); + + DoReflection(); } void ProgramObject::MarkAsDeleted() { @@ -64,69 +62,96 @@ namespace MobileGL { return m_shaders; } - void ProgramObject::PreLink() { - m_uniforms.clear(); - m_uniformOffsets.clear(); - - for (const auto& shader : m_shaders) { - for (const auto& [name, loc] : shader->GetUniformLocations()) { - // collect all the names to map - if (loc != 4095 || m_uniforms.find(name) == m_uniforms.end()) { - m_uniforms[name] = loc; - } - - // set a flag for those who have an explicit location - if (loc != 4095) { - if (loc >= m_uniformOffsets.size()) { - m_uniformOffsets.reserve(std::bit_ceil(loc + 1)); - m_uniformOffsets.resize(loc + 1, 0); - } - assert(m_uniformOffsets[loc] == 0); - m_uniformOffsets[loc] = 1; - } - } + void ProgramObject::DoReflection() { + if (!m_program->buildReflection()) { + m_linkStatus = false; + m_infoLog = "Build reflection failed."; + return; } - // Let's find a location for those who doesn't have one yet - Uint nextLocation = 0; - - // Find first empty location - for (SizeT i = 0; i < m_uniformOffsets.size(); i++) { - if (m_uniformOffsets[i] == 0) { - nextLocation = i; - break; - } + auto uniformCount = m_program->getNumUniformVariables(); + for (int i = 0; i < uniformCount; i++) { + auto& uniform = m_program->getUniform(i); + auto location = uniform.layoutLocation(); + m_maxUniformLocation = std::max(m_maxUniformLocation, location); + m_uniformLocations[uniform.name] = location; } - for (auto& [name, loc] : m_uniforms) { - if (loc == 4095) { - // check if we drained all the holes already - if (nextLocation >= m_uniformOffsets.size()) { - loc = nextLocation; - m_uniformOffsets.push_back(1); - nextLocation++; - continue; - } + m_uniformNames.resize(m_maxUniformLocation + 1); + m_uniformTypes.resize(m_maxUniformLocation + 1); + m_uniformOffsets.resize(m_maxUniformLocation + 1); - // assign an empty location - loc = nextLocation; - m_uniformOffsets[loc] = 1; - - // Find next empty location - for (nextLocation++; nextLocation < m_uniformOffsets.size(); nextLocation++) { - if (m_uniformOffsets[nextLocation] == 0) break; - } - } - } - - m_uniformNames.resize(m_uniformOffsets.size()); - for (auto& [name, loc] : m_uniforms) { - m_uniformNames[loc] = name; - m_uniformNameMaxLength = std::max(m_uniformNameMaxLength, (Int)name.length()); + for (int i = 0; i < uniformCount; i++) { + auto& uniform = m_program->getUniform(i); + auto location = uniform.layoutLocation(); + m_uniformNames[location] = uniform.name; + m_uniformTypes[location] = uniform.glDefineType; } } - void ProgramObject::PostLink() { + // void ProgramObject::PreLink() { + // m_uniforms.clear(); + // m_uniformOffsets.clear(); + // + // for (const auto& shader : m_shaders) { + // for (const auto& [name, loc] : shader->GetUniformLocations()) { + // // collect all the names to map + // if (loc != 4095 || m_uniforms.find(name) == m_uniforms.end()) { + // m_uniforms[name] = loc; + // } + // + // // set a flag for those who have an explicit location + // if (loc != 4095) { + // if (loc >= m_uniformOffsets.size()) { + // m_uniformOffsets.reserve(std::bit_ceil(loc + 1)); + // m_uniformOffsets.resize(loc + 1, 0); + // } + // assert(m_uniformOffsets[loc] == 0); + // m_uniformOffsets[loc] = 1; + // } + // } + // } + // + // // Let's find a location for those who doesn't have one yet + // Uint nextLocation = 0; + // + // // Find first empty location + // for (SizeT i = 0; i < m_uniformOffsets.size(); i++) { + // if (m_uniformOffsets[i] == 0) { + // nextLocation = i; + // break; + // } + // } + // + // for (auto& [name, loc] : m_uniforms) { + // if (loc == 4095) { + // // check if we drained all the holes already + // if (nextLocation >= m_uniformOffsets.size()) { + // loc = nextLocation; + // m_uniformOffsets.push_back(1); + // nextLocation++; + // continue; + // } + // + // // assign an empty location + // loc = nextLocation; + // m_uniformOffsets[loc] = 1; + // + // // Find next empty location + // for (nextLocation++; nextLocation < m_uniformOffsets.size(); nextLocation++) { + // if (m_uniformOffsets[nextLocation] == 0) break; + // } + // } + // } + // + // m_uniformNames.resize(m_uniformOffsets.size()); + // for (auto& [name, loc] : m_uniforms) { + // m_uniformNames[loc] = name; + // m_uniformNameMaxLength = std::max(m_uniformNameMaxLength, (Int)name.length()); + // } + // } + // + // void ProgramObject::PostLink() { // if (m_programBinary.empty()) { // assert(false); // return; @@ -156,7 +181,7 @@ namespace MobileGL { // auto location = m_uniforms[name]; // m_uniformTypes[location] = gltype; // } - } + // } } // namespace GLState } // namespace MG_State } // namespace MobileGL \ No newline at end of file diff --git a/MobileGL/MG_State/GLState/ProgramState/ProgramObject.h b/MobileGL/MG_State/GLState/ProgramState/ProgramObject.h index 1133460f..dbdf2957 100644 --- a/MobileGL/MG_State/GLState/ProgramState/ProgramObject.h +++ b/MobileGL/MG_State/GLState/ProgramState/ProgramObject.h @@ -19,8 +19,8 @@ namespace MobileGL { Int GetUniformMaxLength() const { return m_uniformNameMaxLength; } Uint GetUniformCount() { return m_uniformOffsets.size(); } Int GetUniformLocation(const String& name) { - const auto it = m_uniforms.find(name); - return (it == m_uniforms.end()) ? -1 : it->second; + const auto it = m_uniformLocations.find(name); + return (it == m_uniformLocations.end()) ? -1 : it->second; } GLenum GetUniformType(Uint index) const { return m_uniformTypes[index]; @@ -30,8 +30,9 @@ namespace MobileGL { return m_uniformNames[index]; } private: - void PreLink(); - void PostLink(); + void DoReflection(); + // void PreLink(); + // void PostLink(); const Uint m_id = 0; Vector> m_shaders; @@ -41,16 +42,16 @@ namespace MobileGL { // Uniforms MG_Util::ShaderTranspiler::SpvcMetadata m_metadata; - UnorderedMap m_uniforms; - // 0 or 1 for if the location is explicitly specified at PreLink stage, - // offsets into global ubo for PostLink - Vector m_uniformOffsets; + UnorderedMap m_uniformLocations; Vector m_uniformNames; Vector m_uniformTypes; + // Need to be reflected after linking of SPIR-V binary + Vector m_uniformOffsets; Vector m_uboScratch; Int m_uniformNameMaxLength = 0; + Uint m_maxUniformLocation = 0; String m_infoLog; Bool m_deleteStatus = false; diff --git a/MobileGL/MG_State/GLState/ProgramState/ShaderObject.cpp b/MobileGL/MG_State/GLState/ProgramState/ShaderObject.cpp index d90f40e9..ec795d3a 100644 --- a/MobileGL/MG_State/GLState/ProgramState/ShaderObject.cpp +++ b/MobileGL/MG_State/GLState/ProgramState/ShaderObject.cpp @@ -15,15 +15,19 @@ namespace MobileGL { } void ShaderObject::Compile() { - if (!DoReflection()) { - return; - } + // if (!DoReflection()) { + // return; + // } using namespace MG_Util::ShaderTranspiler; + + // Compile for OpenGL here, so that we can do validation and link + // like a real OpenGL driver at linking stage + // Will compile for other backends later. ShaderAttrib attrib{ .shaderType = GetGLShaderTypeByMGLShaderStage(m_stage), .sourceStr = m_source, - .flags = 0 + .flags = ShaderCompileBits::CompileForOpenGL }; auto result = ShaderCompiler::CompileShader(attrib); @@ -33,9 +37,6 @@ namespace MobileGL { } else { 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); } } @@ -43,35 +44,36 @@ namespace MobileGL { m_deleteStatus = true; } - bool ShaderObject::DoReflection() { - using namespace MG_Util::ShaderTranspiler; - ShaderAttrib attrib{ - .shaderType = GetGLShaderTypeByMGLShaderStage(m_stage), - .sourceStr = m_source, - .flags = ShaderCompileBits::CompileForOpenGL - }; + // 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; + // } - 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 bdbf74e4..9ed7ebb8 100644 --- a/MobileGL/MG_State/GLState/ProgramState/ShaderObject.h +++ b/MobileGL/MG_State/GLState/ProgramState/ShaderObject.h @@ -69,7 +69,7 @@ namespace MobileGL { const String& GetInfoLog() const { return m_infoLog; } const UnorderedMap& GetUniformLocations() const { return m_uniforms; } private: - bool DoReflection(); + // bool DoReflection(); const Uint m_id = 0; const ShaderStage m_stage; String m_source; diff --git a/MobileGL/MG_Test/Program/ProgramTest.cpp b/MobileGL/MG_Test/Program/ProgramTest.cpp index fba40d91..3504e45a 100644 --- a/MobileGL/MG_Test/Program/ProgramTest.cpp +++ b/MobileGL/MG_Test/Program/ProgramTest.cpp @@ -113,9 +113,6 @@ TEST_F(ProgramTest, CompileAndLink) { LinkProgram(program); printf("Program linked.\n"); - // FIXME: fix these later, refactoring uniform location reflection stuff - FAIL() << "GetUniformLocation not implemented yet!"; - EXPECT_EQ(GetUniformLocation(program, "ProjMat"), 0); EXPECT_EQ(GetUniformLocation(program, "Gray"), 1); EXPECT_EQ(GetUniformLocation(program, "Saturation"), 6); From ef5b7cd99a6c8ff1e67c2c95638a5c7d03966223 Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Fri, 15 Aug 2025 15:58:25 +0800 Subject: [PATCH 4/8] [Refactor] (MG_State/Program): get rid of spvc junk --- MobileGL/MG_State/GLState/ProgramState/ProgramObject.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MobileGL/MG_State/GLState/ProgramState/ProgramObject.h b/MobileGL/MG_State/GLState/ProgramState/ProgramObject.h index dbdf2957..f066be6d 100644 --- a/MobileGL/MG_State/GLState/ProgramState/ProgramObject.h +++ b/MobileGL/MG_State/GLState/ProgramState/ProgramObject.h @@ -40,7 +40,7 @@ namespace MobileGL { SharedPtr m_program; // Uniforms - MG_Util::ShaderTranspiler::SpvcMetadata m_metadata; + // MG_Util::ShaderTranspiler::SpvcMetadata m_metadata; UnorderedMap m_uniformLocations; Vector m_uniformNames; From ec95c0401a68c7a9b73a78c11a3c9ef6a91e05d5 Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Fri, 15 Aug 2025 17:16:49 +0800 Subject: [PATCH 5/8] [Feat] (MG_State/Program): GetProgramiv WIP --- .../MG_Impl/GLImpl/Program/GL_Program.cpp | 62 ++++++++++++++++++- .../GLState/ProgramState/ProgramObject.cpp | 7 +++ .../GLState/ProgramState/ProgramObject.h | 10 ++- MobileGL/MG_Test/Program/ProgramTest.cpp | 11 +++- 4 files changed, 85 insertions(+), 5 deletions(-) diff --git a/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp b/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp index 86dfa415..a94d7f9a 100644 --- a/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp +++ b/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp @@ -199,7 +199,63 @@ namespace MobileGL { } void GetProgramiv_State(GLuint program, GLenum pname, GLint* params) { - THROW_UNIMPL_EXCEPTION; + auto programObject = TryToGetProgramObject(program); + if (!programObject) + return; + + switch (pname) { + case GL_DELETE_STATUS: + *params = programObject->GetDeleteStatus(); + break; + case GL_LINK_STATUS: + *params = programObject->GetLinkStatus(); + break; + case GL_VALIDATE_STATUS: + *params = programObject->GetValidateStatus(); + break; + case GL_INFO_LOG_LENGTH: { + const auto& log = programObject->GetInfoLog(); + *params = log.length(); + break; + } + case GL_ATTACHED_SHADERS: { + const auto& attachedShaders = programObject->GetAttachedShaders(); + *params = attachedShaders.size(); + break; + } + case GL_ACTIVE_ATOMIC_COUNTER_BUFFERS: + *params = programObject->GetActiveAtomicCounterCount(); + break; + case GL_ACTIVE_ATTRIBUTES: + *params = programObject->GetActiveAttributesCount(); + break; + case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH: + *params = programObject->GetActiveAttributesMaxLength(); + break; + case GL_ACTIVE_UNIFORMS: + *params = programObject->GetUniformCount(); + break; + case GL_ACTIVE_UNIFORM_MAX_LENGTH: + *params = programObject->GetUniformMaxLength(); + break; + case GL_PROGRAM_BINARY_LENGTH: + case GL_ACTIVE_UNIFORM_BLOCKS: // GL >= 3.1 + case GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH: // ditto. + case GL_COMPUTE_WORK_GROUP_SIZE: // GL >= 4.3 + + case GL_TRANSFORM_FEEDBACK_BUFFER_MODE: + case GL_TRANSFORM_FEEDBACK_VARYINGS: + case GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH: + case GL_GEOMETRY_VERTICES_OUT: + case GL_GEOMETRY_INPUT_TYPE: + case GL_GEOMETRY_OUTPUT_TYPE: + default: + MG_State::pGLContext->RecordError( + ErrorCode::InvalidEnum, + MakeShared("MG_Impl/GLImpl", __func__, + "`pname` is not an accepted value.")); + return; + } } void GetProgramInfoLog_State(GLuint program, GLsizei bufSize, GLsizei* length, GLchar* infoLog) { @@ -355,7 +411,9 @@ namespace MobileGL { } void ValidateProgram_State(GLuint program) { - THROW_UNIMPL_EXCEPTION; + auto programObject = TryToGetProgramObject(program); + if (!programObject) + return; } void AttachShader(GLuint program, GLuint shader) { diff --git a/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp b/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp index 71e3f767..07b24256 100644 --- a/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp +++ b/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp @@ -74,6 +74,7 @@ namespace MobileGL { auto& uniform = m_program->getUniform(i); auto location = uniform.layoutLocation(); m_maxUniformLocation = std::max(m_maxUniformLocation, location); + m_uniformNameMaxLength = std::max(m_uniformNameMaxLength, (Int)uniform.name.length()); m_uniformLocations[uniform.name] = location; } @@ -87,6 +88,12 @@ namespace MobileGL { m_uniformNames[location] = uniform.name; m_uniformTypes[location] = uniform.glDefineType; } + + int inCount = m_program->getNumPipeInputs(); + for (int i = 0; i < inCount; i++) { + auto& inVar = m_program->getPipeInput(i); + m_attribInNameMaxLength = std::max(m_attribInNameMaxLength, (Int)inVar.name.length()); + } } // void ProgramObject::PreLink() { diff --git a/MobileGL/MG_State/GLState/ProgramState/ProgramObject.h b/MobileGL/MG_State/GLState/ProgramState/ProgramObject.h index f066be6d..e06c815b 100644 --- a/MobileGL/MG_State/GLState/ProgramState/ProgramObject.h +++ b/MobileGL/MG_State/GLState/ProgramState/ProgramObject.h @@ -17,7 +17,7 @@ namespace MobileGL { Vector>& GetAttachedShaders(); const String& GetInfoLog() const { return m_infoLog; } Int GetUniformMaxLength() const { return m_uniformNameMaxLength; } - Uint GetUniformCount() { return m_uniformOffsets.size(); } + Uint GetUniformCount() { return m_uniformNames.size(); } Int GetUniformLocation(const String& name) { const auto it = m_uniformLocations.find(name); return (it == m_uniformLocations.end()) ? -1 : it->second; @@ -29,6 +29,13 @@ namespace MobileGL { const String& GetUniformName(Uint index) const { return m_uniformNames[index]; } + + Bool GetDeleteStatus() const { return m_deleteStatus; } + Bool GetLinkStatus() const { return m_linkStatus; } + Bool GetValidateStatus() const { return m_validateStatus; } + Int GetActiveAtomicCounterCount() const { return m_program->getNumAtomicCounters(); } + Int GetActiveAttributesCount() const { return m_program->getNumPipeInputs(); } + Int GetActiveAttributesMaxLength() const { return m_attribInNameMaxLength; } private: void DoReflection(); // void PreLink(); @@ -52,6 +59,7 @@ namespace MobileGL { Int m_uniformNameMaxLength = 0; Uint m_maxUniformLocation = 0; + Int m_attribInNameMaxLength = 0; String m_infoLog; Bool m_deleteStatus = false; diff --git a/MobileGL/MG_Test/Program/ProgramTest.cpp b/MobileGL/MG_Test/Program/ProgramTest.cpp index 3504e45a..6e0cd42a 100644 --- a/MobileGL/MG_Test/Program/ProgramTest.cpp +++ b/MobileGL/MG_Test/Program/ProgramTest.cpp @@ -52,11 +52,12 @@ uniform vec2 InSize; layout(location = 1) uniform vec3 Gray; uniform vec3 RedMatrix; -uniform vec3 GreenMatrix; +uniform vec3 GreenMatrix0; uniform vec3 BlueMatrix; uniform vec3 Offset; uniform vec3 ColorScale; layout(location = 6) uniform float Saturation; +uniform int AQuickFoxJumpsOverALazyDog; out vec4 fragColor; @@ -65,7 +66,7 @@ void main() { // Color Matrix float RedValue = dot(InTexel.rgb, RedMatrix); - float GreenValue = dot(InTexel.rgb, GreenMatrix); + float GreenValue = dot(InTexel.rgb, GreenMatrix0); float BlueValue = dot(InTexel.rgb, BlueMatrix); vec3 OutColor = vec3(RedValue, GreenValue, BlueValue); @@ -116,4 +117,10 @@ TEST_F(ProgramTest, CompileAndLink) { EXPECT_EQ(GetUniformLocation(program, "ProjMat"), 0); EXPECT_EQ(GetUniformLocation(program, "Gray"), 1); EXPECT_EQ(GetUniformLocation(program, "Saturation"), 6); + GLint uniformCount = 0; + GetProgramiv(program, GL_ACTIVE_UNIFORMS, &uniformCount); + EXPECT_EQ(uniformCount, 11); + GLint uniformNameMaxLength = 0; + GetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &uniformNameMaxLength); + EXPECT_EQ(uniformNameMaxLength, 12); } From a050248982d5403a0e04312dffa7ebe73d15ef33 Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Fri, 15 Aug 2025 17:31:58 +0800 Subject: [PATCH 6/8] [Feat] (MG_State/Program): GetProgramiv: GL_ACTIVE_UNIFORM_BLOCKS, GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH --- MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp | 7 ++++++- MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp | 6 ++++++ MobileGL/MG_State/GLState/ProgramState/ProgramObject.h | 5 ++++- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp b/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp index a94d7f9a..0f0b3ed5 100644 --- a/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp +++ b/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp @@ -238,11 +238,16 @@ namespace MobileGL { case GL_ACTIVE_UNIFORM_MAX_LENGTH: *params = programObject->GetUniformMaxLength(); break; - case GL_PROGRAM_BINARY_LENGTH: case GL_ACTIVE_UNIFORM_BLOCKS: // GL >= 3.1 + *params = programObject->GetActiveUniformBlocksCount(); + break; case GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH: // ditto. + *params = programObject->GetActiveUniformBlocksMaxLength(); + break; case GL_COMPUTE_WORK_GROUP_SIZE: // GL >= 4.3 + case GL_PROGRAM_BINARY_LENGTH: + case GL_TRANSFORM_FEEDBACK_BUFFER_MODE: case GL_TRANSFORM_FEEDBACK_VARYINGS: case GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH: diff --git a/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp b/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp index 07b24256..e87a1982 100644 --- a/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp +++ b/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp @@ -94,6 +94,12 @@ namespace MobileGL { auto& inVar = m_program->getPipeInput(i); m_attribInNameMaxLength = std::max(m_attribInNameMaxLength, (Int)inVar.name.length()); } + + int uboCount = m_program->getNumUniformBlocks(); + for (int i = 0; i < uboCount; i++) { + auto& ubo = m_program->getUniformBlock(i); + m_uniformBlockNameMaxLength = std::max(m_uniformBlockNameMaxLength, (Int)ubo.name.length()); + } } // void ProgramObject::PreLink() { diff --git a/MobileGL/MG_State/GLState/ProgramState/ProgramObject.h b/MobileGL/MG_State/GLState/ProgramState/ProgramObject.h index e06c815b..76a65543 100644 --- a/MobileGL/MG_State/GLState/ProgramState/ProgramObject.h +++ b/MobileGL/MG_State/GLState/ProgramState/ProgramObject.h @@ -35,7 +35,9 @@ namespace MobileGL { Bool GetValidateStatus() const { return m_validateStatus; } Int GetActiveAtomicCounterCount() const { return m_program->getNumAtomicCounters(); } Int GetActiveAttributesCount() const { return m_program->getNumPipeInputs(); } + Int GetActiveUniformBlocksCount() const { return m_program->getNumUniformBlocks(); } Int GetActiveAttributesMaxLength() const { return m_attribInNameMaxLength; } + Int GetActiveUniformBlocksMaxLength() const { return m_uniformBlockNameMaxLength; } private: void DoReflection(); // void PreLink(); @@ -57,9 +59,10 @@ namespace MobileGL { Vector m_uniformOffsets; Vector m_uboScratch; - Int m_uniformNameMaxLength = 0; Uint m_maxUniformLocation = 0; + Int m_uniformNameMaxLength = 0; Int m_attribInNameMaxLength = 0; + Int m_uniformBlockNameMaxLength = 0; String m_infoLog; Bool m_deleteStatus = false; From 5a729cd02ee07f1a5130ffde1be1ed3fed7e84c3 Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Fri, 15 Aug 2025 17:42:30 +0800 Subject: [PATCH 7/8] [Feat] (MG_State/Program): GetShaderiv --- .../MG_Impl/GLImpl/Program/GL_Program.cpp | 30 +++++++++++++++++-- .../GLState/ProgramState/ProgramObject.cpp | 2 +- .../GLState/ProgramState/ShaderObject.cpp | 2 +- .../GLState/ProgramState/ShaderObject.h | 6 ++-- 4 files changed, 34 insertions(+), 6 deletions(-) diff --git a/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp b/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp index 0f0b3ed5..51475f0a 100644 --- a/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp +++ b/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp @@ -100,7 +100,7 @@ namespace MobileGL { } GLuint CreateShader_State(GLenum type) { - auto shaderId = MG_State::pGLContext->CreateShader(MG_State::GLState::GetMGLShaderStageByGLShaderType(type)); + auto shaderId = MG_State::pGLContext->CreateShader(MG_State::GLState::ConvertMGLShaderStageByGLShaderType(type)); if (shaderId == 0) { MG_State::pGLContext->RecordError( ErrorCode::InvalidValue, @@ -273,7 +273,33 @@ namespace MobileGL { } void GetShaderiv_State(GLuint shader, GLenum pname, GLint* params) { - THROW_UNIMPL_EXCEPTION; + auto shaderObject = TryToGetShaderObject(shader); + if (!shaderObject) + return; + + switch (pname) { + case GL_SHADER_TYPE: + *params = ConvertGLShaderTypeByMGLShaderStage(shaderObject->GetShaderStage()); + break; + case GL_DELETE_STATUS: + *params = shaderObject->GetDeleteStatus(); + break; + case GL_COMPILE_STATUS: + *params = shaderObject->GetCompileStatus(); + break; + case GL_INFO_LOG_LENGTH: + *params = shaderObject->GetInfoLog().length(); + break; + case GL_SHADER_SOURCE_LENGTH: + *params = shaderObject->GetShaderSource().length(); + break; + default: + MG_State::pGLContext->RecordError( + ErrorCode::InvalidEnum, + MakeShared("MG_Impl/GLImpl", __func__, + "`pname` is not an accepted value.")); + return; + } } void GetShaderInfoLog_State(GLuint shader, GLsizei bufSize, GLsizei* length, GLchar* infoLog) { diff --git a/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp b/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp index e87a1982..f4534ed4 100644 --- a/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp +++ b/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp @@ -31,7 +31,7 @@ namespace MobileGL { Vector shaderTypes(m_shaders.size()); Vector> shaders(m_shaders.size()); for (SizeT i = 0; i < m_shaders.size(); i++) { - shaderTypes[i] = GetGLShaderTypeByMGLShaderStage(m_shaders[i]->GetShaderStage()); + shaderTypes[i] = ConvertGLShaderTypeByMGLShaderStage(m_shaders[i]->GetShaderStage()); shaders[i] = m_shaders[i]->GetCompiledShader(); } diff --git a/MobileGL/MG_State/GLState/ProgramState/ShaderObject.cpp b/MobileGL/MG_State/GLState/ProgramState/ShaderObject.cpp index ec795d3a..145ef741 100644 --- a/MobileGL/MG_State/GLState/ProgramState/ShaderObject.cpp +++ b/MobileGL/MG_State/GLState/ProgramState/ShaderObject.cpp @@ -25,7 +25,7 @@ namespace MobileGL { // like a real OpenGL driver at linking stage // Will compile for other backends later. ShaderAttrib attrib{ - .shaderType = GetGLShaderTypeByMGLShaderStage(m_stage), + .shaderType = ConvertGLShaderTypeByMGLShaderStage(m_stage), .sourceStr = m_source, .flags = ShaderCompileBits::CompileForOpenGL }; diff --git a/MobileGL/MG_State/GLState/ProgramState/ShaderObject.h b/MobileGL/MG_State/GLState/ProgramState/ShaderObject.h index 9ed7ebb8..21818928 100644 --- a/MobileGL/MG_State/GLState/ProgramState/ShaderObject.h +++ b/MobileGL/MG_State/GLState/ProgramState/ShaderObject.h @@ -14,7 +14,7 @@ namespace MobileGL { Unknown = -1 }; - inline static GLenum GetGLShaderTypeByMGLShaderStage(ShaderStage stage) { + inline static GLenum ConvertGLShaderTypeByMGLShaderStage(ShaderStage stage) { switch (stage) { case ShaderStage::Vertex: return GL_VERTEX_SHADER; @@ -34,7 +34,7 @@ namespace MobileGL { } } - inline static ShaderStage GetMGLShaderStageByGLShaderType(GLenum type) { + inline static ShaderStage ConvertMGLShaderStageByGLShaderType(GLenum type) { switch (type) { case GL_VERTEX_SHADER: return ShaderStage::Vertex; @@ -68,6 +68,8 @@ namespace MobileGL { SharedPtr GetCompiledShader() const { return m_shader; } const String& GetInfoLog() const { return m_infoLog; } const UnorderedMap& GetUniformLocations() const { return m_uniforms; } + Bool GetCompileStatus() const { return m_compileStatus; } + Bool GetDeleteStatus() const { return m_deleteStatus; } private: // bool DoReflection(); const Uint m_id = 0; From 13a5fd9761071d415b3acb45f57fc4ef72c63da0 Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Fri, 15 Aug 2025 17:51:14 +0800 Subject: [PATCH 8/8] [Chore] (MG_State/Program): un-implement ValidateProgram --- MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp b/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp index 51475f0a..a8ba513c 100644 --- a/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp +++ b/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp @@ -442,9 +442,7 @@ namespace MobileGL { } void ValidateProgram_State(GLuint program) { - auto programObject = TryToGetProgramObject(program); - if (!programObject) - return; + THROW_UNIMPL_EXCEPTION; } void AttachShader(GLuint program, GLuint shader) {