2 * $Id: rendcore.c,v 1.12 2007-01-24 08:11:14 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_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 };
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;
60 pvraddr_t opaquemod_ptr;
62 pvraddr_t transmod_ptr;
63 pvraddr_t punchout_ptr;
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.
71 float halftofloat( uint16_t half )
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;
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.
92 void render_set_context( uint32_t *context, int render_mode )
94 uint32_t poly1 = context[0], poly2, texture;
95 if( render_mode == RENDER_FULLMOD ) {
100 texture = context[2];
103 if( POLY1_DEPTH_ENABLE(poly1) ) {
104 glEnable( GL_DEPTH_TEST );
105 glDepthFunc( POLY1_DEPTH_MODE(poly1) );
107 glDisable( GL_DEPTH_TEST );
110 switch( POLY1_CULL_MODE(poly1) ) {
113 glDisable( GL_CULL_FACE );
116 glEnable( GL_CULL_FACE );
117 glFrontFace( GL_CW );
120 glEnable( GL_CULL_FACE );
121 glFrontFace( GL_CCW );
125 if( POLY1_SPECULAR(poly1) ) {
126 glEnable(GL_COLOR_SUM);
128 glDisable(GL_COLOR_SUM);
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 );
140 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
142 if( POLY2_TEX_CLAMP_V(poly2) ) {
143 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
145 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
148 glDisable( GL_TEXTURE_2D );
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;
161 #define FARGB_A(x) (((float)(((x)>>24)+1))/256.0)
162 #define FARGB_R(x) (((float)((((x)>>16)&0xFF)+1))/256.0)
163 #define FARGB_G(x) (((float)((((x)>>8)&0xFF)+1))/256.0)
164 #define FARGB_B(x) (((float)(((x)&0xFF)+1))/256.0)
166 void render_unpack_vertexes( struct vertex_unpacked *out, uint32_t poly1,
167 uint32_t *vertexes, int num_vertexes,
168 int vertex_size, int render_mode )
171 if( render_mode == RENDER_FULLMOD ) {
172 m = (vertex_size - 3)/2;
175 for( i=0; i<num_vertexes; i++ ) {
176 float *vertexf = (float *)vertexes;
178 out[i].x = vertexf[0];
179 out[i].y = vertexf[1];
180 out[i].z = vertexf[2];
181 if( POLY1_TEXTURED(poly1) ) {
182 if( POLY1_UV16(poly1) ) {
183 out[i].u = halftofloat(vertexes[k]>>16);
184 out[i].v = halftofloat(vertexes[k]);
187 out[i].u = vertexf[k];
188 out[i].v = vertexf[k+1];
195 uint32_t argb = vertexes[k++];
196 out[i].rgba[0] = FARGB_R(argb);
197 out[i].rgba[1] = FARGB_G(argb);
198 out[i].rgba[2] = FARGB_B(argb);
199 out[i].rgba[3] = FARGB_A(argb);
200 if( POLY1_SPECULAR(poly1) ) {
201 uint32_t offset = vertexes[k++];
202 out[i].offset_rgba[0] = FARGB_R(argb);
203 out[i].offset_rgba[1] = FARGB_G(argb);
204 out[i].offset_rgba[2] = FARGB_B(argb);
205 out[i].offset_rgba[3] = FARGB_A(argb);
207 vertexes += vertex_size;
212 * Unpack the vertexes for a quad, calculating the values for the last
214 * FIXME: Integrate this with rendbkg somehow
216 void render_unpack_quad( struct vertex_unpacked *unpacked, uint32_t poly1,
217 uint32_t *vertexes, int vertex_size,
221 struct vertex_unpacked diff0, diff1;
223 render_unpack_vertexes( unpacked, poly1, vertexes, 3, vertex_size, render_mode );
225 diff0.x = unpacked[0].x - unpacked[1].x;
226 diff0.y = unpacked[0].y - unpacked[1].y;
227 diff1.x = unpacked[2].x - unpacked[1].x;
228 diff1.y = unpacked[2].y - unpacked[1].y;
230 float detxy = ((diff1.y) * (diff0.x)) - ((diff0.y) * (diff1.x));
231 float *vertexf = (float *)(vertexes+(vertex_size*3));
233 memcpy( &unpacked[3], &unpacked[2], sizeof(struct vertex_unpacked) );
234 unpacked[3].x = vertexf[0];
235 unpacked[3].y = vertexf[1];
239 unpacked[3].x = vertexf[0];
240 unpacked[3].y = vertexf[1];
241 float t = ((unpacked[3].x - unpacked[1].x) * diff1.y -
242 (unpacked[3].y - unpacked[1].y) * diff1.x) / detxy;
243 float s = ((unpacked[3].y - unpacked[1].y) * diff0.x -
244 (unpacked[3].x - unpacked[1].x) * diff0.y) / detxy;
245 diff0.z = unpacked[0].z - unpacked[1].z;
246 diff1.z = unpacked[2].z - unpacked[1].z;
247 unpacked[3].z = unpacked[1].z + (t*diff0.z) + (s*diff1.z);
249 diff0.u = unpacked[0].u - unpacked[1].u;
250 diff0.v = unpacked[0].v - unpacked[1].v;
251 diff1.u = unpacked[2].u - unpacked[1].u;
252 diff1.v = unpacked[2].v - unpacked[1].v;
253 unpacked[3].u = unpacked[1].u + (t*diff0.u) + (s*diff1.u);
254 unpacked[3].v = unpacked[1].v + (t*diff0.v) + (s*diff1.v);
256 if( !POLY1_GOURAUD_SHADED(poly1) ) {
257 memcpy( unpacked[3].rgba, unpacked[2].rgba, sizeof(unpacked[2].rgba) );
258 memcpy( unpacked[3].offset_rgba, unpacked[2].offset_rgba, sizeof(unpacked[2].offset_rgba) );
260 for( i=0; i<4; i++ ) {
261 float d0 = unpacked[0].rgba[i] - unpacked[1].rgba[i];
262 float d1 = unpacked[2].rgba[i] - unpacked[1].rgba[i];
263 unpacked[3].rgba[i] = unpacked[1].rgba[i] + (t*d0) + (s*d1);
264 d0 = unpacked[0].offset_rgba[i] - unpacked[1].offset_rgba[i];
265 d1 = unpacked[2].offset_rgba[i] - unpacked[1].offset_rgba[i];
266 unpacked[3].offset_rgba[i] = unpacked[1].offset_rgba[i] + (t*d0) + (s*d1);
271 void render_unpacked_vertex_array( uint32_t poly1, struct vertex_unpacked *vertexes[],
275 glBegin( GL_TRIANGLE_STRIP );
277 for( i=0; i<num_vertexes; i++ ) {
278 if( POLY1_TEXTURED(poly1) ) {
279 glTexCoord2f( vertexes[i]->u, vertexes[i]->v );
282 glColor4f( vertexes[i]->rgba[0], vertexes[i]->rgba[1], vertexes[i]->rgba[2],
283 (pvr2_force_fragment_alpha ? 1.0 : vertexes[i]->rgba[3]) );
285 if( POLY1_SPECULAR(poly1) ) {
286 glSecondaryColor3fEXT( vertexes[i]->offset_rgba[0],
287 vertexes[i]->offset_rgba[1],
288 vertexes[i]->offset_rgba[2] );
290 glVertex3f( vertexes[i]->x, vertexes[i]->y, vertexes[i]->z );
296 void render_quad_vertexes( uint32_t poly1, uint32_t *vertexes, int vertex_size, int render_mode )
298 struct vertex_unpacked unpacked[4];
299 struct vertex_unpacked *pt[4] = {&unpacked[0], &unpacked[1], &unpacked[3], &unpacked[2]};
300 render_unpack_quad( unpacked, poly1, vertexes, vertex_size, render_mode );
301 render_unpacked_vertex_array( poly1, pt, 4 );
304 void render_vertex_array( uint32_t poly1, uint32_t *vert_array[], int num_vertexes, int vertex_size,
309 if( render_mode == RENDER_FULLMOD ) {
310 m = (vertex_size - 3)/2;
313 glBegin( GL_TRIANGLE_STRIP );
315 for( i=0; i<num_vertexes; i++ ) {
316 uint32_t *vertexes = vert_array[i];
317 float *vertexf = (float *)vert_array[i];
320 if( POLY1_TEXTURED(poly1) ) {
321 if( POLY1_UV16(poly1) ) {
322 glTexCoord2f( halftofloat(vertexes[k]>>16),
323 halftofloat(vertexes[k]) );
326 glTexCoord2f( vertexf[k], vertexf[k+1] );
331 argb = vertexes[k++];
332 if( pvr2_force_fragment_alpha ) {
333 glColor4ub( (GLubyte)(argb >> 16), (GLubyte)(argb >> 8),
334 (GLubyte)argb, 0xFF );
336 glColor4ub( (GLubyte)(argb >> 16), (GLubyte)(argb >> 8),
337 (GLubyte)argb, (GLubyte)(argb >> 24) );
340 if( POLY1_SPECULAR(poly1) ) {
341 uint32_t spec = vertexes[k++];
342 glSecondaryColor3ubEXT( (GLubyte)(spec >> 16), (GLubyte)(spec >> 8),
345 glVertex3f( vertexf[0], vertexf[1], vertexf[2] );
346 vertexes += vertex_size;
352 void render_vertexes( uint32_t poly1, uint32_t *vertexes, int num_vertexes, int vertex_size,
355 uint32_t *vert_array[num_vertexes];
357 for( i=0; i<num_vertexes; i++ ) {
358 vert_array[i] = vertexes;
359 vertexes += vertex_size;
361 render_vertex_array( poly1, vert_array, num_vertexes, vertex_size, render_mode );
365 * Render a simple (not auto-sorted) tile
367 void render_tile( pvraddr_t tile_entry, int render_mode, gboolean cheap_modifier_mode ) {
368 uint32_t poly_bank = MMIO_READ(PVR2,RENDER_POLYBASE);
369 uint32_t *tile_list = (uint32_t *)(video_base+tile_entry);
371 uint32_t entry = *tile_list++;
372 if( entry >> 28 == 0x0F ) {
374 } else if( entry >> 28 == 0x0E ) {
375 tile_list = (uint32_t *)(video_base + (entry&0x007FFFFF));
377 uint32_t *polygon = (uint32_t *)(video_base + poly_bank + ((entry & 0x000FFFFF) << 2));
378 int is_modified = entry & 0x01000000;
379 int vertex_length = (entry >> 21) & 0x07;
380 int context_length = 3;
381 if( is_modified && !cheap_modifier_mode ) {
387 if( (entry & 0xE0000000) == 0x80000000 ) {
389 int strip_count = ((entry >> 25) & 0x0F)+1;
390 int polygon_length = 3 * vertex_length + context_length;
392 for( i=0; i<strip_count; i++ ) {
393 render_set_context( polygon, render_mode );
394 render_vertexes( *polygon, polygon+context_length, 3, vertex_length,
396 polygon += polygon_length;
398 } else if( (entry & 0xE0000000) == 0xA0000000 ) {
400 int strip_count = ((entry >> 25) & 0x0F)+1;
401 int polygon_length = 4 * vertex_length + context_length;
403 for( i=0; i<strip_count; i++ ) {
404 render_set_context( polygon, render_mode );
405 render_quad_vertexes( *polygon, polygon+context_length, vertex_length,
407 polygon += polygon_length;
411 int i, first=-1, last = -1;
412 for( i=0; i<6; i++ ) {
413 if( entry & (0x40000000>>i) ) {
414 if( first == -1 ) first = i;
420 render_set_context(polygon, render_mode);
421 render_vertexes( *polygon, polygon+context_length + (first*vertex_length),
422 (last-first+3), vertex_length, render_mode );
429 void pvr2_render_tilebuffer( int width, int height, int clipx1, int clipy1,
430 int clipx2, int clipy2 ) {
432 pvraddr_t segmentbase = MMIO_READ( PVR2, RENDER_TILEBASE );
434 gboolean cheap_shadow;
436 int obj_config = MMIO_READ( PVR2, RENDER_OBJCFG );
437 int isp_config = MMIO_READ( PVR2, RENDER_ISPCFG );
438 int shadow_cfg = MMIO_READ( PVR2, RENDER_SHADOW );
440 if( (obj_config & 0x00200000) == 0 ) {
441 if( isp_config & 1 ) {
450 cheap_shadow = shadow_cfg & 0x100 ? TRUE : FALSE;
452 struct tile_segment *segment = (struct tile_segment *)(video_base + segmentbase);
454 struct timeval tv_start, tv_end;
455 gettimeofday(&tv_start, NULL);
456 glEnable( GL_SCISSOR_TEST );
458 // fwrite_dump32v( (uint32_t *)segment, sizeof(struct tile_segment), 6, stderr );
459 int tilex = SEGMENT_X(segment->control);
460 int tiley = SEGMENT_Y(segment->control);
464 if( x1 + 32 <= clipx1 ||
468 /* Tile completely clipped, skip */
472 /* Set a scissor on the visible part of the tile */
473 int w = MIN(x1+32, clipx2) - x1;
474 int h = MIN(y1+32, clipy2) - y1;
477 glScissor( x1, height-y1-h, w, h );
479 if( (segment->opaque_ptr & NO_POINTER) == 0 ) {
480 if( (segment->opaquemod_ptr & NO_POINTER) == 0 ) {
483 render_tile( segment->opaque_ptr, RENDER_NORMAL, cheap_shadow );
486 if( (segment->trans_ptr & NO_POINTER) == 0 ) {
487 if( (segment->transmod_ptr & NO_POINTER) == 0 ) {
490 if( tile_sort == 2 ||
491 (tile_sort == 1 && ((segment->control & SEGMENT_SORT_TRANS)==0)) ) {
492 render_autosort_tile( segment->trans_ptr, RENDER_NORMAL, cheap_shadow );
494 render_tile( segment->trans_ptr, RENDER_NORMAL, cheap_shadow );
498 if( (segment->punchout_ptr & NO_POINTER) == 0 ) {
499 render_tile( segment->punchout_ptr, RENDER_NORMAL, cheap_shadow );
501 } while( ((segment++)->control & SEGMENT_END) == 0 );
502 glDisable( GL_SCISSOR_TEST );
504 gettimeofday(&tv_end, NULL);
505 timersub(&tv_end,&tv_start, &tv_start);
.