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