2 * $Id: render.c,v 1.5 2006-03-20 11:59:15 nkeynes Exp $
4 * PVR2 Renderer support. This is where the real work happens.
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"
23 #define POLY_COLOUR_PACKED 0x00000000
24 #define POLY_COLOUR_FLOAT 0x00000010
25 #define POLY_COLOUR_INTENSITY 0x00000020
26 #define POLY_COLOUR_INTENSITY_PREV 0x00000030
28 static int pvr2_poly_vertexes[4] = { 3, 4, 6, 8 };
29 static int pvr2_poly_type[4] = { GL_TRIANGLES, GL_QUADS, GL_TRIANGLE_STRIP, GL_TRIANGLE_STRIP };
30 static int pvr2_poly_depthmode[8] = { GL_NEVER, GL_LESS, GL_EQUAL, GL_LEQUAL,
31 GL_GREATER, GL_NOTEQUAL, GL_GEQUAL,
33 static int pvr2_poly_srcblend[8] = {
34 GL_ZERO, GL_ONE, GL_DST_COLOR, GL_ONE_MINUS_DST_COLOR,
35 GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_DST_ALPHA,
36 GL_ONE_MINUS_DST_ALPHA };
37 static int pvr2_poly_dstblend[8] = {
38 GL_ZERO, GL_ONE, GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR,
39 GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_DST_ALPHA,
40 GL_ONE_MINUS_DST_ALPHA };
41 static int pvr2_poly_texblend[4] = {
42 GL_REPLACE, GL_BLEND, GL_DECAL, GL_MODULATE };
43 static int pvr2_render_colour_format[8] = {
44 COLFMT_ARGB1555, COLFMT_RGB565, COLFMT_ARGB4444, COLFMT_ARGB1555,
45 COLFMT_RGB888, COLFMT_ARGB8888, COLFMT_ARGB8888, COLFMT_ARGB4444 };
47 #define POLY_STRIP_TYPE(poly) ( pvr2_poly_type[((poly->command)>>18)&0x03] )
48 #define POLY_STRIP_VERTEXES(poly) ( pvr2_poly_vertexes[((poly->command)>>18)&0x03] )
49 #define POLY_DEPTH_MODE(poly) ( pvr2_poly_depthmode[poly->poly_cfg>>29] )
50 #define POLY_DEPTH_WRITE(poly) (poly->poly_cfg&0x04000000)
51 #define POLY_TEX_WIDTH(poly) ( 1<< (((poly->poly_mode >> 3) & 0x07 ) + 3) )
52 #define POLY_TEX_HEIGHT(poly) ( 1<< (((poly->poly_mode) & 0x07 ) + 3) )
53 #define POLY_BLEND_SRC(poly) ( pvr2_poly_srcblend[(poly->poly_mode) >> 29] )
54 #define POLY_BLEND_DEST(poly) ( pvr2_poly_dstblend[((poly->poly_mode)>>26)&0x07] )
55 #define POLY_TEX_BLEND(poly) ( pvr2_poly_texblend[((poly->poly_mode) >> 6)&0x03] )
56 #define POLY_COLOUR_TYPE(poly) ( poly->command & 0x00000030 )
58 extern uint32_t pvr2_frame_counter;
61 * Describes a rendering buffer that's actually held in GL, for when we need
62 * to fetch the bits back to vram.
64 typedef struct pvr2_render_buffer {
65 uint32_t render_addr; /* The actual address rendered to in pvr ram */
68 } *pvr2_render_buffer_t;
70 struct pvr2_render_buffer front_buffer;
71 struct pvr2_render_buffer back_buffer;
73 struct tile_descriptor {
75 struct tile_pointers {
78 uint32_t opaque_mod_ptr;
80 uint32_t trans_mod_ptr;
81 uint32_t punchout_ptr;
85 /* Textured polygon */
88 uint32_t poly_cfg; /* Bitmask */
89 uint32_t poly_mode; /* texture/blending mask */
90 uint32_t texture; /* texture data */
97 struct pvr2_specular_highlight {
109 struct pvr2_vertex_packed {
118 void pvr2_render_copy_to_sh4( pvr2_render_buffer_t buffer,
119 gboolean backBuffer );
121 int pvr2_render_font_list = -1;
123 int glPrintf( const char *fmt, ... )
125 va_list ap; /* our argument pointer */
128 if (fmt == NULL) /* if there is no string to draw do nothing */
131 len = vsnprintf(buf, sizeof(buf), fmt, ap);
134 if( pvr2_render_font_list == -1 ) {
135 pvr2_render_font_list = video_glx_load_font( "-*-helvetica-*-r-normal--16-*-*-*-p-*-iso8859-1");
138 glPushAttrib(GL_LIST_BIT);
139 glListBase(pvr2_render_font_list - 32);
140 glCallLists(len, GL_UNSIGNED_BYTE, buf);
147 gboolean pvr2_render_init( void )
149 front_buffer.render_addr = -1;
150 back_buffer.render_addr = -1;
154 * Display a rendered frame if one is available.
155 * @param address An address in PVR ram (0500000 range).
156 * @return TRUE if a frame was available to be displayed, otherwise false.
158 gboolean pvr2_render_display_frame( uint32_t address )
160 if( front_buffer.render_addr == address ) {
161 /* Current front buffer is already displayed, so do nothing
162 * and tell the caller that all is well.
166 if( back_buffer.render_addr == address ) {
167 /* The more useful case - back buffer is to be displayed. Swap
170 video_driver->display_back_buffer();
171 front_buffer = back_buffer;
172 back_buffer.render_addr = -1;
179 * Prepare the OpenGL context to receive instructions for a new frame.
181 static void pvr2_render_prepare_context( sh4addr_t render_addr,
182 uint32_t width, uint32_t height,
183 uint32_t colour_format,
184 gboolean texture_target )
186 /* Select and initialize the render context */
187 video_driver->set_render_format( width, height, colour_format, texture_target );
189 if( back_buffer.render_addr != -1 &&
190 back_buffer.render_addr != render_addr ) {
191 /* There's a current back buffer, and we're rendering somewhere else -
192 * flush the back buffer back to vram and start a new back buffer
194 pvr2_render_copy_to_sh4( &back_buffer, TRUE );
197 if( front_buffer.render_addr == render_addr ) {
198 /* In case we've been asked to render to the current front buffer -
199 * invalidate the front buffer and render to the back buffer, ensuring
200 * we swap at the next frame display.
202 front_buffer.render_addr = -1;
204 back_buffer.render_addr = render_addr;
205 back_buffer.width = width;
206 back_buffer.height = height;
207 back_buffer.colour_format = colour_format;
209 /* Setup the display model */
210 glDrawBuffer(GL_BACK);
211 glShadeModel(GL_SMOOTH);
212 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
213 glViewport( 0, 0, width, height );
214 glMatrixMode(GL_PROJECTION);
216 glOrtho( 0, width, height, 0, 0, -65535 );
217 glMatrixMode(GL_MODELVIEW);
219 glCullFace( GL_BACK );
221 /* Clear out the buffers */
222 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
224 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
227 static void pvr2_dump_display_list( uint32_t * display_list, uint32_t length )
230 for( i =0; i<length; i+=4 ) {
231 if( (i % 32) == 0 ) {
233 fprintf( stderr, "\n" );
234 fprintf( stderr, "%08X:", i );
236 fprintf( stderr, " %08X", display_list[i] );
240 static void pvr2_render_display_list( uint32_t *display_list, uint32_t length )
242 uint32_t *cmd_ptr = display_list;
243 int strip_length = 0, vertex_count = 0;
245 gboolean textured = FALSE;
246 struct pvr2_poly *poly;
247 while( cmd_ptr < display_list+length ) {
248 unsigned int cmd = *cmd_ptr >> 24;
250 case PVR2_CMD_POLY_OPAQUE:
251 poly = (struct pvr2_poly *)cmd_ptr;
252 if( poly->command & PVR2_POLY_TEXTURED ) {
253 uint32_t addr = PVR2_TEX_ADDR(poly->texture);
254 int width = POLY_TEX_WIDTH(poly);
255 int height = POLY_TEX_HEIGHT(poly);
256 glEnable( GL_TEXTURE_2D );
257 texcache_get_texture( addr, width, height, poly->texture );
259 glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, POLY_TEX_BLEND(poly) );
262 glDisable( GL_TEXTURE_2D );
264 glBlendFunc( POLY_BLEND_SRC(poly), POLY_BLEND_DEST(poly) );
265 if( poly->command & PVR2_POLY_SPECULAR ) {
266 /* Second block expected */
268 if( POLY_DEPTH_WRITE(poly) ) {
269 glEnable( GL_DEPTH_TEST );
270 glDepthFunc( POLY_DEPTH_MODE(poly) );
272 glDisable( GL_DEPTH_TEST );
275 switch( (poly->poly_cfg >> 27) & 0x03 ) {
278 glDisable( GL_CULL_FACE );
281 glEnable( GL_CULL_FACE );
282 glFrontFace( GL_CW );
285 glEnable( GL_CULL_FACE );
286 glFrontFace( GL_CCW );
288 strip_length = POLY_STRIP_VERTEXES( poly );
289 colour_type = POLY_COLOUR_TYPE( poly );
292 case PVR2_CMD_VERTEX_LAST:
293 case PVR2_CMD_VERTEX:
294 if( vertex_count == 0 ) {
295 if( strip_length == 3 )
296 glBegin( GL_TRIANGLES );
298 glBegin( GL_TRIANGLE_STRIP );
302 struct pvr2_vertex_packed *vertex = (struct pvr2_vertex_packed *)cmd_ptr;
304 glTexCoord2f( vertex->s, vertex->t );
307 switch( colour_type ) {
308 case POLY_COLOUR_PACKED:
309 glColor4ub( vertex->colour >> 16, vertex->colour >> 8,
310 vertex->colour, vertex->colour >> 24 );
313 glVertex3f( vertex->x, vertex->y, vertex->z );
315 if( cmd == PVR2_CMD_VERTEX_LAST ) {
320 if( vertex_count >= strip_length ) {
321 ERROR( "Rendering long strip (expected end after %d)", strip_length );
322 pvr2_dump_display_list( display_list, length );
327 cmd_ptr += 8; /* Next record */
332 * Render a complete scene into the OpenGL back buffer.
333 * Note: this will probably need to be broken up eventually once timings are
336 void pvr2_render_scene( )
338 struct tile_descriptor *tile_desc =
339 (struct tile_descriptor *)mem_get_region(PVR2_RAM_BASE + MMIO_READ( PVR2, TILEBASE ));
341 uint32_t render_addr = MMIO_READ( PVR2, RENDADDR1 );
342 gboolean render_to_tex;
343 if( render_addr & 0x01000000 ) {
344 render_addr = (render_addr & 0x00FFFFFF) + PVR2_RAM_BASE_INT;
345 /* Heuristic - if we're rendering to the interlaced region we're
346 * probably creating a texture rather than rendering actual output.
347 * We can optimise for this case a little
349 render_to_tex = TRUE;
350 WARN( "Render to texture not supported properly yet" );
352 render_addr = (render_addr & 0x00FFFFFF) + PVR2_RAM_BASE;
353 render_to_tex = FALSE;
355 uint32_t render_mode = MMIO_READ( PVR2, RENDMODE );
356 int width = 640; /* FIXME - get this from the tile buffer */
358 int colour_format = pvr2_render_colour_format[render_mode&0x07];
359 pvr2_render_prepare_context( render_addr, width, height, colour_format,
362 uint32_t *display_list =
363 (uint32_t *)mem_get_region(PVR2_RAM_BASE + MMIO_READ( PVR2, OBJBASE ));
364 uint32_t display_length = *display_list++;
366 int clip_x = MMIO_READ( PVR2, HCLIP ) & 0x03FF;
367 int clip_y = MMIO_READ( PVR2, VCLIP ) & 0x03FF;
368 int clip_width = ((MMIO_READ( PVR2, HCLIP ) >> 16) & 0x03FF) - clip_x + 1;
369 int clip_height= ((MMIO_READ( PVR2, VCLIP ) >> 16) & 0x03FF) - clip_y + 1;
371 if( clip_x == 0 && clip_y == 0 && clip_width == width && clip_height == height ) {
372 glDisable( GL_SCISSOR_TEST );
374 glEnable( GL_SCISSOR_TEST );
375 glScissor( clip_x, clip_y, clip_width, clip_height );
378 /* Fog setup goes here */
380 /* Render the display list */
381 pvr2_render_display_list( display_list, display_length );
383 /* Post-render cleanup and update */
385 /* Add frame, fps, etc data */
386 glRasterPos2i( 4, 16 );
387 // glColor3f( 0.0f, 0.0f, 1.0f );
388 glPrintf( "Frame %d", pvr2_frame_counter );
390 /* Generate end of render event */
391 asic_event( EVENT_PVR_RENDER_DONE );
392 DEBUG( "Rendered frame %d", pvr2_frame_counter );
397 * Flush the indicated render buffer back to PVR. Caller is responsible for
398 * tracking whether there is actually anything in the buffer.
400 * @param buffer A render buffer indicating the address to store to, and the
401 * format the data needs to be in.
402 * @param backBuffer TRUE to flush the back buffer, FALSE for
405 void pvr2_render_copy_to_sh4( pvr2_render_buffer_t buffer,
406 gboolean backBuffer )
408 if( buffer->render_addr == -1 )
410 GLenum type, format = GL_RGBA;
411 int size = buffer->width * buffer->height;
413 switch( buffer->colour_format ) {
415 type = GL_UNSIGNED_SHORT_5_6_5;
420 type = GL_UNSIGNED_INT;
422 size = (size<<1)+size;
424 case COLFMT_ARGB1555:
425 type = GL_UNSIGNED_SHORT_5_5_5_1;
428 case COLFMT_ARGB4444:
429 type = GL_UNSIGNED_SHORT_4_4_4_4;
432 case COLFMT_ARGB8888:
433 type = GL_UNSIGNED_INT_8_8_8_8;
440 glReadBuffer( GL_BACK );
442 glReadBuffer( GL_FRONT );
445 if( buffer->render_addr & 0xFF000000 == 0x04000000 ) {
446 /* Interlaced buffer. Go the double copy... :( */
448 glReadPixels( 0, 0, buffer->width, buffer->height, format, type, target );
449 pvr2_vram64_write( buffer->render_addr, target, size );
451 /* Regular buffer - go direct */
452 char *target = mem_get_region( buffer->render_addr );
453 glReadPixels( 0, 0, buffer->width, buffer->height, format, type, target );
459 * Copy data from PVR ram into the GL render buffer.
461 * @param buffer A render buffer indicating the address to read from, and the
462 * format the data is in.
463 * @param backBuffer TRUE to write the back buffer, FALSE for
466 void pvr2_render_copy_from_sh4( pvr2_render_buffer_t buffer,
467 gboolean backBuffer )
469 if( buffer->render_addr == -1 )
471 GLenum type, format = GL_RGBA;
472 int size = buffer->width * buffer->height;
474 switch( buffer->colour_format ) {
476 type = GL_UNSIGNED_SHORT_5_6_5;
481 type = GL_UNSIGNED_INT;
483 size = (size<<1)+size;
485 case COLFMT_ARGB1555:
486 type = GL_UNSIGNED_SHORT_5_5_5_1;
489 case COLFMT_ARGB4444:
490 type = GL_UNSIGNED_SHORT_4_4_4_4;
493 case COLFMT_ARGB8888:
494 type = GL_UNSIGNED_INT_8_8_8_8;
500 glDrawBuffer( GL_BACK );
502 glDrawBuffer( GL_FRONT );
505 glRasterPos2i( 0, 0 );
506 if( buffer->render_addr & 0xFF000000 == 0x04000000 ) {
507 /* Interlaced buffer. Go the double copy... :( */
509 pvr2_vram64_read( target, buffer->render_addr, size );
510 glDrawPixels( buffer->width, buffer->height,
511 format, type, target );
513 /* Regular buffer - go direct */
514 char *target = mem_get_region( buffer->render_addr );
515 glDrawPixels( buffer->width, buffer->height,
516 format, type, target );
.