From 60f68852212339e478dd15a3ec9e3bd6cf70d271 Mon Sep 17 00:00:00 2001 From: Branimir Karadzic Date: Mon, 27 Jul 2026 18:59:38 -0700 Subject: [PATCH] ShaderCompiler: preserve original sampler names colliding with HLSL/MSL keywords SPIRV-Cross's HLSL/MSL backends rename any shader resource whose name collides with a target-language reserved keyword by prepending '_' (e.g. GLSL samplers 'Texture2D'/'Texture2DArray' become '_Texture2D'/'_Texture2DArray'). Babylon.js and bgfx look samplers up by their original GLSL name, so the renamed uniform never bound and the stage silently sampled nothing (transparent output). AppendSamplers now recovers the original pre-transpile name from the parser's ParsedIR (get_name(id)) -- the Compiler transpiles a private copy of the IR, so the parser retains the original names -- and emits that into the bgfx uniform table and the stage map. The texture register (DecorationBinding) is unchanged; only the app-facing name is fixed. Non-colliding samplers resolve to the identical string and are unaffected. The OpenGL stage-assignment guard is now keyed on the recovered name so the vertex and fragment passes agree on the same identifier. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 60c2ec68-6de1-445d-9fc9-b699db737eae --- .../Source/ShaderCompilerCommon.cpp | 28 +++++++++++++------ .../Source/ShaderCompilerCommon.h | 2 +- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/Plugins/ShaderCompiler/Source/ShaderCompilerCommon.cpp b/Plugins/ShaderCompiler/Source/ShaderCompilerCommon.cpp index e2c3c29a7..77d4b55b5 100644 --- a/Plugins/ShaderCompiler/Source/ShaderCompilerCommon.cpp +++ b/Plugins/ShaderCompiler/Source/ShaderCompilerCommon.cpp @@ -90,12 +90,21 @@ namespace Babylon::ShaderCompilerCommon } } - void AppendSamplers(std::vector& bytes, const spirv_cross::Compiler& compiler, const spirv_cross::SmallVector& samplers, std::map& stages) + void AppendSamplers(std::vector& bytes, const spirv_cross::Compiler& compiler, const spirv_cross::ParsedIR& originalIr, const spirv_cross::SmallVector& samplers, std::map& stages) { for (const spirv_cross::Resource& sampler : samplers) { - AppendBytes(bytes, static_cast(sampler.name.size())); - AppendBytes(bytes, sampler.name); + // SPIRV-Cross's HLSL/MSL backends rename resources whose name collides with a reserved + // keyword of the target language (e.g. a GLSL sampler named "Texture2D" or "Texture2DArray" + // becomes "_Texture2D" because those are HLSL built-in object types). bgfx's uniform table + // and Babylon.js look samplers up by their original GLSL name, so the renamed identifier would + // never bind (the sampler silently samples nothing). Recover the pre-transpile name from the + // parser's ParsedIR (the Compiler transpiles a private copy, leaving the parser's names intact). + const std::string& originalName = originalIr.get_name(sampler.id); + const std::string& name = originalName.empty() ? sampler.name : originalName; + + AppendBytes(bytes, static_cast(name.size())); + AppendBytes(bytes, name); AppendBytes(bytes, static_cast(bgfx::UniformType::Sampler | BGFX_UNIFORM_SAMPLERBIT)); // TODO : These values (num, regIndex, regCount) are only used by Vulkan and should be set for that API @@ -113,13 +122,14 @@ namespace Babylon::ShaderCompilerCommon // That produced multiple sampler2D uniforms and a samplerCube all pointing at one unit, // which GLES/ANGLE rejects at draw time with GL_INVALID_OPERATION (D3D11/Metal don't // validate this, so the bug was GL-only). Each sampler now gets its own distinct unit, - // mirroring WebGL's Effect._bindSamplerUniformToChannel. - if (stages.find(sampler.name) == stages.end()) + // mirroring WebGL's Effect._bindSamplerUniformToChannel. Keyed on the recovered + // pre-transpile name (see above) so both stages agree on the same identifier. + if (stages.find(name) == stages.end()) { - stages[sampler.name] = static_cast(stages.size()); + stages[name] = static_cast(stages.size()); } #else - stages[sampler.name] = static_cast(compiler.get_decoration(sampler.id, spv::DecorationBinding)); + stages[name] = static_cast(compiler.get_decoration(sampler.id, spv::DecorationBinding)); #endif } } @@ -298,7 +308,7 @@ namespace Babylon::ShaderCompilerCommon AppendBytes(vertexBytes, static_cast(numUniforms)); AppendUniformBuffer(vertexBytes, uniformsInfo, false); - AppendSamplers(vertexBytes, compiler, samplers, bgfxShaderInfo.UniformStages); + AppendSamplers(vertexBytes, compiler, vertexShaderInfo.Parser->get_parsed_ir(), samplers, bgfxShaderInfo.UniformStages); AppendBytes(vertexBytes, static_cast(vertexShaderInfo.Bytes.size())); AppendBytes(vertexBytes, vertexShaderInfo.Bytes); @@ -359,7 +369,7 @@ namespace Babylon::ShaderCompilerCommon AppendBytes(fragmentBytes, static_cast(numUniforms)); AppendUniformBuffer(fragmentBytes, uniformsInfo, true); - AppendSamplers(fragmentBytes, compiler, samplers, bgfxShaderInfo.UniformStages); + AppendSamplers(fragmentBytes, compiler, fragmentShaderInfo.Parser->get_parsed_ir(), samplers, bgfxShaderInfo.UniformStages); AppendBytes(fragmentBytes, static_cast(fragmentShaderInfo.Bytes.size())); AppendBytes(fragmentBytes, fragmentShaderInfo.Bytes); diff --git a/Plugins/ShaderCompiler/Source/ShaderCompilerCommon.h b/Plugins/ShaderCompiler/Source/ShaderCompilerCommon.h index e66ba6c78..3694ef5f4 100644 --- a/Plugins/ShaderCompiler/Source/ShaderCompilerCommon.h +++ b/Plugins/ShaderCompiler/Source/ShaderCompilerCommon.h @@ -61,7 +61,7 @@ namespace Babylon::ShaderCompilerCommon }; void AppendUniformBuffer(std::vector& bytes, const NonSamplerUniformsInfo& uniformBuffer, bool isFragment); - void AppendSamplers(std::vector& bytes, const spirv_cross::Compiler& compiler, const spirv_cross::SmallVector& samplers, std::map& stages); + void AppendSamplers(std::vector& bytes, const spirv_cross::Compiler& compiler, const spirv_cross::ParsedIR& originalIr, const spirv_cross::SmallVector& samplers, std::map& stages); NonSamplerUniformsInfo CollectNonSamplerUniforms(spirv_cross::Parser& parser, const spirv_cross::Compiler& compiler); /// Assigns unique descriptor bindings to every uniform buffer in the shader so that