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>
1200 lines
31 KiB
C++
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);
|
|
}
|
|
/*}}} */
|
|
|