For where there's no vertex JIT. It skins the same way as the steps:
the skin matrix is 0 + bone * weight, kept as the columns that
Vec3ByMatrix43() and Norm3ByMatrix43() multiply and add unfused in the
same order (by lane on ARM64, like those), and only rebuilt when the
weight changes. 2.2 ns a vertex in God of War against the JIT's 1.95
and the steps' 12-18.
Without the vertex JIT, God of War's instructions drop by 6.8% per 10
emulated seconds.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The decoders clear gstate_c.vertexFullAlpha when a vertex has less than
full alpha, and a batch decodes each of its draws in turn. The God of War
and GTA decoders assigned it instead, so a draw with full alpha set it
back after an earlier one had cleared it. God of War's also read the
alpha from the normal: its struct had color and normal swapped (the
output came out right, as each went to the matching slot), so the flag
never got set for its most used format.
The vertex decoder test now decodes a vertex with full alpha after a
draw that cleared the flag and after one that didn't.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
For where there's no vertex JIT (iOS), as they're a few percent slower
than the JIT's but four to eleven times faster than the steps. The
formats carry most of the vertices of ATV Offroad Fury: Blazin' Trails,
Wipeout Pure and Killzone: Liberation, and a lot of Gods Eater Burst's.
They convert like the steps (PrescaleUV moves to the header for that),
and the vertex decoder test now also compares each format's decoder
without the JIT against the steps.
Without the vertex JIT, 10 emulated seconds on an M1, instructions:
ATV -9.9%, Wipeout -6.0%, Killzone -5.4%, Gods Eater -2.2%.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
They were only used for UV from texture coordinates. With the texture
matrix or environment map, UV isn't prescaled, which is the same as a
scale of 1 and no offset, so NoPrescale versions pass that. God of War
draws 5 million of its vertices per 10 seconds this way, which without
the vertex JIT took 9.6 ns each through the steps and now 2.4.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The two handwritten SIMD decoders are used with or without the JIT, and had
drifted from the step functions:
- The God of War one ignored g_DoubleTextureCoordinates, giving HD Remaster
games the wrong UVs, and passed NaN and infinite positions through. Those
now come out finite like everywhere else.
- The GTA one expanded 5551 colors wrongly on NEON (a left shift where the
SSE version shifts right).
- On ARM64, both now fuse the UV scale and offset, like the JIT and the steps
as the compiler builds them.
Both are back in the unit test, which now also feeds NaN and infinity to plain
float positions and checks they come out finite, and runs only on x86-64 and
arm64 for now.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>