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