From 6ac0fd6f0a39db75ec35d5d00b562d8a5298db67 Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Tue, 11 Nov 2025 17:06:46 +0800 Subject: [PATCH] [Feat]: (MG_Util/ShaderTranspiler): TMglGlslIoResolver: a custom glslang IoResolver to realize `glBindAttribLocation` semantics --- .../GLState/ProgramState/ProgramObject.cpp | 141 +++++++++--------- MobileGL/MG_Test/Program/ProgramTest.cpp | 7 +- .../ShaderTranspiler/ShaderCompiler.cpp | 12 +- MobileGL/MG_Util/ShaderTranspiler/Types.h | 1 + .../glslang/TMglGlslIoResolver.cpp | 21 ++- .../glslang/TMglGlslIoResolver.h | 19 ++- 6 files changed, 114 insertions(+), 87 deletions(-) diff --git a/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp b/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp index 993bdc49..098d4343 100644 --- a/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp +++ b/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp @@ -86,6 +86,7 @@ namespace MobileGL { MG_Util::ShaderTranspiler::ProgramAttrib attrib{ .shaders = Move(shaders), + .explicitAttribLocations = m_explicitAttribLocations }; MGLOG_D("ProgramObject %u: Calling ShaderCompiler::LinkProgram", m_externalIndex); @@ -246,79 +247,81 @@ namespace MobileGL { m_attribTypes[location] = inVar.glDefineType; MGLOG_D("ProgramObject %u: Reflection - placed attrib '%s' at explicit location %d", m_externalIndex, inVar.name.c_str(), location); - } else if (location >= (int)m_attribs.size()) { - MGLOG_W("ProgramObject %u: ProgramObject::DoReflection - attrib location %d >= attribs.size() " - "(%zu). Ignoring.", - m_externalIndex, location, m_attribs.size()); - continue; - } else { - bool placed = false; - for (size_t idx = 0; idx < m_attribs.size(); ++idx) { - if (m_attribs[idx].empty()) { - m_attribs[idx] = inVar.name; - m_attribTypes[idx] = inVar.glDefineType; - placed = true; - MGLOG_D("ProgramObject %u: Reflection - placed attrib '%s' into free slot %zu", - m_externalIndex, inVar.name.c_str(), idx); - break; - } - } - if (!placed && (int)m_attribs.size() < maxAttribs) { - m_attribs.push_back(inVar.name); - m_attribTypes.push_back(inVar.glDefineType); - placed = true; - MGLOG_D("ProgramObject %u: Reflection - pushed attrib '%s' to new slot %zu", - m_externalIndex, inVar.name.c_str(), m_attribs.size() - 1); - } - if (!placed) { - MGLOG_W("ProgramObject %u: ProgramObject::DoReflection - cannot place attrib '%s' (no free " - "slot and at max capacity). Ignoring.", - m_externalIndex, inVar.name.c_str()); - } } + // else if (location >= (int)m_attribs.size()) { + // MGLOG_W("ProgramObject %u: ProgramObject::DoReflection - attrib location %d >= attribs.size() " + // "(%zu). Ignoring.", + // m_externalIndex, location, m_attribs.size()); + // continue; + // } + // else { + // bool placed = false; + // for (size_t idx = 0; idx < m_attribs.size(); ++idx) { + // if (m_attribs[idx].empty()) { + // m_attribs[idx] = inVar.name; + // m_attribTypes[idx] = inVar.glDefineType; + // placed = true; + // MGLOG_D("ProgramObject %u: Reflection - placed attrib '%s' into free slot %zu", + // m_externalIndex, inVar.name.c_str(), idx); + // break; + // } + // } + // if (!placed && (int)m_attribs.size() < maxAttribs) { + // m_attribs.push_back(inVar.name); + // m_attribTypes.push_back(inVar.glDefineType); + // placed = true; + // MGLOG_D("ProgramObject %u: Reflection - pushed attrib '%s' to new slot %zu", + // m_externalIndex, inVar.name.c_str(), m_attribs.size() - 1); + // } + // if (!placed) { + // MGLOG_W("ProgramObject %u: ProgramObject::DoReflection - cannot place attrib '%s' (no free " + // "slot and at max capacity). Ignoring.", + // m_externalIndex, inVar.name.c_str()); + // } + // } } // Implement glBindAttribLocation semantics (explicit locations set by user) - for (auto& [name, location] : m_explicitAttribLocations) { - MGLOG_D("ProgramObject %u: Reflection - explicit attrib location request: name='%s' location=%d", - m_externalIndex, name.c_str(), location); - if (location < 0) continue; - if (location >= (int)m_attribs.size()) { - if (location >= maxAttribs) { - MGLOG_W("ProgramObject %u: SetExplicitAttribLocation: requested location %d >= " - "GL_MAX_VERTEX_ATTRIBS (%d). Ignored for attribute '%s'.", - m_externalIndex, location, maxAttribs, name.c_str()); - continue; - } - m_attribs.resize(location + 1); - m_attribTypes.resize(location + 1); - MGLOG_D("ProgramObject %u: Reflection - resized attrib arrays to %zu to accommodate explicit " - "location %d", - m_externalIndex, m_attribs.size(), location); - } - - if (m_attribs[location] != name) { - auto it = std::find(m_attribs.begin(), m_attribs.end(), name); - if (it == m_attribs.end()) { - MGLOG_D("ProgramObject %u: Reflection - explicit attrib '%s' not found in current list, " - "skipping swap", - m_externalIndex, name.c_str()); - continue; - } - auto idx = std::distance(m_attribs.begin(), it); - std::swap(m_attribs[location], m_attribs[idx]); - std::swap(m_attribTypes[location], m_attribTypes[idx]); - MGLOG_D("ProgramObject %u: Reflection - swapped attrib '%s' from idx %zu to explicit " - "location %d", - m_externalIndex, name.c_str(), idx, location); - } - - for (SizeT idx = 0; idx < m_attribs.size(); ++idx) { - m_attribLocation[m_attribs[idx]] = idx; - MGLOG_D("ProgramObject %u: Reflection - attribLocation['%s'] = %zu", m_externalIndex, - m_attribs[idx].c_str(), idx); - } - } + // for (auto& [name, location] : m_explicitAttribLocations) { + // MGLOG_D("ProgramObject %u: Reflection - explicit attrib location request: name='%s' location=%d", + // m_externalIndex, name.c_str(), location); + // if (location < 0) continue; + // if (location >= (int)m_attribs.size()) { + // if (location >= maxAttribs) { + // MGLOG_W("ProgramObject %u: SetExplicitAttribLocation: requested location %d >= " + // "GL_MAX_VERTEX_ATTRIBS (%d). Ignored for attribute '%s'.", + // m_externalIndex, location, maxAttribs, name.c_str()); + // continue; + // } + // m_attribs.resize(location + 1); + // m_attribTypes.resize(location + 1); + // MGLOG_D("ProgramObject %u: Reflection - resized attrib arrays to %zu to accommodate explicit " + // "location %d", + // m_externalIndex, m_attribs.size(), location); + // } + // + // if (m_attribs[location] != name) { + // auto it = std::find(m_attribs.begin(), m_attribs.end(), name); + // if (it == m_attribs.end()) { + // MGLOG_D("ProgramObject %u: Reflection - explicit attrib '%s' not found in current list, " + // "skipping swap", + // m_externalIndex, name.c_str()); + // continue; + // } + // auto idx = std::distance(m_attribs.begin(), it); + // std::swap(m_attribs[location], m_attribs[idx]); + // std::swap(m_attribTypes[location], m_attribTypes[idx]); + // MGLOG_D("ProgramObject %u: Reflection - swapped attrib '%s' from idx %zu to explicit " + // "location %d", + // m_externalIndex, name.c_str(), idx, location); + // } + // + // for (SizeT idx = 0; idx < m_attribs.size(); ++idx) { + // m_attribLocation[m_attribs[idx]] = idx; + // MGLOG_D("ProgramObject %u: Reflection - attribLocation['%s'] = %zu", m_externalIndex, + // m_attribs[idx].c_str(), idx); + // } + // } // ---------- UBO ---------- int uboCount = m_program->getNumUniformBlocks(); diff --git a/MobileGL/MG_Test/Program/ProgramTest.cpp b/MobileGL/MG_Test/Program/ProgramTest.cpp index 38358523..1bb16ade 100644 --- a/MobileGL/MG_Test/Program/ProgramTest.cpp +++ b/MobileGL/MG_Test/Program/ProgramTest.cpp @@ -26,6 +26,7 @@ in float fIn2; in float fIn5; in float fIn6; in float fIn1; +layout (location = 0) in float fIn0; in float fIn3; layout(location = 0) uniform mat4 ProjMat; @@ -45,7 +46,7 @@ void main(){ vec2 dummy2 = TestMat2[0]; vec3 dummy3 = TestMat3[0]; - oneTexel = (1.0 * (fIn1 * fIn2 * fIn3 * fIn4 * fIn5 * fIn6)) / InSize; + oneTexel = (1.0 * (fIn1 * fIn2 * fIn3 * fIn4 * fIn5 * fIn6 * fIn0)) / InSize; texCoord = Position.xy / OutSize; })"; @@ -135,6 +136,9 @@ TEST_F(ProgramTest, CompileAndLink) { BindAttribLocation(program, 5, "fIn5"); printf("Linking program...\n"); LinkProgram(program); + GLint linkStatus = GL_FALSE; + GetProgramiv(program, GL_LINK_STATUS, &linkStatus); + ASSERT_EQ(linkStatus, GL_TRUE); printf("Program linked.\n"); ASSERT_EQ(GetUniformLocation(program, "ProjMat"), 0); @@ -151,6 +155,7 @@ TEST_F(ProgramTest, CompileAndLink) { ASSERT_EQ(GetAttribLocation(program, "fIn1"), 1); ASSERT_EQ(GetAttribLocation(program, "fIn3"), 3); ASSERT_EQ(GetAttribLocation(program, "fIn5"), 5); + ASSERT_EQ(GetAttribLocation(program, "fIn0"), 0); UseProgram(program); diff --git a/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.cpp b/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.cpp index 504f5a52..52b8088b 100644 --- a/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.cpp +++ b/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.cpp @@ -174,13 +174,13 @@ namespace MobileGL { return std::unexpected(r); } - UniquePtr resolver; + // UniquePtr resolver; + UniquePtr resolver; for (unsigned stage = 0; stage < EShLangCount; stage++) { - auto* pResolver = program->getGlslIoResolver((EShLanguage)stage); - if (pResolver) { - resolver = UniquePtr(pResolver); - break; - } + if (program->getIntermediate((EShLanguage)stage) == nullptr) + continue; + resolver = MakeUnique(*program, (EShLanguage)stage, attrib.explicitAttribLocations); + break; } auto ioMapper = UniquePtr(glslang::GetGlslIoMapper()); diff --git a/MobileGL/MG_Util/ShaderTranspiler/Types.h b/MobileGL/MG_Util/ShaderTranspiler/Types.h index 080d01c7..30ad27bd 100644 --- a/MobileGL/MG_Util/ShaderTranspiler/Types.h +++ b/MobileGL/MG_Util/ShaderTranspiler/Types.h @@ -21,6 +21,7 @@ namespace MobileGL { struct ProgramAttrib { Vector> shaders; + UnorderedMap explicitAttribLocations; }; struct ProgramBinaryAttrib { diff --git a/MobileGL/MG_Util/ShaderTranspiler/glslang/TMglGlslIoResolver.cpp b/MobileGL/MG_Util/ShaderTranspiler/glslang/TMglGlslIoResolver.cpp index e9df15f1..fcff34ca 100644 --- a/MobileGL/MG_Util/ShaderTranspiler/glslang/TMglGlslIoResolver.cpp +++ b/MobileGL/MG_Util/ShaderTranspiler/glslang/TMglGlslIoResolver.cpp @@ -4,10 +4,17 @@ #include "TMglGlslIoResolver.h" -int TMglGlslIoResolver::resolveInOutLocation(EShLanguage stage, glslang::TVarEntryInfo &ent) { - return glslang::TDefaultGlslIoResolver::resolveInOutLocation(stage, ent); -} - -int TMglGlslIoResolver::resolveUniformLocation(EShLanguage stage, glslang::TVarEntryInfo &ent) { - return glslang::TDefaultGlslIoResolver::resolveUniformLocation(stage, ent); -} +namespace MobileGL { + void TMglGlslIoResolver::reserverStorageSlot(glslang::TVarEntryInfo& ent, TInfoSink& infoSink) { + const glslang::TType& type = ent.symbol->getType(); + const glslang::TString& name = ent.symbol->getAccessName(); + if (type.getQualifier().isPipeInput()) { + auto it = m_explicitAttribLocations.find(name.c_str()); + if (it != m_explicitAttribLocations.end()) { + auto& writableType = ent.symbol->getWritableType(); + writableType.getQualifier().layoutLocation = it->second; + } + } + TDefaultGlslIoResolver::reserverStorageSlot(ent, infoSink); + } +} \ No newline at end of file diff --git a/MobileGL/MG_Util/ShaderTranspiler/glslang/TMglGlslIoResolver.h b/MobileGL/MG_Util/ShaderTranspiler/glslang/TMglGlslIoResolver.h index 44422b9d..77f34baf 100644 --- a/MobileGL/MG_Util/ShaderTranspiler/glslang/TMglGlslIoResolver.h +++ b/MobileGL/MG_Util/ShaderTranspiler/glslang/TMglGlslIoResolver.h @@ -11,10 +11,21 @@ #include #include #include "TVarEntryInfo.h" +#include "MG_Util/Types.h" -class TMglGlslIoResolver: public glslang::TDefaultGlslIoResolver { - int resolveInOutLocation(EShLanguage stage, glslang::TVarEntryInfo& ent) override; - int resolveUniformLocation(EShLanguage /*stage*/, glslang::TVarEntryInfo& ent) override; -}; +namespace MobileGL { + class TMglGlslIoResolver: public glslang::TDefaultGlslIoResolver { + public: + using ExplicitVarSlotMap = UnorderedMap; + TMglGlslIoResolver(const glslang::TIntermediate& intermediate, const ExplicitVarSlotMap& attribLocations): + TDefaultGlslIoResolver(intermediate), m_explicitAttribLocations(attribLocations) {} + TMglGlslIoResolver(const glslang::TProgram& program, const EShLanguage stage, const ExplicitVarSlotMap& attribLocations): + TDefaultGlslIoResolver(*program.getIntermediate(stage)), + m_explicitAttribLocations(attribLocations) {} + void reserverStorageSlot(glslang::TVarEntryInfo& ent, TInfoSink& infoSink) override; + protected: + const ExplicitVarSlotMap& m_explicitAttribLocations; + }; +}