filename | src/pvr2/tacore.c |
changeset | 429:e581b90c3fb3 |
prev | 340:5ae1c80a68fb |
next | 561:533f6b478071 |
author | nkeynes |
date | Wed Oct 31 09:10:23 2007 +0000 (16 years ago) |
permissions | -rw-r--r-- |
last change | Add save/restore of render buffers in save states Gzip memory blocks in save states Move front-buffer management back to pvr2 Add screenshot preview when loading save states Various minor fixes and cleanups |
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;
1030 }
1031 ta_status.state = STATE_IN_POLYGON;
1032 }
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();
1058 }
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();
1067 }
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();
1083 }
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 */
1090 }
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 ) );
1103 }
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);
1114 }
1115 }
1116 break;
1117 case TA_CMD_SPRITE_CONTEXT:
1118 if( ta_status.state == STATE_IDLE ) {
1119 ta_init_list( TA_POLYCMD_LISTTYPE( data->i ) );
1120 }
1122 if( ta_status.vertex_count != 0 ) {
1123 ta_fill_vertexes();
1124 ta_commit_polygon();
1125 }
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;
1136 }
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();
1142 }
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();
1148 }
1149 break;
1150 default:
1151 if( ta_status.state == STATE_IN_POLYGON ) {
1152 ta_bad_input_error();
1153 }
1154 }
1155 break;
1156 }
1158 }
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.
1166 *
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 )
1172 {
1173 if( ta_status.debug_output ) {
1174 fwrite_dump32( (uint32_t *)buf, length, stderr );
1175 }
1177 for( ; length >=32; length -= 32 ) {
1178 pvr2_ta_process_block( buf );
1179 buf += 32;
1180 }
1181 }
.