Skip to content

[Native] Combined native-engine GL fixes (depth, cube load, cube RTT, updateTextureData)#18567

Draft
bkaradzic-microsoft wants to merge 6 commits into
masterfrom
native-combined-gl-fixes
Draft

[Native] Combined native-engine GL fixes (depth, cube load, cube RTT, updateTextureData)#18567
bkaradzic-microsoft wants to merge 6 commits into
masterfrom
native-combined-gl-fixes

Conversation

@bkaradzic-microsoft

@bkaradzic-microsoft bkaradzic-microsoft commented Jun 11, 2026

Copy link
Copy Markdown
Member

Paired native PR: BabylonJS/BabylonNative#1752

What

Integration branch combining the four native-engine fixes below (each also exists as its own focused
PR — those remain the review units). Opened so combined CI / testing can validate the cumulative
effect and the full set of BabylonNative validation tests they re-enable.

Fix Babylon.js PR BabylonNative PR
Honor depthCullingState.depthTest on the native engine #18558 BabylonJS/BabylonNative#1747
Load single-file .dds/.ktx/.ktx2 cubemaps #18560 BabylonJS/BabylonNative#1748
Cube render target support #18561 BabylonJS/BabylonNative#1750
Report engine.name = "Native" + implement updateTextureData #18566 BabylonJS/BabylonNative#1751

Validation tests re-enabled (10)

Built babylon.max.js from this branch and ran the BabylonNative Playground validation suite
(Win32 / D3D11). All 10 previously-excluded tests now pass pixel comparison:

