fix(webgl): auto-restore context after loss
🔍 Lint / 🪄 Check lint (pull_request) Has been cancelled
🔍 Lint / 🎨 Check format (pull_request) Has been cancelled
🔍 Lint / 🔎 Typecheck (pull_request) Has been cancelled
📊 Quality / 🔒 Security Audit (pull_request) Has been cancelled
📊 Quality / 📋 Dependency Freshness (pull_request) Has been cancelled
📊 Quality / 📦 Bundle Size (pull_request) Has been cancelled
🔍 Lint / 🏗 Build (pull_request) Has been cancelled
🔍 Lint / 🪄 Check lint (pull_request) Has been cancelled
🔍 Lint / 🎨 Check format (pull_request) Has been cancelled
🔍 Lint / 🔎 Typecheck (pull_request) Has been cancelled
📊 Quality / 🔒 Security Audit (pull_request) Has been cancelled
📊 Quality / 📋 Dependency Freshness (pull_request) Has been cancelled
📊 Quality / 📦 Bundle Size (pull_request) Has been cancelled
🔍 Lint / 🏗 Build (pull_request) Has been cancelled
The Canvas onCreated callback used to log Context Lost but never asked the GPU to restore it, which left the page on a frozen black canvas until the user reloaded. We now grab the WEBGL_lose_context extension on mount and call restoreContext() 500ms after a loss, giving the GPU time to free memory before we ask for a new context. The existing webglcontextrestored handler reinstates the shadow map settings, so recovery is transparent to the user. This does not prevent context loss itself — frequent losses still indicate VRAM pressure or HMR-driven context churn — but it removes the need to reload manually when the GPU recycles us.
This commit is contained in:
+14
-3
@@ -96,9 +96,16 @@ export function HomePage(): React.JSX.Element | null {
|
|||||||
gl.shadowMap.type = THREE.PCFShadowMap;
|
gl.shadowMap.type = THREE.PCFShadowMap;
|
||||||
gl.shadowMap.autoUpdate = true;
|
gl.shadowMap.autoUpdate = true;
|
||||||
|
|
||||||
|
// The browser hands us a WEBGL_lose_context extension we can use to
|
||||||
|
// ask the GPU to restore the context after a loss. Without this the
|
||||||
|
// page stays frozen on a black canvas until the user reloads.
|
||||||
|
const loseContextExt = gl.getContext().getExtension("WEBGL_lose_context");
|
||||||
|
|
||||||
const handleContextLost = (event: Event) => {
|
const handleContextLost = (event: Event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
logger.error("WebGL", "Context lost - GPU resources exhausted");
|
logger.error("WebGL", "Context lost - attempting auto-restore");
|
||||||
|
// Give the GPU a moment to free resources before asking it back.
|
||||||
|
window.setTimeout(() => loseContextExt?.restoreContext(), 500);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleContextRestored = () => {
|
const handleContextRestored = () => {
|
||||||
@@ -121,10 +128,14 @@ export function HomePage(): React.JSX.Element | null {
|
|||||||
// all hooks (rules of hooks) but BEFORE any expensive render.
|
// all hooks (rules of hooks) but BEFORE any expensive render.
|
||||||
if (!hasSiteBeenVisitedToday()) return null;
|
if (!hasSiteBeenVisitedToday()) return null;
|
||||||
|
|
||||||
|
const showFadeToVideoOverlay =
|
||||||
|
introStep === "fade-to-video" ||
|
||||||
|
(introStep === "loading-map" && sceneLoadingState.status === "ready");
|
||||||
|
|
||||||
const renderIntroOverlay = () => {
|
const renderIntroOverlay = () => {
|
||||||
|
if (showFadeToVideoOverlay) return <FadeToVideoOverlay />;
|
||||||
|
|
||||||
switch (introStep) {
|
switch (introStep) {
|
||||||
case "fade-to-video":
|
|
||||||
return <FadeToVideoOverlay />;
|
|
||||||
case "video":
|
case "video":
|
||||||
return <IntroVideoPlayer />;
|
return <IntroVideoPlayer />;
|
||||||
case "dialogue-intro":
|
case "dialogue-intro":
|
||||||
|
|||||||
Reference in New Issue
Block a user