diff --git a/Apps/Playground/ReferenceImages/iridescence-nme.png b/Apps/Playground/ReferenceImages/iridescence-nme.png
new file mode 100644
index 000000000..688275065
Binary files /dev/null and b/Apps/Playground/ReferenceImages/iridescence-nme.png differ
diff --git a/Apps/Playground/ReferenceImages/nme-multi-build.png b/Apps/Playground/ReferenceImages/nme-multi-build.png
new file mode 100644
index 000000000..776109f1e
Binary files /dev/null and b/Apps/Playground/ReferenceImages/nme-multi-build.png differ
diff --git a/Apps/Playground/Scripts/config.json b/Apps/Playground/Scripts/config.json
index 2361ed138..6846df105 100644
--- a/Apps/Playground/Scripts/config.json
+++ b/Apps/Playground/Scripts/config.json
@@ -1,6 +1,17 @@
{
"root": "https://cdn.babylonjs.com",
"tests": [
+ {
+ "title": "Iridescence NME",
+ "playgroundId": "#2FDQT5#1507",
+ "referenceImage": "iridescence-nme.png"
+ },
+ {
+ "title": "NME Multi Build",
+ "playgroundId": "#D8AK3Z#104",
+ "referenceImage": "nme-multi-build.png",
+ "renderCount": 50
+ },
{
"title": "EXR Loader",
"playgroundId": "#4RN0VF#151",
diff --git a/Apps/package-lock.json b/Apps/package-lock.json
index dea5ee440..a5e24e3de 100644
--- a/Apps/package-lock.json
+++ b/Apps/package-lock.json
@@ -8,11 +8,11 @@
"name": "BabylonNative",
"version": "0.0.1",
"dependencies": {
- "babylonjs": "^7.22.3",
- "babylonjs-gltf2interface": "^7.22.3",
- "babylonjs-gui": "^7.22.3",
- "babylonjs-loaders": "^7.22.3",
- "babylonjs-materials": "^7.22.3",
+ "babylonjs": "^7.23.0",
+ "babylonjs-gltf2interface": "^7.23.0",
+ "babylonjs-gui": "^7.23.0",
+ "babylonjs-loaders": "^7.23.0",
+ "babylonjs-materials": "^7.23.0",
"chai": "^4.3.4",
"jsc-android": "^241213.1.0",
"mocha": "^9.2.2",
@@ -80,39 +80,39 @@
}
},
"node_modules/babylonjs": {
- "version": "7.22.3",
- "resolved": "https://registry.npmjs.org/babylonjs/-/babylonjs-7.22.3.tgz",
- "integrity": "sha512-21zma76b242rlm9DR/Nxgu9J3OfD8WbD0/MvBXAURITTX+5HiIQz/2xTHoxp9PVy7967Kmua8XlCcf+HhvB/7Q==",
+ "version": "7.23.0",
+ "resolved": "https://registry.npmjs.org/babylonjs/-/babylonjs-7.23.0.tgz",
+ "integrity": "sha512-7RAg/Z/GrIzHq8elPWbGoMUriPmYn2DmreZ+9tkn9ZYS74G/2muXjshtBL7zhNXBOCLsEvYUnpUtgfIW2lN3ow==",
"hasInstallScript": true
},
"node_modules/babylonjs-gltf2interface": {
- "version": "7.22.3",
- "resolved": "https://registry.npmjs.org/babylonjs-gltf2interface/-/babylonjs-gltf2interface-7.22.3.tgz",
- "integrity": "sha512-dxSbSiYPoYU2M0j9Q+1CJr9SLtnWLIStbT3z8q2fgowdiKCs1HZ1E/3vSt5a9Cu3Z3PT+9r0pzgajDRhdb8kaA=="
+ "version": "7.23.0",
+ "resolved": "https://registry.npmjs.org/babylonjs-gltf2interface/-/babylonjs-gltf2interface-7.23.0.tgz",
+ "integrity": "sha512-ccpHBLStLChWwvrAHvR/cGi8/+U9/uC2WtmDKnvC8Tev1vCJrTm7IiEh0cZLULvUzQmY6x0FUcMCxqxgrETIBQ=="
},
"node_modules/babylonjs-gui": {
- "version": "7.22.3",
- "resolved": "https://registry.npmjs.org/babylonjs-gui/-/babylonjs-gui-7.22.3.tgz",
- "integrity": "sha512-HaR2qR9fB10VBhUDUMku4FUJfyWW5mIoeM0aLxLZHB0DBE5zbDW3L5OY8KDjK8KQfNd83rg3wJbf9E0jGA/fMA==",
+ "version": "7.23.0",
+ "resolved": "https://registry.npmjs.org/babylonjs-gui/-/babylonjs-gui-7.23.0.tgz",
+ "integrity": "sha512-9RtGsY1j/5bbv059aRPOZHaROSEJV9I8PoKo7CIUpaykf9i2gSrWWZgAtsh5lAGT2yAHCi8G0u7mjldTLh5nIg==",
"dependencies": {
- "babylonjs": "^7.22.3"
+ "babylonjs": "^7.23.0"
}
},
"node_modules/babylonjs-loaders": {
- "version": "7.22.3",
- "resolved": "https://registry.npmjs.org/babylonjs-loaders/-/babylonjs-loaders-7.22.3.tgz",
- "integrity": "sha512-iClngcHz94XVDELwUr0WVRX3Nd7VRtTohk+Vr9N8glerYPMPs2QmjwmWeHW21QQ6Ps0W+qGn5MK8/ci0pBs1wA==",
+ "version": "7.23.0",
+ "resolved": "https://registry.npmjs.org/babylonjs-loaders/-/babylonjs-loaders-7.23.0.tgz",
+ "integrity": "sha512-HYHHM1xO+x6ySPu63KN4Vh4uNjJIs2EelO2APR2lD/Dtpw1OVTgmEBaPcn1N7Lnor6Ey4uh0QhK3fRAkbnFVcQ==",
"dependencies": {
- "babylonjs": "^7.22.3",
- "babylonjs-gltf2interface": "^7.22.3"
+ "babylonjs": "^7.23.0",
+ "babylonjs-gltf2interface": "^7.23.0"
}
},
"node_modules/babylonjs-materials": {
- "version": "7.22.3",
- "resolved": "https://registry.npmjs.org/babylonjs-materials/-/babylonjs-materials-7.22.3.tgz",
- "integrity": "sha512-2+q+yt9G3zHFln1jFWRZGUTa29UPuKymqQkwnrpm6nEgKyNvxxRa0DZ69BYMcN61WqDycx7y3GRyTubZjMvbcw==",
+ "version": "7.23.0",
+ "resolved": "https://registry.npmjs.org/babylonjs-materials/-/babylonjs-materials-7.23.0.tgz",
+ "integrity": "sha512-RLY65+x5RpX+ck/wzhjmvdPKFoUgx6vng97eTVOrWXEu4l1jwPn5wm8dZVW9gT3Ay+FoX+zmVsf5h/iV0giMPw==",
"dependencies": {
- "babylonjs": "^7.22.3"
+ "babylonjs": "^7.23.0"
}
},
"node_modules/balanced-match": {
@@ -1038,38 +1038,38 @@
"integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw=="
},
"babylonjs": {
- "version": "7.22.3",
- "resolved": "https://registry.npmjs.org/babylonjs/-/babylonjs-7.22.3.tgz",
- "integrity": "sha512-21zma76b242rlm9DR/Nxgu9J3OfD8WbD0/MvBXAURITTX+5HiIQz/2xTHoxp9PVy7967Kmua8XlCcf+HhvB/7Q=="
+ "version": "7.23.0",
+ "resolved": "https://registry.npmjs.org/babylonjs/-/babylonjs-7.23.0.tgz",
+ "integrity": "sha512-7RAg/Z/GrIzHq8elPWbGoMUriPmYn2DmreZ+9tkn9ZYS74G/2muXjshtBL7zhNXBOCLsEvYUnpUtgfIW2lN3ow=="
},
"babylonjs-gltf2interface": {
- "version": "7.22.3",
- "resolved": "https://registry.npmjs.org/babylonjs-gltf2interface/-/babylonjs-gltf2interface-7.22.3.tgz",
- "integrity": "sha512-dxSbSiYPoYU2M0j9Q+1CJr9SLtnWLIStbT3z8q2fgowdiKCs1HZ1E/3vSt5a9Cu3Z3PT+9r0pzgajDRhdb8kaA=="
+ "version": "7.23.0",
+ "resolved": "https://registry.npmjs.org/babylonjs-gltf2interface/-/babylonjs-gltf2interface-7.23.0.tgz",
+ "integrity": "sha512-ccpHBLStLChWwvrAHvR/cGi8/+U9/uC2WtmDKnvC8Tev1vCJrTm7IiEh0cZLULvUzQmY6x0FUcMCxqxgrETIBQ=="
},
"babylonjs-gui": {
- "version": "7.22.3",
- "resolved": "https://registry.npmjs.org/babylonjs-gui/-/babylonjs-gui-7.22.3.tgz",
- "integrity": "sha512-HaR2qR9fB10VBhUDUMku4FUJfyWW5mIoeM0aLxLZHB0DBE5zbDW3L5OY8KDjK8KQfNd83rg3wJbf9E0jGA/fMA==",
+ "version": "7.23.0",
+ "resolved": "https://registry.npmjs.org/babylonjs-gui/-/babylonjs-gui-7.23.0.tgz",
+ "integrity": "sha512-9RtGsY1j/5bbv059aRPOZHaROSEJV9I8PoKo7CIUpaykf9i2gSrWWZgAtsh5lAGT2yAHCi8G0u7mjldTLh5nIg==",
"requires": {
- "babylonjs": "^7.22.3"
+ "babylonjs": "^7.23.0"
}
},
"babylonjs-loaders": {
- "version": "7.22.3",
- "resolved": "https://registry.npmjs.org/babylonjs-loaders/-/babylonjs-loaders-7.22.3.tgz",
- "integrity": "sha512-iClngcHz94XVDELwUr0WVRX3Nd7VRtTohk+Vr9N8glerYPMPs2QmjwmWeHW21QQ6Ps0W+qGn5MK8/ci0pBs1wA==",
+ "version": "7.23.0",
+ "resolved": "https://registry.npmjs.org/babylonjs-loaders/-/babylonjs-loaders-7.23.0.tgz",
+ "integrity": "sha512-HYHHM1xO+x6ySPu63KN4Vh4uNjJIs2EelO2APR2lD/Dtpw1OVTgmEBaPcn1N7Lnor6Ey4uh0QhK3fRAkbnFVcQ==",
"requires": {
- "babylonjs": "^7.22.3",
- "babylonjs-gltf2interface": "^7.22.3"
+ "babylonjs": "^7.23.0",
+ "babylonjs-gltf2interface": "^7.23.0"
}
},
"babylonjs-materials": {
- "version": "7.22.3",
- "resolved": "https://registry.npmjs.org/babylonjs-materials/-/babylonjs-materials-7.22.3.tgz",
- "integrity": "sha512-2+q+yt9G3zHFln1jFWRZGUTa29UPuKymqQkwnrpm6nEgKyNvxxRa0DZ69BYMcN61WqDycx7y3GRyTubZjMvbcw==",
+ "version": "7.23.0",
+ "resolved": "https://registry.npmjs.org/babylonjs-materials/-/babylonjs-materials-7.23.0.tgz",
+ "integrity": "sha512-RLY65+x5RpX+ck/wzhjmvdPKFoUgx6vng97eTVOrWXEu4l1jwPn5wm8dZVW9gT3Ay+FoX+zmVsf5h/iV0giMPw==",
"requires": {
- "babylonjs": "^7.22.3"
+ "babylonjs": "^7.23.0"
}
},
"balanced-match": {
diff --git a/Apps/package.json b/Apps/package.json
index e6cde0f09..ce4dc8020 100644
--- a/Apps/package.json
+++ b/Apps/package.json
@@ -6,11 +6,11 @@
"getNightly": "node scripts/getNightly.js"
},
"dependencies": {
- "babylonjs": "^7.22.3",
- "babylonjs-gltf2interface": "^7.22.3",
- "babylonjs-gui": "^7.22.3",
- "babylonjs-loaders": "^7.22.3",
- "babylonjs-materials": "^7.22.3",
+ "babylonjs": "^7.23.0",
+ "babylonjs-gltf2interface": "^7.23.0",
+ "babylonjs-gui": "^7.23.0",
+ "babylonjs-loaders": "^7.23.0",
+ "babylonjs-materials": "^7.23.0",
"chai": "^4.3.4",
"jsc-android": "^241213.1.0",
"mocha": "^9.2.2",
diff --git a/Plugins/NativeEngine/Source/ShaderCompilerD3D.h b/Plugins/NativeEngine/Source/ShaderCompilerD3D.h
index 76a9ff447..8335e3335 100644
--- a/Plugins/NativeEngine/Source/ShaderCompilerD3D.h
+++ b/Plugins/NativeEngine/Source/ShaderCompilerD3D.h
@@ -106,6 +106,7 @@ namespace Babylon
ShaderCompilerTraversers::AssignLocationsAndNamesToVertexVaryingsD3D(program, ids, vertexAttributeRenaming);
ShaderCompilerTraversers::SplitSamplersIntoSamplersAndTextures(program, ids);
ShaderCompilerTraversers::InvertYDerivativeOperands(program);
+ ShaderCompilerTraversers::ReassignBindingToSamplers(program);
// clang-format off
static const spirv_cross::HLSLVertexAttributeRemap attributes[] = {
diff --git a/Plugins/NativeEngine/Source/ShaderCompilerMetal.cpp b/Plugins/NativeEngine/Source/ShaderCompilerMetal.cpp
index e8a13c023..3116f8481 100644
--- a/Plugins/NativeEngine/Source/ShaderCompilerMetal.cpp
+++ b/Plugins/NativeEngine/Source/ShaderCompilerMetal.cpp
@@ -107,7 +107,8 @@ namespace Babylon
ShaderCompilerTraversers::AssignLocationsAndNamesToVertexVaryingsMetal(program, ids, vertexAttributeRenaming);
ShaderCompilerTraversers::SplitSamplersIntoSamplersAndTextures(program, ids);
ShaderCompilerTraversers::InvertYDerivativeOperands(program);
-
+ ShaderCompilerTraversers::ReassignBindingToSamplers(program);
+
std::string vertexGLSL(vertexSource.data(), vertexSource.size());
auto [vertexParser, vertexCompiler] = CompileShader(program, EShLangVertex, vertexGLSL);
diff --git a/Plugins/NativeEngine/Source/ShaderCompilerTraversers.cpp b/Plugins/NativeEngine/Source/ShaderCompilerTraversers.cpp
index 55ab4f55d..836023fa1 100644
--- a/Plugins/NativeEngine/Source/ShaderCompilerTraversers.cpp
+++ b/Plugins/NativeEngine/Source/ShaderCompilerTraversers.cpp
@@ -901,6 +901,78 @@ namespace Babylon::ShaderCompilerTraversers
TIntermediate* m_intermediate{};
};
+
+ ///
+ /// https://github.com/BabylonJS/BabylonNative/issues/1411
+ /// When a same sampler is declared in VS and FS, GLSlang assign a different binding location for VS and FS.
+ /// Max binding location is 16 so if more than 8 samplers are declared then D3Dcompile will not compile the shader.
+ /// This is the case for NME shaders for example.
+ /// The following traverser list samplers from the VS (and their binding location) and set the same binding location
+ /// in FS if it's present. If a sampler is present in FS but not in VS, then a binding location id will be used and incremented.
+ /// potential solution replacements:
+ /// - do not expose samplers in generated nme shaders (this doesn't fix the issue if samplers are declared in VS and FS for genuine reasons)
+ /// Apart from potential regressions and more complex TS code, the problem resides in D3D world only.
+ /// - use spirv optimizer tool to remove unused samplers: it will not fix the issue, binary will be bigger and compilation time will be longer.
+ ///
+ class ReassignBindingToSamplersTraverser : public TIntermTraverser
+ {
+ public:
+ static void Traverse(TProgram& program)
+ {
+ ReassignBindingToSamplersTraverser reassignBindingToSamplersTraverser{ };
+ program.getIntermediate(EShLangVertex)->getTreeRoot()->traverse(&reassignBindingToSamplersTraverser);
+ reassignBindingToSamplersTraverser.m_fragmentPass = true;
+ program.getIntermediate(EShLangFragment)->getTreeRoot()->traverse(&reassignBindingToSamplersTraverser);
+ }
+
+ protected:
+ void visitSymbol(TIntermSymbol* symbol) override {
+ // Check if the symbol is a sampler
+ const TType& type = symbol->getType();
+ if (type.getBasicType() == EbtSampler) {
+ TQualifier& qualifier = symbol->getWritableType().getQualifier();
+ std::string name{symbol->getName().c_str()};
+ static const std::string suffix = "Texture";
+ // appends 'Texture' to the name see SamplerSplitterTraverser for differenciation
+ bool textureEnds = name.size() >= suffix.size() && name.compare(name.size() - suffix.size(), suffix.size(), suffix) == 0;
+ if (!textureEnds)
+ {
+ name += suffix;
+ }
+ if (m_fragmentPass)
+ {
+ // fragment pass
+ auto iter = m_samplerLayoutBinding.find(name);
+ if (iter == m_samplerLayoutBinding.end())
+ {
+ qualifier.layoutBinding = ++m_nextLayoutBinding;
+ m_samplerLayoutBinding[name] = qualifier.layoutBinding;
+ }
+ else
+ {
+ qualifier.layoutBinding = iter->second;
+ }
+ }
+ else
+ {
+ if (qualifier.hasBinding())
+ {
+ // vertex pass
+ m_samplerLayoutBinding[name] = qualifier.layoutBinding;
+ m_nextLayoutBinding = std::max(m_nextLayoutBinding, qualifier.layoutBinding);
+ }
+ }
+ }
+ }
+
+ private:
+ ReassignBindingToSamplersTraverser()
+ {
+ }
+ std::map m_samplerLayoutBinding;
+ bool m_fragmentPass{};
+ unsigned int m_nextLayoutBinding{0};
+ };
}
ScopeT MoveNonSamplerUniformsIntoStruct(TProgram& program, IdGenerator& ids)
@@ -937,4 +1009,9 @@ namespace Babylon::ShaderCompilerTraversers
{
InvertYDerivativeOperandsTraverser::Traverse(program);
}
+
+ void ReassignBindingToSamplers(glslang::TProgram& program)
+ {
+ ReassignBindingToSamplersTraverser::Traverse(program);
+ }
}
diff --git a/Plugins/NativeEngine/Source/ShaderCompilerTraversers.h b/Plugins/NativeEngine/Source/ShaderCompilerTraversers.h
index a24b42710..97e880c4b 100644
--- a/Plugins/NativeEngine/Source/ShaderCompilerTraversers.h
+++ b/Plugins/NativeEngine/Source/ShaderCompilerTraversers.h
@@ -82,4 +82,6 @@ namespace Babylon::ShaderCompilerTraversers
/// https://github.com/bkaradzic/bgfx/blob/7be225bf490bb1cd231cfb4abf7e617bf35b59cb/src/bgfx_shader.sh#L44-L45
/// https://github.com/bkaradzic/bgfx/blob/7be225bf490bb1cd231cfb4abf7e617bf35b59cb/src/bgfx_shader.sh#L62-L65
void InvertYDerivativeOperands(glslang::TProgram& program);
+
+ void ReassignBindingToSamplers(glslang::TProgram& program);
}