Skip to content

Mgrasfaster - #193

Merged
techomancer merged 6 commits into
mainfrom
mgrasfaster
Oct 8, 2026
Merged

techomancer merged 6 commits into
mainfrom
mgrasfaster

Conversation

@techomancer

Copy link
Copy Markdown
Owner

added mgras jit and converted raster pipeline to ints
moar speed

techomancer and others added 6 commits October 8, 2026 01:49
IMPACT's per-pixel pipeline, compiled with Cranelift per configuration,
modelled on the REX3 shader JIT.

- RSS and TE1 state is plain #[repr(C)] data: the stipple and transfer
  Options became a plain Slot, Block/Stipple/Xfer/Sampler/Buffer are
  repr(C), and triangle and GL line setup are shared structs
  (Rss::tri_setup, Rss::gl_line_setup) that both engines draw from.
- PipeKey packs a primitive's pipeline into 64 bits (mixed radix, about
  2^58 at most): primitive, clipping, draw target, pixel format, logic op,
  alpha/stencil/depth tests, blending, texture environment, format,
  filtering and wrap modes, fog. Keys are normalised so configurations
  that draw alike share a shader.
- Emitters mirror the interpreter expression for expression (Rust round,
  clamp, min and saturating casts spelled out; libm and divisions through
  the interpreter's own code), so shaders are bit-exact.
- The board keeps a persistent context; only writes to pipeline state
  registers invalidate its cached part, and each primitive memoises its
  shader. Row values are pinned against Cranelift's rematerialisation.
- rss_jit_tests.rs sweeps the key space coverage-first (every value of
  every field, greedy pair coverage, random data) on two boards and
  compares pixel memory, clip IDs and stipple state word for word.
- mgras jit [on|off|sync|list] in the monitor; IRIS_GR4_JIT, GR4_JIT_DISASM.

2.5-6x faster than the interpreter on representative primitives.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The level of detail was hypot and libm log2, which the raster JIT could
only reach by calling back into Rust mid-fragment. Both engines now use
te1::lod: the square root of the larger sum of squares, and lod_log2 (the
exponent plus a cubic in the mantissa, exact on powers of two, within
0.0011 elsewhere). The JIT emits the same operations inline, so shaders
make no calls and stay bit-exact with the interpreter.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The RE4 and TE1 are integer machines; colour from the iterators to the
framebuffer is now modelled that way (src/dev/mgras/fixed.rs):

- colour and fog iterators as 12.16 planes in the shared triangle and
  GL line setup, evaluated base + dx (i - xs) + dy (yref - j), wrapping;
- texels widened to 12 bits by repeating bits (4: x0x111, 8: v<<4|v>>4);
- bilinear with 8-bit weights (the four products sum to 12.16 exactly),
  trilinear with an 8-bit mip fraction;
- texture environment, fog and blending through mul = (a*b) >> 28;
- shift down on write: >> 20 to bytes, >> 16 to a 12-bit index.

The JIT emits the same integer operations: the equivalence sweep and
the mgras suite under IRIS_GR4_JIT=sync pass. Half-alpha blends round
down now (0x7F, was 0x80); the blend test expects that.

Bilinear textured triangles: 68 -> 42 ns/px (5x the interpreter);
trilinear 136 -> 110; shaded and depth-tested 17 -> 12.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Z registers are z.12 fixed point; depth now stays that way. The
triangle setup turns the depth plane into a z.12 i64 plane at pixels
(fixed::zplane, evaluated like the colour planes), GL lines step a z.12
base per pixel, and fixed::zbuf rounds to the 24-bit buffer value
((z + 2048) >> 12, clamped), which is what z.round().clamp() gave for
every depth that can be stored. The JIT emits the same i64 arithmetic.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
S/W, T/W and 1/W are i64 planes at 2^32 (their registers' scale),
evaluated like the colour and depth planes. Per fragment:

- a reciprocal unit divides out W: normalise 1/W, a 1024-entry seed
  table and one Newton step (fixed::recip, good to about 2^-22), then s
  and t in Q31 by one 64x64->128 multiply each;
- per level, texels in Q16 (s >> (15 - lw)): the integer part picks the
  texel, bits 15:8 are the bilinear weight; no float floor or saturating
  conversions;
- the level of detail in Q8: Q16 texel derivatives, the larger sum of
  squares, a 256-entry log2 table (fixed::lod_q8), replacing the float
  cubic log2; it picks magnification, the nearest level and the
  trilinear fraction.

A fragment whose 1/W is not positive is left untextured (before: only
zero or non-finite). The JIT emits the same integer operations; the
equivalence sweep and the mgras suite under IRIS_GR4_JIT=sync pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@techomancer
techomancer merged commit 041fd17 into main Oct 8, 2026
1 check passed
@techomancer
techomancer deleted the mgrasfaster branch October 8, 2026 15:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant