BabylonJS/Babylon.js · error

updateWrappedNativeTexture: wrapped texture is part of a mul

Error message

updateWrappedNativeTexture: wrapped texture is part of a multi render-target; not supported. Dispose and re-wrap.

What it means

updateWrappedNativeTexture scans the render-target wrapper cache; if the wrapped texture belongs to a multi render-target (MRT) wrapper, updating the underlying handle is unsupported and throws, because MRT framebuffers cannot be safely rebuilt around the swap in this version.

Source

Thrown at packages/dev/core/src/Engines/thinNativeEngine.pure.ts:2184

            );
        }
        if (this._engine.getTextureLayerCount) {
            const newLayerCount = this._engine.getTextureLayerCount(texture);
            const oldLayerCount = internalTexture.is2DArray ? internalTexture.depth : 1;
            if (newLayerCount !== oldLayerCount) {
                throw new Error(`updateWrappedNativeTexture: new handle layer count (${newLayerCount}) must match the wrapped texture's layer count (${oldLayerCount}).`);
            }
        }

        // Pre-validate before mutating any state so a thrown precondition leaves the InternalTexture untouched.
        // Note: rtWrapper.texture only returns _textures[0]; walk every attachment to catch the multi-RT case where
        // the wrapped texture is at index > 0.
        for (const rtWrapper of this._renderTargetWrapperCache) {
            if (!rtWrapper.textures?.includes(internalTexture)) {
                continue;
            }
            if (rtWrapper.isMulti) {
                throw new Error("updateWrappedNativeTexture: wrapped texture is part of a multi render-target; not supported. Dispose and re-wrap.");
            }
            if (rtWrapper._depthStencilTexture) {
                // After a DisableRendering / EnableRendering cycle the bgfx framebuffer + the depth/stencil texture's
                // bgfx handle are both stale. Rebuilding the depth/stencil texture from the wrapper's stored settings
                // is feasible but non-trivial; v1 rejects and asks the caller to dispose + re-wrap.
                throw new Error("updateWrappedNativeTexture: wrapped texture's render-target wrapper has a depth/stencil texture; not supported. Dispose and re-wrap.");
            }
        }

        internalTexture._hardwareTexture = new NativeHardwareTexture(texture, this._engine);
        internalTexture.isReady = true;
        this.updateTextureSamplingMode(internalTexture.samplingMode, internalTexture);

        // Rebuild the framebuffer of any render-target wrapper holding this wrapped texture as its color attachment.
        // After a DisableRendering / EnableRendering cycle the bgfx framebuffer handle is stale; the consumer-supplied
        // new texture is the moment we have a fresh handle to rebuild against.
        for (const rtWrapper of this._renderTargetWrapperCache) {
            if (rtWrapper.texture !== internalTexture) {

View on GitHub (pinned to 0592b347b8)

Solutions

  1. Dispose the MRT wrapper and its textures, then recreate the render target wrapping the new native textures.
  2. Keep hot-swappable textures in single-attachment render targets instead of MRT.
  3. Restructure the pass so the swapped texture is not part of the MRT set.

Example fix

// before
engine.updateWrappedNativeTexture(gbuffer.tex[1], newTex); // MRT attachment

// after
mrtWrapper.dispose();
gbuffer = recreateMRT(scene, { texture1: newTex });
Defensive patterns

Strategy: validation

Validate before calling

const inMrt = engine._renderTargetWrapperCache.some(rt => rt.isMulti && rt.textures?.includes(wrapped));
if (inMrt) throw new Error("Texture is an MRT attachment; dispose and recreate the render target instead of updating.");

Try / catch

try {
  engine.updateWrappedNativeTexture(wrapped, newNativeTex);
} catch (e) {
  if (e.message.includes("multi render-target")) {
    recreateRenderTargetWithNewTexture(wrapped, newNativeTex);
  } else throw e;
}

Prevention

When it happens

Trigger: Calling engine.updateWrappedNativeTexture on a texture that appears in rtWrapper.textures of a wrapper with isMulti == true (a texture bound in a multi render-target pass).

Common situations: Deferred-rendering pipelines that swap G-buffer textures created as MRT attachments (position at index > 0); attempting hot-swap of MRT color attachments.

Related errors


AI-assisted analysis of BabylonJS/Babylon.js@0592b347b8 (2026-08-30). Data as JSON: /api/errors/e0d8a6d463426500. Report an issue: GitHub.