BabylonJS/Babylon.js · error

Unable to create multi sampled framebuffer

Error message

Unable to create multi sampled framebuffer

What it means

When creating a multi-render-target with dontCreateTextures=true and samples>1, the engine asks WebGL for a new framebuffer via gl.createFramebuffer(). WebGL returns null when it cannot allocate the framebuffer (out of GPU memory/context loss/exhausted resources), and BabylonJS throws this error instead of silently returning a broken render target.

Source

Thrown at packages/dev/core/src/Engines/Extensions/engine.multiRender.pure.ts:358

        }
        rtWrapper.setTextures(textures);
        if (initializeBuffers) {
            gl.drawBuffers(attachments);
        }

        this._bindUnboundFramebuffer(currentFramebuffer);

        rtWrapper.setLayerAndFaceIndices(layerIndex, faceIndex);

        this.resetTextureCache();

        if (!dontCreateTextures) {
            this.updateMultipleRenderTargetTextureSampleCount(rtWrapper, samples, initializeBuffers);
        } else if (samples > 1) {
            const framebuffer = gl.createFramebuffer();

            if (!framebuffer) {
                throw new Error("Unable to create multi sampled framebuffer");
            }

            rtWrapper._samples = samples;
            rtWrapper._MSAAFramebuffer = framebuffer;

            if (textureCount > 0 && initializeBuffers) {
                this._bindUnboundFramebuffer(framebuffer);
                gl.drawBuffers(attachments);
                this._bindUnboundFramebuffer(currentFramebuffer);
            }
        }

        return rtWrapper;
    };

    ThinEngine.prototype.updateMultipleRenderTargetTextureSampleCount = function (
        rtWrapper: Nullable<WebGLRenderTargetWrapper>,
        samples: number,

View on GitHub (pinned to 0592b347b8)

Solutions

  1. Check for WebGL context loss first (gl.isContextLost(), engine.onContextLostObservable) and re-create the engine.
  2. Reduce render target size, sample count, or number of simultaneous render targets to free GPU resources.
  3. Dispose unused render targets/textures (rtWrapper.dispose(), engine.disposeUnusedTextures) before creating the new MRT.
  4. Wrap MRT creation in try/catch and retry with samples=1 after cleanup.
  5. Listen to engine.onContextLost/Restored and reinitialize resources on restore.

Example fix

// before
const rt = engine.createMultipleRenderTarget(size, { dontCreateTextures: true, samples: 4 });
// after
if (engine._gl.isContextLost()) {
    await recreateEngine();
}
let rt;
try {
    rt = engine.createMultipleRenderTarget(size, { dontCreateTextures: true, samples: 4 });
} catch (e) {
    rt = engine.createMultipleRenderTarget(size, { dontCreateTextures: true, samples: 1 });
}
Defensive patterns

Strategy: try-catch

Validate before calling

const gl = (engine as any)._gl;
if (gl.isContextLost()) {
    throw new Error('WebGL context lost; recreate engine before creating MRT');
}

Type guard

function canAllocateGl(e: AbstractEngine): boolean {
    const gl = (e as any)._gl as WebGL2RenderingContext | undefined;
    return !!gl && !gl.isContextLost();
}

Try / catch

try {
    rt = engine.createMultipleRenderTarget(size, { dontCreateTextures: true, samples: 4 });
} catch (e) {
    if (e instanceof Error && e.message.includes('Unable to create multi sampled framebuffer')) {
        rt = engine.createMultipleRenderTarget(size, { dontCreateTextures: true, samples: 1 });
    } else { throw e; }
}

Prevention

When it happens

Trigger: engine.createMultipleRenderTarget(size, { dontCreateTextures: true, samples: >1 }) on a WebGL engine where gl.createFramebuffer() returns null — typically resource exhaustion or a lost/invalid GL context.

Common situations: Very large MRT sizes combined with many existing render targets exhausting framebuffer/memory limits; WebGL context lost (GPU reset, tab backgrounding) so all gl.create* calls return null; embedded/mobile GPUs with tight memory; calling before the context is fully valid in custom engine setups.

Related errors


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