filename | src/pvr2/tacore.c |
changeset | 189:615b70cfd729 |
next | 193:31151fcc3cb7 |
author | nkeynes |
date | Wed Aug 02 04:06:45 2006 +0000 (17 years ago) |
permissions | -rw-r--r-- |
last change | Issue 0003: TA Vertex compiler Initial implementation of the TA. Renderer hooked up to the TA "properly" now as well |
view | annotate | diff | log | raw |
1 /**
2 * $Id: tacore.c,v 1.1 2006-08-02 04:06:45 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 int current_vertex_type;
124 int vertex_count; /* index of last start-vertex seen, or -1 if no vertexes
125 * are present
126 */
127 int max_vertex; /* Maximum number of vertexes in the current polygon (3/4/6/8) */
128 int current_list_type;
129 uint32_t current_tile_matrix; /* Memory location of the first tile for the current list. */
130 uint32_t current_tile_size; /* Size of the tile matrix space in 32-bit words (0/8/16/32)*/
131 uint32_t intensity1, intensity2;
132 /**
133 * Current working object
134 */
135 int poly_context_size;
136 int poly_vertex_size;
137 int poly_parity;
138 uint32_t poly_context[5];
139 uint32_t poly_pointer;
140 struct tile_bounds last_triangle_bounds;
141 struct pvr2_ta_vertex poly_vertex[8];
142 int debug_output;
143 };
145 static struct pvr2_ta_status ta_status;
147 static int tilematrix_sizes[4] = {0,8,16,32};
149 /**
150 * Convenience union - ta data is either 32-bit integer or 32-bit float.
151 */
152 union ta_data {
153 unsigned int i;
154 float f;
155 };
158 void pvr2_ta_reset() {
159 ta_status.state = STATE_ERROR; /* State not valid until initialized */
160 ta_status.debug_output = 0;
161 }
163 void pvr2_ta_init() {
164 ta_status.state = STATE_IDLE;
165 ta_status.current_list_type = -1;
166 ta_status.current_vertex_type = -1;
167 ta_status.poly_parity = 0;
168 ta_status.vertex_count = 0;
169 ta_status.max_vertex = 3;
170 ta_status.last_triangle_bounds.x1 = -1;
172 uint32_t size = MMIO_READ( PVR2, TA_TILESIZE );
173 ta_status.width = (size & 0xFFFF) + 1;
174 ta_status.height = (size >> 16) + 1;
175 uint32_t control = MMIO_READ( PVR2, TA_TILECFG );
176 ta_status.tilelist_dir = (control >> 20) & 0x01;
177 ta_status.tilelist_size = tilematrix_sizes[ (control & 0x03) ];
178 MMIO_WRITE( PVR2, TA_POLYPOS, MMIO_READ( PVR2, TA_POLYBASE ) );
179 uint32_t plistpos = MMIO_READ( PVR2, TA_LISTBASE ) >> 2;
180 if( ta_status.tilelist_dir == TA_GROW_DOWN ) {
181 plistpos -= ta_status.tilelist_size;
182 }
183 MMIO_WRITE( PVR2, TA_LISTPOS, plistpos );
184 }
186 static uint32_t parse_float_colour( float a, float r, float g, float b ) {
187 return
188 (((unsigned int)((256 * CLAMP(a,0.0,1.0))-1))<<24) |
189 (((unsigned int)((256 * CLAMP(r,0.0,1.0))-1))<<16) |
190 (((unsigned int)((256 * CLAMP(g,0.0,1.0))-1))<<8) |
191 (((unsigned int)((256 * CLAMP(b,0.0,1.0))-1)));
192 }
194 static uint32_t parse_intensity_colour( uint32_t base, float intensity )
195 {
196 unsigned int i = (unsigned int)(256 * CLAMP(intensity, 0.0,1.0));
198 return
199 (((((base & 0xFF) * i) & 0xFF00) |
200 (((base & 0xFF00) * i) & 0xFF0000) |
201 (((base & 0xFF0000) * i) & 0xFF000000)) >> 8) |
202 base & 0xFF000000;
203 }
205 /**
206 * Initialize the specified TA list.
207 */
208 static void ta_init_list( unsigned int listtype ) {
209 int config = MMIO_READ( PVR2, TA_TILECFG );
210 int tile_matrix = MMIO_READ( PVR2, TA_TILEBASE );
211 if( listtype <= TA_LIST_PUNCH_OUT ) {
212 int i;
213 uint32_t *p;
214 for( i=0; i < listtype; i++ ) {
215 int size = tilematrix_sizes[(config & 0x03)] << 2;
216 tile_matrix += ta_status.width * ta_status.height * size;
217 config >>= 4;
218 }
219 ta_status.current_tile_matrix = tile_matrix;
220 ta_status.current_tile_size = tilematrix_sizes[(config & 0x03)];
222 /* Initialize each tile to 0xF0000000 */
223 if( ta_status.current_tile_size != 0 ) {
224 p = (uint32_t *)(video_base + tile_matrix);
225 for( i=0; i< ta_status.width * ta_status.height; i++ ) {
226 *p = 0xF0000000;
227 p += ta_status.current_tile_size;
228 }
229 }
230 }
231 ta_status.state = STATE_IN_LIST;
232 ta_status.current_list_type = listtype;
233 ta_status.last_triangle_bounds.x1 = -1;
234 }
236 static int list_events[5] = {EVENT_PVR_OPAQUE_DONE, EVENT_PVR_OPAQUEMOD_DONE,
237 EVENT_PVR_TRANS_DONE, EVENT_PVR_TRANSMOD_DONE,
238 EVENT_PVR_PUNCHOUT_DONE };
240 static void ta_end_list() {
241 if( ta_status.current_list_type != TA_LIST_NONE ) {
242 asic_event( list_events[ta_status.current_list_type] );
243 ta_status.current_list_type = TA_LIST_NONE;
244 ta_status.current_vertex_type = -1;
245 ta_status.state = STATE_IDLE;
246 }
247 }
249 /**
250 * Write data out to the polygon buffer.
251 * If the end-of-buffer is reached, asserts EVENT_PVR_PRIM_ALLOC_FAIL
252 * @param data to be written
253 * @param length Number of 32-bit words to write.
254 * @return number of words actually written
255 */
256 static int ta_write_polygon_buffer( uint32_t *data, int length )
257 {
258 int rv;
259 int posn = MMIO_READ( PVR2, TA_POLYPOS );
260 int end = MMIO_READ( PVR2, TA_POLYEND );
261 uint32_t *target = (uint32_t *)(video_base + posn);
262 for( rv=0; rv < length; rv++ ) {
263 if( posn == end ) {
264 asic_event( EVENT_PVR_PRIM_ALLOC_FAIL );
265 asic_event( EVENT_TA_ERROR );
266 // ta_status.state = STATE_ERROR;
267 break;
268 }
269 *target++ = *data++;
270 posn += 4;
271 }
273 MMIO_WRITE( PVR2, TA_POLYPOS, posn );
274 return rv;
275 }
277 /**
278 * Allocate a new tile list from the grow space
279 */
280 static uint32_t ta_alloc_tilelist() {
281 uint32_t posn = MMIO_READ( PVR2, TA_LISTPOS );
282 uint32_t newposn;
283 if( ta_status.tilelist_dir == TA_GROW_DOWN ) {
284 newposn = posn - ta_status.tilelist_size;
285 } else {
286 newposn = posn + ta_status.tilelist_size;
287 }
288 MMIO_WRITE( PVR2, TA_LISTPOS, newposn );
289 return posn << 2;
290 }
292 /**
293 * Write a tile entry out to the matrix.
294 */
295 static int ta_write_tile_entry( int x, int y, uint32_t tile_entry ) {
296 uint32_t tile = TILESLOT(x,y);
297 uint32_t value;
298 uint32_t lasttri = 0;
299 int i,l;
301 if( (tile_entry & 0x80000000) &&
302 ta_status.last_triangle_bounds.x1 != -1 &&
303 ta_status.last_triangle_bounds.x1 <= x &&
304 ta_status.last_triangle_bounds.x2 >= x &&
305 ta_status.last_triangle_bounds.y1 <= y &&
306 ta_status.last_triangle_bounds.y2 >= y ) {
307 /* potential for triangle stacking */
308 lasttri = tile_entry & 0xE1E00000;
309 }
312 if( PVRRAM(tile) == 0xF0000000 ) {
313 PVRRAM(tile) = tile_entry;
314 PVRRAM(tile+4) = 0xF0000000;
315 return;
316 }
318 while(1) {
319 value = PVRRAM(tile);
320 for( i=1; i<ta_status.current_tile_size; i++ ) {
321 tile += 4;
322 uint32_t nextval = PVRRAM(tile);
323 if( nextval == 0xF0000000 ) {
324 if( lasttri != 0 && lasttri == (value&0xE1E00000) ) {
325 int count = (value & 0x1E000000) + 0x02000000;
326 if( count < 0x20000000 ) {
327 PVRRAM(tile-4) = (value & 0xE1FFFFFF) | count;
328 return;
329 }
330 }
331 if( i < ta_status.current_tile_size-1 ) {
332 PVRRAM(tile) = tile_entry;
333 PVRRAM(tile+4) = 0xF0000000;
334 return;
335 }
336 }
337 value = nextval;
338 }
340 if( value == 0xF0000000 ) {
341 value = ta_alloc_tilelist();
342 PVRRAM(tile) = value | 0xE0000000;
343 tile = value;
344 PVRRAM(tile) = tile_entry;
345 PVRRAM(tile+4) = 0xF0000000;
346 return;
347 } else if( (value & 0xFF000000) == 0xE0000000 ) {
348 tile = (value & 0x00FFFFFF);
349 } else {
350 /* This should never happen */
351 return 0;
352 }
353 }
354 }
356 /**
357 * Write a completed polygon out to the memory buffers
358 * OPTIMIZEME: This is not terribly efficient at the moment.
359 */
360 static void ta_commit_polygon( ) {
361 int i, x, y;
362 int tx[ta_status.vertex_count], ty[ta_status.vertex_count];
363 struct tile_bounds triangle_bound[ta_status.vertex_count - 2];
364 struct tile_bounds polygon_bound;
365 uint32_t poly_context[5];
367 if( ta_status.vertex_count < 2 ) {
368 return; /* No polygons - ignore */
369 }
370 memcpy( poly_context, ta_status.poly_context, ta_status.poly_context_size * 4 );
372 /* Compute the tile coordinates for each vertex (need to be careful with
373 * clamping here)
374 */
375 for( i=0; i<ta_status.vertex_count; i++ ) {
376 if( ta_status.poly_vertex[i].x < 0.0 ) {
377 tx[i] = -1;
378 } else if( ta_status.poly_vertex[i].x > (float)INT_MAX ) {
379 tx[i] = INT_MAX/32;
380 } else {
381 tx[i] = (int)(ta_status.poly_vertex[i].x / 32.0);
382 }
383 if( ta_status.poly_vertex[i].y < 0.0 ) {
384 ty[i] = -1;
385 } else if( ta_status.poly_vertex[i].y > (float)INT_MAX ) {
386 ty[i] = INT_MAX/32;
387 } else {
388 ty[i] = (int)(ta_status.poly_vertex[i].y / 32.0);
389 }
391 }
393 /* Compute bounding box for each triangle individually, as well
394 * as the overall polygon.
395 */
397 for( i=0; i<ta_status.vertex_count-2; i++ ) {
398 triangle_bound[i].x1 = MIN3(tx[i],tx[i+1],tx[i+2]);
399 triangle_bound[i].x2 = MAX3(tx[i],tx[i+1],tx[i+2]);
400 triangle_bound[i].y1 = MIN3(ty[i],ty[i+1],ty[i+2]);
401 triangle_bound[i].y2 = MAX3(ty[i],ty[i+1],ty[i+2]);
402 if( i == 0 ) {
403 polygon_bound.x1 = triangle_bound[0].x1;
404 polygon_bound.y1 = triangle_bound[0].y1;
405 polygon_bound.x2 = triangle_bound[0].x2;
406 polygon_bound.y2 = triangle_bound[0].y2;
407 } else {
408 polygon_bound.x1 = MIN(polygon_bound.x1, triangle_bound[i].x1);
409 polygon_bound.x2 = MAX(polygon_bound.x2, triangle_bound[i].x2);
410 polygon_bound.y1 = MIN(polygon_bound.y1, triangle_bound[i].y1);
411 polygon_bound.y2 = MAX(polygon_bound.y2, triangle_bound[i].y2);
412 }
413 }
415 /* If the polygon is actually entirely out of the frustum, clip it entirely */
416 if( polygon_bound.x2 < 0 || polygon_bound.x1 > ta_status.width ||
417 polygon_bound.y2 < 0 || polygon_bound.y1 > ta_status.height ) {
418 return;
419 }
421 /* Clamp the polygon bounds to the frustum */
422 if( polygon_bound.x1 < 0 ) polygon_bound.x1 = 0;
423 if( polygon_bound.x2 >= ta_status.width ) polygon_bound.x2 = ta_status.width-1;
424 if( polygon_bound.y1 < 0 ) polygon_bound.y1 = 0;
425 if( polygon_bound.y2 >= ta_status.width ) polygon_bound.y2 = ta_status.height-1;
427 /* Set the "single tile" flag if it's entirely contained in 1 tile */
428 if( polygon_bound.x1 == polygon_bound.x2 &&
429 polygon_bound.y1 == polygon_bound.y2 ) {
430 poly_context[0] |= 0x00200000;
431 }
433 /* Ok, we're good to go - write out the polygon first */
434 uint32_t tile_entry = MMIO_READ( PVR2, TA_POLYPOS ) >> 2 | ta_status.poly_pointer;
436 int status = ta_write_polygon_buffer( poly_context, ta_status.poly_context_size );
437 if( status == 0 ) {
438 /* No memory available - abort */
439 return;
440 } else {
441 for( i=0; i<ta_status.vertex_count && status != 0; i++ ) {
442 status = ta_write_polygon_buffer( (uint32_t *)(&ta_status.poly_vertex[i]), 3 + ta_status.poly_vertex_size );
443 }
444 }
446 /* And now the tile entries. Triangles are different from everything else */
447 if( ta_status.vertex_count == 3 ) {
448 tile_entry |= 0x80000000;
449 for( y=polygon_bound.y1; y<=polygon_bound.y2; y++ ) {
450 for( x=polygon_bound.x1; x<=polygon_bound.x2; x++ ) {
451 ta_write_tile_entry( x,y,tile_entry );
452 }
453 }
454 ta_status.last_triangle_bounds.x1 = polygon_bound.x1;
455 ta_status.last_triangle_bounds.y1 = polygon_bound.y1;
456 ta_status.last_triangle_bounds.x2 = polygon_bound.x2;
457 ta_status.last_triangle_bounds.y2 = polygon_bound.y2;
458 } else if( ta_status.current_vertex_type == TA_VERTEX_SPRITE ||
459 ta_status.current_vertex_type == TA_VERTEX_TEX_SPRITE ) {
460 tile_entry |= 0xA0000000;
461 for( y=polygon_bound.y1; y<=polygon_bound.y2; y++ ) {
462 for( x=polygon_bound.x1; x<=polygon_bound.x2; x++ ) {
463 ta_write_tile_entry( x,y,tile_entry );
464 }
465 }
466 ta_status.last_triangle_bounds.x1 = polygon_bound.x1;
467 ta_status.last_triangle_bounds.y1 = polygon_bound.y1;
468 ta_status.last_triangle_bounds.x2 = polygon_bound.x2;
469 ta_status.last_triangle_bounds.y2 = polygon_bound.y2;
470 } else {
471 for( y=polygon_bound.y1; y<=polygon_bound.y2; y++ ) {
472 for( x=polygon_bound.x1; x<=polygon_bound.x2; x++ ) {
473 uint32_t entry = tile_entry;
474 for( i=0; i<ta_status.vertex_count-2; i++ ) {
475 if( triangle_bound[i].x1 <= x && triangle_bound[i].x2 >= x &&
476 triangle_bound[i].y1 <= y && triangle_bound[i].y2 >= y ) {
477 entry |= (0x40000000>>i);
478 }
479 }
480 ta_write_tile_entry( x, y, entry );
481 }
482 }
483 ta_status.last_triangle_bounds.x1 = -1;
484 }
485 }
487 /**
488 * Variant of ta_split_polygon called when vertex_count == max_vertex, but
489 * the client hasn't sent the LAST VERTEX flag. Commit the poly as normal
490 * first, then start a new poly with the first 2 vertexes taken from the
491 * current one.
492 */
493 static void ta_split_polygon() {
494 ta_commit_polygon();
495 if( TA_IS_NORMAL_POLY() ) {
496 /* This only applies to ordinary polys - Sprites + modifier lists are
497 * handled differently
498 */
499 if( ta_status.vertex_count == 3 ) {
500 /* Triangles use an odd/even scheme */
501 if( ta_status.poly_parity == 0 ) {
502 memcpy( &ta_status.poly_vertex[0], &ta_status.poly_vertex[2],
503 sizeof(struct pvr2_ta_vertex) );
504 ta_status.poly_parity = 1;
505 } else {
506 memcpy( &ta_status.poly_vertex[1], &ta_status.poly_vertex[2],
507 sizeof(struct pvr2_ta_vertex) );
508 ta_status.poly_parity = 0;
509 }
510 } else {
511 /* Everything else just uses the last 2 vertexes in order */
512 memcpy( &ta_status.poly_vertex[0], &ta_status.poly_vertex[ta_status.vertex_count-2],
513 sizeof(struct pvr2_ta_vertex)*2 );
514 ta_status.poly_parity = 0;
515 }
516 ta_status.vertex_count = 2;
517 } else {
518 ta_status.vertex_count = 0;
519 }
520 }
522 /**
523 * Parse the polygon context block and setup the internal state to receive
524 * vertexes.
525 * @param data 32 bytes of parameter data.
526 */
527 static void ta_parse_polygon_context( union ta_data *data ) {
528 int colourfmt = TA_POLYCMD_COLOURFMT(data[0].i);
529 ta_status.max_vertex = TA_POLYCMD_LENGTH(data[0].i);
530 ta_status.vertex_count = 0;
531 ta_status.poly_context[0] =
532 (data[1].i & 0xFC1FFFFF) | ((data[0].i & 0x0B) << 22);
533 ta_status.poly_context[1] = data[2].i;
534 ta_status.poly_context[3] = data[4].i;
535 ta_status.poly_parity = 0;
536 if( data[0].i & TA_POLYCMD_TEXTURED ) {
537 ta_status.current_vertex_type = data[0].i & 0x0D;
538 ta_status.poly_context[2] = data[3].i;
539 ta_status.poly_context[4] = data[5].i;
540 if( data[0].i & TA_POLYCMD_SPECULAR ) {
541 ta_status.poly_context[0] |= 0x01000000;
542 ta_status.poly_vertex_size = 4;
543 } else {
544 ta_status.poly_vertex_size = 3;
545 }
546 if( data[0].i & TA_POLYCMD_UV16 ) {
547 ta_status.poly_vertex_size--;
548 }
549 } else {
550 ta_status.current_vertex_type = 0;
551 ta_status.poly_vertex_size = 1;
552 ta_status.poly_context[2] = 0;
553 ta_status.poly_context[4] = 0;
554 }
556 ta_status.poly_pointer = (ta_status.poly_vertex_size << 21);
557 ta_status.poly_context_size = 3;
558 if( data[0].i & TA_POLYCMD_MODIFIED ) {
559 ta_status.poly_pointer |= 0x01000000;
560 if( data[0].i & TA_POLYCMD_FULLMOD ) {
561 ta_status.poly_context_size = 5;
562 ta_status.poly_vertex_size <<= 1;
563 ta_status.current_vertex_type |= 0x40;
564 /* Modified/float not supported - behaves as per last intensity */
565 if( colourfmt == TA_POLYCMD_COLOURFMT_FLOAT ) {
566 colourfmt = TA_POLYCMD_COLOURFMT_LASTINT;
567 }
568 }
569 }
571 if( colourfmt == TA_POLYCMD_COLOURFMT_INTENSITY ) {
572 if( TA_POLYCMD_IS_FULLMOD(data[0].i) ||
573 TA_POLYCMD_IS_SPECULAR(data[0].i) ) {
574 ta_status.state = STATE_EXPECT_POLY_BLOCK2;
575 } else {
576 ta_status.intensity1 =
577 parse_float_colour( data[4].f, data[5].f, data[6].f, data[7].f );
578 }
579 } else if( colourfmt == TA_POLYCMD_COLOURFMT_LASTINT ) {
580 colourfmt = TA_POLYCMD_COLOURFMT_INTENSITY;
581 }
583 ta_status.current_vertex_type |= colourfmt;
584 }
586 /**
587 * Parse the modifier volume context block and setup the internal state to
588 * receive modifier vertexes.
589 * @param data 32 bytes of parameter data.
590 */
591 static void ta_parse_modifier_context( union ta_data *data ) {
592 ta_status.current_vertex_type = TA_VERTEX_MOD_VOLUME;
593 ta_status.poly_vertex_size = 0;
594 ta_status.poly_context_size = 3;
595 ta_status.poly_context[0] = (data[1].i & 0xFC1FFFFF) |
596 ((data[0].i & 0x0B)<<22);
597 if( TA_POLYCMD_IS_SPECULAR(data[0].i) ) {
598 ta_status.poly_context[0] |= 0x01000000;
599 }
600 ta_status.poly_context[1] = 0;
601 ta_status.poly_context[2] = 0;
602 ta_status.vertex_count = 0;
603 ta_status.max_vertex = 3;
604 ta_status.poly_pointer = 0;
605 }
607 /**
608 * Parse the sprite context block and setup the internal state to receive
609 * vertexes.
610 * @param data 32 bytes of parameter data.
611 */
612 static void ta_parse_sprite_context( union ta_data *data ) {
613 ta_status.poly_context_size = 3;
614 ta_status.poly_context[0] = (data[1].i & 0xFC1FFFFF) |
615 ((data[0].i & 0x0B)<<22) | 0x00400000;
616 if( TA_POLYCMD_IS_SPECULAR(data[0].i) ) {
617 ta_status.poly_context[0] |= 0x01000000;
618 }
619 ta_status.poly_context[1] = data[2].i;
620 ta_status.poly_context[2] = data[3].i;
621 if( data[0].i & TA_POLYCMD_TEXTURED ) {
622 ta_status.poly_vertex_size = 2;
623 ta_status.poly_vertex[2].detail[1] = data[4].i;
624 ta_status.current_vertex_type = TA_VERTEX_TEX_SPRITE;
625 } else {
626 ta_status.poly_vertex_size = 1;
627 ta_status.poly_vertex[2].detail[0] = data[4].i;
628 ta_status.current_vertex_type = TA_VERTEX_SPRITE;
629 }
630 ta_status.vertex_count = 0;
631 ta_status.max_vertex = 4;
632 ta_status.poly_pointer = (ta_status.poly_vertex_size << 21);
633 }
635 /**
636 * Copy the last read vertex into all vertexes up to max_vertex. Used for
637 * Aborted polygons under some circumstances.
638 */
639 static void ta_fill_vertexes( ) {
640 int i;
641 for( i=ta_status.vertex_count; i<ta_status.max_vertex; i++ ) {
642 memcpy( &ta_status.poly_vertex[i], &ta_status.poly_vertex[ta_status.vertex_count-1],
643 sizeof( struct pvr2_ta_vertex ) );
644 }
645 ta_status.vertex_count = ta_status.max_vertex;
646 }
648 static void ta_parse_vertex( union ta_data *data ) {
649 struct pvr2_ta_vertex *vertex = &ta_status.poly_vertex[ta_status.vertex_count];
650 vertex->x = data[1].f;
651 vertex->y = data[2].f;
652 vertex->z = data[3].f;
654 switch( ta_status.current_vertex_type ) {
655 case TA_VERTEX_PACKED:
656 vertex->detail[0] = data[6].i;
657 break;
658 case TA_VERTEX_FLOAT:
659 vertex->detail[0] = parse_float_colour( data[4].f, data[5].f, data[6].f, data[7].f );
660 break;
661 case TA_VERTEX_INTENSITY:
662 vertex->detail[0] = parse_intensity_colour( ta_status.intensity1, data[6].f );
663 break;
665 case TA_VERTEX_TEX_SPEC_PACKED:
666 vertex->detail[3] = data[7].i; /* ARGB */
667 /* Fallthrough */
668 case TA_VERTEX_TEX_PACKED:
669 vertex->detail[0] = data[4].i; /* U */
670 vertex->detail[1] = data[5].i; /* V */
671 vertex->detail[2] = data[6].i; /* ARGB */
672 break;
673 case TA_VERTEX_TEX_UV16_SPEC_PACKED:
674 vertex->detail[2] = data[7].i; /* ARGB */
675 /* Fallthrough */
676 case TA_VERTEX_TEX_UV16_PACKED:
677 vertex->detail[0] = data[4].i; /* UV */
678 vertex->detail[1] = data[6].i; /* ARGB */
679 break;
681 case TA_VERTEX_TEX_FLOAT:
682 case TA_VERTEX_TEX_SPEC_FLOAT:
683 vertex->detail[0] = data[4].i; /* U */
684 vertex->detail[1] = data[5].i; /* UV */
685 ta_status.state = STATE_EXPECT_VERTEX_BLOCK2;
686 break;
687 case TA_VERTEX_TEX_UV16_FLOAT:
688 case TA_VERTEX_TEX_UV16_SPEC_FLOAT:
689 vertex->detail[0] = data[4].i; /* UV */
690 ta_status.state = STATE_EXPECT_VERTEX_BLOCK2;
691 break;
693 case TA_VERTEX_TEX_SPEC_INTENSITY:
694 vertex->detail[3] = parse_intensity_colour( ta_status.intensity2, data[7].f );
695 /* Fallthrough */
696 case TA_VERTEX_TEX_INTENSITY:
697 vertex->detail[0] = data[4].i; /* U */
698 vertex->detail[1] = data[5].i; /* V */
699 vertex->detail[2] = parse_intensity_colour( ta_status.intensity1, data[6].f );
700 break;
701 case TA_VERTEX_TEX_UV16_SPEC_INTENSITY:
702 vertex->detail[2] = parse_intensity_colour( ta_status.intensity2, data[7].f );
703 /* Fallthrough */
704 case TA_VERTEX_TEX_UV16_INTENSITY:
705 vertex->detail[0] = data[4].i; /* UV */
706 vertex->detail[1] = parse_intensity_colour( ta_status.intensity1, data[6].f );
707 break;
709 case TA_VERTEX_PACKED_MOD:
710 vertex->detail[0] = data[4].i; /* ARGB */
711 vertex->detail[1] = data[5].i; /* ARGB */
712 break;
713 case TA_VERTEX_INTENSITY_MOD:
714 vertex->detail[0] = parse_intensity_colour( ta_status.intensity1, data[4].f );
715 vertex->detail[1] = parse_intensity_colour( ta_status.intensity2, data[5].f );
716 break;
718 case TA_VERTEX_TEX_SPEC_PACKED_MOD:
719 vertex->detail[3] = data[7].i; /* ARGB0 */
720 /* Fallthrough */
721 case TA_VERTEX_TEX_PACKED_MOD:
722 vertex->detail[0] = data[4].i; /* U0 */
723 vertex->detail[1] = data[5].i; /* V0 */
724 vertex->detail[2] = data[6].i; /* ARGB0 */
725 ta_status.state = STATE_EXPECT_VERTEX_BLOCK2;
726 break;
727 case TA_VERTEX_TEX_UV16_SPEC_PACKED_MOD:
728 vertex->detail[2] = data[7].i; /* ARGB0 */
729 /* Fallthrough */
730 case TA_VERTEX_TEX_UV16_PACKED_MOD:
731 vertex->detail[0] = data[4].i; /* UV0 */
732 vertex->detail[1] = data[6].i; /* ARGB0 */
733 ta_status.state = STATE_EXPECT_VERTEX_BLOCK2;
734 break;
736 case TA_VERTEX_TEX_SPEC_INTENSITY_MOD:
737 vertex->detail[3] = parse_intensity_colour( ta_status.intensity1, data[7].f );
738 /* Fallthrough */
739 case TA_VERTEX_TEX_INTENSITY_MOD:
740 vertex->detail[0] = data[4].i; /* U0 */
741 vertex->detail[1] = data[5].i; /* V0 */
742 vertex->detail[2] = parse_intensity_colour( ta_status.intensity1, data[6].f );
743 ta_status.state = STATE_EXPECT_VERTEX_BLOCK2;
744 break;
745 case TA_VERTEX_TEX_UV16_SPEC_INTENSITY_MOD:
746 vertex->detail[2] = parse_intensity_colour( ta_status.intensity1, data[7].f );
747 /* Fallthrough */
748 case TA_VERTEX_TEX_UV16_INTENSITY_MOD:
749 vertex->detail[0] = data[4].i; /* UV0 */
750 vertex->detail[1] = parse_intensity_colour( ta_status.intensity1, data[6].f );
751 ta_status.state = STATE_EXPECT_VERTEX_BLOCK2;
752 break;
754 case TA_VERTEX_SPRITE:
755 case TA_VERTEX_TEX_SPRITE:
756 case TA_VERTEX_MOD_VOLUME:
757 vertex++;
758 vertex->x = data[4].f;
759 vertex->y = data[5].f;
760 vertex->z = data[6].f;
761 vertex++;
762 vertex->x = data[7].f;
763 ta_status.vertex_count += 2;
764 ta_status.state = STATE_EXPECT_VERTEX_BLOCK2;
765 break;
766 }
767 ta_status.vertex_count++;
768 }
770 static void ta_parse_vertex_block2( union ta_data *data ) {
771 struct pvr2_ta_vertex *vertex = &ta_status.poly_vertex[ta_status.vertex_count-1];
773 switch( ta_status.current_vertex_type ) {
774 case TA_VERTEX_TEX_SPEC_FLOAT:
775 vertex->detail[3] = parse_float_colour( data[4].f, data[5].f, data[6].f, data[7].f );
776 /* Fallthrough */
777 case TA_VERTEX_TEX_FLOAT:
778 vertex->detail[2] = parse_float_colour( data[0].f, data[1].f, data[2].f, data[3].f );
779 break;
780 case TA_VERTEX_TEX_UV16_SPEC_FLOAT:
781 vertex->detail[2] = parse_float_colour( data[4].f, data[5].f, data[6].f, data[7].f );
782 /* Fallthrough */
783 case TA_VERTEX_TEX_UV16_FLOAT:
784 vertex->detail[1] = parse_float_colour( data[0].f, data[1].f, data[2].f, data[3].f );
785 break;
786 case TA_VERTEX_TEX_PACKED_MOD:
787 vertex->detail[3] = data[0].i; /* U1 */
788 vertex->detail[4] = data[1].i; /* V1 */
789 vertex->detail[5] = data[2].i; /* ARGB1 */
790 break;
791 case TA_VERTEX_TEX_SPEC_PACKED_MOD:
792 vertex->detail[4] = data[0].i; /* U1 */
793 vertex->detail[5] = data[1].i; /* V1 */
794 vertex->detail[6] = data[2].i; /* ARGB1 */
795 vertex->detail[7] = data[3].i; /* ARGB1 */
796 break;
797 case TA_VERTEX_TEX_UV16_PACKED_MOD:
798 vertex->detail[2] = data[0].i; /* UV1 */
799 vertex->detail[3] = data[2].i; /* ARGB1 */
800 break;
801 case TA_VERTEX_TEX_UV16_SPEC_PACKED_MOD:
802 vertex->detail[3] = data[0].i; /* UV1 */
803 vertex->detail[4] = data[2].i; /* ARGB1 */
804 vertex->detail[5] = data[3].i; /* ARGB1 */
805 break;
807 case TA_VERTEX_TEX_INTENSITY_MOD:
808 vertex->detail[3] = data[0].i; /* U1 */
809 vertex->detail[4] = data[1].i; /* V1 */
810 vertex->detail[5] = parse_intensity_colour( ta_status.intensity2, data[2].f ); /* ARGB1 */
811 break;
812 case TA_VERTEX_TEX_SPEC_INTENSITY_MOD:
813 vertex->detail[4] = data[0].i; /* U1 */
814 vertex->detail[5] = data[1].i; /* V1 */
815 vertex->detail[6] = parse_intensity_colour( ta_status.intensity2, data[2].f ); /* ARGB1 */
816 vertex->detail[7] = parse_intensity_colour( ta_status.intensity2, data[3].f ); /* ARGB1 */
817 break;
818 case TA_VERTEX_TEX_UV16_INTENSITY_MOD:
819 vertex->detail[2] = data[0].i; /* UV1 */
820 vertex->detail[3] = parse_intensity_colour( ta_status.intensity2, data[2].f ); /* ARGB1 */
821 break;
822 case TA_VERTEX_TEX_UV16_SPEC_INTENSITY_MOD:
823 vertex->detail[3] = data[0].i; /* UV1 */
824 vertex->detail[4] = parse_intensity_colour( ta_status.intensity2, data[2].f ); /* ARGB1 */
825 vertex->detail[5] = parse_intensity_colour( ta_status.intensity2, data[3].f ); /* ARGB1 */
826 break;
828 case TA_VERTEX_SPRITE:
829 vertex->y = data[0].f;
830 vertex->z = data[1].f;
831 vertex++;
832 ta_status.vertex_count++;
833 vertex->x = data[2].f;
834 vertex->y = data[3].f;
835 vertex->z = 0;
836 vertex->detail[0] = 0;
837 ta_status.poly_vertex[0].detail[0] = 0;
838 ta_status.poly_vertex[1].detail[0] = 0;
839 break;
840 case TA_VERTEX_TEX_SPRITE:
841 vertex->y = data[0].f;
842 vertex->z = data[1].f;
843 vertex++;
844 ta_status.vertex_count++;
845 vertex->x = data[2].f;
846 vertex->y = data[3].f;
847 vertex->z = 0;
848 vertex->detail[0] = 0;
849 vertex->detail[1] = 0;
850 ta_status.poly_vertex[0].detail[0] = data[5].i;
851 ta_status.poly_vertex[0].detail[1] = 0;
852 ta_status.poly_vertex[1].detail[0] = data[6].i;
853 ta_status.poly_vertex[1].detail[1] = 0;
854 ta_status.poly_vertex[2].detail[0] = data[7].i;
855 break;
856 case TA_VERTEX_MOD_VOLUME:
857 vertex->y = data[0].f;
858 vertex->z = data[1].f;
859 break;
860 }
861 ta_status.state = STATE_IN_LIST;
862 }
864 /**
865 * Process 1 32-byte block of ta data
866 */
867 void pvr2_ta_process_block( char *input ) {
868 union ta_data *data = (union ta_data *)input;
870 switch( ta_status.state ) {
871 case STATE_ERROR:
872 /* Error raised - stop processing until reset */
873 return;
875 case STATE_EXPECT_POLY_BLOCK2:
876 /* This is always a pair of floating-point colours */
877 ta_status.intensity1 =
878 parse_float_colour( data[0].f, data[1].f, data[2].f, data[3].f );
879 ta_status.intensity2 =
880 parse_float_colour( data[4].f, data[5].f, data[6].f, data[7].f );
881 ta_status.state = STATE_IN_LIST;
882 break;
884 case STATE_EXPECT_VERTEX_BLOCK2:
885 ta_parse_vertex_block2( data );
886 if( ta_status.vertex_count == ta_status.max_vertex ) {
887 ta_split_polygon();
888 }
889 break;
891 case STATE_EXPECT_END_VERTEX_BLOCK2:
892 ta_parse_vertex_block2( data );
893 ta_commit_polygon();
894 ta_status.vertex_count = 0;
895 ta_status.poly_parity = 0;
897 case STATE_IN_LIST:
898 case STATE_IDLE:
899 switch( TA_CMD( data->i ) ) {
900 case TA_CMD_END_LIST:
901 ta_end_list();
902 break;
903 case TA_CMD_CLIP: /* TODO */
904 break;
905 case TA_CMD_POLYGON_CONTEXT:
906 if( ta_status.state == STATE_IDLE ) {
907 ta_init_list( TA_POLYCMD_LISTTYPE( data->i ) );
908 }
910 if( ta_status.vertex_count != 0 ) {
911 ta_fill_vertexes();
912 ta_commit_polygon();
913 }
915 if( TA_IS_MODIFIER_LIST( ta_status.current_list_type ) ) {
916 ta_parse_modifier_context(data);
917 } else {
918 ta_parse_polygon_context(data);
919 }
920 break;
921 case TA_CMD_SPRITE_CONTEXT:
922 if( ta_status.state == STATE_IDLE ) {
923 ta_init_list( TA_POLYCMD_LISTTYPE( data->i ) );
924 }
926 if( ta_status.vertex_count != 0 ) {
927 ta_fill_vertexes();
928 ta_commit_polygon();
929 }
931 ta_parse_sprite_context(data);
932 break;
933 case TA_CMD_VERTEX:
934 ta_parse_vertex(data);
936 if( ta_status.state == STATE_EXPECT_VERTEX_BLOCK2 ) {
937 if( TA_IS_END_VERTEX(data[0].i) ) {
938 ta_status.state = STATE_EXPECT_END_VERTEX_BLOCK2;
939 }
940 } else if( TA_IS_END_VERTEX(data->i) ) {
941 ta_commit_polygon();
942 ta_status.vertex_count = 0;
943 ta_status.poly_parity = 0;
944 } else if( ta_status.vertex_count == ta_status.max_vertex ) {
945 ta_split_polygon();
946 }
947 break;
948 }
949 break;
950 }
952 }
956 /**
957 * Write a block of data to the tile accelerator, adding the data to the
958 * current scene. We don't make any particular attempt to interpret the data
959 * at this stage, deferring that until render time.
960 *
961 * Currently copies the data verbatim to the vertex buffer, processing only
962 * far enough to generate the correct end-of-list events. Tile buffer is
963 * entirely ignored.
964 */
965 void pvr2_ta_write( char *buf, uint32_t length )
966 {
967 if( ta_status.debug_output ) {
968 fwrite_dump32( (uint32_t *)buf, length, stderr );
969 }
971 for( ; length >=32; length -= 32 ) {
972 pvr2_ta_process_block( buf );
973 buf += 32;
974 }
975 }
.