Skip to content

Commit fec14d1

Browse files
mvaligurskyMartin Valigursky
andauthored
Cache validated FBO configurations in debug builds (#8491)
* perf: Cache validated FBO configurations to avoid repeated checkFramebufferStatus calls In debug builds, gl.checkFramebufferStatus causes an expensive GPU sync (~16ms per call). This caches validated framebuffer format configurations per device using DeviceCache, so the check only runs once per unique combination of color formats, depth/stencil config, and sample count. Subsequent render targets with the same configuration skip the check. This is a debug-mode-only optimization - checkFramebufferStatus is already stripped from production builds via Debug.call. Made-with: Cursor * update --------- Co-authored-by: Martin Valigursky <mvaligursky@snapchat.com>
1 parent 8dc91b2 commit fec14d1

File tree

1 file changed

+25
-0
lines changed

1 file changed

+25
-0
lines changed

src/platform/graphics/webgl/webgl-render-target.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
import { Debug } from '../../../core/debug.js';
22
import { PIXELFORMAT_RGBA8 } from '../constants.js';
33
import { DebugGraphics } from '../debug-graphics.js';
4+
import { DeviceCache } from '../device-cache.js';
45
import { getMultisampledTextureCache } from '../multi-sampled-texture-cache.js';
56

67
/**
78
* @import { RenderTarget } from '../render-target.js'
89
* @import { WebglGraphicsDevice } from './webgl-graphics-device.js'
910
*/
1011

12+
const _validatedFboConfigs = new DeviceCache();
13+
1114
/**
1215
* A private class representing a pair of framebuffers, when MSAA is used.
1316
*
@@ -372,6 +375,24 @@ class WebglRenderTarget {
372375
* @private
373376
*/
374377
_checkFbo(device, target, type = '') {
378+
379+
// Build a key from attachment formats, depth/stencil config, samples, and FBO type.
380+
// Dimensions are excluded as they don't affect framebuffer completeness.
381+
const colorFormats = target._colorBuffers?.map(b => b?.format ?? -1).join(',') ?? '';
382+
const depthInfo = target._depth ? (target._depthBuffer ? `dt${target._depthBuffer.format}` : (target._stencil ? 'ds' : 'd')) : '';
383+
const key = `${type}:${colorFormats}:${depthInfo}:${target._samples}`;
384+
385+
// clear validated configs on context loss to re-validate after restore
386+
const validated = _validatedFboConfigs.get(device, () => {
387+
const set = new Set();
388+
set.loseContext = () => set.clear();
389+
return set;
390+
});
391+
392+
if (validated.has(key)) {
393+
return;
394+
}
395+
375396
const gl = device.gl;
376397
const status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
377398
let errorCode;
@@ -390,6 +411,10 @@ class WebglRenderTarget {
390411
break;
391412
}
392413

414+
if (status === gl.FRAMEBUFFER_COMPLETE) {
415+
validated.add(key);
416+
}
417+
393418
Debug.assert(!errorCode, `Framebuffer creation failed with error code ${errorCode}, render target: ${target.name} ${type}`, target);
394419
}
395420

0 commit comments

Comments
 (0)