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