diff --git a/src/platform/graphics/webgl/webgl-render-target.js b/src/platform/graphics/webgl/webgl-render-target.js index 75917516bb4..d8c3e20793e 100644 --- a/src/platform/graphics/webgl/webgl-render-target.js +++ b/src/platform/graphics/webgl/webgl-render-target.js @@ -1,6 +1,7 @@ import { Debug } from '../../../core/debug.js'; import { PIXELFORMAT_RGBA8 } from '../constants.js'; import { DebugGraphics } from '../debug-graphics.js'; +import { DeviceCache } from '../device-cache.js'; import { getMultisampledTextureCache } from '../multi-sampled-texture-cache.js'; /** @@ -8,6 +9,8 @@ import { getMultisampledTextureCache } from '../multi-sampled-texture-cache.js'; * @import { WebglGraphicsDevice } from './webgl-graphics-device.js' */ +const _validatedFboConfigs = new DeviceCache(); + /** * A private class representing a pair of framebuffers, when MSAA is used. * @@ -372,6 +375,24 @@ class WebglRenderTarget { * @private */ _checkFbo(device, target, type = '') { + + // Build a key from attachment formats, depth/stencil config, samples, and FBO type. + // Dimensions are excluded as they don't affect framebuffer completeness. + const colorFormats = target._colorBuffers?.map(b => b?.format ?? -1).join(',') ?? ''; + const depthInfo = target._depth ? (target._depthBuffer ? `dt${target._depthBuffer.format}` : (target._stencil ? 'ds' : 'd')) : ''; + const key = `${type}:${colorFormats}:${depthInfo}:${target._samples}`; + + // clear validated configs on context loss to re-validate after restore + const validated = _validatedFboConfigs.get(device, () => { + const set = new Set(); + set.loseContext = () => set.clear(); + return set; + }); + + if (validated.has(key)) { + return; + } + const gl = device.gl; const status = gl.checkFramebufferStatus(gl.FRAMEBUFFER); let errorCode; @@ -390,6 +411,10 @@ class WebglRenderTarget { break; } + if (status === gl.FRAMEBUFFER_COMPLETE) { + validated.add(key); + } + Debug.assert(!errorCode, `Framebuffer creation failed with error code ${errorCode}, render target: ${target.name} ${type}`, target); }