Search
lxdream.org :: lxdream/src/pvr2/rendcore.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/pvr2/rendcore.c
changeset 191:df4441cf3128
prev189:615b70cfd729
next215:f432833e8303
author nkeynes
date Sun Aug 06 09:43:03 2006 +0000 (17 years ago)
permissions -rw-r--r--
last change Add alignment checks
view annotate diff log raw
     1 /**
     2  * $Id: rendcore.c,v 1.2 2006-08-02 06:24:08 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 "pvr2/pvr2.h"
    19 #include "asic.h"
    21 static int pvr2_poly_depthmode[8] = { GL_NEVER, GL_LESS, GL_EQUAL, GL_LEQUAL,
    22 				      GL_GREATER, GL_NOTEQUAL, GL_GEQUAL, 
    23 				      GL_ALWAYS };
    24 static int pvr2_poly_srcblend[8] = { 
    25     GL_ZERO, GL_ONE, GL_DST_COLOR, GL_ONE_MINUS_DST_COLOR,
    26     GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_DST_ALPHA, 
    27     GL_ONE_MINUS_DST_ALPHA };
    28 static int pvr2_poly_dstblend[8] = {
    29     GL_ZERO, GL_ONE, GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR,
    30     GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_DST_ALPHA,
    31     GL_ONE_MINUS_DST_ALPHA };
    32 static int pvr2_poly_texblend[4] = {
    33     GL_REPLACE, GL_BLEND, GL_DECAL, GL_MODULATE };
    34 static int pvr2_render_colour_format[8] = {
    35     COLFMT_ARGB1555, COLFMT_RGB565, COLFMT_ARGB4444, COLFMT_ARGB1555,
    36     COLFMT_RGB888, COLFMT_ARGB8888, COLFMT_ARGB8888, COLFMT_ARGB4444 };
    37 #define POLY1_DEPTH_MODE(poly1) ( pvr2_poly_depthmode[(poly1)>>29] )
    38 #define POLY1_DEPTH_ENABLE(poly1) (((poly1)&0x04000000) == 0 )
    39 #define POLY1_CULL_MODE(poly1) (((poly1)>>27)&0x03)
    40 #define POLY1_TEXTURED(poly1) (((poly1)&0x02000000))
    41 #define POLY1_SPECULAR(poly1) (((poly1)&0x01000000))
    42 #define POLY1_SHADE_MODEL(poly1) (((poly1)&0x00800000) ? GL_SMOOTH : GL_FLAT)
    43 #define POLY1_UV16(poly1)   (((poly1)&0x00400000))
    44 #define POLY1_SINGLE_TILE(poly1) (((poly1)&0x00200000))
    46 #define POLY2_SRC_BLEND(poly2) ( pvr2_poly_srcblend[(poly2) >> 29] )
    47 #define POLY2_DEST_BLEND(poly2) ( pvr2_poly_dstblend[((poly2)>>26)&0x07] )
    48 #define POLY2_SRC_BLEND_ENABLE(poly2) ((poly2)&0x02000000)
    49 #define POLY2_DEST_BLEND_ENABLE(poly2) ((poly2)&0x01000000)
    50 #define POLY2_COLOUR_CLAMP_ENABLE(poly2) ((poly2)&0x00200000)
    51 #define POLY2_ALPHA_ENABLE(poly2) ((poly2)&0x001000000)
    52 #define POLY2_TEX_ALPHA_ENABLE(poly2) (((poly2)&0x00080000) == 0 )
    53 #define POLY2_TEX_WIDTH(poly2) ( 1<< ((((poly2) >> 3) & 0x07 ) + 3) )
    54 #define POLY2_TEX_HEIGHT(poly2) ( 1<< (((poly2) & 0x07 ) + 3) )
    55 #define POLY2_TEX_BLEND(poly2) ( pvr2_poly_texblend[((poly2) >> 6)&0x03] )
    57 #define RENDER_ZONLY  0
    58 #define RENDER_NORMAL 1     /* Render non-modified polygons */
    59 #define RENDER_CHEAPMOD 2   /* Render cheap-modified polygons */
    60 #define RENDER_FULLMOD 3    /* Render the fully-modified version of the polygons */
    62 #define CULL_NONE 0
    63 #define CULL_SMALL 1
    64 #define CULL_CCW 2
    65 #define CULL_CW 3
    67 #define SEGMENT_END         0x80000000
    68 #define SEGMENT_SORT_TRANS  0x20000000
    69 #define SEGMENT_START       0x10000000
    70 #define SEGMENT_X(c)        (((c) >> 2) & 0x3F)
    71 #define SEGMENT_Y(c)        (((c) >> 8) & 0x3F)
    72 #define NO_POINTER          0x80000000
    74 extern char *video_base;
    76 struct tile_segment {
    77     uint32_t control;
    78     pvraddr_t opaque_ptr;
    79     pvraddr_t opaquemod_ptr;
    80     pvraddr_t trans_ptr;
    81     pvraddr_t transmod_ptr;
    82     pvraddr_t punchout_ptr;
    83 };
    85 /**
    86  * Convert a half-float (16-bit) FP number to a regular 32-bit float.
    87  * Source is 1-bit sign, 5-bit exponent, 10-bit mantissa.
    88  * TODO: Check the correctness of this.
    89  */
    90 float halftofloat( uint16_t half )
    91 {
    92     union {
    93         float f;
    94         uint32_t i;
    95     } temp;
    96     int e = ((half & 0x7C00) >> 10) - 15 + 127;
    98     temp.i = ((half & 0x8000) << 16) | (e << 23) |
    99              ((half & 0x03FF) << 13);
   100     return temp.f;
   101 }
   104 /**
   105  * Setup the GL context for the supplied polygon context.
   106  * @param context pointer to 3 or 5 words of polygon context
   107  * @param modified boolean flag indicating that the modified
   108  *  version should be used, rather than the normal version.
   109  */
   110 void render_set_context( uint32_t *context, int render_mode )
   111 {
   112     uint32_t poly1 = context[0], poly2, texture;
   113     if( render_mode == RENDER_FULLMOD ) {
   114 	poly2 = context[3];
   115 	texture = context[4];
   116     } else {
   117 	poly2 = context[1];
   118 	texture = context[2];
   119     }
   121     if( POLY1_DEPTH_ENABLE(poly1) ) {
   122 	glEnable( GL_DEPTH_TEST );
   123 	glDepthFunc( POLY1_DEPTH_MODE(poly1) );
   124     } else {
   125 	glDisable( GL_DEPTH_TEST );
   126     }
   128     switch( POLY1_CULL_MODE(poly1) ) {
   129     case CULL_NONE:
   130     case CULL_SMALL:
   131 	glDisable( GL_CULL_FACE );
   132 	break;
   133     case CULL_CCW:
   134 	glEnable( GL_CULL_FACE );
   135 	glFrontFace( GL_CW );
   136 	break;
   137     case CULL_CW:
   138 	glEnable( GL_CULL_FACE );
   139 	glFrontFace( GL_CCW );
   140 	break;
   141     }
   143     if( POLY1_TEXTURED(poly1) ) {
   144 	int width = POLY2_TEX_WIDTH(poly2);
   145 	int height = POLY2_TEX_HEIGHT(poly2);
   146 	glEnable(GL_TEXTURE_2D);
   147 	texcache_get_texture( (texture&0x001FFFFF)<<3, width, height, texture );
   148 	glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, POLY2_TEX_BLEND(poly2) );
   149     } else {
   150 	glDisable( GL_TEXTURE_2D );
   151     }
   153     glShadeModel( POLY1_SHADE_MODEL(poly1) );
   155     glBlendFunc( POLY2_SRC_BLEND(poly2), POLY2_DEST_BLEND(poly2) );
   156     if( POLY2_TEX_ALPHA_ENABLE(poly2) ) {
   157 	glEnable(GL_BLEND);
   158     } else {
   159 	glDisable(GL_BLEND);
   160     }
   161 }
   163 void render_vertexes( uint32_t poly1, uint32_t *vertexes, int num_vertexes, int vertex_size,
   164 		      int render_mode ) 
   165 {
   166     int i, m=0;
   168     if( render_mode == RENDER_FULLMOD ) {
   169 	m = (vertex_size - 3)/2;
   170     }
   172     glBegin( GL_TRIANGLE_STRIP );
   174     for( i=0; i<num_vertexes; i++ ) {
   175 	float *vertexf = (float *)vertexes;
   176 	uint32_t argb;
   177 	if( POLY1_TEXTURED(poly1) ) {
   178 	    if( POLY1_UV16(poly1) ) {
   179 		glTexCoord2f( halftofloat(vertexes[m+3]>>16),
   180 			      halftofloat(vertexes[m+3]) );
   181 		argb = vertexes[m+4];
   182 	    } else {
   183 		glTexCoord2f( vertexf[m+3], vertexf[m+4] );
   184 		argb = vertexes[m+5];
   185 	    }
   186 	} else {
   187 	    argb = vertexes[m+3];
   188 	}
   190 	glColor4ub( (GLubyte)(argb >> 16), (GLubyte)(argb >> 8), 
   191 		    (GLubyte)argb, (GLubyte)(argb >> 24) );
   192 	glVertex3f( vertexf[0], vertexf[1], vertexf[2] );
   193 	vertexes += vertex_size;
   194     }
   196     glEnd();
   197 }
   199 /**
   200  * Render a simple (not auto-sorted) tile
   201  */
   202 void render_tile( pvraddr_t tile_entry, int render_mode, gboolean cheap_modifier_mode ) {
   204     uint32_t *tile_list = (uint32_t *)(video_base+tile_entry);
   205     do {
   206 	uint32_t entry = *tile_list++;
   207 	if( entry >> 28 == 0x0F ) {
   208 	    break;
   209 	} else if( entry >> 28 == 0x0E ) {
   210 	    tile_list = (uint32_t *)(video_base + (entry&0x007FFFFF));
   211 	} else {
   212 	    uint32_t *polygon = (uint32_t *)(video_base + ((entry & 0x001FFFFF) << 2));
   213 	    int is_modified = entry & 0x01000000;
   214 	    int vertex_length = (entry >> 21) & 0x07;
   215 	    int context_length = 3;
   216 	    if( is_modified && !cheap_modifier_mode ) {
   217 		context_length = 5;
   218 		vertex_length *= 2 ;
   219 	    }
   220 	    vertex_length += 3;
   222 	    if( (entry & 0xE0000000) == 0x80000000 ) {
   223 		/* Triangle(s) */
   224 		int strip_count = ((entry >> 25) & 0x0F)+1;
   225 		int polygon_length = 3 * vertex_length + context_length;
   226 		int i;
   227 		for( i=0; i<strip_count; i++ ) {
   228 		    render_set_context( polygon, render_mode );
   229 		    render_vertexes( *polygon, polygon+context_length, 3, vertex_length,
   230 				     render_mode );
   231 		    polygon += polygon_length;
   232 		}
   233 	    } else if( (entry & 0xE0000000) == 0xA0000000 ) {
   234 		/* Sprite(s) */
   235 		int strip_count = (entry >> 25) & 0x0F;
   236 		int polygon_length = 4 * vertex_length + context_length;
   237 		int i;
   238 		for( i=0; i<strip_count; i++ ) {
   239 		    render_set_context( polygon, render_mode );
   240 		    render_vertexes( *polygon, polygon+context_length, 4, vertex_length,
   241 				     render_mode );
   242 		    polygon += polygon_length;
   243 		}
   244 	    } else {
   245 		/* Polygon */
   246 		int i, first=-1, last = -1;
   247 		for( i=0; i<6; i++ ) {
   248 		    if( entry & (0x40000000>>i) ) {
   249 			if( first == -1 ) first = i;
   250 			last = i;
   251 		    }
   252 		}
   253 		if( first != -1 ) {
   254 		    first = 0;
   255 		    render_set_context(polygon, render_mode);
   256 		    render_vertexes( *polygon, polygon+context_length + (first*vertex_length),
   257 				     (last-first+3), vertex_length, render_mode );
   258 		}
   259 	    }
   260 	}
   261     } while( 1 );
   262 }
   264 void render_autosort_tile( pvraddr_t tile_entry, int render_mode, gboolean cheap_modifier_mode ) {
   265     //WARN( "Autosort not implemented yet" );
   266     render_tile( tile_entry, render_mode, cheap_modifier_mode );
   267 }
   269 void pvr2_render_tilebuffer( int width, int height, int clipx1, int clipy1, 
   270 			int clipx2, int clipy2 ) {
   272     pvraddr_t segmentbase = MMIO_READ( PVR2, RENDER_TILEBASE );
   273     int tile_sort;
   274     gboolean cheap_shadow;
   276     int obj_config = MMIO_READ( PVR2, RENDER_OBJCFG );
   277     int isp_config = MMIO_READ( PVR2, RENDER_ISPCFG );
   278     int shadow_cfg = MMIO_READ( PVR2, RENDER_SHADOW );
   280     if( obj_config & 0x00200000 ) {
   281 	if( isp_config & 1 ) {
   282 	    tile_sort = 0;
   283 	} else {
   284 	    tile_sort = 2;
   285 	}
   286     } else {
   287 	tile_sort = 1;
   288     }
   290     cheap_shadow = shadow_cfg & 0x100 ? TRUE : FALSE;
   292     struct tile_segment *segment = (struct tile_segment *)(video_base + segmentbase);
   294     glEnable( GL_SCISSOR_TEST );
   295     while( (segment->control & SEGMENT_END) == 0 ) {
   296 	int tilex = SEGMENT_X(segment->control);
   297 	int tiley = SEGMENT_Y(segment->control);
   299 	int x1 = tilex << 5;
   300 	int y1 = tiley << 5;
   301 	if( x1 + 32 <= clipx1 ||
   302 	    y1 + 32 <= clipy1 ||
   303 	    x1 >= clipx2 ||
   304 	    y1 >= clipy2 ) {
   305 	    /* Tile completely clipped, skip */
   306 	    segment++;
   307 	    continue;
   308 	}
   310 	/* Set a scissor on the visible part of the tile */
   311 	int w = MIN(x1+32, clipx2) - x1;
   312 	int h = MIN(y1+32, clipy2) - y1;
   313 	x1 = MAX(x1,clipx1);
   314 	y1 = MAX(y1,clipy1);
   315 	glScissor( x1, height-y1-h, w, h );
   317 	if( (segment->opaque_ptr & NO_POINTER) == 0 ) {
   318 	    if( (segment->opaquemod_ptr & NO_POINTER) == 0 ) {
   319 		/* TODO */
   320 	    }
   321 	    render_tile( segment->opaque_ptr, RENDER_NORMAL, cheap_shadow );
   322 	}
   324 	if( (segment->trans_ptr & NO_POINTER) == 0 ) {
   325 	    if( (segment->transmod_ptr & NO_POINTER) == 0 ) {
   326 		/* TODO */
   327 	    } 
   328 	    if( tile_sort == 2 || (tile_sort == 1 && (segment->control & SEGMENT_SORT_TRANS)) ) {
   329 		render_autosort_tile( segment->trans_ptr, RENDER_NORMAL, cheap_shadow );
   330 	    } else {
   331 		render_tile( segment->trans_ptr, RENDER_NORMAL, cheap_shadow );
   332 	    }
   333 	}
   335 	if( (segment->punchout_ptr & NO_POINTER) == 0 ) {
   336 	    render_tile( segment->punchout_ptr, RENDER_NORMAL, cheap_shadow );
   337 	}
   338 	segment++;
   339     }
   340     glDisable( GL_SCISSOR_TEST );
   341 }
.