Search
lxdream.org :: lxdream/src/pvr2/rendcore.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/pvr2/rendcore.c
changeset 318:363935d31859
prev308:10a5b5475fb0
next319:5392aed6a982
author nkeynes
date Tue Jan 23 12:03:57 2007 +0000 (14 years ago)
permissions -rw-r--r--
last change Add initial offset color support
Honor the "enable fragment alpha" bit
view annotate diff log raw
     1 /**
     2  * $Id: rendcore.c,v 1.11 2007-01-23 12:03:57 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, GL_MODULATE, GL_DECAL, GL_MODULATE };
    35 int pvr2_render_colour_format[8] = {
    36     COLFMT_ARGB1555, COLFMT_RGB565, COLFMT_ARGB4444, COLFMT_ARGB1555,
    37     COLFMT_RGB888, COLFMT_ARGB8888, COLFMT_ARGB8888, COLFMT_ARGB4444 };
    40 #define CULL_NONE 0
    41 #define CULL_SMALL 1
    42 #define CULL_CCW 2
    43 #define CULL_CW 3
    45 #define SEGMENT_END         0x80000000
    46 #define SEGMENT_ZCLEAR      0x40000000
    47 #define SEGMENT_SORT_TRANS  0x20000000
    48 #define SEGMENT_START       0x10000000
    49 #define SEGMENT_X(c)        (((c) >> 2) & 0x3F)
    50 #define SEGMENT_Y(c)        (((c) >> 8) & 0x3F)
    51 #define NO_POINTER          0x80000000
    53 extern char *video_base;
    55 gboolean pvr2_force_fragment_alpha;
    57 struct tile_segment {
    58     uint32_t control;
    59     pvraddr_t opaque_ptr;
    60     pvraddr_t opaquemod_ptr;
    61     pvraddr_t trans_ptr;
    62     pvraddr_t transmod_ptr;
    63     pvraddr_t punchout_ptr;
    64 };
    66 /**
    67  * Convert a half-float (16-bit) FP number to a regular 32-bit float.
    68  * Source is 1-bit sign, 5-bit exponent, 10-bit mantissa.
    69  * TODO: Check the correctness of this.
    70  */
    71 float halftofloat( uint16_t half )
    72 {
    73     union {
    74         float f;
    75         uint32_t i;
    76     } temp;
    77     /* int e = ((half & 0x7C00) >> 10) - 15 + 127;
    79     temp.i = ((half & 0x8000) << 16) | (e << 23) |
    80     ((half & 0x03FF) << 13); */
    81     temp.i = ((uint32_t)half)<<16;
    82     return temp.f;
    83 }
    86 /**
    87  * Setup the GL context for the supplied polygon context.
    88  * @param context pointer to 3 or 5 words of polygon context
    89  * @param modified boolean flag indicating that the modified
    90  *  version should be used, rather than the normal version.
    91  */
    92 void render_set_context( uint32_t *context, int render_mode )
    93 {
    94     uint32_t poly1 = context[0], poly2, texture;
    95     if( render_mode == RENDER_FULLMOD ) {
    96 	poly2 = context[3];
    97 	texture = context[4];
    98     } else {
    99 	poly2 = context[1];
   100 	texture = context[2];
   101     }
   103     if( POLY1_DEPTH_ENABLE(poly1) ) {
   104 	glEnable( GL_DEPTH_TEST );
   105 	glDepthFunc( POLY1_DEPTH_MODE(poly1) );
   106     } else {
   107 	glDisable( GL_DEPTH_TEST );
   108     }
   110     switch( POLY1_CULL_MODE(poly1) ) {
   111     case CULL_NONE:
   112     case CULL_SMALL:
   113 	glDisable( GL_CULL_FACE );
   114 	break;
   115     case CULL_CCW:
   116 	glEnable( GL_CULL_FACE );
   117 	glFrontFace( GL_CW );
   118 	break;
   119     case CULL_CW:
   120 	glEnable( GL_CULL_FACE );
   121 	glFrontFace( GL_CCW );
   122 	break;
   123     }
   125     if( POLY1_SPECULAR(poly1) ) {
   126 	glEnable(GL_COLOR_SUM);
   127     } else {
   128 	glDisable(GL_COLOR_SUM);
   129     }
   131     if( POLY1_TEXTURED(poly1) ) {
   132 	int width = POLY2_TEX_WIDTH(poly2);
   133 	int height = POLY2_TEX_HEIGHT(poly2);
   134 	glEnable(GL_TEXTURE_2D);
   135 	texcache_get_texture( (texture&0x000FFFFF)<<3, width, height, texture );
   136 	glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, POLY2_TEX_BLEND(poly2) );
   137 	if( POLY2_TEX_CLAMP_U(poly2) ) {
   138 	    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
   139 	} else {
   140 	    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
   141 	}	    
   142 	if( POLY2_TEX_CLAMP_V(poly2) ) {
   143 	    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
   144 	} else {
   145 	    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
   146 	}
   147     } else {
   148 	glDisable( GL_TEXTURE_2D );
   149     }
   151     glShadeModel( POLY1_SHADE_MODEL(poly1) );
   153     int srcblend = POLY2_SRC_BLEND(poly2);
   154     int destblend = POLY2_DEST_BLEND(poly2);
   155     glBlendFunc( srcblend, destblend );
   157     pvr2_force_fragment_alpha = POLY2_ALPHA_ENABLE(poly2) ? FALSE : TRUE;
   159 }
   161 void render_vertexes( uint32_t poly1, uint32_t *vertexes, int num_vertexes, int vertex_size,
   162 		      int render_mode ) 
   163 {
   164     int i, m=0;
   166     if( render_mode == RENDER_FULLMOD ) {
   167 	m = (vertex_size - 3)/2;
   168     }
   170     glBegin( GL_TRIANGLE_STRIP );
   172     for( i=0; i<num_vertexes; i++ ) {
   173 	float *vertexf = (float *)vertexes;
   174 	uint32_t argb;
   175 	int k = m + 3;
   176 	if( POLY1_TEXTURED(poly1) ) {
   177 	    if( POLY1_UV16(poly1) ) {
   178 		glTexCoord2f( halftofloat(vertexes[k]>>16),
   179 			      halftofloat(vertexes[k]) );
   180 		k++;
   181 	    } else {
   182 		glTexCoord2f( vertexf[k], vertexf[k+1] );
   183 		k+=2;
   184 	    }
   185 	}
   187 	argb = vertexes[k++];
   188 	if( pvr2_force_fragment_alpha ) {
   189 	    glColor4ub( (GLubyte)(argb >> 16), (GLubyte)(argb >> 8), 
   190 			(GLubyte)argb, 0xFF );
   191 	} else {
   192 	    glColor4ub( (GLubyte)(argb >> 16), (GLubyte)(argb >> 8), 
   193 			(GLubyte)argb, (GLubyte)(argb >> 24) );
   194 	}
   196 	if( POLY1_SPECULAR(poly1) ) {
   197 	    uint32_t spec = vertexes[k++];
   198 	    glSecondaryColor3ubEXT( (GLubyte)(spec >> 16), (GLubyte)(spec >> 8), 
   199 				 (GLubyte)spec );
   200 	}
   201 	glVertex3f( vertexf[0], vertexf[1], vertexf[2] );
   202 	vertexes += vertex_size;
   203     }
   205     glEnd();
   206 }
   208 /**
   209  * Render a simple (not auto-sorted) tile
   210  */
   211 void render_tile( pvraddr_t tile_entry, int render_mode, gboolean cheap_modifier_mode ) {
   212     uint32_t poly_bank = MMIO_READ(PVR2,RENDER_POLYBASE);
   213     uint32_t *tile_list = (uint32_t *)(video_base+tile_entry);
   214     do {
   215 	uint32_t entry = *tile_list++;
   216 	if( entry >> 28 == 0x0F ) {
   217 	    break;
   218 	} else if( entry >> 28 == 0x0E ) {
   219 	    tile_list = (uint32_t *)(video_base + (entry&0x007FFFFF));
   220 	} else {
   221 	    uint32_t *polygon = (uint32_t *)(video_base + poly_bank + ((entry & 0x000FFFFF) << 2));
   222 	    int is_modified = entry & 0x01000000;
   223 	    int vertex_length = (entry >> 21) & 0x07;
   224 	    int context_length = 3;
   225 	    if( is_modified && !cheap_modifier_mode ) {
   226 		context_length = 5;
   227 		vertex_length *= 2 ;
   228 	    }
   229 	    vertex_length += 3;
   231 	    if( (entry & 0xE0000000) == 0x80000000 ) {
   232 		/* Triangle(s) */
   233 		int strip_count = ((entry >> 25) & 0x0F)+1;
   234 		int polygon_length = 3 * vertex_length + context_length;
   235 		int i;
   236 		for( i=0; i<strip_count; i++ ) {
   237 		    render_set_context( polygon, render_mode );
   238 		    render_vertexes( *polygon, polygon+context_length, 3, vertex_length,
   239 				     render_mode );
   240 		    polygon += polygon_length;
   241 		}
   242 	    } else if( (entry & 0xE0000000) == 0xA0000000 ) {
   243 		/* Sprite(s) */
   244 		int strip_count = (entry >> 25) & 0x0F;
   245 		int polygon_length = 4 * vertex_length + context_length;
   246 		int i;
   247 		for( i=0; i<strip_count; i++ ) {
   248 		    render_set_context( polygon, render_mode );
   249 		    render_vertexes( *polygon, polygon+context_length, 4, vertex_length,
   250 				     render_mode );
   251 		    polygon += polygon_length;
   252 		}
   253 	    } else {
   254 		/* Polygon */
   255 		int i, first=-1, last = -1;
   256 		for( i=0; i<6; i++ ) {
   257 		    if( entry & (0x40000000>>i) ) {
   258 			if( first == -1 ) first = i;
   259 			last = i;
   260 		    }
   261 		}
   262 		if( first != -1 ) {
   263 		    first = 0;
   264 		    render_set_context(polygon, render_mode);
   265 		    render_vertexes( *polygon, polygon+context_length + (first*vertex_length),
   266 				     (last-first+3), vertex_length, render_mode );
   267 		}
   268 	    }
   269 	}
   270     } while( 1 );
   271 }
   273 void pvr2_render_tilebuffer( int width, int height, int clipx1, int clipy1, 
   274 			int clipx2, int clipy2 ) {
   276     pvraddr_t segmentbase = MMIO_READ( PVR2, RENDER_TILEBASE );
   277     int tile_sort;
   278     gboolean cheap_shadow;
   280     int obj_config = MMIO_READ( PVR2, RENDER_OBJCFG );
   281     int isp_config = MMIO_READ( PVR2, RENDER_ISPCFG );
   282     int shadow_cfg = MMIO_READ( PVR2, RENDER_SHADOW );
   284     if( (obj_config & 0x00200000) == 0 ) {
   285 	if( isp_config & 1 ) {
   286 	    tile_sort = 0;
   287 	} else {
   288 	    tile_sort = 2;
   289 	}
   290     } else {
   291 	tile_sort = 1;
   292     }
   294     cheap_shadow = shadow_cfg & 0x100 ? TRUE : FALSE;
   296     struct tile_segment *segment = (struct tile_segment *)(video_base + segmentbase);
   298     struct timeval tv_start, tv_end;
   299     gettimeofday(&tv_start, NULL);
   300     glEnable( GL_SCISSOR_TEST );
   301     do {
   302 	// fwrite_dump32v( (uint32_t *)segment, sizeof(struct tile_segment), 6, stderr );
   303 	int tilex = SEGMENT_X(segment->control);
   304 	int tiley = SEGMENT_Y(segment->control);
   306 	int x1 = tilex << 5;
   307 	int y1 = tiley << 5;
   308 	if( x1 + 32 <= clipx1 ||
   309 	    y1 + 32 <= clipy1 ||
   310 	    x1 >= clipx2 ||
   311 	    y1 >= clipy2 ) {
   312 	    /* Tile completely clipped, skip */
   313 	    continue;
   314 	}
   316 	/* Set a scissor on the visible part of the tile */
   317 	int w = MIN(x1+32, clipx2) - x1;
   318 	int h = MIN(y1+32, clipy2) - y1;
   319 	x1 = MAX(x1,clipx1);
   320 	y1 = MAX(y1,clipy1);
   321 	glScissor( x1, height-y1-h, w, h );
   323 	if( (segment->opaque_ptr & NO_POINTER) == 0 ) {
   324 	    if( (segment->opaquemod_ptr & NO_POINTER) == 0 ) {
   325 		/* TODO */
   326 	    }
   327 	    render_tile( segment->opaque_ptr, RENDER_NORMAL, cheap_shadow );
   328 	}
   330 	if( (segment->trans_ptr & NO_POINTER) == 0 ) {
   331 	    if( (segment->transmod_ptr & NO_POINTER) == 0 ) {
   332 		/* TODO */
   333 	    } 
   334 	    if( tile_sort == 2 || 
   335 		(tile_sort == 1 && ((segment->control & SEGMENT_SORT_TRANS)==0)) ) {
   336 		render_autosort_tile( segment->trans_ptr, RENDER_NORMAL, cheap_shadow );
   337 	    } else {
   338 		render_tile( segment->trans_ptr, RENDER_NORMAL, cheap_shadow );
   339 	    }
   340 	}
   342 	if( (segment->punchout_ptr & NO_POINTER) == 0 ) {
   343 	    render_tile( segment->punchout_ptr, RENDER_NORMAL, cheap_shadow );
   344 	}
   345     } while( ((segment++)->control & SEGMENT_END) == 0 );
   346     glDisable( GL_SCISSOR_TEST );
   348     gettimeofday(&tv_end, NULL);
   349     timersub(&tv_end,&tv_start, &tv_start);
   350 }
.