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); }