Search
lxdream.org :: lxdream/src/pvr2/rendcore.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/pvr2/rendcore.c
changeset 635:76c63aac3590
prev561:533f6b478071
author nkeynes
date Thu Feb 14 13:54:11 2008 +0000 (12 years ago)
branchlxdream-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 }
.