Search
lxdream.org :: lxdream/src/pvr2/tacore.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/pvr2/tacore.c
changeset 203:c86a40546fc0
prev200:c3bdcd373b6d
next206:f5de539c0fcb
author nkeynes
date Sun Aug 06 06:13:51 2006 +0000 (14 years ago)
permissions -rw-r--r--
last change First pass at implementing the tile clip. Reasonably accurate wrt basic
understanding of how its supposed to work, not so accurate wrt actual
hardware behaviour
view annotate diff log raw
     1 /**
     2  * $Id: tacore.c,v 1.7 2006-08-06 06:13:51 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
    77 #define TA_IS_NORMAL_POLY() (ta_status.current_vertex_type < TA_VERTEX_SPRITE)
    79 static int strip_lengths[4] = {3,4,6,8}; /* in vertexes */
    80 #define TA_POLYCMD_LISTTYPE(i) ( ((i) >> 24) & 0x0F )
    81 #define TA_POLYCMD_USELENGTH(i) ( i & 0x00800000 )
    82 #define TA_POLYCMD_LENGTH(i)  strip_lengths[((i >> 18) & 0x03)]
    83 #define TA_POLYCMD_CLIP(i)  ((i>>16)&0x03)
    84 #define TA_POLYCMD_CLIP_NONE 0
    85 #define TA_POLYCMD_CLIP_INSIDE 2
    86 #define TA_POLYCMD_CLIP_OUTSIDE 3
    87 #define TA_POLYCMD_COLOURFMT(i)  (i & 0x00000030)
    88 #define TA_POLYCMD_COLOURFMT_ARGB32 0x00000000
    89 #define TA_POLYCMD_COLOURFMT_FLOAT 0x00000010
    90 #define TA_POLYCMD_COLOURFMT_INTENSITY 0x00000020
    91 #define TA_POLYCMD_COLOURFMT_LASTINT 0x00000030
    93 #define TA_POLYCMD_MODIFIED 0x00000080
    94 #define TA_POLYCMD_FULLMOD  0x00000040
    95 #define TA_POLYCMD_TEXTURED 0x00000008
    96 #define TA_POLYCMD_SPECULAR 0x00000004
    97 #define TA_POLYCMD_SHADED 0x00000002
    98 #define TA_POLYCMD_UV16 0x00000001
   100 #define TA_POLYCMD_IS_SPECULAR(i) ((i & 0x0000000C)==0x0000000C) /* Only applies to textured polys */
   101 #define TA_POLYCMD_IS_FULLMOD(i) ((i & 0x000000C0)==0x000000C0)
   104 #define TA_IS_END_VERTEX(i) (i & 0x10000000)
   106 /** Note these are not the IEEE 754 definitions - the TA treats NANs
   107  * as if they were INFs of the appropriate sign.
   108  */
   109 #define TA_IS_INF(f) (((*((uint32_t *)&f)) & 0xFF800000) == 0x7F800000)
   110 #define TA_IS_NINF(f) (((*((uint32_t *)&f)) & 0xFF800000) == 0xFF800000)
   112 #define MIN3( x1, x2, x3 ) ( (x1)<(x2)? ((x1)<(x3)?(x1):(x3)) : ((x2)<(x3)?(x2):(x3)) )
   113 #define MAX3( x1, x2, x3 ) ( (x1)>(x2)? ((x1)>(x3)?(x1):(x3)) : ((x2)>(x3)?(x2):(x3)) )
   115 #define TILESLOT( x, y ) (ta_status.current_tile_matrix + (ta_status.current_tile_size * (y * ta_status.width+ x) << 2))
   117 extern char *video_base;
   118 #define PVRRAM(addr) (*(uint32_t *)(video_base + ((addr)&PVR2_RAM_MASK)))
   120 struct pvr2_ta_vertex {
   121     float x,y,z;
   122     uint32_t detail[8]; /* 0-8 detail words */
   123 };
   125 struct tile_bounds {
   126     int x1, y1, x2, y2;
   127 };
   129 struct pvr2_ta_status {
   130     int state;
   131     int width, height; /* Tile resolution, ie 20x15 */
   132     int tilelist_dir; /* Growth direction of the tilelist, 0 = up, 1 = down */
   133     uint32_t tilelist_size; /* Size of the tilelist segments */
   134     uint32_t tilelist_start; /* Initial address of the tilelist */
   135     int current_vertex_type;
   136     gboolean accept_vertexes;
   137     int vertex_count; /* index of last start-vertex seen, or -1 if no vertexes 
   138 			 * are present
   139 			 */
   140     int max_vertex;     /* Maximum number of vertexes in the current polygon (3/4/6/8) */
   141     int current_list_type;
   142     uint32_t current_tile_matrix; /* Memory location of the first tile for the current list. */
   143     uint32_t current_tile_size; /* Size of the tile matrix space  in 32-bit words (0/8/16/32)*/
   144     uint32_t intensity1, intensity2;
   145     struct tile_bounds clip;
   146     int clip_mode;
   147     /**
   148      * Current working object
   149      */
   150     int poly_context_size;
   151     int poly_vertex_size;
   152     int poly_parity;
   153     uint32_t poly_context[5];
   154     uint32_t poly_pointer;
   155     struct tile_bounds last_triangle_bounds;
   156     struct pvr2_ta_vertex poly_vertex[8];
   157     int debug_output;
   158 };
   160 static struct pvr2_ta_status ta_status;
   162 static int tilematrix_sizes[4] = {0,8,16,32};
   164 /**
   165  * Convenience union - ta data is either 32-bit integer or 32-bit float.
   166  */
   167 union ta_data {
   168     unsigned int i;
   169     float f;
   170 };
   173 void pvr2_ta_reset() {
   174     ta_status.state = STATE_ERROR; /* State not valid until initialized */
   175     ta_status.debug_output = 0;
   176 }
   178 void pvr2_ta_save_state( FILE *f )
   179 {
   180     fwrite( &ta_status, sizeof(ta_status), 1, f );
   181 }
   183 int pvr2_ta_load_state( FILE *f )
   184 {
   185     if( fread( &ta_status, sizeof(ta_status), 1, f ) != 1 )
   186 	return 1;
   187     return 0;
   188 }
   190 void pvr2_ta_init() {
   191     ta_status.state = STATE_IDLE;
   192     ta_status.current_list_type = -1;
   193     ta_status.current_vertex_type = -1;
   194     ta_status.poly_parity = 0;
   195     ta_status.vertex_count = 0;
   196     ta_status.max_vertex = 3;
   197     ta_status.last_triangle_bounds.x1 = -1;
   198     ta_status.accept_vertexes = TRUE;
   199     ta_status.clip.x1 = 0;
   200     ta_status.clip.y1 = 0;
   201     ta_status.clip_mode = TA_POLYCMD_CLIP_NONE;
   203     uint32_t size = MMIO_READ( PVR2, TA_TILESIZE );
   204     ta_status.width = (size & 0xFFFF) + 1;
   205     ta_status.height = (size >> 16) + 1;
   206     ta_status.clip.x2 = ta_status.width-1;
   207     ta_status.clip.y2 = ta_status.height-1;
   208     uint32_t control = MMIO_READ( PVR2, TA_TILECFG );
   209     ta_status.tilelist_dir = (control >> 20) & 0x01;
   210     ta_status.tilelist_size = tilematrix_sizes[ (control & 0x03) ];
   211     MMIO_WRITE( PVR2, TA_POLYPOS, MMIO_READ( PVR2, TA_POLYBASE ) );
   212     uint32_t plistpos = MMIO_READ( PVR2, TA_LISTBASE ) >> 2;
   213     if( ta_status.tilelist_dir == TA_GROW_DOWN ) {
   214 	plistpos -= ta_status.tilelist_size;
   215     }
   216     MMIO_WRITE( PVR2, TA_LISTPOS, plistpos );
   217     ta_status.tilelist_start = plistpos;
   218 }
   220 static uint32_t parse_float_colour( float a, float r, float g, float b ) {
   221     int ai,ri,gi,bi;
   223     if( TA_IS_INF(a) ) {
   224 	ai = 255;
   225     } else {
   226 	ai = 256 * CLAMP(a,0.0,1.0) - 1;
   227 	if( ai < 0 ) ai = 0;
   228     }
   229     if( TA_IS_INF(r) ) {
   230 	ri = 255;
   231     } else {
   232 	ri = 256 * CLAMP(r,0.0,1.0) - 1;
   233 	if( ri < 0 ) ri = 0;
   234     }
   235     if( TA_IS_INF(g) ) {
   236 	gi = 255;
   237     } else {
   238 	gi = 256 * CLAMP(g,0.0,1.0) - 1;
   239 	if( gi < 0 ) gi = 0;
   240     }
   241     if( TA_IS_INF(b) ) {
   242 	bi = 255;
   243     } else {
   244 	bi = 256 * CLAMP(b,0.0,1.0) - 1;
   245 	if( bi < 0 ) bi = 0;
   246     }
   247     return (ai << 24) | (ri << 16) | (gi << 8) | bi;
   248 }
   250 static uint32_t parse_intensity_colour( uint32_t base, float intensity )
   251 {
   252     unsigned int i = (unsigned int)(256 * CLAMP(intensity, 0.0,1.0));
   254     return
   255 	(((((base & 0xFF) * i) & 0xFF00) |
   256 	  (((base & 0xFF00) * i) & 0xFF0000) |
   257 	  (((base & 0xFF0000) * i) & 0xFF000000)) >> 8) |
   258 	base & 0xFF000000;
   259 }
   261 /**
   262  * Initialize the specified TA list.
   263  */
   264 static void ta_init_list( unsigned int listtype ) {
   265     int config = MMIO_READ( PVR2, TA_TILECFG );
   266     int tile_matrix = MMIO_READ( PVR2, TA_TILEBASE );
   267     int list_end = MMIO_READ( PVR2, TA_LISTEND );
   269     ta_status.current_tile_matrix = tile_matrix;
   271     /* If the list grows down, the end must be < tile matrix start. 
   272      * If it grows up, the end must be > tile matrix start.
   273      * Don't ask me why, it just does...
   274      */
   275     if( ((ta_status.tilelist_dir == TA_GROW_DOWN && list_end <= tile_matrix) ||
   276 	 (ta_status.tilelist_dir == TA_GROW_UP && list_end >= tile_matrix )) &&
   277 	listtype <= TA_LIST_PUNCH_OUT ) {
   278 	int i;
   279 	uint32_t *p;
   280 	for( i=0; i < listtype; i++ ) {
   281 	    int size = tilematrix_sizes[(config & 0x03)] << 2;
   282 	    ta_status.current_tile_matrix += ta_status.width * ta_status.height * size;
   283 	    config >>= 4;
   284 	}
   285 	ta_status.current_tile_size = tilematrix_sizes[(config & 0x03)];
   287 	/* Initialize each tile to 0xF0000000 */
   288 	if( ta_status.current_tile_size != 0 ) {
   289 	    p = (uint32_t *)(video_base + ta_status.current_tile_matrix);
   290 	    for( i=0; i< ta_status.width * ta_status.height; i++ ) {
   291 		*p = 0xF0000000;
   292 		p += ta_status.current_tile_size;
   293 	    }
   294 	}
   295     } else {
   296 	ta_status.current_tile_size = 0;
   297     }
   299     if( tile_matrix == list_end ) {
   300 	ta_status.current_tile_size = 0;
   301     }
   303     ta_status.state = STATE_IN_LIST;
   304     ta_status.current_list_type = listtype;
   305     ta_status.last_triangle_bounds.x1 = -1;
   306 }
   308 static int list_events[5] = {EVENT_PVR_OPAQUE_DONE, EVENT_PVR_OPAQUEMOD_DONE, 
   309 			     EVENT_PVR_TRANS_DONE, EVENT_PVR_TRANSMOD_DONE,
   310 			     EVENT_PVR_PUNCHOUT_DONE };
   312 static void ta_end_list() {
   313     if( ta_status.current_list_type != TA_LIST_NONE ) {
   314 	asic_event( list_events[ta_status.current_list_type] );
   315 	if( ta_status.state == STATE_IN_POLYGON ) {
   316 	    asic_event( EVENT_TA_ERROR );
   317 	    asic_event( EVENT_PVR_BAD_INPUT );
   318 	}
   319 	ta_status.current_list_type = TA_LIST_NONE;
   320 	ta_status.current_vertex_type = -1;
   321 	ta_status.state = STATE_IDLE;
   322     }
   323 }
   325 /**
   326  * Write data out to the polygon buffer.
   327  * If the end-of-buffer is reached, asserts EVENT_PVR_PRIM_ALLOC_FAIL
   328  * @param data to be written
   329  * @param length Number of 32-bit words to write.
   330  * @return number of words actually written
   331  */
   332 static int ta_write_polygon_buffer( uint32_t *data, int length )
   333 {
   334     int rv;
   335     int posn = MMIO_READ( PVR2, TA_POLYPOS );
   336     int end = MMIO_READ( PVR2, TA_POLYEND );
   337     uint32_t *target = (uint32_t *)(video_base + posn);
   338     for( rv=0; rv < length; rv++ ) {
   339 	if( posn == end ) {
   340 	    asic_event( EVENT_PVR_PRIM_ALLOC_FAIL );
   341 	    asic_event( EVENT_TA_ERROR );
   342 	    //	    ta_status.state = STATE_ERROR;
   343 	    break;
   344 	}
   345 	*target++ = *data++;
   346 	posn += 4;
   347     }
   349     MMIO_WRITE( PVR2, TA_POLYPOS, posn );
   350     return rv;
   351 }
   353 #define TA_NO_ALLOC 0xFFFFFFFF
   355 /**
   356  * Allocate a new tile list block from the grow space and update the
   357  * word at reference to be a link to the new block.
   358  */
   359 static uint32_t ta_alloc_tilelist( uint32_t reference ) {
   360     uint32_t posn = MMIO_READ( PVR2, TA_LISTPOS );
   361     uint32_t limit = MMIO_READ( PVR2, TA_LISTEND ) >> 2;
   362     uint32_t newposn;
   363     uint32_t result;
   364     if( ta_status.tilelist_dir == TA_GROW_DOWN ) {
   365 	newposn = posn - ta_status.tilelist_size;
   366 	if( posn == limit ) {
   367 	    PVRRAM(posn<<2) = 0xF0000000;
   368 	    PVRRAM(reference) = 0xE0000000 | (posn<<2);
   369 	    return TA_NO_ALLOC;
   370 	} else if( posn < limit ) {
   371 	    PVRRAM(reference) = 0xE0000000 | (posn<<2);
   372 	    return TA_NO_ALLOC;
   373 	} else if( newposn <= limit ) {
   374 	} else if( newposn <= (limit + ta_status.tilelist_size) ) {
   375 	    asic_event( EVENT_TA_ERROR );
   376 	    asic_event( EVENT_PVR_MATRIX_ALLOC_FAIL );
   377 	    MMIO_WRITE( PVR2, TA_LISTPOS, newposn );
   378 	} else {
   379 	    MMIO_WRITE( PVR2, TA_LISTPOS, newposn );
   380 	}
   381 	PVRRAM(reference) = 0xE0000000 | (posn<<2);
   382 	return posn << 2;
   383     } else {
   384 	newposn = posn + ta_status.tilelist_size;
   385 	if( posn == limit ) {
   386 	    PVRRAM(posn<<2) = 0xF0000000;
   387 	    PVRRAM(reference) = 0xE0000000 | (posn<<2);
   388 	    return TA_NO_ALLOC;
   389 	} else if ( posn > limit ) {
   390 	    PVRRAM(reference) = 0xE0000000 | (posn<<2);
   391 	    return TA_NO_ALLOC;
   392 	} else if( newposn >= limit ) {
   393 	} else if( newposn >= (limit - ta_status.tilelist_size) ) {
   394 	    asic_event( EVENT_TA_ERROR );
   395 	    asic_event( EVENT_PVR_MATRIX_ALLOC_FAIL );
   396 	    MMIO_WRITE( PVR2, TA_LISTPOS, newposn );
   397 	} else {
   398 	    MMIO_WRITE( PVR2, TA_LISTPOS, newposn );
   399 	}	    
   400 	PVRRAM(reference) = 0xE0000000 | (posn<<2);
   401 	return posn << 2;
   402     }
   403 }
   405 /**
   406  * Write a tile entry out to the matrix.
   407  */
   408 static int ta_write_tile_entry( int x, int y, uint32_t tile_entry ) {
   409     uint32_t tile = TILESLOT(x,y);
   410     uint32_t tilestart = tile;
   411     uint32_t value;
   412     uint32_t lasttri = 0;
   413     int i,l;
   415     if( ta_status.clip_mode == TA_POLYCMD_CLIP_OUTSIDE &&
   416 	x >= ta_status.clip.x1 && x <= ta_status.clip.x2 &&
   417 	y >= ta_status.clip.y1 && y <= ta_status.clip.y2 ) {
   418 	/* Tile clipped out */
   419 	return 0;
   420     }
   422     if( (tile_entry & 0x80000000) && 
   423 	ta_status.last_triangle_bounds.x1 != -1 &&
   424 	ta_status.last_triangle_bounds.x1 <= x &&
   425 	ta_status.last_triangle_bounds.x2 >= x &&
   426 	ta_status.last_triangle_bounds.y1 <= y &&
   427 	ta_status.last_triangle_bounds.y2 >= y ) {
   428 	/* potential for triangle stacking */
   429 	lasttri = tile_entry & 0xE1E00000;
   430     }
   433     if( PVRRAM(tile) == 0xF0000000 ) {
   434 	PVRRAM(tile) = tile_entry;
   435 	PVRRAM(tile+4) = 0xF0000000;
   436 	return;
   437     }
   439     while(1) {
   440 	value = PVRRAM(tile);
   441 	for( i=1; i<ta_status.current_tile_size; i++ ) {
   442 	    tile += 4;
   443 	    uint32_t nextval = PVRRAM(tile);
   444 	    if( nextval == 0xF0000000 ) {
   445 		if( lasttri != 0 && lasttri == (value&0xE1E00000) ) {
   446 		    int count = (value & 0x1E000000) + 0x02000000;
   447 		    if( count < 0x20000000 ) {
   448 			PVRRAM(tile-4) = (value & 0xE1FFFFFF) | count;
   449 			return;
   450 		    }
   451 		}
   452 		if( i < ta_status.current_tile_size-1 ) {
   453 		    PVRRAM(tile) = tile_entry;
   454 		    PVRRAM(tile+4) = 0xF0000000;
   455 		    return;
   456 		}
   457 	    }
   458 	    value = nextval;
   459 	}
   461 	if( value == 0xF0000000 ) {
   462 	    tile = ta_alloc_tilelist(tile);
   463 	    if( tile != TA_NO_ALLOC ) {
   464 		PVRRAM(tile) = tile_entry;
   465 		PVRRAM(tile+4) = 0xF0000000;
   466 	    }
   467 	    return;
   468 	} else if( (value & 0xFF000000) == 0xE0000000 ) {
   469 	    value &= 0x00FFFFFF;
   470 	    if( value == tilestart )
   471 		return 0; /* Loop */
   472 	    tilestart = tile = value;
   473 	} else {
   474 	    /* This should never happen */
   475 	    return 0;
   476 	}
   477     }
   478 }
   480 /**
   481  * Write a completed polygon out to the memory buffers 
   482  * OPTIMIZEME: This is not terribly efficient at the moment.
   483  */
   484 static void ta_commit_polygon( ) {
   485     int i, x, y;
   486     int tx[ta_status.vertex_count], ty[ta_status.vertex_count];
   487     struct tile_bounds triangle_bound[ta_status.vertex_count - 2];
   488     struct tile_bounds polygon_bound;
   489     uint32_t poly_context[5];
   491     if( ta_status.vertex_count < 2 ) {
   492 	return; /* No polygons - ignore */
   493     }
   494     memcpy( poly_context, ta_status.poly_context, ta_status.poly_context_size * 4 );
   496     /* Compute the tile coordinates for each vertex (need to be careful with
   497      * clamping here)
   498      */
   499     for( i=0; i<ta_status.vertex_count; i++ ) {
   500 	if( ta_status.poly_vertex[i].x < 0.0 || TA_IS_NINF(ta_status.poly_vertex[i].x) ) {
   501 	    tx[i] = -1;
   502 	} else if( ta_status.poly_vertex[i].x > (float)INT_MAX || TA_IS_INF(ta_status.poly_vertex[i].x) ) {
   503 	    tx[i] = INT_MAX/32;
   504 	} else {
   505 	    tx[i] = (int)(ta_status.poly_vertex[i].x / 32.0);
   506 	}
   507 	if( ta_status.poly_vertex[i].y < 0.0 || TA_IS_NINF(ta_status.poly_vertex[i].y)) {
   508 	    ty[i] = -1;
   509 	} else if( ta_status.poly_vertex[i].y > (float)INT_MAX || TA_IS_INF(ta_status.poly_vertex[i].y) ) {
   510 	    ty[i] = INT_MAX/32;
   511 	} else {
   512 	    ty[i] = (int)(ta_status.poly_vertex[i].y / 32.0);
   513 	}
   515     }
   517     /* Compute bounding box for each triangle individually, as well
   518      * as the overall polygon.
   519      */
   521     for( i=0; i<ta_status.vertex_count-2; i++ ) {
   522 	triangle_bound[i].x1 = MIN3(tx[i],tx[i+1],tx[i+2]);
   523 	triangle_bound[i].x2 = MAX3(tx[i],tx[i+1],tx[i+2]);
   524 	triangle_bound[i].y1 = MIN3(ty[i],ty[i+1],ty[i+2]);
   525 	triangle_bound[i].y2 = MAX3(ty[i],ty[i+1],ty[i+2]);
   526 	if( i == 0 ) {
   527 	    polygon_bound.x1 = triangle_bound[0].x1;
   528 	    polygon_bound.y1 = triangle_bound[0].y1;
   529 	    polygon_bound.x2 = triangle_bound[0].x2;
   530 	    polygon_bound.y2 = triangle_bound[0].y2;
   531 	} else {
   532 	    polygon_bound.x1 = MIN(polygon_bound.x1, triangle_bound[i].x1);
   533 	    polygon_bound.x2 = MAX(polygon_bound.x2, triangle_bound[i].x2);
   534 	    polygon_bound.y1 = MIN(polygon_bound.y1, triangle_bound[i].y1);
   535 	    polygon_bound.y2 = MAX(polygon_bound.y2, triangle_bound[i].y2);
   536 	}
   537     }
   539     /* Clamp the polygon bounds to the frustum */
   540     if( polygon_bound.x1 < 0 ) polygon_bound.x1 = 0;
   541     if( polygon_bound.x2 >= ta_status.width ) polygon_bound.x2 = ta_status.width-1;
   542     if( polygon_bound.y1 < 0 ) polygon_bound.y1 = 0;
   543     if( polygon_bound.y2 >= ta_status.width ) polygon_bound.y2 = ta_status.height-1;
   545     /* Set the "single tile" flag if it's entirely contained in 1 tile */
   546     if( polygon_bound.x1 == polygon_bound.x2 &&
   547 	polygon_bound.y1 == polygon_bound.y2 ) {
   548 	poly_context[0] |= 0x00200000;
   549     }
   551     /* If the polygon is entirely clipped, don't even write the polygon data */
   552     switch( ta_status.clip_mode ) {
   553     case TA_POLYCMD_CLIP_NONE:
   554 	if( polygon_bound.x2 < 0 || polygon_bound.x1 >= ta_status.width ||
   555 	    polygon_bound.y2 < 0 || polygon_bound.y1 >= ta_status.height ) {
   556 	    return;
   557 	}
   558 	break;
   559     case TA_POLYCMD_CLIP_INSIDE:
   560 	if( polygon_bound.x2 < ta_status.clip.x1 || polygon_bound.x1 > ta_status.clip.x2 ||
   561 	    polygon_bound.y2 < ta_status.clip.y1 || polygon_bound.y1 > ta_status.clip.y1 ) {
   562 	    return;
   563 	} else {
   564 	    /* Clamp to clip bounds */
   565 	    if( polygon_bound.x1 < ta_status.clip.x1 ) polygon_bound.x1 = ta_status.clip.x1;
   566 	    if( polygon_bound.x2 > ta_status.clip.x2 ) polygon_bound.x2 = ta_status.clip.x2;
   567 	    if( polygon_bound.y1 < ta_status.clip.y1 ) polygon_bound.y1 = ta_status.clip.y1;
   568 	    if( polygon_bound.y2 > ta_status.clip.y2 ) polygon_bound.y2 = ta_status.clip.y2;
   569 	}
   570 	break;
   571     case TA_POLYCMD_CLIP_OUTSIDE:
   572 	if( polygon_bound.x1 >= ta_status.clip.x1 && polygon_bound.x2 <= ta_status.clip.x2 &&
   573 	    polygon_bound.y1 >= ta_status.clip.y1 && polygon_bound.y2 <= ta_status.clip.y2 ) {
   574 	    return;
   575 	}
   576 	break;
   577     }
   579     /* Ok, we're good to go - write out the polygon first */
   580     uint32_t tile_entry = MMIO_READ( PVR2, TA_POLYPOS ) >> 2 | ta_status.poly_pointer;
   582     int status = ta_write_polygon_buffer( poly_context, ta_status.poly_context_size );
   583     if( status == 0 ) {
   584 	/* No memory available - abort */
   585 	return;
   586     } else {
   587 	for( i=0; i<ta_status.vertex_count && status != 0; i++ ) {
   588 	    status = ta_write_polygon_buffer( (uint32_t *)(&ta_status.poly_vertex[i]), 3 + ta_status.poly_vertex_size );
   589 	}
   590     }
   592     if( ta_status.current_tile_size == 0 ) {
   593 	/* No memory for tile entry, so don't write anything */
   594 	return;
   595     }
   597     /* And now the tile entries. Triangles are different from everything else */
   598     if( ta_status.vertex_count == 3 ) {
   599 	tile_entry |= 0x80000000;
   600 	for( y=polygon_bound.y1; y<=polygon_bound.y2; y++ ) {
   601 	    for( x=polygon_bound.x1; x<=polygon_bound.x2; x++ ) {
   602 		ta_write_tile_entry( x,y,tile_entry );
   603 	    }
   604 	}
   605 	ta_status.last_triangle_bounds.x1 = polygon_bound.x1;
   606 	ta_status.last_triangle_bounds.y1 = polygon_bound.y1;
   607 	ta_status.last_triangle_bounds.x2 = polygon_bound.x2;
   608 	ta_status.last_triangle_bounds.y2 = polygon_bound.y2;
   609     } else if( ta_status.current_vertex_type == TA_VERTEX_SPRITE ||
   610 	       ta_status.current_vertex_type == TA_VERTEX_TEX_SPRITE ) {
   611 	tile_entry |= 0xA0000000;
   612 	for( y=polygon_bound.y1; y<=polygon_bound.y2; y++ ) {
   613 	    for( x=polygon_bound.x1; x<=polygon_bound.x2; x++ ) {
   614 		ta_write_tile_entry( x,y,tile_entry );
   615 	    }
   616 	}
   617 	ta_status.last_triangle_bounds.x1 = polygon_bound.x1;
   618 	ta_status.last_triangle_bounds.y1 = polygon_bound.y1;
   619 	ta_status.last_triangle_bounds.x2 = polygon_bound.x2;
   620 	ta_status.last_triangle_bounds.y2 = polygon_bound.y2;
   621     } else {
   622 	for( y=polygon_bound.y1; y<=polygon_bound.y2; y++ ) {
   623 	    for( x=polygon_bound.x1; x<=polygon_bound.x2; x++ ) {
   624 		uint32_t entry = tile_entry;
   625 		for( i=0; i<ta_status.vertex_count-2; i++ ) {
   626 		    if( triangle_bound[i].x1 <= x && triangle_bound[i].x2 >= x &&
   627 			triangle_bound[i].y1 <= y && triangle_bound[i].y2 >= y ) {
   628 			entry |= (0x40000000>>i);
   629 		    }
   630 		}
   631 		ta_write_tile_entry( x, y, entry );
   632 	    }
   633 	}
   634 	ta_status.last_triangle_bounds.x1 = -1;
   635     }
   636 }
   638 /**
   639  * Variant of ta_split_polygon called when vertex_count == max_vertex, but 
   640  * the client hasn't sent the LAST VERTEX flag. Commit the poly as normal
   641  * first, then start a new poly with the first 2 vertexes taken from the 
   642  * current one.
   643  */
   644 static void ta_split_polygon() {
   645     ta_commit_polygon();
   646     if( TA_IS_NORMAL_POLY() ) { 
   647 	/* This only applies to ordinary polys - Sprites + modifier lists are
   648 	 * handled differently
   649 	 */
   650 	if( ta_status.vertex_count == 3 ) {
   651 	    /* Triangles use an odd/even scheme */
   652 	    if( ta_status.poly_parity == 0 ) {
   653 		memcpy( &ta_status.poly_vertex[0], &ta_status.poly_vertex[2], 
   654 			sizeof(struct pvr2_ta_vertex) );
   655 		ta_status.poly_parity = 1;
   656 	    } else {
   657 		memcpy( &ta_status.poly_vertex[1], &ta_status.poly_vertex[2],
   658 			sizeof(struct pvr2_ta_vertex) );
   659 		ta_status.poly_parity = 0;
   660 	    }
   661 	} else {
   662 	    /* Everything else just uses the last 2 vertexes in order */
   663 	    memcpy( &ta_status.poly_vertex[0], &ta_status.poly_vertex[ta_status.vertex_count-2], 
   664 		    sizeof(struct pvr2_ta_vertex)*2 );
   665 	    ta_status.poly_parity = 0;
   666 	}
   667 	ta_status.vertex_count = 2;
   668     } else {
   669 	ta_status.vertex_count = 0;
   670     }
   671 }
   673 /**
   674  * Parse the polygon context block and setup the internal state to receive
   675  * vertexes.
   676  * @param data 32 bytes of parameter data.
   677  */
   678 static void ta_parse_polygon_context( union ta_data *data ) {
   679     int colourfmt = TA_POLYCMD_COLOURFMT(data[0].i);
   680     if( TA_POLYCMD_USELENGTH(data[0].i) ) {
   681 	ta_status.max_vertex = TA_POLYCMD_LENGTH(data[0].i);
   682     }
   683     ta_status.clip_mode = TA_POLYCMD_CLIP(data[0].i);
   684     if( ta_status.clip_mode == 1 ) { /* Reserved - treat as CLIP_INSIDE */
   685 	ta_status.clip_mode = TA_POLYCMD_CLIP_INSIDE;
   686     }
   687     ta_status.vertex_count = 0;
   688     ta_status.poly_context[0] = 
   689 	(data[1].i & 0xFC1FFFFF) | ((data[0].i & 0x0B) << 22);
   690     ta_status.poly_context[1] = data[2].i;
   691     ta_status.poly_context[3] = data[4].i;
   692     ta_status.poly_parity = 0;
   693     if( data[0].i & TA_POLYCMD_TEXTURED ) {
   694 	ta_status.current_vertex_type = data[0].i & 0x0D;
   695 	ta_status.poly_context[2] = data[3].i;
   696 	ta_status.poly_context[4] = data[5].i;
   697 	if( data[0].i & TA_POLYCMD_SPECULAR ) {
   698 	    ta_status.poly_context[0] |= 0x01000000;
   699 	    ta_status.poly_vertex_size = 4;
   700 	} else {
   701 	    ta_status.poly_vertex_size = 3;
   702 	}
   703 	if( data[0].i & TA_POLYCMD_UV16 ) {
   704 	    ta_status.poly_vertex_size--;
   705 	}
   706     } else {
   707 	ta_status.current_vertex_type = 0;
   708 	ta_status.poly_vertex_size = 1;
   709 	ta_status.poly_context[2] = 0;
   710 	ta_status.poly_context[4] = 0;
   711     }
   713     ta_status.poly_pointer = (ta_status.poly_vertex_size << 21);
   714     ta_status.poly_context_size = 3;
   715     if( data[0].i & TA_POLYCMD_MODIFIED ) {
   716 	ta_status.poly_pointer |= 0x01000000;
   717 	if( data[0].i & TA_POLYCMD_FULLMOD ) {
   718 	    ta_status.poly_context_size = 5;
   719 	    ta_status.poly_vertex_size <<= 1;
   720 	    ta_status.current_vertex_type |= 0x40;
   721 	    /* Modified/float not supported - behaves as per last intensity */
   722 	    if( colourfmt == TA_POLYCMD_COLOURFMT_FLOAT ) {
   723 		colourfmt = TA_POLYCMD_COLOURFMT_LASTINT;
   724 	    }
   725 	}
   726     }
   728     if( colourfmt == TA_POLYCMD_COLOURFMT_INTENSITY ) {
   729 	if( TA_POLYCMD_IS_FULLMOD(data[0].i) ||
   730 	    TA_POLYCMD_IS_SPECULAR(data[0].i) ) {
   731 	    ta_status.state = STATE_EXPECT_POLY_BLOCK2;
   732 	} else {
   733 	    ta_status.intensity1 = 
   734 		parse_float_colour( data[4].f, data[5].f, data[6].f, data[7].f );
   735 	}
   736     } else if( colourfmt == TA_POLYCMD_COLOURFMT_LASTINT ) {
   737 	colourfmt = TA_POLYCMD_COLOURFMT_INTENSITY;
   738     }
   740     ta_status.current_vertex_type |= colourfmt;
   741 }
   743 /**
   744  * Parse the modifier volume context block and setup the internal state to 
   745  * receive modifier vertexes.
   746  * @param data 32 bytes of parameter data.
   747  */
   748 static void ta_parse_modifier_context( union ta_data *data ) {
   749     ta_status.current_vertex_type = TA_VERTEX_MOD_VOLUME;
   750     ta_status.poly_vertex_size = 0;
   751     ta_status.poly_context_size = 3;
   752     ta_status.poly_context[0] = (data[1].i & 0xFC1FFFFF) |
   753 	((data[0].i & 0x0B)<<22);
   754     if( TA_POLYCMD_IS_SPECULAR(data[0].i) ) {
   755 	ta_status.poly_context[0] |= 0x01000000;
   756     }
   757     ta_status.poly_context[1] = 0;
   758     ta_status.poly_context[2] = 0;
   759     ta_status.vertex_count = 0;
   760     ta_status.max_vertex = 3;
   761     ta_status.poly_pointer = 0;
   762 }
   764 /**
   765  * Parse the sprite context block and setup the internal state to receive
   766  * vertexes.
   767  * @param data 32 bytes of parameter data.
   768  */
   769 static void ta_parse_sprite_context( union ta_data *data ) {
   770     ta_status.poly_context_size = 3;
   771     ta_status.poly_context[0] = (data[1].i & 0xFC1FFFFF) |
   772 	((data[0].i & 0x0B)<<22) | 0x00400000;
   773     if( TA_POLYCMD_IS_SPECULAR(data[0].i) ) {
   774 	ta_status.poly_context[0] |= 0x01000000;
   775     }
   776     ta_status.poly_context[1] = data[2].i;
   777     ta_status.poly_context[2] = data[3].i;
   778     if( data[0].i & TA_POLYCMD_TEXTURED ) {
   779 	ta_status.poly_vertex_size = 2;
   780 	ta_status.poly_vertex[2].detail[1] = data[4].i;
   781 	ta_status.current_vertex_type = TA_VERTEX_TEX_SPRITE;
   782     } else {
   783 	ta_status.poly_vertex_size = 1;
   784 	ta_status.poly_vertex[2].detail[0] = data[4].i;
   785 	ta_status.current_vertex_type = TA_VERTEX_SPRITE;
   786     }
   787     ta_status.vertex_count = 0;
   788     ta_status.max_vertex = 4;
   789     ta_status.poly_pointer = (ta_status.poly_vertex_size << 21);
   790 }
   792 /**
   793  * Copy the last read vertex into all vertexes up to max_vertex. Used for
   794  * Aborted polygons under some circumstances.
   795  */
   796 static void ta_fill_vertexes( ) {
   797     int i;
   798     for( i=ta_status.vertex_count; i<ta_status.max_vertex; i++ ) {
   799 	memcpy( &ta_status.poly_vertex[i], &ta_status.poly_vertex[ta_status.vertex_count-1],
   800 		sizeof( struct pvr2_ta_vertex ) );
   801     }
   802 }
   804 static void ta_parse_vertex( union ta_data *data ) {
   805     struct pvr2_ta_vertex *vertex = &ta_status.poly_vertex[ta_status.vertex_count];
   806     vertex->x = data[1].f;
   807     vertex->y = data[2].f;
   808     vertex->z = data[3].f;
   810     switch( ta_status.current_vertex_type ) {
   811     case TA_VERTEX_PACKED:
   812 	vertex->detail[0] = data[6].i;
   813 	break;
   814     case TA_VERTEX_FLOAT:
   815 	vertex->detail[0] = parse_float_colour( data[4].f, data[5].f, data[6].f, data[7].f );
   816 	break;
   817     case TA_VERTEX_INTENSITY:
   818 	vertex->detail[0] = parse_intensity_colour( ta_status.intensity1, data[6].f );
   819 	break;
   821     case TA_VERTEX_TEX_SPEC_PACKED:
   822 	vertex->detail[3] = data[7].i; /* ARGB */
   823 	/* Fallthrough */
   824     case TA_VERTEX_TEX_PACKED:
   825 	vertex->detail[0] = data[4].i; /* U */
   826 	vertex->detail[1] = data[5].i; /* V */
   827 	vertex->detail[2] = data[6].i; /* ARGB */
   828 	break;
   829     case TA_VERTEX_TEX_UV16_SPEC_PACKED:
   830 	vertex->detail[2] = data[7].i; /* ARGB */
   831 	/* Fallthrough */
   832     case TA_VERTEX_TEX_UV16_PACKED:
   833 	vertex->detail[0] = data[4].i; /* UV */
   834 	vertex->detail[1] = data[6].i; /* ARGB */
   835 	break;
   837     case TA_VERTEX_TEX_FLOAT:
   838     case TA_VERTEX_TEX_SPEC_FLOAT:
   839 	vertex->detail[0] = data[4].i; /* U */
   840 	vertex->detail[1] = data[5].i; /* UV */
   841 	ta_status.state = STATE_EXPECT_VERTEX_BLOCK2;
   842 	break;
   843     case TA_VERTEX_TEX_UV16_FLOAT:
   844     case TA_VERTEX_TEX_UV16_SPEC_FLOAT:
   845 	vertex->detail[0] = data[4].i; /* UV */
   846 	ta_status.state = STATE_EXPECT_VERTEX_BLOCK2;
   847 	break;
   849     case TA_VERTEX_TEX_SPEC_INTENSITY:
   850 	vertex->detail[3] = parse_intensity_colour( ta_status.intensity2, data[7].f );
   851 	/* Fallthrough */
   852     case TA_VERTEX_TEX_INTENSITY:
   853 	vertex->detail[0] = data[4].i; /* U */
   854 	vertex->detail[1] = data[5].i; /* V */
   855 	vertex->detail[2] = parse_intensity_colour( ta_status.intensity1, data[6].f );
   856 	break;
   857     case TA_VERTEX_TEX_UV16_SPEC_INTENSITY:
   858 	vertex->detail[2] = parse_intensity_colour( ta_status.intensity2, data[7].f );
   859 	/* Fallthrough */
   860     case TA_VERTEX_TEX_UV16_INTENSITY:
   861 	vertex->detail[0] = data[4].i; /* UV */
   862 	vertex->detail[1] = parse_intensity_colour( ta_status.intensity1, data[6].f );
   863 	break;
   865     case TA_VERTEX_PACKED_MOD:
   866 	vertex->detail[0] = data[4].i; /* ARGB */
   867 	vertex->detail[1] = data[5].i; /* ARGB */
   868 	break;
   869     case TA_VERTEX_INTENSITY_MOD:
   870 	vertex->detail[0] = parse_intensity_colour( ta_status.intensity1, data[4].f );
   871 	vertex->detail[1] = parse_intensity_colour( ta_status.intensity2, data[5].f );
   872 	break;
   874     case TA_VERTEX_TEX_SPEC_PACKED_MOD:
   875 	vertex->detail[3] = data[7].i; /* ARGB0 */
   876 	/* Fallthrough */
   877     case TA_VERTEX_TEX_PACKED_MOD:
   878 	vertex->detail[0] = data[4].i; /* U0 */
   879 	vertex->detail[1] = data[5].i; /* V0 */
   880 	vertex->detail[2] = data[6].i; /* ARGB0 */
   881 	ta_status.state = STATE_EXPECT_VERTEX_BLOCK2;
   882 	break;
   883     case TA_VERTEX_TEX_UV16_SPEC_PACKED_MOD:
   884 	vertex->detail[2] = data[7].i; /* ARGB0 */
   885 	/* Fallthrough */
   886     case TA_VERTEX_TEX_UV16_PACKED_MOD:
   887 	vertex->detail[0] = data[4].i; /* UV0 */
   888 	vertex->detail[1] = data[6].i; /* ARGB0 */
   889 	ta_status.state = STATE_EXPECT_VERTEX_BLOCK2;
   890 	break;
   892     case TA_VERTEX_TEX_SPEC_INTENSITY_MOD:
   893 	vertex->detail[3] = parse_intensity_colour( ta_status.intensity1, data[7].f );
   894 	/* Fallthrough */
   895     case TA_VERTEX_TEX_INTENSITY_MOD:
   896 	vertex->detail[0] = data[4].i; /* U0 */
   897 	vertex->detail[1] = data[5].i; /* V0 */
   898 	vertex->detail[2] = parse_intensity_colour( ta_status.intensity1, data[6].f );
   899 	ta_status.state = STATE_EXPECT_VERTEX_BLOCK2;
   900 	break;
   901     case TA_VERTEX_TEX_UV16_SPEC_INTENSITY_MOD:
   902 	vertex->detail[2] = parse_intensity_colour( ta_status.intensity1, data[7].f );
   903 	/* Fallthrough */
   904     case TA_VERTEX_TEX_UV16_INTENSITY_MOD:
   905 	vertex->detail[0] = data[4].i; /* UV0 */
   906 	vertex->detail[1] = parse_intensity_colour( ta_status.intensity1, data[6].f );
   907 	ta_status.state = STATE_EXPECT_VERTEX_BLOCK2;
   908 	break;
   910     case TA_VERTEX_SPRITE:
   911     case TA_VERTEX_TEX_SPRITE:
   912     case TA_VERTEX_MOD_VOLUME:
   913 	vertex++;
   914 	vertex->x = data[4].f;
   915 	vertex->y = data[5].f;
   916 	vertex->z = data[6].f;
   917 	vertex++;
   918 	vertex->x = data[7].f;
   919 	ta_status.vertex_count += 2;
   920 	ta_status.state = STATE_EXPECT_VERTEX_BLOCK2;
   921 	break;
   922     }
   923     ta_status.vertex_count++;
   924 }
   926 static void ta_parse_vertex_block2( union ta_data *data ) {
   927     struct pvr2_ta_vertex *vertex = &ta_status.poly_vertex[ta_status.vertex_count-1];
   929     switch( ta_status.current_vertex_type ) {
   930     case TA_VERTEX_TEX_SPEC_FLOAT:
   931 	vertex->detail[3] = parse_float_colour( data[4].f, data[5].f, data[6].f, data[7].f );
   932 	/* Fallthrough */
   933     case TA_VERTEX_TEX_FLOAT:
   934 	vertex->detail[2] = parse_float_colour( data[0].f, data[1].f, data[2].f, data[3].f );
   935 	break;
   936     case TA_VERTEX_TEX_UV16_SPEC_FLOAT:
   937 	vertex->detail[2] = parse_float_colour( data[4].f, data[5].f, data[6].f, data[7].f );
   938 	/* Fallthrough */
   939     case TA_VERTEX_TEX_UV16_FLOAT:
   940 	vertex->detail[1] = parse_float_colour( data[0].f, data[1].f, data[2].f, data[3].f );
   941 	break;
   942     case TA_VERTEX_TEX_PACKED_MOD:
   943 	vertex->detail[3] = data[0].i; /* U1 */
   944 	vertex->detail[4] = data[1].i; /* V1 */
   945 	vertex->detail[5] = data[2].i; /* ARGB1 */
   946 	break;
   947     case TA_VERTEX_TEX_SPEC_PACKED_MOD:
   948 	vertex->detail[4] = data[0].i; /* U1 */
   949 	vertex->detail[5] = data[1].i; /* V1 */
   950 	vertex->detail[6] = data[2].i; /* ARGB1 */
   951 	vertex->detail[7] = data[3].i; /* ARGB1 */
   952 	break;
   953     case TA_VERTEX_TEX_UV16_PACKED_MOD:
   954 	vertex->detail[2] = data[0].i; /* UV1 */
   955 	vertex->detail[3] = data[2].i; /* ARGB1 */
   956 	break;
   957     case TA_VERTEX_TEX_UV16_SPEC_PACKED_MOD:
   958 	vertex->detail[3] = data[0].i; /* UV1 */
   959 	vertex->detail[4] = data[2].i; /* ARGB1 */
   960 	vertex->detail[5] = data[3].i; /* ARGB1 */
   961 	break;
   963     case TA_VERTEX_TEX_INTENSITY_MOD:
   964 	vertex->detail[3] = data[0].i; /* U1 */
   965 	vertex->detail[4] = data[1].i; /* V1 */
   966 	vertex->detail[5] = parse_intensity_colour( ta_status.intensity2, data[2].f ); /* ARGB1 */
   967 	break;
   968     case TA_VERTEX_TEX_SPEC_INTENSITY_MOD:
   969 	vertex->detail[4] = data[0].i; /* U1 */
   970 	vertex->detail[5] = data[1].i; /* V1 */
   971 	vertex->detail[6] = parse_intensity_colour( ta_status.intensity2, data[2].f ); /* ARGB1 */
   972 	vertex->detail[7] = parse_intensity_colour( ta_status.intensity2, data[3].f ); /* ARGB1 */
   973 	break;
   974     case TA_VERTEX_TEX_UV16_INTENSITY_MOD:
   975 	vertex->detail[2] = data[0].i; /* UV1 */
   976 	vertex->detail[3] = parse_intensity_colour( ta_status.intensity2, data[2].f ); /* ARGB1 */
   977 	break;
   978     case TA_VERTEX_TEX_UV16_SPEC_INTENSITY_MOD:
   979 	vertex->detail[3] = data[0].i; /* UV1 */
   980 	vertex->detail[4] = parse_intensity_colour( ta_status.intensity2, data[2].f ); /* ARGB1 */
   981 	vertex->detail[5] = parse_intensity_colour( ta_status.intensity2, data[3].f ); /* ARGB1 */
   982 	break;
   984     case TA_VERTEX_SPRITE:
   985 	vertex->y = data[0].f;
   986 	vertex->z = data[1].f;
   987 	vertex++;
   988 	ta_status.vertex_count++;
   989 	vertex->x = data[2].f;
   990 	vertex->y = data[3].f;
   991 	vertex->z = 0;
   992 	vertex->detail[0] = 0;
   993 	ta_status.poly_vertex[0].detail[0] = 0;
   994 	ta_status.poly_vertex[1].detail[0] = 0;
   995 	break;
   996     case TA_VERTEX_TEX_SPRITE:
   997 	vertex->y = data[0].f;
   998 	vertex->z = data[1].f;
   999 	vertex++;
  1000 	ta_status.vertex_count++;
  1001 	vertex->x = data[2].f;
  1002 	vertex->y = data[3].f;
  1003 	vertex->z = 0;
  1004 	vertex->detail[0] = 0;
  1005 	vertex->detail[1] = 0;
  1006 	ta_status.poly_vertex[0].detail[0] = data[5].i;
  1007 	ta_status.poly_vertex[0].detail[1] = 0;
  1008 	ta_status.poly_vertex[1].detail[0] = data[6].i;
  1009 	ta_status.poly_vertex[1].detail[1] = 0;
  1010 	ta_status.poly_vertex[2].detail[0] = data[7].i;
  1011 	break;
  1012     case TA_VERTEX_MOD_VOLUME:
  1013 	vertex->y = data[0].f;
  1014 	vertex->z = data[1].f;
  1015 	break;
  1017     ta_status.state = STATE_IN_POLYGON;
  1020 /**
  1021  * Process 1 32-byte block of ta data
  1022  */
  1023 void pvr2_ta_process_block( char *input ) {
  1024     union ta_data *data = (union ta_data *)input;
  1026     switch( ta_status.state ) {
  1027     case STATE_ERROR:
  1028 	/* Error raised - stop processing until reset */
  1029 	return;
  1031     case STATE_EXPECT_POLY_BLOCK2:
  1032 	/* This is always a pair of floating-point colours */
  1033 	ta_status.intensity1 = 
  1034 	    parse_float_colour( data[0].f, data[1].f, data[2].f, data[3].f );
  1035 	ta_status.intensity2 =
  1036 	    parse_float_colour( data[4].f, data[5].f, data[6].f, data[7].f );
  1037 	ta_status.state = STATE_IN_LIST;
  1038 	break;
  1040     case STATE_EXPECT_VERTEX_BLOCK2:
  1041 	ta_parse_vertex_block2( data );
  1042 	if( ta_status.vertex_count == ta_status.max_vertex ) {
  1043 	    ta_split_polygon();
  1045 	break;
  1047     case STATE_EXPECT_END_VERTEX_BLOCK2:
  1048 	ta_parse_vertex_block2( data );
  1049 	ta_commit_polygon();
  1050 	ta_status.vertex_count = 0;
  1051 	ta_status.poly_parity = 0;
  1052 	ta_status.state = STATE_IN_LIST;
  1053 	break;
  1054     case STATE_IN_LIST:
  1055     case STATE_IN_POLYGON:
  1056     case STATE_IDLE:
  1057 	switch( TA_CMD( data->i ) ) {
  1058 	case TA_CMD_END_LIST:
  1059 	    ta_end_list();
  1060 	    break;
  1061 	case TA_CMD_CLIP:
  1062 	    if( ta_status.state == STATE_IN_POLYGON ) {
  1063 		asic_event( EVENT_PVR_BAD_INPUT );
  1064 		asic_event( EVENT_TA_ERROR );
  1065 		/* Enter stuffed up mode */
  1067 	    ta_status.clip.x1 = data[4].i & 0x3F;
  1068 	    ta_status.clip.y1 = data[5].i & 0x0F;
  1069 	    ta_status.clip.x2 = data[6].i & 0x3F;
  1070 	    ta_status.clip.y2 = data[7].i & 0x0F;
  1071 	    if( ta_status.clip.x2 >= ta_status.width )
  1072 		ta_status.clip.x2 = ta_status.width - 1;
  1073 	    if( ta_status.clip.y2 >= ta_status.height )
  1074 		ta_status.clip.y2 = ta_status.height - 1;
  1075 	    break;
  1076 	case TA_CMD_POLYGON_CONTEXT:
  1077 	    if( ta_status.state == STATE_IDLE ) {
  1078 		ta_init_list( TA_POLYCMD_LISTTYPE( data->i ) );
  1081 	    if( ta_status.vertex_count != 0 ) {
  1082 		/* Error, and not a very well handled one either */
  1083 		asic_event( EVENT_PVR_BAD_INPUT );
  1084 		asic_event( EVENT_TA_ERROR );
  1085 		ta_status.accept_vertexes = FALSE;
  1086 		ta_fill_vertexes();
  1087 	    } else {
  1088 		if( TA_IS_MODIFIER_LIST( ta_status.current_list_type ) ) {
  1089 		    ta_parse_modifier_context(data);
  1090 		} else {
  1091 		    ta_parse_polygon_context(data);
  1094 	    break;
  1095 	case TA_CMD_SPRITE_CONTEXT:
  1096 	    if( ta_status.state == STATE_IDLE ) {
  1097 		ta_init_list( TA_POLYCMD_LISTTYPE( data->i ) );
  1100 	    if( ta_status.vertex_count != 0 ) {
  1101 		ta_fill_vertexes();
  1102 		ta_commit_polygon();
  1105 	    ta_parse_sprite_context(data);
  1106 	    break;
  1107 	case TA_CMD_VERTEX:
  1108 	    ta_status.state = STATE_IN_POLYGON;
  1109 	    ta_parse_vertex(data);
  1111 	    if( ta_status.state == STATE_EXPECT_VERTEX_BLOCK2 ) {
  1112 		if( TA_IS_END_VERTEX(data[0].i) ) {
  1113 		    ta_status.state = STATE_EXPECT_END_VERTEX_BLOCK2;
  1115 	    } else if( TA_IS_END_VERTEX(data->i) ) {
  1116 		ta_commit_polygon();
  1117 		ta_status.vertex_count = 0;
  1118 		ta_status.poly_parity = 0;
  1119 		ta_status.state = STATE_IN_LIST;
  1120 	    } else if( ta_status.vertex_count == ta_status.max_vertex ) {
  1121 		ta_split_polygon();
  1123 	    break;
  1125 	break;
  1132 /**
  1133  * Write a block of data to the tile accelerator, adding the data to the 
  1134  * current scene. We don't make any particular attempt to interpret the data
  1135  * at this stage, deferring that until render time.
  1137  * Currently copies the data verbatim to the vertex buffer, processing only
  1138  * far enough to generate the correct end-of-list events. Tile buffer is
  1139  * entirely ignored.
  1140  */
  1141 void pvr2_ta_write( char *buf, uint32_t length )
  1143     if( ta_status.debug_output ) {
  1144 	fwrite_dump32( (uint32_t *)buf, length, stderr );
  1147     for( ; length >=32; length -= 32 ) {
  1148 	pvr2_ta_process_block( buf );
  1149 	buf += 32;
.