//{{{ 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 //}}}