Files
CydandClaude Fable 5 db7745fcd0 sda4: commit the Glaze developer hard-drive dump
Un-ignored: the dev drive is the ground truth the restoration and
emulator work constantly reference (DPL3/LIBDPL + VRENDER i860 renderer
source, BT/RP live+dev game trees, VGL_LABS pod boot, scene/audio
content). Kept in-repo for the pod-owner community.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 19:41:15 -05:00

615 lines
15 KiB
Scheme

//{{{ on higher-level fns
//
// Under old 8-bit shader, we called scanline from scansegment
//
// scansegment is called twice per triangle, so it pays to
// make the entry to scansegment as cheap as possible
//
// so i suggest that triangle() is fully assembly-coded.
//
// we can pre-compute the floats dr dg db dz into dbl floating
// registers for the duration of a whole triangle
// then only ir ig ib iz need setting up, according to alignment
// of start segment
//
// we can organise that scansegment is called with all the right
// register parameters to pass on to scanline
//
// we are trying to optimise 100ish pixel triangles - i.e 16 pixels
// wide by 16 pixels high (128)
//
// so we will call scansegment twice per triangle, scanline 16 times
// and will fill 8 lines > 8, 4 > 4, 4 < 4
// giving rates of 16 / (8/2.6 + 4/2 + 4) = 1.76 Mpix
// so a 128 pixel triangle will fill in 72 uS, giving a triangle rate of
// 13.8 k - however, we will have a rate of 26k 64 pixel triangles
//
// this is crap
//
//
//}}}
//{{{ register allocation
//
// Important - we should strive to keep the register allocations
// identical between calls, at which point we can call the inner
// loop indirectly from a single triangle function
//
//
// r1 return address
// r2 sp
// r3 frameP
// r4 .. r15 I should strive to conserve
// r16 .. r30 I can trash away
// r31 reserved as an addressing temporary - but available
//
// extern void scaninit ( int idr, int idg, int idb, int idz );
//
// extern void texinit ( int idu, int idv, int willy, int idz );
//
// extern void scanline ( int *fbuffer, int *zbuffer,
// int ir, int ig, int ib, int iz, int dx,
// int dr, int dg, int db, int dz );
//
// extern void ftexline ( int *fbuffer, int *zbuffer,
// int iu, int iv, int texbase, int iz, int dx,
// int idu, idv, dummy, dz );
//
// FUNCTION PARAMETERS
//
#define param1 r16
#define param2 r17
#define param3 r18
#define param4 r19
#define param5 r20
#define param6 r21
#define param7 r22
#define param8 r23
#define param9 r24
#define param10 r25
#define param11 r26
//
// DOUBLE FLOAT LOCALS
//
// interpolant values
// we should save these first !
//
#define oddz f6
#define ddz f4
#define ddz_lo f4
#define ddz_hi f5
#define r_lo f8
#define r_hi f9
#define r r_lo
#define g_lo f10
#define g_hi f11
#define g g_lo
#define u_lo f8
#define u_hi f9
#define u u_lo
#define v_lo f10
#define v_hi f11
#define v v_lo
#define b_lo f12
#define b_hi f13
#define b b_lo
#define z_lo f14
#define z_hi f15
#define z z_lo
#define dr_lo f16
#define dr_hi f17
#define dr dr_lo
#define du_lo f16
#define du_hi f17
#define du du_lo
#define dg_lo f18
#define dg_hi f19
#define dg dg_lo
#define dv_lo f18
#define dv_hi f19
#define dv dv_lo
#define db_lo f20
#define db_hi f21
#define db db_lo
#define dz_lo f22
#define dz_hi f23
#define dz dz_lo
// double-length float temporaries
#define oldz_lo f24
#define oldz_hi f25
#define oldz oldz_lo
#define nuz f26
#define col f28
#define col_lo f28
#define col_hi f29
#define dbltmp f30
#define col_next f12
#define colnext_lo f12
#define colnext_hi f13
#define tex_val1 f20
#define tex_val2 f21
//}}}
//{{{ scaninit ( int idr, int idg, int idb, int idz )
.text
.globl _scaninit
.align 8
#define indr param1
#define indg param2
#define indb param3
#define indz param4
#define itemp1 param5
_scaninit::
addu indr,indr,itemp1
ixfr itemp1, dr_lo
addu indg,indg,itemp1
ixfr itemp1, dg_lo
addu indb,indb,itemp1
ixfr itemp1, db_lo
addu indz,indz,itemp1
ixfr itemp1, dz_lo
addu itemp1,itemp1,itemp1
ixfr itemp1, ddz_lo
fmov.ss dr_lo,dr_hi
fmov.ss dg_lo,dg_hi
fmov.ss db_lo,db_hi
fmov.ss dz_lo,dz_hi
bri r1
fmov.ss ddz_lo,ddz_hi
#undef indr
#undef indg
#undef indb
#undef indz
#undef itemp1
//}}}
//{{{ scanline ( int *fb, int *zb, int ir, int ig, int ib, int iz, int dx )
.globl _scanline
.align 8
#define paddr param1
#define zaddr param2
#define ir param3
#define ig param4
#define ib param5
#define iz param6
#define dx param7
#define idr param8
#define idg param9
#define idb param10
#define idz param11
#define itemp1 r27
#define itemp2 r28
#define itemp3 r29
#define itemp4 r30
#define minus1 itemp1
_scanline:
and 4,paddr,r0 // if paddr&7 == 0, cc set
bc .aligned // so we jump if paddr&7==0, i.e aligned
.unaligned: // ie first pixel NOT on a 64-bit boundary
//{{{
// ir corresponds to high word of 64-bit pair, so we down tick to
// get ir_lo etc.
//
//
// align to double boundary
adds -12, zaddr, zaddr
adds -12, paddr, paddr
fld.d -8(zaddr), oldz // load zbuffer value (from &z0-4)
ixfr ir, r_hi
ixfr ig, g_hi
ixfr ib, b_hi
ixfr iz, z_hi
// construct lo word of rgbz by subtraction
subs ir, idr, ir
subs ig, idg, ig
subs ib, idb, ib
subs iz, idz, iz
adds -1,r0,minus1
ixfr minus1, z_lo // important - zlo MUST be invisible for fchkz
ixfr ir, r_lo
ixfr ig, g_lo
ixfr ib, b_lo
adds 1,dx,dx // tick count
fzchkl oldz,z,nuz // z-check with frigged z
and 3,dx,itemp3 // itemp3 = extras on rhs
br .aligned_path
ixfr iz, z_lo // correct z
//}}}
.aligned: // ie first pixel IS on a 64-bit boundary
//{{{
//
// write iz into dbl z lo, iz+dz into dbl z hi etc
//
adds -8, zaddr, zaddr
adds -8, paddr, paddr
fld.d -8(zaddr), oldz // load zbuffer value HOURS to complete
ixfr ir, r_lo
ixfr ig, g_lo
ixfr ib, b_lo
ixfr iz, z_lo
adds ib, idb, ib
adds ig, idg, ig
adds ir, idr, ir
adds iz, idz, iz
ixfr iz, z_hi // this needs 3 cycles to complete before fzchkl
ixfr ib, b_hi
ixfr ig, g_hi
ixfr ir, r_hi
adds -1,r0,minus1
.dual
fzchkl oldz,z,nuz // z-check with unfrigged z
and 3,dx,itemp3 // itemp3 = extras on rhs
.aligned_path:
faddp b,f0,f0
or r0,dx,itemp2 // itemp2 = orig dx
faddp g,f0,f0
shr 2,dx,dx // dx now n of 4s
faddp r,f0,f0
adds -4, itemp2, r0 // goto last 4 if dx < 4
form f0,col
bc .last_few
fnop
adds -1,dx,dx // corrected for autoincrement, so test -3 below
fnop
bla minus1, dx, .inner_loop
fnop
nop
//}}}
//{{{ 32-bit z, 32-bit pixel inner loop
.inner_loop:
faddz z,dz,oddz
fst.d nuz, 8(zaddr)++
faddz z,ddz,z
nop
fzchkl oldz,oddz,nuz
fld.d 16(zaddr), oldz
fzchks f0,f0,f0
fst.d nuz, 8(zaddr)++
faddp b,db,b
nop
faddp g,dg,g
nop
faddp r,dr,r
pst.d col, 8(paddr)++
form f0,col
nop
faddp b,db,b
nop
faddp g,dg,g
pst.d col, 8(paddr)++
faddp r,dr,r
nop
form f0,col
bla minus1,dx,.inner_loop
fzchkl oldz,z,nuz
fld.d 16(zaddr), oldz
// weve exited the loop here
fnop
or r0,itemp3,r0 // for exit condition code
fnop
bc .zb_exit
//}}}
//{{{ there are < 4 pixels to go - we have a good z in nuz, and a good col
//
// this is fortunate - if pixels left = 1, then we CANT have a -1
// mask in z_lo, since it would have bumped dx to 2
//
// so - if dx == 1 we mask off the high z and re-execute fzchk - otherwise
// dont fzchk as we need result of previous (in case of 1 pixel wide)
//
// this is VERY lucky ...
//
.last_few:
faddp b,db,b
ixfr minus1,z_hi
faddp g,dg,g
nop
faddp r,dr,r
xor 1, itemp3, r0
form f0,oddz
bnc .proceed // if dx!=1, goto proceed USE PREVIOUS PM 7..6
fzchkl oldz,z,nuz
nop
.proceed:
fzchks f0,f0,f0 // trash 4 PM bits
adds -2,itemp3,itemp3 // dx-=2
fzchkl f0,f0,f0 // and 2 more PM bits
fst.d nuz, 8(zaddr)++
faddz z,dz,z // so what for last 2 pixels ?
subs r0,itemp3,r0 // CC set if itemp3>0
form f0,f0 // trash merge register
pst.d col, 8(paddr)++
form oddz, col // copy oddz -> col for next iter
bc.t .last_few
fzchkl oldz,z,nuz
fld.d 16(zaddr), oldz
.zb_exit:
.enddual
form f0,f0
nop
form f0,f0
bri r1
nop
//}}}
#undef paddr
#undef zaddr
#undef ir
#undef ig
#undef ib
#undef iz
#undef dx
#undef idr
#undef idg
#undef idb
#undef idz
#undef itemp1
#undef itemp2
#undef itemp3
#undef itemp4
#undef minus1
//}}}
//{{{ texinit ( int idu, int idv, int compat, int idz )
.globl _texinit
.align 8
#define indu param1
#define indv param2
#define indz param4
#define itemp1 param5
_texinit::
// build dr*2 dg*2 dz*2
adds indu, indu,itemp1
and 0xffff, itemp1,itemp1
ixfr itemp1, du_lo
ixfr itemp1, du_hi
adds indv, indv,itemp1
and 0xffff, itemp1,itemp1
ixfr itemp1, dv_lo
ixfr itemp1, dv_hi
adds indz,indz,itemp1
ixfr itemp1, dz_lo // dz_lo=2*idz
bri r1
ixfr itemp1, dz_hi // dz_lo=2*idz
#undef indu
#undef indv
#undef indz
#undef itemp1
//}}}
//{{{ ftexline ( *fb, *zb, u, v, *tb, z, dx, du, dv, DUMMY ,dz )
.globl _ftexline
.align 8
#define paddr param1
#define zaddr param2
#define iu param3
#define iv param4
#define texbase param5
#define iz param6
#define dx param7
#define idu param8
#define idv param9
#define itemp2 param10
#define idz param11
#define itemp1 r27
#define itemp3 r28
#define itemp4 r29
#define txtemp1 r30
#define minus1 itemp1
_ftexline::
and 4,paddr,r0 // if paddr&7 == 0, cc set
bc .txaligned // so we jump if paddr&7==0, i.e aligned
.txunaligned: // ie first pixel NOT on a 64-bit boundary
//{{{
// align to double boundary
adds -12, zaddr, zaddr
adds -12, paddr, paddr
fld.d -8(zaddr), oldz // load zbuffer value (from &z0-4)
// correct for interpolant over-tick
subs iu, idu, itemp1
and 0xffff,itemp1,itemp1
ixfr itemp1, u_lo
and 0xffff,iu,itemp1
ixfr itemp1, u_hi
subs iv, idv, itemp1
and 0xffff,itemp1,itemp1
ixfr itemp1, v_lo
and 0xffff,iv,itemp1
ixfr itemp1, v_hi
ixfr iz, z_hi
subs iz, idz, iz
adds -1,r0,minus1
ixfr minus1, z_lo // important - zlo MUST be invisible for fchkz
adds 1,dx,dx // tick count
fzchkl oldz,z,nuz // z-check with frigged z
and 1,dx,itemp3 // itemp3 = extras on rhs
br .txaligned_path
ixfr iz, z_lo // correct z
//}}}
.txaligned: // ie first pixel IS on a 64-bit boundary
//{{{
//
// write iz into dbl z lo, iz+dz into dbl z hi etc
//
adds -8, zaddr, zaddr
adds -8, paddr, paddr
fld.d -8(zaddr), oldz // load zbuffer value HOURS to complete
ixfr iz, z_lo
adds iz, idz, iz
ixfr iz, z_hi // this needs 3 cycles to complete before fzchkl
and 0xffff,iu,itemp1
ixfr itemp1, u_lo
adds iu, idu, itemp1
and 0xffff,itemp1,itemp1
ixfr itemp1, u_hi
and 0xffff,iv,itemp1
ixfr itemp1, v_lo
adds iv, idv, itemp1
and 0xffff,itemp1,itemp1
ixfr itemp1, v_hi
adds -1,r0,minus1
fzchkl oldz,z,nuz // z-check with unfrigged z
and 1,dx,itemp3 // itemp3 = extras on rhs
//}}}
.txaligned_path: // above branches re-merge here
//{{{
.dual
form f0,f0 // clear merge to start up
or r0,dx,itemp2 // itemp2 = orig dx
faddp u,f0,f0
shr 1,dx,dx // dx now n of 2s
faddp v,f0,f0
adds -2, itemp2, r0 // goto last 2 if dx < 2
form f0,col
bc .txlast_few
fnop
adds -1,dx,dx // corrected for autoincrement, so test -3 below
fnop
bla minus1, dx, .txinner_loop
fnop
nop
//}}}
//{{{ 32-bit z, texture inner loop, 2 pixels at a time
.txinner_loop:
fxfr col_lo,txtemp1 // txtemp1 = interpolated u,v
nop
fxfr col_hi,itemp4 // itemp4 = interpolated hi u,v
fst.d nuz, 8(zaddr)++
faddz z,dz,z
shr 2,txtemp1,txtemp1 // drop 2 of 4 blue bits, i.e word address
fzchks f0,f0,f0 // drop 4 more bits
fld.l texbase(txtemp1),col_lo
fzchkl f0,f0,f0 // drop 2 more bits
shr 2,itemp4,itemp4
faddp u,du,u
fld.l texbase(itemp4),col_hi
faddp v,dv,v
pst.d col, 8(paddr)++
form f0,col
bla minus1,dx,.txinner_loop
fzchkl oldz,z,nuz
fld.d 16(zaddr), oldz
// weve exited the loop here
fnop
or r0,itemp3,r0
fnop
bc .tx_exit
//}}}
//{{{ there is just 1 pixel to go - we have a good z in nuz, and 2 good cols
//
.txlast_few:
fxfr col_lo,txtemp1 // txtemp1 = interpolated u,v
ixfr minus1,z_hi
fzchkl oldz,z,nuz
shr 2,txtemp1,txtemp1
fzchks f0,f0,f0 // trash 4 PM bits
fld.l texbase(txtemp1), col_lo
fzchkl f0,f0,f0 // and 2 more PM bits
fst.d nuz, 8(zaddr)++
fnop
pst.d col, 8(paddr)++
.tx_exit:
.enddual
form f0,f0
bri r1
form f0,f0
nop
//}}}
#undef paddr
#undef zaddr
#undef iu
#undef iv
#undef texbase
#undef iz
#undef dx
#undef idu
#undef idv
#undef idz
#undef itemp2
#undef itemp1
#undef itemp3
#undef itemp4
#undef txtemp1
#undef minus1
//}}}