From 9ba5a3aba94354c152937d0f86999d5589ce7416 Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Thu, 29 Oct 2026 19:26:47 +0400 Subject: [PATCH] fix(navara): invalidate cached glyphs after context loss Clear the display-resource signature used by static sprite reuse when the WebGL context is lost or restored. Cover both events and verify that caching resumes after the redraw. --- src/globe/navara/overlayPass.js | 6 ++++-- src/globe/navara/overlayPass.test.mjs | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/globe/navara/overlayPass.js b/src/globe/navara/overlayPass.js index e3a4dd26d..d6be5dc6a 100644 --- a/src/globe/navara/overlayPass.js +++ b/src/globe/navara/overlayPass.js @@ -48,12 +48,14 @@ void main(){vec4 bg=texture2D(image,vUv);vec4 glyph=texture2D(glyphs,vUv);if(gly }); const quad = new FullScreenQuad(composite); const canvas = renderer.domElement; + const display = { target, composite, quad, canvas, signature: null }; const invalidate = () => { - target.signature = null; + display.signature = null; }; canvas?.addEventListener('webglcontextlost', invalidate); canvas?.addEventListener('webglcontextrestored', invalidate); - return { target, composite, quad, canvas, invalidate }; + display.invalidate = invalidate; + return display; } function staticSpriteSignature(scene, camera, renderer, width, height) { diff --git a/src/globe/navara/overlayPass.test.mjs b/src/globe/navara/overlayPass.test.mjs index 93d31c5fe..b5119f581 100644 --- a/src/globe/navara/overlayPass.test.mjs +++ b/src/globe/navara/overlayPass.test.mjs @@ -30,6 +30,7 @@ function harness() { pass = new GevOverlayPass(scene, new PerspectiveCamera(), overlay), draws = []; const renderer = { + domElement: new EventTarget(), autoClear: true, outputColorSpace: SRGBColorSpace, getPixelRatio: () => 1, @@ -190,6 +191,21 @@ test('static sprite glyphs reuse their target until instance data changes', () = h.pass.camera.updateMatrixWorld(); h.pass.render(h.renderer, input, output); assert.equal(h.draws.filter((draw) => draw.object === h.scene).length, 3); + for (const type of ['webglcontextlost', 'webglcontextrestored']) { + h.renderer.domElement.dispatchEvent(new Event(type)); + const before = h.draws.filter((draw) => draw.object === h.scene).length; + h.pass.render(h.renderer, input, output); + assert.equal( + h.draws.filter((draw) => draw.object === h.scene).length, + before + 1, + `${type} invalidates the cached GPU pixels`, + ); + h.pass.render(h.renderer, input, output); + assert.equal( + h.draws.filter((draw) => draw.object === h.scene).length, + before + 1, + ); + } h.pass.dispose(); texture.dispose(); mesh.geometry.dispose();