From 9f8381ff71253fdba018e0bc2e88555fdfefe35c Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Tue, 3 Nov 2026 22:56:24 +0400 Subject: [PATCH] Check a parked renderer's real WebGL context before reuse and rebuild it when the context is lost --- src/standalone/rendererCache.js | 7 ++++++- src/standalone/rendererCache.test.mjs | 11 +++++++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/standalone/rendererCache.js b/src/standalone/rendererCache.js index 49db694df..9347ab7a3 100644 --- a/src/standalone/rendererCache.js +++ b/src/standalone/rendererCache.js @@ -8,7 +8,12 @@ export function createRendererCache() { const host = document.getElementById('cesiumContainer'); let entry = idle.get(kind); idle.delete(kind); - if (entry?.lost) { + // loseContext() takes effect before its queued DOM event is delivered. + // Check the existing context too, before resuming a parked render loop. + const canvas = entry?.scene.engine.host.canvas; + const context = + canvas?.getContext?.('webgl2') ?? canvas?.getContext?.('webgl'); + if (entry && (entry.lost || context?.isContextLost())) { entry.dispose(); entry = null; } diff --git a/src/standalone/rendererCache.test.mjs b/src/standalone/rendererCache.test.mjs index aca7cc207..4b4b2cddc 100644 --- a/src/standalone/rendererCache.test.mjs +++ b/src/standalone/rendererCache.test.mjs @@ -54,7 +54,8 @@ test('a parked renderer is reused, but a lost context is disposed before rebuild assert.equal(first.engine.host.container.isConnected, true); cache.retain('navara'); release(); - first.engine.host.canvas.dispatchEvent(new Event('webglcontextlost')); + // The WebGL context is already lost, but its DOM event has not fired. + first.engine.host.canvas.getContext = () => ({ isContextLost: () => true }); const second = await open(); assert.notEqual(second, first); assert.equal(released, 1); @@ -66,7 +67,13 @@ test('a parked renderer is reused, but a lost context is disposed before rebuild await assert.rejects(open(), /resume failed/); assert.equal(second.engine.host.container.isConnected, false); assert.equal(released, 2); + const eventLost = await open(); + cache.retain('navara'); + release(); + eventLost.engine.host.canvas.dispatchEvent(new Event('webglcontextlost')); const third = await open(); + assert.notEqual(third, eventLost); + assert.equal(released, 3); third.suspend = () => { throw new Error('suspend failed'); }; @@ -74,5 +81,5 @@ test('a parked renderer is reused, but a lost context is disposed before rebuild assert.throws(release, /suspend failed/); assert.equal(third.engine.host.container.isConnected, false); cache.clear(); - assert.equal(released, 3); + assert.equal(released, 4); });