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