Repository navigation
Vectorize contact solving and reuse world step storage - #101
Open
edwardgushchin wants to merge 5 commits into
Open
edwardgushchin wants to merge 5 commits into
edwardgushchin wants to merge 5 commits into
Conversation
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.
Active physics steps allocate transient solver/task storage, and wide contact math processes four scalar lanes. This PR collects all portable downstream Box2D.NET runtime patches accumulated since tag 3.1.654, adapts them to current upstream main (
154bacd0fddc0e72e484d3061cdc76aa2d842994), and adds regression tests and a reproducible dense workload.It includes the original per-world buffer reuse in this PR and both changes from #102. #102 remains open; its static revolute/wheel fixes are also included here.
Changes
Vector256<float>contact storage/arithmetic, gather/scatter, indices and layout validation. Scalar NaN/signed-zero selection and separate multiply/add remain intact; the existingVector<float>overloads are unchanged.netstandard2.1path uses scalar eight-lane storage and C# 12 static method-group caching, with no new package dependencies.The complete patch inventory and report maps every portable vendored delta to its current upstream implementation. Visibility/nullable/XML-warning embedding adaptations and engine-owned scene/contact/interpolation code require downstream types and are excluded explicitly. Upstream's existing
B2WorldDef.capacitycovers expected body/contact capacity preparation.Measurements
Ryzen 7 5700X, Linux x64, .NET 10.0.1, Release with
DOTNET_TieredCompilation=0. Same 1,536 always-awake circles, 144 Hz, four substeps, 1,600 warmup and 1,024 measured steps. Three fresh-process trials per configuration, alternated within each trial; medians of trial means and p99 values:154bacdAll nine trials produce the identical complete body-state SHA-256:
C2554173F6A5D78AD49163D4BBF0909906B31A92518A795A2FEC21A63E22CEDD.Raw JSON trials are committed beside the benchmark. The host desktop load was uncontrolled. These are kernel measurements, not rendered FPS or a native Box2D comparison.
Verification and boundaries
netstandard2.1,net8.0,net9.0,net10.0.netstandard2.1assembly on .NET 10: 12/12 of the same regression/determinism tests, including warmed static revolute/wheel allocation checks.0x26E08AEE..NET 9runtime execution and other CPUs/operating systems remain unverified locally. Upstream's workflow currently limits PR base branches topr/**, so a PR targetingmaindoes not automatically receive its checks.Low-level API/layout change:
B2FloatWbecomes 32 bytes and wide constraint indices become eight elements. On .NET 8+,X/Y/Z/Ware ref-returning properties over vector storage, while scalar fallback retains fields. Direct reads/writes and the four-argument constructor remain usable, but field reflection/ABI and wide-structure layout require consumers of these public low-level types to rebuild. The existing two-argumentb2DestroySolverSetentry point is retained. Buffers retain peak capacity for a world's lifetime; new topology/nested jobs can allocate. Resuming a partly solved world after a fatal error is not a recovery contract.