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