Search
lxdream.org :: lxdream/src/pvr2/tacore.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/pvr2/tacore.c
changeset 215:f432833e8303
prev206:f5de539c0fcb
next305:1191085c5988
author nkeynes
date Wed Jan 03 09:00:17 2007 +0000 (17 years ago)
permissions -rw-r--r--
last change Adjust timers when they're read rather than waiting until the next time
slice. Also temporarily cut the CPU time by 4.
Initialize the FRQCR register to 0x0E0A for convenience
view annotate diff log raw
     1 /**
     2  * $Id: tacore.c,v 1.9 2006-08-18 12:43:24 nkeynes Exp $
     3  *
     4  * PVR2 Tile Accelerator implementation
     5  *
     6  * Copyright (c) 2005 Nathan Keynes.
     7  *
     8  * This program is free software; you can redistribute it and/or modify
     9  * it under the terms of the GNU General Public License as published by
    10  * the Free Software Foundation; either version 2 of the License, or
    11  * (at your option) any later version.
    12  *
    13  * This program is distributed in the hope that it will be useful,
    14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    16  * GNU General Public License for more details.
    17  */
    18 #include "pvr2.h"
    19 #include "asic.h"
    21 #define STATE_IDLE                 0
    22 #define STATE_IN_LIST              1
    23 #define STATE_IN_POLYGON           2
    24 #define STATE_EXPECT_POLY_BLOCK2   3
    25 #define STATE_EXPECT_VERTEX_BLOCK2 4
    26 #define STATE_ERROR                5
    27 #define STATE_EXPECT_END_VERTEX_BLOCK2 7
    29 #define TA_CMD(i) ( (i) >> 29 )
    30 #define TA_CMD_END_LIST 0
    31 #define TA_CMD_CLIP 1
    32 #define TA_CMD_POLYGON_CONTEXT 4
    33 #define TA_CMD_SPRITE_CONTEXT 5
    34 #define TA_CMD_VERTEX 7
    36 #define TA_LIST_NONE -1
    37 #define TA_LIST_OPAQUE 0
    38 #define TA_LIST_OPAQUE_MOD 1
    39 #define TA_LIST_TRANS 2
    40 #define TA_LIST_TRANS_MOD 3
    41 #define TA_LIST_PUNCH_OUT 4
    42 #define TA_IS_MODIFIER_LIST(list) (list == TA_LIST_OPAQUE_MOD || list == TA_LIST_TRANS_MOD)
    44 #define TA_GROW_UP 0
    45 #define TA_GROW_DOWN 1
    47 #define TA_VERTEX_NONE                        -1
    48 #define TA_VERTEX_PACKED                      0x00
    49 #define TA_VERTEX_TEX_PACKED                  0x08
    50 #define TA_VERTEX_TEX_SPEC_PACKED             0x0C
    51 #define TA_VERTEX_TEX_UV16_PACKED             0x09
    52 #define TA_VERTEX_TEX_UV16_SPEC_PACKED        0x0D
    53 #define TA_VERTEX_FLOAT                       0x10
    54 #define TA_VERTEX_TEX_FLOAT                   0x18
    55 #define TA_VERTEX_TEX_SPEC_FLOAT              0x1C
    56 #define TA_VERTEX_TEX_UV16_FLOAT              0x19
    57 #define TA_VERTEX_TEX_UV16_SPEC_FLOAT         0x1D
    58 #define TA_VERTEX_INTENSITY                   0x20
    59 #define TA_VERTEX_TEX_INTENSITY               0x28
    60 #define TA_VERTEX_TEX_SPEC_INTENSITY          0x2C
    61 #define TA_VERTEX_TEX_UV16_INTENSITY          0x29
    62 #define TA_VERTEX_TEX_UV16_SPEC_INTENSITY     0x2D
    63 #define TA_VERTEX_PACKED_MOD                  0x40
    64 #define TA_VERTEX_TEX_PACKED_MOD              0x48
    65 #define TA_VERTEX_TEX_SPEC_PACKED_MOD         0x4C
    66 #define TA_VERTEX_TEX_UV16_PACKED_MOD         0x49
    67 #define TA_VERTEX_TEX_UV16_SPEC_PACKED_MOD    0x4D
    68 #define TA_VERTEX_INTENSITY_MOD               0x60
    69 #define TA_VERTEX_TEX_INTENSITY_MOD           0x68
    70 #define TA_VERTEX_TEX_SPEC_INTENSITY_MOD      0x6C
    71 #define TA_VERTEX_TEX_UV16_INTENSITY_MOD      0x69
    72 #define TA_VERTEX_TEX_UV16_SPEC_INTENSITY_MOD 0x6D
    73 #define TA_VERTEX_SPRITE                      0x80
    74 #define TA_VERTEX_TEX_SPRITE                  0x88
    75 #define TA_VERTEX_MOD_VOLUME                  0x81
    76 #define TA_VERTEX_LISTLESS                    0xFF
    78 #define TA_IS_NORMAL_POLY() (ta_status.current_vertex_type < TA_VERTEX_SPRITE)
    80 static int strip_lengths[4] = {3,4,6,8}; /* in vertexes */
    81 #define TA_POLYCMD_LISTTYPE(i) ( ((i) >> 24) & 0x0F )
    82 #define TA_POLYCMD_USELENGTH(i) ( i & 0x00800000 )
    83 #define TA_POLYCMD_LENGTH(i)  strip_lengths[((i >> 18) & 0x03)]
    84 #define TA_POLYCMD_CLIP(i)  ((i>>16)&0x03)
    85 #define TA_POLYCMD_CLIP_NONE 0
    86 #define TA_POLYCMD_CLIP_INSIDE 2
    87 #define TA_POLYCMD_CLIP_OUTSIDE 3
    88 #define TA_POLYCMD_COLOURFMT(i)  (i & 0x00000030)
    89 #define TA_POLYCMD_COLOURFMT_ARGB32 0x00000000
    90 #define TA_POLYCMD_COLOURFMT_FLOAT 0x00000010
    91 #define TA_POLYCMD_COLOURFMT_INTENSITY 0x00000020
    92 #define TA_POLYCMD_COLOURFMT_LASTINT 0x00000030
    94 #define TA_POLYCMD_MODIFIED 0x00000080
    95 #define TA_POLYCMD_FULLMOD  0x00000040
    96 #define TA_POLYCMD_TEXTURED 0x00000008
    97 #define TA_POLYCMD_SPECULAR 0x00000004
    98 #define TA_POLYCMD_SHADED 0x00000002
    99 #define TA_POLYCMD_UV16 0x00000001
   101 #define TA_POLYCMD_IS_SPECULAR(i) ((i & 0x0000000C)==0x0000000C) /* Only applies to textured polys */
   102 #define TA_POLYCMD_IS_FULLMOD(i) ((i & 0x000000C0)==0x000000C0)
   105 #define TA_IS_END_VERTEX(i) (i & 0x10000000)
   107 /** Note these are not the IEEE 754 definitions - the TA treats NANs
   108  * as if they were INFs of the appropriate sign.
   109  */
   110 #define TA_IS_INF(f) (((*((uint32_t *)&f)) & 0xFF800000) == 0x7F800000)
   111 #define TA_IS_NINF(f) (((*((uint32_t *)&f)) & 0xFF800000) == 0xFF800000)
   113 #define MIN3( x1, x2, x3 ) ( (x1)<(x2)? ((x1)<(x3)?(x1):(x3)) : ((x2)<(x3)?(x2):(x3)) )
   114 #define MAX3( x1, x2, x3 ) ( (x1)>(x2)? ((x1)>(x3)?(x1):(x3)) : ((x2)>(x3)?(x2):(x3)) )
   116 #define TILESLOT( x, y ) (ta_status.current_tile_matrix + (ta_status.current_tile_size * (y * ta_status.width+ x) << 2))
   118 extern char *video_base;
   119 #define PVRRAM(addr) (*(uint32_t *)(video_base + ((addr)&PVR2_RAM_MASK)))
   121 struct pvr2_ta_vertex {
   122     float x,y,z;
   123     uint32_t detail[8]; /* 0-8 detail words */
   124 };
   126 struct tile_bounds {
   127     int x1, y1, x2, y2;
   128 };
   130 struct pvr2_ta_status {
   131     int state;
   132     int width, height; /* Tile resolution, ie 20x15 */
   133     int tilelist_dir; /* Growth direction of the tilelist, 0 = up, 1 = down */
   134     uint32_t tilelist_size; /* Size of the tilelist segments */
   135     uint32_t tilelist_start; /* Initial address of the tilelist */
   136     int polybuf_start; /* Initial bank address of the polygon buffer (ie &0x00F00000) */
   137     int current_vertex_type;
   138     gboolean accept_vertexes;
   139     int vertex_count; /* index of last start-vertex seen, or -1 if no vertexes 
   140 			 * are present
   141 			 */
   142     int max_vertex;     /* Maximum number of vertexes in the current polygon (3/4/6/8) */
   143     int current_list_type;
   144     uint32_t current_tile_matrix; /* Memory location of the first tile for the current list. */
   145     uint32_t current_tile_size; /* Size of the tile matrix space  in 32-bit words (0/8/16/32)*/
   146     uint32_t intensity1, intensity2;
   147     struct tile_bounds clip;
   148     int clip_mode;
   149     /**
   150      * Current working object
   151      */
   152     int poly_context_size;
   153     int poly_vertex_size;
   154     int poly_parity;
   155     uint32_t poly_context[5];
   156     uint32_t poly_pointer;
   157     struct tile_bounds last_triangle_bounds;
   158     struct pvr2_ta_vertex poly_vertex[8];
   159     int debug_output;
   160 };
   162 static struct pvr2_ta_status ta_status;
   164 static int tilematrix_sizes[4] = {0,8,16,32};
   166 /**
   167  * Convenience union - ta data is either 32-bit integer or 32-bit float.
   168  */
   169 union ta_data {
   170     unsigned int i;
   171     float f;
   172 };
   175 void pvr2_ta_reset() {
   176     ta_status.state = STATE_ERROR; /* State not valid until initialized */
   177     ta_status.debug_output = 0;
   178 }
   180 void pvr2_ta_save_state( FILE *f )
   181 {
   182     fwrite( &ta_status, sizeof(ta_status), 1, f );
   183 }
   185 int pvr2_ta_load_state( FILE *f )
   186 {
   187     if( fread( &ta_status, sizeof(ta_status), 1, f ) != 1 )
   188 	return 1;
   189     return 0;
   190 }
   192 void pvr2_ta_init() {
   193     ta_status.state = STATE_IDLE;
   194     ta_status.current_list_type = -1;
   195     ta_status.current_vertex_type = -1;
   196     ta_status.poly_parity = 0;
   197     ta_status.vertex_count = 0;
   198     ta_status.max_vertex = 3;
   199     ta_status.current_vertex_type = TA_VERTEX_LISTLESS;
   200     ta_status.poly_vertex_size = 0;
   201     memset(&ta_status.poly_context[1], 0, 4);
   202     ta_status.last_triangle_bounds.x1 = -1;
   203     ta_status.accept_vertexes = TRUE;
   204     ta_status.clip.x1 = 0;
   205     ta_status.clip.y1 = 0;
   206     ta_status.clip_mode = TA_POLYCMD_CLIP_NONE;
   208     uint32_t size = MMIO_READ( PVR2, TA_TILESIZE );
   209     ta_status.width = (size & 0xFFFF) + 1;
   210     ta_status.height = (size >> 16) + 1;
   211     ta_status.clip.x2 = ta_status.width-1;
   212     ta_status.clip.y2 = ta_status.height-1;
   213     uint32_t control = MMIO_READ( PVR2, TA_TILECFG );
   214     ta_status.tilelist_dir = (control >> 20) & 0x01;
   215     ta_status.tilelist_size = tilematrix_sizes[ (control & 0x03) ];
   216     MMIO_WRITE( PVR2, TA_POLYPOS, MMIO_READ( PVR2, TA_POLYBASE ) );
   217     uint32_t plistpos = MMIO_READ( PVR2, TA_LISTBASE ) >> 2;
   218     if( ta_status.tilelist_dir == TA_GROW_DOWN ) {
   219 	plistpos -= ta_status.tilelist_size;
   220     }
   221     MMIO_WRITE( PVR2, TA_LISTPOS, plistpos );
   222     ta_status.tilelist_start = plistpos;
   223     ta_status.polybuf_start = MMIO_READ( PVR2, TA_POLYBASE ) & 0x00F00000;
   224 }
   226 static uint32_t parse_float_colour( float a, float r, float g, float b ) {
   227     int ai,ri,gi,bi;
   229     if( TA_IS_INF(a) ) {
   230 	ai = 255;
   231     } else {
   232 	ai = 256 * CLAMP(a,0.0,1.0) - 1;
   233 	if( ai < 0 ) ai = 0;
   234     }
   235     if( TA_IS_INF(r) ) {
   236 	ri = 255;
   237     } else {
   238 	ri = 256 * CLAMP(r,0.0,1.0) - 1;
   239 	if( ri < 0 ) ri = 0;
   240     }
   241     if( TA_IS_INF(g) ) {
   242 	gi = 255;
   243     } else {
   244 	gi = 256 * CLAMP(g,0.0,1.0) - 1;
   245 	if( gi < 0 ) gi = 0;
   246     }
   247     if( TA_IS_INF(b) ) {
   248 	bi = 255;
   249     } else {
   250 	bi = 256 * CLAMP(b,0.0,1.0) - 1;
   251 	if( bi < 0 ) bi = 0;
   252     }
   253     return (ai << 24) | (ri << 16) | (gi << 8) | bi;
   254 }
   256 static uint32_t parse_intensity_colour( uint32_t base, float intensity )
   257 {
   258     unsigned int i = (unsigned int)(256 * CLAMP(intensity, 0.0,1.0));
   260     return
   261 	(((((base & 0xFF) * i) & 0xFF00) |
   262 	  (((base & 0xFF00) * i) & 0xFF0000) |
   263 	  (((base & 0xFF0000) * i) & 0xFF000000)) >> 8) |
   264 	base & 0xFF000000;
   265 }
   267 /**
   268  * Initialize the specified TA list.
   269  */
   270 static void ta_init_list( unsigned int listtype ) {
   271     int config = MMIO_READ( PVR2, TA_TILECFG );
   272     int tile_matrix = MMIO_READ( PVR2, TA_TILEBASE );
   273     int list_end = MMIO_READ( PVR2, TA_LISTEND );
   275     ta_status.current_tile_matrix = tile_matrix;
   277     /* If the list grows down, the end must be < tile matrix start. 
   278      * If it grows up, the end must be > tile matrix start.
   279      * Don't ask me why, it just does...
   280      */
   281     if( ((ta_status.tilelist_dir == TA_GROW_DOWN && list_end <= tile_matrix) ||
   282 	 (ta_status.tilelist_dir == TA_GROW_UP && list_end >= tile_matrix )) &&
   283 	listtype <= TA_LIST_PUNCH_OUT ) {
   284 	int i;
   285 	uint32_t *p;
   286 	for( i=0; i < listtype; i++ ) {
   287 	    int size = tilematrix_sizes[(config & 0x03)] << 2;
   288 	    ta_status.current_tile_matrix += ta_status.width * ta_status.height * size;
   289 	    config >>= 4;
   290 	}
   291 	ta_status.current_tile_size = tilematrix_sizes[(config & 0x03)];
   293 	/* Initialize each tile to 0xF0000000 */
   294 	if( ta_status.current_tile_size != 0 ) {
   295 	    p = (uint32_t *)(video_base + ta_status.current_tile_matrix);
   296 	    for( i=0; i< ta_status.width * ta_status.height; i++ ) {
   297 		*p = 0xF0000000;
   298 		p += ta_status.current_tile_size;
   299 	    }
   300 	}
   301     } else {
   302 	ta_status.current_tile_size = 0;
   303     }
   305     if( tile_matrix == list_end ) {
   306 	ta_status.current_tile_size = 0;
   307     }
   309     ta_status.state = STATE_IN_LIST;
   310     ta_status.current_list_type = listtype;
   311     ta_status.last_triangle_bounds.x1 = -1;
   312 }
   314 static int list_events[5] = {EVENT_PVR_OPAQUE_DONE, EVENT_PVR_OPAQUEMOD_DONE, 
   315 			     EVENT_PVR_TRANS_DONE, EVENT_PVR_TRANSMOD_DONE,
   316 			     EVENT_PVR_PUNCHOUT_DONE };
   318 static void ta_end_list() {
   319     if( ta_status.current_list_type != TA_LIST_NONE ) {
   320 	asic_event( list_events[ta_status.current_list_type] );
   321     }
   322     ta_status.current_list_type = TA_LIST_NONE;
   323     ta_status.current_vertex_type = TA_VERTEX_LISTLESS;
   324     ta_status.poly_vertex_size = 0;
   325     memset(&ta_status.poly_context[1], 0, 4);
   326     ta_status.state = STATE_IDLE;
   327 }
   329 static void ta_bad_input_error() {
   330     asic_event( EVENT_TA_ERROR );
   331     asic_event( EVENT_PVR_BAD_INPUT );
   332 }
   334 /**
   335  * Write data out to the polygon buffer.
   336  * If the end-of-buffer is reached, asserts EVENT_PVR_PRIM_ALLOC_FAIL
   337  * @param data to be written
   338  * @param length Number of 32-bit words to write.
   339  * @return number of words actually written
   340  */
   341 static int ta_write_polygon_buffer( uint32_t *data, int length )
   342 {
   343     int rv;
   344     int posn = MMIO_READ( PVR2, TA_POLYPOS );
   345     int end = MMIO_READ( PVR2, TA_POLYEND );
   346     uint32_t *target = (uint32_t *)(video_base + posn);
   347     for( rv=0; rv < length; rv++ ) {
   348 	if( posn == end ) {
   349 	    asic_event( EVENT_PVR_PRIM_ALLOC_FAIL );
   350 	    asic_event( EVENT_TA_ERROR );
   351 	    //	    ta_status.state = STATE_ERROR;
   352 	    break;
   353 	}
   354 	if( posn < PVR2_RAM_SIZE ) {
   355 	    *target++ = *data++;
   356 	}
   357 	posn += 4;
   358     }
   360     MMIO_WRITE( PVR2, TA_POLYPOS, posn );
   361     return rv;
   362 }
   364 #define TA_NO_ALLOC 0xFFFFFFFF
   366 /**
   367  * Allocate a new tile list block from the grow space and update the
   368  * word at reference to be a link to the new block.
   369  */
   370 static uint32_t ta_alloc_tilelist( uint32_t reference ) {
   371     uint32_t posn = MMIO_READ( PVR2, TA_LISTPOS );
   372     uint32_t limit = MMIO_READ( PVR2, TA_LISTEND ) >> 2;
   373     uint32_t newposn;
   374     uint32_t result;
   375     if( ta_status.tilelist_dir == TA_GROW_DOWN ) {
   376 	newposn = posn - ta_status.tilelist_size;
   377 	if( posn == limit ) {
   378 	    PVRRAM(posn<<2) = 0xF0000000;
   379 	    PVRRAM(reference) = 0xE0000000 | (posn<<2);
   380 	    return TA_NO_ALLOC;
   381 	} else if( posn < limit ) {
   382 	    PVRRAM(reference) = 0xE0000000 | (posn<<2);
   383 	    return TA_NO_ALLOC;
   384 	} else if( newposn <= limit ) {
   385 	} else if( newposn <= (limit + ta_status.tilelist_size) ) {
   386 	    asic_event( EVENT_TA_ERROR );
   387 	    asic_event( EVENT_PVR_MATRIX_ALLOC_FAIL );
   388 	    MMIO_WRITE( PVR2, TA_LISTPOS, newposn );
   389 	} else {
   390 	    MMIO_WRITE( PVR2, TA_LISTPOS, newposn );
   391 	}
   392 	PVRRAM(reference) = 0xE0000000 | (posn<<2);
   393 	return posn << 2;
   394     } else {
   395 	newposn = posn + ta_status.tilelist_size;
   396 	if( posn == limit ) {
   397 	    PVRRAM(posn<<2) = 0xF0000000;
   398 	    PVRRAM(reference) = 0xE0000000 | (posn<<2);
   399 	    return TA_NO_ALLOC;
   400 	} else if ( posn > limit ) {
   401 	    PVRRAM(reference) = 0xE0000000 | (posn<<2);
   402 	    return TA_NO_ALLOC;
   403 	} else if( newposn >= limit ) {
   404 	} else if( newposn >= (limit - ta_status.tilelist_size) ) {
   405 	    asic_event( EVENT_TA_ERROR );
   406 	    asic_event( EVENT_PVR_MATRIX_ALLOC_FAIL );
   407 	    MMIO_WRITE( PVR2, TA_LISTPOS, newposn );
   408 	} else {
   409 	    MMIO_WRITE( PVR2, TA_LISTPOS, newposn );
   410 	}	    
   411 	PVRRAM(reference) = 0xE0000000 | (posn<<2);
   412 	return posn << 2;
   413     }
   414 }
   416 /**
   417  * Write a tile entry out to the matrix.
   418  */
   419 static int ta_write_tile_entry( int x, int y, uint32_t tile_entry ) {
   420     uint32_t tile = TILESLOT(x,y);
   421     uint32_t tilestart = tile;
   422     uint32_t value;
   423     uint32_t lasttri = 0;
   424     int i,l;
   426     if( ta_status.clip_mode == TA_POLYCMD_CLIP_OUTSIDE &&
   427 	x >= ta_status.clip.x1 && x <= ta_status.clip.x2 &&
   428 	y >= ta_status.clip.y1 && y <= ta_status.clip.y2 ) {
   429 	/* Tile clipped out */
   430 	return 0;
   431     }
   433     if( (tile_entry & 0x80000000) && 
   434 	ta_status.last_triangle_bounds.x1 != -1 &&
   435 	ta_status.last_triangle_bounds.x1 <= x &&
   436 	ta_status.last_triangle_bounds.x2 >= x &&
   437 	ta_status.last_triangle_bounds.y1 <= y &&
   438 	ta_status.last_triangle_bounds.y2 >= y ) {
   439 	/* potential for triangle stacking */
   440 	lasttri = tile_entry & 0xE1E00000;
   441     }
   444     if( PVRRAM(tile) == 0xF0000000 ) {
   445 	PVRRAM(tile) = tile_entry;
   446 	PVRRAM(tile+4) = 0xF0000000;
   447 	return;
   448     }
   450     while(1) {
   451 	value = PVRRAM(tile);
   452 	for( i=1; i<ta_status.current_tile_size; i++ ) {
   453 	    tile += 4;
   454 	    uint32_t nextval = PVRRAM(tile);
   455 	    if( nextval == 0xF0000000 ) {
   456 		if( lasttri != 0 && lasttri == (value&0xE1E00000) ) {
   457 		    int count = (value & 0x1E000000) + 0x02000000;
   458 		    if( count < 0x20000000 ) {
   459 			PVRRAM(tile-4) = (value & 0xE1FFFFFF) | count;
   460 			return;
   461 		    }
   462 		}
   463 		if( i < ta_status.current_tile_size-1 ) {
   464 		    PVRRAM(tile) = tile_entry;
   465 		    PVRRAM(tile+4) = 0xF0000000;
   466 		    return;
   467 		}
   468 	    }
   469 	    value = nextval;
   470 	}
   472 	if( value == 0xF0000000 ) {
   473 	    tile = ta_alloc_tilelist(tile);
   474 	    if( tile != TA_NO_ALLOC ) {
   475 		PVRRAM(tile) = tile_entry;
   476 		PVRRAM(tile+4) = 0xF0000000;
   477 	    }
   478 	    return;
   479 	} else if( (value & 0xFF000000) == 0xE0000000 ) {
   480 	    value &= 0x00FFFFFF;
   481 	    if( value == tilestart )
   482 		return 0; /* Loop */
   483 	    tilestart = tile = value;
   484 	} else {
   485 	    /* This should never happen */
   486 	    return 0;
   487 	}
   488     }
   489 }
   491 /**
   492  * Write a completed polygon out to the memory buffers 
   493  * OPTIMIZEME: This is not terribly efficient at the moment.
   494  */
   495 static void ta_commit_polygon( ) {
   496     int i, x, y;
   497     int tx[ta_status.vertex_count], ty[ta_status.vertex_count];
   498     struct tile_bounds triangle_bound[ta_status.vertex_count - 2];
   499     struct tile_bounds polygon_bound;
   500     uint32_t poly_context[5];
   502     memcpy( poly_context, ta_status.poly_context, ta_status.poly_context_size * 4 );
   504     /* Compute the tile coordinates for each vertex (need to be careful with
   505      * clamping here)
   506      */
   507     for( i=0; i<ta_status.vertex_count; i++ ) {
   508 	if( ta_status.poly_vertex[i].x < 0.0 || TA_IS_NINF(ta_status.poly_vertex[i].x) ) {
   509 	    tx[i] = -1;
   510 	} else if( ta_status.poly_vertex[i].x > (float)INT_MAX || TA_IS_INF(ta_status.poly_vertex[i].x) ) {
   511 	    tx[i] = INT_MAX/32;
   512 	} else {
   513 	    tx[i] = (int)(ta_status.poly_vertex[i].x / 32.0);
   514 	}
   515 	if( ta_status.poly_vertex[i].y < 0.0 || TA_IS_NINF(ta_status.poly_vertex[i].y)) {
   516 	    ty[i] = -1;
   517 	} else if( ta_status.poly_vertex[i].y > (float)INT_MAX || TA_IS_INF(ta_status.poly_vertex[i].y) ) {
   518 	    ty[i] = INT_MAX/32;
   519 	} else {
   520 	    ty[i] = (int)(ta_status.poly_vertex[i].y / 32.0);
   521 	}
   523     }
   525     /* Compute bounding box for each triangle individually, as well
   526      * as the overall polygon.
   527      */
   529     for( i=0; i<ta_status.vertex_count-2; i++ ) {
   530 	triangle_bound[i].x1 = MIN3(tx[i],tx[i+1],tx[i+2]);
   531 	triangle_bound[i].x2 = MAX3(tx[i],tx[i+1],tx[i+2]);
   532 	triangle_bound[i].y1 = MIN3(ty[i],ty[i+1],ty[i+2]);
   533 	triangle_bound[i].y2 = MAX3(ty[i],ty[i+1],ty[i+2]);
   534 	if( i == 0 ) {
   535 	    polygon_bound.x1 = triangle_bound[0].x1;
   536 	    polygon_bound.y1 = triangle_bound[0].y1;
   537 	    polygon_bound.x2 = triangle_bound[0].x2;
   538 	    polygon_bound.y2 = triangle_bound[0].y2;
   539 	} else {
   540 	    polygon_bound.x1 = MIN(polygon_bound.x1, triangle_bound[i].x1);
   541 	    polygon_bound.x2 = MAX(polygon_bound.x2, triangle_bound[i].x2);
   542 	    polygon_bound.y1 = MIN(polygon_bound.y1, triangle_bound[i].y1);
   543 	    polygon_bound.y2 = MAX(polygon_bound.y2, triangle_bound[i].y2);
   544 	}
   545     }
   547     /* Clamp the polygon bounds to the frustum */
   548     if( polygon_bound.x1 < 0 ) polygon_bound.x1 = 0;
   549     if( polygon_bound.x2 >= ta_status.width ) polygon_bound.x2 = ta_status.width-1;
   550     if( polygon_bound.y1 < 0 ) polygon_bound.y1 = 0;
   551     if( polygon_bound.y2 >= ta_status.width ) polygon_bound.y2 = ta_status.height-1;
   553     /* Set the "single tile" flag if it's entirely contained in 1 tile */
   554     if( polygon_bound.x1 == polygon_bound.x2 &&
   555 	polygon_bound.y1 == polygon_bound.y2 ) {
   556 	poly_context[0] |= 0x00200000;
   557     }
   559     /* If the polygon is entirely clipped, don't even write the polygon data */
   560     switch( ta_status.clip_mode ) {
   561     case TA_POLYCMD_CLIP_NONE:
   562 	if( polygon_bound.x2 < 0 || polygon_bound.x1 >= ta_status.width ||
   563 	    polygon_bound.y2 < 0 || polygon_bound.y1 >= ta_status.height ) {
   564 	    return;
   565 	}
   566 	break;
   567     case TA_POLYCMD_CLIP_INSIDE:
   568 	if( polygon_bound.x2 < ta_status.clip.x1 || polygon_bound.x1 > ta_status.clip.x2 ||
   569 	    polygon_bound.y2 < ta_status.clip.y1 || polygon_bound.y1 > ta_status.clip.y1 ) {
   570 	    return;
   571 	} else {
   572 	    /* Clamp to clip bounds */
   573 	    if( polygon_bound.x1 < ta_status.clip.x1 ) polygon_bound.x1 = ta_status.clip.x1;
   574 	    if( polygon_bound.x2 > ta_status.clip.x2 ) polygon_bound.x2 = ta_status.clip.x2;
   575 	    if( polygon_bound.y1 < ta_status.clip.y1 ) polygon_bound.y1 = ta_status.clip.y1;
   576 	    if( polygon_bound.y2 > ta_status.clip.y2 ) polygon_bound.y2 = ta_status.clip.y2;
   577 	}
   578 	break;
   579     case TA_POLYCMD_CLIP_OUTSIDE:
   580 	if( polygon_bound.x1 >= ta_status.clip.x1 && polygon_bound.x2 <= ta_status.clip.x2 &&
   581 	    polygon_bound.y1 >= ta_status.clip.y1 && polygon_bound.y2 <= ta_status.clip.y2 ) {
   582 	    return;
   583 	}
   584 	break;
   585     }
   587     /* Ok, we're good to go - write out the polygon first */
   588     uint32_t tile_entry = (MMIO_READ( PVR2, TA_POLYPOS ) - ta_status.polybuf_start) >> 2 | 
   589 	ta_status.poly_pointer;
   591     int status = ta_write_polygon_buffer( poly_context, ta_status.poly_context_size );
   592     if( status == 0 ) {
   593 	/* No memory available - abort */
   594 	return;
   595     } else {
   596 	for( i=0; i<ta_status.vertex_count && status != 0; i++ ) {
   597 	    status = ta_write_polygon_buffer( (uint32_t *)(&ta_status.poly_vertex[i]), 3 + ta_status.poly_vertex_size );
   598 	}
   599     }
   601     if( ta_status.current_tile_size == 0 ) {
   602 	/* No memory for tile entry, so don't write anything */
   603 	return;
   604     }
   606     /* And now the tile entries. Triangles are different from everything else */
   607     if( ta_status.vertex_count == 3 ) {
   608 	tile_entry |= 0x80000000;
   609 	for( y=polygon_bound.y1; y<=polygon_bound.y2; y++ ) {
   610 	    for( x=polygon_bound.x1; x<=polygon_bound.x2; x++ ) {
   611 		ta_write_tile_entry( x,y,tile_entry );
   612 	    }
   613 	}
   614 	ta_status.last_triangle_bounds.x1 = polygon_bound.x1;
   615 	ta_status.last_triangle_bounds.y1 = polygon_bound.y1;
   616 	ta_status.last_triangle_bounds.x2 = polygon_bound.x2;
   617 	ta_status.last_triangle_bounds.y2 = polygon_bound.y2;
   618     } else if( ta_status.current_vertex_type == TA_VERTEX_SPRITE ||
   619 	       ta_status.current_vertex_type == TA_VERTEX_TEX_SPRITE ) {
   620 	tile_entry |= 0xA0000000;
   621 	for( y=polygon_bound.y1; y<=polygon_bound.y2; y++ ) {
   622 	    for( x=polygon_bound.x1; x<=polygon_bound.x2; x++ ) {
   623 		ta_write_tile_entry( x,y,tile_entry );
   624 	    }
   625 	}
   626 	ta_status.last_triangle_bounds.x1 = polygon_bound.x1;
   627 	ta_status.last_triangle_bounds.y1 = polygon_bound.y1;
   628 	ta_status.last_triangle_bounds.x2 = polygon_bound.x2;
   629 	ta_status.last_triangle_bounds.y2 = polygon_bound.y2;
   630     } else {
   631 	for( y=polygon_bound.y1; y<=polygon_bound.y2; y++ ) {
   632 	    for( x=polygon_bound.x1; x<=polygon_bound.x2; x++ ) {
   633 		uint32_t entry = tile_entry;
   634 		for( i=0; i<ta_status.vertex_count-2; i++ ) {
   635 		    if( triangle_bound[i].x1 <= x && triangle_bound[i].x2 >= x &&
   636 			triangle_bound[i].y1 <= y && triangle_bound[i].y2 >= y ) {
   637 			entry |= (0x40000000>>i);
   638 		    }
   639 		}
   640 		ta_write_tile_entry( x, y, entry );
   641 	    }
   642 	}
   643 	ta_status.last_triangle_bounds.x1 = -1;
   644     }
   645 }
   647 /**
   648  * Variant of ta_split_polygon called when vertex_count == max_vertex, but 
   649  * the client hasn't sent the LAST VERTEX flag. Commit the poly as normal
   650  * first, then start a new poly with the first 2 vertexes taken from the 
   651  * current one.
   652  */
   653 static void ta_split_polygon() {
   654     ta_commit_polygon();
   655     if( TA_IS_NORMAL_POLY() ) { 
   656 	/* This only applies to ordinary polys - Sprites + modifier lists are
   657 	 * handled differently
   658 	 */
   659 	if( ta_status.vertex_count == 3 ) {
   660 	    /* Triangles use an odd/even scheme */
   661 	    if( ta_status.poly_parity == 0 ) {
   662 		memcpy( &ta_status.poly_vertex[0], &ta_status.poly_vertex[2], 
   663 			sizeof(struct pvr2_ta_vertex) );
   664 		ta_status.poly_parity = 1;
   665 	    } else {
   666 		memcpy( &ta_status.poly_vertex[1], &ta_status.poly_vertex[2],
   667 			sizeof(struct pvr2_ta_vertex) );
   668 		ta_status.poly_parity = 0;
   669 	    }
   670 	} else {
   671 	    /* Everything else just uses the last 2 vertexes in order */
   672 	    memcpy( &ta_status.poly_vertex[0], &ta_status.poly_vertex[ta_status.vertex_count-2], 
   673 		    sizeof(struct pvr2_ta_vertex)*2 );
   674 	    ta_status.poly_parity = 0;
   675 	}
   676 	ta_status.vertex_count = 2;
   677     } else {
   678 	ta_status.vertex_count = 0;
   679     }
   680 }
   682 /**
   683  * Parse the polygon context block and setup the internal state to receive
   684  * vertexes.
   685  * @param data 32 bytes of parameter data.
   686  */
   687 static void ta_parse_polygon_context( union ta_data *data ) {
   688     int colourfmt = TA_POLYCMD_COLOURFMT(data[0].i);
   689     if( TA_POLYCMD_USELENGTH(data[0].i) ) {
   690 	ta_status.max_vertex = TA_POLYCMD_LENGTH(data[0].i);
   691     }
   692     ta_status.clip_mode = TA_POLYCMD_CLIP(data[0].i);
   693     if( ta_status.clip_mode == 1 ) { /* Reserved - treat as CLIP_INSIDE */
   694 	ta_status.clip_mode = TA_POLYCMD_CLIP_INSIDE;
   695     }
   696     ta_status.vertex_count = 0;
   697     ta_status.poly_context[0] = 
   698 	(data[1].i & 0xFC1FFFFF) | ((data[0].i & 0x0B) << 22);
   699     ta_status.poly_context[1] = data[2].i;
   700     ta_status.poly_context[3] = data[4].i;
   701     ta_status.poly_parity = 0;
   702     if( data[0].i & TA_POLYCMD_TEXTURED ) {
   703 	ta_status.current_vertex_type = data[0].i & 0x0D;
   704 	ta_status.poly_context[2] = data[3].i;
   705 	ta_status.poly_context[4] = data[5].i;
   706 	if( data[0].i & TA_POLYCMD_SPECULAR ) {
   707 	    ta_status.poly_context[0] |= 0x01000000;
   708 	    ta_status.poly_vertex_size = 4;
   709 	} else {
   710 	    ta_status.poly_vertex_size = 3;
   711 	}
   712 	if( data[0].i & TA_POLYCMD_UV16 ) {
   713 	    ta_status.poly_vertex_size--;
   714 	}
   715     } else {
   716 	ta_status.current_vertex_type = 0;
   717 	ta_status.poly_vertex_size = 1;
   718 	ta_status.poly_context[2] = 0;
   719 	ta_status.poly_context[4] = 0;
   720     }
   722     ta_status.poly_pointer = (ta_status.poly_vertex_size << 21);
   723     ta_status.poly_context_size = 3;
   724     if( data[0].i & TA_POLYCMD_MODIFIED ) {
   725 	ta_status.poly_pointer |= 0x01000000;
   726 	if( data[0].i & TA_POLYCMD_FULLMOD ) {
   727 	    ta_status.poly_context_size = 5;
   728 	    ta_status.poly_vertex_size <<= 1;
   729 	    ta_status.current_vertex_type |= 0x40;
   730 	    /* Modified/float not supported - behaves as per last intensity */
   731 	    if( colourfmt == TA_POLYCMD_COLOURFMT_FLOAT ) {
   732 		colourfmt = TA_POLYCMD_COLOURFMT_LASTINT;
   733 	    }
   734 	}
   735     }
   737     if( colourfmt == TA_POLYCMD_COLOURFMT_INTENSITY ) {
   738 	if( TA_POLYCMD_IS_FULLMOD(data[0].i) ||
   739 	    TA_POLYCMD_IS_SPECULAR(data[0].i) ) {
   740 	    ta_status.state = STATE_EXPECT_POLY_BLOCK2;
   741 	} else {
   742 	    ta_status.intensity1 = 
   743 		parse_float_colour( data[4].f, data[5].f, data[6].f, data[7].f );
   744 	}
   745     } else if( colourfmt == TA_POLYCMD_COLOURFMT_LASTINT ) {
   746 	colourfmt = TA_POLYCMD_COLOURFMT_INTENSITY;
   747     }
   749     ta_status.current_vertex_type |= colourfmt;
   750 }
   752 /**
   753  * Parse the modifier volume context block and setup the internal state to 
   754  * receive modifier vertexes.
   755  * @param data 32 bytes of parameter data.
   756  */
   757 static void ta_parse_modifier_context( union ta_data *data ) {
   758     ta_status.current_vertex_type = TA_VERTEX_MOD_VOLUME;
   759     ta_status.poly_vertex_size = 0;
   760     ta_status.clip_mode = TA_POLYCMD_CLIP(data[0].i);
   761     if( ta_status.clip_mode == 1 ) { /* Reserved - treat as CLIP_INSIDE */
   762 	ta_status.clip_mode = TA_POLYCMD_CLIP_INSIDE;
   763     }
   764     ta_status.poly_context_size = 3;
   765     ta_status.poly_context[0] = (data[1].i & 0xFC1FFFFF) |
   766 	((data[0].i & 0x0B)<<22);
   767     if( TA_POLYCMD_IS_SPECULAR(data[0].i) ) {
   768 	ta_status.poly_context[0] |= 0x01000000;
   769     }
   770     ta_status.poly_context[1] = 0;
   771     ta_status.poly_context[2] = 0;
   772     ta_status.vertex_count = 0;
   773     ta_status.max_vertex = 3;
   774     ta_status.poly_pointer = 0;
   775 }
   777 /**
   778  * Parse the sprite context block and setup the internal state to receive
   779  * vertexes.
   780  * @param data 32 bytes of parameter data.
   781  */
   782 static void ta_parse_sprite_context( union ta_data *data ) {
   783     ta_status.poly_context_size = 3;
   784     ta_status.poly_context[0] = (data[1].i & 0xFC1FFFFF) |
   785 	((data[0].i & 0x0B)<<22) | 0x00400000;
   786     if( TA_POLYCMD_IS_SPECULAR(data[0].i) ) {
   787 	ta_status.poly_context[0] |= 0x01000000;
   788     }
   789     ta_status.poly_context[1] = data[2].i;
   790     ta_status.poly_context[2] = data[3].i;
   791     if( data[0].i & TA_POLYCMD_TEXTURED ) {
   792 	ta_status.poly_vertex_size = 2;
   793 	ta_status.poly_vertex[2].detail[1] = data[4].i;
   794 	ta_status.current_vertex_type = TA_VERTEX_TEX_SPRITE;
   795     } else {
   796 	ta_status.poly_vertex_size = 1;
   797 	ta_status.poly_vertex[2].detail[0] = data[4].i;
   798 	ta_status.current_vertex_type = TA_VERTEX_SPRITE;
   799     }
   800     ta_status.vertex_count = 0;
   801     ta_status.max_vertex = 4;
   802     ta_status.poly_pointer = (ta_status.poly_vertex_size << 21);
   803 }
   805 /**
   806  * Copy the last read vertex into all vertexes up to max_vertex. Used for
   807  * Aborted polygons under some circumstances.
   808  */
   809 static void ta_fill_vertexes( ) {
   810     int i;
   811     for( i=ta_status.vertex_count; i<ta_status.max_vertex; i++ ) {
   812 	memcpy( &ta_status.poly_vertex[i], &ta_status.poly_vertex[ta_status.vertex_count-1],
   813 		sizeof( struct pvr2_ta_vertex ) );
   814     }
   815 }
   817 static void ta_parse_vertex( union ta_data *data ) {
   818     struct pvr2_ta_vertex *vertex = &ta_status.poly_vertex[ta_status.vertex_count];
   819     vertex->x = data[1].f;
   820     vertex->y = data[2].f;
   821     vertex->z = data[3].f;
   823     switch( ta_status.current_vertex_type ) {
   824     case TA_VERTEX_PACKED:
   825 	vertex->detail[0] = data[6].i;
   826 	break;
   827     case TA_VERTEX_FLOAT:
   828 	vertex->detail[0] = parse_float_colour( data[4].f, data[5].f, data[6].f, data[7].f );
   829 	break;
   830     case TA_VERTEX_INTENSITY:
   831 	vertex->detail[0] = parse_intensity_colour( ta_status.intensity1, data[6].f );
   832 	break;
   834     case TA_VERTEX_TEX_SPEC_PACKED:
   835 	vertex->detail[3] = data[7].i; /* ARGB */
   836 	/* Fallthrough */
   837     case TA_VERTEX_TEX_PACKED:
   838 	vertex->detail[0] = data[4].i; /* U */
   839 	vertex->detail[1] = data[5].i; /* V */
   840 	vertex->detail[2] = data[6].i; /* ARGB */
   841 	break;
   842     case TA_VERTEX_TEX_UV16_SPEC_PACKED:
   843 	vertex->detail[2] = data[7].i; /* ARGB */
   844 	/* Fallthrough */
   845     case TA_VERTEX_TEX_UV16_PACKED:
   846 	vertex->detail[0] = data[4].i; /* UV */
   847 	vertex->detail[1] = data[6].i; /* ARGB */
   848 	break;
   850     case TA_VERTEX_TEX_FLOAT:
   851     case TA_VERTEX_TEX_SPEC_FLOAT:
   852 	vertex->detail[0] = data[4].i; /* U */
   853 	vertex->detail[1] = data[5].i; /* UV */
   854 	ta_status.state = STATE_EXPECT_VERTEX_BLOCK2;
   855 	break;
   856     case TA_VERTEX_TEX_UV16_FLOAT:
   857     case TA_VERTEX_TEX_UV16_SPEC_FLOAT:
   858 	vertex->detail[0] = data[4].i; /* UV */
   859 	ta_status.state = STATE_EXPECT_VERTEX_BLOCK2;
   860 	break;
   862     case TA_VERTEX_TEX_SPEC_INTENSITY:
   863 	vertex->detail[3] = parse_intensity_colour( ta_status.intensity2, data[7].f );
   864 	/* Fallthrough */
   865     case TA_VERTEX_TEX_INTENSITY:
   866 	vertex->detail[0] = data[4].i; /* U */
   867 	vertex->detail[1] = data[5].i; /* V */
   868 	vertex->detail[2] = parse_intensity_colour( ta_status.intensity1, data[6].f );
   869 	break;
   870     case TA_VERTEX_TEX_UV16_SPEC_INTENSITY:
   871 	vertex->detail[2] = parse_intensity_colour( ta_status.intensity2, data[7].f );
   872 	/* Fallthrough */
   873     case TA_VERTEX_TEX_UV16_INTENSITY:
   874 	vertex->detail[0] = data[4].i; /* UV */
   875 	vertex->detail[1] = parse_intensity_colour( ta_status.intensity1, data[6].f );
   876 	break;
   878     case TA_VERTEX_PACKED_MOD:
   879 	vertex->detail[0] = data[4].i; /* ARGB */
   880 	vertex->detail[1] = data[5].i; /* ARGB */
   881 	break;
   882     case TA_VERTEX_INTENSITY_MOD:
   883 	vertex->detail[0] = parse_intensity_colour( ta_status.intensity1, data[4].f );
   884 	vertex->detail[1] = parse_intensity_colour( ta_status.intensity2, data[5].f );
   885 	break;
   887     case TA_VERTEX_TEX_SPEC_PACKED_MOD:
   888 	vertex->detail[3] = data[7].i; /* ARGB0 */
   889 	/* Fallthrough */
   890     case TA_VERTEX_TEX_PACKED_MOD:
   891 	vertex->detail[0] = data[4].i; /* U0 */
   892 	vertex->detail[1] = data[5].i; /* V0 */
   893 	vertex->detail[2] = data[6].i; /* ARGB0 */
   894 	ta_status.state = STATE_EXPECT_VERTEX_BLOCK2;
   895 	break;
   896     case TA_VERTEX_TEX_UV16_SPEC_PACKED_MOD:
   897 	vertex->detail[2] = data[7].i; /* ARGB0 */
   898 	/* Fallthrough */
   899     case TA_VERTEX_TEX_UV16_PACKED_MOD:
   900 	vertex->detail[0] = data[4].i; /* UV0 */
   901 	vertex->detail[1] = data[6].i; /* ARGB0 */
   902 	ta_status.state = STATE_EXPECT_VERTEX_BLOCK2;
   903 	break;
   905     case TA_VERTEX_TEX_SPEC_INTENSITY_MOD:
   906 	vertex->detail[3] = parse_intensity_colour( ta_status.intensity1, data[7].f );
   907 	/* Fallthrough */
   908     case TA_VERTEX_TEX_INTENSITY_MOD:
   909 	vertex->detail[0] = data[4].i; /* U0 */
   910 	vertex->detail[1] = data[5].i; /* V0 */
   911 	vertex->detail[2] = parse_intensity_colour( ta_status.intensity1, data[6].f );
   912 	ta_status.state = STATE_EXPECT_VERTEX_BLOCK2;
   913 	break;
   914     case TA_VERTEX_TEX_UV16_SPEC_INTENSITY_MOD:
   915 	vertex->detail[2] = parse_intensity_colour( ta_status.intensity1, data[7].f );
   916 	/* Fallthrough */
   917     case TA_VERTEX_TEX_UV16_INTENSITY_MOD:
   918 	vertex->detail[0] = data[4].i; /* UV0 */
   919 	vertex->detail[1] = parse_intensity_colour( ta_status.intensity1, data[6].f );
   920 	ta_status.state = STATE_EXPECT_VERTEX_BLOCK2;
   921 	break;
   923     case TA_VERTEX_SPRITE:
   924     case TA_VERTEX_TEX_SPRITE:
   925     case TA_VERTEX_MOD_VOLUME:
   926     case TA_VERTEX_LISTLESS:
   927 	vertex++;
   928 	vertex->x = data[4].f;
   929 	vertex->y = data[5].f;
   930 	vertex->z = data[6].f;
   931 	vertex++;
   932 	vertex->x = data[7].f;
   933 	ta_status.vertex_count += 2;
   934 	ta_status.state = STATE_EXPECT_VERTEX_BLOCK2;
   935 	break;
   936     }
   937     ta_status.vertex_count++;
   938 }
   940 static void ta_parse_vertex_block2( union ta_data *data ) {
   941     struct pvr2_ta_vertex *vertex = &ta_status.poly_vertex[ta_status.vertex_count-1];
   943     switch( ta_status.current_vertex_type ) {
   944     case TA_VERTEX_TEX_SPEC_FLOAT:
   945 	vertex->detail[3] = parse_float_colour( data[4].f, data[5].f, data[6].f, data[7].f );
   946 	/* Fallthrough */
   947     case TA_VERTEX_TEX_FLOAT:
   948 	vertex->detail[2] = parse_float_colour( data[0].f, data[1].f, data[2].f, data[3].f );
   949 	break;
   950     case TA_VERTEX_TEX_UV16_SPEC_FLOAT:
   951 	vertex->detail[2] = parse_float_colour( data[4].f, data[5].f, data[6].f, data[7].f );
   952 	/* Fallthrough */
   953     case TA_VERTEX_TEX_UV16_FLOAT:
   954 	vertex->detail[1] = parse_float_colour( data[0].f, data[1].f, data[2].f, data[3].f );
   955 	break;
   956     case TA_VERTEX_TEX_PACKED_MOD:
   957 	vertex->detail[3] = data[0].i; /* U1 */
   958 	vertex->detail[4] = data[1].i; /* V1 */
   959 	vertex->detail[5] = data[2].i; /* ARGB1 */
   960 	break;
   961     case TA_VERTEX_TEX_SPEC_PACKED_MOD:
   962 	vertex->detail[4] = data[0].i; /* U1 */
   963 	vertex->detail[5] = data[1].i; /* V1 */
   964 	vertex->detail[6] = data[2].i; /* ARGB1 */
   965 	vertex->detail[7] = data[3].i; /* ARGB1 */
   966 	break;
   967     case TA_VERTEX_TEX_UV16_PACKED_MOD:
   968 	vertex->detail[2] = data[0].i; /* UV1 */
   969 	vertex->detail[3] = data[2].i; /* ARGB1 */
   970 	break;
   971     case TA_VERTEX_TEX_UV16_SPEC_PACKED_MOD:
   972 	vertex->detail[3] = data[0].i; /* UV1 */
   973 	vertex->detail[4] = data[2].i; /* ARGB1 */
   974 	vertex->detail[5] = data[3].i; /* ARGB1 */
   975 	break;
   977     case TA_VERTEX_TEX_INTENSITY_MOD:
   978 	vertex->detail[3] = data[0].i; /* U1 */
   979 	vertex->detail[4] = data[1].i; /* V1 */
   980 	vertex->detail[5] = parse_intensity_colour( ta_status.intensity2, data[2].f ); /* ARGB1 */
   981 	break;
   982     case TA_VERTEX_TEX_SPEC_INTENSITY_MOD:
   983 	vertex->detail[4] = data[0].i; /* U1 */
   984 	vertex->detail[5] = data[1].i; /* V1 */
   985 	vertex->detail[6] = parse_intensity_colour( ta_status.intensity2, data[2].f ); /* ARGB1 */
   986 	vertex->detail[7] = parse_intensity_colour( ta_status.intensity2, data[3].f ); /* ARGB1 */
   987 	break;
   988     case TA_VERTEX_TEX_UV16_INTENSITY_MOD:
   989 	vertex->detail[2] = data[0].i; /* UV1 */
   990 	vertex->detail[3] = parse_intensity_colour( ta_status.intensity2, data[2].f ); /* ARGB1 */
   991 	break;
   992     case TA_VERTEX_TEX_UV16_SPEC_INTENSITY_MOD:
   993 	vertex->detail[3] = data[0].i; /* UV1 */
   994 	vertex->detail[4] = parse_intensity_colour( ta_status.intensity2, data[2].f ); /* ARGB1 */
   995 	vertex->detail[5] = parse_intensity_colour( ta_status.intensity2, data[3].f ); /* ARGB1 */
   996 	break;
   998     case TA_VERTEX_SPRITE:
   999 	vertex->y = data[0].f;
  1000 	vertex->z = data[1].f;
  1001 	vertex++;
  1002 	ta_status.vertex_count++;
  1003 	vertex->x = data[2].f;
  1004 	vertex->y = data[3].f;
  1005 	vertex->z = 0;
  1006 	vertex->detail[0] = 0;
  1007 	ta_status.poly_vertex[0].detail[0] = 0;
  1008 	ta_status.poly_vertex[1].detail[0] = 0;
  1009 	break;
  1010     case TA_VERTEX_TEX_SPRITE:
  1011 	vertex->y = data[0].f;
  1012 	vertex->z = data[1].f;
  1013 	vertex++;
  1014 	ta_status.vertex_count++;
  1015 	vertex->x = data[2].f;
  1016 	vertex->y = data[3].f;
  1017 	vertex->z = 0;
  1018 	vertex->detail[0] = 0;
  1019 	vertex->detail[1] = 0;
  1020 	ta_status.poly_vertex[0].detail[0] = data[5].i;
  1021 	ta_status.poly_vertex[0].detail[1] = 0;
  1022 	ta_status.poly_vertex[1].detail[0] = data[6].i;
  1023 	ta_status.poly_vertex[1].detail[1] = 0;
  1024 	ta_status.poly_vertex[2].detail[0] = data[7].i;
  1025 	break;
  1026     case TA_VERTEX_MOD_VOLUME:
  1027     case TA_VERTEX_LISTLESS:
  1028 	vertex->y = data[0].f;
  1029 	vertex->z = data[1].f;
  1030 	break;
  1032     ta_status.state = STATE_IN_POLYGON;
  1035 /**
  1036  * Process 1 32-byte block of ta data
  1037  */
  1038 void pvr2_ta_process_block( char *input ) {
  1039     union ta_data *data = (union ta_data *)input;
  1041     switch( ta_status.state ) {
  1042     case STATE_ERROR:
  1043 	/* Fatal error raised - stop processing until reset */
  1044 	return;
  1046     case STATE_EXPECT_POLY_BLOCK2:
  1047 	/* This is always a pair of floating-point colours */
  1048 	ta_status.intensity1 = 
  1049 	    parse_float_colour( data[0].f, data[1].f, data[2].f, data[3].f );
  1050 	ta_status.intensity2 =
  1051 	    parse_float_colour( data[4].f, data[5].f, data[6].f, data[7].f );
  1052 	ta_status.state = STATE_IN_LIST;
  1053 	break;
  1055     case STATE_EXPECT_VERTEX_BLOCK2:
  1056 	ta_parse_vertex_block2( data );
  1057 	if( ta_status.vertex_count == ta_status.max_vertex ) {
  1058 	    ta_split_polygon();
  1060 	break;
  1062     case STATE_EXPECT_END_VERTEX_BLOCK2:
  1063 	ta_parse_vertex_block2( data );
  1064 	if( ta_status.vertex_count < 3 ) {
  1065 	    ta_bad_input_error();
  1066 	} else {
  1067 	    ta_commit_polygon();
  1069 	ta_status.vertex_count = 0;
  1070 	ta_status.poly_parity = 0;
  1071 	ta_status.state = STATE_IN_LIST;
  1072 	break;
  1073     case STATE_IN_LIST:
  1074     case STATE_IN_POLYGON:
  1075     case STATE_IDLE:
  1076 	switch( TA_CMD( data->i ) ) {
  1077 	case TA_CMD_END_LIST:
  1078 	    if( ta_status.state == STATE_IN_POLYGON ) {
  1079 		ta_bad_input_error();
  1080 		ta_end_list();
  1081 		ta_status.state = STATE_ERROR; /* Abort further processing */
  1082 	    } else {
  1083 		ta_end_list();
  1085 	    break;
  1086 	case TA_CMD_CLIP:
  1087 	    if( ta_status.state == STATE_IN_POLYGON ) {
  1088 		ta_bad_input_error();
  1089 		ta_status.accept_vertexes = FALSE;
  1090 		/* Enter stuffed up mode */
  1092 	    ta_status.clip.x1 = data[4].i & 0x3F;
  1093 	    ta_status.clip.y1 = data[5].i & 0x0F;
  1094 	    ta_status.clip.x2 = data[6].i & 0x3F;
  1095 	    ta_status.clip.y2 = data[7].i & 0x0F;
  1096 	    if( ta_status.clip.x2 >= ta_status.width )
  1097 		ta_status.clip.x2 = ta_status.width - 1;
  1098 	    if( ta_status.clip.y2 >= ta_status.height )
  1099 		ta_status.clip.y2 = ta_status.height - 1;
  1100 	    break;
  1101 	case TA_CMD_POLYGON_CONTEXT:
  1102 	    if( ta_status.state == STATE_IDLE ) {
  1103 		ta_init_list( TA_POLYCMD_LISTTYPE( data->i ) );
  1106 	    if( ta_status.vertex_count != 0 ) {
  1107 		/* Error, and not a very well handled one either */
  1108 		ta_bad_input_error();
  1109 		ta_status.accept_vertexes = FALSE;
  1110 	    } else {
  1111 		if( TA_IS_MODIFIER_LIST( ta_status.current_list_type ) ) {
  1112 		    ta_parse_modifier_context(data);
  1113 		} else {
  1114 		    ta_parse_polygon_context(data);
  1117 	    break;
  1118 	case TA_CMD_SPRITE_CONTEXT:
  1119 	    if( ta_status.state == STATE_IDLE ) {
  1120 		ta_init_list( TA_POLYCMD_LISTTYPE( data->i ) );
  1123 	    if( ta_status.vertex_count != 0 ) {
  1124 		ta_fill_vertexes();
  1125 		ta_commit_polygon();
  1128 	    ta_parse_sprite_context(data);
  1129 	    break;
  1130 	case TA_CMD_VERTEX:
  1131 	    ta_status.state = STATE_IN_POLYGON;
  1132 	    ta_parse_vertex(data);
  1134 	    if( ta_status.state == STATE_EXPECT_VERTEX_BLOCK2 ) {
  1135 		if( TA_IS_END_VERTEX(data[0].i) ) {
  1136 		    ta_status.state = STATE_EXPECT_END_VERTEX_BLOCK2;
  1138 	    } else if( TA_IS_END_VERTEX(data->i) ) {
  1139 		if( ta_status.vertex_count < 3 ) {
  1140 		    ta_bad_input_error();
  1141 		} else {
  1142 		    ta_commit_polygon();
  1144 		ta_status.vertex_count = 0;
  1145 		ta_status.poly_parity = 0;
  1146 		ta_status.state = STATE_IN_LIST;
  1147 	    } else if( ta_status.vertex_count == ta_status.max_vertex ) {
  1148 		ta_split_polygon();
  1150 	    break;
  1151 	default:
  1152 	    if( ta_status.state == STATE_IN_POLYGON ) {
  1153 		ta_bad_input_error();
  1156 	break;
  1163 /**
  1164  * Write a block of data to the tile accelerator, adding the data to the 
  1165  * current scene. We don't make any particular attempt to interpret the data
  1166  * at this stage, deferring that until render time.
  1168  * Currently copies the data verbatim to the vertex buffer, processing only
  1169  * far enough to generate the correct end-of-list events. Tile buffer is
  1170  * entirely ignored.
  1171  */
  1172 void pvr2_ta_write( char *buf, uint32_t length )
  1174     if( ta_status.debug_output ) {
  1175 	fwrite_dump32( (uint32_t *)buf, length, stderr );
  1178     for( ; length >=32; length -= 32 ) {
  1179 	pvr2_ta_process_block( buf );
  1180 	buf += 32;
.