diff --git a/Apps/Playground/Scripts/config.json b/Apps/Playground/Scripts/config.json index 3b7389558..f7ba4e18e 100644 --- a/Apps/Playground/Scripts/config.json +++ b/Apps/Playground/Scripts/config.json @@ -843,8 +843,6 @@ { "title": "NME Multi Build", "playgroundId": "#D8AK3Z#113", - "excludeFromAutomaticTesting": true, - "reason": "Test crashes or hangs on Babylon Native", "referenceImage": "nme-multi-build.png" }, { @@ -1265,9 +1263,9 @@ { "title": "Custom render target", "playgroundId": "#TQCEBF#5", - "excludeFromAutomaticTesting": true, - "reason": "Test crashes on Win32 D3D11 plain (STATUS_BREAKPOINT)", - "referenceImage": "customRTT.png" + "referenceImage": "customRTT.png", + "excludedGraphicsApis": ["OpenGL"], + "reason": "GL cube skybox face-boundary seam (~12% pixel diff in upper sky); passes on D3D11/D3D12. Per-face vertical flip is required (disabling it worsens diff to 43%); residual seam is a bgfx-level GL cubemap face-boundary/seamless-filtering issue. Tracked for OpenGL backend follow-up." }, { "title": "Draco Mesh Compression (decodeMeshAsync, numWorkers = 1)", @@ -2839,9 +2837,7 @@ { "title": "UV2 Morphing", "playgroundId": "#N5DLM7#1", - "referenceImage": "UV2-Morphing.png", - "excludeFromAutomaticTesting": true, - "reason": "Test fails locally on Win32 D3D11 sweep; disabled until BabylonNative fixes are made." + "referenceImage": "UV2-Morphing.png" }, { "title": "FrameGraph nrge shadows", @@ -4449,9 +4445,7 @@ { "title": "Vertex Pulling - Morph Targets and Bones", "playgroundId": "#CT4C3C#2", - "referenceImage": "vertexPullingMorphBones.png", - "excludeFromAutomaticTesting": true, - "reason": "Test fails locally on Win32 D3D11 sweep; disabled until BabylonNative fixes are made." + "referenceImage": "vertexPullingMorphBones.png" }, { "title": "Vertex Pulling - isUnIndexed with index buffer", diff --git a/Apps/package-lock.json b/Apps/package-lock.json index 2156eb656..d8adf7009 100644 --- a/Apps/package-lock.json +++ b/Apps/package-lock.json @@ -11,13 +11,13 @@ "UnitTests/JavaScript" ], "dependencies": { - "babylonjs": "^9.3.4", - "babylonjs-addons": "^9.3.4", - "babylonjs-gltf2interface": "^9.3.4", - "babylonjs-gui": "^9.3.4", - "babylonjs-loaders": "^9.3.4", - "babylonjs-materials": "^9.3.4", - "babylonjs-serializers": "^9.3.4", + "babylonjs": "^9.15.0", + "babylonjs-addons": "^9.15.0", + "babylonjs-gltf2interface": "^9.15.0", + "babylonjs-gui": "^9.15.0", + "babylonjs-loaders": "^9.15.0", + "babylonjs-materials": "^9.15.0", + "babylonjs-serializers": "^9.15.0", "jsc-android": "^241213.1.0", "v8-android": "^7.8.2" } @@ -2596,63 +2596,63 @@ } }, "node_modules/babylonjs": { - "version": "9.9.1", - "resolved": "https://registry.npmjs.org/babylonjs/-/babylonjs-9.9.1.tgz", - "integrity": "sha512-zMH8r0l/il9PJhy2+uS+/EyeLBy/ElZg0lKLj2d+ZrUarOanjMISaACw0HUx7C1EgYoXUFSMQLYcpXguleh8GA==", + "version": "9.15.0", + "resolved": "https://registry.npmjs.org/babylonjs/-/babylonjs-9.15.0.tgz", + "integrity": "sha512-IJQhrxsxxj4KCg4aSsB5chLidzAfbghr8rnzo6sRLFin6ipfeayCxg7MevjaMzqdVmc/BOMU6sj49nSNrBq+yQ==", "hasInstallScript": true, "license": "Apache-2.0" }, "node_modules/babylonjs-addons": { - "version": "9.9.1", - "resolved": "https://registry.npmjs.org/babylonjs-addons/-/babylonjs-addons-9.9.1.tgz", - "integrity": "sha512-Hi9QZqeanqG+4VAAmJmHJh7JKf1bc/Y5Ml+wuv+W+3f/dKltZpy/pii/QN4vhYRyrU0n+S8OJc+kVeaUUFjHEg==", + "version": "9.15.0", + "resolved": "https://registry.npmjs.org/babylonjs-addons/-/babylonjs-addons-9.15.0.tgz", + "integrity": "sha512-7vxm0ffFXWHCZWDlYYleifb6mg1iSH7nNo+sA9706z7QIfpNnLS9+9cTYadWobvhURwaD/DHAKnm7Z8ckq9YAA==", "license": "Apache-2.0", "dependencies": { - "babylonjs": "9.9.1" + "babylonjs": "9.15.0" } }, "node_modules/babylonjs-gltf2interface": { - "version": "9.9.1", - "resolved": "https://registry.npmjs.org/babylonjs-gltf2interface/-/babylonjs-gltf2interface-9.9.1.tgz", - "integrity": "sha512-qHE7pASEWbRORU+NEPSSL9fyVh6gBNqC1ugV94YL9Dz0HnLcH8YNcxdi6Pf+oXgFHRrXWZiJATn37HynsF7/0g==", + "version": "9.15.0", + "resolved": "https://registry.npmjs.org/babylonjs-gltf2interface/-/babylonjs-gltf2interface-9.15.0.tgz", + "integrity": "sha512-Yr/WvOvnsZFN2LoyNU/ZZbT+lXMdNA9OiZzE4RibI1tnYxQjpPKT6X1cxQ/ACJPVzKwudxzJxQ/f/Tdba4TLDg==", "license": "Apache-2.0" }, "node_modules/babylonjs-gui": { - "version": "9.9.1", - "resolved": "https://registry.npmjs.org/babylonjs-gui/-/babylonjs-gui-9.9.1.tgz", - "integrity": "sha512-w6HSvuHSqLYUOuxvko+gkjAQMvatf7gnOPufLRslm+P4tC+5KMEd0hyC+1vHCJuQmZXXkoc/GnozzFeaqllHZw==", + "version": "9.15.0", + "resolved": "https://registry.npmjs.org/babylonjs-gui/-/babylonjs-gui-9.15.0.tgz", + "integrity": "sha512-klF2ywhA040JMQ3Z5XaGkN4S0GIOshtnvtUd8kbYqlLYEu5i6/y/zvB8V3O4geslzV0kWcBe2mIthlr7M7p4og==", "license": "Apache-2.0", "dependencies": { - "babylonjs": "9.9.1" + "babylonjs": "9.15.0" } }, "node_modules/babylonjs-loaders": { - "version": "9.9.1", - "resolved": "https://registry.npmjs.org/babylonjs-loaders/-/babylonjs-loaders-9.9.1.tgz", - "integrity": "sha512-bFSe4TQTi7aA7RsWmuZHQLX4mBMoza5D+AFRD2tVrizGyGCfQJALKnKze7Z3OetFyeo72838GXJAXmyiOWcxAA==", + "version": "9.15.0", + "resolved": "https://registry.npmjs.org/babylonjs-loaders/-/babylonjs-loaders-9.15.0.tgz", + "integrity": "sha512-k5Kg9wmuy0n4ZAWu9woFk3C1yEwSvQHRv0Ct2GOQtuRvIHUIyRcW4KEKOsW0GOiApSjXh9nQcabdJTnUo8IBNw==", "license": "Apache-2.0", "dependencies": { - "babylonjs": "9.9.1", - "babylonjs-gltf2interface": "9.9.1" + "babylonjs": "9.15.0", + "babylonjs-gltf2interface": "9.15.0" } }, "node_modules/babylonjs-materials": { - "version": "9.9.1", - "resolved": "https://registry.npmjs.org/babylonjs-materials/-/babylonjs-materials-9.9.1.tgz", - "integrity": "sha512-2ai5hk59dzHRUN28/5/Nijknn+IungSuoBsrHrNZE2T/yIT+/T/IrU0ebm53nRYliv6NG0IaxSCfnh6euZUj7A==", + "version": "9.15.0", + "resolved": "https://registry.npmjs.org/babylonjs-materials/-/babylonjs-materials-9.15.0.tgz", + "integrity": "sha512-E9C5EB0nZJrGvT7Mb38gypAnzi1q8vr/Gi+fTeqRQilIU8mdk+YzD5unfKOROEv8arRFCXGWrtBqkIN8k2PFxA==", "license": "Apache-2.0", "dependencies": { - "babylonjs": "9.9.1" + "babylonjs": "9.15.0" } }, "node_modules/babylonjs-serializers": { - "version": "9.9.1", - "resolved": "https://registry.npmjs.org/babylonjs-serializers/-/babylonjs-serializers-9.9.1.tgz", - "integrity": "sha512-nZJPplzHprwJhp4JVLgB3dEpJR2HvEElPIDvOoAFf1IcaKwcDja2tZTGXIbARdWlTX547pN0qN/vEd6dYLrnDA==", + "version": "9.15.0", + "resolved": "https://registry.npmjs.org/babylonjs-serializers/-/babylonjs-serializers-9.15.0.tgz", + "integrity": "sha512-iLYwPzZrUr2SnwHcsXjHJHYdJIVC+boW6z/olE0mE5GvqmfKXTtqFr9wRGrsq85BarhHQkfVlfQdFwhFq/JG4w==", "license": "Apache-2.0", "dependencies": { - "babylonjs": "9.9.1", - "babylonjs-gltf2interface": "9.9.1" + "babylonjs": "9.15.0", + "babylonjs-gltf2interface": "9.15.0" } }, "node_modules/balanced-match": { diff --git a/Apps/package.json b/Apps/package.json index f6a7e31e7..632285ede 100644 --- a/Apps/package.json +++ b/Apps/package.json @@ -9,13 +9,13 @@ "getNightly": "node scripts/getNightly.js" }, "dependencies": { - "babylonjs": "^9.3.4", - "babylonjs-addons": "^9.3.4", - "babylonjs-gltf2interface": "^9.3.4", - "babylonjs-gui": "^9.3.4", - "babylonjs-loaders": "^9.3.4", - "babylonjs-materials": "^9.3.4", - "babylonjs-serializers": "^9.3.4", + "babylonjs": "^9.15.0", + "babylonjs-addons": "^9.15.0", + "babylonjs-gltf2interface": "^9.15.0", + "babylonjs-gui": "^9.15.0", + "babylonjs-loaders": "^9.15.0", + "babylonjs-materials": "^9.15.0", + "babylonjs-serializers": "^9.15.0", "jsc-android": "^241213.1.0", "v8-android": "^7.8.2" } diff --git a/Plugins/NativeEngine/Source/NativeEngine.cpp b/Plugins/NativeEngine/Source/NativeEngine.cpp index 864031710..8fa756893 100644 --- a/Plugins/NativeEngine/Source/NativeEngine.cpp +++ b/Plugins/NativeEngine/Source/NativeEngine.cpp @@ -1484,8 +1484,21 @@ namespace Babylon const auto height{static_cast(rawHeight)}; const auto depth{static_cast(rawDepth)}; - uint64_t flags{BGFX_TEXTURE_NONE | BGFX_SAMPLER_NONE | BGFX_CAPS_TEXTURE_2D_ARRAY}; - texture->Create2D(width, height, generateMips, depth, Cast(format), flags); + // bgfx only allocates a true array texture (GL_TEXTURE_2D_ARRAY / + // D3D11 Texture2DArray) when numLayers > 1; a single-layer request + // collapses to a plain 2D texture (GL_TEXTURE_2D). The cross-compiled + // shaders always sample this resource as a 2D-array sampler + // (e.g. `sampler2DArray morphTargets`), so on OpenGL the single-layer + // 2D texture cannot bind to the array sampler and reads as zero -- + // which, for texture-based morph targets with a single target, + // collapses all vertices to the origin and makes the mesh disappear. + // WebGL2 creates a real depth-1 TEXTURE_2D_ARRAY, so match that by + // allocating at least two layers; only the requested `depth` layers + // are ever uploaded or sampled (the shader indexes an explicit layer). + const uint16_t allocLayers{depth > 1 ? depth : static_cast(2)}; + + uint64_t flags{BGFX_TEXTURE_NONE | BGFX_SAMPLER_NONE}; + texture->Create2D(width, height, generateMips, allocLayers, Cast(format), flags); if (!data.IsNull()) { diff --git a/Plugins/ShaderCompiler/Source/ShaderCompilerCommon.cpp b/Plugins/ShaderCompiler/Source/ShaderCompilerCommon.cpp index b47e6e3df..a805ec283 100644 --- a/Plugins/ShaderCompiler/Source/ShaderCompilerCommon.cpp +++ b/Plugins/ShaderCompiler/Source/ShaderCompilerCommon.cpp @@ -98,8 +98,19 @@ namespace Babylon::ShaderCompilerCommon #if OPENGL BX_UNUSED(compiler); - const auto stage{static_cast(stages.size())}; - stages[sampler.name] = stage; + // A program's vertex and fragment shaders share this stages map, and Babylon's + // generated GLSL frequently declares the same sampler in both stages. Assign a stage + // (texture unit) the first time a sampler name is seen and reuse it thereafter; without + // the guard the second pass would re-run stages[name] = stages.size() on already-present + // names, which doesn't grow the map, collapsing every such sampler onto the same unit. + // 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()) + { + stages[sampler.name] = static_cast(stages.size()); + } #else stages[sampler.name] = static_cast(compiler.get_decoration(sampler.id, spv::DecorationBinding)); #endif