Fix non-deterministic gvar compilation#1960
Merged
anthrotype merged 4 commits intomainfrom Apr 16, 2026
Merged
Conversation
Derived from Georama's uni03060300 (breve + grave combining mark). The composite has 4 corner masters; its component uni0306 has 5 intermediate layers (4 on-axis edges + 1 interior at wght=0.5, wdth=0.4). When edge intermediates are inserted incrementally before the interior point, they narrow the VariationModel's support regions, causing the interior interpolation to produce a mathematically different result (up to ~19 units off). The test verifies that ensure_composite_defined_at_component_locations produces results matching independent interpolation from the original (unmodified) model at every missing location. If you are lucky and the test passes, that is still the non-determinism at play. Run it again until it will fail :)
Member
Author
|
gladly both failed at first shot: https://github.com/googlefonts/fontc/actions/runs/24506123258/job/71624978566?pr=1960#step:5:244 |
…c gvar Two functions in fontir/src/glyph.rs (ensure_composite_defined_at_component_locations and ensure_component_has_consistent_layers) incrementally added interpolated instances to composite glyphs while iterating HashSet/HashMap keys. Each insertion changed the VariationModel used for subsequent interpolations, creating a feedback loop where HashMap iteration order (non-deterministic per process) produced different delta values. The fix is to compute all interpolations from the original (unmodified) source set, then insert all the interpolated instances at the end. This makes the computation order-independent. Fixes #1873
…_component_locations ensure_composite_defined_at_component_locations now returns Result<Glyph, BadGlyph>; both interpolation sites can call instantiate_instance directly since missing locations are pre-filtered.
Deduplicates the batch-interpolate-then-insert pattern from ensure_composite_defined_at_component_locations and ensure_component_has_consistent_layers into a single function.
cmyr
approved these changes
Apr 16, 2026
Member
cmyr
left a comment
There was a problem hiding this comment.
good catch, this has been annoying me :)
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.
Fixes #1873
ensure_composite_defined_at_component_locationsandensure_component_has_consistent_layersincrementally inserted interpolated instances into a glyph's source map, mutating the VariationModel between iterations. Combined with non-deterministic HashMap iteration order, this produced different interpolation results across builds.The fix is to collect all missing locations first, interpolate all from the unmodified source map, and insert them at the end after the loop. Each interpolation now sees the same VariationModel regardless of processing order.
I derived two reproducers from Georama's topology (4 corner masters + 5 intermediates including an interior off-axis location) that verify each interpolated instance returned from these functions matches an independent
interpolate_instancecall on the original glyph.Note that because of the non-determinism, the test may pass the first time the CI runs if the random iteration order happens to be the lucky one.
I also confirmed that Georama deterministically builds the same gvar after the fix.