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