filename | src/pvr2/tacore.c |
changeset | 801:92b518a2e915 |
prev | 753:1fe39c3a9bbc |
next | 931:430048ea8b71 |
next | 953:f4a156508ad1 |
author | nkeynes |
date | Sun Oct 26 02:28:29 2008 +0000 (15 years ago) |
permissions | -rw-r--r-- |
last change | Move the precision/size tests to translation-time rather than execution-time, and flush/retranslate on a mismatch. Shaves a few percent off the core runtime |
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 extern char *video_base;
123 #define PVRRAM(addr) (*(uint32_t *)(video_base + ((addr)&PVR2_RAM_MASK)))
125 struct pvr2_ta_vertex {
126 float x,y,z;
127 uint32_t detail[8]; /* 0-8 detail words */
128 };
130 struct tile_bounds {
131 int32_t x1, y1, x2, y2;
132 };
134 struct pvr2_ta_status {
135 int32_t state;
136 int32_t width, height; /* Tile resolution, ie 20x15 */
137 int32_t tilelist_dir; /* Growth direction of the tilelist, 0 = up, 1 = down */
138 uint32_t tilelist_size; /* Size of the tilelist segments */
139 uint32_t tilelist_start; /* Initial address of the tilelist */
140 uint32_t polybuf_start; /* Initial bank address of the polygon buffer (ie &0x00F00000) */
141 int32_t current_vertex_type;
142 uint32_t accept_vertexes; /* 0 = NO, 1 = YES */
143 int32_t vertex_count; /* index of last start-vertex seen, or -1 if no vertexes
144 * are present
145 */
146 uint32_t max_vertex; /* Maximum number of vertexes in the current polygon (3/4/6/8) */
147 uint32_t current_list_type;
148 uint32_t current_tile_matrix; /* Memory location of the first tile for the current list. */
149 uint32_t current_tile_size; /* Size of the tile matrix space in 32-bit words (0/8/16/32)*/
150 uint32_t intensity1, intensity2;
151 struct tile_bounds clip;
152 int32_t clip_mode;
153 /**
154 * Current working object
155 */
156 int32_t poly_context_size;
157 int32_t poly_vertex_size;
158 int32_t poly_parity;
159 uint32_t poly_context[5];
160 uint32_t poly_pointer;
161 struct tile_bounds last_triangle_bounds;
162 struct pvr2_ta_vertex poly_vertex[8];
163 uint32_t debug_output;
164 };
166 static struct pvr2_ta_status ta_status;
168 static int tilematrix_sizes[4] = {0,8,16,32};
170 /**
171 * Convenience union - ta data is either 32-bit integer or 32-bit float.
172 */
173 union ta_data {
174 unsigned int i;
175 float f;
176 };
179 void pvr2_ta_reset() {
180 ta_status.state = STATE_ERROR; /* State not valid until initialized */
181 ta_status.debug_output = 0;
182 }
184 void pvr2_ta_save_state( FILE *f )
185 {
186 fwrite( &ta_status, sizeof(ta_status), 1, f );
187 }
189 int pvr2_ta_load_state( FILE *f )
190 {
191 if( fread( &ta_status, sizeof(ta_status), 1, f ) != 1 )
192 return 1;
193 return 0;
194 }
196 void pvr2_ta_init() {
197 ta_status.state = STATE_IDLE;
198 ta_status.current_list_type = -1;
199 ta_status.current_vertex_type = -1;
200 ta_status.poly_parity = 0;
201 ta_status.vertex_count = 0;
202 ta_status.max_vertex = 3;
203 ta_status.current_vertex_type = TA_VERTEX_LISTLESS;
204 ta_status.poly_vertex_size = 0;
205 memset(&ta_status.poly_context[1], 0, 4);
206 ta_status.last_triangle_bounds.x1 = -1;
207 ta_status.accept_vertexes = TRUE;
208 ta_status.clip.x1 = 0;
209 ta_status.clip.y1 = 0;
210 ta_status.clip_mode = TA_POLYCMD_CLIP_NONE;
212 uint32_t size = MMIO_READ( PVR2, TA_TILESIZE );
213 ta_status.width = (size & 0xFFFF) + 1;
214 ta_status.height = (size >> 16) + 1;
215 ta_status.clip.x2 = ta_status.width-1;
216 ta_status.clip.y2 = ta_status.height-1;
217 uint32_t control = MMIO_READ( PVR2, TA_TILECFG );
218 ta_status.tilelist_dir = (control >> 20) & 0x01;
219 ta_status.tilelist_size = tilematrix_sizes[ (control & 0x03) ];
220 MMIO_WRITE( PVR2, TA_POLYPOS, MMIO_READ( PVR2, TA_POLYBASE ) );
221 uint32_t plistpos = MMIO_READ( PVR2, TA_LISTBASE ) >> 2;
222 if( ta_status.tilelist_dir == TA_GROW_DOWN ) {
223 plistpos -= ta_status.tilelist_size;
224 }
225 MMIO_WRITE( PVR2, TA_LISTPOS, plistpos );
226 ta_status.tilelist_start = plistpos;
227 ta_status.polybuf_start = MMIO_READ( PVR2, TA_POLYBASE ) & 0x00F00000;
228 }
230 static uint32_t parse_float_colour( float a, float r, float g, float b ) {
231 int ai,ri,gi,bi;
233 if( TA_IS_INF(a) ) {
234 ai = 255;
235 } else {
236 ai = 256 * CLAMP(a,0.0,1.0) - 1;
237 if( ai < 0 ) ai = 0;
238 }
239 if( TA_IS_INF(r) ) {
240 ri = 255;
241 } else {
242 ri = 256 * CLAMP(r,0.0,1.0) - 1;
243 if( ri < 0 ) ri = 0;
244 }
245 if( TA_IS_INF(g) ) {
246 gi = 255;
247 } else {
248 gi = 256 * CLAMP(g,0.0,1.0) - 1;
249 if( gi < 0 ) gi = 0;
250 }
251 if( TA_IS_INF(b) ) {
252 bi = 255;
253 } else {
254 bi = 256 * CLAMP(b,0.0,1.0) - 1;
255 if( bi < 0 ) bi = 0;
256 }
257 return (ai << 24) | (ri << 16) | (gi << 8) | bi;
258 }
260 static uint32_t parse_intensity_colour( uint32_t base, float intensity )
261 {
262 unsigned int i = (unsigned int)(256 * CLAMP(intensity, 0.0,1.0));
264 return
265 (((((base & 0xFF) * i) & 0xFF00) |
266 (((base & 0xFF00) * i) & 0xFF0000) |
267 (((base & 0xFF0000) * i) & 0xFF000000)) >> 8) |
268 (base & 0xFF000000);
269 }
271 /**
272 * Initialize the specified TA list.
273 */
274 static void ta_init_list( unsigned int listtype ) {
275 int config = MMIO_READ( PVR2, TA_TILECFG );
276 int tile_matrix = MMIO_READ( PVR2, TA_TILEBASE );
277 int list_end = MMIO_READ( PVR2, TA_LISTEND );
279 ta_status.current_tile_matrix = tile_matrix;
281 /* If the list grows down, the end must be < tile matrix start.
282 * If it grows up, the end must be > tile matrix start.
283 * Don't ask me why, it just does...
284 */
285 if( ((ta_status.tilelist_dir == TA_GROW_DOWN && list_end <= tile_matrix) ||
286 (ta_status.tilelist_dir == TA_GROW_UP && list_end >= tile_matrix )) &&
287 listtype <= TA_LIST_PUNCH_OUT ) {
288 int i;
289 uint32_t *p;
290 for( i=0; i < listtype; i++ ) {
291 int size = tilematrix_sizes[(config & 0x03)] << 2;
292 ta_status.current_tile_matrix += ta_status.width * ta_status.height * size;
293 config >>= 4;
294 }
295 ta_status.current_tile_size = tilematrix_sizes[(config & 0x03)];
297 /* Initialize each tile to 0xF0000000 */
298 if( ta_status.current_tile_size != 0 ) {
299 p = (uint32_t *)(video_base + ta_status.current_tile_matrix);
300 for( i=0; i< ta_status.width * ta_status.height; i++ ) {
301 *p = 0xF0000000;
302 p += ta_status.current_tile_size;
303 }
304 }
305 } else {
306 ta_status.current_tile_size = 0;
307 }
309 if( tile_matrix == list_end ) {
310 ta_status.current_tile_size = 0;
311 }
313 ta_status.state = STATE_IN_LIST;
314 ta_status.current_list_type = listtype;
315 ta_status.last_triangle_bounds.x1 = -1;
316 }
318 static int list_events[5] = {EVENT_PVR_OPAQUE_DONE, EVENT_PVR_OPAQUEMOD_DONE,
319 EVENT_PVR_TRANS_DONE, EVENT_PVR_TRANSMOD_DONE,
320 EVENT_PVR_PUNCHOUT_DONE };
322 static void ta_end_list() {
323 if( ta_status.current_list_type != TA_LIST_NONE ) {
324 asic_event( list_events[ta_status.current_list_type] );
325 }
326 ta_status.current_list_type = TA_LIST_NONE;
327 ta_status.current_vertex_type = TA_VERTEX_LISTLESS;
328 ta_status.poly_vertex_size = 0;
329 memset(&ta_status.poly_context[1], 0, 4);
330 ta_status.state = STATE_IDLE;
331 }
333 static void ta_bad_input_error() {
334 asic_event( EVENT_PVR_BAD_INPUT );
335 }
337 /**
338 * Write data out to the polygon buffer.
339 * If the end-of-buffer is reached, asserts EVENT_PVR_PRIM_ALLOC_FAIL
340 * @param data to be written
341 * @param length Number of 32-bit words to write.
342 * @return number of words actually written
343 */
344 static int ta_write_polygon_buffer( uint32_t *data, int length )
345 {
346 int rv;
347 int posn = MMIO_READ( PVR2, TA_POLYPOS );
348 int end = MMIO_READ( PVR2, TA_POLYEND );
349 uint32_t *target = (uint32_t *)(video_base + posn);
350 for( rv=0; rv < length; rv++ ) {
351 if( posn == end ) {
352 asic_event( EVENT_PVR_PRIM_ALLOC_FAIL );
353 // ta_status.state = STATE_ERROR;
354 break;
355 }
356 if( posn < PVR2_RAM_SIZE ) {
357 *target++ = *data++;
358 }
359 posn += 4;
360 }
362 MMIO_WRITE( PVR2, TA_POLYPOS, posn );
363 return rv;
364 }
366 #define TA_NO_ALLOC 0xFFFFFFFF
368 /**
369 * Allocate a new tile list block from the grow space and update the
370 * word at reference to be a link to the new block.
371 */
372 static uint32_t ta_alloc_tilelist( uint32_t reference ) {
373 uint32_t posn = MMIO_READ( PVR2, TA_LISTPOS );
374 uint32_t limit = MMIO_READ( PVR2, TA_LISTEND ) >> 2;
375 uint32_t newposn;
376 if( ta_status.tilelist_dir == TA_GROW_DOWN ) {
377 newposn = posn - ta_status.tilelist_size;
378 if( posn == limit ) {
379 PVRRAM(posn<<2) = 0xF0000000;
380 PVRRAM(reference) = 0xE0000000 | (posn<<2);
381 return TA_NO_ALLOC;
382 } else if( posn < limit ) {
383 PVRRAM(reference) = 0xE0000000 | (posn<<2);
384 return TA_NO_ALLOC;
385 } else if( newposn <= limit ) {
386 } else if( newposn <= (limit + ta_status.tilelist_size) ) {
387 asic_event( EVENT_PVR_MATRIX_ALLOC_FAIL );
388 MMIO_WRITE( PVR2, TA_LISTPOS, newposn );
389 } else {
390 MMIO_WRITE( PVR2, TA_LISTPOS, newposn );
391 }
392 PVRRAM(reference) = 0xE0000000 | (posn<<2);
393 return posn << 2;
394 } else {
395 newposn = posn + ta_status.tilelist_size;
396 if( posn == limit ) {
397 PVRRAM(posn<<2) = 0xF0000000;
398 PVRRAM(reference) = 0xE0000000 | (posn<<2);
399 return TA_NO_ALLOC;
400 } else if ( posn > limit ) {
401 PVRRAM(reference) = 0xE0000000 | (posn<<2);
402 return TA_NO_ALLOC;
403 } else if( newposn >= limit ) {
404 } else if( newposn >= (limit - ta_status.tilelist_size) ) {
405 asic_event( EVENT_PVR_MATRIX_ALLOC_FAIL );
406 MMIO_WRITE( PVR2, TA_LISTPOS, newposn );
407 } else {
408 MMIO_WRITE( PVR2, TA_LISTPOS, newposn );
409 }
410 PVRRAM(reference) = 0xE0000000 | (posn<<2);
411 return posn << 2;
412 }
413 }
415 /**
416 * Write a tile entry out to the matrix.
417 */
418 static void ta_write_tile_entry( int x, int y, uint32_t tile_entry ) {
419 uint32_t tile = TILESLOT(x,y);
420 uint32_t tilestart = tile;
421 uint32_t value;
422 uint32_t lasttri = 0;
423 int i;
425 if( ta_status.clip_mode == TA_POLYCMD_CLIP_OUTSIDE &&
426 x >= ta_status.clip.x1 && x <= ta_status.clip.x2 &&
427 y >= ta_status.clip.y1 && y <= ta_status.clip.y2 ) {
428 /* Tile clipped out */
429 return;
430 }
432 if( (tile_entry & 0x80000000) &&
433 ta_status.last_triangle_bounds.x1 != -1 &&
434 ta_status.last_triangle_bounds.x1 <= x &&
435 ta_status.last_triangle_bounds.x2 >= x &&
436 ta_status.last_triangle_bounds.y1 <= y &&
437 ta_status.last_triangle_bounds.y2 >= y ) {
438 /* potential for triangle stacking */
439 lasttri = tile_entry & 0xE1E00000;
440 }
443 if( PVRRAM(tile) == 0xF0000000 ) {
444 PVRRAM(tile) = tile_entry;
445 PVRRAM(tile+4) = 0xF0000000;
446 return;
447 }
449 while(1) {
450 value = PVRRAM(tile);
451 for( i=1; i<ta_status.current_tile_size; i++ ) {
452 tile += 4;
453 uint32_t nextval = PVRRAM(tile);
454 if( nextval == 0xF0000000 ) {
455 if( lasttri != 0 && lasttri == (value&0xE1E00000) ) {
456 int count = (value & 0x1E000000) + 0x02000000;
457 if( count < 0x20000000 ) {
458 PVRRAM(tile-4) = (value & 0xE1FFFFFF) | count;
459 return;
460 }
461 }
462 if( i < ta_status.current_tile_size-1 ) {
463 PVRRAM(tile) = tile_entry;
464 PVRRAM(tile+4) = 0xF0000000;
465 return;
466 }
467 }
468 value = nextval;
469 }
471 if( value == 0xF0000000 ) {
472 tile = ta_alloc_tilelist(tile);
473 if( tile != TA_NO_ALLOC ) {
474 PVRRAM(tile) = tile_entry;
475 PVRRAM(tile+4) = 0xF0000000;
476 }
477 return;
478 } else if( (value & 0xFF000000) == 0xE0000000 ) {
479 value &= 0x00FFFFFF;
480 if( value == tilestart )
481 return; /* Loop */
482 tilestart = tile = value;
483 } else {
484 /* This should never happen */
485 return;
486 }
487 }
488 }
490 /**
491 * Write a completed polygon out to the memory buffers
492 * OPTIMIZEME: This is not terribly efficient at the moment.
493 */
494 static void ta_commit_polygon( ) {
495 int i, x, y;
496 int tx[ta_status.vertex_count], ty[ta_status.vertex_count];
497 struct tile_bounds triangle_bound[ta_status.vertex_count - 2];
498 struct tile_bounds polygon_bound;
499 uint32_t poly_context[5];
501 memcpy( poly_context, ta_status.poly_context, ta_status.poly_context_size * 4 );
503 /* Compute the tile coordinates for each vertex (need to be careful with
504 * clamping here)
505 */
506 for( i=0; i<ta_status.vertex_count; i++ ) {
507 if( ta_status.poly_vertex[i].x < 0.0 || TA_IS_NINF(ta_status.poly_vertex[i].x) ) {
508 tx[i] = -1;
509 } else if( ta_status.poly_vertex[i].x > (float)INT_MAX || TA_IS_INF(ta_status.poly_vertex[i].x) ) {
510 tx[i] = INT_MAX/32;
511 } else {
512 tx[i] = (int)(ta_status.poly_vertex[i].x / 32.0);
513 }
514 if( ta_status.poly_vertex[i].y < 0.0 || TA_IS_NINF(ta_status.poly_vertex[i].y)) {
515 ty[i] = -1;
516 } else if( ta_status.poly_vertex[i].y > (float)INT_MAX || TA_IS_INF(ta_status.poly_vertex[i].y) ) {
517 ty[i] = INT_MAX/32;
518 } else {
519 ty[i] = (int)(ta_status.poly_vertex[i].y / 32.0);
520 }
522 }
524 /* Compute bounding box for each triangle individually, as well
525 * as the overall polygon.
526 */
528 triangle_bound[0].x1 = MIN3(tx[0],tx[1],tx[2]);
529 triangle_bound[0].x2 = MAX3(tx[0],tx[1],tx[2]);
530 triangle_bound[0].y1 = MIN3(ty[0],ty[1],ty[2]);
531 triangle_bound[0].y2 = MAX3(ty[0],ty[1],ty[2]);
532 polygon_bound.x1 = triangle_bound[0].x1;
533 polygon_bound.y1 = triangle_bound[0].y1;
534 polygon_bound.x2 = triangle_bound[0].x2;
535 polygon_bound.y2 = triangle_bound[0].y2;
537 for( i=1; i<ta_status.vertex_count-2; i++ ) {
538 triangle_bound[i].x1 = MIN3(tx[i],tx[i+1],tx[i+2]);
539 triangle_bound[i].x2 = MAX3(tx[i],tx[i+1],tx[i+2]);
540 triangle_bound[i].y1 = MIN3(ty[i],ty[i+1],ty[i+2]);
541 triangle_bound[i].y2 = MAX3(ty[i],ty[i+1],ty[i+2]);
542 polygon_bound.x1 = MIN(polygon_bound.x1, triangle_bound[i].x1);
543 polygon_bound.x2 = MAX(polygon_bound.x2, triangle_bound[i].x2);
544 polygon_bound.y1 = MIN(polygon_bound.y1, triangle_bound[i].y1);
545 polygon_bound.y2 = MAX(polygon_bound.y2, triangle_bound[i].y2);
546 }
548 /* Clamp the polygon bounds to the frustum */
549 if( polygon_bound.x1 < 0 ) polygon_bound.x1 = 0;
550 if( polygon_bound.x2 >= ta_status.width ) polygon_bound.x2 = ta_status.width-1;
551 if( polygon_bound.y1 < 0 ) polygon_bound.y1 = 0;
552 if( polygon_bound.y2 >= ta_status.width ) polygon_bound.y2 = ta_status.height-1;
554 /* Set the "single tile" flag if it's entirely contained in 1 tile */
555 if( polygon_bound.x1 == polygon_bound.x2 &&
556 polygon_bound.y1 == polygon_bound.y2 ) {
557 poly_context[0] |= 0x00200000;
558 }
560 /* If the polygon is entirely clipped, don't even write the polygon data */
561 switch( ta_status.clip_mode ) {
562 case TA_POLYCMD_CLIP_NONE:
563 if( polygon_bound.x2 < 0 || polygon_bound.x1 >= ta_status.width ||
564 polygon_bound.y2 < 0 || polygon_bound.y1 >= ta_status.height ) {
565 return;
566 }
567 break;
568 case TA_POLYCMD_CLIP_INSIDE:
569 if( polygon_bound.x2 < ta_status.clip.x1 || polygon_bound.x1 > ta_status.clip.x2 ||
570 polygon_bound.y2 < ta_status.clip.y1 || polygon_bound.y1 > ta_status.clip.y2 ) {
571 return;
572 } else {
573 /* Clamp to clip bounds */
574 if( polygon_bound.x1 < ta_status.clip.x1 ) polygon_bound.x1 = ta_status.clip.x1;
575 if( polygon_bound.x2 > ta_status.clip.x2 ) polygon_bound.x2 = ta_status.clip.x2;
576 if( polygon_bound.y1 < ta_status.clip.y1 ) polygon_bound.y1 = ta_status.clip.y1;
577 if( polygon_bound.y2 > ta_status.clip.y2 ) polygon_bound.y2 = ta_status.clip.y2;
578 }
579 break;
580 case TA_POLYCMD_CLIP_OUTSIDE:
581 if( polygon_bound.x1 >= ta_status.clip.x1 && polygon_bound.x2 <= ta_status.clip.x2 &&
582 polygon_bound.y1 >= ta_status.clip.y1 && polygon_bound.y2 <= ta_status.clip.y2 ) {
583 return;
584 }
585 break;
586 }
588 /* Ok, we're good to go - write out the polygon first */
589 uint32_t tile_entry = (MMIO_READ( PVR2, TA_POLYPOS ) - ta_status.polybuf_start) >> 2 |
590 ta_status.poly_pointer;
592 int status = ta_write_polygon_buffer( poly_context, ta_status.poly_context_size );
593 if( status == 0 ) {
594 /* No memory available - abort */
595 return;
596 } else {
597 for( i=0; i<ta_status.vertex_count && status != 0; i++ ) {
598 status = ta_write_polygon_buffer( (uint32_t *)(&ta_status.poly_vertex[i]), 3 + ta_status.poly_vertex_size );
599 }
600 }
602 if( ta_status.current_tile_size == 0 ) {
603 /* No memory for tile entry, so don't write anything */
604 return;
605 }
607 /* And now the tile entries. Triangles are different from everything else */
608 if( ta_status.vertex_count == 3 ) {
609 tile_entry |= 0x80000000;
610 for( y=polygon_bound.y1; y<=polygon_bound.y2; y++ ) {
611 for( x=polygon_bound.x1; x<=polygon_bound.x2; x++ ) {
612 ta_write_tile_entry( x,y,tile_entry );
613 }
614 }
615 ta_status.last_triangle_bounds.x1 = polygon_bound.x1;
616 ta_status.last_triangle_bounds.y1 = polygon_bound.y1;
617 ta_status.last_triangle_bounds.x2 = polygon_bound.x2;
618 ta_status.last_triangle_bounds.y2 = polygon_bound.y2;
619 } else if( ta_status.current_vertex_type == TA_VERTEX_SPRITE ||
620 ta_status.current_vertex_type == TA_VERTEX_TEX_SPRITE ) {
621 tile_entry |= 0xA0000000;
622 for( y=polygon_bound.y1; y<=polygon_bound.y2; y++ ) {
623 for( x=polygon_bound.x1; x<=polygon_bound.x2; x++ ) {
624 ta_write_tile_entry( x,y,tile_entry );
625 }
626 }
627 ta_status.last_triangle_bounds.x1 = polygon_bound.x1;
628 ta_status.last_triangle_bounds.y1 = polygon_bound.y1;
629 ta_status.last_triangle_bounds.x2 = polygon_bound.x2;
630 ta_status.last_triangle_bounds.y2 = polygon_bound.y2;
631 } else {
632 for( y=polygon_bound.y1; y<=polygon_bound.y2; y++ ) {
633 for( x=polygon_bound.x1; x<=polygon_bound.x2; x++ ) {
634 uint32_t entry = tile_entry;
635 for( i=0; i<ta_status.vertex_count-2; i++ ) {
636 if( triangle_bound[i].x1 <= x && triangle_bound[i].x2 >= x &&
637 triangle_bound[i].y1 <= y && triangle_bound[i].y2 >= y ) {
638 entry |= (0x40000000>>i);
639 }
640 }
641 ta_write_tile_entry( x, y, entry );
642 }
643 }
644 ta_status.last_triangle_bounds.x1 = -1;
645 }
646 }
648 /**
649 * Variant of ta_split_polygon called when vertex_count == max_vertex, but
650 * the client hasn't sent the LAST VERTEX flag. Commit the poly as normal
651 * first, then start a new poly with the first 2 vertexes taken from the
652 * current one.
653 */
654 static void ta_split_polygon() {
655 ta_commit_polygon();
656 if( TA_IS_NORMAL_POLY() ) {
657 /* This only applies to ordinary polys - Sprites + modifier lists are
658 * handled differently
659 */
660 if( ta_status.vertex_count == 3 ) {
661 /* Triangles use an odd/even scheme */
662 if( ta_status.poly_parity == 0 ) {
663 memcpy( &ta_status.poly_vertex[0], &ta_status.poly_vertex[2],
664 sizeof(struct pvr2_ta_vertex) );
665 ta_status.poly_parity = 1;
666 } else {
667 memcpy( &ta_status.poly_vertex[1], &ta_status.poly_vertex[2],
668 sizeof(struct pvr2_ta_vertex) );
669 ta_status.poly_parity = 0;
670 }
671 } else {
672 /* Everything else just uses the last 2 vertexes in order */
673 memcpy( &ta_status.poly_vertex[0], &ta_status.poly_vertex[ta_status.vertex_count-2],
674 sizeof(struct pvr2_ta_vertex)*2 );
675 ta_status.poly_parity = 0;
676 }
677 ta_status.vertex_count = 2;
678 } else {
679 ta_status.vertex_count = 0;
680 }
681 }
683 /**
684 * Parse the polygon context block and setup the internal state to receive
685 * vertexes.
686 * @param data 32 bytes of parameter data.
687 */
688 static void ta_parse_polygon_context( union ta_data *data ) {
689 int colourfmt = TA_POLYCMD_COLOURFMT(data[0].i);
690 if( TA_POLYCMD_USELENGTH(data[0].i) ) {
691 ta_status.max_vertex = TA_POLYCMD_LENGTH(data[0].i);
692 }
693 ta_status.clip_mode = TA_POLYCMD_CLIP(data[0].i);
694 if( ta_status.clip_mode == 1 ) { /* Reserved - treat as CLIP_INSIDE */
695 ta_status.clip_mode = TA_POLYCMD_CLIP_INSIDE;
696 }
697 ta_status.vertex_count = 0;
698 ta_status.poly_context[0] =
699 (data[1].i & 0xFC1FFFFF) | ((data[0].i & 0x0B) << 22);
700 ta_status.poly_context[1] = data[2].i;
701 ta_status.poly_context[3] = data[4].i;
702 ta_status.poly_parity = 0;
703 if( data[0].i & TA_POLYCMD_TEXTURED ) {
704 ta_status.current_vertex_type = data[0].i & 0x0D;
705 ta_status.poly_context[2] = data[3].i;
706 ta_status.poly_context[4] = data[5].i;
707 if( data[0].i & TA_POLYCMD_SPECULAR ) {
708 ta_status.poly_context[0] |= 0x01000000;
709 ta_status.poly_vertex_size = 4;
710 } else {
711 ta_status.poly_vertex_size = 3;
712 }
713 if( data[0].i & TA_POLYCMD_UV16 ) {
714 ta_status.poly_vertex_size--;
715 }
716 } else {
717 ta_status.current_vertex_type = 0;
718 ta_status.poly_vertex_size = 1;
719 ta_status.poly_context[2] = 0;
720 ta_status.poly_context[4] = 0;
721 }
723 ta_status.poly_pointer = (ta_status.poly_vertex_size << 21);
724 ta_status.poly_context_size = 3;
725 if( data[0].i & TA_POLYCMD_MODIFIED ) {
726 ta_status.poly_pointer |= 0x01000000;
727 if( data[0].i & TA_POLYCMD_FULLMOD ) {
728 ta_status.poly_context_size = 5;
729 ta_status.poly_vertex_size <<= 1;
730 ta_status.current_vertex_type |= 0x40;
731 /* Modified/float not supported - behaves as per last intensity */
732 if( colourfmt == TA_POLYCMD_COLOURFMT_FLOAT ) {
733 colourfmt = TA_POLYCMD_COLOURFMT_LASTINT;
734 }
735 }
736 }
738 if( colourfmt == TA_POLYCMD_COLOURFMT_INTENSITY ) {
739 if( TA_POLYCMD_IS_FULLMOD(data[0].i) ||
740 TA_POLYCMD_IS_SPECULAR(data[0].i) ) {
741 ta_status.state = STATE_EXPECT_POLY_BLOCK2;
742 } else {
743 ta_status.intensity1 =
744 parse_float_colour( data[4].f, data[5].f, data[6].f, data[7].f );
745 }
746 } else if( colourfmt == TA_POLYCMD_COLOURFMT_LASTINT ) {
747 colourfmt = TA_POLYCMD_COLOURFMT_INTENSITY;
748 }
750 ta_status.current_vertex_type |= colourfmt;
751 }
753 /**
754 * Parse the modifier volume context block and setup the internal state to
755 * receive modifier vertexes.
756 * @param data 32 bytes of parameter data.
757 */
758 static void ta_parse_modifier_context( union ta_data *data ) {
759 ta_status.current_vertex_type = TA_VERTEX_MOD_VOLUME;
760 ta_status.poly_vertex_size = 0;
761 ta_status.clip_mode = TA_POLYCMD_CLIP(data[0].i);
762 if( ta_status.clip_mode == 1 ) { /* Reserved - treat as CLIP_INSIDE */
763 ta_status.clip_mode = TA_POLYCMD_CLIP_INSIDE;
764 }
765 ta_status.poly_context_size = 3;
766 ta_status.poly_context[0] = (data[1].i & 0xFC1FFFFF) |
767 ((data[0].i & 0x0B)<<22);
768 if( TA_POLYCMD_IS_SPECULAR(data[0].i) ) {
769 ta_status.poly_context[0] |= 0x01000000;
770 }
771 ta_status.poly_context[1] = 0;
772 ta_status.poly_context[2] = 0;
773 ta_status.vertex_count = 0;
774 ta_status.max_vertex = 3;
775 ta_status.poly_pointer = 0;
776 }
778 /**
779 * Parse the sprite context block and setup the internal state to receive
780 * vertexes.
781 * @param data 32 bytes of parameter data.
782 */
783 static void ta_parse_sprite_context( union ta_data *data ) {
784 ta_status.poly_context_size = 3;
785 ta_status.poly_context[0] = (data[1].i & 0xFC1FFFFF) |
786 ((data[0].i & 0x0B)<<22) | 0x00400000;
787 ta_status.clip_mode = TA_POLYCMD_CLIP(data[0].i);
788 if( ta_status.clip_mode == 1 ) { /* Reserved - treat as CLIP_INSIDE */
789 ta_status.clip_mode = TA_POLYCMD_CLIP_INSIDE;
790 }
791 if( TA_POLYCMD_IS_SPECULAR(data[0].i) ) {
792 ta_status.poly_context[0] |= 0x01000000;
793 }
794 ta_status.poly_context[1] = data[2].i;
795 ta_status.poly_context[2] = data[3].i;
796 if( data[0].i & TA_POLYCMD_TEXTURED ) {
797 ta_status.poly_vertex_size = 2;
798 ta_status.poly_vertex[2].detail[1] = data[4].i;
799 ta_status.current_vertex_type = TA_VERTEX_TEX_SPRITE;
800 } else {
801 ta_status.poly_vertex_size = 1;
802 ta_status.poly_vertex[2].detail[0] = data[4].i;
803 ta_status.current_vertex_type = TA_VERTEX_SPRITE;
804 }
805 ta_status.vertex_count = 0;
806 ta_status.max_vertex = 4;
807 ta_status.poly_pointer = (ta_status.poly_vertex_size << 21);
808 }
810 /**
811 * Copy the last read vertex into all vertexes up to max_vertex. Used for
812 * Aborted polygons under some circumstances.
813 */
814 static void ta_fill_vertexes( ) {
815 int i;
816 for( i=ta_status.vertex_count; i<ta_status.max_vertex; i++ ) {
817 memcpy( &ta_status.poly_vertex[i], &ta_status.poly_vertex[ta_status.vertex_count-1],
818 sizeof( struct pvr2_ta_vertex ) );
819 }
820 }
822 static void ta_parse_vertex( union ta_data *data ) {
823 struct pvr2_ta_vertex *vertex = &ta_status.poly_vertex[ta_status.vertex_count];
824 vertex->x = data[1].f;
825 vertex->y = data[2].f;
826 vertex->z = data[3].f;
828 switch( ta_status.current_vertex_type ) {
829 case TA_VERTEX_PACKED:
830 vertex->detail[0] = data[6].i;
831 break;
832 case TA_VERTEX_FLOAT:
833 vertex->detail[0] = parse_float_colour( data[4].f, data[5].f, data[6].f, data[7].f );
834 break;
835 case TA_VERTEX_INTENSITY:
836 vertex->detail[0] = parse_intensity_colour( ta_status.intensity1, data[6].f );
837 break;
839 case TA_VERTEX_TEX_SPEC_PACKED:
840 vertex->detail[3] = data[7].i; /* ARGB */
841 /* Fallthrough */
842 case TA_VERTEX_TEX_PACKED:
843 vertex->detail[0] = data[4].i; /* U */
844 vertex->detail[1] = data[5].i; /* V */
845 vertex->detail[2] = data[6].i; /* ARGB */
846 break;
847 case TA_VERTEX_TEX_UV16_SPEC_PACKED:
848 vertex->detail[2] = data[7].i; /* ARGB */
849 /* Fallthrough */
850 case TA_VERTEX_TEX_UV16_PACKED:
851 vertex->detail[0] = data[4].i; /* UV */
852 vertex->detail[1] = data[6].i; /* ARGB */
853 break;
855 case TA_VERTEX_TEX_FLOAT:
856 case TA_VERTEX_TEX_SPEC_FLOAT:
857 vertex->detail[0] = data[4].i; /* U */
858 vertex->detail[1] = data[5].i; /* UV */
859 ta_status.state = STATE_EXPECT_VERTEX_BLOCK2;
860 break;
861 case TA_VERTEX_TEX_UV16_FLOAT:
862 case TA_VERTEX_TEX_UV16_SPEC_FLOAT:
863 vertex->detail[0] = data[4].i; /* UV */
864 ta_status.state = STATE_EXPECT_VERTEX_BLOCK2;
865 break;
867 case TA_VERTEX_TEX_SPEC_INTENSITY:
868 vertex->detail[3] = parse_intensity_colour( ta_status.intensity2, data[7].f );
869 /* Fallthrough */
870 case TA_VERTEX_TEX_INTENSITY:
871 vertex->detail[0] = data[4].i; /* U */
872 vertex->detail[1] = data[5].i; /* V */
873 vertex->detail[2] = parse_intensity_colour( ta_status.intensity1, data[6].f );
874 break;
875 case TA_VERTEX_TEX_UV16_SPEC_INTENSITY:
876 vertex->detail[2] = parse_intensity_colour( ta_status.intensity2, data[7].f );
877 /* Fallthrough */
878 case TA_VERTEX_TEX_UV16_INTENSITY:
879 vertex->detail[0] = data[4].i; /* UV */
880 vertex->detail[1] = parse_intensity_colour( ta_status.intensity1, data[6].f );
881 break;
883 case TA_VERTEX_PACKED_MOD:
884 vertex->detail[0] = data[4].i; /* ARGB */
885 vertex->detail[1] = data[5].i; /* ARGB */
886 break;
887 case TA_VERTEX_INTENSITY_MOD:
888 vertex->detail[0] = parse_intensity_colour( ta_status.intensity1, data[4].f );
889 vertex->detail[1] = parse_intensity_colour( ta_status.intensity2, data[5].f );
890 break;
892 case TA_VERTEX_TEX_SPEC_PACKED_MOD:
893 vertex->detail[3] = data[7].i; /* ARGB0 */
894 /* Fallthrough */
895 case TA_VERTEX_TEX_PACKED_MOD:
896 vertex->detail[0] = data[4].i; /* U0 */
897 vertex->detail[1] = data[5].i; /* V0 */
898 vertex->detail[2] = data[6].i; /* ARGB0 */
899 ta_status.state = STATE_EXPECT_VERTEX_BLOCK2;
900 break;
901 case TA_VERTEX_TEX_UV16_SPEC_PACKED_MOD:
902 vertex->detail[2] = data[7].i; /* ARGB0 */
903 /* Fallthrough */
904 case TA_VERTEX_TEX_UV16_PACKED_MOD:
905 vertex->detail[0] = data[4].i; /* UV0 */
906 vertex->detail[1] = data[6].i; /* ARGB0 */
907 ta_status.state = STATE_EXPECT_VERTEX_BLOCK2;
908 break;
910 case TA_VERTEX_TEX_SPEC_INTENSITY_MOD:
911 vertex->detail[3] = parse_intensity_colour( ta_status.intensity1, data[7].f );
912 /* Fallthrough */
913 case TA_VERTEX_TEX_INTENSITY_MOD:
914 vertex->detail[0] = data[4].i; /* U0 */
915 vertex->detail[1] = data[5].i; /* V0 */
916 vertex->detail[2] = parse_intensity_colour( ta_status.intensity1, data[6].f );
917 ta_status.state = STATE_EXPECT_VERTEX_BLOCK2;
918 break;
919 case TA_VERTEX_TEX_UV16_SPEC_INTENSITY_MOD:
920 vertex->detail[2] = parse_intensity_colour( ta_status.intensity1, data[7].f );
921 /* Fallthrough */
922 case TA_VERTEX_TEX_UV16_INTENSITY_MOD:
923 vertex->detail[0] = data[4].i; /* UV0 */
924 vertex->detail[1] = parse_intensity_colour( ta_status.intensity1, data[6].f );
925 ta_status.state = STATE_EXPECT_VERTEX_BLOCK2;
926 break;
928 case TA_VERTEX_SPRITE:
929 case TA_VERTEX_TEX_SPRITE:
930 case TA_VERTEX_MOD_VOLUME:
931 case TA_VERTEX_LISTLESS:
932 vertex++;
933 vertex->x = data[4].f;
934 vertex->y = data[5].f;
935 vertex->z = data[6].f;
936 vertex++;
937 vertex->x = data[7].f;
938 ta_status.vertex_count += 2;
939 ta_status.state = STATE_EXPECT_VERTEX_BLOCK2;
940 break;
941 }
942 ta_status.vertex_count++;
943 }
945 static void ta_parse_vertex_block2( union ta_data *data ) {
946 struct pvr2_ta_vertex *vertex = &ta_status.poly_vertex[ta_status.vertex_count-1];
948 switch( ta_status.current_vertex_type ) {
949 case TA_VERTEX_TEX_SPEC_FLOAT:
950 vertex->detail[3] = parse_float_colour( data[4].f, data[5].f, data[6].f, data[7].f );
951 /* Fallthrough */
952 case TA_VERTEX_TEX_FLOAT:
953 vertex->detail[2] = parse_float_colour( data[0].f, data[1].f, data[2].f, data[3].f );
954 break;
955 case TA_VERTEX_TEX_UV16_SPEC_FLOAT:
956 vertex->detail[2] = parse_float_colour( data[4].f, data[5].f, data[6].f, data[7].f );
957 /* Fallthrough */
958 case TA_VERTEX_TEX_UV16_FLOAT:
959 vertex->detail[1] = parse_float_colour( data[0].f, data[1].f, data[2].f, data[3].f );
960 break;
961 case TA_VERTEX_TEX_PACKED_MOD:
962 vertex->detail[3] = data[0].i; /* U1 */
963 vertex->detail[4] = data[1].i; /* V1 */
964 vertex->detail[5] = data[2].i; /* ARGB1 */
965 break;
966 case TA_VERTEX_TEX_SPEC_PACKED_MOD:
967 vertex->detail[4] = data[0].i; /* U1 */
968 vertex->detail[5] = data[1].i; /* V1 */
969 vertex->detail[6] = data[2].i; /* ARGB1 */
970 vertex->detail[7] = data[3].i; /* ARGB1 */
971 break;
972 case TA_VERTEX_TEX_UV16_PACKED_MOD:
973 vertex->detail[2] = data[0].i; /* UV1 */
974 vertex->detail[3] = data[2].i; /* ARGB1 */
975 break;
976 case TA_VERTEX_TEX_UV16_SPEC_PACKED_MOD:
977 vertex->detail[3] = data[0].i; /* UV1 */
978 vertex->detail[4] = data[2].i; /* ARGB1 */
979 vertex->detail[5] = data[3].i; /* ARGB1 */
980 break;
982 case TA_VERTEX_TEX_INTENSITY_MOD:
983 vertex->detail[3] = data[0].i; /* U1 */
984 vertex->detail[4] = data[1].i; /* V1 */
985 vertex->detail[5] = parse_intensity_colour( ta_status.intensity2, data[2].f ); /* ARGB1 */
986 break;
987 case TA_VERTEX_TEX_SPEC_INTENSITY_MOD:
988 vertex->detail[4] = data[0].i; /* U1 */
989 vertex->detail[5] = data[1].i; /* V1 */
990 vertex->detail[6] = parse_intensity_colour( ta_status.intensity2, data[2].f ); /* ARGB1 */
991 vertex->detail[7] = parse_intensity_colour( ta_status.intensity2, data[3].f ); /* ARGB1 */
992 break;
993 case TA_VERTEX_TEX_UV16_INTENSITY_MOD:
994 vertex->detail[2] = data[0].i; /* UV1 */
995 vertex->detail[3] = parse_intensity_colour( ta_status.intensity2, data[2].f ); /* ARGB1 */
996 break;
997 case TA_VERTEX_TEX_UV16_SPEC_INTENSITY_MOD:
998 vertex->detail[3] = data[0].i; /* UV1 */
999 vertex->detail[4] = parse_intensity_colour( ta_status.intensity2, data[2].f ); /* ARGB1 */
1000 vertex->detail[5] = parse_intensity_colour( ta_status.intensity2, data[3].f ); /* ARGB1 */
1001 break;
1003 case TA_VERTEX_SPRITE:
1004 vertex->y = data[0].f;
1005 vertex->z = data[1].f;
1006 vertex++;
1007 ta_status.vertex_count++;
1008 vertex->x = data[2].f;
1009 vertex->y = data[3].f;
1010 vertex->z = 0;
1011 vertex->detail[0] = 0;
1012 ta_status.poly_vertex[0].detail[0] = 0;
1013 ta_status.poly_vertex[1].detail[0] = 0;
1014 break;
1015 case TA_VERTEX_TEX_SPRITE:
1016 vertex->y = data[0].f;
1017 vertex->z = data[1].f;
1018 vertex++;
1019 ta_status.vertex_count++;
1020 vertex->x = data[2].f;
1021 vertex->y = data[3].f;
1022 vertex->z = 0;
1023 vertex->detail[0] = 0;
1024 vertex->detail[1] = 0;
1025 ta_status.poly_vertex[0].detail[0] = data[5].i;
1026 ta_status.poly_vertex[0].detail[1] = 0;
1027 ta_status.poly_vertex[1].detail[0] = data[6].i;
1028 ta_status.poly_vertex[1].detail[1] = 0;
1029 ta_status.poly_vertex[2].detail[0] = data[7].i;
1030 break;
1031 case TA_VERTEX_MOD_VOLUME:
1032 case TA_VERTEX_LISTLESS:
1033 vertex->y = data[0].f;
1034 vertex->z = data[1].f;
1035 break;
1036 }
1037 ta_status.state = STATE_IN_POLYGON;
1038 }
1040 /**
1041 * Process 1 32-byte block of ta data
1042 */
1043 void pvr2_ta_process_block( unsigned char *input ) {
1044 union ta_data *data = (union ta_data *)input;
1046 switch( ta_status.state ) {
1047 case STATE_ERROR:
1048 /* Fatal error raised - stop processing until reset */
1049 return;
1051 case STATE_EXPECT_POLY_BLOCK2:
1052 /* This is always a pair of floating-point colours */
1053 ta_status.intensity1 =
1054 parse_float_colour( data[0].f, data[1].f, data[2].f, data[3].f );
1055 ta_status.intensity2 =
1056 parse_float_colour( data[4].f, data[5].f, data[6].f, data[7].f );
1057 ta_status.state = STATE_IN_LIST;
1058 break;
1060 case STATE_EXPECT_VERTEX_BLOCK2:
1061 ta_parse_vertex_block2( data );
1062 if( ta_status.vertex_count == ta_status.max_vertex ) {
1063 ta_split_polygon();
1064 }
1065 break;
1067 case STATE_EXPECT_END_VERTEX_BLOCK2:
1068 ta_parse_vertex_block2( data );
1069 if( ta_status.vertex_count < 3 ) {
1070 ta_bad_input_error();
1071 } else {
1072 ta_commit_polygon();
1073 }
1074 ta_status.vertex_count = 0;
1075 ta_status.poly_parity = 0;
1076 ta_status.state = STATE_IN_LIST;
1077 break;
1078 case STATE_IN_LIST:
1079 case STATE_IN_POLYGON:
1080 case STATE_IDLE:
1081 switch( TA_CMD( data->i ) ) {
1082 case TA_CMD_END_LIST:
1083 if( ta_status.state == STATE_IN_POLYGON ) {
1084 ta_bad_input_error();
1085 ta_end_list();
1086 ta_status.state = STATE_ERROR; /* Abort further processing */
1087 } else {
1088 ta_end_list();
1089 }
1090 break;
1091 case TA_CMD_CLIP:
1092 if( ta_status.state == STATE_IN_POLYGON ) {
1093 ta_bad_input_error();
1094 ta_status.accept_vertexes = FALSE;
1095 /* Enter stuffed up mode */
1096 }
1097 ta_status.clip.x1 = data[4].i & 0x3F;
1098 ta_status.clip.y1 = data[5].i & 0x0F;
1099 ta_status.clip.x2 = data[6].i & 0x3F;
1100 ta_status.clip.y2 = data[7].i & 0x0F;
1101 if( ta_status.clip.x2 >= ta_status.width )
1102 ta_status.clip.x2 = ta_status.width - 1;
1103 if( ta_status.clip.y2 >= ta_status.height )
1104 ta_status.clip.y2 = ta_status.height - 1;
1105 break;
1106 case TA_CMD_POLYGON_CONTEXT:
1107 if( ta_status.state == STATE_IDLE ) {
1108 ta_init_list( TA_POLYCMD_LISTTYPE( data->i ) );
1109 }
1111 if( ta_status.vertex_count != 0 ) {
1112 /* Error, and not a very well handled one either */
1113 ta_bad_input_error();
1114 ta_status.accept_vertexes = FALSE;
1115 } else {
1116 if( TA_IS_MODIFIER_LIST( ta_status.current_list_type ) ) {
1117 ta_parse_modifier_context(data);
1118 } else {
1119 ta_parse_polygon_context(data);
1120 }
1121 }
1122 break;
1123 case TA_CMD_SPRITE_CONTEXT:
1124 if( ta_status.state == STATE_IDLE ) {
1125 ta_init_list( TA_POLYCMD_LISTTYPE( data->i ) );
1126 }
1128 if( ta_status.vertex_count != 0 ) {
1129 ta_fill_vertexes();
1130 ta_commit_polygon();
1131 }
1133 ta_parse_sprite_context(data);
1134 break;
1135 case TA_CMD_VERTEX:
1136 ta_status.state = STATE_IN_POLYGON;
1137 ta_parse_vertex(data);
1139 if( ta_status.state == STATE_EXPECT_VERTEX_BLOCK2 ) {
1140 if( TA_IS_END_VERTEX(data[0].i) ) {
1141 ta_status.state = STATE_EXPECT_END_VERTEX_BLOCK2;
1142 }
1143 } else if( TA_IS_END_VERTEX(data->i) ) {
1144 if( ta_status.vertex_count < 3 ) {
1145 ta_bad_input_error();
1146 } else {
1147 ta_commit_polygon();
1148 }
1149 ta_status.vertex_count = 0;
1150 ta_status.poly_parity = 0;
1151 ta_status.state = STATE_IN_LIST;
1152 } else if( ta_status.vertex_count == ta_status.max_vertex ) {
1153 ta_split_polygon();
1154 }
1155 break;
1156 default:
1157 if( ta_status.state == STATE_IN_POLYGON ) {
1158 ta_bad_input_error();
1159 }
1160 }
1161 break;
1162 }
1164 }
1166 /**
1167 * Find the first polygon or sprite context in the supplied buffer of TA
1168 * data.
1169 * @return A pointer to the context, or NULL if it cannot be found
1170 */
1171 uint32_t *pvr2_ta_find_polygon_context( uint32_t *buf, uint32_t length )
1172 {
1173 uint32_t *poly;
1174 for( poly = buf; poly < buf+(length>>2); poly += 8 ) {
1175 if( TA_CMD(*poly) == TA_CMD_POLYGON_CONTEXT ||
1176 TA_CMD(*poly) == TA_CMD_SPRITE_CONTEXT ) {
1177 return poly;
1178 }
1179 }
1180 return NULL;
1181 }
1183 /**
1184 * Write a block of data to the tile accelerator, adding the data to the
1185 * current scene. We don't make any particular attempt to interpret the data
1186 * at this stage, deferring that until render time.
1187 *
1188 * Currently copies the data verbatim to the vertex buffer, processing only
1189 * far enough to generate the correct end-of-list events. Tile buffer is
1190 * entirely ignored.
1191 */
1192 void pvr2_ta_write( unsigned char *buf, uint32_t length )
1193 {
1194 if( ta_status.debug_output ) {
1195 fwrite_dump32( (uint32_t *)buf, length, stderr );
1196 }
1198 for( ; length >=32; length -= 32 ) {
1199 pvr2_ta_process_block( buf );
1200 buf += 32;
1201 }
1202 }
.