filename | src/pvr2/rendcore.c |
changeset | 341:924029ff95ea |
prev | 338:8c68d9097846 |
next | 350:5852da948231 |
author | nkeynes |
date | Mon Feb 05 08:52:59 2007 +0000 (17 years ago) |
permissions | -rw-r--r-- |
last change | Fix compressed mipmap textures (byte count was wrong) Change internal gl format to the simple versions - let the implementation use whatever's most efficient |
view | annotate | diff | log | raw |
1 /**
2 * $Id: rendcore.c,v 1.16 2007-01-31 10:32:25 nkeynes Exp $
3 *
4 * PVR2 renderer core.
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 <sys/time.h>
19 #include "pvr2/pvr2.h"
20 #include "asic.h"
22 int pvr2_poly_depthmode[8] = { GL_NEVER, GL_LESS, GL_EQUAL, GL_LEQUAL,
23 GL_GREATER, GL_NOTEQUAL, GL_GEQUAL,
24 GL_ALWAYS };
25 int pvr2_poly_srcblend[8] = {
26 GL_ZERO, GL_ONE, GL_DST_COLOR, GL_ONE_MINUS_DST_COLOR,
27 GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_DST_ALPHA,
28 GL_ONE_MINUS_DST_ALPHA };
29 int pvr2_poly_dstblend[8] = {
30 GL_ZERO, GL_ONE, GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR,
31 GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_DST_ALPHA,
32 GL_ONE_MINUS_DST_ALPHA };
33 int pvr2_poly_texblend[4] = {
34 GL_REPLACE,
35 GL_MODULATE,
36 GL_DECAL,
37 GL_MODULATE
38 };
39 int pvr2_render_colour_format[8] = {
40 COLFMT_ARGB1555, COLFMT_RGB565, COLFMT_ARGB4444, COLFMT_ARGB1555,
41 COLFMT_RGB888, COLFMT_ARGB8888, COLFMT_ARGB8888, COLFMT_ARGB4444 };
44 #define CULL_NONE 0
45 #define CULL_SMALL 1
46 #define CULL_CCW 2
47 #define CULL_CW 3
49 #define SEGMENT_END 0x80000000
50 #define SEGMENT_ZCLEAR 0x40000000
51 #define SEGMENT_SORT_TRANS 0x20000000
52 #define SEGMENT_START 0x10000000
53 #define SEGMENT_X(c) (((c) >> 2) & 0x3F)
54 #define SEGMENT_Y(c) (((c) >> 8) & 0x3F)
55 #define NO_POINTER 0x80000000
57 extern char *video_base;
59 gboolean pvr2_force_fragment_alpha = FALSE;
60 gboolean pvr2_debug_render = FALSE;
62 struct tile_segment {
63 uint32_t control;
64 pvraddr_t opaque_ptr;
65 pvraddr_t opaquemod_ptr;
66 pvraddr_t trans_ptr;
67 pvraddr_t transmod_ptr;
68 pvraddr_t punchout_ptr;
69 };
71 void render_print_tilelist( FILE *f, uint32_t tile_entry );
73 /**
74 * Convert a half-float (16-bit) FP number to a regular 32-bit float.
75 * Source is 1-bit sign, 5-bit exponent, 10-bit mantissa.
76 * TODO: Check the correctness of this.
77 */
78 float halftofloat( uint16_t half )
79 {
80 union {
81 float f;
82 uint32_t i;
83 } temp;
84 /* int e = ((half & 0x7C00) >> 10) - 15 + 127;
86 temp.i = ((half & 0x8000) << 16) | (e << 23) |
87 ((half & 0x03FF) << 13); */
88 temp.i = ((uint32_t)half)<<16;
89 return temp.f;
90 }
93 /**
94 * Setup the GL context for the supplied polygon context.
95 * @param context pointer to 3 or 5 words of polygon context
96 * @param modified boolean flag indicating that the modified
97 * version should be used, rather than the normal version.
98 */
99 void render_set_context( uint32_t *context, int render_mode )
100 {
101 uint32_t poly1 = context[0], poly2, texture;
102 if( render_mode == RENDER_FULLMOD ) {
103 poly2 = context[3];
104 texture = context[4];
105 } else {
106 poly2 = context[1];
107 texture = context[2];
108 }
110 if( POLY1_DEPTH_ENABLE(poly1) ) {
111 glEnable( GL_DEPTH_TEST );
112 glDepthFunc( POLY1_DEPTH_MODE(poly1) );
113 } else {
114 glDisable( GL_DEPTH_TEST );
115 }
117 switch( POLY1_CULL_MODE(poly1) ) {
118 case CULL_NONE:
119 case CULL_SMALL:
120 glDisable( GL_CULL_FACE );
121 break;
122 case CULL_CCW:
123 glEnable( GL_CULL_FACE );
124 glFrontFace( GL_CW );
125 break;
126 case CULL_CW:
127 glEnable( GL_CULL_FACE );
128 glFrontFace( GL_CCW );
129 break;
130 }
132 if( POLY1_SPECULAR(poly1) ) {
133 glEnable(GL_COLOR_SUM);
134 } else {
135 glDisable(GL_COLOR_SUM);
136 }
138 pvr2_force_fragment_alpha = POLY2_ALPHA_ENABLE(poly2) ? FALSE : TRUE;
140 if( POLY1_TEXTURED(poly1) ) {
141 int width = POLY2_TEX_WIDTH(poly2);
142 int height = POLY2_TEX_HEIGHT(poly2);
143 glEnable(GL_TEXTURE_2D);
144 texcache_get_texture( (texture&0x000FFFFF)<<3, width, height, texture );
145 switch( POLY2_TEX_BLEND(poly2) ) {
146 case 0: /* Replace */
147 glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
148 break;
149 case 2:/* Decal */
150 glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL );
151 break;
152 case 1: /* Modulate RGB */
153 /* This is not directly supported by opengl (other than by mucking
154 * with the texture format), but we get the same effect by forcing
155 * the fragment alpha to 1.0 and using GL_MODULATE.
156 */
157 pvr2_force_fragment_alpha = TRUE;
158 case 3: /* Modulate RGBA */
159 glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
160 break;
161 }
162 glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, POLY2_TEX_BLEND(poly2) );
163 if( POLY2_TEX_CLAMP_U(poly2) ) {
164 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
165 } else {
166 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
167 }
168 if( POLY2_TEX_CLAMP_V(poly2) ) {
169 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
170 } else {
171 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
172 }
173 } else {
174 glDisable( GL_TEXTURE_2D );
175 }
177 glShadeModel( POLY1_SHADE_MODEL(poly1) );
179 int srcblend = POLY2_SRC_BLEND(poly2);
180 int destblend = POLY2_DEST_BLEND(poly2);
181 glBlendFunc( srcblend, destblend );
183 if( POLY2_SRC_BLEND_TARGET(poly2) || POLY2_DEST_BLEND_TARGET(poly2) ) {
184 ERROR( "Accumulation buffer not supported" );
185 }
188 }
190 #define FARGB_A(x) (((float)(((x)>>24)+1))/256.0)
191 #define FARGB_R(x) (((float)((((x)>>16)&0xFF)+1))/256.0)
192 #define FARGB_G(x) (((float)((((x)>>8)&0xFF)+1))/256.0)
193 #define FARGB_B(x) (((float)(((x)&0xFF)+1))/256.0)
195 void render_unpack_vertexes( struct vertex_unpacked *out, uint32_t poly1,
196 uint32_t *vertexes, int num_vertexes,
197 int vertex_size, int render_mode )
198 {
199 int m = 0, i;
200 if( render_mode == RENDER_FULLMOD ) {
201 m = (vertex_size - 3)/2;
202 }
204 for( i=0; i<num_vertexes; i++ ) {
205 float *vertexf = (float *)vertexes;
206 int k = m + 3;
207 out[i].x = vertexf[0];
208 out[i].y = vertexf[1];
209 out[i].z = vertexf[2];
210 if( POLY1_TEXTURED(poly1) ) {
211 if( POLY1_UV16(poly1) ) {
212 out[i].u = halftofloat(vertexes[k]>>16);
213 out[i].v = halftofloat(vertexes[k]);
214 k++;
215 } else {
216 out[i].u = vertexf[k];
217 out[i].v = vertexf[k+1];
218 k+=2;
219 }
220 } else {
221 out[i].u = 0;
222 out[i].v = 0;
223 }
224 uint32_t argb = vertexes[k++];
225 out[i].rgba[0] = FARGB_R(argb);
226 out[i].rgba[1] = FARGB_G(argb);
227 out[i].rgba[2] = FARGB_B(argb);
228 out[i].rgba[3] = FARGB_A(argb);
229 if( POLY1_SPECULAR(poly1) ) {
230 uint32_t offset = vertexes[k++];
231 out[i].offset_rgba[0] = FARGB_R(argb);
232 out[i].offset_rgba[1] = FARGB_G(argb);
233 out[i].offset_rgba[2] = FARGB_B(argb);
234 out[i].offset_rgba[3] = FARGB_A(argb);
235 }
236 vertexes += vertex_size;
237 }
238 }
240 /**
241 * Unpack the vertexes for a quad, calculating the values for the last
242 * vertex.
243 * FIXME: Integrate this with rendbkg somehow
244 */
245 void render_unpack_quad( struct vertex_unpacked *unpacked, uint32_t poly1,
246 uint32_t *vertexes, int vertex_size,
247 int render_mode )
248 {
249 int i;
250 struct vertex_unpacked diff0, diff1;
252 render_unpack_vertexes( unpacked, poly1, vertexes, 3, vertex_size, render_mode );
254 diff0.x = unpacked[0].x - unpacked[1].x;
255 diff0.y = unpacked[0].y - unpacked[1].y;
256 diff1.x = unpacked[2].x - unpacked[1].x;
257 diff1.y = unpacked[2].y - unpacked[1].y;
259 float detxy = ((diff1.y) * (diff0.x)) - ((diff0.y) * (diff1.x));
260 float *vertexf = (float *)(vertexes+(vertex_size*3));
261 if( detxy == 0 ) {
262 memcpy( &unpacked[3], &unpacked[2], sizeof(struct vertex_unpacked) );
263 unpacked[3].x = vertexf[0];
264 unpacked[3].y = vertexf[1];
265 return;
266 }
268 unpacked[3].x = vertexf[0];
269 unpacked[3].y = vertexf[1];
270 float t = ((unpacked[3].x - unpacked[1].x) * diff1.y -
271 (unpacked[3].y - unpacked[1].y) * diff1.x) / detxy;
272 float s = ((unpacked[3].y - unpacked[1].y) * diff0.x -
273 (unpacked[3].x - unpacked[1].x) * diff0.y) / detxy;
274 diff0.z = (1/unpacked[0].z) - (1/unpacked[1].z);
275 diff1.z = (1/unpacked[2].z) - (1/unpacked[1].z);
276 unpacked[3].z = 1/((1/unpacked[1].z) + (t*diff0.z) + (s*diff1.z));
278 diff0.u = unpacked[0].u - unpacked[1].u;
279 diff0.v = unpacked[0].v - unpacked[1].v;
280 diff1.u = unpacked[2].u - unpacked[1].u;
281 diff1.v = unpacked[2].v - unpacked[1].v;
282 unpacked[3].u = unpacked[1].u + (t*diff0.u) + (s*diff1.u);
283 unpacked[3].v = unpacked[1].v + (t*diff0.v) + (s*diff1.v);
285 if( !POLY1_GOURAUD_SHADED(poly1) ) {
286 memcpy( unpacked[3].rgba, unpacked[2].rgba, sizeof(unpacked[2].rgba) );
287 memcpy( unpacked[3].offset_rgba, unpacked[2].offset_rgba, sizeof(unpacked[2].offset_rgba) );
288 } else {
289 for( i=0; i<4; i++ ) {
290 float d0 = unpacked[0].rgba[i] - unpacked[1].rgba[i];
291 float d1 = unpacked[2].rgba[i] - unpacked[1].rgba[i];
292 unpacked[3].rgba[i] = unpacked[1].rgba[i] + (t*d0) + (s*d1);
293 d0 = unpacked[0].offset_rgba[i] - unpacked[1].offset_rgba[i];
294 d1 = unpacked[2].offset_rgba[i] - unpacked[1].offset_rgba[i];
295 unpacked[3].offset_rgba[i] = unpacked[1].offset_rgba[i] + (t*d0) + (s*d1);
296 }
297 }
298 }
300 void render_unpacked_vertex_array( uint32_t poly1, struct vertex_unpacked *vertexes[],
301 int num_vertexes ) {
302 int i;
304 glBegin( GL_TRIANGLE_STRIP );
306 for( i=0; i<num_vertexes; i++ ) {
307 if( POLY1_TEXTURED(poly1) ) {
308 glTexCoord2f( vertexes[i]->u, vertexes[i]->v );
309 }
311 if( pvr2_force_fragment_alpha ) {
312 glColor4f( vertexes[i]->rgba[0], vertexes[i]->rgba[1], vertexes[i]->rgba[2], 1.0 );
313 } else {
314 glColor4f( vertexes[i]->rgba[0], vertexes[i]->rgba[1], vertexes[i]->rgba[2],
315 vertexes[i]->rgba[3] );
316 }
317 if( POLY1_SPECULAR(poly1) ) {
318 glSecondaryColor3fEXT( vertexes[i]->offset_rgba[0],
319 vertexes[i]->offset_rgba[1],
320 vertexes[i]->offset_rgba[2] );
321 }
322 glVertex3f( vertexes[i]->x, vertexes[i]->y, 1/vertexes[i]->z );
323 }
325 glEnd();
326 }
328 void render_quad_vertexes( uint32_t poly1, uint32_t *vertexes, int vertex_size, int render_mode )
329 {
330 struct vertex_unpacked unpacked[4];
331 struct vertex_unpacked *pt[4] = {&unpacked[0], &unpacked[1], &unpacked[3], &unpacked[2]};
332 render_unpack_quad( unpacked, poly1, vertexes, vertex_size, render_mode );
333 render_unpacked_vertex_array( poly1, pt, 4 );
334 }
336 void render_vertex_array( uint32_t poly1, uint32_t *vert_array[], int num_vertexes, int vertex_size,
337 int render_mode )
338 {
339 int i, m=0;
341 if( render_mode == RENDER_FULLMOD ) {
342 m = (vertex_size - 3)/2;
343 }
345 glBegin( GL_TRIANGLE_STRIP );
347 for( i=0; i<num_vertexes; i++ ) {
348 uint32_t *vertexes = vert_array[i];
349 float *vertexf = (float *)vert_array[i];
350 uint32_t argb;
351 int k = m + 3;
352 if( POLY1_TEXTURED(poly1) ) {
353 if( POLY1_UV16(poly1) ) {
354 glTexCoord2f( halftofloat(vertexes[k]>>16),
355 halftofloat(vertexes[k]) );
356 k++;
357 } else {
358 glTexCoord2f( vertexf[k], vertexf[k+1] );
359 k+=2;
360 }
361 }
363 argb = vertexes[k++];
364 if( pvr2_force_fragment_alpha ) {
365 glColor4ub( (GLubyte)(argb >> 16), (GLubyte)(argb >> 8),
366 (GLubyte)argb, 0xFF );
367 } else {
368 glColor4ub( (GLubyte)(argb >> 16), (GLubyte)(argb >> 8),
369 (GLubyte)argb, (GLubyte)(argb >> 24) );
370 }
372 if( POLY1_SPECULAR(poly1) ) {
373 uint32_t spec = vertexes[k++];
374 glSecondaryColor3ubEXT( (GLubyte)(spec >> 16), (GLubyte)(spec >> 8),
375 (GLubyte)spec );
376 }
377 glVertex3f( vertexf[0], vertexf[1], 1/vertexf[2] );
378 vertexes += vertex_size;
379 }
381 glEnd();
382 }
384 void render_vertexes( uint32_t poly1, uint32_t *vertexes, int num_vertexes, int vertex_size,
385 int render_mode )
386 {
387 uint32_t *vert_array[num_vertexes];
388 int i;
389 for( i=0; i<num_vertexes; i++ ) {
390 vert_array[i] = vertexes;
391 vertexes += vertex_size;
392 }
393 render_vertex_array( poly1, vert_array, num_vertexes, vertex_size, render_mode );
394 }
396 /**
397 * Render a simple (not auto-sorted) tile
398 */
399 void render_tile( pvraddr_t tile_entry, int render_mode, gboolean cheap_modifier_mode ) {
400 uint32_t poly_bank = MMIO_READ(PVR2,RENDER_POLYBASE);
401 uint32_t *tile_list = (uint32_t *)(video_base+tile_entry);
402 do {
403 uint32_t entry = *tile_list++;
404 if( entry >> 28 == 0x0F ) {
405 break;
406 } else if( entry >> 28 == 0x0E ) {
407 tile_list = (uint32_t *)(video_base + (entry&0x007FFFFF));
408 } else {
409 uint32_t *polygon = (uint32_t *)(video_base + poly_bank + ((entry & 0x000FFFFF) << 2));
410 int is_modified = entry & 0x01000000;
411 int vertex_length = (entry >> 21) & 0x07;
412 int context_length = 3;
413 if( is_modified && !cheap_modifier_mode ) {
414 context_length = 5;
415 vertex_length *= 2 ;
416 }
417 vertex_length += 3;
419 if( (entry & 0xE0000000) == 0x80000000 ) {
420 /* Triangle(s) */
421 int strip_count = ((entry >> 25) & 0x0F)+1;
422 int polygon_length = 3 * vertex_length + context_length;
423 int i;
424 for( i=0; i<strip_count; i++ ) {
425 render_set_context( polygon, render_mode );
426 render_vertexes( *polygon, polygon+context_length, 3, vertex_length,
427 render_mode );
428 polygon += polygon_length;
429 }
430 } else if( (entry & 0xE0000000) == 0xA0000000 ) {
431 /* Sprite(s) */
432 int strip_count = ((entry >> 25) & 0x0F)+1;
433 int polygon_length = 4 * vertex_length + context_length;
434 int i;
435 for( i=0; i<strip_count; i++ ) {
436 render_set_context( polygon, render_mode );
437 render_quad_vertexes( *polygon, polygon+context_length, vertex_length,
438 render_mode );
439 polygon += polygon_length;
440 }
441 } else {
442 /* Polygon */
443 int i, first=-1, last = -1;
444 for( i=0; i<6; i++ ) {
445 if( entry & (0x40000000>>i) ) {
446 if( first == -1 ) first = i;
447 last = i;
448 }
449 }
450 if( first != -1 ) {
451 first = 0;
452 render_set_context(polygon, render_mode);
453 render_vertexes( *polygon, polygon+context_length + (first*vertex_length),
454 (last-first+3), vertex_length, render_mode );
455 }
456 }
457 }
458 } while( 1 );
459 }
461 void pvr2_render_tilebuffer( int width, int height, int clipx1, int clipy1,
462 int clipx2, int clipy2 ) {
464 pvraddr_t segmentbase = MMIO_READ( PVR2, RENDER_TILEBASE );
465 int tile_sort;
466 gboolean cheap_shadow;
468 int obj_config = MMIO_READ( PVR2, RENDER_OBJCFG );
469 int isp_config = MMIO_READ( PVR2, RENDER_ISPCFG );
470 int shadow_cfg = MMIO_READ( PVR2, RENDER_SHADOW );
472 if( (obj_config & 0x00200000) == 0 ) {
473 if( isp_config & 1 ) {
474 tile_sort = 0;
475 } else {
476 tile_sort = 2;
477 }
478 } else {
479 tile_sort = 1;
480 }
482 cheap_shadow = shadow_cfg & 0x100 ? TRUE : FALSE;
484 struct tile_segment *segment = (struct tile_segment *)(video_base + segmentbase);
486 struct timeval tv_start, tv_end;
487 gettimeofday(&tv_start, NULL);
488 glEnable( GL_SCISSOR_TEST );
489 do {
490 // fwrite_dump32v( (uint32_t *)segment, sizeof(struct tile_segment), 6, stderr );
491 int tilex = SEGMENT_X(segment->control);
492 int tiley = SEGMENT_Y(segment->control);
494 int x1 = tilex << 5;
495 int y1 = tiley << 5;
496 if( x1 + 32 <= clipx1 ||
497 y1 + 32 <= clipy1 ||
498 x1 >= clipx2 ||
499 y1 >= clipy2 ) {
500 /* Tile completely clipped, skip */
501 continue;
502 }
504 /* Set a scissor on the visible part of the tile */
505 int w = MIN(x1+32, clipx2) - x1;
506 int h = MIN(y1+32, clipy2) - y1;
507 x1 = MAX(x1,clipx1);
508 y1 = MAX(y1,clipy1);
509 glScissor( x1, height-y1-h, w, h );
511 if( (segment->opaque_ptr & NO_POINTER) == 0 ) {
512 if( pvr2_debug_render ) {
513 fprintf( stderr, "Tile %d,%d Opaque\n", tilex, tiley );
514 render_print_tilelist( stderr, segment->opaque_ptr );
515 }
516 if( (segment->opaquemod_ptr & NO_POINTER) == 0 ) {
517 /* TODO */
518 }
519 render_tile( segment->opaque_ptr, RENDER_NORMAL, cheap_shadow );
520 }
522 if( (segment->trans_ptr & NO_POINTER) == 0 ) {
523 if( pvr2_debug_render ) {
524 fprintf( stderr, "Tile %d,%d Trans\n", tilex, tiley );
525 render_print_tilelist( stderr, segment->trans_ptr );
526 }
527 if( (segment->transmod_ptr & NO_POINTER) == 0 ) {
528 /* TODO */
529 }
530 if( tile_sort == 2 ||
531 (tile_sort == 1 && ((segment->control & SEGMENT_SORT_TRANS)==0)) ) {
532 render_autosort_tile( segment->trans_ptr, RENDER_NORMAL, cheap_shadow );
533 } else {
534 render_tile( segment->trans_ptr, RENDER_NORMAL, cheap_shadow );
535 }
536 }
538 if( (segment->punchout_ptr & NO_POINTER) == 0 ) {
539 if( pvr2_debug_render ) {
540 fprintf( stderr, "Tile %d,%d Punchout\n", tilex, tiley );
541 render_print_tilelist( stderr, segment->punchout_ptr );
542 }
543 render_tile( segment->punchout_ptr, RENDER_NORMAL, cheap_shadow );
544 }
545 } while( ((segment++)->control & SEGMENT_END) == 0 );
546 glDisable( GL_SCISSOR_TEST );
548 gettimeofday(&tv_end, NULL);
549 timersub(&tv_end,&tv_start, &tv_start);
550 }
552 static float render_find_maximum_tile_z( pvraddr_t tile_entry, float inputz )
553 {
554 uint32_t poly_bank = MMIO_READ(PVR2,RENDER_POLYBASE);
555 uint32_t *tile_list = (uint32_t *)(video_base+tile_entry);
556 int shadow_cfg = MMIO_READ( PVR2, RENDER_SHADOW ) & 0x100;
557 int i, j;
558 float z = inputz;
559 do {
560 uint32_t entry = *tile_list++;
561 if( entry >> 28 == 0x0F ) {
562 break;
563 } else if( entry >> 28 == 0x0E ) {
564 tile_list = (uint32_t *)(video_base + (entry&0x007FFFFF));
565 } else {
566 uint32_t *polygon = (uint32_t *)(video_base + poly_bank + ((entry & 0x000FFFFF) << 2));
567 int is_modified = entry & 0x01000000;
568 int vertex_length = (entry >> 21) & 0x07;
569 int context_length = 3;
570 if( (entry & 0x01000000) && shadow_cfg ) {
571 context_length = 5;
572 vertex_length *= 2 ;
573 }
574 vertex_length += 3;
575 if( (entry & 0xE0000000) == 0x80000000 ) {
576 /* Triangle(s) */
577 int strip_count = ((entry >> 25) & 0x0F)+1;
578 float *vertexz = (float *)(polygon+context_length+2);
579 for( i=0; i<strip_count; i++ ) {
580 for( j=0; j<3; j++ ) {
581 if( *vertexz > z ) {
582 z = *vertexz;
583 }
584 vertexz += vertex_length;
585 }
586 vertexz += context_length;
587 }
588 } else if( (entry & 0xE0000000) == 0xA0000000 ) {
589 /* Sprite(s) */
590 int strip_count = ((entry >> 25) & 0x0F)+1;
591 int polygon_length = 4 * vertex_length + context_length;
592 int i;
593 float *vertexz = (float *)(polygon+context_length+2);
594 for( i=0; i<strip_count; i++ ) {
595 for( j=0; j<4; j++ ) {
596 if( *vertexz > z ) {
597 z = *vertexz;
598 }
599 vertexz += vertex_length;
600 }
601 vertexz+=context_length;
602 }
603 } else {
604 /* Polygon */
605 int i, first=-1, last = -1;
606 float *vertexz = (float *)polygon+context_length+2;
607 for( i=0; i<6; i++ ) {
608 if( (entry & (0x40000000>>i)) && *vertexz > z ) {
609 z = *vertexz;
610 }
611 vertexz += vertex_length;
612 }
613 }
614 }
615 } while(1);
616 return z;
617 }
619 /**
620 * Scan through the scene to determine the largest z value (in order to set up
621 * an appropriate near clip plane).
622 */
623 float pvr2_render_find_maximum_z( )
624 {
625 pvraddr_t segmentbase = MMIO_READ( PVR2, RENDER_TILEBASE );
626 float maximumz = MMIO_READF( PVR2, RENDER_FARCLIP ); /* Initialize to the far clip plane */
628 struct tile_segment *segment = (struct tile_segment *)(video_base + segmentbase);
629 do {
631 if( (segment->opaque_ptr & NO_POINTER) == 0 ) {
632 maximumz = render_find_maximum_tile_z(segment->opaque_ptr, maximumz);
633 }
634 if( (segment->opaquemod_ptr & NO_POINTER) == 0 ) {
635 maximumz = render_find_maximum_tile_z(segment->opaquemod_ptr, maximumz);
636 }
637 if( (segment->trans_ptr & NO_POINTER) == 0 ) {
638 maximumz = render_find_maximum_tile_z(segment->trans_ptr, maximumz);
639 }
640 if( (segment->transmod_ptr & NO_POINTER) == 0 ) {
641 maximumz = render_find_maximum_tile_z(segment->transmod_ptr, maximumz);
642 }
643 if( (segment->punchout_ptr & NO_POINTER) == 0 ) {
644 maximumz = render_find_maximum_tile_z(segment->punchout_ptr, maximumz);
645 }
647 } while( ((segment++)->control & SEGMENT_END) == 0 );
649 return 1/maximumz;
650 }
652 /**
653 * Scan the segment info to determine the width and height of the render (in
654 * pixels).
655 * @param x,y output values to receive the width and height info.
656 */
657 void pvr2_render_getsize( int *x, int *y )
658 {
659 pvraddr_t segmentbase = MMIO_READ( PVR2, RENDER_TILEBASE );
660 int maxx = 0, maxy = 0;
662 struct tile_segment *segment = (struct tile_segment *)(video_base + segmentbase);
663 do {
664 int tilex = SEGMENT_X(segment->control);
665 int tiley = SEGMENT_Y(segment->control);
666 if( tilex > maxx ) {
667 maxx = tilex;
668 }
669 if( tiley > maxy ) {
670 maxy = tiley;
671 }
672 } while( ((segment++)->control & SEGMENT_END) == 0 );
674 *x = (maxx+1)<<5;
675 *y = (maxy+1)<<5;
676 }
678 void render_print_vertexes( FILE *f, uint32_t poly1, uint32_t *vert_array[],
679 int num_vertexes, int vertex_size )
680 {
681 char buf[256], *p;
682 int i,j, k;
683 for( i=0; i<num_vertexes; i++ ) {
684 p = buf;
685 float *vertf = (float *)vert_array[i];
686 uint32_t *verti = (uint32_t *)vert_array[i];
687 p += sprintf( p, " V %9.5f,%9.5f,%9.5f ", vertf[0], vertf[1], vertf[2] );
688 k = 3;
689 if( POLY1_TEXTURED(poly1) ) {
690 if( POLY1_UV16(poly1) ) {
691 p += sprintf( p, "uv=%9.5f,%9.5f ",
692 halftofloat(verti[k]>>16),
693 halftofloat(verti[k]) );
694 k++;
695 } else {
696 p += sprintf( p, "uv=%9.5f,%9.5f ", vertf[k], vertf[k+1] );
697 k+=2;
698 }
699 }
701 p += sprintf( p, "%08X ", verti[k++] );
702 if( POLY1_SPECULAR(poly1) ) {
703 p += sprintf( p, "%08X", verti[k++] );
704 }
705 p += sprintf( p, "\n" );
706 fprintf( f, buf );
707 }
708 }
710 void render_print_polygon( FILE *f, uint32_t entry )
711 {
712 uint32_t poly_bank = MMIO_READ(PVR2,RENDER_POLYBASE);
713 int shadow_cfg = MMIO_READ( PVR2, RENDER_SHADOW ) & 0x100;
714 int i, j;
716 if( entry >> 28 == 0x0F ) {
717 fprintf( f, "EOT\n" );
718 } else if( entry >> 28 == 0x0E ) {
719 fprintf( f, "LINK %08X\n", entry &0x7FFFFF );
720 } else {
721 uint32_t *polygon = (uint32_t *)(video_base + poly_bank + ((entry & 0x000FFFFF) << 2));
722 int is_modified = entry & 0x01000000;
723 int vertex_length = (entry >> 21) & 0x07;
724 int context_length = 3;
725 if( (entry & 0x01000000) && shadow_cfg ) {
726 context_length = 5;
727 vertex_length *= 2 ;
728 }
729 vertex_length += 3;
730 if( (entry & 0xE0000000) == 0x80000000 ) {
731 /* Triangle(s) */
732 int strip_count = ((entry >> 25) & 0x0F)+1;
733 for( i=0; i<strip_count; i++ ) {
734 fprintf( f, "TRI %08X %08X %08X\n", polygon[0], polygon[1], polygon[2] );
735 uint32_t *array[3];
736 array[0] = polygon + context_length;
737 array[1] = array[0] + vertex_length;
738 array[2] = array[1] + vertex_length;
739 render_print_vertexes( f, *polygon, array, 3, vertex_length );
740 polygon = array[2] + vertex_length;
741 }
742 } else if( (entry & 0xE0000000) == 0xA0000000 ) {
743 /* Sprite(s) */
744 int strip_count = ((entry >> 25) & 0x0F)+1;
745 for( i=0; i<strip_count; i++ ) {
746 fprintf( f, "QUAD %08X %08X %08X\n", polygon[0], polygon[1], polygon[2] );
747 uint32_t *array[4];
748 array[0] = polygon + context_length;
749 array[1] = array[0] + vertex_length;
750 array[2] = array[1] + vertex_length;
751 array[3] = array[2] + vertex_length;
752 render_print_vertexes( f, *polygon, array, 4, vertex_length );
753 polygon = array[3] + vertex_length;
754 }
755 } else {
756 /* Polygon */
757 int last = -1;
758 float *vertexz = (float *)polygon+context_length+2;
759 uint32_t *array[8];
760 for( i=0; i<6; i++ ) {
761 if( entry & (0x40000000>>i) ) {
762 last = i;
763 }
764 }
765 fprintf( f, "POLY %08X %08X %08X\n", polygon[0], polygon[1], polygon[2] );
766 for( i=0; i<last+2; i++ ) {
767 array[i] = polygon + context_length + vertex_length*i;
768 }
769 render_print_vertexes( f, *polygon, array, last+2, vertex_length );
770 }
771 }
772 }
774 void render_print_tilelist( FILE *f, uint32_t tile_entry )
775 {
776 uint32_t *tile_list = (uint32_t *)(video_base+tile_entry);
777 do {
778 uint32_t entry = *tile_list++;
779 if( entry >> 28 == 0x0F ) {
780 break;
781 } else if( entry >> 28 == 0x0E ) {
782 tile_list = (uint32_t *)(video_base + (entry&0x007FFFFF));
783 } else {
784 render_print_polygon(f, entry);
785 }
786 } while( 1 );
787 }
.