//{{{ 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 100 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 // // //}}} // // 32-bit gouraud shaded z-buffered entrypoint // .globl _zbufferline .align 8 //{{{ do the funky gibbon //{{{ define registers // // 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 // // scanline ( int *fbuffer, int *zbuffer, // int ir, int ig, int ib, int iz, // int idr, int idg, int idb, int idz, int dx ) // // // // // FUNCTION PARAMETERS // #define paddr r16 #define zaddr r17 #define ir r18 #define ig r19 #define ib r20 #define iz r21 #define idr r22 #define idg r23 #define idb r24 #define idz r25 #define dx r26 // // 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 b_lo f12 #define b_hi f13 #define b b_lo #define z_lo f14 #define z_hi f15 #define z z_lo // interpolant delta values #define dr_lo f16 #define dr_hi f17 #define dr dr_lo #define dg_lo f18 #define dg_hi f19 #define dg dg_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 dbltmp f30 // integer temporaries #define itemp1 r27 #define itemp2 r28 #define itemp3 r29 #define itemp4 r30 #define minus1 itemp1 //}}} _zbufferline: adds -5,dx,r0 bnc .zb_optimise // if dx >= 17, GOTO optimise (i.e at least 2 runs) //{{{ short-run setup ixfr ib, b_lo ixfr ig, g_lo br .tidy_up ixfr ir, r_lo //}}} .zb_optimise: //{{{ fast z-buffer loop // construct floating-point 2dr 2dg 2db 2dz //{{{ addu idr,idr,itemp1 ixfr itemp1, dr_lo addu idg,idg,itemp1 ixfr itemp1, dg_lo addu idb,idb,itemp1 ixfr itemp1, db_lo addu idz,idz,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 fmov.ss ddz_lo,ddz_hi and 4,paddr,r0 // if paddr&7 == 0, cc set bc .aligned // so we jump if paddr&7==0, i.e aligned //}}} // on entering inner loop, we need a col and an oldz, and we need // paddr and zaddr down-ticked // unaligned branch //{{{ // ir corresponds to high word of 64-bit pair, so we down tick to // get ir_lo etc. // // 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 ixfr ir, r_lo ixfr ig, g_lo ixfr ib, b_lo adds -1,r0,minus1 ixfr minus1, z_lo // important - zlo MUST be invisible for fchkz // align to double boundary adds -12, zaddr, zaddr adds -4, paddr, paddr // the branch destination adds -8! fld.d 8(zaddr), oldz // load zbuffer value (from &z0-4) 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: //{{{ // // write iz into dbl z lo, iz+dz into dbl z hi etc // 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 fld.d r0(zaddr), oldz // load zbuffer value ixfr ib, b_hi ixfr ig, g_hi ixfr ir, r_hi ixfr iz, z_hi adds -1,r0,minus1 adds -8, zaddr, zaddr and 3,dx,itemp3 // itemp3 = extras on rhs .dual fzchkl oldz,z,nuz // z-check with unfrigged z nop .aligned_path: faddp b,f0,f0 shr 2,dx,dx faddp g,f0,f0 adds -1,dx,dx // fix dx for by 8 inner loop faddp r,f0,f0 bla minus1, dx, .inner_loop form f0,col adds -8, paddr, paddr //}}} // THIS IS THE INNER LOOP //{{{ 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 nop faddp b,db,b fst.d nuz, 8(zaddr)++ faddp g,dg,g pst.d col, 8(paddr)++ faddp r,dr,r nop 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 //}}} // on exit, we have yet to do itemp3 loops // not only that but zaddr and paddr are pointing 8 ahead // we have a formed colour and have read oldz // however, we just HAVE to read oldz again, // but we can fix the pointers .enddual fmov.ss f0, f0 or r0,itemp3,dx fnop bc .slow_exit adds 8,zaddr,zaddr adds 8,paddr,paddr fxfr z_lo, iz //}}} // this is the entrypoint for short runs - .tidy_up: //{{{ short runs, deltas hold single click, dx holds pixels_left-1 // loop doing simple z-buffer // ixfr idr, dr_lo ixfr idg, dg_lo ixfr idb, db_lo .dual faddp b,f0,f0 adds -1, r0, minus1 // set up decrementing counter faddp g,f0,f0 adds minus1, dx, dx // correct for bla faddp r,f0,f0 bla minus1,dx,.longhand_loop // SET UP LCC ! ! ! required by bla form f0,col adds -4, paddr, paddr .longhand_loop: faddp b,db,b ld.l r0(zaddr), itemp3 fnop subu iz,itemp3,r0 fnop bnc.t .do_replace faddp g,dg,g fst.l col, 4(paddr)++ .no_replace: // walk pointers to pixel + colour fnop addu 4,zaddr,zaddr fnop addu 4,paddr,paddr faddp r,dr,r bla minus1, dx, .longhand_loop form f0,col adds iz,idz,iz fnop br .slow_exit fnop nop .do_replace: // replace pixel / zixel faddp r,dr,r addu 4,zaddr,zaddr fnop st.l iz, -4(zaddr) form f0,col bla minus1, dx, .longhand_loop fnop adds iz,idz,iz // right, weve done .slow_exit: .enddual fmov.ss f0,f0 bri r1 fnop nop //}}} //{{{ undefine registers #undef paddr #undef zaddr #undef ir #undef ig #undef ib #undef iz #undef idr #undef idg #undef idb #undef idz #undef dx // // LOCALS // // // interpolant values #undef r_lo #undef r_hi #undef r #undef g_lo #undef g_hi #undef g #undef b_lo #undef b_hi #undef b #undef z_lo #undef z_hi #undef z // interpolant delta values #undef dr_lo #undef dr_hi #undef dr #undef dg_lo #undef dg_hi #undef dg #undef db_lo #undef db_hi #undef db #undef dz_lo #undef dz_hi #undef dz // double-length float temporaries #undef oldz_lo #undef oldz_hi #undef oldz #undef nuz #undef col // integer temporaries #undef itemp1 #undef itemp2 #undef itemp3 #undef itemp4 #undef minus1 //}}} //}}} // // simple 1 pixel at a time texturing // .globl _textureline .align 8 //{{{ texture (YEAH!) //{{{ define registers // // texline ( int *fbuffer, int *zbuffer, // int iu, int iv, int iz, // int idu, int idv, int idz, int texbase ) // // FUNCTION PARAMETERS // #define paddr r16 #define zaddr r17 #define ir r18 #define ig r19 #define iz r20 #define idr r21 #define idg r22 #define idz r23 #define tex_base r24 #define dx r25 // // LOCALS // // // interpolant values #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 dblspare f12 #define z_lo f14 #define z_hi f15 #define z z_lo // interpolant delta values #define dr_lo f16 #define dr_hi f17 #define dr dr_lo #define dg_lo f18 #define dg_hi f19 #define dg dg_lo #define tex_val1 f20 #define tex_val2 f21 #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_lo f28 #define col_hi f29 #define col col_lo #define dbltmp f30 // integer temporaries #define itemp1 r27 #define itemp2 r28 #define itemp3 r29 #define itemp4 r30 #define minus1 itemp1 //}}} _textureline: //{{{ setup .tx_slow: // // build floating-point dr dg db registers // NB replace on new <= old // // or r1,r0, itemp2 // or r16,r0,itemp1 // // call _setpixelsize // or 1,r0,r16 // set pixel size to 16 bits // // or itemp2,r0,r1 // or itemp1,r0,r16 // fmov.dd f0, g // fmov.dd f0, dg // fmov.dd f0, r // fmov.dd f0, dr and 0xffff, idg, itemp1 ixfr itemp1, dg_lo // these are 16 bit deltas !!!! and 0xffff, idr, itemp1 ixfr itemp1, dr_lo and 0xffff, ig, itemp1 ixfr itemp1, g_lo and 0xffff, ir, itemp1 ixfr itemp1, r_lo //}}} //{{{ short runs, deltas hold single click, dx holds pixels_left-1 // // loop doing simple textured (!) z-buffer // // possible optimisation is to do 2 at a time, so we save on faddps // and stuff // // if we do fld.d, faddz, fchkz we can branch on PM // to determine visibility // // .dual faddp f0,f0,f0 adds -1, r0, minus1 // set up decrementing counter fnop adds minus1, dx, dx // correct for bla fnop bla minus1,dx,.t_longhand_loop // SET UP LCC ! ! ! required by bla fnop adds -4, paddr, paddr .t_longhand_loop: pfaddp g,dg,f0 addu 4,zaddr,zaddr pfaddp r,dr,g ld.l -4(zaddr), itemp3 pform f0,r addu 4,paddr,paddr pform f0,col subu iz,itemp3,r0 fxfr col_lo, itemp2 bnc.t .t_do_replace fnop st.l iz, -4(zaddr) .t_no_replace: // walk pointers to pixel + colour fnop bla minus1, dx, .t_longhand_loop fnop adds iz,idz,iz fnop br .t_slow_exit fnop nop .t_do_replace: // replace pixel / zixel fnop adds iz,idz,iz fnop fld.l tex_base(itemp2), tex_val1 fnop bla minus1, dx, .t_longhand_loop fnop fst.l tex_val1, r0(paddr) // right, weve done .t_slow_exit: .enddual fmov.ss f0,f0 bri r1 fnop nop //}}} //}}}