Repository navigation
Conversation
This is a line-by-line translation of SSE implementation; as such it's not always optimal and there might be better instruction or intrinsic choices available in some places. Instead of duplicating the existing functions with their flow, we only duplicate the building blocks (decodeVertexGroup & decodeTriangleGroup), and patch the other functions using ifdefs for the short segments of SIMD code. This appears to be reasonably easy to follow still, and hopefully will make it easier to maintain this code in the future. Triangle decoding relies on vqtbl1q which is an AArch64 instruction; while we could synthesize it out of vqtbl1 on 32-bit ARM, meshlet decoding is a fairly cutting edge feature that should not need 32-bit support, so we use a scalar fallback there for simplicity.
Unlike SSE, NEON has a native instruction to narrow 32-bit integers with truncation, which is exactly what we need here.
Instead of relying on the compiler to synthesize lane store, use the intrinsic. This also fixes int->unsigned int casts from unaligned_int. As part of this, unaligned_int type becomes unused in NEON; move it to shared code to avoid duplication and only define it for SSE.
We now try to store the values using the "expected" type for the value; this is mostly for aesthetics as the types here are erased.
This is the more important path for non-raw meshlet decoding so we should test it instead of 4-byte writes. Note that the benchmark code doesn't test "raw" decoding; raw decoding is mostly useful when the output vertex/triangle data needs to be post-processed via SIMD, so it should not be benchmarked in isolation.
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.
The NEON code mostly follows SSE implementation, with a few adjustments,
such as the use of
vmovnfor 16-bit truncation, and 16->8 byte shuffles whenpossible.
Instead of duplicating the existing functions with their flow, we only
duplicate the building blocks (
decodeVertexGroup&decodeTriangleGroup),and patch the other functions using ifdefs for the short segments of SIMD
code. This appears to be reasonably easy to follow still, and hopefully
will make it easier to maintain this code in the future.
Triangle decoding relies on vqtbl1q which is an AArch64 instruction; while
we could synthesize it out of vqtbl1 on 32-bit ARM, meshlet decoding is a
fairly cutting edge feature that should not need 32-bit support, so we use
a scalar fallback there for simplicity.
The resulting code runs at ~1.7-2B triangles/second when decoding meshlets
with vertex references, and ~2.5-3B triangles/second when decoding triangle-only
data on Apple M4. The "raw" decoding is curiously a little slower because it needs
an extra shuffle (compared to vector shift) to repack the state bytes, so the optimal
path would decode 3-byte triangles.
This contribution is sponsored by Valve.