Skip to content

webgl: fix ROI/sulci/label overlay toggles racing the texture bake#643

Merged
jackgallant merged 1 commit into
mainfrom
claude/overlay-toggle-race
Jun 1, 2026
Merged

webgl: fix ROI/sulci/label overlay toggles racing the texture bake#643
jackgallant merged 1 commit into
mainfrom
claude/overlay-toggle-race

Conversation

@jackgallant
Copy link
Copy Markdown
Contributor

Problem

On the WebGL make_static viewers (e.g. viewer-stories-group, viewer-chen-2026), the ROI-boundary / sulci / label switches often fail to take effect — the rendered overlay disagrees with the checkbox state. It's intermittent and feels like a buffering issue.

Root cause

The overlay layers are SVG display_layers. Each switch calls Overlay.show()/hide(), which flips the layer's display style and dispatches "update", driving SVGOverlay.prototype.update(). That re-bakes the whole overlay into a GPU texture asynchronously:

svg.toDataURL("image/png", …) → new Image() → img.onload → new THREE.Texture → dispatch("update", {texture})

and the viewer commits whatever arrives:

this.uniforms.overlay.value = evt.texture;   // last to RESOLVE wins

There was no sequencing guard. Toggling layers in quick succession starts several bakes concurrently; they can resolve out of order, so the last bake to finish — not the last one requested — is left on the GPU. The overlay then drifts out of sync with the switches.

Fix

Tag each bake with a per-SVGOverlay generation id and discard any bake whose generation is stale, so only the most recent toggle's texture is ever committed. Also removes a stray console.log("Updating overlay!") that fired on every update.

7 insertions, 1 deletion; no behavior change other than correctness. node --check passes.

Verification

Repro: open a viewer, rapidly toggle ROIs / sulci / labels — before, the picture frequently lands on a state that doesn't match the boxes; after, it always settles on the current switch state. Re-baking each affected viewer via the pycortex-roidraw reengine.py tooling propagates the fix into the deployed exports.

🤖 Generated with Claude Code

The SVG overlay (ROI boundaries, sulci, labels) is re-baked into a GPU
texture asynchronously in SVGOverlay.update(): svg.toDataURL() -> Image
-> onload -> new THREE.Texture -> dispatch "update", which the viewer
commits to uniforms.overlay.value.

There was no sequencing guard, so toggling layers in quick succession
started several bakes concurrently that could finish out of order. The
last bake to *resolve* (not the last one *requested*) won, leaving a
stale overlay texture that disagreed with the checkbox state — the
intermittent "switches don't take effect / buffering" bug seen across
the make_static viewers.

Tag each bake with a per-overlay generation id and discard any bake
whose generation is no longer current, so only the most recent toggle's
texture is ever committed. Also drops a stray console.log that fired on
every update.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a generation tracking mechanism (_updateGen) to the SVG overlay update process in svgoverlay.js. This ensures that asynchronous texture bakes finishing out of order do not overwrite newer updates, preventing stale textures from being displayed. There are no review comments, and we have no feedback to provide.

@jackgallant jackgallant merged commit 2c64b0b into main Jun 1, 2026
13 checks passed
@jackgallant jackgallant deleted the claude/overlay-toggle-race branch June 1, 2026 17:12
jackgallant added a commit to gallantlab/viewer-chen-2024 that referenced this pull request Jun 1, 2026
jackgallant added a commit to gallantlab/viewer-chen-2026 that referenced this pull request Jun 1, 2026
jackgallant added a commit to gallantlab/viewer-shortclips-group that referenced this pull request Jun 1, 2026
jackgallant added a commit to gallantlab/viewer-stories-group-roidraw that referenced this pull request Jun 1, 2026
jackgallant added a commit to gallantlab/viewer-cortical-anatomy that referenced this pull request Jun 1, 2026
jackgallant added a commit to gallantlab/viewer-deniz-2019 that referenced this pull request Jun 1, 2026
jackgallant added a commit to gallantlab/viewer-huth-2016 that referenced this pull request Jun 1, 2026
jackgallant added a commit to gallantlab/viewer-lescroart-2018 that referenced this pull request Jun 1, 2026
jackgallant added a commit to gallantlab/viewer-stories-group that referenced this pull request Jun 1, 2026
jackgallant added a commit that referenced this pull request Jun 1, 2026
)

Toggling an overlay layer (ROIs / sulci / labels) re-bakes the overlay
into a GPU texture asynchronously; SVGOverlay dispatches "update" with the
new texture, and the surface swaps it into uniforms.overlay.value and
re-dispatches "update" on itself (mriview_surface.js). But addSurf never
wired the surface's "update" to the viewer's redraw, so the swap landed
with no schedule() call. The menu schedules a redraw immediately on toggle
— which races (and usually beats) the async bake — so the new overlay was
not drawn until the next interaction. The switch appeared not to work.

Wire surf "update" -> viewer.schedule() in addSurf so the overlay redraws
as soon as the rebaked texture is committed. Complements the generation
guard in #643 (which fixed out-of-order bakes); together a single toggle
now deterministically lands on the current switch state.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
jackgallant added a commit to gallantlab/viewer-chen-2024 that referenced this pull request Jun 1, 2026
jackgallant added a commit to gallantlab/viewer-chen-2026 that referenced this pull request Jun 1, 2026
jackgallant added a commit to gallantlab/viewer-shortclips-group that referenced this pull request Jun 1, 2026
jackgallant added a commit to gallantlab/viewer-stories-group-roidraw that referenced this pull request Jun 1, 2026
jackgallant added a commit to gallantlab/viewer-cortical-anatomy that referenced this pull request Jun 1, 2026
jackgallant added a commit to gallantlab/viewer-deniz-2019 that referenced this pull request Jun 1, 2026
jackgallant added a commit to gallantlab/viewer-huth-2016 that referenced this pull request Jun 1, 2026
jackgallant added a commit to gallantlab/viewer-lescroart-2018 that referenced this pull request Jun 1, 2026
jackgallant added a commit to gallantlab/viewer-stories-group that referenced this pull request Jun 1, 2026
jackgallant added a commit that referenced this pull request Jun 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant