Search
lxdream.org :: lxdream/src/pvr2/tacore.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/pvr2/tacore.c
changeset 953:f4a156508ad1
prev801:92b518a2e915
next1067:d3c00ffccfcd
author nkeynes
date Sun Jul 05 13:53:48 2009 +1000 (14 years ago)
permissions -rw-r--r--
last change No-op merge lxdream-render to remove head (actually long since merged)
view annotate diff log raw
     1 /**
     2  * $Id$
     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 <string.h>
    19 #include "lxdream.h"
    20 #include "pvr2/pvr2.h"
    21 #include "pvr2/pvr2mmio.h"
    22 #include "asic.h"
    23 #include "dream.h"
    25 #define STATE_IDLE                 0
    26 #define STATE_IN_LIST              1
    27 #define STATE_IN_POLYGON           2
    28 #define STATE_EXPECT_POLY_BLOCK2   3
    29 #define STATE_EXPECT_VERTEX_BLOCK2 4
    30 #define STATE_ERROR                5
    31 #define STATE_EXPECT_END_VERTEX_BLOCK2 7
    33 #define TA_CMD(i) ( (i) >> 29 )
    34 #define TA_CMD_END_LIST 0
    35 #define TA_CMD_CLIP 1
    36 #define TA_CMD_POLYGON_CONTEXT 4
    37 #define TA_CMD_SPRITE_CONTEXT 5
    38 #define TA_CMD_VERTEX 7
    40 #define TA_LIST_NONE -1
    41 #define TA_LIST_OPAQUE 0
    42 #define TA_LIST_OPAQUE_MOD 1
    43 #define TA_LIST_TRANS 2
    44 #define TA_LIST_TRANS_MOD 3
    45 #define TA_LIST_PUNCH_OUT 4
    46 #define TA_IS_MODIFIER_LIST(list) (list == TA_LIST_OPAQUE_MOD || list == TA_LIST_TRANS_MOD)
    48 #define TA_GROW_UP 0
    49 #define TA_GROW_DOWN 1
    51 #define TA_VERTEX_NONE                        -1
    52 #define TA_VERTEX_PACKED                      0x00
    53 #define TA_VERTEX_TEX_PACKED                  0x08
    54 #define TA_VERTEX_TEX_SPEC_PACKED             0x0C
    55 #define TA_VERTEX_TEX_UV16_PACKED             0x09
    56 #define TA_VERTEX_TEX_UV16_SPEC_PACKED        0x0D
    57 #define TA_VERTEX_FLOAT                       0x10
    58 #define TA_VERTEX_TEX_FLOAT                   0x18
    59 #define TA_VERTEX_TEX_SPEC_FLOAT              0x1C
    60 #define TA_VERTEX_TEX_UV16_FLOAT              0x19
    61 #define TA_VERTEX_TEX_UV16_SPEC_FLOAT         0x1D
    62 #define TA_VERTEX_INTENSITY                   0x20
    63 #define TA_VERTEX_TEX_INTENSITY               0x28
    64 #define TA_VERTEX_TEX_SPEC_INTENSITY          0x2C
    65 #define TA_VERTEX_TEX_UV16_INTENSITY          0x29
    66 #define TA_VERTEX_TEX_UV16_SPEC_INTENSITY     0x2D
    67 #define TA_VERTEX_PACKED_MOD                  0x40
    68 #define TA_VERTEX_TEX_PACKED_MOD              0x48
    69 #define TA_VERTEX_TEX_SPEC_PACKED_MOD         0x4C
    70 #define TA_VERTEX_TEX_UV16_PACKED_MOD         0x49
    71 #define TA_VERTEX_TEX_UV16_SPEC_PACKED_MOD    0x4D
    72 #define TA_VERTEX_INTENSITY_MOD               0x60
    73 #define TA_VERTEX_TEX_INTENSITY_MOD           0x68
    74 #define TA_VERTEX_TEX_SPEC_INTENSITY_MOD      0x6C
    75 #define TA_VERTEX_TEX_UV16_INTENSITY_MOD      0x69
    76 #define TA_VERTEX_TEX_UV16_SPEC_INTENSITY_MOD 0x6D
    77 #define TA_VERTEX_SPRITE                      0x80
    78 #define TA_VERTEX_TEX_SPRITE                  0x88
    79 #define TA_VERTEX_MOD_VOLUME                  0x81
    80 #define TA_VERTEX_LISTLESS                    0xFF
    82 #define TA_IS_NORMAL_POLY() (ta_status.current_vertex_type < TA_VERTEX_SPRITE)
    84 static int strip_lengths[4] = {3,4,6,8}; /* in vertexes */
    85 #define TA_POLYCMD_LISTTYPE(i) ( ((i) >> 24) & 0x0F )
    86 #define TA_POLYCMD_USELENGTH(i) ( i & 0x00800000 )
    87 #define TA_POLYCMD_LENGTH(i)  strip_lengths[((i >> 18) & 0x03)]
    88 #define TA_POLYCMD_CLIP(i)  ((i>>16)&0x03)
    89 #define TA_POLYCMD_CLIP_NONE 0
    90 #define TA_POLYCMD_CLIP_INSIDE 2
    91 #define TA_POLYCMD_CLIP_OUTSIDE 3
    92 #define TA_POLYCMD_COLOURFMT(i)  (i & 0x00000030)
    93 #define TA_POLYCMD_COLOURFMT_ARGB32 0x00000000
    94 #define TA_POLYCMD_COLOURFMT_FLOAT 0x00000010
    95 #define TA_POLYCMD_COLOURFMT_INTENSITY 0x00000020
    96 #define TA_POLYCMD_COLOURFMT_LASTINT 0x00000030
    98 #define TA_POLYCMD_MODIFIED 0x00000080
    99 #define TA_POLYCMD_FULLMOD  0x00000040
   100 #define TA_POLYCMD_TEXTURED 0x00000008
   101 #define TA_POLYCMD_SPECULAR 0x00000004
   102 #define TA_POLYCMD_SHADED 0x00000002
   103 #define TA_POLYCMD_UV16 0x00000001
   105 #define TA_POLYCMD_IS_SPECULAR(i) ((i & 0x0000000C)==0x0000000C) /* Only applies to textured polys */
   106 #define TA_POLYCMD_IS_FULLMOD(i) ((i & 0x000000C0)==0x000000C0)
   109 #define TA_IS_END_VERTEX(i) (i & 0x10000000)
   111 /** Note these are not the IEEE 754 definitions - the TA treats NANs
   112  * as if they were INFs of the appropriate sign.
   113  */
   114 #define TA_IS_INF(f) (((*((uint32_t *)&f)) & 0xFF800000) == 0x7F800000)
   115 #define TA_IS_NINF(f) (((*((uint32_t *)&f)) & 0xFF800000) == 0xFF800000)
   117 #define MIN3( x1, x2, x3 ) ( (x1)<(x2)? ((x1)<(x3)?(x1):(x3)) : ((x2)<(x3)?(x2):(x3)) )
   118 #define MAX3( x1, x2, x3 ) ( (x1)>(x2)? ((x1)>(x3)?(x1):(x3)) : ((x2)>(x3)?(x2):(x3)) )
   120 #define TILESLOT( x, y ) (ta_status.current_tile_matrix + (ta_status.current_tile_size * (y * ta_status.width+ x) << 2))
   122 #define PVRRAM(addr) (*(uint32_t *)(pvr2_main_ram + ((addr)&PVR2_RAM_MASK)))
   124 struct pvr2_ta_vertex {
   125     float x,y,z;
   126     uint32_t detail[8]; /* 0-8 detail words */
   127 };
   129 struct tile_bounds {
   130     int32_t x1, y1, x2, y2;
   131 };
   133 struct pvr2_ta_status {
   134     int32_t state;
   135     int32_t width, height; /* Tile resolution, ie 20x15 */
   136     int32_t tilelist_dir; /* Growth direction of the tilelist, 0 = up, 1 = down */
   137     uint32_t tilelist_size; /* Size of the tilelist segments */
   138     uint32_t tilelist_start; /* Initial address of the tilelist */
   139     uint32_t polybuf_start; /* Initial bank address of the polygon buffer (ie &0x00F00000) */
   140     int32_t current_vertex_type;
   141     uint32_t accept_vertexes; /* 0 = NO, 1 = YES */
   142     int32_t vertex_count; /* index of last start-vertex seen, or -1 if no vertexes 
   143      * are present
   144      */
   145     uint32_t max_vertex;     /* Maximum number of vertexes in the current polygon (3/4/6/8) */
   146     uint32_t current_list_type;
   147     uint32_t current_tile_matrix; /* Memory location of the first tile for the current list. */
   148     uint32_t current_tile_size; /* Size of the tile matrix space  in 32-bit words (0/8/16/32)*/
   149     uint32_t intensity1, intensity2;
   150     struct tile_bounds clip;
   151     int32_t clip_mode;
   152     /**
   153      * Current working object
   154      */
   155     int32_t poly_context_size;
   156     int32_t poly_vertex_size;
   157     int32_t poly_parity;
   158     uint32_t poly_context[5];
   159     uint32_t poly_pointer;
   160     struct tile_bounds last_triangle_bounds;
   161     struct pvr2_ta_vertex poly_vertex[8];
   162     uint32_t debug_output;
   163 };
   165 static struct pvr2_ta_status ta_status;
   167 static int tilematrix_sizes[4] = {0,8,16,32};
   169 /**
   170  * Convenience union - ta data is either 32-bit integer or 32-bit float.
   171  */
   172 union ta_data {
   173     unsigned int i;
   174     float f;
   175 };
   178 void pvr2_ta_reset() {
   179     ta_status.state = STATE_ERROR; /* State not valid until initialized */
   180     ta_status.debug_output = 0;
   181 }
   183 void pvr2_ta_save_state( FILE *f )
   184 {
   185     fwrite( &ta_status, sizeof(ta_status), 1, f );
   186 }
   188 int pvr2_ta_load_state( FILE *f )
   189 {
   190     if( fread( &ta_status, sizeof(ta_status), 1, f ) != 1 )
   191         return 1;
   192     return 0;
   193 }
   195 void pvr2_ta_init() {
   196     ta_status.state = STATE_IDLE;
   197     ta_status.current_list_type = -1;
   198     ta_status.current_vertex_type = -1;
   199     ta_status.poly_parity = 0;
   200     ta_status.vertex_count = 0;
   201     ta_status.max_vertex = 3;
   202     ta_status.current_vertex_type = TA_VERTEX_LISTLESS;
   203     ta_status.poly_vertex_size = 0;
   204     memset(&ta_status.poly_context[1], 0, 4);
   205     ta_status.last_triangle_bounds.x1 = -1;
   206     ta_status.accept_vertexes = TRUE;
   207     ta_status.clip.x1 = 0;
   208     ta_status.clip.y1 = 0;
   209     ta_status.clip_mode = TA_POLYCMD_CLIP_NONE;
   211     uint32_t size = MMIO_READ( PVR2, TA_TILESIZE );
   212     ta_status.width = (size & 0xFFFF) + 1;
   213     ta_status.height = (size >> 16) + 1;
   214     ta_status.clip.x2 = ta_status.width-1;
   215     ta_status.clip.y2 = ta_status.height-1;
   216     uint32_t control = MMIO_READ( PVR2, TA_TILECFG );
   217     ta_status.tilelist_dir = (control >> 20) & 0x01;
   218     ta_status.tilelist_size = tilematrix_sizes[ (control & 0x03) ];
   219     MMIO_WRITE( PVR2, TA_POLYPOS, MMIO_READ( PVR2, TA_POLYBASE ) );
   220     uint32_t plistpos = MMIO_READ( PVR2, TA_LISTBASE ) >> 2;
   221     if( ta_status.tilelist_dir == TA_GROW_DOWN ) {
   222         plistpos -= ta_status.tilelist_size;
   223     }
   224     MMIO_WRITE( PVR2, TA_LISTPOS, plistpos );
   225     ta_status.tilelist_start = plistpos;
   226     ta_status.polybuf_start = MMIO_READ( PVR2, TA_POLYBASE ) & 0x00F00000;
   227 }
   229 static uint32_t parse_float_colour( float a, float r, float g, float b ) {
   230     int ai,ri,gi,bi;
   232     if( TA_IS_INF(a) ) {
   233         ai = 255;
   234     } else {
   235         ai = 256 * CLAMP(a,0.0,1.0) - 1;
   236         if( ai < 0 ) ai = 0;
   237     }
   238     if( TA_IS_INF(r) ) {
   239         ri = 255;
   240     } else {
   241         ri = 256 * CLAMP(r,0.0,1.0) - 1;
   242         if( ri < 0 ) ri = 0;
   243     }
   244     if( TA_IS_INF(g) ) {
   245         gi = 255;
   246     } else {
   247         gi = 256 * CLAMP(g,0.0,1.0) - 1;
   248         if( gi < 0 ) gi = 0;
   249     }
   250     if( TA_IS_INF(b) ) {
   251         bi = 255;
   252     } else {
   253         bi = 256 * CLAMP(b,0.0,1.0) - 1;
   254         if( bi < 0 ) bi = 0;
   255     }
   256     return (ai << 24) | (ri << 16) | (gi << 8) | bi;
   257 }
   259 static uint32_t parse_intensity_colour( uint32_t base, float intensity )
   260 {
   261     unsigned int i = (unsigned int)(256 * CLAMP(intensity, 0.0,1.0));
   263     return
   264     (((((base & 0xFF) * i) & 0xFF00) |
   265             (((base & 0xFF00) * i) & 0xFF0000) |
   266             (((base & 0xFF0000) * i) & 0xFF000000)) >> 8) |
   267             (base & 0xFF000000);
   268 }
   270 /**
   271  * Initialize the specified TA list.
   272  */
   273 static void ta_init_list( unsigned int listtype ) {
   274     int config = MMIO_READ( PVR2, TA_TILECFG );
   275     int tile_matrix = MMIO_READ( PVR2, TA_TILEBASE );
   276     int list_end = MMIO_READ( PVR2, TA_LISTEND );
   278     ta_status.current_tile_matrix = tile_matrix;
   280     /* If the list grows down, the end must be < tile matrix start. 
   281      * If it grows up, the end must be > tile matrix start.
   282      * Don't ask me why, it just does...
   283      */
   284     if( ((ta_status.tilelist_dir == TA_GROW_DOWN && list_end <= tile_matrix) ||
   285             (ta_status.tilelist_dir == TA_GROW_UP && list_end >= tile_matrix )) &&
   286             listtype <= TA_LIST_PUNCH_OUT ) {
   287         int i;
   288         uint32_t *p;
   289         for( i=0; i < listtype; i++ ) {
   290             int size = tilematrix_sizes[(config & 0x03)] << 2;
   291             ta_status.current_tile_matrix += ta_status.width * ta_status.height * size;
   292             config >>= 4;
   293         }
   294         ta_status.current_tile_size = tilematrix_sizes[(config & 0x03)];
   296         /* Initialize each tile to 0xF0000000 */
   297         if( ta_status.current_tile_size != 0 ) {
   298             p = (uint32_t *)(pvr2_main_ram + ta_status.current_tile_matrix);
   299             for( i=0; i< ta_status.width * ta_status.height; i++ ) {
   300                 *p = 0xF0000000;
   301                 p += ta_status.current_tile_size;
   302             }
   303         }
   304     } else {
   305         ta_status.current_tile_size = 0;
   306     }
   308     if( tile_matrix == list_end ) {
   309         ta_status.current_tile_size = 0;
   310     }
   312     ta_status.state = STATE_IN_LIST;
   313     ta_status.current_list_type = listtype;
   314     ta_status.last_triangle_bounds.x1 = -1;
   315 }
   317 static int list_events[5] = {EVENT_PVR_OPAQUE_DONE, EVENT_PVR_OPAQUEMOD_DONE, 
   318         EVENT_PVR_TRANS_DONE, EVENT_PVR_TRANSMOD_DONE,
   319         EVENT_PVR_PUNCHOUT_DONE };
   321 static void ta_end_list() {
   322     if( ta_status.current_list_type != TA_LIST_NONE ) {
   323         asic_event( list_events[ta_status.current_list_type] );
   324     }
   325     ta_status.current_list_type = TA_LIST_NONE;
   326     ta_status.current_vertex_type = TA_VERTEX_LISTLESS;
   327     ta_status.poly_vertex_size = 0;
   328     memset(&ta_status.poly_context[1], 0, 4);
   329     ta_status.state = STATE_IDLE;
   330 }
   332 static void ta_bad_input_error() {
   333     asic_event( EVENT_PVR_BAD_INPUT );
   334 }
   336 /**
   337  * Write data out to the polygon buffer.
   338  * If the end-of-buffer is reached, asserts EVENT_PVR_PRIM_ALLOC_FAIL
   339  * @param data to be written
   340  * @param length Number of 32-bit words to write.
   341  * @return number of words actually written
   342  */
   343 static int ta_write_polygon_buffer( uint32_t *data, int length )
   344 {
   345     int rv;
   346     int posn = MMIO_READ( PVR2, TA_POLYPOS );
   347     int end = MMIO_READ( PVR2, TA_POLYEND );
   348     uint32_t *target = (uint32_t *)(pvr2_main_ram + posn);
   349     for( rv=0; rv < length; rv++ ) {
   350         if( posn == end ) {
   351             asic_event( EVENT_PVR_PRIM_ALLOC_FAIL );
   352             //	    ta_status.state = STATE_ERROR;
   353             break;
   354         }
   355         if( posn < PVR2_RAM_SIZE ) {
   356             *target++ = *data++;
   357         }
   358         posn += 4;
   359     }
   361     MMIO_WRITE( PVR2, TA_POLYPOS, posn );
   362     return rv;
   363 }
   365 #define TA_NO_ALLOC 0xFFFFFFFF
   367 /**
   368  * Allocate a new tile list block from the grow space and update the
   369  * word at reference to be a link to the new block.
   370  */
   371 static uint32_t ta_alloc_tilelist( uint32_t reference ) {
   372     uint32_t posn = MMIO_READ( PVR2, TA_LISTPOS );
   373     uint32_t limit = MMIO_READ( PVR2, TA_LISTEND ) >> 2;
   374     uint32_t newposn;
   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_PVR_MATRIX_ALLOC_FAIL );
   387             MMIO_WRITE( PVR2, TA_LISTPOS, newposn );
   388         } else {
   389             MMIO_WRITE( PVR2, TA_LISTPOS, newposn );
   390         }
   391         PVRRAM(reference) = 0xE0000000 | (posn<<2);
   392         return posn << 2;
   393     } else {
   394         newposn = posn + ta_status.tilelist_size;
   395         if( posn == limit ) {
   396             PVRRAM(posn<<2) = 0xF0000000;
   397             PVRRAM(reference) = 0xE0000000 | (posn<<2);
   398             return TA_NO_ALLOC;
   399         } else if ( posn > limit ) {
   400             PVRRAM(reference) = 0xE0000000 | (posn<<2);
   401             return TA_NO_ALLOC;
   402         } else if( newposn >= limit ) {
   403         } else if( newposn >= (limit - ta_status.tilelist_size) ) {
   404             asic_event( EVENT_PVR_MATRIX_ALLOC_FAIL );
   405             MMIO_WRITE( PVR2, TA_LISTPOS, newposn );
   406         } else {
   407             MMIO_WRITE( PVR2, TA_LISTPOS, newposn );
   408         }	    
   409         PVRRAM(reference) = 0xE0000000 | (posn<<2);
   410         return posn << 2;
   411     }
   412 }
   414 /**
   415  * Write a tile entry out to the matrix.
   416  */
   417 static void ta_write_tile_entry( int x, int y, uint32_t tile_entry ) {
   418     uint32_t tile = TILESLOT(x,y);
   419     uint32_t tilestart = tile;
   420     uint32_t value;
   421     uint32_t lasttri = 0;
   422     int i;
   424     if( ta_status.clip_mode == TA_POLYCMD_CLIP_OUTSIDE &&
   425             x >= ta_status.clip.x1 && x <= ta_status.clip.x2 &&
   426             y >= ta_status.clip.y1 && y <= ta_status.clip.y2 ) {
   427         /* Tile clipped out */
   428         return;
   429     }
   431     if( (tile_entry & 0x80000000) && 
   432             ta_status.last_triangle_bounds.x1 != -1 &&
   433             ta_status.last_triangle_bounds.x1 <= x &&
   434             ta_status.last_triangle_bounds.x2 >= x &&
   435             ta_status.last_triangle_bounds.y1 <= y &&
   436             ta_status.last_triangle_bounds.y2 >= y ) {
   437         /* potential for triangle stacking */
   438         lasttri = tile_entry & 0xE1E00000;
   439     }
   442     if( PVRRAM(tile) == 0xF0000000 ) {
   443         PVRRAM(tile) = tile_entry;
   444         PVRRAM(tile+4) = 0xF0000000;
   445         return;
   446     }
   448     while(1) {
   449         value = PVRRAM(tile);
   450         for( i=1; i<ta_status.current_tile_size; i++ ) {
   451             tile += 4;
   452             uint32_t nextval = PVRRAM(tile);
   453             if( nextval == 0xF0000000 ) {
   454                 if( lasttri != 0 && lasttri == (value&0xE1E00000) ) {
   455                     int count = (value & 0x1E000000) + 0x02000000;
   456                     if( count < 0x20000000 ) {
   457                         PVRRAM(tile-4) = (value & 0xE1FFFFFF) | count;
   458                         return;
   459                     }
   460                 }
   461                 if( i < ta_status.current_tile_size-1 ) {
   462                     PVRRAM(tile) = tile_entry;
   463                     PVRRAM(tile+4) = 0xF0000000;
   464                     return;
   465                 }
   466             }
   467             value = nextval;
   468         }
   470         if( value == 0xF0000000 ) {
   471             tile = ta_alloc_tilelist(tile);
   472             if( tile != TA_NO_ALLOC ) {
   473                 PVRRAM(tile) = tile_entry;
   474                 PVRRAM(tile+4) = 0xF0000000;
   475             }
   476             return;
   477         } else if( (value & 0xFF000000) == 0xE0000000 ) {
   478             value &= 0x00FFFFFF;
   479             if( value == tilestart )
   480                 return; /* Loop */
   481             tilestart = tile = value;
   482         } else {
   483             /* This should never happen */
   484             return;
   485         }
   486     }
   487 }
   489 /**
   490  * Write a completed polygon out to the memory buffers 
   491  * OPTIMIZEME: This is not terribly efficient at the moment.
   492  */
   493 static void ta_commit_polygon( ) {
   494     int i, x, y;
   495     int tx[ta_status.vertex_count], ty[ta_status.vertex_count];
   496     struct tile_bounds triangle_bound[ta_status.vertex_count - 2];
   497     struct tile_bounds polygon_bound;
   498     uint32_t poly_context[5];
   500     memcpy( poly_context, ta_status.poly_context, ta_status.poly_context_size * 4 );
   502     /* Compute the tile coordinates for each vertex (need to be careful with
   503      * clamping here)
   504      */
   505     for( i=0; i<ta_status.vertex_count; i++ ) {
   506         if( ta_status.poly_vertex[i].x < 0.0 || TA_IS_NINF(ta_status.poly_vertex[i].x) ) {
   507             tx[i] = -1;
   508         } else if( ta_status.poly_vertex[i].x > (float)INT_MAX || TA_IS_INF(ta_status.poly_vertex[i].x) ) {
   509             tx[i] = INT_MAX/32;
   510         } else {
   511             tx[i] = (int)(ta_status.poly_vertex[i].x / 32.0);
   512         }
   513         if( ta_status.poly_vertex[i].y < 0.0 || TA_IS_NINF(ta_status.poly_vertex[i].y)) {
   514             ty[i] = -1;
   515         } else if( ta_status.poly_vertex[i].y > (float)INT_MAX || TA_IS_INF(ta_status.poly_vertex[i].y) ) {
   516             ty[i] = INT_MAX/32;
   517         } else {
   518             ty[i] = (int)(ta_status.poly_vertex[i].y / 32.0);
   519         }
   521     }
   523     /* Compute bounding box for each triangle individually, as well
   524      * as the overall polygon.
   525      */
   527     triangle_bound[0].x1 = MIN3(tx[0],tx[1],tx[2]);
   528     triangle_bound[0].x2 = MAX3(tx[0],tx[1],tx[2]);
   529     triangle_bound[0].y1 = MIN3(ty[0],ty[1],ty[2]);
   530     triangle_bound[0].y2 = MAX3(ty[0],ty[1],ty[2]);
   531     polygon_bound.x1 = triangle_bound[0].x1;
   532     polygon_bound.y1 = triangle_bound[0].y1;
   533     polygon_bound.x2 = triangle_bound[0].x2;
   534     polygon_bound.y2 = triangle_bound[0].y2;
   536     for( i=1; i<ta_status.vertex_count-2; i++ ) {
   537         triangle_bound[i].x1 = MIN3(tx[i],tx[i+1],tx[i+2]);
   538         triangle_bound[i].x2 = MAX3(tx[i],tx[i+1],tx[i+2]);
   539         triangle_bound[i].y1 = MIN3(ty[i],ty[i+1],ty[i+2]);
   540         triangle_bound[i].y2 = MAX3(ty[i],ty[i+1],ty[i+2]);
   541         polygon_bound.x1 = MIN(polygon_bound.x1, triangle_bound[i].x1);
   542         polygon_bound.x2 = MAX(polygon_bound.x2, triangle_bound[i].x2);
   543         polygon_bound.y1 = MIN(polygon_bound.y1, triangle_bound[i].y1);
   544         polygon_bound.y2 = MAX(polygon_bound.y2, triangle_bound[i].y2);
   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.y2 ) {
   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     ta_status.clip_mode = TA_POLYCMD_CLIP(data[0].i);
   787     if( ta_status.clip_mode == 1 ) { /* Reserved - treat as CLIP_INSIDE */
   788         ta_status.clip_mode = TA_POLYCMD_CLIP_INSIDE;
   789     }
   790     if( TA_POLYCMD_IS_SPECULAR(data[0].i) ) {
   791         ta_status.poly_context[0] |= 0x01000000;
   792     }
   793     ta_status.poly_context[1] = data[2].i;
   794     ta_status.poly_context[2] = data[3].i;
   795     if( data[0].i & TA_POLYCMD_TEXTURED ) {
   796         ta_status.poly_vertex_size = 2;
   797         ta_status.poly_vertex[2].detail[1] = data[4].i;
   798         ta_status.current_vertex_type = TA_VERTEX_TEX_SPRITE;
   799     } else {
   800         ta_status.poly_vertex_size = 1;
   801         ta_status.poly_vertex[2].detail[0] = data[4].i;
   802         ta_status.current_vertex_type = TA_VERTEX_SPRITE;
   803     }
   804     ta_status.vertex_count = 0;
   805     ta_status.max_vertex = 4;
   806     ta_status.poly_pointer = (ta_status.poly_vertex_size << 21);
   807 }
   809 /**
   810  * Copy the last read vertex into all vertexes up to max_vertex. Used for
   811  * Aborted polygons under some circumstances.
   812  */
   813 static void ta_fill_vertexes( ) {
   814     int i;
   815     for( i=ta_status.vertex_count; i<ta_status.max_vertex; i++ ) {
   816         memcpy( &ta_status.poly_vertex[i], &ta_status.poly_vertex[ta_status.vertex_count-1],
   817                 sizeof( struct pvr2_ta_vertex ) );
   818     }
   819 }
   821 static void ta_parse_vertex( union ta_data *data ) {
   822     struct pvr2_ta_vertex *vertex = &ta_status.poly_vertex[ta_status.vertex_count];
   823     vertex->x = data[1].f;
   824     vertex->y = data[2].f;
   825     vertex->z = data[3].f;
   827     switch( ta_status.current_vertex_type ) {
   828     case TA_VERTEX_PACKED:
   829         vertex->detail[0] = data[6].i;
   830         break;
   831     case TA_VERTEX_FLOAT:
   832         vertex->detail[0] = parse_float_colour( data[4].f, data[5].f, data[6].f, data[7].f );
   833         break;
   834     case TA_VERTEX_INTENSITY:
   835         vertex->detail[0] = parse_intensity_colour( ta_status.intensity1, data[6].f );
   836         break;
   838     case TA_VERTEX_TEX_SPEC_PACKED:
   839         vertex->detail[3] = data[7].i; /* ARGB */
   840         /* Fallthrough */
   841     case TA_VERTEX_TEX_PACKED:
   842         vertex->detail[0] = data[4].i; /* U */
   843         vertex->detail[1] = data[5].i; /* V */
   844         vertex->detail[2] = data[6].i; /* ARGB */
   845         break;
   846     case TA_VERTEX_TEX_UV16_SPEC_PACKED:
   847         vertex->detail[2] = data[7].i; /* ARGB */
   848         /* Fallthrough */
   849     case TA_VERTEX_TEX_UV16_PACKED:
   850         vertex->detail[0] = data[4].i; /* UV */
   851         vertex->detail[1] = data[6].i; /* ARGB */
   852         break;
   854     case TA_VERTEX_TEX_FLOAT:
   855     case TA_VERTEX_TEX_SPEC_FLOAT:
   856         vertex->detail[0] = data[4].i; /* U */
   857         vertex->detail[1] = data[5].i; /* UV */
   858         ta_status.state = STATE_EXPECT_VERTEX_BLOCK2;
   859         break;
   860     case TA_VERTEX_TEX_UV16_FLOAT:
   861     case TA_VERTEX_TEX_UV16_SPEC_FLOAT:
   862         vertex->detail[0] = data[4].i; /* UV */
   863         ta_status.state = STATE_EXPECT_VERTEX_BLOCK2;
   864         break;
   866     case TA_VERTEX_TEX_SPEC_INTENSITY:
   867         vertex->detail[3] = parse_intensity_colour( ta_status.intensity2, data[7].f );
   868         /* Fallthrough */
   869     case TA_VERTEX_TEX_INTENSITY:
   870         vertex->detail[0] = data[4].i; /* U */
   871         vertex->detail[1] = data[5].i; /* V */
   872         vertex->detail[2] = parse_intensity_colour( ta_status.intensity1, data[6].f );
   873         break;
   874     case TA_VERTEX_TEX_UV16_SPEC_INTENSITY:
   875         vertex->detail[2] = parse_intensity_colour( ta_status.intensity2, data[7].f );
   876         /* Fallthrough */
   877     case TA_VERTEX_TEX_UV16_INTENSITY:
   878         vertex->detail[0] = data[4].i; /* UV */
   879         vertex->detail[1] = parse_intensity_colour( ta_status.intensity1, data[6].f );
   880         break;
   882     case TA_VERTEX_PACKED_MOD:
   883         vertex->detail[0] = data[4].i; /* ARGB */
   884         vertex->detail[1] = data[5].i; /* ARGB */
   885         break;
   886     case TA_VERTEX_INTENSITY_MOD:
   887         vertex->detail[0] = parse_intensity_colour( ta_status.intensity1, data[4].f );
   888         vertex->detail[1] = parse_intensity_colour( ta_status.intensity2, data[5].f );
   889         break;
   891     case TA_VERTEX_TEX_SPEC_PACKED_MOD:
   892         vertex->detail[3] = data[7].i; /* ARGB0 */
   893         /* Fallthrough */
   894     case TA_VERTEX_TEX_PACKED_MOD:
   895         vertex->detail[0] = data[4].i; /* U0 */
   896         vertex->detail[1] = data[5].i; /* V0 */
   897         vertex->detail[2] = data[6].i; /* ARGB0 */
   898         ta_status.state = STATE_EXPECT_VERTEX_BLOCK2;
   899         break;
   900     case TA_VERTEX_TEX_UV16_SPEC_PACKED_MOD:
   901         vertex->detail[2] = data[7].i; /* ARGB0 */
   902         /* Fallthrough */
   903     case TA_VERTEX_TEX_UV16_PACKED_MOD:
   904         vertex->detail[0] = data[4].i; /* UV0 */
   905         vertex->detail[1] = data[6].i; /* ARGB0 */
   906         ta_status.state = STATE_EXPECT_VERTEX_BLOCK2;
   907         break;
   909     case TA_VERTEX_TEX_SPEC_INTENSITY_MOD:
   910         vertex->detail[3] = parse_intensity_colour( ta_status.intensity1, data[7].f );
   911         /* Fallthrough */
   912     case TA_VERTEX_TEX_INTENSITY_MOD:
   913         vertex->detail[0] = data[4].i; /* U0 */
   914         vertex->detail[1] = data[5].i; /* V0 */
   915         vertex->detail[2] = parse_intensity_colour( ta_status.intensity1, data[6].f );
   916         ta_status.state = STATE_EXPECT_VERTEX_BLOCK2;
   917         break;
   918     case TA_VERTEX_TEX_UV16_SPEC_INTENSITY_MOD:
   919         vertex->detail[2] = parse_intensity_colour( ta_status.intensity1, data[7].f );
   920         /* Fallthrough */
   921     case TA_VERTEX_TEX_UV16_INTENSITY_MOD:
   922         vertex->detail[0] = data[4].i; /* UV0 */
   923         vertex->detail[1] = parse_intensity_colour( ta_status.intensity1, data[6].f );
   924         ta_status.state = STATE_EXPECT_VERTEX_BLOCK2;
   925         break;
   927     case TA_VERTEX_SPRITE:
   928     case TA_VERTEX_TEX_SPRITE:
   929     case TA_VERTEX_MOD_VOLUME:
   930     case TA_VERTEX_LISTLESS:
   931         vertex++;
   932         vertex->x = data[4].f;
   933         vertex->y = data[5].f;
   934         vertex->z = data[6].f;
   935         vertex++;
   936         vertex->x = data[7].f;
   937         ta_status.vertex_count += 2;
   938         ta_status.state = STATE_EXPECT_VERTEX_BLOCK2;
   939         break;
   940     }
   941     ta_status.vertex_count++;
   942 }
   944 static void ta_parse_vertex_block2( union ta_data *data ) {
   945     struct pvr2_ta_vertex *vertex = &ta_status.poly_vertex[ta_status.vertex_count-1];
   947     switch( ta_status.current_vertex_type ) {
   948     case TA_VERTEX_TEX_SPEC_FLOAT:
   949         vertex->detail[3] = parse_float_colour( data[4].f, data[5].f, data[6].f, data[7].f );
   950         /* Fallthrough */
   951     case TA_VERTEX_TEX_FLOAT:
   952         vertex->detail[2] = parse_float_colour( data[0].f, data[1].f, data[2].f, data[3].f );
   953         break;
   954     case TA_VERTEX_TEX_UV16_SPEC_FLOAT:
   955         vertex->detail[2] = parse_float_colour( data[4].f, data[5].f, data[6].f, data[7].f );
   956         /* Fallthrough */
   957     case TA_VERTEX_TEX_UV16_FLOAT:
   958         vertex->detail[1] = parse_float_colour( data[0].f, data[1].f, data[2].f, data[3].f );
   959         break;
   960     case TA_VERTEX_TEX_PACKED_MOD:
   961         vertex->detail[3] = data[0].i; /* U1 */
   962         vertex->detail[4] = data[1].i; /* V1 */
   963         vertex->detail[5] = data[2].i; /* ARGB1 */
   964         break;
   965     case TA_VERTEX_TEX_SPEC_PACKED_MOD:
   966         vertex->detail[4] = data[0].i; /* U1 */
   967         vertex->detail[5] = data[1].i; /* V1 */
   968         vertex->detail[6] = data[2].i; /* ARGB1 */
   969         vertex->detail[7] = data[3].i; /* ARGB1 */
   970         break;
   971     case TA_VERTEX_TEX_UV16_PACKED_MOD:
   972         vertex->detail[2] = data[0].i; /* UV1 */
   973         vertex->detail[3] = data[2].i; /* ARGB1 */
   974         break;
   975     case TA_VERTEX_TEX_UV16_SPEC_PACKED_MOD:
   976         vertex->detail[3] = data[0].i; /* UV1 */
   977         vertex->detail[4] = data[2].i; /* ARGB1 */
   978         vertex->detail[5] = data[3].i; /* ARGB1 */
   979         break;
   981     case TA_VERTEX_TEX_INTENSITY_MOD:
   982         vertex->detail[3] = data[0].i; /* U1 */
   983         vertex->detail[4] = data[1].i; /* V1 */
   984         vertex->detail[5] = parse_intensity_colour( ta_status.intensity2, data[2].f ); /* ARGB1 */
   985         break;
   986     case TA_VERTEX_TEX_SPEC_INTENSITY_MOD:
   987         vertex->detail[4] = data[0].i; /* U1 */
   988         vertex->detail[5] = data[1].i; /* V1 */
   989         vertex->detail[6] = parse_intensity_colour( ta_status.intensity2, data[2].f ); /* ARGB1 */
   990         vertex->detail[7] = parse_intensity_colour( ta_status.intensity2, data[3].f ); /* ARGB1 */
   991         break;
   992     case TA_VERTEX_TEX_UV16_INTENSITY_MOD:
   993         vertex->detail[2] = data[0].i; /* UV1 */
   994         vertex->detail[3] = parse_intensity_colour( ta_status.intensity2, data[2].f ); /* ARGB1 */
   995         break;
   996     case TA_VERTEX_TEX_UV16_SPEC_INTENSITY_MOD:
   997         vertex->detail[3] = data[0].i; /* UV1 */
   998         vertex->detail[4] = parse_intensity_colour( ta_status.intensity2, data[2].f ); /* ARGB1 */
   999         vertex->detail[5] = parse_intensity_colour( ta_status.intensity2, data[3].f ); /* ARGB1 */
  1000         break;
  1002     case TA_VERTEX_SPRITE:
  1003         vertex->y = data[0].f;
  1004         vertex->z = data[1].f;
  1005         vertex++;
  1006         ta_status.vertex_count++;
  1007         vertex->x = data[2].f;
  1008         vertex->y = data[3].f;
  1009         vertex->z = 0;
  1010         vertex->detail[0] = 0;
  1011         ta_status.poly_vertex[0].detail[0] = 0;
  1012         ta_status.poly_vertex[1].detail[0] = 0;
  1013         break;
  1014     case TA_VERTEX_TEX_SPRITE:
  1015         vertex->y = data[0].f;
  1016         vertex->z = data[1].f;
  1017         vertex++;
  1018         ta_status.vertex_count++;
  1019         vertex->x = data[2].f;
  1020         vertex->y = data[3].f;
  1021         vertex->z = 0;
  1022         vertex->detail[0] = 0;
  1023         vertex->detail[1] = 0;
  1024         ta_status.poly_vertex[0].detail[0] = data[5].i;
  1025         ta_status.poly_vertex[0].detail[1] = 0;
  1026         ta_status.poly_vertex[1].detail[0] = data[6].i;
  1027         ta_status.poly_vertex[1].detail[1] = 0;
  1028         ta_status.poly_vertex[2].detail[0] = data[7].i;
  1029         break;
  1030     case TA_VERTEX_MOD_VOLUME:
  1031     case TA_VERTEX_LISTLESS:
  1032         vertex->y = data[0].f;
  1033         vertex->z = data[1].f;
  1034         break;
  1036     ta_status.state = STATE_IN_POLYGON;
  1039 /**
  1040  * Process 1 32-byte block of ta data
  1041  */
  1042 void pvr2_ta_process_block( unsigned char *input ) {
  1043     union ta_data *data = (union ta_data *)input;
  1045     switch( ta_status.state ) {
  1046     case STATE_ERROR:
  1047         /* Fatal error raised - stop processing until reset */
  1048         return;
  1050     case STATE_EXPECT_POLY_BLOCK2:
  1051         /* This is always a pair of floating-point colours */
  1052         ta_status.intensity1 = 
  1053             parse_float_colour( data[0].f, data[1].f, data[2].f, data[3].f );
  1054         ta_status.intensity2 =
  1055             parse_float_colour( data[4].f, data[5].f, data[6].f, data[7].f );
  1056         ta_status.state = STATE_IN_LIST;
  1057         break;
  1059     case STATE_EXPECT_VERTEX_BLOCK2:
  1060         ta_parse_vertex_block2( data );
  1061         if( ta_status.vertex_count == ta_status.max_vertex ) {
  1062             ta_split_polygon();
  1064         break;
  1066     case STATE_EXPECT_END_VERTEX_BLOCK2:
  1067         ta_parse_vertex_block2( data );
  1068         if( ta_status.vertex_count < 3 ) {
  1069             ta_bad_input_error();
  1070         } else {
  1071             ta_commit_polygon();
  1073         ta_status.vertex_count = 0;
  1074         ta_status.poly_parity = 0;
  1075         ta_status.state = STATE_IN_LIST;
  1076         break;
  1077     case STATE_IN_LIST:
  1078     case STATE_IN_POLYGON:
  1079     case STATE_IDLE:
  1080         switch( TA_CMD( data->i ) ) {
  1081         case TA_CMD_END_LIST:
  1082             if( ta_status.state == STATE_IN_POLYGON ) {
  1083                 ta_bad_input_error();
  1084                 ta_end_list();
  1085                 ta_status.state = STATE_ERROR; /* Abort further processing */
  1086             } else {
  1087                 ta_end_list();
  1089             break;
  1090         case TA_CMD_CLIP:
  1091             if( ta_status.state == STATE_IN_POLYGON ) {
  1092                 ta_bad_input_error();
  1093                 ta_status.accept_vertexes = FALSE;
  1094                 /* Enter stuffed up mode */
  1096             ta_status.clip.x1 = data[4].i & 0x3F;
  1097             ta_status.clip.y1 = data[5].i & 0x0F;
  1098             ta_status.clip.x2 = data[6].i & 0x3F;
  1099             ta_status.clip.y2 = data[7].i & 0x0F;
  1100             if( ta_status.clip.x2 >= ta_status.width )
  1101                 ta_status.clip.x2 = ta_status.width - 1;
  1102             if( ta_status.clip.y2 >= ta_status.height )
  1103                 ta_status.clip.y2 = ta_status.height - 1;
  1104             break;
  1105         case TA_CMD_POLYGON_CONTEXT:
  1106             if( ta_status.state == STATE_IDLE ) {
  1107                 ta_init_list( TA_POLYCMD_LISTTYPE( data->i ) );
  1110             if( ta_status.vertex_count != 0 ) {
  1111                 /* Error, and not a very well handled one either */
  1112                 ta_bad_input_error();
  1113                 ta_status.accept_vertexes = FALSE;
  1114             } else {
  1115                 if( TA_IS_MODIFIER_LIST( ta_status.current_list_type ) ) {
  1116                     ta_parse_modifier_context(data);
  1117                 } else {
  1118                     ta_parse_polygon_context(data);
  1121             break;
  1122         case TA_CMD_SPRITE_CONTEXT:
  1123             if( ta_status.state == STATE_IDLE ) {
  1124                 ta_init_list( TA_POLYCMD_LISTTYPE( data->i ) );
  1127             if( ta_status.vertex_count != 0 ) {
  1128                 ta_fill_vertexes();
  1129                 ta_commit_polygon();
  1132             ta_parse_sprite_context(data);
  1133             break;
  1134         case TA_CMD_VERTEX:
  1135             ta_status.state = STATE_IN_POLYGON;
  1136             ta_parse_vertex(data);
  1138             if( ta_status.state == STATE_EXPECT_VERTEX_BLOCK2 ) {
  1139                 if( TA_IS_END_VERTEX(data[0].i) ) {
  1140                     ta_status.state = STATE_EXPECT_END_VERTEX_BLOCK2;
  1142             } else if( TA_IS_END_VERTEX(data->i) ) {
  1143                 if( ta_status.vertex_count < 3 ) {
  1144                     ta_bad_input_error();
  1145                 } else {
  1146                     ta_commit_polygon();
  1148                 ta_status.vertex_count = 0;
  1149                 ta_status.poly_parity = 0;
  1150                 ta_status.state = STATE_IN_LIST;
  1151             } else if( ta_status.vertex_count == ta_status.max_vertex ) {
  1152                 ta_split_polygon();
  1154             break;
  1155         default:
  1156             if( ta_status.state == STATE_IN_POLYGON ) {
  1157                 ta_bad_input_error();
  1160         break;
  1165 /**
  1166  * Find the first polygon or sprite context in the supplied buffer of TA
  1167  * data.
  1168  * @return A pointer to the context, or NULL if it cannot be found 
  1169  */
  1170 uint32_t *pvr2_ta_find_polygon_context( uint32_t *buf, uint32_t length )
  1172     uint32_t *poly;
  1173     for( poly = buf; poly < buf+(length>>2); poly += 8 ) {
  1174         if( TA_CMD(*poly) == TA_CMD_POLYGON_CONTEXT ||
  1175             TA_CMD(*poly) == TA_CMD_SPRITE_CONTEXT ) {
  1176             return poly;
  1179     return NULL;
  1182 /**
  1183  * Write a block of data to the tile accelerator, adding the data to the 
  1184  * current scene. We don't make any particular attempt to interpret the data
  1185  * at this stage, deferring that until render time.
  1187  * Currently copies the data verbatim to the vertex buffer, processing only
  1188  * far enough to generate the correct end-of-list events. Tile buffer is
  1189  * entirely ignored.
  1190  */
  1191 void pvr2_ta_write( unsigned char *buf, uint32_t length )
  1193     if( ta_status.debug_output ) {
  1194         fwrite_dump32( (uint32_t *)buf, length, stderr );
  1197     for( ; length >=32; length -= 32 ) {
  1198         pvr2_ta_process_block( buf );
  1199         buf += 32;
  1203 void FASTCALL pvr2_ta_write_burst( sh4addr_t addr, unsigned char *data )
  1205     if( ta_status.debug_output ) {
  1206         fwrite_dump32( (uint32_t *)data, 32, stderr );
  1208     pvr2_ta_process_block( data );
.