Files
TeslaRel410/sda4/DPL3/VRENDER/PXPL5SUP/PXPL5SUP.C
T
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

1200 lines
31 KiB
C++

/*{{{ 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#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; i<grab_chunks; i++ ) {
bin->usage=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; x<binsx; x++ ) {
for (y=0; y<binsy; y++ ) {
i=x+(y*16);
screenbins[i].head=next_binchunk();
screenbins[i].tail=screenbins[i].head;
back_offs = init_screenbin ( screenbins[i].head,
x*64, y*128, hires );
bins_made++;
prevx=x;
prevy=y;
}
}
return bins_made;
}
/*}}} */
#if 0
/*{{{ void reinitbins ( screenbin *screenbins, int hires,*/
void reinitbins ( screenbin *screenbins, int hires,
int binsx, int binsy, int bins_made )
{
int x, y, i;
int prevx=-1, prevy=-1;
for (x=0; x<binsx; x++ ) {
for (y=0; y<binsy; y++ ) {
int *offs;
i=x+(y*16);
offs=&screenbins[i].head->DMA_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);
}
/*}}} */