The GE doesn't divide by a q <= 0: it samples the last texel in u and v,
whatever s and t are, in clamp and repeat modes alike (gpu/texmtx/negq). The
hardware backends divided, which mirrors a projected texture behind its
projector: Fate/Extra's character shadows ran up the school's walls (#18667).
The software renderer sampled (0, 0) instead.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
When a triangle's q, s and t plane sums fit 32 bits wherever its spans
are walked, and the planes' exponents keep the GE's UV arithmetic in the
normal float range (GEUVSpanSafe), a span's plane values are one vector
add each and GEUVSpanCore runs without its range checks. Tested bit for
bit against the scalar code under those conditions.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
GEUVSpan does the GE's per-pixel UV arithmetic for four pixels at once:
the plane values to float24s by exponent arithmetic, GERecip with its
table entries gathered, and the truncated 24-bit products from the 16-bit
significands' product. Lanes it doesn't cover (values past 2^24,
denormals, results out of range) send the span to the scalar code.
Tested bit for bit against it.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
GEDot3 forms one term per lane and sums across the lanes, about 1.5-2x
as fast as the scalar GEDot. Adds Vec4S32::GetLane.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Skinning did each component's weighted bone entries and its chain of
GEAdds separately in scalar code. The components now go in lanes, with
GEMulFloat24x4 for the weighted entries, one-term row sums for the
products and GEAdd4 for the sums, in the same order. Checked against the
scalar version on every vertex of 143 skinned frame dumps.
GEMulFloat24x4 matches ProductToFloat24, so inf and NaN bone entries
behave as before. GEAdd4 handles two zero operands without its fallback.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
They're truncated to float24 with one AND, and their exponents, fractions
and signs worked out for all terms at once, each term then broadcasting its
lane (new CrossSIMD Vec4S32::SplatLane). The term count becomes a template
parameter so the lanes are constants. About 75-83 M transforms/s on an M1,
from 68; results unchanged.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The four clip space rows of a vertex, the texture matrix's three, the world
normal's three, the vector to a light, and each row of the combined matrix
now take one GERowSum4 call. Same results (pspautotests, frametests and
the probe regression set unchanged).
GERowSum4 scales its result by adding to the exponent instead of
multiplying, and CrossSIMD gets a Vec4S32::Max for the largest lsb. About
68 M transforms/s against 26 for four scalar GERowSums on an M1 (a pure
NEON version with per-lane shifts did about 79); replaying the frametest
dumps gets only about 1% faster, up to 11% on Taiko no Tatsujin.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Four rows sharing their left operands, like a vertex transform's: with
float24 operands each exact product is a 32-bit integer, (1.a' * 1.b') >> 15
= 32768 + a' + b' + (a' b' >> 15), and the terms are aligned by scaling with
a power of two and truncating. Lanes whose result exponent is out of a
single float scale's reach take the scalar GERowSum. Tested bit for bit
against GERowSum on random operands (arm64 and x86-64). Not used yet.
Also adds an arithmetic Vec4S32::Shr and the float/int bit casts to
CrossSIMD.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The GE keeps the specular and spot exponents to 5 significant bits,
truncated, and from 512 up (infinity and NaN included) uses 496. Only
the specular one was truncated, and neither saturated. A huge or NaN
exponent overflowed pspPow's bits: highlights wrong on every backend,
and on D3D11, where the overflowing float to int conversion gives a
NaN, black (Everybody's Golf, #22418). With the exponent clamped, t
stays in range for every base the backends produce.
Measured, now bit exact in the software renderer and within 4 levels
on Vulkan.
Fixes#22418
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The minor-axis offset an antialiased line's alpha comes from is computed
with the triangle setup's reciprocal of the line's major length, walking
from v0, and floored; diagonal lines are y-major. exp112 went from 101
differing pixels to 23; the misses left sit at reciprocal segment starts.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Nearly every segment's K is floor(2^39 / (65536 + 256 i) / 16) * 16. The
fit to probe data left a few segments loose and slightly low; segment 39
made Blade Dancer's large triangle one depth unit high where the PSP's
depth test rejects it (frame dump now exact). Segments 39, 162, 253 and 255
now use the formula, which every probe accepts.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Segment 161's K was 16 low: exp54's one inexact Gouraud triangle needs
q >= 40211 at index 41275 (its y gradient -1366), and exp39/exp41 bound K
from above, leaving a window of 16 that the depth-only fit had missed. Every
color and depth probe is now exact.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The exponent times the log (the float's bits) keeps units of 16 in the bits,
truncated toward zero, not floored at 1. Fixes the last specular pixels at
small exponents (gpu/probe exp102 e = 0.3, exp3, exp4 e = 0.05); all lighting
probes are now bit exact.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The GE arithmetic in GEMath.h against values measured on a PSP: the
reciprocal for sampled mantissas (gpu/probe exp15), the triangle setup
reciprocal (exp38-41), antialiased line alphas (exp112), and the cases the
other probes pinned down (float24 truncation, the adder and row sums, rsqrt,
the mip log2, texture coordinate precision, the lighting pow and color
scaling).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>