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>
615 lines
15 KiB
Scheme
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
|
|
//}}}
|
|
|