2 * $Id: rendcore.c,v 1.8 2007-01-15 10:11:13 nkeynes Exp $
6 * Copyright (c) 2005 Nathan Keynes.
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.
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.
19 #include "pvr2/pvr2.h"
22 int pvr2_poly_depthmode[8] = { GL_NEVER, GL_LESS, GL_EQUAL, GL_LEQUAL,
23 GL_GREATER, GL_NOTEQUAL, GL_GEQUAL,
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_BLEND, 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 };
45 #define SEGMENT_END 0x80000000
46 #define SEGMENT_SORT_TRANS 0x20000000
47 #define SEGMENT_START 0x10000000
48 #define SEGMENT_X(c) (((c) >> 2) & 0x3F)
49 #define SEGMENT_Y(c) (((c) >> 8) & 0x3F)
50 #define NO_POINTER 0x80000000
52 extern char *video_base;
57 pvraddr_t opaquemod_ptr;
59 pvraddr_t transmod_ptr;
60 pvraddr_t punchout_ptr;
64 * Convert a half-float (16-bit) FP number to a regular 32-bit float.
65 * Source is 1-bit sign, 5-bit exponent, 10-bit mantissa.
66 * TODO: Check the correctness of this.
68 float halftofloat( uint16_t half )
74 int e = ((half & 0x7C00) >> 10) - 15 + 127;
76 temp.i = ((half & 0x8000) << 16) | (e << 23) |
77 ((half & 0x03FF) << 13);
83 * Setup the GL context for the supplied polygon context.
84 * @param context pointer to 3 or 5 words of polygon context
85 * @param modified boolean flag indicating that the modified
86 * version should be used, rather than the normal version.
88 void render_set_context( uint32_t *context, int render_mode )
90 uint32_t poly1 = context[0], poly2, texture;
91 if( render_mode == RENDER_FULLMOD ) {
99 if( POLY1_DEPTH_ENABLE(poly1) ) {
100 glEnable( GL_DEPTH_TEST );
101 glDepthFunc( POLY1_DEPTH_MODE(poly1) );
103 glDisable( GL_DEPTH_TEST );
106 switch( POLY1_CULL_MODE(poly1) ) {
109 glDisable( GL_CULL_FACE );
112 glEnable( GL_CULL_FACE );
113 glFrontFace( GL_CW );
116 glEnable( GL_CULL_FACE );
117 glFrontFace( GL_CCW );
121 if( POLY1_TEXTURED(poly1) ) {
122 int width = POLY2_TEX_WIDTH(poly2);
123 int height = POLY2_TEX_HEIGHT(poly2);
124 glEnable(GL_TEXTURE_2D);
125 texcache_get_texture( (texture&0x000FFFFF)<<3, width, height, texture );
126 glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, POLY2_TEX_BLEND(poly2) );
128 glDisable( GL_TEXTURE_2D );
131 glShadeModel( POLY1_SHADE_MODEL(poly1) );
133 int srcblend = POLY2_SRC_BLEND(poly2);
134 int destblend = POLY2_DEST_BLEND(poly2);
135 glBlendFunc( srcblend, destblend );
136 if( POLY2_TEX_ALPHA_ENABLE(poly2) ) {
143 void render_vertexes( uint32_t poly1, uint32_t *vertexes, int num_vertexes, int vertex_size,
148 if( render_mode == RENDER_FULLMOD ) {
149 m = (vertex_size - 3)/2;
152 glBegin( GL_TRIANGLE_STRIP );
154 for( i=0; i<num_vertexes; i++ ) {
155 float *vertexf = (float *)vertexes;
157 if( POLY1_TEXTURED(poly1) ) {
158 if( POLY1_UV16(poly1) ) {
159 glTexCoord2f( halftofloat(vertexes[m+3]>>16),
160 halftofloat(vertexes[m+3]) );
161 argb = vertexes[m+4];
163 glTexCoord2f( vertexf[m+3], vertexf[m+4] );
164 argb = vertexes[m+5];
167 argb = vertexes[m+3];
170 glColor4ub( (GLubyte)(argb >> 16), (GLubyte)(argb >> 8),
171 (GLubyte)argb, (GLubyte)(argb >> 24) );
172 glVertex3f( vertexf[0], vertexf[1], vertexf[2] );
173 vertexes += vertex_size;
180 * Render a simple (not auto-sorted) tile
182 void render_tile( pvraddr_t tile_entry, int render_mode, gboolean cheap_modifier_mode ) {
183 uint32_t poly_bank = MMIO_READ(PVR2,RENDER_POLYBASE);
184 uint32_t *tile_list = (uint32_t *)(video_base+tile_entry);
186 uint32_t entry = *tile_list++;
187 if( entry >> 28 == 0x0F ) {
189 } else if( entry >> 28 == 0x0E ) {
190 tile_list = (uint32_t *)(video_base + (entry&0x007FFFFF));
192 uint32_t *polygon = (uint32_t *)(video_base + poly_bank + ((entry & 0x000FFFFF) << 2));
193 int is_modified = entry & 0x01000000;
194 int vertex_length = (entry >> 21) & 0x07;
195 int context_length = 3;
196 if( is_modified && !cheap_modifier_mode ) {
202 if( (entry & 0xE0000000) == 0x80000000 ) {
204 int strip_count = ((entry >> 25) & 0x0F)+1;
205 int polygon_length = 3 * vertex_length + context_length;
207 for( i=0; i<strip_count; i++ ) {
208 render_set_context( polygon, render_mode );
209 render_vertexes( *polygon, polygon+context_length, 3, vertex_length,
211 polygon += polygon_length;
213 } else if( (entry & 0xE0000000) == 0xA0000000 ) {
215 int strip_count = (entry >> 25) & 0x0F;
216 int polygon_length = 4 * vertex_length + context_length;
218 for( i=0; i<strip_count; i++ ) {
219 render_set_context( polygon, render_mode );
220 render_vertexes( *polygon, polygon+context_length, 4, vertex_length,
222 polygon += polygon_length;
226 int i, first=-1, last = -1;
227 for( i=0; i<6; i++ ) {
228 if( entry & (0x40000000>>i) ) {
229 if( first == -1 ) first = i;
235 render_set_context(polygon, render_mode);
236 render_vertexes( *polygon, polygon+context_length + (first*vertex_length),
237 (last-first+3), vertex_length, render_mode );
244 void pvr2_render_tilebuffer( int width, int height, int clipx1, int clipy1,
245 int clipx2, int clipy2 ) {
247 pvraddr_t segmentbase = MMIO_READ( PVR2, RENDER_TILEBASE );
249 gboolean cheap_shadow;
251 int obj_config = MMIO_READ( PVR2, RENDER_OBJCFG );
252 int isp_config = MMIO_READ( PVR2, RENDER_ISPCFG );
253 int shadow_cfg = MMIO_READ( PVR2, RENDER_SHADOW );
255 if( (obj_config & 0x00200000) == 0 ) {
256 if( isp_config & 1 ) {
265 cheap_shadow = shadow_cfg & 0x100 ? TRUE : FALSE;
267 struct tile_segment *segment = (struct tile_segment *)(video_base + segmentbase);
269 struct timeval tv_start, tv_end;
270 gettimeofday(&tv_start, NULL);
271 glEnable( GL_SCISSOR_TEST );
273 // fwrite_dump32v( (uint32_t *)segment, sizeof(struct tile_segment), 6, stderr );
274 int tilex = SEGMENT_X(segment->control);
275 int tiley = SEGMENT_Y(segment->control);
279 if( x1 + 32 <= clipx1 ||
283 /* Tile completely clipped, skip */
287 /* Set a scissor on the visible part of the tile */
288 int w = MIN(x1+32, clipx2) - x1;
289 int h = MIN(y1+32, clipy2) - y1;
292 glScissor( x1, height-y1-h, w, h );
294 if( (segment->opaque_ptr & NO_POINTER) == 0 ) {
295 if( (segment->opaquemod_ptr & NO_POINTER) == 0 ) {
298 render_tile( segment->opaque_ptr, RENDER_NORMAL, cheap_shadow );
301 if( (segment->trans_ptr & NO_POINTER) == 0 ) {
302 if( (segment->transmod_ptr & NO_POINTER) == 0 ) {
305 if( tile_sort == 2 ||
306 (tile_sort == 1 && ((segment->control & SEGMENT_SORT_TRANS)==0)) ) {
307 render_autosort_tile( segment->trans_ptr, RENDER_NORMAL, cheap_shadow );
309 render_tile( segment->trans_ptr, RENDER_NORMAL, cheap_shadow );
313 if( (segment->punchout_ptr & NO_POINTER) == 0 ) {
314 render_tile( segment->punchout_ptr, RENDER_NORMAL, cheap_shadow );
316 } while( ((segment++)->control & SEGMENT_END) == 0 );
317 glDisable( GL_SCISSOR_TEST );
319 gettimeofday(&tv_end, NULL);
320 timersub(&tv_end,&tv_start, &tv_start);
.