Search
lxdream.org :: lxdream/src/pvr2/tacore.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/pvr2/tacore.c
changeset 429:e581b90c3fb3
prev340:5ae1c80a68fb
next561:533f6b478071
author nkeynes
date Wed Nov 07 11:45:53 2007 +0000 (16 years ago)
permissions -rw-r--r--
last change Add crash handler to get a backtrace via gdb
view annotate diff log raw
     1 /**
     2  * $Id: tacore.c,v 1.12 2007-10-08 11:52:13 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_PVR_BAD_INPUT );
   331 }
   333 /**
   334  * Write data out to the polygon buffer.
   335  * If the end-of-buffer is reached, asserts EVENT_PVR_PRIM_ALLOC_FAIL
   336  * @param data to be written
   337  * @param length Number of 32-bit words to write.
   338  * @return number of words actually written
   339  */
   340 static int ta_write_polygon_buffer( uint32_t *data, int length )
   341 {
   342     int rv;
   343     int posn = MMIO_READ( PVR2, TA_POLYPOS );
   344     int end = MMIO_READ( PVR2, TA_POLYEND );
   345     uint32_t *target = (uint32_t *)(video_base + posn);
   346     for( rv=0; rv < length; rv++ ) {
   347 	if( posn == end ) {
   348 	    asic_event( EVENT_PVR_PRIM_ALLOC_FAIL );
   349 	    //	    ta_status.state = STATE_ERROR;
   350 	    break;
   351 	}
   352 	if( posn < PVR2_RAM_SIZE ) {
   353 	    *target++ = *data++;
   354 	}
   355 	posn += 4;
   356     }
   358     MMIO_WRITE( PVR2, TA_POLYPOS, posn );
   359     return rv;
   360 }
   362 #define TA_NO_ALLOC 0xFFFFFFFF
   364 /**
   365  * Allocate a new tile list block from the grow space and update the
   366  * word at reference to be a link to the new block.
   367  */
   368 static uint32_t ta_alloc_tilelist( uint32_t reference ) {
   369     uint32_t posn = MMIO_READ( PVR2, TA_LISTPOS );
   370     uint32_t limit = MMIO_READ( PVR2, TA_LISTEND ) >> 2;
   371     uint32_t newposn;
   372     if( ta_status.tilelist_dir == TA_GROW_DOWN ) {
   373 	newposn = posn - ta_status.tilelist_size;
   374 	if( posn == limit ) {
   375 	    PVRRAM(posn<<2) = 0xF0000000;
   376 	    PVRRAM(reference) = 0xE0000000 | (posn<<2);
   377 	    return TA_NO_ALLOC;
   378 	} else if( posn < limit ) {
   379 	    PVRRAM(reference) = 0xE0000000 | (posn<<2);
   380 	    return TA_NO_ALLOC;
   381 	} else if( newposn <= limit ) {
   382 	} else if( newposn <= (limit + ta_status.tilelist_size) ) {
   383 	    asic_event( EVENT_PVR_MATRIX_ALLOC_FAIL );
   384 	    MMIO_WRITE( PVR2, TA_LISTPOS, newposn );
   385 	} else {
   386 	    MMIO_WRITE( PVR2, TA_LISTPOS, newposn );
   387 	}
   388 	PVRRAM(reference) = 0xE0000000 | (posn<<2);
   389 	return posn << 2;
   390     } else {
   391 	newposn = posn + ta_status.tilelist_size;
   392 	if( posn == limit ) {
   393 	    PVRRAM(posn<<2) = 0xF0000000;
   394 	    PVRRAM(reference) = 0xE0000000 | (posn<<2);
   395 	    return TA_NO_ALLOC;
   396 	} else if ( posn > limit ) {
   397 	    PVRRAM(reference) = 0xE0000000 | (posn<<2);
   398 	    return TA_NO_ALLOC;
   399 	} else if( newposn >= limit ) {
   400 	} else if( newposn >= (limit - ta_status.tilelist_size) ) {
   401 	    asic_event( EVENT_PVR_MATRIX_ALLOC_FAIL );
   402 	    MMIO_WRITE( PVR2, TA_LISTPOS, newposn );
   403 	} else {
   404 	    MMIO_WRITE( PVR2, TA_LISTPOS, newposn );
   405 	}	    
   406 	PVRRAM(reference) = 0xE0000000 | (posn<<2);
   407 	return posn << 2;
   408     }
   409 }
   411 /**
   412  * Write a tile entry out to the matrix.
   413  */
   414 static void ta_write_tile_entry( int x, int y, uint32_t tile_entry ) {
   415     uint32_t tile = TILESLOT(x,y);
   416     uint32_t tilestart = tile;
   417     uint32_t value;
   418     uint32_t lasttri = 0;
   419     int i;
   421     if( ta_status.clip_mode == TA_POLYCMD_CLIP_OUTSIDE &&
   422 	x >= ta_status.clip.x1 && x <= ta_status.clip.x2 &&
   423 	y >= ta_status.clip.y1 && y <= ta_status.clip.y2 ) {
   424 	/* Tile clipped out */
   425 	return;
   426     }
   428     if( (tile_entry & 0x80000000) && 
   429 	ta_status.last_triangle_bounds.x1 != -1 &&
   430 	ta_status.last_triangle_bounds.x1 <= x &&
   431 	ta_status.last_triangle_bounds.x2 >= x &&
   432 	ta_status.last_triangle_bounds.y1 <= y &&
   433 	ta_status.last_triangle_bounds.y2 >= y ) {
   434 	/* potential for triangle stacking */
   435 	lasttri = tile_entry & 0xE1E00000;
   436     }
   439     if( PVRRAM(tile) == 0xF0000000 ) {
   440 	PVRRAM(tile) = tile_entry;
   441 	PVRRAM(tile+4) = 0xF0000000;
   442 	return;
   443     }
   445     while(1) {
   446 	value = PVRRAM(tile);
   447 	for( i=1; i<ta_status.current_tile_size; i++ ) {
   448 	    tile += 4;
   449 	    uint32_t nextval = PVRRAM(tile);
   450 	    if( nextval == 0xF0000000 ) {
   451 		if( lasttri != 0 && lasttri == (value&0xE1E00000) ) {
   452 		    int count = (value & 0x1E000000) + 0x02000000;
   453 		    if( count < 0x20000000 ) {
   454 			PVRRAM(tile-4) = (value & 0xE1FFFFFF) | count;
   455 			return;
   456 		    }
   457 		}
   458 		if( i < ta_status.current_tile_size-1 ) {
   459 		    PVRRAM(tile) = tile_entry;
   460 		    PVRRAM(tile+4) = 0xF0000000;
   461 		    return;
   462 		}
   463 	    }
   464 	    value = nextval;
   465 	}
   467 	if( value == 0xF0000000 ) {
   468 	    tile = ta_alloc_tilelist(tile);
   469 	    if( tile != TA_NO_ALLOC ) {
   470 		PVRRAM(tile) = tile_entry;
   471 		PVRRAM(tile+4) = 0xF0000000;
   472 	    }
   473 	    return;
   474 	} else if( (value & 0xFF000000) == 0xE0000000 ) {
   475 	    value &= 0x00FFFFFF;
   476 	    if( value == tilestart )
   477 		return; /* Loop */
   478 	    tilestart = tile = value;
   479 	} else {
   480 	    /* This should never happen */
   481 	    return;
   482 	}
   483     }
   484 }
   486 /**
   487  * Write a completed polygon out to the memory buffers 
   488  * OPTIMIZEME: This is not terribly efficient at the moment.
   489  */
   490 static void ta_commit_polygon( ) {
   491     int i, x, y;
   492     int tx[ta_status.vertex_count], ty[ta_status.vertex_count];
   493     struct tile_bounds triangle_bound[ta_status.vertex_count - 2];
   494     struct tile_bounds polygon_bound;
   495     uint32_t poly_context[5];
   497     memcpy( poly_context, ta_status.poly_context, ta_status.poly_context_size * 4 );
   499     /* Compute the tile coordinates for each vertex (need to be careful with
   500      * clamping here)
   501      */
   502     for( i=0; i<ta_status.vertex_count; i++ ) {
   503 	if( ta_status.poly_vertex[i].x < 0.0 || TA_IS_NINF(ta_status.poly_vertex[i].x) ) {
   504 	    tx[i] = -1;
   505 	} else if( ta_status.poly_vertex[i].x > (float)INT_MAX || TA_IS_INF(ta_status.poly_vertex[i].x) ) {
   506 	    tx[i] = INT_MAX/32;
   507 	} else {
   508 	    tx[i] = (int)(ta_status.poly_vertex[i].x / 32.0);
   509 	}
   510 	if( ta_status.poly_vertex[i].y < 0.0 || TA_IS_NINF(ta_status.poly_vertex[i].y)) {
   511 	    ty[i] = -1;
   512 	} else if( ta_status.poly_vertex[i].y > (float)INT_MAX || TA_IS_INF(ta_status.poly_vertex[i].y) ) {
   513 	    ty[i] = INT_MAX/32;
   514 	} else {
   515 	    ty[i] = (int)(ta_status.poly_vertex[i].y / 32.0);
   516 	}
   518     }
   520     /* Compute bounding box for each triangle individually, as well
   521      * as the overall polygon.
   522      */
   524     for( i=0; i<ta_status.vertex_count-2; i++ ) {
   525 	triangle_bound[i].x1 = MIN3(tx[i],tx[i+1],tx[i+2]);
   526 	triangle_bound[i].x2 = MAX3(tx[i],tx[i+1],tx[i+2]);
   527 	triangle_bound[i].y1 = MIN3(ty[i],ty[i+1],ty[i+2]);
   528 	triangle_bound[i].y2 = MAX3(ty[i],ty[i+1],ty[i+2]);
   529 	if( i == 0 ) {
   530 	    polygon_bound.x1 = triangle_bound[0].x1;
   531 	    polygon_bound.y1 = triangle_bound[0].y1;
   532 	    polygon_bound.x2 = triangle_bound[0].x2;
   533 	    polygon_bound.y2 = triangle_bound[0].y2;
   534 	} else {
   535 	    polygon_bound.x1 = MIN(polygon_bound.x1, triangle_bound[i].x1);
   536 	    polygon_bound.x2 = MAX(polygon_bound.x2, triangle_bound[i].x2);
   537 	    polygon_bound.y1 = MIN(polygon_bound.y1, triangle_bound[i].y1);
   538 	    polygon_bound.y2 = MAX(polygon_bound.y2, triangle_bound[i].y2);
   539 	}
   540     }
   542     /* Clamp the polygon bounds to the frustum */
   543     if( polygon_bound.x1 < 0 ) polygon_bound.x1 = 0;
   544     if( polygon_bound.x2 >= ta_status.width ) polygon_bound.x2 = ta_status.width-1;
   545     if( polygon_bound.y1 < 0 ) polygon_bound.y1 = 0;
   546     if( polygon_bound.y2 >= ta_status.width ) polygon_bound.y2 = ta_status.height-1;
   548     /* Set the "single tile" flag if it's entirely contained in 1 tile */
   549     if( polygon_bound.x1 == polygon_bound.x2 &&
   550 	polygon_bound.y1 == polygon_bound.y2 ) {
   551 	poly_context[0] |= 0x00200000;
   552     }
   554     /* If the polygon is entirely clipped, don't even write the polygon data */
   555     switch( ta_status.clip_mode ) {
   556     case TA_POLYCMD_CLIP_NONE:
   557 	if( polygon_bound.x2 < 0 || polygon_bound.x1 >= ta_status.width ||
   558 	    polygon_bound.y2 < 0 || polygon_bound.y1 >= ta_status.height ) {
   559 	    return;
   560 	}
   561 	break;
   562     case TA_POLYCMD_CLIP_INSIDE:
   563 	if( polygon_bound.x2 < ta_status.clip.x1 || polygon_bound.x1 > ta_status.clip.x2 ||
   564 	    polygon_bound.y2 < ta_status.clip.y1 || polygon_bound.y1 > ta_status.clip.y2 ) {
   565 	    return;
   566 	} else {
   567 	    /* Clamp to clip bounds */
   568 	    if( polygon_bound.x1 < ta_status.clip.x1 ) polygon_bound.x1 = ta_status.clip.x1;
   569 	    if( polygon_bound.x2 > ta_status.clip.x2 ) polygon_bound.x2 = ta_status.clip.x2;
   570 	    if( polygon_bound.y1 < ta_status.clip.y1 ) polygon_bound.y1 = ta_status.clip.y1;
   571 	    if( polygon_bound.y2 > ta_status.clip.y2 ) polygon_bound.y2 = ta_status.clip.y2;
   572 	}
   573 	break;
   574     case TA_POLYCMD_CLIP_OUTSIDE:
   575 	if( polygon_bound.x1 >= ta_status.clip.x1 && polygon_bound.x2 <= ta_status.clip.x2 &&
   576 	    polygon_bound.y1 >= ta_status.clip.y1 && polygon_bound.y2 <= ta_status.clip.y2 ) {
   577 	    return;
   578 	}
   579 	break;
   580     }
   582     /* Ok, we're good to go - write out the polygon first */
   583     uint32_t tile_entry = (MMIO_READ( PVR2, TA_POLYPOS ) - ta_status.polybuf_start) >> 2 | 
   584 	ta_status.poly_pointer;
   586     int status = ta_write_polygon_buffer( poly_context, ta_status.poly_context_size );
   587     if( status == 0 ) {
   588 	/* No memory available - abort */
   589 	return;
   590     } else {
   591 	for( i=0; i<ta_status.vertex_count && status != 0; i++ ) {
   592 	    status = ta_write_polygon_buffer( (uint32_t *)(&ta_status.poly_vertex[i]), 3 + ta_status.poly_vertex_size );
   593 	}
   594     }
   596     if( ta_status.current_tile_size == 0 ) {
   597 	/* No memory for tile entry, so don't write anything */
   598 	return;
   599     }
   601     /* And now the tile entries. Triangles are different from everything else */
   602     if( ta_status.vertex_count == 3 ) {
   603 	tile_entry |= 0x80000000;
   604 	for( y=polygon_bound.y1; y<=polygon_bound.y2; y++ ) {
   605 	    for( x=polygon_bound.x1; x<=polygon_bound.x2; x++ ) {
   606 		ta_write_tile_entry( x,y,tile_entry );
   607 	    }
   608 	}
   609 	ta_status.last_triangle_bounds.x1 = polygon_bound.x1;
   610 	ta_status.last_triangle_bounds.y1 = polygon_bound.y1;
   611 	ta_status.last_triangle_bounds.x2 = polygon_bound.x2;
   612 	ta_status.last_triangle_bounds.y2 = polygon_bound.y2;
   613     } else if( ta_status.current_vertex_type == TA_VERTEX_SPRITE ||
   614 	       ta_status.current_vertex_type == TA_VERTEX_TEX_SPRITE ) {
   615 	tile_entry |= 0xA0000000;
   616 	for( y=polygon_bound.y1; y<=polygon_bound.y2; y++ ) {
   617 	    for( x=polygon_bound.x1; x<=polygon_bound.x2; x++ ) {
   618 		ta_write_tile_entry( x,y,tile_entry );
   619 	    }
   620 	}
   621 	ta_status.last_triangle_bounds.x1 = polygon_bound.x1;
   622 	ta_status.last_triangle_bounds.y1 = polygon_bound.y1;
   623 	ta_status.last_triangle_bounds.x2 = polygon_bound.x2;
   624 	ta_status.last_triangle_bounds.y2 = polygon_bound.y2;
   625     } else {
   626 	for( y=polygon_bound.y1; y<=polygon_bound.y2; y++ ) {
   627 	    for( x=polygon_bound.x1; x<=polygon_bound.x2; x++ ) {
   628 		uint32_t entry = tile_entry;
   629 		for( i=0; i<ta_status.vertex_count-2; i++ ) {
   630 		    if( triangle_bound[i].x1 <= x && triangle_bound[i].x2 >= x &&
   631 			triangle_bound[i].y1 <= y && triangle_bound[i].y2 >= y ) {
   632 			entry |= (0x40000000>>i);
   633 		    }
   634 		}
   635 		ta_write_tile_entry( x, y, entry );
   636 	    }
   637 	}
   638 	ta_status.last_triangle_bounds.x1 = -1;
   639     }
   640 }
   642 /**
   643  * Variant of ta_split_polygon called when vertex_count == max_vertex, but 
   644  * the client hasn't sent the LAST VERTEX flag. Commit the poly as normal
   645  * first, then start a new poly with the first 2 vertexes taken from the 
   646  * current one.
   647  */
   648 static void ta_split_polygon() {
   649     ta_commit_polygon();
   650     if( TA_IS_NORMAL_POLY() ) { 
   651 	/* This only applies to ordinary polys - Sprites + modifier lists are
   652 	 * handled differently
   653 	 */
   654 	if( ta_status.vertex_count == 3 ) {
   655 	    /* Triangles use an odd/even scheme */
   656 	    if( ta_status.poly_parity == 0 ) {
   657 		memcpy( &ta_status.poly_vertex[0], &ta_status.poly_vertex[2], 
   658 			sizeof(struct pvr2_ta_vertex) );
   659 		ta_status.poly_parity = 1;
   660 	    } else {
   661 		memcpy( &ta_status.poly_vertex[1], &ta_status.poly_vertex[2],
   662 			sizeof(struct pvr2_ta_vertex) );
   663 		ta_status.poly_parity = 0;
   664 	    }
   665 	} else {
   666 	    /* Everything else just uses the last 2 vertexes in order */
   667 	    memcpy( &ta_status.poly_vertex[0], &ta_status.poly_vertex[ta_status.vertex_count-2], 
   668 		    sizeof(struct pvr2_ta_vertex)*2 );
   669 	    ta_status.poly_parity = 0;
   670 	}
   671 	ta_status.vertex_count = 2;
   672     } else {
   673 	ta_status.vertex_count = 0;
   674     }
   675 }
   677 /**
   678  * Parse the polygon context block and setup the internal state to receive
   679  * vertexes.
   680  * @param data 32 bytes of parameter data.
   681  */
   682 static void ta_parse_polygon_context( union ta_data *data ) {
   683     int colourfmt = TA_POLYCMD_COLOURFMT(data[0].i);
   684     if( TA_POLYCMD_USELENGTH(data[0].i) ) {
   685 	ta_status.max_vertex = TA_POLYCMD_LENGTH(data[0].i);
   686     }
   687     ta_status.clip_mode = TA_POLYCMD_CLIP(data[0].i);
   688     if( ta_status.clip_mode == 1 ) { /* Reserved - treat as CLIP_INSIDE */
   689 	ta_status.clip_mode = TA_POLYCMD_CLIP_INSIDE;
   690     }
   691     ta_status.vertex_count = 0;
   692     ta_status.poly_context[0] = 
   693 	(data[1].i & 0xFC1FFFFF) | ((data[0].i & 0x0B) << 22);
   694     ta_status.poly_context[1] = data[2].i;
   695     ta_status.poly_context[3] = data[4].i;
   696     ta_status.poly_parity = 0;
   697     if( data[0].i & TA_POLYCMD_TEXTURED ) {
   698 	ta_status.current_vertex_type = data[0].i & 0x0D;
   699 	ta_status.poly_context[2] = data[3].i;
   700 	ta_status.poly_context[4] = data[5].i;
   701 	if( data[0].i & TA_POLYCMD_SPECULAR ) {
   702 	    ta_status.poly_context[0] |= 0x01000000;
   703 	    ta_status.poly_vertex_size = 4;
   704 	} else {
   705 	    ta_status.poly_vertex_size = 3;
   706 	}
   707 	if( data[0].i & TA_POLYCMD_UV16 ) {
   708 	    ta_status.poly_vertex_size--;
   709 	}
   710     } else {
   711 	ta_status.current_vertex_type = 0;
   712 	ta_status.poly_vertex_size = 1;
   713 	ta_status.poly_context[2] = 0;
   714 	ta_status.poly_context[4] = 0;
   715     }
   717     ta_status.poly_pointer = (ta_status.poly_vertex_size << 21);
   718     ta_status.poly_context_size = 3;
   719     if( data[0].i & TA_POLYCMD_MODIFIED ) {
   720 	ta_status.poly_pointer |= 0x01000000;
   721 	if( data[0].i & TA_POLYCMD_FULLMOD ) {
   722 	    ta_status.poly_context_size = 5;
   723 	    ta_status.poly_vertex_size <<= 1;
   724 	    ta_status.current_vertex_type |= 0x40;
   725 	    /* Modified/float not supported - behaves as per last intensity */
   726 	    if( colourfmt == TA_POLYCMD_COLOURFMT_FLOAT ) {
   727 		colourfmt = TA_POLYCMD_COLOURFMT_LASTINT;
   728 	    }
   729 	}
   730     }
   732     if( colourfmt == TA_POLYCMD_COLOURFMT_INTENSITY ) {
   733 	if( TA_POLYCMD_IS_FULLMOD(data[0].i) ||
   734 	    TA_POLYCMD_IS_SPECULAR(data[0].i) ) {
   735 	    ta_status.state = STATE_EXPECT_POLY_BLOCK2;
   736 	} else {
   737 	    ta_status.intensity1 = 
   738 		parse_float_colour( data[4].f, data[5].f, data[6].f, data[7].f );
   739 	}
   740     } else if( colourfmt == TA_POLYCMD_COLOURFMT_LASTINT ) {
   741 	colourfmt = TA_POLYCMD_COLOURFMT_INTENSITY;
   742     }
   744     ta_status.current_vertex_type |= colourfmt;
   745 }
   747 /**
   748  * Parse the modifier volume context block and setup the internal state to 
   749  * receive modifier vertexes.
   750  * @param data 32 bytes of parameter data.
   751  */
   752 static void ta_parse_modifier_context( union ta_data *data ) {
   753     ta_status.current_vertex_type = TA_VERTEX_MOD_VOLUME;
   754     ta_status.poly_vertex_size = 0;
   755     ta_status.clip_mode = TA_POLYCMD_CLIP(data[0].i);
   756     if( ta_status.clip_mode == 1 ) { /* Reserved - treat as CLIP_INSIDE */
   757 	ta_status.clip_mode = TA_POLYCMD_CLIP_INSIDE;
   758     }
   759     ta_status.poly_context_size = 3;
   760     ta_status.poly_context[0] = (data[1].i & 0xFC1FFFFF) |
   761 	((data[0].i & 0x0B)<<22);
   762     if( TA_POLYCMD_IS_SPECULAR(data[0].i) ) {
   763 	ta_status.poly_context[0] |= 0x01000000;
   764     }
   765     ta_status.poly_context[1] = 0;
   766     ta_status.poly_context[2] = 0;
   767     ta_status.vertex_count = 0;
   768     ta_status.max_vertex = 3;
   769     ta_status.poly_pointer = 0;
   770 }
   772 /**
   773  * Parse the sprite context block and setup the internal state to receive
   774  * vertexes.
   775  * @param data 32 bytes of parameter data.
   776  */
   777 static void ta_parse_sprite_context( union ta_data *data ) {
   778     ta_status.poly_context_size = 3;
   779     ta_status.poly_context[0] = (data[1].i & 0xFC1FFFFF) |
   780 	((data[0].i & 0x0B)<<22) | 0x00400000;
   781     ta_status.clip_mode = TA_POLYCMD_CLIP(data[0].i);
   782     if( ta_status.clip_mode == 1 ) { /* Reserved - treat as CLIP_INSIDE */
   783 	ta_status.clip_mode = TA_POLYCMD_CLIP_INSIDE;
   784     }
   785     if( TA_POLYCMD_IS_SPECULAR(data[0].i) ) {
   786 	ta_status.poly_context[0] |= 0x01000000;
   787     }
   788     ta_status.poly_context[1] = data[2].i;
   789     ta_status.poly_context[2] = data[3].i;
   790     if( data[0].i & TA_POLYCMD_TEXTURED ) {
   791 	ta_status.poly_vertex_size = 2;
   792 	ta_status.poly_vertex[2].detail[1] = data[4].i;
   793 	ta_status.current_vertex_type = TA_VERTEX_TEX_SPRITE;
   794     } else {
   795 	ta_status.poly_vertex_size = 1;
   796 	ta_status.poly_vertex[2].detail[0] = data[4].i;
   797 	ta_status.current_vertex_type = TA_VERTEX_SPRITE;
   798     }
   799     ta_status.vertex_count = 0;
   800     ta_status.max_vertex = 4;
   801     ta_status.poly_pointer = (ta_status.poly_vertex_size << 21);
   802 }
   804 /**
   805  * Copy the last read vertex into all vertexes up to max_vertex. Used for
   806  * Aborted polygons under some circumstances.
   807  */
   808 static void ta_fill_vertexes( ) {
   809     int i;
   810     for( i=ta_status.vertex_count; i<ta_status.max_vertex; i++ ) {
   811 	memcpy( &ta_status.poly_vertex[i], &ta_status.poly_vertex[ta_status.vertex_count-1],
   812 		sizeof( struct pvr2_ta_vertex ) );
   813     }
   814 }
   816 static void ta_parse_vertex( union ta_data *data ) {
   817     struct pvr2_ta_vertex *vertex = &ta_status.poly_vertex[ta_status.vertex_count];
   818     vertex->x = data[1].f;
   819     vertex->y = data[2].f;
   820     vertex->z = data[3].f;
   822     switch( ta_status.current_vertex_type ) {
   823     case TA_VERTEX_PACKED:
   824 	vertex->detail[0] = data[6].i;
   825 	break;
   826     case TA_VERTEX_FLOAT:
   827 	vertex->detail[0] = parse_float_colour( data[4].f, data[5].f, data[6].f, data[7].f );
   828 	break;
   829     case TA_VERTEX_INTENSITY:
   830 	vertex->detail[0] = parse_intensity_colour( ta_status.intensity1, data[6].f );
   831 	break;
   833     case TA_VERTEX_TEX_SPEC_PACKED:
   834 	vertex->detail[3] = data[7].i; /* ARGB */
   835 	/* Fallthrough */
   836     case TA_VERTEX_TEX_PACKED:
   837 	vertex->detail[0] = data[4].i; /* U */
   838 	vertex->detail[1] = data[5].i; /* V */
   839 	vertex->detail[2] = data[6].i; /* ARGB */
   840 	break;
   841     case TA_VERTEX_TEX_UV16_SPEC_PACKED:
   842 	vertex->detail[2] = data[7].i; /* ARGB */
   843 	/* Fallthrough */
   844     case TA_VERTEX_TEX_UV16_PACKED:
   845 	vertex->detail[0] = data[4].i; /* UV */
   846 	vertex->detail[1] = data[6].i; /* ARGB */
   847 	break;
   849     case TA_VERTEX_TEX_FLOAT:
   850     case TA_VERTEX_TEX_SPEC_FLOAT:
   851 	vertex->detail[0] = data[4].i; /* U */
   852 	vertex->detail[1] = data[5].i; /* UV */
   853 	ta_status.state = STATE_EXPECT_VERTEX_BLOCK2;
   854 	break;
   855     case TA_VERTEX_TEX_UV16_FLOAT:
   856     case TA_VERTEX_TEX_UV16_SPEC_FLOAT:
   857 	vertex->detail[0] = data[4].i; /* UV */
   858 	ta_status.state = STATE_EXPECT_VERTEX_BLOCK2;
   859 	break;
   861     case TA_VERTEX_TEX_SPEC_INTENSITY:
   862 	vertex->detail[3] = parse_intensity_colour( ta_status.intensity2, data[7].f );
   863 	/* Fallthrough */
   864     case TA_VERTEX_TEX_INTENSITY:
   865 	vertex->detail[0] = data[4].i; /* U */
   866 	vertex->detail[1] = data[5].i; /* V */
   867 	vertex->detail[2] = parse_intensity_colour( ta_status.intensity1, data[6].f );
   868 	break;
   869     case TA_VERTEX_TEX_UV16_SPEC_INTENSITY:
   870 	vertex->detail[2] = parse_intensity_colour( ta_status.intensity2, data[7].f );
   871 	/* Fallthrough */
   872     case TA_VERTEX_TEX_UV16_INTENSITY:
   873 	vertex->detail[0] = data[4].i; /* UV */
   874 	vertex->detail[1] = parse_intensity_colour( ta_status.intensity1, data[6].f );
   875 	break;
   877     case TA_VERTEX_PACKED_MOD:
   878 	vertex->detail[0] = data[4].i; /* ARGB */
   879 	vertex->detail[1] = data[5].i; /* ARGB */
   880 	break;
   881     case TA_VERTEX_INTENSITY_MOD:
   882 	vertex->detail[0] = parse_intensity_colour( ta_status.intensity1, data[4].f );
   883 	vertex->detail[1] = parse_intensity_colour( ta_status.intensity2, data[5].f );
   884 	break;
   886     case TA_VERTEX_TEX_SPEC_PACKED_MOD:
   887 	vertex->detail[3] = data[7].i; /* ARGB0 */
   888 	/* Fallthrough */
   889     case TA_VERTEX_TEX_PACKED_MOD:
   890 	vertex->detail[0] = data[4].i; /* U0 */
   891 	vertex->detail[1] = data[5].i; /* V0 */
   892 	vertex->detail[2] = data[6].i; /* ARGB0 */
   893 	ta_status.state = STATE_EXPECT_VERTEX_BLOCK2;
   894 	break;
   895     case TA_VERTEX_TEX_UV16_SPEC_PACKED_MOD:
   896 	vertex->detail[2] = data[7].i; /* ARGB0 */
   897 	/* Fallthrough */
   898     case TA_VERTEX_TEX_UV16_PACKED_MOD:
   899 	vertex->detail[0] = data[4].i; /* UV0 */
   900 	vertex->detail[1] = data[6].i; /* ARGB0 */
   901 	ta_status.state = STATE_EXPECT_VERTEX_BLOCK2;
   902 	break;
   904     case TA_VERTEX_TEX_SPEC_INTENSITY_MOD:
   905 	vertex->detail[3] = parse_intensity_colour( ta_status.intensity1, data[7].f );
   906 	/* Fallthrough */
   907     case TA_VERTEX_TEX_INTENSITY_MOD:
   908 	vertex->detail[0] = data[4].i; /* U0 */
   909 	vertex->detail[1] = data[5].i; /* V0 */
   910 	vertex->detail[2] = parse_intensity_colour( ta_status.intensity1, data[6].f );
   911 	ta_status.state = STATE_EXPECT_VERTEX_BLOCK2;
   912 	break;
   913     case TA_VERTEX_TEX_UV16_SPEC_INTENSITY_MOD:
   914 	vertex->detail[2] = parse_intensity_colour( ta_status.intensity1, data[7].f );
   915 	/* Fallthrough */
   916     case TA_VERTEX_TEX_UV16_INTENSITY_MOD:
   917 	vertex->detail[0] = data[4].i; /* UV0 */
   918 	vertex->detail[1] = parse_intensity_colour( ta_status.intensity1, data[6].f );
   919 	ta_status.state = STATE_EXPECT_VERTEX_BLOCK2;
   920 	break;
   922     case TA_VERTEX_SPRITE:
   923     case TA_VERTEX_TEX_SPRITE:
   924     case TA_VERTEX_MOD_VOLUME:
   925     case TA_VERTEX_LISTLESS:
   926 	vertex++;
   927 	vertex->x = data[4].f;
   928 	vertex->y = data[5].f;
   929 	vertex->z = data[6].f;
   930 	vertex++;
   931 	vertex->x = data[7].f;
   932 	ta_status.vertex_count += 2;
   933 	ta_status.state = STATE_EXPECT_VERTEX_BLOCK2;
   934 	break;
   935     }
   936     ta_status.vertex_count++;
   937 }
   939 static void ta_parse_vertex_block2( union ta_data *data ) {
   940     struct pvr2_ta_vertex *vertex = &ta_status.poly_vertex[ta_status.vertex_count-1];
   942     switch( ta_status.current_vertex_type ) {
   943     case TA_VERTEX_TEX_SPEC_FLOAT:
   944 	vertex->detail[3] = parse_float_colour( data[4].f, data[5].f, data[6].f, data[7].f );
   945 	/* Fallthrough */
   946     case TA_VERTEX_TEX_FLOAT:
   947 	vertex->detail[2] = parse_float_colour( data[0].f, data[1].f, data[2].f, data[3].f );
   948 	break;
   949     case TA_VERTEX_TEX_UV16_SPEC_FLOAT:
   950 	vertex->detail[2] = parse_float_colour( data[4].f, data[5].f, data[6].f, data[7].f );
   951 	/* Fallthrough */
   952     case TA_VERTEX_TEX_UV16_FLOAT:
   953 	vertex->detail[1] = parse_float_colour( data[0].f, data[1].f, data[2].f, data[3].f );
   954 	break;
   955     case TA_VERTEX_TEX_PACKED_MOD:
   956 	vertex->detail[3] = data[0].i; /* U1 */
   957 	vertex->detail[4] = data[1].i; /* V1 */
   958 	vertex->detail[5] = data[2].i; /* ARGB1 */
   959 	break;
   960     case TA_VERTEX_TEX_SPEC_PACKED_MOD:
   961 	vertex->detail[4] = data[0].i; /* U1 */
   962 	vertex->detail[5] = data[1].i; /* V1 */
   963 	vertex->detail[6] = data[2].i; /* ARGB1 */
   964 	vertex->detail[7] = data[3].i; /* ARGB1 */
   965 	break;
   966     case TA_VERTEX_TEX_UV16_PACKED_MOD:
   967 	vertex->detail[2] = data[0].i; /* UV1 */
   968 	vertex->detail[3] = data[2].i; /* ARGB1 */
   969 	break;
   970     case TA_VERTEX_TEX_UV16_SPEC_PACKED_MOD:
   971 	vertex->detail[3] = data[0].i; /* UV1 */
   972 	vertex->detail[4] = data[2].i; /* ARGB1 */
   973 	vertex->detail[5] = data[3].i; /* ARGB1 */
   974 	break;
   976     case TA_VERTEX_TEX_INTENSITY_MOD:
   977 	vertex->detail[3] = data[0].i; /* U1 */
   978 	vertex->detail[4] = data[1].i; /* V1 */
   979 	vertex->detail[5] = parse_intensity_colour( ta_status.intensity2, data[2].f ); /* ARGB1 */
   980 	break;
   981     case TA_VERTEX_TEX_SPEC_INTENSITY_MOD:
   982 	vertex->detail[4] = data[0].i; /* U1 */
   983 	vertex->detail[5] = data[1].i; /* V1 */
   984 	vertex->detail[6] = parse_intensity_colour( ta_status.intensity2, data[2].f ); /* ARGB1 */
   985 	vertex->detail[7] = parse_intensity_colour( ta_status.intensity2, data[3].f ); /* ARGB1 */
   986 	break;
   987     case TA_VERTEX_TEX_UV16_INTENSITY_MOD:
   988 	vertex->detail[2] = data[0].i; /* UV1 */
   989 	vertex->detail[3] = parse_intensity_colour( ta_status.intensity2, data[2].f ); /* ARGB1 */
   990 	break;
   991     case TA_VERTEX_TEX_UV16_SPEC_INTENSITY_MOD:
   992 	vertex->detail[3] = data[0].i; /* UV1 */
   993 	vertex->detail[4] = parse_intensity_colour( ta_status.intensity2, data[2].f ); /* ARGB1 */
   994 	vertex->detail[5] = parse_intensity_colour( ta_status.intensity2, data[3].f ); /* ARGB1 */
   995 	break;
   997     case TA_VERTEX_SPRITE:
   998 	vertex->y = data[0].f;
   999 	vertex->z = data[1].f;
  1000 	vertex++;
  1001 	ta_status.vertex_count++;
  1002 	vertex->x = data[2].f;
  1003 	vertex->y = data[3].f;
  1004 	vertex->z = 0;
  1005 	vertex->detail[0] = 0;
  1006 	ta_status.poly_vertex[0].detail[0] = 0;
  1007 	ta_status.poly_vertex[1].detail[0] = 0;
  1008 	break;
  1009     case TA_VERTEX_TEX_SPRITE:
  1010 	vertex->y = data[0].f;
  1011 	vertex->z = data[1].f;
  1012 	vertex++;
  1013 	ta_status.vertex_count++;
  1014 	vertex->x = data[2].f;
  1015 	vertex->y = data[3].f;
  1016 	vertex->z = 0;
  1017 	vertex->detail[0] = 0;
  1018 	vertex->detail[1] = 0;
  1019 	ta_status.poly_vertex[0].detail[0] = data[5].i;
  1020 	ta_status.poly_vertex[0].detail[1] = 0;
  1021 	ta_status.poly_vertex[1].detail[0] = data[6].i;
  1022 	ta_status.poly_vertex[1].detail[1] = 0;
  1023 	ta_status.poly_vertex[2].detail[0] = data[7].i;
  1024 	break;
  1025     case TA_VERTEX_MOD_VOLUME:
  1026     case TA_VERTEX_LISTLESS:
  1027 	vertex->y = data[0].f;
  1028 	vertex->z = data[1].f;
  1029 	break;
  1031     ta_status.state = STATE_IN_POLYGON;
  1034 /**
  1035  * Process 1 32-byte block of ta data
  1036  */
  1037 void pvr2_ta_process_block( unsigned char *input ) {
  1038     union ta_data *data = (union ta_data *)input;
  1040     switch( ta_status.state ) {
  1041     case STATE_ERROR:
  1042 	/* Fatal error raised - stop processing until reset */
  1043 	return;
  1045     case STATE_EXPECT_POLY_BLOCK2:
  1046 	/* This is always a pair of floating-point colours */
  1047 	ta_status.intensity1 = 
  1048 	    parse_float_colour( data[0].f, data[1].f, data[2].f, data[3].f );
  1049 	ta_status.intensity2 =
  1050 	    parse_float_colour( data[4].f, data[5].f, data[6].f, data[7].f );
  1051 	ta_status.state = STATE_IN_LIST;
  1052 	break;
  1054     case STATE_EXPECT_VERTEX_BLOCK2:
  1055 	ta_parse_vertex_block2( data );
  1056 	if( ta_status.vertex_count == ta_status.max_vertex ) {
  1057 	    ta_split_polygon();
  1059 	break;
  1061     case STATE_EXPECT_END_VERTEX_BLOCK2:
  1062 	ta_parse_vertex_block2( data );
  1063 	if( ta_status.vertex_count < 3 ) {
  1064 	    ta_bad_input_error();
  1065 	} else {
  1066 	    ta_commit_polygon();
  1068 	ta_status.vertex_count = 0;
  1069 	ta_status.poly_parity = 0;
  1070 	ta_status.state = STATE_IN_LIST;
  1071 	break;
  1072     case STATE_IN_LIST:
  1073     case STATE_IN_POLYGON:
  1074     case STATE_IDLE:
  1075 	switch( TA_CMD( data->i ) ) {
  1076 	case TA_CMD_END_LIST:
  1077 	    if( ta_status.state == STATE_IN_POLYGON ) {
  1078 		ta_bad_input_error();
  1079 		ta_end_list();
  1080 		ta_status.state = STATE_ERROR; /* Abort further processing */
  1081 	    } else {
  1082 		ta_end_list();
  1084 	    break;
  1085 	case TA_CMD_CLIP:
  1086 	    if( ta_status.state == STATE_IN_POLYGON ) {
  1087 		ta_bad_input_error();
  1088 		ta_status.accept_vertexes = FALSE;
  1089 		/* Enter stuffed up mode */
  1091 	    ta_status.clip.x1 = data[4].i & 0x3F;
  1092 	    ta_status.clip.y1 = data[5].i & 0x0F;
  1093 	    ta_status.clip.x2 = data[6].i & 0x3F;
  1094 	    ta_status.clip.y2 = data[7].i & 0x0F;
  1095 	    if( ta_status.clip.x2 >= ta_status.width )
  1096 		ta_status.clip.x2 = ta_status.width - 1;
  1097 	    if( ta_status.clip.y2 >= ta_status.height )
  1098 		ta_status.clip.y2 = ta_status.height - 1;
  1099 	    break;
  1100 	case TA_CMD_POLYGON_CONTEXT:
  1101 	    if( ta_status.state == STATE_IDLE ) {
  1102 		ta_init_list( TA_POLYCMD_LISTTYPE( data->i ) );
  1105 	    if( ta_status.vertex_count != 0 ) {
  1106 		/* Error, and not a very well handled one either */
  1107 		ta_bad_input_error();
  1108 		ta_status.accept_vertexes = FALSE;
  1109 	    } else {
  1110 		if( TA_IS_MODIFIER_LIST( ta_status.current_list_type ) ) {
  1111 		    ta_parse_modifier_context(data);
  1112 		} else {
  1113 		    ta_parse_polygon_context(data);
  1116 	    break;
  1117 	case TA_CMD_SPRITE_CONTEXT:
  1118 	    if( ta_status.state == STATE_IDLE ) {
  1119 		ta_init_list( TA_POLYCMD_LISTTYPE( data->i ) );
  1122 	    if( ta_status.vertex_count != 0 ) {
  1123 		ta_fill_vertexes();
  1124 		ta_commit_polygon();
  1127 	    ta_parse_sprite_context(data);
  1128 	    break;
  1129 	case TA_CMD_VERTEX:
  1130 	    ta_status.state = STATE_IN_POLYGON;
  1131 	    ta_parse_vertex(data);
  1133 	    if( ta_status.state == STATE_EXPECT_VERTEX_BLOCK2 ) {
  1134 		if( TA_IS_END_VERTEX(data[0].i) ) {
  1135 		    ta_status.state = STATE_EXPECT_END_VERTEX_BLOCK2;
  1137 	    } else if( TA_IS_END_VERTEX(data->i) ) {
  1138 		if( ta_status.vertex_count < 3 ) {
  1139 		    ta_bad_input_error();
  1140 		} else {
  1141 		    ta_commit_polygon();
  1143 		ta_status.vertex_count = 0;
  1144 		ta_status.poly_parity = 0;
  1145 		ta_status.state = STATE_IN_LIST;
  1146 	    } else if( ta_status.vertex_count == ta_status.max_vertex ) {
  1147 		ta_split_polygon();
  1149 	    break;
  1150 	default:
  1151 	    if( ta_status.state == STATE_IN_POLYGON ) {
  1152 		ta_bad_input_error();
  1155 	break;
  1162 /**
  1163  * Write a block of data to the tile accelerator, adding the data to the 
  1164  * current scene. We don't make any particular attempt to interpret the data
  1165  * at this stage, deferring that until render time.
  1167  * Currently copies the data verbatim to the vertex buffer, processing only
  1168  * far enough to generate the correct end-of-list events. Tile buffer is
  1169  * entirely ignored.
  1170  */
  1171 void pvr2_ta_write( unsigned char *buf, uint32_t length )
  1173     if( ta_status.debug_output ) {
  1174 	fwrite_dump32( (uint32_t *)buf, length, stderr );
  1177     for( ; length >=32; length -= 32 ) {
  1178 	pvr2_ta_process_block( buf );
  1179 	buf += 32;
.