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