webgl: fix ROI/sulci/label overlay toggles racing the texture bake#643
Merged
Conversation
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>
Contributor
There was a problem hiding this comment.
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
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
This was referenced Jun 1, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
On the WebGL
make_staticviewers (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 callsOverlay.show()/hide(), which flips the layer'sdisplaystyle and dispatches"update", drivingSVGOverlay.prototype.update(). That re-bakes the whole overlay into a GPU texture asynchronously:and the viewer commits whatever arrives:
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-
SVGOverlaygeneration id and discard any bake whose generation is stale, so only the most recent toggle's texture is ever committed. Also removes a strayconsole.log("Updating overlay!")that fired on every update.7 insertions, 1 deletion; no behavior change other than correctness.
node --checkpasses.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-roidrawreengine.pytooling propagates the fix into the deployed exports.🤖 Generated with Claude Code