Honor depthCullingState.depthTest (#18558)

  • [392] blur-cube-with-the-effect-renderer

Single-file .dds/.ktx/.ktx2 cubemap loading (#18560)

  • [141] NMEGLTF
  • [172] Anisotropic
  • [173] Clear Coat
  • [246] PBRMetallicRoughnessMaterial
  • [247] PBRSpecularGlossinessMaterial
  • [248] PBR

Cube render targets (#18561)

  • [284] Shadows with instances in left handed system
  • [285] Shadows with instances in right handed system

updateTextureData + engine.name = "Native" (#18566)

  • [336] Test updateTextureData

Note

Draft integration branch — the four individual PRs are the units to review/merge.


Related PRs & landing order

Integration branches — combined CI/validation only; the four constituent paired PRs are the review/merge units:

Each constituent pair lands in the order Babylon.js PR → babylonjs npm release → BabylonNative PR (the native validation tests only go green once the paired JS is in the bundled engine):

Fix Babylon.js (lands first) BabylonNative (lands last)
Honor depthCullingState.depthTest #18558 test re-enable folded into BabylonJS/BabylonNative#1748
Single-file .dds/.ktx/.ktx2 cubemaps #18560 BabylonJS/BabylonNative#1748
Cube render targets #18561 BabylonJS/BabylonNative#1750
updateTextureData + engine.name "Native" #18566 BabylonJS/BabylonNative#1751

The integration branches themselves merge (if at all) only after their constituent pairs.

@bjsplat

bjsplat commented Jun 11, 2026

Copy link
Copy Markdown
Collaborator

Please make sure to label your PR with "bug", "new feature" or "breaking change" label(s).
To prevent this PR from going to the changelog marked it with the "skip changelog" label.

@bjsplat

bjsplat commented Jun 11, 2026

Copy link
Copy Markdown
Collaborator

Snapshot stored with reference name:
refs/pull/18567/merge

Test environment:
https://snapshots-cvgtc2eugrd3cgfd.z01.azurefd.net/refs/pull/18567/merge/index.html

To test a playground add it to the URL, for example:

https://snapshots-cvgtc2eugrd3cgfd.z01.azurefd.net/refs/pull/18567/merge/index.html#WGZLGJ#4600

Links to test your changes to core in the published versions of the Babylon tools (does not contain changes you made to the tools themselves):

https://playground.babylonjs.com/?snapshot=refs/pull/18567/merge
https://sandbox.babylonjs.com/?snapshot=refs/pull/18567/merge
https://gui.babylonjs.com/?snapshot=refs/pull/18567/merge
https://nme.babylonjs.com/?snapshot=refs/pull/18567/merge

To test the snapshot in the playground with a playground ID add it after the snapshot query string:

https://playground.babylonjs.com/?snapshot=refs/pull/18567/merge#BCU1XR#0

If you made changes to the sandbox or playground in this PR, additional comments will be generated soon containing links to the dev versions of those tools.

@bjsplat

bjsplat commented Jun 11, 2026

Copy link
Copy Markdown
Collaborator

@bjsplat

bjsplat commented Jun 11, 2026

Copy link
Copy Markdown
Collaborator

@bjsplat

bjsplat commented Jun 11, 2026

Copy link
Copy Markdown
Collaborator

🟢 Memory Leak Test Results

13 passed, 0 leaked out of 13 scenarios

🟢 All memory leak tests passed — no leaks detected.

Passed Scenarios (13)
Scenario Package
Core Feature Stack @babylonjs/core
Core Rendering Materials Shadows Stack @babylonjs/core
Core Textures Render Targets PostProcess Stack @babylonjs/core
GUI Fullscreen UI Controls @babylonjs/gui
GUI Mesh ADT Controls @babylonjs/gui
Loaders Boombox Import @babylonjs/loaders
Loaders OBJ Direct Load @babylonjs/loaders
Loaders STL Direct Load @babylonjs/loaders
Materials Library Stack @babylonjs/materials
Serializers glTF Export @babylonjs/serializers
Serializers GLB Export @babylonjs/serializers
PostProcesses Digital Rain Stack @babylonjs/post-processes
Procedural Textures Stack @babylonjs/procedural-textures

@bjsplat

bjsplat commented Jun 11, 2026

Copy link
Copy Markdown
Collaborator

@bjsplat

bjsplat commented Jun 11, 2026

Copy link
Copy Markdown
Collaborator

⚡ Performance Test Results

🟢 All performance tests passed — no regressions detected.

bkaradzic and others added 6 commits June 16, 2026 10:04
EffectRenderer (and ThinDepthPeelingRenderer) disable depth testing by setting
engine.depthCullingState.depthTest directly. On WebGL/WebGPU this is flushed by
applyStates() at draw time, but the native engine only honored depth state set
through the explicit setDepthBuffer() command and never flushed depthCullingState
before a draw, so the toggle was silently dropped. A fullscreen EffectWrapper pass
then kept the previous draw's depth test and every fragment was discarded, producing
an all-black target.

Reconcile depthCullingState.depthTest before each native draw to match the
cross-engine contract: setDepthBuffer() keeps the state object authoritative and
_flushDepthTestState() emits the command when the direct toggle differs from what was
last encoded. No public API change.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The native createCubeTexture override only handled a single .env file or six
face files; a single self-contained cubemap container (.dds/.ktx/.ktx2, as
produced by CubeTexture.CreateFromPrefilteredData) threw "Cannot load cubemap
because 6 files were not defined". The generic WebGL loader route is unusable on
native (its texture-upload and cube-readback entry points are unimplemented).

Route a single-URL container cubemap to engine.loadCubeTexture with the raw
buffer; the native engine decodes it (bimg) and, when polynomials are requested,
returns spherical-harmonics coefficients computed from the top mip, which are set
as the texture's spherical polynomial. loadCubeTexture's onSuccess now optionally
carries those coefficients. The .env and six-file paths are unchanged.

Pairs with a Babylon Native NativeEngine change implementing the single-buffer
cube decode and spherical-harmonics computation.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…d onSuccess

The six-file path passed the Promise resolve directly, which is not assignable to
the widened onSuccess signature (sphericalPolynomial?: Float32Array). Wrap with
() => resolve() / () => reject(new Error(...)).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
NativeEngine had no createRenderTargetCubeTexture / per-face bindFramebuffer
override, so ReflectionProbe and point-light cube shadows fell through to the
WebGL path and dereferenced the null _gl context (TEXTURE_CUBE_MAP undefined).

- createRenderTargetCubeTexture: native cube color texture + one framebuffer
  per face (the native side binds the matching cube layer).
- bindFramebuffer: bind the per-face framebuffer for cube render targets.
- generateMipMapsForCubemap: no-op on Native (bgfx auto-generates the mip
  chain on render-target resolve, like 2D RTTs).
- NativeRenderTargetWrapper: track per-face framebuffers, release on dispose.
- nativeInterfaces: thread cube/layer params through initializeTexture and
  createFrameBuffer.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The native engine inherited engine.name === "WebGL" from ThinEngine, so code
that guards WebGL-only _gl access with �ngine.name === "WebGL" ran on the
native engine and dereferenced the null _gl context (e.g. TEXTURE_2D undefined).
updateTextureData also threw "not implemented".

- Report a distinct engine name ("Native"), mirroring how the WebGPU engine
  reports "WebGPU", so name-gated WebGL-only code paths skip the native engine.
- Implement updateTextureData: forward the sub-rectangle (plus invertY, so the
  native side can match the base texture's vertical orientation) to the native
  engine. generateMipMaps is ignored (mip regeneration after a partial update is
  not supported on Native).

Pairs with the BabylonNative change adding NativeEngine::UpdateTextureData.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@bkaradzic-microsoft bkaradzic-microsoft force-pushed the native-combined-gl-fixes branch from 73c6f7b to bbac444 Compare June 16, 2026 17:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants