filename | src/pvr2/tacore.c |
changeset | 193:31151fcc3cb7 |
prev | 189:615b70cfd729 |
next | 194:7fcecbcd5f01 |
author | nkeynes |
date | Fri Aug 04 01:38:30 2006 +0000 (16 years ago) |
permissions | -rw-r--r-- |
last change | Add more tile list limit tests Implement tile list limits in the ta core. Rename TA_TILEEND to TA_LISTEND |
view | annotate | diff | log | raw |
1 /**
2 * $Id: tacore.c,v 1.2 2006-08-04 01:38:27 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_EXPECT_POLY_BLOCK2 2
24 #define STATE_EXPECT_VERTEX_BLOCK2 3
25 #define STATE_ERROR 4
26 #define STATE_EXPECT_END_VERTEX_BLOCK2 7
28 #define TA_CMD(i) ( (i) >> 29 )
29 #define TA_CMD_END_LIST 0
30 #define TA_CMD_CLIP 1
31 #define TA_CMD_POLYGON_CONTEXT 4
32 #define TA_CMD_SPRITE_CONTEXT 5
33 #define TA_CMD_VERTEX 7
35 #define TA_LIST_NONE -1
36 #define TA_LIST_OPAQUE 0
37 #define TA_LIST_OPAQUE_MOD 1
38 #define TA_LIST_TRANS 2
39 #define TA_LIST_TRANS_MOD 3
40 #define TA_LIST_PUNCH_OUT 4
41 #define TA_IS_MODIFIER_LIST(list) (list == TA_LIST_OPAQUE_MOD || list == TA_LIST_TRANS_MOD)
43 #define TA_GROW_UP 0
44 #define TA_GROW_DOWN 1
46 #define TA_VERTEX_NONE -1
47 #define TA_VERTEX_PACKED 0x00
48 #define TA_VERTEX_TEX_PACKED 0x08
49 #define TA_VERTEX_TEX_SPEC_PACKED 0x0C
50 #define TA_VERTEX_TEX_UV16_PACKED 0x09
51 #define TA_VERTEX_TEX_UV16_SPEC_PACKED 0x0D
52 #define TA_VERTEX_FLOAT 0x10
53 #define TA_VERTEX_TEX_FLOAT 0x18
54 #define TA_VERTEX_TEX_SPEC_FLOAT 0x1C
55 #define TA_VERTEX_TEX_UV16_FLOAT 0x19
56 #define TA_VERTEX_TEX_UV16_SPEC_FLOAT 0x1D
57 #define TA_VERTEX_INTENSITY 0x20
58 #define TA_VERTEX_TEX_INTENSITY 0x28
59 #define TA_VERTEX_TEX_SPEC_INTENSITY 0x2C
60 #define TA_VERTEX_TEX_UV16_INTENSITY 0x29
61 #define TA_VERTEX_TEX_UV16_SPEC_INTENSITY 0x2D
62 #define TA_VERTEX_PACKED_MOD 0x40
63 #define TA_VERTEX_TEX_PACKED_MOD 0x48
64 #define TA_VERTEX_TEX_SPEC_PACKED_MOD 0x4C
65 #define TA_VERTEX_TEX_UV16_PACKED_MOD 0x49
66 #define TA_VERTEX_TEX_UV16_SPEC_PACKED_MOD 0x4D
67 #define TA_VERTEX_INTENSITY_MOD 0x60
68 #define TA_VERTEX_TEX_INTENSITY_MOD 0x68
69 #define TA_VERTEX_TEX_SPEC_INTENSITY_MOD 0x6C
70 #define TA_VERTEX_TEX_UV16_INTENSITY_MOD 0x69
71 #define TA_VERTEX_TEX_UV16_SPEC_INTENSITY_MOD 0x6D
72 #define TA_VERTEX_SPRITE 0x80
73 #define TA_VERTEX_TEX_SPRITE 0x88
74 #define TA_VERTEX_MOD_VOLUME 0x81
76 #define TA_IS_NORMAL_POLY() (ta_status.current_vertex_type < TA_VERTEX_SPRITE)
78 static int strip_lengths[4] = {3,4,6,8}; /* in vertexes */
79 #define TA_POLYCMD_LISTTYPE(i) ( ((i) >> 24) & 0x0F )
80 #define TA_POLYCMD_LENGTH(i) strip_lengths[((i >> 18) & 0x03)]
81 #define TA_POLYCMD_CLIP(i) ((i>>16)&0x03)
82 #define TA_POLYCMD_COLOURFMT(i) (i & 0x00000030)
83 #define TA_POLYCMD_COLOURFMT_ARGB32 0x00000000
84 #define TA_POLYCMD_COLOURFMT_FLOAT 0x00000010
85 #define TA_POLYCMD_COLOURFMT_INTENSITY 0x00000020
86 #define TA_POLYCMD_COLOURFMT_LASTINT 0x00000030
88 #define TA_POLYCMD_MODIFIED 0x00000080
89 #define TA_POLYCMD_FULLMOD 0x00000040
90 #define TA_POLYCMD_TEXTURED 0x00000008
91 #define TA_POLYCMD_SPECULAR 0x00000004
92 #define TA_POLYCMD_SHADED 0x00000002
93 #define TA_POLYCMD_UV16 0x00000001
95 #define TA_POLYCMD_IS_SPECULAR(i) ((i & 0x0000000C)==0x0000000C) /* Only applies to textured polys */
96 #define TA_POLYCMD_IS_FULLMOD(i) ((i & 0x000000C0)==0x000000C0)
99 #define TA_IS_END_VERTEX(i) (i & 0x10000000)
101 #define MIN3( x1, x2, x3 ) ( (x1)<(x2)? ((x1)<(x3)?(x1):(x3)) : ((x2)<(x3)?(x2):(x3)) )
102 #define MAX3( x1, x2, x3 ) ( (x1)>(x2)? ((x1)>(x3)?(x1):(x3)) : ((x2)>(x3)?(x2):(x3)) )
104 #define TILESLOT( x, y ) (ta_status.current_tile_matrix + (ta_status.current_tile_size * (y * ta_status.width+ x) << 2))
106 extern char *video_base;
107 #define PVRRAM(addr) (*(uint32_t *)(video_base + ((addr)&PVR2_RAM_MASK)))
109 struct pvr2_ta_vertex {
110 float x,y,z;
111 uint32_t detail[8]; /* 0-8 detail words */
112 };
114 struct tile_bounds {
115 int x1, y1, x2, y2;
116 };
118 struct pvr2_ta_status {
119 int state;
120 int width, height; /* Tile resolution, ie 20x15 */
121 int tilelist_dir; /* Growth direction of the tilelist, 0 = up, 1 = down */
122 uint32_t tilelist_size; /* Size of the tilelist segments */
123 uint32_t tilelist_start; /* Initial address of the tilelist */
124 int current_vertex_type;
125 gboolean accept_vertexes;
126 int vertex_count; /* index of last start-vertex seen, or -1 if no vertexes
127 * are present
128 */
129 int max_vertex; /* Maximum number of vertexes in the current polygon (3/4/6/8) */
130 int current_list_type;
131 uint32_t current_tile_matrix; /* Memory location of the first tile for the current list. */
132 uint32_t current_tile_size; /* Size of the tile matrix space in 32-bit words (0/8/16/32)*/
133 uint32_t intensity1, intensity2;
134 /**
135 * Current working object
136 */
137 int poly_context_size;
138 int poly_vertex_size;
139 int poly_parity;
140 uint32_t poly_context[5];
141 uint32_t poly_pointer;
142 struct tile_bounds last_triangle_bounds;
143 struct pvr2_ta_vertex poly_vertex[8];
144 int debug_output;
145 };
147 static struct pvr2_ta_status ta_status;
149 static int tilematrix_sizes[4] = {0,8,16,32};
151 /**
152 * Convenience union - ta data is either 32-bit integer or 32-bit float.
153 */
154 union ta_data {
155 unsigned int i;
156 float f;
157 };
160 void pvr2_ta_reset() {
161 ta_status.state = STATE_ERROR; /* State not valid until initialized */
162 ta_status.debug_output = 0;
163 }
165 void pvr2_ta_save_state( FILE *f )
166 {
167 fwrite( &ta_status, sizeof(ta_status), 1, f );
168 }
170 int pvr2_ta_load_state( FILE *f )
171 {
172 if( fread( &ta_status, sizeof(ta_status), 1, f ) != 1 )
173 return 1;
174 return 0;
175 }
177 void pvr2_ta_init() {
178 ta_status.state = STATE_IDLE;
179 ta_status.current_list_type = -1;
180 ta_status.current_vertex_type = -1;
181 ta_status.poly_parity = 0;
182 ta_status.vertex_count = 0;
183 ta_status.max_vertex = 3;
184 ta_status.last_triangle_bounds.x1 = -1;
185 ta_status.accept_vertexes = TRUE;
187 uint32_t size = MMIO_READ( PVR2, TA_TILESIZE );
188 ta_status.width = (size & 0xFFFF) + 1;
189 ta_status.height = (size >> 16) + 1;
190 uint32_t control = MMIO_READ( PVR2, TA_TILECFG );
191 ta_status.tilelist_dir = (control >> 20) & 0x01;
192 ta_status.tilelist_size = tilematrix_sizes[ (control & 0x03) ];
193 MMIO_WRITE( PVR2, TA_POLYPOS, MMIO_READ( PVR2, TA_POLYBASE ) );
194 uint32_t plistpos = MMIO_READ( PVR2, TA_LISTBASE ) >> 2;
195 if( ta_status.tilelist_dir == TA_GROW_DOWN ) {
196 plistpos -= ta_status.tilelist_size;
197 }
198 MMIO_WRITE( PVR2, TA_LISTPOS, plistpos );
199 ta_status.tilelist_start = plistpos;
200 }
202 static uint32_t parse_float_colour( float a, float r, float g, float b ) {
203 return
204 (((unsigned int)((256 * CLAMP(a,0.0,1.0))-1))<<24) |
205 (((unsigned int)((256 * CLAMP(r,0.0,1.0))-1))<<16) |
206 (((unsigned int)((256 * CLAMP(g,0.0,1.0))-1))<<8) |
207 (((unsigned int)((256 * CLAMP(b,0.0,1.0))-1)));
208 }
210 static uint32_t parse_intensity_colour( uint32_t base, float intensity )
211 {
212 unsigned int i = (unsigned int)(256 * CLAMP(intensity, 0.0,1.0));
214 return
215 (((((base & 0xFF) * i) & 0xFF00) |
216 (((base & 0xFF00) * i) & 0xFF0000) |
217 (((base & 0xFF0000) * i) & 0xFF000000)) >> 8) |
218 base & 0xFF000000;
219 }
221 /**
222 * Initialize the specified TA list.
223 */
224 static void ta_init_list( unsigned int listtype ) {
225 int config = MMIO_READ( PVR2, TA_TILECFG );
226 int tile_matrix = MMIO_READ( PVR2, TA_TILEBASE );
227 int list_end = MMIO_READ( PVR2, TA_LISTEND );
229 ta_status.current_tile_matrix = tile_matrix;
231 /* If the list grows down, the end must be < tile matrix start.
232 * If it grows up, the end must be > tile matrix start.
233 * Don't ask me why, it just does...
234 */
235 if( ((ta_status.tilelist_dir == TA_GROW_DOWN && list_end <= tile_matrix) ||
236 (ta_status.tilelist_dir == TA_GROW_UP && list_end >= tile_matrix )) &&
237 listtype <= TA_LIST_PUNCH_OUT ) {
238 int i;
239 uint32_t *p;
240 for( i=0; i < listtype; i++ ) {
241 int size = tilematrix_sizes[(config & 0x03)] << 2;
242 ta_status.current_tile_matrix += ta_status.width * ta_status.height * size;
243 config >>= 4;
244 }
245 ta_status.current_tile_size = tilematrix_sizes[(config & 0x03)];
247 /* Initialize each tile to 0xF0000000 */
248 if( ta_status.current_tile_size != 0 ) {
249 p = (uint32_t *)(video_base + ta_status.current_tile_matrix);
250 for( i=0; i< ta_status.width * ta_status.height; i++ ) {
251 *p = 0xF0000000;
252 p += ta_status.current_tile_size;
253 }
254 }
255 } else {
256 ta_status.current_tile_size = 0;
257 }
259 if( tile_matrix == list_end ) {
260 ta_status.current_tile_size = 0;
261 }
263 ta_status.state = STATE_IN_LIST;
264 ta_status.current_list_type = listtype;
265 ta_status.last_triangle_bounds.x1 = -1;
266 }
268 static int list_events[5] = {EVENT_PVR_OPAQUE_DONE, EVENT_PVR_OPAQUEMOD_DONE,
269 EVENT_PVR_TRANS_DONE, EVENT_PVR_TRANSMOD_DONE,
270 EVENT_PVR_PUNCHOUT_DONE };
272 static void ta_end_list() {
273 if( ta_status.current_list_type != TA_LIST_NONE ) {
274 asic_event( list_events[ta_status.current_list_type] );
275 ta_status.current_list_type = TA_LIST_NONE;
276 ta_status.current_vertex_type = -1;
277 ta_status.state = STATE_IDLE;
278 }
279 }
281 /**
282 * Write data out to the polygon buffer.
283 * If the end-of-buffer is reached, asserts EVENT_PVR_PRIM_ALLOC_FAIL
284 * @param data to be written
285 * @param length Number of 32-bit words to write.
286 * @return number of words actually written
287 */
288 static int ta_write_polygon_buffer( uint32_t *data, int length )
289 {
290 int rv;
291 int posn = MMIO_READ( PVR2, TA_POLYPOS );
292 int end = MMIO_READ( PVR2, TA_POLYEND );
293 uint32_t *target = (uint32_t *)(video_base + posn);
294 for( rv=0; rv < length; rv++ ) {
295 if( posn == end ) {
296 asic_event( EVENT_PVR_PRIM_ALLOC_FAIL );
297 asic_event( EVENT_TA_ERROR );
298 // ta_status.state = STATE_ERROR;
299 break;
300 }
301 *target++ = *data++;
302 posn += 4;
303 }
305 MMIO_WRITE( PVR2, TA_POLYPOS, posn );
306 return rv;
307 }
309 #define TA_NO_ALLOC 0xFFFFFFFF
311 /**
312 * Allocate a new tile list block from the grow space and update the
313 * word at reference to be a link to the new block.
314 */
315 static uint32_t ta_alloc_tilelist( uint32_t reference ) {
316 uint32_t posn = MMIO_READ( PVR2, TA_LISTPOS );
317 uint32_t limit = MMIO_READ( PVR2, TA_LISTEND ) >> 2;
318 uint32_t newposn;
319 uint32_t result;
320 if( ta_status.tilelist_dir == TA_GROW_DOWN ) {
321 newposn = posn - ta_status.tilelist_size;
322 if( posn == limit ) {
323 PVRRAM(posn<<2) = 0xF0000000;
324 PVRRAM(reference) = 0xE0000000 | (posn<<2);
325 return TA_NO_ALLOC;
326 } else if( posn < limit ) {
327 PVRRAM(reference) = 0xE0000000 | (posn<<2);
328 return TA_NO_ALLOC;
329 } else if( newposn <= limit ) {
330 } else if( newposn <= (limit + ta_status.tilelist_size) ) {
331 asic_event( EVENT_TA_ERROR );
332 asic_event( EVENT_PVR_MATRIX_ALLOC_FAIL );
333 MMIO_WRITE( PVR2, TA_LISTPOS, newposn );
334 } else {
335 MMIO_WRITE( PVR2, TA_LISTPOS, newposn );
336 }
337 PVRRAM(reference) = 0xE0000000 | (posn<<2);
338 return posn << 2;
339 } else {
340 newposn = posn + ta_status.tilelist_size;
341 if( posn == limit ) {
342 PVRRAM(posn<<2) = 0xF0000000;
343 PVRRAM(reference) = 0xE0000000 | (posn<<2);
344 return TA_NO_ALLOC;
345 } else if ( posn > limit ) {
346 PVRRAM(reference) = 0xE0000000 | (posn<<2);
347 return TA_NO_ALLOC;
348 } else if( newposn >= limit ) {
349 } else if( newposn >= (limit - ta_status.tilelist_size) ) {
350 asic_event( EVENT_TA_ERROR );
351 asic_event( EVENT_PVR_MATRIX_ALLOC_FAIL );
352 MMIO_WRITE( PVR2, TA_LISTPOS, newposn );
353 } else {
354 MMIO_WRITE( PVR2, TA_LISTPOS, newposn );
355 }
356 PVRRAM(reference) = 0xE0000000 | (posn<<2);
357 return posn << 2;
358 }
359 }
361 /**
362 * Write a tile entry out to the matrix.
363 */
364 static int ta_write_tile_entry( int x, int y, uint32_t tile_entry ) {
365 uint32_t tile = TILESLOT(x,y);
366 uint32_t tilestart = tile;
367 uint32_t value;
368 uint32_t lasttri = 0;
369 int i,l;
371 if( (tile_entry & 0x80000000) &&
372 ta_status.last_triangle_bounds.x1 != -1 &&
373 ta_status.last_triangle_bounds.x1 <= x &&
374 ta_status.last_triangle_bounds.x2 >= x &&
375 ta_status.last_triangle_bounds.y1 <= y &&
376 ta_status.last_triangle_bounds.y2 >= y ) {
377 /* potential for triangle stacking */
378 lasttri = tile_entry & 0xE1E00000;
379 }
382 if( PVRRAM(tile) == 0xF0000000 ) {
383 PVRRAM(tile) = tile_entry;
384 PVRRAM(tile+4) = 0xF0000000;
385 return;
386 }
388 while(1) {
389 value = PVRRAM(tile);
390 for( i=1; i<ta_status.current_tile_size; i++ ) {
391 tile += 4;
392 uint32_t nextval = PVRRAM(tile);
393 if( nextval == 0xF0000000 ) {
394 if( lasttri != 0 && lasttri == (value&0xE1E00000) ) {
395 int count = (value & 0x1E000000) + 0x02000000;
396 if( count < 0x20000000 ) {
397 PVRRAM(tile-4) = (value & 0xE1FFFFFF) | count;
398 return;
399 }
400 }
401 if( i < ta_status.current_tile_size-1 ) {
402 PVRRAM(tile) = tile_entry;
403 PVRRAM(tile+4) = 0xF0000000;
404 return;
405 }
406 }
407 value = nextval;
408 }
410 if( value == 0xF0000000 ) {
411 tile = ta_alloc_tilelist(tile);
412 if( tile != TA_NO_ALLOC ) {
413 PVRRAM(tile) = tile_entry;
414 PVRRAM(tile+4) = 0xF0000000;
415 }
416 return;
417 } else if( (value & 0xFF000000) == 0xE0000000 ) {
418 value &= 0x00FFFFFF;
419 if( value == tilestart )
420 return 0; /* Loop */
421 tilestart = tile = value;
422 } else {
423 /* This should never happen */
424 return 0;
425 }
426 }
427 }
429 /**
430 * Write a completed polygon out to the memory buffers
431 * OPTIMIZEME: This is not terribly efficient at the moment.
432 */
433 static void ta_commit_polygon( ) {
434 int i, x, y;
435 int tx[ta_status.vertex_count], ty[ta_status.vertex_count];
436 struct tile_bounds triangle_bound[ta_status.vertex_count - 2];
437 struct tile_bounds polygon_bound;
438 uint32_t poly_context[5];
440 if( ta_status.vertex_count < 2 ) {
441 return; /* No polygons - ignore */
442 }
443 memcpy( poly_context, ta_status.poly_context, ta_status.poly_context_size * 4 );
445 /* Compute the tile coordinates for each vertex (need to be careful with
446 * clamping here)
447 */
448 for( i=0; i<ta_status.vertex_count; i++ ) {
449 if( ta_status.poly_vertex[i].x < 0.0 ) {
450 tx[i] = -1;
451 } else if( ta_status.poly_vertex[i].x > (float)INT_MAX ) {
452 tx[i] = INT_MAX/32;
453 } else {
454 tx[i] = (int)(ta_status.poly_vertex[i].x / 32.0);
455 }
456 if( ta_status.poly_vertex[i].y < 0.0 ) {
457 ty[i] = -1;
458 } else if( ta_status.poly_vertex[i].y > (float)INT_MAX ) {
459 ty[i] = INT_MAX/32;
460 } else {
461 ty[i] = (int)(ta_status.poly_vertex[i].y / 32.0);
462 }
464 }
466 /* Compute bounding box for each triangle individually, as well
467 * as the overall polygon.
468 */
470 for( i=0; i<ta_status.vertex_count-2; i++ ) {
471 triangle_bound[i].x1 = MIN3(tx[i],tx[i+1],tx[i+2]);
472 triangle_bound[i].x2 = MAX3(tx[i],tx[i+1],tx[i+2]);
473 triangle_bound[i].y1 = MIN3(ty[i],ty[i+1],ty[i+2]);
474 triangle_bound[i].y2 = MAX3(ty[i],ty[i+1],ty[i+2]);
475 if( i == 0 ) {
476 polygon_bound.x1 = triangle_bound[0].x1;
477 polygon_bound.y1 = triangle_bound[0].y1;
478 polygon_bound.x2 = triangle_bound[0].x2;
479 polygon_bound.y2 = triangle_bound[0].y2;
480 } else {
481 polygon_bound.x1 = MIN(polygon_bound.x1, triangle_bound[i].x1);
482 polygon_bound.x2 = MAX(polygon_bound.x2, triangle_bound[i].x2);
483 polygon_bound.y1 = MIN(polygon_bound.y1, triangle_bound[i].y1);
484 polygon_bound.y2 = MAX(polygon_bound.y2, triangle_bound[i].y2);
485 }
486 }
488 /* If the polygon is actually entirely out of the frustum, clip it entirely */
489 if( polygon_bound.x2 < 0 || polygon_bound.x1 > ta_status.width ||
490 polygon_bound.y2 < 0 || polygon_bound.y1 > ta_status.height ) {
491 return;
492 }
494 /* Clamp the polygon bounds to the frustum */
495 if( polygon_bound.x1 < 0 ) polygon_bound.x1 = 0;
496 if( polygon_bound.x2 >= ta_status.width ) polygon_bound.x2 = ta_status.width-1;
497 if( polygon_bound.y1 < 0 ) polygon_bound.y1 = 0;
498 if( polygon_bound.y2 >= ta_status.width ) polygon_bound.y2 = ta_status.height-1;
500 /* Set the "single tile" flag if it's entirely contained in 1 tile */
501 if( polygon_bound.x1 == polygon_bound.x2 &&
502 polygon_bound.y1 == polygon_bound.y2 ) {
503 poly_context[0] |= 0x00200000;
504 }
506 /* Ok, we're good to go - write out the polygon first */
507 uint32_t tile_entry = MMIO_READ( PVR2, TA_POLYPOS ) >> 2 | ta_status.poly_pointer;
509 int status = ta_write_polygon_buffer( poly_context, ta_status.poly_context_size );
510 if( status == 0 ) {
511 /* No memory available - abort */
512 return;
513 } else {
514 for( i=0; i<ta_status.vertex_count && status != 0; i++ ) {
515 status = ta_write_polygon_buffer( (uint32_t *)(&ta_status.poly_vertex[i]), 3 + ta_status.poly_vertex_size );
516 }
517 }
519 if( ta_status.current_tile_size == 0 ) {
520 /* No memory for tile entry, so don't write anything */
521 return;
522 }
524 /* And now the tile entries. Triangles are different from everything else */
525 if( ta_status.vertex_count == 3 ) {
526 tile_entry |= 0x80000000;
527 for( y=polygon_bound.y1; y<=polygon_bound.y2; y++ ) {
528 for( x=polygon_bound.x1; x<=polygon_bound.x2; x++ ) {
529 ta_write_tile_entry( x,y,tile_entry );
530 }
531 }
532 ta_status.last_triangle_bounds.x1 = polygon_bound.x1;
533 ta_status.last_triangle_bounds.y1 = polygon_bound.y1;
534 ta_status.last_triangle_bounds.x2 = polygon_bound.x2;
535 ta_status.last_triangle_bounds.y2 = polygon_bound.y2;
536 } else if( ta_status.current_vertex_type == TA_VERTEX_SPRITE ||
537 ta_status.current_vertex_type == TA_VERTEX_TEX_SPRITE ) {
538 tile_entry |= 0xA0000000;
539 for( y=polygon_bound.y1; y<=polygon_bound.y2; y++ ) {
540 for( x=polygon_bound.x1; x<=polygon_bound.x2; x++ ) {
541 ta_write_tile_entry( x,y,tile_entry );
542 }
543 }
544 ta_status.last_triangle_bounds.x1 = polygon_bound.x1;
545 ta_status.last_triangle_bounds.y1 = polygon_bound.y1;
546 ta_status.last_triangle_bounds.x2 = polygon_bound.x2;
547 ta_status.last_triangle_bounds.y2 = polygon_bound.y2;
548 } else {
549 for( y=polygon_bound.y1; y<=polygon_bound.y2; y++ ) {
550 for( x=polygon_bound.x1; x<=polygon_bound.x2; x++ ) {
551 uint32_t entry = tile_entry;
552 for( i=0; i<ta_status.vertex_count-2; i++ ) {
553 if( triangle_bound[i].x1 <= x && triangle_bound[i].x2 >= x &&
554 triangle_bound[i].y1 <= y && triangle_bound[i].y2 >= y ) {
555 entry |= (0x40000000>>i);
556 }
557 }
558 ta_write_tile_entry( x, y, entry );
559 }
560 }
561 ta_status.last_triangle_bounds.x1 = -1;
562 }
563 }
565 /**
566 * Variant of ta_split_polygon called when vertex_count == max_vertex, but
567 * the client hasn't sent the LAST VERTEX flag. Commit the poly as normal
568 * first, then start a new poly with the first 2 vertexes taken from the
569 * current one.
570 */
571 static void ta_split_polygon() {
572 ta_commit_polygon();
573 if( TA_IS_NORMAL_POLY() ) {
574 /* This only applies to ordinary polys - Sprites + modifier lists are
575 * handled differently
576 */
577 if( ta_status.vertex_count == 3 ) {
578 /* Triangles use an odd/even scheme */
579 if( ta_status.poly_parity == 0 ) {
580 memcpy( &ta_status.poly_vertex[0], &ta_status.poly_vertex[2],
581 sizeof(struct pvr2_ta_vertex) );
582 ta_status.poly_parity = 1;
583 } else {
584 memcpy( &ta_status.poly_vertex[1], &ta_status.poly_vertex[2],
585 sizeof(struct pvr2_ta_vertex) );
586 ta_status.poly_parity = 0;
587 }
588 } else {
589 /* Everything else just uses the last 2 vertexes in order */
590 memcpy( &ta_status.poly_vertex[0], &ta_status.poly_vertex[ta_status.vertex_count-2],
591 sizeof(struct pvr2_ta_vertex)*2 );
592 ta_status.poly_parity = 0;
593 }
594 ta_status.vertex_count = 2;
595 } else {
596 ta_status.vertex_count = 0;
597 }
598 }
600 /**
601 * Parse the polygon context block and setup the internal state to receive
602 * vertexes.
603 * @param data 32 bytes of parameter data.
604 */
605 static void ta_parse_polygon_context( union ta_data *data ) {
606 int colourfmt = TA_POLYCMD_COLOURFMT(data[0].i);
607 ta_status.max_vertex = TA_POLYCMD_LENGTH(data[0].i);
608 ta_status.vertex_count = 0;
609 ta_status.poly_context[0] =
610 (data[1].i & 0xFC1FFFFF) | ((data[0].i & 0x0B) << 22);
611 ta_status.poly_context[1] = data[2].i;
612 ta_status.poly_context[3] = data[4].i;
613 ta_status.poly_parity = 0;
614 if( data[0].i & TA_POLYCMD_TEXTURED ) {
615 ta_status.current_vertex_type = data[0].i & 0x0D;
616 ta_status.poly_context[2] = data[3].i;
617 ta_status.poly_context[4] = data[5].i;
618 if( data[0].i & TA_POLYCMD_SPECULAR ) {
619 ta_status.poly_context[0] |= 0x01000000;
620 ta_status.poly_vertex_size = 4;
621 } else {
622 ta_status.poly_vertex_size = 3;
623 }
624 if( data[0].i & TA_POLYCMD_UV16 ) {
625 ta_status.poly_vertex_size--;
626 }
627 } else {
628 ta_status.current_vertex_type = 0;
629 ta_status.poly_vertex_size = 1;
630 ta_status.poly_context[2] = 0;
631 ta_status.poly_context[4] = 0;
632 }
634 ta_status.poly_pointer = (ta_status.poly_vertex_size << 21);
635 ta_status.poly_context_size = 3;
636 if( data[0].i & TA_POLYCMD_MODIFIED ) {
637 ta_status.poly_pointer |= 0x01000000;
638 if( data[0].i & TA_POLYCMD_FULLMOD ) {
639 ta_status.poly_context_size = 5;
640 ta_status.poly_vertex_size <<= 1;
641 ta_status.current_vertex_type |= 0x40;
642 /* Modified/float not supported - behaves as per last intensity */
643 if( colourfmt == TA_POLYCMD_COLOURFMT_FLOAT ) {
644 colourfmt = TA_POLYCMD_COLOURFMT_LASTINT;
645 }
646 }
647 }
649 if( colourfmt == TA_POLYCMD_COLOURFMT_INTENSITY ) {
650 if( TA_POLYCMD_IS_FULLMOD(data[0].i) ||
651 TA_POLYCMD_IS_SPECULAR(data[0].i) ) {
652 ta_status.state = STATE_EXPECT_POLY_BLOCK2;
653 } else {
654 ta_status.intensity1 =
655 parse_float_colour( data[4].f, data[5].f, data[6].f, data[7].f );
656 }
657 } else if( colourfmt == TA_POLYCMD_COLOURFMT_LASTINT ) {
658 colourfmt = TA_POLYCMD_COLOURFMT_INTENSITY;
659 }
661 ta_status.current_vertex_type |= colourfmt;
662 }
664 /**
665 * Parse the modifier volume context block and setup the internal state to
666 * receive modifier vertexes.
667 * @param data 32 bytes of parameter data.
668 */
669 static void ta_parse_modifier_context( union ta_data *data ) {
670 ta_status.current_vertex_type = TA_VERTEX_MOD_VOLUME;
671 ta_status.poly_vertex_size = 0;
672 ta_status.poly_context_size = 3;
673 ta_status.poly_context[0] = (data[1].i & 0xFC1FFFFF) |
674 ((data[0].i & 0x0B)<<22);
675 if( TA_POLYCMD_IS_SPECULAR(data[0].i) ) {
676 ta_status.poly_context[0] |= 0x01000000;
677 }
678 ta_status.poly_context[1] = 0;
679 ta_status.poly_context[2] = 0;
680 ta_status.vertex_count = 0;
681 ta_status.max_vertex = 3;
682 ta_status.poly_pointer = 0;
683 }
685 /**
686 * Parse the sprite context block and setup the internal state to receive
687 * vertexes.
688 * @param data 32 bytes of parameter data.
689 */
690 static void ta_parse_sprite_context( union ta_data *data ) {
691 ta_status.poly_context_size = 3;
692 ta_status.poly_context[0] = (data[1].i & 0xFC1FFFFF) |
693 ((data[0].i & 0x0B)<<22) | 0x00400000;
694 if( TA_POLYCMD_IS_SPECULAR(data[0].i) ) {
695 ta_status.poly_context[0] |= 0x01000000;
696 }
697 ta_status.poly_context[1] = data[2].i;
698 ta_status.poly_context[2] = data[3].i;
699 if( data[0].i & TA_POLYCMD_TEXTURED ) {
700 ta_status.poly_vertex_size = 2;
701 ta_status.poly_vertex[2].detail[1] = data[4].i;
702 ta_status.current_vertex_type = TA_VERTEX_TEX_SPRITE;
703 } else {
704 ta_status.poly_vertex_size = 1;
705 ta_status.poly_vertex[2].detail[0] = data[4].i;
706 ta_status.current_vertex_type = TA_VERTEX_SPRITE;
707 }
708 ta_status.vertex_count = 0;
709 ta_status.max_vertex = 4;
710 ta_status.poly_pointer = (ta_status.poly_vertex_size << 21);
711 }
713 /**
714 * Copy the last read vertex into all vertexes up to max_vertex. Used for
715 * Aborted polygons under some circumstances.
716 */
717 static void ta_fill_vertexes( ) {
718 int i;
719 for( i=ta_status.vertex_count; i<ta_status.max_vertex; i++ ) {
720 memcpy( &ta_status.poly_vertex[i], &ta_status.poly_vertex[ta_status.vertex_count-1],
721 sizeof( struct pvr2_ta_vertex ) );
722 }
723 }
725 static void ta_parse_vertex( union ta_data *data ) {
726 struct pvr2_ta_vertex *vertex = &ta_status.poly_vertex[ta_status.vertex_count];
727 vertex->x = data[1].f;
728 vertex->y = data[2].f;
729 vertex->z = data[3].f;
731 switch( ta_status.current_vertex_type ) {
732 case TA_VERTEX_PACKED:
733 vertex->detail[0] = data[6].i;
734 break;
735 case TA_VERTEX_FLOAT:
736 vertex->detail[0] = parse_float_colour( data[4].f, data[5].f, data[6].f, data[7].f );
737 break;
738 case TA_VERTEX_INTENSITY:
739 vertex->detail[0] = parse_intensity_colour( ta_status.intensity1, data[6].f );
740 break;
742 case TA_VERTEX_TEX_SPEC_PACKED:
743 vertex->detail[3] = data[7].i; /* ARGB */
744 /* Fallthrough */
745 case TA_VERTEX_TEX_PACKED:
746 vertex->detail[0] = data[4].i; /* U */
747 vertex->detail[1] = data[5].i; /* V */
748 vertex->detail[2] = data[6].i; /* ARGB */
749 break;
750 case TA_VERTEX_TEX_UV16_SPEC_PACKED:
751 vertex->detail[2] = data[7].i; /* ARGB */
752 /* Fallthrough */
753 case TA_VERTEX_TEX_UV16_PACKED:
754 vertex->detail[0] = data[4].i; /* UV */
755 vertex->detail[1] = data[6].i; /* ARGB */
756 break;
758 case TA_VERTEX_TEX_FLOAT:
759 case TA_VERTEX_TEX_SPEC_FLOAT:
760 vertex->detail[0] = data[4].i; /* U */
761 vertex->detail[1] = data[5].i; /* UV */
762 ta_status.state = STATE_EXPECT_VERTEX_BLOCK2;
763 break;
764 case TA_VERTEX_TEX_UV16_FLOAT:
765 case TA_VERTEX_TEX_UV16_SPEC_FLOAT:
766 vertex->detail[0] = data[4].i; /* UV */
767 ta_status.state = STATE_EXPECT_VERTEX_BLOCK2;
768 break;
770 case TA_VERTEX_TEX_SPEC_INTENSITY:
771 vertex->detail[3] = parse_intensity_colour( ta_status.intensity2, data[7].f );
772 /* Fallthrough */
773 case TA_VERTEX_TEX_INTENSITY:
774 vertex->detail[0] = data[4].i; /* U */
775 vertex->detail[1] = data[5].i; /* V */
776 vertex->detail[2] = parse_intensity_colour( ta_status.intensity1, data[6].f );
777 break;
778 case TA_VERTEX_TEX_UV16_SPEC_INTENSITY:
779 vertex->detail[2] = parse_intensity_colour( ta_status.intensity2, data[7].f );
780 /* Fallthrough */
781 case TA_VERTEX_TEX_UV16_INTENSITY:
782 vertex->detail[0] = data[4].i; /* UV */
783 vertex->detail[1] = parse_intensity_colour( ta_status.intensity1, data[6].f );
784 break;
786 case TA_VERTEX_PACKED_MOD:
787 vertex->detail[0] = data[4].i; /* ARGB */
788 vertex->detail[1] = data[5].i; /* ARGB */
789 break;
790 case TA_VERTEX_INTENSITY_MOD:
791 vertex->detail[0] = parse_intensity_colour( ta_status.intensity1, data[4].f );
792 vertex->detail[1] = parse_intensity_colour( ta_status.intensity2, data[5].f );
793 break;
795 case TA_VERTEX_TEX_SPEC_PACKED_MOD:
796 vertex->detail[3] = data[7].i; /* ARGB0 */
797 /* Fallthrough */
798 case TA_VERTEX_TEX_PACKED_MOD:
799 vertex->detail[0] = data[4].i; /* U0 */
800 vertex->detail[1] = data[5].i; /* V0 */
801 vertex->detail[2] = data[6].i; /* ARGB0 */
802 ta_status.state = STATE_EXPECT_VERTEX_BLOCK2;
803 break;
804 case TA_VERTEX_TEX_UV16_SPEC_PACKED_MOD:
805 vertex->detail[2] = data[7].i; /* ARGB0 */
806 /* Fallthrough */
807 case TA_VERTEX_TEX_UV16_PACKED_MOD:
808 vertex->detail[0] = data[4].i; /* UV0 */
809 vertex->detail[1] = data[6].i; /* ARGB0 */
810 ta_status.state = STATE_EXPECT_VERTEX_BLOCK2;
811 break;
813 case TA_VERTEX_TEX_SPEC_INTENSITY_MOD:
814 vertex->detail[3] = parse_intensity_colour( ta_status.intensity1, data[7].f );
815 /* Fallthrough */
816 case TA_VERTEX_TEX_INTENSITY_MOD:
817 vertex->detail[0] = data[4].i; /* U0 */
818 vertex->detail[1] = data[5].i; /* V0 */
819 vertex->detail[2] = parse_intensity_colour( ta_status.intensity1, data[6].f );
820 ta_status.state = STATE_EXPECT_VERTEX_BLOCK2;
821 break;
822 case TA_VERTEX_TEX_UV16_SPEC_INTENSITY_MOD:
823 vertex->detail[2] = parse_intensity_colour( ta_status.intensity1, data[7].f );
824 /* Fallthrough */
825 case TA_VERTEX_TEX_UV16_INTENSITY_MOD:
826 vertex->detail[0] = data[4].i; /* UV0 */
827 vertex->detail[1] = parse_intensity_colour( ta_status.intensity1, data[6].f );
828 ta_status.state = STATE_EXPECT_VERTEX_BLOCK2;
829 break;
831 case TA_VERTEX_SPRITE:
832 case TA_VERTEX_TEX_SPRITE:
833 case TA_VERTEX_MOD_VOLUME:
834 vertex++;
835 vertex->x = data[4].f;
836 vertex->y = data[5].f;
837 vertex->z = data[6].f;
838 vertex++;
839 vertex->x = data[7].f;
840 ta_status.vertex_count += 2;
841 ta_status.state = STATE_EXPECT_VERTEX_BLOCK2;
842 break;
843 }
844 ta_status.vertex_count++;
845 }
847 static void ta_parse_vertex_block2( union ta_data *data ) {
848 struct pvr2_ta_vertex *vertex = &ta_status.poly_vertex[ta_status.vertex_count-1];
850 switch( ta_status.current_vertex_type ) {
851 case TA_VERTEX_TEX_SPEC_FLOAT:
852 vertex->detail[3] = parse_float_colour( data[4].f, data[5].f, data[6].f, data[7].f );
853 /* Fallthrough */
854 case TA_VERTEX_TEX_FLOAT:
855 vertex->detail[2] = parse_float_colour( data[0].f, data[1].f, data[2].f, data[3].f );
856 break;
857 case TA_VERTEX_TEX_UV16_SPEC_FLOAT:
858 vertex->detail[2] = parse_float_colour( data[4].f, data[5].f, data[6].f, data[7].f );
859 /* Fallthrough */
860 case TA_VERTEX_TEX_UV16_FLOAT:
861 vertex->detail[1] = parse_float_colour( data[0].f, data[1].f, data[2].f, data[3].f );
862 break;
863 case TA_VERTEX_TEX_PACKED_MOD:
864 vertex->detail[3] = data[0].i; /* U1 */
865 vertex->detail[4] = data[1].i; /* V1 */
866 vertex->detail[5] = data[2].i; /* ARGB1 */
867 break;
868 case TA_VERTEX_TEX_SPEC_PACKED_MOD:
869 vertex->detail[4] = data[0].i; /* U1 */
870 vertex->detail[5] = data[1].i; /* V1 */
871 vertex->detail[6] = data[2].i; /* ARGB1 */
872 vertex->detail[7] = data[3].i; /* ARGB1 */
873 break;
874 case TA_VERTEX_TEX_UV16_PACKED_MOD:
875 vertex->detail[2] = data[0].i; /* UV1 */
876 vertex->detail[3] = data[2].i; /* ARGB1 */
877 break;
878 case TA_VERTEX_TEX_UV16_SPEC_PACKED_MOD:
879 vertex->detail[3] = data[0].i; /* UV1 */
880 vertex->detail[4] = data[2].i; /* ARGB1 */
881 vertex->detail[5] = data[3].i; /* ARGB1 */
882 break;
884 case TA_VERTEX_TEX_INTENSITY_MOD:
885 vertex->detail[3] = data[0].i; /* U1 */
886 vertex->detail[4] = data[1].i; /* V1 */
887 vertex->detail[5] = parse_intensity_colour( ta_status.intensity2, data[2].f ); /* ARGB1 */
888 break;
889 case TA_VERTEX_TEX_SPEC_INTENSITY_MOD:
890 vertex->detail[4] = data[0].i; /* U1 */
891 vertex->detail[5] = data[1].i; /* V1 */
892 vertex->detail[6] = parse_intensity_colour( ta_status.intensity2, data[2].f ); /* ARGB1 */
893 vertex->detail[7] = parse_intensity_colour( ta_status.intensity2, data[3].f ); /* ARGB1 */
894 break;
895 case TA_VERTEX_TEX_UV16_INTENSITY_MOD:
896 vertex->detail[2] = data[0].i; /* UV1 */
897 vertex->detail[3] = parse_intensity_colour( ta_status.intensity2, data[2].f ); /* ARGB1 */
898 break;
899 case TA_VERTEX_TEX_UV16_SPEC_INTENSITY_MOD:
900 vertex->detail[3] = data[0].i; /* UV1 */
901 vertex->detail[4] = parse_intensity_colour( ta_status.intensity2, data[2].f ); /* ARGB1 */
902 vertex->detail[5] = parse_intensity_colour( ta_status.intensity2, data[3].f ); /* ARGB1 */
903 break;
905 case TA_VERTEX_SPRITE:
906 vertex->y = data[0].f;
907 vertex->z = data[1].f;
908 vertex++;
909 ta_status.vertex_count++;
910 vertex->x = data[2].f;
911 vertex->y = data[3].f;
912 vertex->z = 0;
913 vertex->detail[0] = 0;
914 ta_status.poly_vertex[0].detail[0] = 0;
915 ta_status.poly_vertex[1].detail[0] = 0;
916 break;
917 case TA_VERTEX_TEX_SPRITE:
918 vertex->y = data[0].f;
919 vertex->z = data[1].f;
920 vertex++;
921 ta_status.vertex_count++;
922 vertex->x = data[2].f;
923 vertex->y = data[3].f;
924 vertex->z = 0;
925 vertex->detail[0] = 0;
926 vertex->detail[1] = 0;
927 ta_status.poly_vertex[0].detail[0] = data[5].i;
928 ta_status.poly_vertex[0].detail[1] = 0;
929 ta_status.poly_vertex[1].detail[0] = data[6].i;
930 ta_status.poly_vertex[1].detail[1] = 0;
931 ta_status.poly_vertex[2].detail[0] = data[7].i;
932 break;
933 case TA_VERTEX_MOD_VOLUME:
934 vertex->y = data[0].f;
935 vertex->z = data[1].f;
936 break;
937 }
938 ta_status.state = STATE_IN_LIST;
939 }
941 /**
942 * Process 1 32-byte block of ta data
943 */
944 void pvr2_ta_process_block( char *input ) {
945 union ta_data *data = (union ta_data *)input;
947 switch( ta_status.state ) {
948 case STATE_ERROR:
949 /* Error raised - stop processing until reset */
950 return;
952 case STATE_EXPECT_POLY_BLOCK2:
953 /* This is always a pair of floating-point colours */
954 ta_status.intensity1 =
955 parse_float_colour( data[0].f, data[1].f, data[2].f, data[3].f );
956 ta_status.intensity2 =
957 parse_float_colour( data[4].f, data[5].f, data[6].f, data[7].f );
958 ta_status.state = STATE_IN_LIST;
959 break;
961 case STATE_EXPECT_VERTEX_BLOCK2:
962 ta_parse_vertex_block2( data );
963 if( ta_status.vertex_count == ta_status.max_vertex ) {
964 ta_split_polygon();
965 }
966 break;
968 case STATE_EXPECT_END_VERTEX_BLOCK2:
969 ta_parse_vertex_block2( data );
970 ta_commit_polygon();
971 ta_status.vertex_count = 0;
972 ta_status.poly_parity = 0;
974 case STATE_IN_LIST:
975 case STATE_IDLE:
976 switch( TA_CMD( data->i ) ) {
977 case TA_CMD_END_LIST:
978 ta_end_list();
979 break;
980 case TA_CMD_CLIP: /* TODO */
981 break;
982 case TA_CMD_POLYGON_CONTEXT:
983 if( ta_status.state == STATE_IDLE ) {
984 ta_init_list( TA_POLYCMD_LISTTYPE( data->i ) );
985 }
987 if( ta_status.vertex_count != 0 ) {
988 /* Error, and not a very well handled one either */
989 asic_event( EVENT_PVR_BAD_INPUT );
990 asic_event( EVENT_TA_ERROR );
991 ta_status.accept_vertexes = FALSE;
992 ta_fill_vertexes();
993 } else {
994 if( TA_IS_MODIFIER_LIST( ta_status.current_list_type ) ) {
995 ta_parse_modifier_context(data);
996 } else {
997 ta_parse_polygon_context(data);
998 }
999 }
1000 break;
1001 case TA_CMD_SPRITE_CONTEXT:
1002 if( ta_status.state == STATE_IDLE ) {
1003 ta_init_list( TA_POLYCMD_LISTTYPE( data->i ) );
1004 }
1006 if( ta_status.vertex_count != 0 ) {
1007 ta_fill_vertexes();
1008 ta_commit_polygon();
1009 }
1011 ta_parse_sprite_context(data);
1012 break;
1013 case TA_CMD_VERTEX:
1014 ta_parse_vertex(data);
1016 if( ta_status.state == STATE_EXPECT_VERTEX_BLOCK2 ) {
1017 if( TA_IS_END_VERTEX(data[0].i) ) {
1018 ta_status.state = STATE_EXPECT_END_VERTEX_BLOCK2;
1019 }
1020 } else if( TA_IS_END_VERTEX(data->i) ) {
1021 ta_commit_polygon();
1022 ta_status.vertex_count = 0;
1023 ta_status.poly_parity = 0;
1024 } else if( ta_status.vertex_count == ta_status.max_vertex ) {
1025 ta_split_polygon();
1026 }
1027 break;
1028 }
1029 break;
1030 }
1032 }
1036 /**
1037 * Write a block of data to the tile accelerator, adding the data to the
1038 * current scene. We don't make any particular attempt to interpret the data
1039 * at this stage, deferring that until render time.
1040 *
1041 * Currently copies the data verbatim to the vertex buffer, processing only
1042 * far enough to generate the correct end-of-list events. Tile buffer is
1043 * entirely ignored.
1044 */
1045 void pvr2_ta_write( char *buf, uint32_t length )
1046 {
1047 if( ta_status.debug_output ) {
1048 fwrite_dump32( (uint32_t *)buf, length, stderr );
1049 }
1051 for( ; length >=32; length -= 32 ) {
1052 pvr2_ta_process_block( buf );
1053 buf += 32;
1054 }
1055 }
.