[Fix, Test] (GLState, ShaderTranspiler): report GL's default binding of zero for an unqualified uniform block

This commit is contained in:
2026-08-22 12:41:18 -04:00
parent 6a2e9dc791
commit 0eb5d54bb8
8 changed files with 103 additions and 13 deletions
@@ -486,7 +486,8 @@ namespace MobileGL {
attrib.explicitFragmentOutLocations,
attrib.explicitFragmentOutIndices,
attrib.explicitOpaqueUniformBindings,
attrib.storageBlocksWithoutBinding);
attrib.storageBlocksWithoutBinding,
attrib.uniformBlocksWithoutBinding);
break;
}
auto ioMapper = UniquePtr<glslang::TIoMapper>(glslang::GetGlslIoMapper());
@@ -76,6 +76,7 @@ namespace MobileGL {
// assigned - see the comment on TMglGlslIoResolver::reserverResourceSlot.
UnorderedMap<String, Uint>* explicitOpaqueUniformBindings = nullptr;
std::set<String>* storageBlocksWithoutBinding = nullptr;
std::set<String>* uniformBlocksWithoutBinding = nullptr;
};
struct ProgramBinaryAttrib {
@@ -196,6 +196,17 @@ namespace MobileGL {
m_storageBlocksWithoutBinding->insert(name.c_str());
}
// A UNIFORM block that declared no binding. Same capture point and same union-across-
// stages reasoning as the storage-block set above, and the same reason it cannot be
// asked later: mapIO is about to write an auto-assigned binding into this very
// qualifier. MGL_GLOBAL_UBO is MobileGL's own synthesized block, not an application
// one - it never reaches the GL block space and must not be seeded here.
if (m_uniformBlocksWithoutBinding != nullptr && type.getBasicType() == glslang::EbtBlock &&
qualifier.storage == glslang::EvqUniform && !qualifier.hasBinding() &&
name.compare(MG_Util::ShaderTranspiler::GLOBAL_UBO_NAME) != 0) {
m_uniformBlocksWithoutBinding->insert(name.c_str());
}
TDefaultGlslIoResolver::reserverResourceSlot(ent, infoSink);
}
@@ -29,16 +29,19 @@ namespace MobileGL {
TMglGlslIoResolver(const glslang::TIntermediate& intermediate, const ExplicitVarSlotMap& vertexIns,
const ExplicitVarSlotMap& fragOuts, const ExplicitVarSlotMap& fragOutIndices,
ExplicitVarSlotMap* opaqueUniformBindings,
std::set<String>* storageBlocksWithoutBinding = nullptr)
std::set<String>* storageBlocksWithoutBinding = nullptr,
std::set<String>* uniformBlocksWithoutBinding = nullptr)
: TDefaultGlslIoResolver(intermediate), m_explicitVertexIns(vertexIns), m_explicitFragOuts(fragOuts),
m_explicitFragOutIndices(fragOutIndices), m_explicitOpaqueUniformBindings(opaqueUniformBindings),
m_storageBlocksWithoutBinding(storageBlocksWithoutBinding) {}
m_storageBlocksWithoutBinding(storageBlocksWithoutBinding),
m_uniformBlocksWithoutBinding(uniformBlocksWithoutBinding) {}
TMglGlslIoResolver(const glslang::TProgram& program, const EShLanguage stage,
const ExplicitVarSlotMap& vertexIns, const ExplicitVarSlotMap& fragOuts,
const ExplicitVarSlotMap& fragOutIndices, ExplicitVarSlotMap* opaqueUniformBindings,
std::set<String>* storageBlocksWithoutBinding = nullptr)
std::set<String>* storageBlocksWithoutBinding = nullptr,
std::set<String>* uniformBlocksWithoutBinding = nullptr)
: TMglGlslIoResolver(*program.getIntermediate(stage), vertexIns, fragOuts, fragOutIndices,
opaqueUniformBindings, storageBlocksWithoutBinding) {}
opaqueUniformBindings, storageBlocksWithoutBinding, uniformBlocksWithoutBinding) {}
void reserverStorageSlot(glslang::TVarEntryInfo& ent, TInfoSink& infoSink) override;
void reserverResourceSlot(glslang::TVarEntryInfo& ent, TInfoSink& infoSink) override;
int resolveInOutLocation(EShLanguage stage, glslang::TVarEntryInfo& ent) override;
@@ -62,6 +65,13 @@ namespace MobileGL {
// layout(binding = N). GL 4.3 core 7.8 gives such a block binding ZERO; see
// ProgramLinkTask::SeedDefaultStorageBlockBindings for what is done with them.
std::set<String>* m_storageBlocksWithoutBinding = nullptr;
// The same capture for UNIFORM blocks. GL 4.6 core 7.6.2 gives an unqualified uniform
// block binding ZERO, and glslang's auto-mapper does not: it packs uniform blocks into
// the same slot space as samplers and images (spvVersion.openGl is 0 under
// setEnvClient(EShClientVulkan), so TDefaultGlslIoResolver::resolveBinding keys every
// resource kind on set 0), so an unbound block declared after an unbound image lands on
// 1. See ProgramLinkTask's UBO reflection loop for what is done with them.
std::set<String>* m_uniformBlocksWithoutBinding = nullptr;
std::map<glslang::TString, int> m_plainUniformLocationSizeByName;
std::map<glslang::TString, int> m_plainUniformLocationByName;
bool m_plainUniformLocationsAssigned = false;