/*{{{ Pixel-Planes V support code*/ /* ********************************** File pxpl5sup.c Project pazpl5 Author p j atkin (c) DIVISION Ltd 1993 */ /*}}} */ /*{{{ on pxpl5 oddness*/ /* pxpl5 forces you to do 3 things you normally wouldnt do on a graphics system - edgeize, planarize and binitize primitives edgeizing involves turning a polygon into a set of edges, each edge described by an expression of the form f(x,y) = Ax + By + C, where conventionally a point is INSIDE the edge if f(x,y) > 0 at (x,y) planarization is pretty similar, and is used for Z-buffering, Gouraud-shading and texturing. Planarization involves computing a screen-space planar equation for a given variable - so to Z-buffer, Gouraud-shade and texture a triangle we need to compute Z=fz(x,y), r=fr(x,y), g=fg(x,y), b=fb(x,y), u=fu(x,y), v=fv(x,y) where each of fz, fr, fg, fb, fu, fv are cast as expression of the form f=Ax + By + C binitization is different, and stems from the original MIMDness of pxpl5 - rather than build a 640x512 array of pixel-processors, we use multiple arrays of 128x128 (or 64x128) and if the polygons scatter statistically well, we can get many times more performance for a given number of pixel-processors in order to do this, as a triangle is transformed to screen-space, we need to determine how many screen-space regions of 64x128 are overlapped by the triangle, and place the triangle into 'bins' associated with each region. binitization may kill me yet. */ /*}}} */ /*{{{ includes*/ #include #include #include #include "..\dpltypes.h" #include "..\culltypes.h" #include "DMAengn.h" #include "pxpl5typ.h" #include "pxpl5tri.h" #include "divpxmap.h" #include "eof.h" #include "\projects\dbi0150\dbi0151\ucode\igc_opco.h" #include "\projects\dbi0150\dbi0151\ucode\igc_comm.h" /*}}} */ extern float* compute_phong_table ( float ); /* ********************************************** i860 XP memory management support */ /*{{{ from john world*/ #define physAddr(addr) (addr)&0xfffff000 #define PRESENT 0x001 #define WRITEABLE 0x002 #define USER 0x004 #define WRITE_THROUGH 0x008 #define CACHE_DISABLE 0x010 #define ACCESSED 0x020 #define DIRTY 0x040 #define CACHE_FLAGS (PRESENT | DIRTY | USER | WRITEABLE) extern int mapContiguousPages ( int type, int pages, int flags ); static int lastGrab=1; /*}}} */ /*{{{ static int *devirtualize ( int *virtual_address )*/ static int *devirtualize ( int *virtual_address ) { int address=(int) virtual_address; int low =address & 0xfff; int alias; alias=0xfffff000 & pageEntry ( address ); alias|=low; return (int *) alias; #if 0 /*{{{ massages*/ printf ("devirtualizing 0x%x to 0x%x\n", address, alias ); printf ("checking - pageEntry(0x%x) = 0x%x\n", address, pageEntry(address)); printf ("hitting alias\n" ); { int t=*((int *) alias); } printf ("hit alias\n" ); printf (" pageEntry(0x%x) = 0x%x\n", alias, pageEntry(alias)); /*}}} */ #endif } /*}}} */ /*{{{ static int *newPages ( int pages )*/ static int *newPages ( int pages ) { int i, *retVal; lastGrab^=1; retVal = (int *) mapContiguousPages ( -1, pages, CACHE_FLAGS ); /* flush(); */ return devirtualize(retVal); } /*}}} */ /*{{{ int *newBytes ( int bytes )*/ int *newBytes ( int bytes ) { int *t= (int *) newPages ((bytes + 4095) / 4096 ); return t; } /*}}} */ /* ********************************************** in-memory material and texture coding */ /*{{{ variables for opcode / coefficients*/ float *coefficient_ptr; coeffchunk *coeffstore0, *coeffstore1, *lastcoeffptr; /*}}} */ #if 0 /*{{{ pxpl5tri_fn pxpl5patch_triangleFunc ( PATCH *p, MATERIAL *m )*/ pxpl5tri_fn pxpl5patch_triangleFunc ( PATCH *p, MATERIAL *m ) { pxpl5tri_fn triathlon=(pxpl5tri_fn) &tri_zb_rgb; int strip=p->head->strip_shade; int texture=(m->tex) && (strip & strip_shade_textured); if (strip & (strip_shade_coloured | strip_shade_smooth)) { if (texture) triathlon = (pxpl5tri_fn) &tri_zb_rgb_t; else triathlon = (pxpl5tri_fn) &tri_zb_rgb; } else { if (texture) triathlon = (pxpl5tri_fn) &tri_zb_f_t; else triathlon = (pxpl5tri_fn) &tri_zb_f; } return triathlon; } /*}}} */ /*{{{ static int pxpl5mtl_texture ( MATERIAL *s, PATCH *p )*/ static int pxpl5mtl_texture ( MATERIAL *s, PATCH *p ) { #define offs_shift ((dvpx_texid)-(dvpx_scalar)) #define size_shift ((dvpx_texsize)-(dvpx_scalar)) #define ramp_shift ((dvpx_texrampsel)-(dvpx_scalar)) int tex=0; if (p->head->strip_shade & strip_shade_textured) { if (s->tex) { if (s->tex->map) { tex = (s->tex->map->hwareSize << size_shift) | (((s->tex->map->hwareOffs) & 63) << offs_shift) | ((s->ramp_entry & 0x3) << ramp_shift); } else { return 0; } } } return tex; } /*}}} */ /*{{{ static void pxpl5izeSurface ( MATERIAL *surf, PATCH *p )*/ static void pxpl5izeSurface ( MATERIAL *surf, PATCH *p ) { extern float *PAZ_phong_table; /* this fills in the pxpl5codeWord and the pp5tri_fn we need to compute the intrinsic colour based on kd */ int texture; texture = pxpl5mtl_texture ( surf, p ); surf->specular_table=compute_phong_table ( surf->power ); surf->pxpl5codeword =texture; surf->pxpl5opcode = 15 - (int) (15.0f * surf->opacity); surf->triangle_fn = pxpl5patch_triangleFunc ( p, surf ); } /*}}} */ /*{{{ void pxpl5izePatch ( PATCH *p, MATERIAL *front, MATERIAL *back )*/ void pxpl5izePatch ( PATCH *p, MATERIAL *front, MATERIAL *back ) { if (front && p) pxpl5izeSurface ( front, p ); if (back && p) pxpl5izeSurface ( back, p ); } /*}}} */ /*{{{ pxpl5tri_fn pxpl5patch_sphereFunc ( PATCH *p, MATERIAL *m )*/ pxpl5tri_fn pxpl5patch_sphereFunc ( PATCH *p, MATERIAL *m ) { extern float* sphere_zb_rgb ( float *coeffs, float material, int opcode1, VERTEX *v1, VERTEX *v2, VERTEX *v3 ); return (pxpl5tri_fn) &sphere_zb_rgb; } /*}}} */ /*{{{ static void pxpl5izeSphereSurface ( MATERIAL *surf, PATCH *p )*/ static void pxpl5izeSphereSurface ( MATERIAL *surf, PATCH *p ) { extern float *PAZ_phong_table; /* this fills in the pxpl5codeWord and the pp5tri_fn we need to compute the intrinsic colour based on kd */ surf->specular_table=compute_phong_table ( surf->power ); surf->pxpl5codeword =0; /*{{{ compute opcode1 from opacity (should be done in material?)*/ if (surf->opacity < 0.125f) { surf->pxpl5opcode = Ix_CLRENABS(); } else if (surf->opacity > 0.99f) { surf->pxpl5opcode = Ix_SETENABS(); } else if (surf->opacity < 0.249f ) { surf->pxpl5opcode = Ix_MEMintoENAB( dvpx_opaque_12 ); } else if (surf->opacity < 0.499f ) { surf->pxpl5opcode = Ix_MEMintoENAB( dvpx_opaque_25 ); } else if (surf->opacity < 0.749f ) { surf->pxpl5opcode = Ix_MEMintoENAB( dvpx_opaque_50 ); } else if (surf->opacity < 0.8749f ) { surf->pxpl5opcode = Ix_MEMBARintoENAB( dvpx_opaque_25 ); } else { surf->pxpl5opcode = Ix_MEMBARintoENAB( dvpx_opaque_12 ); } /*}}} */ surf->triangle_fn = pxpl5patch_sphereFunc ( p, surf ); } /*}}} */ /*{{{ void pxpl5izeSpheres ( PATCH *p, MATERIAL *front, MATERIAL *back )*/ void pxpl5izeSpheres ( PATCH *p, MATERIAL *front, MATERIAL *back ) { if (front && p) pxpl5izeSphereSurface ( front, p ); if (back && p) pxpl5izeSphereSurface ( back, p ); } /*}}} */ #endif /* ************************************ edgize, planarize support */ /*{{{ on planarization*/ /* Examination of the equations for planarization, and the UNC rendering library, indicates some useful speedups for planarizing. A recurring term is the divisor for all 3 coefficients, termed C. This is independent of the planarized variable; it only varies with screen-space X and Y, so can be precomputed once per triangle and re-used for all planarized expressions ditto some recurring difference expressions (x1 - x2 etc.) So preplanarize precomputes the useful stuff into a structure for subsequent planarizing. Ideally of course we precompute this into a set of floating-point registers. Later. Or maybe right now - how many registers do I need to do this? rx23 \ rx31 > the recurring differences rx12 / rC the divisor for preplanarizing; now to planarize, strive to keep rv1y rv2y rv3y rv1x rv2x and rv3x in registers also so we keep 10 fp registers hanging around, so to planarize a variable we access memory 3 times, to load v1 v2 v3 (which are used many times) using up just 13 fp registers then 3 writes to eqn->A, eqn->B, eqn->C this should be very fast indeed on an XP The correct structure for the code is probably a dispatch vector of C functions associated with each type of triangle - e.g 24-bit Gouraud, 8-bit Gouraud + intrinsic + spec 8-bit Gouraud + intrinsic + spec + texture + MIP etc, the function calls an assembly stub which preplanarizes, then repeatedly calls an assembly-coded planarize as many times as needed Planarization looks like a cost of 25 ticks per planarized variable, so we can planarize Z, diffuse, spec in 1.5 uS (667k triangles/sec) Z, diffuse, spec, u, v, homo in 3uS (333k ) Z, diffuse, spec, u, v, homo, MIP in 3.5uS, or (286k ) it looks like we can edgize in about 20 ticks per edge, or 1.2 uS per triangle, so the edgize / planarize costs become Z, diffuse, spec in 2.7 uS (370k triangles/sec) Z, diffuse, spec, u, v, homo in 4.2 uS (238k ) Z, diffuse, spec, u, v, homo, MIP in 3.5uS, or (212k ) or the VWE benchmark of flat-shaded textured quads - Z, u, v, homo, MIP in 3.6uS or (278k ) SO we are in shape performance-wise for planarization. How is binitizing. Read on. */ /*}}} */ /*{{{ void preplanarize ( preplane *p, float *v1, float *v2, float *v3 )*/ void preplanarize ( preplane *p, float *v1, float *v2, float *v3 ) { float v1x=v1[X]; float v2x=v2[X]; float v3x=v3[X]; float v1y=v1[Y]; float v2y=v2[Y]; float v3y=v3[Y]; p->x23=v2x - v3x; p->x31=v3x - v1x; p->x12=v1x - v2x; p->C=1.0f / ((v1x * (v2y - v3y)) + (v2x * (v3y - v1y)) + (v3x * (v1y - v2y))); printf ("preplanarize, computed C=%f x12=%f x23=%f x31=%f\n", p->C, p->x12, p->x23, p->x31 ); } /*}}} */ /*{{{ void planarize ( float *eqn, float *v1, float *v2, float *v3, int index, preplane *p )*/ void planarize ( float *eqn, float *v1, float *v2, float *v3, int index, preplane *p ) { float v1x=v1[X]; float v2x=v2[X]; float v3x=v3[X]; float v1y=v1[Y]; float v2y=v2[Y]; float v3y=v3[Y]; float v1f=v1[index]; float v2f=v2[index]; float v3f=v3[index]; printf ( "planarize - f1 = %f, f2=%f, f3=%f\n", v1f, v2f, v3f ); printf ( " x1 = %f, x2=%f, x3=%f y1=%f y2=%f y3=%f\n", v1x, v2x, v3x, v1y, v2y, v3y ); eqn[0]=-p->C* ((v1y * (v2f - v3f)) + (v2y * (v3f - v1f)) + (v3y * (v1f - v2f))); eqn[1]=-p->C*((v1f * p->x23) + (v2f * p->x31) + (v3f * p->x12)); eqn[2]= p->C*((v1x*((v2y*v3f) - (v3y*v2f))) + (v2x*((v3y*v1f) - (v1y*v3f))) + (v3x*((v1y*v2f) - (v2y*v1f)))); } /*}}} */ /*{{{ void tex_fixz ( float *z1, float *z2, float *z3 )*/ void tex_fixz ( float *z1, float *z2, float *z3 ) { float p=0.99f; int *iz1=(int *) z1; int *iz2=(int *) z2; int *iz3=(int *) z3; int one, v1, v2, v3, max, bump; one = *(int *) &p; printf ("\nbefore tex_fixz - z1=%4.4f z2=%4.4f z3=%4.4f\n", *z1, *z2, *z3 ); v1=*iz1; v2=*iz2; v3=*iz3; if (v1 > v2) { if (v1 > v3) { max=v1; } else { max=v3; } } else { if (v2 > v3) { max=v2; } else { max=v3; } } bump = (126 << 23) - (max & 0x7f800000); printf ("bump computed as %d\n", 1<<(bump>>23) ); v1+=bump; v2+=bump; v3+=bump; *(int *) z1=v1; *(int *) z2=v2; *(int *) z3=v3; printf ("after tex_fixz - z1=%4.4f z2=%4.4f z3=%4.4f\n", *z1, *z2, *z3 ); } /*}}} */ /*{{{ */ /* ********************* takes 2 point p1 and p2 and computes the edge equation edge Ax + By + C, +ve inside, -ve outside the edge 4 cases - a) p0 b) p1 \ / \ / \ / p1 p0 c) p1 d) p0 \ / \ / \ / p0 p1 We need to ensure that in all cases we treat the edges identically, e.g a = c with flipped vertices / opcode, ditto b, d */ /*}}} */ /*{{{ void edgeize ( float *eqn, float *p1, float *p2 )*/ void edgeize ( float *eqn, float *p1, float *p2 ) { /* however, 1st approximation - this will suffer rounding errors + DDA cracks */ eqn[0] = p1[Y] - p2[Y]; eqn[1] = p2[X] - p1[X]; eqn[2] =(p2[Y]*p1[X]) - (p2[X]*p1[Y]); } /*}}} */ /* ************************************ binitize support */ /*{{{ variables for binning*/ binchunk *free_binchunks=NULL; screenbin *screen0bins = NULL, *screen1bins = NULL, *screenbins = NULL; screenbin *trans_screen0bins = NULL, *trans_screen1bins = NULL, *trans_screenbins = NULL; int DMAscreen=0, writeScreen=1; /*}}} */ /*{{{ static void grab_binchunks ( int grab_chunks )*/ static void grab_binchunks ( int grab_chunks ) { /* mallocs and inits an initial tranche of binchunks */ int i; binchunk *bin; bin=(binchunk *) newBytes ( grab_chunks * sizeof(binchunk)); if (bin == NULL) { printf ("Malloc failed in grab_binchunk\n" ); exit(666); } for (i=0; iusage=0; bin->next=free_binchunks; free_binchunks=bin; bin++; } } /*}}} */ /*{{{ binchunk *next_binchunk ()*/ binchunk *next_binchunk () { binchunk *chunky; if (free_binchunks == NULL) { grab_binchunks(16); } chunky=free_binchunks; free_binchunks=free_binchunks->next; chunky->usage=0; chunky->next=NULL; return chunky; } /*}}} */ /*{{{ coeffchunk *next_coeffchunk ()*/ coeffchunk *last_coeffchunk =NULL; coeffchunk *last_coeffchunk0=NULL; coeffchunk *last_coeffchunk1=NULL; coeffchunk *next_coeffchunk () { coeffchunk *chunky; coeffchunk *lcc=last_coeffchunk; if (lcc==NULL) { printf ("severe error, last_coeff_chunk NULL\n\n\n" ); return NULL; } if (lcc->next) { /* re-use old guy from list */ chunky=lcc->next; last_coeffchunk=chunky; return chunky; } else { /* list exhausted, grab a new one */ chunky=newBytes(sizeof(coeffchunk)); if (chunky) chunky->next=NULL; else { printf ("Warning, out of coefficient store\n" ); } lcc->next=chunky; last_coeffchunk=chunky; return chunky; } } /*}}} */ int back_offs=0; /*{{{ static int initbins ( screenbin *screenbins, int hires, int bins_x, int bins_y, int bins_made )*/ static int initbins ( screenbin *screenbins, int hires, int binsx, int binsy, int bins_made ) { int x, y, i; int prevx=-1, prevy=-1; for (x=0; xDMA_opcodes[fuckyoffs+64]; /* int *DMAptr = &firstbin->DMA_opcodes[0]; */ IGC_CPY ( offs, dvpx_opacity, dvpx_texu+FUCKING_OFFSET, dvpx_opacitybits ); prevx=x; prevy=y; } } return bins_made; } /*}}} */ /*{{{ void reinit_screenbins ( int screenx, int screeny, int hires )*/ void reinit_screenbins ( int screenx, int screeny, int hires ) { int binsx=screenx >> divpl5_xshift; int binsy=screeny >> divpl5_yshift; int bins_made=0, i, j, x, y; reinitbins ( screen0bins, hires, binsx, binsy, bins_made ); reinitbins ( screen1bins, hires, binsx, binsy, bins_made ); reinitbins ( trans_screen0bins, hires, binsx, binsy, bins_made ); reinitbins ( trans_screen1bins, hires, binsx, binsy, bins_made ); } /*}}} */ #endif /*{{{ void create_screenbins ( int screenx, int screeny, int coeff_words )*/ void create_screenbins ( int screenx, int screeny, int hires ) { int binsx=screenx >> divpl5_xshift; int binsy=screeny >> divpl5_yshift; int bins_made=0, i, j, x, y; /* printf ("create_screenbins, %d by %d\n", screenx, screeny ); */ /*{{{ create bins 0*/ screen0bins=(screenbin *) malloc (binsx*binsy*sizeof(screenbin)); if (screen0bins == NULL) { printf ("Failed to malloc screenbins0\n" ); exit (666); } /*}}} */ /*{{{ and bins 1*/ screen1bins=(screenbin *) malloc (binsx*binsy*sizeof(screenbin)); if (screen1bins == NULL) { printf ("Failed to malloc screenbins1\n" ); exit (666); } /*}}} */ /*{{{ create transp bins 0*/ trans_screen0bins=(screenbin *) malloc (binsx*binsy*sizeof(screenbin)); if (trans_screen0bins == NULL) { printf ("Failed to malloc screenbins0\n" ); exit (666); } /*}}} */ /*{{{ and bins 1*/ trans_screen1bins=(screenbin *) malloc (binsx*binsy*sizeof(screenbin)); if (trans_screen1bins == NULL) { printf ("Failed to malloc screenbins1\n" ); exit (666); } /*}}} */ bins_made=initbins ( screen0bins, hires, binsx, binsy, bins_made ); bins_made=initbins ( screen1bins, hires, binsx, binsy, bins_made ); bins_made=initbins ( trans_screen0bins, hires, binsx, binsy, bins_made ); bins_made=initbins ( trans_screen1bins, hires, binsx, binsy, bins_made ); screenbins = screen0bins; trans_screenbins = trans_screen0bins; grab_binchunks(256); /*{{{ coeff store 0*/ coeffstore0=newBytes(sizeof(coeffchunk)); if (coeffstore0 == NULL) { printf ("Failed to malloc coeffs0\n" ); exit (666); } else coeffstore0->next=NULL; /*}}} */ /*{{{ and store 1*/ coeffstore1=newBytes(sizeof(coeffchunk)); if (coeffstore1 == NULL) { printf ("Failed to malloc coeffs1\n" ); exit (666); } else coeffstore1->next=NULL; /*}}} */ lastcoeffptr = coeffstore0; last_coeffchunk0 = coeffstore0; last_coeffchunk1 = coeffstore1; last_coeffchunk = last_coeffchunk0; coefficient_ptr = lastcoeffptr; /* printf ("created %d screenbins, screenbins at 0x%x trans_bins at 0x%x\n", bins_made, (int) screenbins, (int) trans_screenbins ); */ } /*}}} */ /*{{{ void liberate_screenbins ( screenbin *bins,*/ void liberate_screenbins ( screenbin *bins, int screenx, int screeny ) { /* ******************** take the whole screen and put it back onto the free list, EXCEPT for 1st chunk in each screen region The 1st chunk contains pxpl5 config stuff for this screen bin, and should not be dicked with - word 63 in the chunk indicates how many 64-bit words of startup are in the chunk, and hence how to patch the usage ... this is really tacky. So dont forget how it works. **************** */ int i, j, opcodes; binchunk *chunk, *fbc=free_binchunks; screenbin *lbin=screenbins; if (bins->head==NULL) { printf ("WHOAH - NULL head bins=0x%x lbins=0x%x\n", bins, lbin ); while (1) ; } else opcodes=bins->head->DMA_opcodes[63]; for (i=screenx>>divpl5_xshift; i; i-- ) { for (j=screeny>>divpl5_yshift; j; j-- ) { binchunk *heed=bins->head; chunk=heed->next; if (chunk) { /* *************************** simply chain the whole shooting match into the free list !!! chunk is the head of a partial freelist, which ends at bins->tail, so point bins->tail->next at current freechunk, then set current freechunk to chunk, and that's it ************************* */ bins->tail->next=fbc; fbc=chunk; } bins->tail = heed; heed->next = NULL; heed->usage = opcodes; bins++; } } free_binchunks=fbc; } /*}}} */ /*{{{ void binitize ( int macro_lo, int macro_hi,*/ void binitize ( int macro_lo, int macro_hi, float fminx, float fminy, float fmaxx, float fmaxy, int screen_maxx, int screen_maxy, int screen_bins_x ) { /* binitizes a primitive of known screen-space extents the DMA engine macros associated with the primitive are held in macro_lo, macro_hi - typically { SEND macro_address,size } the screen-space extents are held in fminx .. fmaxy, and the integer screen resolution is held in screen_maxx, screen_maxy, with (optimization) the bin-count in the x-direction held in screen_bins_x To binitize, we first work out what is the lower left corner bin, then outer loop in y, inner loop x, dropping the macro into all encountered bins. */ int minx, miny, maxx, maxy; minx=(int) fminx; miny=(int) fminy; maxx=(int) fmaxx; maxy=(int) fmaxy; if (maxx < 0) return; if (maxy < 0) return; if (minx > screen_maxx) return; if (miny > screen_maxy) return; if (maxx > screen_maxx) maxx=screen_maxx; if (maxy > screen_maxy) maxy=screen_maxy; if (minx < 0) minx=0; if (miny < 0) miny=0; minx >>= divpl5_xshift; miny >>= divpl5_yshift; maxx >>= divpl5_xshift; maxy >>= divpl5_yshift; /* so we have minimax xy in screen-space bin indices - put the data into bins */ { /* get 1st bin */ int screenbinix=(miny*screen_bins_x) + minx; screenbin *top_left_bin=&screenbins[screenbinix]; screenbin *lbin=top_left_bin; screenbin *xbin=lbin; register int x, y; /* scan down all y bins */ for (y=(maxy-miny)+1; y; y-- ) { /* scan across all x bins */ xbin=lbin; for (x=(maxx-minx)+1; x; x-- ) { /* add doubleword macro to bin */ register binchunk *bin=xbin->tail; register int usage=(bin->usage)>>2; if (bin->usage == BIN_FULL) { binchunk *nextbin=next_binchunk (); bin->DMA_opcodes[usage++]=(int) nextbin; bin->DMA_opcodes[usage++]=DMA_GOTO; bin=nextbin; xbin->tail=bin; usage=0; } bin->DMA_opcodes[usage++]=macro_lo; bin->DMA_opcodes[usage++]=macro_hi; bin->usage=usage<<2; xbin++; } lbin+=screen_bins_x; } } } /*}}} */ /*{{{ float *safe_binitize ( int macro_lo, int macro_hi,*/ float *safe_binitize ( int macro_lo, int macro_hi, float fminx, float fminy, float fmaxx, float fmaxy, int screen_bins_x ) { /* binitizes a primitive of known screen-space extents the DMA engine macros associated with the primitive are held in macro_lo, macro_hi - typically { SEND macro_address,size } the screen-space extents are held in fminx .. fmaxy, and the integer screen resolution is held in screen_maxx, screen_maxy, with (optimization) the bin-count in the x-direction held in screen_bins_x To binitize, we first work out what is the lower left corner bin, then outer loop in y, inner loop x, dropping the macro into all encountered bins. */ int minx, miny, maxx, maxy; minx=(int) fminx; miny=(int) fminy; maxx=(int) fmaxx; maxy=(int) fmaxy; minx >>= divpl5_xshift; miny >>= divpl5_yshift; maxx >>= divpl5_xshift; maxy >>= divpl5_yshift; /* so we have minimax xy in screen-space bin indices - put the data into bins */ { /* get 1st bin */ int screenbinix=(miny*screen_bins_x) + minx; screenbin *top_left_bin=&screenbins[screenbinix]; screenbin *lbin=top_left_bin; screenbin *xbin=lbin; register int x, y; /* scan down all y bins */ for (y=(maxy-miny)+1; y; y-- ) { /* scan across all x bins */ xbin=lbin; for (x=(maxx-minx)+1; x; x-- ) { /* add doubleword macro to bin */ register binchunk *bin=xbin->tail; register int usage=bin->usage >> 2; if (bin->usage == BIN_FULL) { binchunk *nextbin=next_binchunk (); bin->DMA_opcodes[usage++]=(int) nextbin; bin->DMA_opcodes[usage++]=DMA_GOTO; bin=nextbin; xbin->tail=bin; usage=0; } bin->DMA_opcodes[usage++]=macro_lo; bin->DMA_opcodes[usage++]=macro_hi; bin->usage=usage << 2; xbin++; } lbin+=screen_bins_x; } } return coefficient_ptr; } /*}}} */ /* ********************************************** pxpl5 debugging / tracing code */ /*{{{ void trace_regs ( int *r0 )*/ void trace_regs ( int *r0, char *str ) { int i; float *f0=(float *) &r0[31]; printf ("Trace regs %s\n", str ); fflush(stdout); for (i=0; i<31; i++) { if ((i&3) == 3) printf ("\n"); printf ("r%2d= 0x%8x ", i+1, r0[i] ); } for (i=0; i<30; i++) { if ((i&1) == 0) printf ("\n"); printf ("f%2d= %6.4f (0x%8x) ", i+2, f0[i], ((int *) f0)[i] ); } printf ("\n"); fflush(stdout); } /*}}} */ /*{{{ static char *macro_name ( int macro )*/ static char *macro_name ( int macro ) { char *c; int fourbits=0x0f&(macro>>28); switch (fourbits) { case 0x0 : c= "GOTO "; break; case 0x1 : c= "SEND "; break; case 0x5 : c= "LSEND "; break; case 0x9 : c= "SENDE "; break; case 0xa : c= "LSENDE"; break; case 0x2 : c= "TILE "; break; case 0x3 : c= "TXDN "; break; case 0x7 : c= "RETE "; break; case 0xf : c= "STOP "; break; case 0x6 : c= "FLUSH "; break; default : c= "illegal macro"; break; } return c; } /*}}} */ /*{{{ void dump_bins ( screenbin *bins, int bins_x, int bins_y, int dump_coeffs )*/ void dump_bins ( screenbin *bins, int tile_x, int tile_y, int dump_coeffs ) { int i, j, address, macro; screenbin *thisbin; binchunk *chunk; printf ("Dump_bins tile address %d, %d \n", tile_x, tile_y ); thisbin=&bins[tile_x+(tile_y * (1024 / 64))]; chunk=thisbin->head; printf ( "head 0x%x tail 0x%x\n", (int) thisbin->head, (int) thisbin->tail ); if (chunk == NULL) { printf ("Error, fully empty region in dump_bins\n" ); } else { int dumping=1; while (dumping) { int usage=chunk->usage; /* usage now in bytes ! */ int index=0; if (usage == 0) dumping=0; else { while (usage) { address=chunk->DMA_opcodes[index++]; macro =chunk->DMA_opcodes[index++]; usage-=8; if ((macro&DMA_CMD_MASK) == DMA_GOTO_VAL) { printf ("GOTO 0x%x\n", address ); chunk=(binchunk *) address; usage=chunk->usage; index=0; } else if ((macro&DMA_CMD_MASK) == DMA_SEND_VAL) { printf ("SEND 0x%x %d words\n", address, macro&DMA_SIZE_MASK ); } else { printf ("WEIRD macro 0x%x address 0x%x\n", macro, address ); dumping=0; } } if (chunk == thisbin->tail) printf ("DONE : ran off end of tail\n" ); else printf ("ERROR : ran off end of list\n" ); dumping=0; } } } } /*}}} */ /*{{{ void tracepixelmap ()*/ void tracepixelmap () { return; #if 0 /*{{{ */ printf ("dvpx_io is %d\n", dvpx_io ); printf ("dvpx_texu is %d\n", dvpx_texu ); printf ("dvpx_texv is %d\n", dvpx_texv ); printf ("dvpx_texmip is %d\n", dvpx_texmip ); printf ("dvpx_texz is %d\n", dvpx_texz ); printf ("dvpx_zbuf is %d\n", dvpx_zbuf ); printf ("dvpx_scalar is %d\n", dvpx_scalar ); printf ("dvpx_pixcolourtype is %d\n", dvpx_pixcolourtype ); printf ("dvpx_texsize is %d\n", dvpx_texsize ); printf ("dvpx_texid is %d\n", dvpx_texid ); printf ("dvpx_intrinsic is %d\n", dvpx_intrinsic ); printf ("dvpx_texrampsel is %d\n", dvpx_texrampsel ); printf ("dvpx_r24 is %d\n", dvpx_r24 ); printf ("dvpx_g24 is %d\n", dvpx_g24 ); printf ("dvpx_diffuse is %d\n", dvpx_diffuse ); printf ("dvpx_b24 is %d\n", dvpx_b24 ); printf ("dvpx_specular is %d\n", dvpx_specular ); printf ("dvpx_opaque_50 is %d\n", dvpx_opaque_50 ); printf ("dvpx_opaque_25 is %d\n", dvpx_opaque_25 ); printf ("dvpx_opaque_12 is %d\n", dvpx_opaque_12 ); printf ("dvpx_eofenblsave is %d\n", dvpx_enblsave ); printf ("dvpx_eofr is %d\n", dvpx_eofr ); printf ("dvpx_eofg is %d\n", dvpx_eofg ); printf ("dvpx_eofb is %d\n", dvpx_eofb ); printf ("dvpx_eofsubu is %d\n", dvpx_eofsubu ); printf ("dvpx_eofsubv is %d\n", dvpx_eofsubv ); printf ("dvpx_eofspec is %d\n", dvpx_eofspec ); printf ("dvpx_eofpixtype is %d\n", dvpx_eofpixtype ); printf ("dvpx_eoftexramp is %d\n", dvpx_eoftexramp ); printf ("dvpx_freebit is %d\n", dvpx_freebit ); /*}}} */ #endif } /*}}} */ /*{{{ void binitize_fail ( int code, float fminx, fminy, fmaxx, fmaxy )*/ void binitize_fail ( int code, float fminx, float fminy, float fmaxx, float fmaxy ) { printf ( "Binitize fail - exit code %d, minx %f miny %f maxx %f maxy %f\n", code, fminx, fminy, fmaxx, fmaxy ); exit (0); } /*}}} */