filename | src/pvr2/rendcore.c |
changeset | 318:363935d31859 |
prev | 308:10a5b5475fb0 |
next | 319:5392aed6a982 |
author | nkeynes |
date | Tue Jan 23 12:03:57 2007 +0000 (17 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 }
.