Search
lxdream.org :: lxdream/src/pvr2/rendcore.c :: diff
lxdream 0.9.1
released Jun 29
Download Now
filename src/pvr2/rendcore.c
changeset 189:615b70cfd729
next191:df4441cf3128
author nkeynes
date Wed Aug 02 04:06:45 2006 +0000 (13 years ago)
permissions -rw-r--r--
last change Issue 0003: TA Vertex compiler
Initial implementation of the TA.
Renderer hooked up to the TA "properly" now as well
file annotate diff log raw
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/src/pvr2/rendcore.c Wed Aug 02 04:06:45 2006 +0000
1.3 @@ -0,0 +1,341 @@
1.4 +/**
1.5 + * $Id: rendcore.c,v 1.1 2006-08-02 04:06:45 nkeynes Exp $
1.6 + *
1.7 + * PVR2 renderer core.
1.8 + *
1.9 + * Copyright (c) 2005 Nathan Keynes.
1.10 + *
1.11 + * This program is free software; you can redistribute it and/or modify
1.12 + * it under the terms of the GNU General Public License as published by
1.13 + * the Free Software Foundation; either version 2 of the License, or
1.14 + * (at your option) any later version.
1.15 + *
1.16 + * This program is distributed in the hope that it will be useful,
1.17 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.18 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.19 + * GNU General Public License for more details.
1.20 + */
1.21 +#include "pvr2/pvr2.h"
1.22 +#include "asic.h"
1.23 +
1.24 +static int pvr2_poly_depthmode[8] = { GL_NEVER, GL_LESS, GL_EQUAL, GL_LEQUAL,
1.25 + GL_GREATER, GL_NOTEQUAL, GL_GEQUAL,
1.26 + GL_ALWAYS };
1.27 +static int pvr2_poly_srcblend[8] = {
1.28 + GL_ZERO, GL_ONE, GL_DST_COLOR, GL_ONE_MINUS_DST_COLOR,
1.29 + GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_DST_ALPHA,
1.30 + GL_ONE_MINUS_DST_ALPHA };
1.31 +static int pvr2_poly_dstblend[8] = {
1.32 + GL_ZERO, GL_ONE, GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR,
1.33 + GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_DST_ALPHA,
1.34 + GL_ONE_MINUS_DST_ALPHA };
1.35 +static int pvr2_poly_texblend[4] = {
1.36 + GL_REPLACE, GL_BLEND, GL_DECAL, GL_MODULATE };
1.37 +static int pvr2_render_colour_format[8] = {
1.38 + COLFMT_ARGB1555, COLFMT_RGB565, COLFMT_ARGB4444, COLFMT_ARGB1555,
1.39 + COLFMT_RGB888, COLFMT_ARGB8888, COLFMT_ARGB8888, COLFMT_ARGB4444 };
1.40 +#define POLY1_DEPTH_MODE(poly1) ( pvr2_poly_depthmode[(poly1)>>29] )
1.41 +#define POLY1_DEPTH_ENABLE(poly1) (((poly1)&0x04000000) == 0 )
1.42 +#define POLY1_CULL_MODE(poly1) (((poly1)>>27)&0x03)
1.43 +#define POLY1_TEXTURED(poly1) (((poly1)&0x02000000))
1.44 +#define POLY1_SPECULAR(poly1) (((poly1)&0x01000000))
1.45 +#define POLY1_SHADE_MODEL(poly1) (((poly1)&0x00800000) ? GL_SMOOTH : GL_FLAT)
1.46 +#define POLY1_UV16(poly1) (((poly1)&0x00400000))
1.47 +#define POLY1_SINGLE_TILE(poly1) (((poly1)&0x00200000))
1.48 +
1.49 +#define POLY2_SRC_BLEND(poly2) ( pvr2_poly_srcblend[(poly2) >> 29] )
1.50 +#define POLY2_DEST_BLEND(poly2) ( pvr2_poly_dstblend[((poly2)>>26)&0x07] )
1.51 +#define POLY2_SRC_BLEND_ENABLE(poly2) ((poly2)&0x02000000)
1.52 +#define POLY2_DEST_BLEND_ENABLE(poly2) ((poly2)&0x01000000)
1.53 +#define POLY2_COLOUR_CLAMP_ENABLE(poly2) ((poly2)&0x00200000)
1.54 +#define POLY2_ALPHA_ENABLE(poly2) ((poly2)&0x001000000)
1.55 +#define POLY2_TEX_ALPHA_ENABLE(poly2) (((poly2)&0x00080000) == 0 )
1.56 +#define POLY2_TEX_WIDTH(poly2) ( 1<< ((((poly2) >> 3) & 0x07 ) + 3) )
1.57 +#define POLY2_TEX_HEIGHT(poly2) ( 1<< (((poly2) & 0x07 ) + 3) )
1.58 +#define POLY2_TEX_BLEND(poly2) ( pvr2_poly_texblend[((poly2) >> 6)&0x03] )
1.59 +
1.60 +#define RENDER_ZONLY 0
1.61 +#define RENDER_NORMAL 1 /* Render non-modified polygons */
1.62 +#define RENDER_CHEAPMOD 2 /* Render cheap-modified polygons */
1.63 +#define RENDER_FULLMOD 3 /* Render the fully-modified version of the polygons */
1.64 +
1.65 +#define CULL_NONE 0
1.66 +#define CULL_SMALL 1
1.67 +#define CULL_CCW 2
1.68 +#define CULL_CW 3
1.69 +
1.70 +#define SEGMENT_END 0x80000000
1.71 +#define SEGMENT_SORT_TRANS 0x20000000
1.72 +#define SEGMENT_START 0x10000000
1.73 +#define SEGMENT_X(c) (((c) >> 2) & 0x3F)
1.74 +#define SEGMENT_Y(c) (((c) >> 8) & 0x3F)
1.75 +#define NO_POINTER 0x80000000
1.76 +
1.77 +extern char *video_base;
1.78 +
1.79 +struct tile_segment {
1.80 + uint32_t control;
1.81 + pvraddr_t opaque_ptr;
1.82 + pvraddr_t opaquemod_ptr;
1.83 + pvraddr_t trans_ptr;
1.84 + pvraddr_t transmod_ptr;
1.85 + pvraddr_t punchout_ptr;
1.86 +};
1.87 +
1.88 +/**
1.89 + * Convert a half-float (16-bit) FP number to a regular 32-bit float.
1.90 + * Source is 1-bit sign, 5-bit exponent, 10-bit mantissa.
1.91 + * TODO: Check the correctness of this.
1.92 + */
1.93 +float halftofloat( uint16_t half )
1.94 +{
1.95 + union {
1.96 + float f;
1.97 + uint32_t i;
1.98 + } temp;
1.99 + int e = ((half & 0x7C00) >> 10) - 15 + 127;
1.100 +
1.101 + temp.i = ((half & 0x8000) << 16) | (e << 23) |
1.102 + ((half & 0x03FF) << 13);
1.103 + return temp.f;
1.104 +}
1.105 +
1.106 +
1.107 +/**
1.108 + * Setup the GL context for the supplied polygon context.
1.109 + * @param context pointer to 3 or 5 words of polygon context
1.110 + * @param modified boolean flag indicating that the modified
1.111 + * version should be used, rather than the normal version.
1.112 + */
1.113 +void render_set_context( uint32_t *context, int render_mode )
1.114 +{
1.115 + uint32_t poly1 = context[0], poly2, texture;
1.116 + if( render_mode == RENDER_FULLMOD ) {
1.117 + poly2 = context[3];
1.118 + texture = context[4];
1.119 + } else {
1.120 + poly2 = context[1];
1.121 + texture = context[2];
1.122 + }
1.123 +
1.124 + if( POLY1_DEPTH_ENABLE(poly1) ) {
1.125 + glEnable( GL_DEPTH_TEST );
1.126 + glDepthFunc( POLY1_DEPTH_MODE(poly1) );
1.127 + } else {
1.128 + glDisable( GL_DEPTH_TEST );
1.129 + }
1.130 +
1.131 + switch( POLY1_CULL_MODE(poly1) ) {
1.132 + case CULL_NONE:
1.133 + case CULL_SMALL:
1.134 + glDisable( GL_CULL_FACE );
1.135 + break;
1.136 + case CULL_CCW:
1.137 + glEnable( GL_CULL_FACE );
1.138 + glFrontFace( GL_CW );
1.139 + break;
1.140 + case CULL_CW:
1.141 + glEnable( GL_CULL_FACE );
1.142 + glFrontFace( GL_CCW );
1.143 + break;
1.144 + }
1.145 +
1.146 + if( POLY1_TEXTURED(poly1) ) {
1.147 + int width = POLY2_TEX_WIDTH(poly2);
1.148 + int height = POLY2_TEX_HEIGHT(poly2);
1.149 + glEnable(GL_TEXTURE_2D);
1.150 + texcache_get_texture( (texture&0x001FFFFF)<<3, width, height, texture );
1.151 + glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, POLY2_TEX_BLEND(poly2) );
1.152 + } else {
1.153 + glDisable( GL_TEXTURE_2D );
1.154 + }
1.155 +
1.156 + glShadeModel( POLY1_SHADE_MODEL(poly1) );
1.157 +
1.158 + glBlendFunc( POLY2_SRC_BLEND(poly2), POLY2_DEST_BLEND(poly2) );
1.159 + if( POLY2_TEX_ALPHA_ENABLE(poly2) ) {
1.160 + glEnable(GL_BLEND);
1.161 + } else {
1.162 + glDisable(GL_BLEND);
1.163 + }
1.164 +}
1.165 +
1.166 +void render_vertexes( uint32_t poly1, uint32_t *vertexes, int num_vertexes, int vertex_size,
1.167 + int render_mode )
1.168 +{
1.169 + int i, m=0;
1.170 +
1.171 + if( render_mode == RENDER_FULLMOD ) {
1.172 + m = (vertex_size - 3)/2;
1.173 + }
1.174 +
1.175 + glBegin( GL_TRIANGLE_STRIP );
1.176 +
1.177 + for( i=0; i<num_vertexes; i++ ) {
1.178 + float *vertexf = (float *)vertexes;
1.179 + uint32_t argb;
1.180 + if( POLY1_TEXTURED(poly1) ) {
1.181 + if( POLY1_UV16(poly1) ) {
1.182 + glTexCoord2f( halftofloat(vertexes[m+3]>>16),
1.183 + halftofloat(vertexes[m+3]) );
1.184 + argb = vertexes[m+4];
1.185 + } else {
1.186 + glTexCoord2f( vertexf[m+3], vertexf[m+4] );
1.187 + argb = vertexes[m+5];
1.188 + }
1.189 + } else {
1.190 + argb = vertexes[m+3];
1.191 + }
1.192 +
1.193 + glColor4ub( (GLubyte)(argb >> 16), (GLubyte)(argb >> 8),
1.194 + (GLubyte)argb, (GLubyte)(argb >> 24) );
1.195 + glVertex3f( vertexf[0], vertexf[1], vertexf[2] );
1.196 + vertexes += vertex_size;
1.197 + }
1.198 +
1.199 + glEnd();
1.200 +}
1.201 +
1.202 +/**
1.203 + * Render a simple (not auto-sorted) tile
1.204 + */
1.205 +void render_tile( pvraddr_t tile_entry, int render_mode, gboolean cheap_modifier_mode ) {
1.206 +
1.207 + uint32_t *tile_list = (uint32_t *)(video_base+tile_entry);
1.208 + do {
1.209 + uint32_t entry = *tile_list++;
1.210 + if( entry >> 28 == 0x0F ) {
1.211 + break;
1.212 + } else if( entry >> 28 == 0x0E ) {
1.213 + tile_list = (uint32_t *)(video_base + (entry&0x007FFFFF));
1.214 + } else {
1.215 + uint32_t *polygon = (uint32_t *)(video_base + ((entry & 0x001FFFFF) << 2));
1.216 + int is_modified = entry & 0x01000000;
1.217 + int vertex_length = (entry >> 21) & 0x07;
1.218 + int context_length = 3;
1.219 + if( is_modified && !cheap_modifier_mode ) {
1.220 + context_length = 5;
1.221 + vertex_length *= 2 ;
1.222 + }
1.223 + vertex_length += 3;
1.224 +
1.225 + if( (entry & 0xE0000000) == 0x80000000 ) {
1.226 + /* Triangle(s) */
1.227 + int strip_count = ((entry >> 25) & 0x0F)+1;
1.228 + int polygon_length = 3 * vertex_length + context_length;
1.229 + int i;
1.230 + for( i=0; i<strip_count; i++ ) {
1.231 + render_set_context( polygon, render_mode );
1.232 + render_vertexes( *polygon, polygon+context_length, 3, vertex_length,
1.233 + render_mode );
1.234 + polygon += polygon_length;
1.235 + }
1.236 + } else if( (entry & 0xE0000000) == 0xA0000000 ) {
1.237 + /* Sprite(s) */
1.238 + int strip_count = (entry >> 25) & 0x0F;
1.239 + int polygon_length = 4 * vertex_length + context_length;
1.240 + int i;
1.241 + for( i=0; i<strip_count; i++ ) {
1.242 + render_set_context( polygon, render_mode );
1.243 + render_vertexes( *polygon, polygon+context_length, 4, vertex_length,
1.244 + render_mode );
1.245 + polygon += polygon_length;
1.246 + }
1.247 + } else {
1.248 + /* Polygon */
1.249 + int i, first=-1, last = -1;
1.250 + for( i=0; i<6; i++ ) {
1.251 + if( entry & (0x40000000>>i) ) {
1.252 + if( first == -1 ) first = i;
1.253 + last = i;
1.254 + }
1.255 + }
1.256 + if( first != -1 ) {
1.257 + first = 0;
1.258 + render_set_context(polygon, render_mode);
1.259 + render_vertexes( *polygon, polygon+context_length + (first*vertex_length),
1.260 + (last-first+3), vertex_length, render_mode );
1.261 + }
1.262 + }
1.263 + }
1.264 + } while( 1 );
1.265 +}
1.266 +
1.267 +void render_autosort_tile( pvraddr_t tile_entry, int render_mode, gboolean cheap_modifier_mode ) {
1.268 + //WARN( "Autosort not implemented yet" );
1.269 + render_tile( tile_entry, render_mode, cheap_modifier_mode );
1.270 +}
1.271 +
1.272 +void pvr2_render_tilebuffer( int width, int height, int clipx1, int clipy1,
1.273 + int clipx2, int clipy2 ) {
1.274 +
1.275 + pvraddr_t segmentbase = MMIO_READ( PVR2, TILEBASE );
1.276 + int tile_sort;
1.277 + gboolean cheap_shadow;
1.278 +
1.279 + int obj_config = MMIO_READ( PVR2, OBJCFG );
1.280 + int isp_config = MMIO_READ( PVR2, ISPCFG );
1.281 + int shadow_cfg = MMIO_READ( PVR2, SHADOW );
1.282 +
1.283 + if( obj_config & 0x00200000 ) {
1.284 + if( isp_config & 1 ) {
1.285 + tile_sort = 0;
1.286 + } else {
1.287 + tile_sort = 2;
1.288 + }
1.289 + } else {
1.290 + tile_sort = 1;
1.291 + }
1.292 +
1.293 + cheap_shadow = shadow_cfg & 0x100 ? TRUE : FALSE;
1.294 +
1.295 + struct tile_segment *segment = (struct tile_segment *)(video_base + segmentbase);
1.296 +
1.297 + glEnable( GL_SCISSOR_TEST );
1.298 + while( (segment->control & SEGMENT_END) == 0 ) {
1.299 + int tilex = SEGMENT_X(segment->control);
1.300 + int tiley = SEGMENT_Y(segment->control);
1.301 +
1.302 + int x1 = tilex << 5;
1.303 + int y1 = tiley << 5;
1.304 + if( x1 + 32 <= clipx1 ||
1.305 + y1 + 32 <= clipy1 ||
1.306 + x1 >= clipx2 ||
1.307 + y1 >= clipy2 ) {
1.308 + /* Tile completely clipped, skip */
1.309 + segment++;
1.310 + continue;
1.311 + }
1.312 +
1.313 + /* Set a scissor on the visible part of the tile */
1.314 + int w = MIN(x1+32, clipx2) - x1;
1.315 + int h = MIN(y1+32, clipy2) - y1;
1.316 + x1 = MAX(x1,clipx1);
1.317 + y1 = MAX(y1,clipy1);
1.318 + glScissor( x1, height-y1-h, w, h );
1.319 +
1.320 + if( (segment->opaque_ptr & NO_POINTER) == 0 ) {
1.321 + if( (segment->opaquemod_ptr & NO_POINTER) == 0 ) {
1.322 + /* TODO */
1.323 + }
1.324 + render_tile( segment->opaque_ptr, RENDER_NORMAL, cheap_shadow );
1.325 + }
1.326 +
1.327 + if( (segment->trans_ptr & NO_POINTER) == 0 ) {
1.328 + if( (segment->transmod_ptr & NO_POINTER) == 0 ) {
1.329 + /* TODO */
1.330 + }
1.331 + if( tile_sort == 2 || (tile_sort == 1 && (segment->control & SEGMENT_SORT_TRANS)) ) {
1.332 + render_autosort_tile( segment->trans_ptr, RENDER_NORMAL, cheap_shadow );
1.333 + } else {
1.334 + render_tile( segment->trans_ptr, RENDER_NORMAL, cheap_shadow );
1.335 + }
1.336 + }
1.337 +
1.338 + if( (segment->punchout_ptr & NO_POINTER) == 0 ) {
1.339 + render_tile( segment->punchout_ptr, RENDER_NORMAL, cheap_shadow );
1.340 + }
1.341 + segment++;
1.342 + }
1.343 + glDisable( GL_SCISSOR_TEST );
1.344 +}
.