{"record":{"id":"a199137bdb16667e","repo":"BabylonJS/Babylon.js","slug":"unable-to-create-multi-sampled-framebuffer","errorCode":null,"errorMessage":"Unable to create multi sampled framebuffer","messagePattern":"Unable to create multi sampled framebuffer","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/dev/core/src/Engines/Extensions/engine.multiRender.pure.ts","lineNumber":358,"sourceCode":"        }\r\n        rtWrapper.setTextures(textures);\r\n        if (initializeBuffers) {\r\n            gl.drawBuffers(attachments);\r\n        }\r\n\r\n        this._bindUnboundFramebuffer(currentFramebuffer);\r\n\r\n        rtWrapper.setLayerAndFaceIndices(layerIndex, faceIndex);\r\n\r\n        this.resetTextureCache();\r\n\r\n        if (!dontCreateTextures) {\r\n            this.updateMultipleRenderTargetTextureSampleCount(rtWrapper, samples, initializeBuffers);\r\n        } else if (samples > 1) {\r\n            const framebuffer = gl.createFramebuffer();\r\n\r\n            if (!framebuffer) {\r\n                throw new Error(\"Unable to create multi sampled framebuffer\");\r\n            }\r\n\r\n            rtWrapper._samples = samples;\r\n            rtWrapper._MSAAFramebuffer = framebuffer;\r\n\r\n            if (textureCount > 0 && initializeBuffers) {\r\n                this._bindUnboundFramebuffer(framebuffer);\r\n                gl.drawBuffers(attachments);\r\n                this._bindUnboundFramebuffer(currentFramebuffer);\r\n            }\r\n        }\r\n\r\n        return rtWrapper;\r\n    };\r\n\r\n    ThinEngine.prototype.updateMultipleRenderTargetTextureSampleCount = function (\r\n        rtWrapper: Nullable<WebGLRenderTargetWrapper>,\r\n        samples: number,\r","sourceCodeStart":340,"sourceCodeEnd":376,"githubUrl":"https://github.com/BabylonJS/Babylon.js/blob/0592b347b8a4ee0236089ea86a749cacfdb266d8/packages/dev/core/src/Engines/Extensions/engine.multiRender.pure.ts#L340-L376","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Check for WebGL context loss first (gl.isContextLost(), engine.onContextLostObservable) and re-create the engine.","Reduce render target size, sample count, or number of simultaneous render targets to free GPU resources.","Dispose unused render targets/textures (rtWrapper.dispose(), engine.disposeUnusedTextures) before creating the new MRT.","Wrap MRT creation in try/catch and retry with samples=1 after cleanup.","Listen to engine.onContextLost/Restored and reinitialize resources on restore."],"exampleFix":"// before\nconst rt = engine.createMultipleRenderTarget(size, { dontCreateTextures: true, samples: 4 });\n// after\nif (engine._gl.isContextLost()) {\n    await recreateEngine();\n}\nlet rt;\ntry {\n    rt = engine.createMultipleRenderTarget(size, { dontCreateTextures: true, samples: 4 });\n} catch (e) {\n    rt = engine.createMultipleRenderTarget(size, { dontCreateTextures: true, samples: 1 });\n}","handlingStrategy":"try-catch","validationCode":"const gl = (engine as any)._gl;\nif (gl.isContextLost()) {\n    throw new Error('WebGL context lost; recreate engine before creating MRT');\n}","typeGuard":"function canAllocateGl(e: AbstractEngine): boolean {\n    const gl = (e as any)._gl as WebGL2RenderingContext | undefined;\n    return !!gl && !gl.isContextLost();\n}","tryCatchPattern":"try {\n    rt = engine.createMultipleRenderTarget(size, { dontCreateTextures: true, samples: 4 });\n} catch (e) {\n    if (e instanceof Error && e.message.includes('Unable to create multi sampled framebuffer')) {\n        rt = engine.createMultipleRenderTarget(size, { dontCreateTextures: true, samples: 1 });\n    } else { throw e; }\n}","preventionTips":["Track GPU memory pressure: dispose old render targets before creating new ones","Listen to engine.onContextLostObservable and reinitialize resources on restore","Cap samples via engine.getCaps().maxMSAASamples and avoid oversized MRTs","Wrap framebuffer allocation in try/catch with a samples=1 retry","Monitor for null returns from other gl.create* calls as an early context-loss signal"],"tags":["webgl","framebuffer","msaa","gpu-memory","context-loss"],"backgroundTag":"framebuffer-allocation-failed","analyzedSha":"0592b347b8a4ee0236089ea86a749cacfdb266d8","analyzedAt":"2026-08-30T15:11:20.442Z","schemaVersion":2},"datasetVersion":"2026-08-30T18:17:15.746Z"}