Split out of #457, where it was raised during review and descoped.
What happens
_handleWebglContextLost (components/scatter-plot/scatter-plot.ts) destroys the renderer and nulls it; _createWebglRenderer then builds a fresh one. There is no attempt counter, no backoff, and no ceiling.
When the loss was caused by the very allocation the rebuild is about to make again — a large dataset on a device that could not hold it — the app rebuilds, re-allocates the same footprint, loses the context again, and repeats. The user sees a flickering or blank plot with nothing explaining it.
Why it is not urgent
Verified during #457: a rebuilt renderer starts at capacity = 0, so the geometric-growth overshoot that could contribute to a loss does not survive it. That removes the most likely self-sustaining case, which is why #457 shipped without a counter.
It also means the naive fix is wrong. A blanket "stop after two losses" would permanently disable rendering on a healthy machine after two unrelated losses — and this codebase manufactures losses of its own on resize and on renderer teardown, so two is easy to reach without anything being wrong.
Direction
Distinguish the cases rather than counting them:
Related
dispose() (webgl/renderer/webgl-renderer.ts) does not call WEBGL_lose_context.loseContext(), though the export path does. Chrome caps live contexts per page and force-loses the oldest when the cap is hit, so leaking a context per recovery and per resize-rebuild is a plausible source of losses. Worth fixing alongside, and cheap.
Acceptance
A second suspicious loss retries at reduced footprint rather than reallocating identically; a third surfaces a message instead of looping. Testable against the existing mock GL context by driving webglcontextlost directly.
Split out of #457, where it was raised during review and descoped.
What happens
_handleWebglContextLost(components/scatter-plot/scatter-plot.ts) destroys the renderer and nulls it;_createWebglRendererthen builds a fresh one. There is no attempt counter, no backoff, and no ceiling.When the loss was caused by the very allocation the rebuild is about to make again — a large dataset on a device that could not hold it — the app rebuilds, re-allocates the same footprint, loses the context again, and repeats. The user sees a flickering or blank plot with nothing explaining it.
Why it is not urgent
Verified during #457: a rebuilt renderer starts at
capacity = 0, so the geometric-growth overshoot that could contribute to a loss does not survive it. That removes the most likely self-sustaining case, which is why #457 shipped without a counter.It also means the naive fix is wrong. A blanket "stop after two losses" would permanently disable rendering on a healthy machine after two unrelated losses — and this codebase manufactures losses of its own on resize and on renderer teardown, so two is easy to reach without anything being wrong.
Direction
Distinguish the cases rather than counting them:
renderer-degradedhost-message channel added in perf/correctness: the pie-chart atlas is allocated for every dataset and silently makes MAX_TEXTURE_SIZE the point ceiling #457.Related
dispose()(webgl/renderer/webgl-renderer.ts) does not callWEBGL_lose_context.loseContext(), though the export path does. Chrome caps live contexts per page and force-loses the oldest when the cap is hit, so leaking a context per recovery and per resize-rebuild is a plausible source of losses. Worth fixing alongside, and cheap.Acceptance
A second suspicious loss retries at reduced footprint rather than reallocating identically; a third surfaces a message instead of looping. Testable against the existing mock GL context by driving
webglcontextlostdirectly.