From 57dd0fe480672874561078e789f7b25a59f483b0 Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Tue, 4 Nov 2025 21:55:26 +0800 Subject: [PATCH] [Feat]: implement glBindVertexAttribLocation in DirectGLES backend (fixing OptiFine?) --- MobileGL/MG_Backend/DirectGLES/Managers.cpp | 3 ++ .../GLState/ProgramState/ProgramObject.cpp | 9 +++-- .../GLState/ProgramState/ProgramObject.h | 4 +++ MobileGL/MG_Test/Program/ProgramTest.cpp | 34 +++++++++++++++++-- .../MG_Util/ShaderTranspiler/SpvcSession.cpp | 19 +++++++++++ .../MG_Util/ShaderTranspiler/SpvcSession.h | 1 + 6 files changed, 66 insertions(+), 4 deletions(-) diff --git a/MobileGL/MG_Backend/DirectGLES/Managers.cpp b/MobileGL/MG_Backend/DirectGLES/Managers.cpp index 26684d18..1c521c3f 100644 --- a/MobileGL/MG_Backend/DirectGLES/Managers.cpp +++ b/MobileGL/MG_Backend/DirectGLES/Managers.cpp @@ -501,6 +501,9 @@ namespace MobileGL::MG_Backend::DirectGLES { auto& spirvCode = shaderSpirvs[index]; MG_Util::ShaderTranspiler::SpvcSession spvcSession(spirvCode); + if (glShaderType == GL_VERTEX_SHADER) { + spvcSession.SetVertexAttribLocation(stateProgramObject->GetAttribLocationMap()); + } spvc_compiler_options options; spvcSession.CreateOptions(&options); diff --git a/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp b/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp index f8e96ae3..cdfe94ff 100644 --- a/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp +++ b/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp @@ -195,6 +195,10 @@ namespace MobileGL { std::swap(m_attribs[location], m_attribs[idx]); std::swap(m_attribTypes[location], m_attribTypes[idx]); } + + for (SizeT idx = 0; idx < m_attribs.size(); ++idx) { + m_attribLocation[m_attribs[idx]] = idx; + } } // ---------- UBO ---------- @@ -207,7 +211,6 @@ namespace MobileGL { m_uniformBlockIndex[ubo.name] = ubo.getBinding(); m_uniformBlockIndexInTProgram[ubo.getBinding()] = i; } - } void ProgramObject::GenerateBinary() { @@ -244,7 +247,9 @@ namespace MobileGL { assert(binaryResult); m_generatedSpirv = Move(binaryResult.value()); - for (auto spv : m_generatedSpirv) { + for (SizeT i = 0; i < m_generatedSpirv.size(); i++) { + auto& spv = m_generatedSpirv[i]; + auto shaderType = shaderTypes[i]; SpvcSession session(spv); auto result = session.ParseMetaData(); if (result < 0) { diff --git a/MobileGL/MG_State/GLState/ProgramState/ProgramObject.h b/MobileGL/MG_State/GLState/ProgramState/ProgramObject.h index a525c043..96de9d96 100644 --- a/MobileGL/MG_State/GLState/ProgramState/ProgramObject.h +++ b/MobileGL/MG_State/GLState/ProgramState/ProgramObject.h @@ -108,6 +108,8 @@ namespace MobileGL { Uint GetExternalIndex() const { return m_externalIndex; } + const UnorderedMap& GetAttribLocationMap() const { return m_attribLocation; } + private: void DoReflection(); void GenerateBinary(); @@ -124,6 +126,8 @@ namespace MobileGL { UnorderedMap m_explicitAttribLocations; Vector m_attribs; Vector m_attribTypes; + // For SpvcSession::SetVertexAttribLocation() + UnorderedMap m_attribLocation; // Uniforms UnorderedMap m_uniformLocations; diff --git a/MobileGL/MG_Test/Program/ProgramTest.cpp b/MobileGL/MG_Test/Program/ProgramTest.cpp index b2e96d91..27e6ed69 100644 --- a/MobileGL/MG_Test/Program/ProgramTest.cpp +++ b/MobileGL/MG_Test/Program/ProgramTest.cpp @@ -19,7 +19,7 @@ TEST_F(ProgramTest, Sanity) { const char* vsSrc = R"(#version 460 -layout (location = 0) in vec4 Position; +layout (location = 2) in vec4 Position; in float fIn4; in float fIn2; in float fIn5; @@ -146,7 +146,7 @@ TEST_F(ProgramTest, CompileAndLink) { GetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &uniformNameMaxLength); ASSERT_EQ(uniformNameMaxLength, 12); - ASSERT_EQ(GetAttribLocation(program, "Position"), 0); + ASSERT_EQ(GetAttribLocation(program, "Position"), 2); ASSERT_EQ(GetAttribLocation(program, "fIn1"), 1); ASSERT_EQ(GetAttribLocation(program, "fIn3"), 3); ASSERT_EQ(GetAttribLocation(program, "fIn5"), 5); @@ -169,6 +169,36 @@ TEST_F(ProgramTest, CompileAndLink) { int intVal; GetUniformiv(program, locInt, &intVal); EXPECT_EQ(intVal, 114514); + + auto programObj = MG_State::pGLContext->GetProgramObject(program); + auto& shaderSpirvs = programObj->GetGeneratedSpirv(); + for (int index = 0; index < shaderSpirvs.size(); ++index) { + String source; + auto& spirvCode = shaderSpirvs[index]; + + MG_Util::ShaderTranspiler::SpvcSession spvcSession(spirvCode); + + spvc_compiler_options options; + spvcSession.CreateOptions(&options); + + spvc_compiler_options_set_uint(options, SPVC_COMPILER_OPTION_GLSL_VERSION, 320); + spvc_compiler_options_set_bool(options, SPVC_COMPILER_OPTION_GLSL_ES, SPVC_TRUE); + spvc_compiler_options_set_bool(options, SPVC_COMPILER_OPTION_GLSL_VULKAN_SEMANTICS, SPVC_FALSE); + + spvcSession.SetOptions(options); + + const char* result = nullptr; + spvcSession.Compile(&result); + + if (!result) { + MG_Util::ShaderTranspiler::ResultInfo r; + r.log += "Failed to compile the shader to GLSL: \n"; + r.log += spvcSession.GetLastErrorString(); + r.errc = -5; + FAIL() << r.log; + } + printf("shader dump: \n%s\n", result); + } } TEST_F(ProgramTest, UniformMatrixFunctions) { diff --git a/MobileGL/MG_Util/ShaderTranspiler/SpvcSession.cpp b/MobileGL/MG_Util/ShaderTranspiler/SpvcSession.cpp index a02604f7..732a77c9 100644 --- a/MobileGL/MG_Util/ShaderTranspiler/SpvcSession.cpp +++ b/MobileGL/MG_Util/ShaderTranspiler/SpvcSession.cpp @@ -60,6 +60,25 @@ namespace MobileGL { return variables; } + spvc_result SpvcSession::SetVertexAttribLocation(const UnorderedMap& location) { + // TODO: We should assert we're really dealing with vertex shader here + + SPVC_CHK_INIT + const spvc_reflected_resource *list = nullptr; + size_t count = 0; + SPVC_CHK_RESULT(spvc_resources_get_resource_list_for_type(resources, SPVC_RESOURCE_TYPE_STAGE_INPUT, &list, &count)); + for (size_t i = 0; i < count; ++i) { + auto& resource = list[i]; + auto it = location.find(resource.name); + if (it != location.end()) { + // realize glBindVertexAttribLocation here + // it->second should be the location explicitly requested + spvc_compiler_set_decoration(compiler, resource.id, SpvDecorationLocation, it->second); + } + } + SPVC_CHK_RETURN + } + spvc_result SpvcSession::Compile(const char** result) { SPVC_CHK_INIT SPVC_CHK_RESULT(spvc_compiler_compile(compiler, result)); diff --git a/MobileGL/MG_Util/ShaderTranspiler/SpvcSession.h b/MobileGL/MG_Util/ShaderTranspiler/SpvcSession.h index 13cde7c7..73506564 100644 --- a/MobileGL/MG_Util/ShaderTranspiler/SpvcSession.h +++ b/MobileGL/MG_Util/ShaderTranspiler/SpvcSession.h @@ -73,6 +73,7 @@ namespace MobileGL { spvc_result CreateOptions(spvc_compiler_options* options); spvc_result SetOptions(spvc_compiler_options options); Vector GetShaderInterface(spvc_resource_type resource_type) const; + spvc_result SetVertexAttribLocation(const UnorderedMap& location); spvc_result Compile(const char** result); const SpvcMetadata& GetMetadata() const; const char* GetLastErrorString() const;