Search
lxdream.org :: lxdream/src/pvr2/render.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/pvr2/render.c
changeset 144:7f0714e89aaa
prev132:48a8cc541742
next161:408b9210395f
author nkeynes
date Mon May 15 08:28:52 2006 +0000 (14 years ago)
permissions -rw-r--r--
last change Rename video_driver to display_driver
Add input source to display
Implement configuration file support
Hook controllers up to configuration
view annotate diff log raw
     1 /**
     2  * $Id: render.c,v 1.8 2006-05-15 08:28:52 nkeynes Exp $
     3  *
     4  * PVR2 Renderer support. This is where the real work happens.
     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  */
    19 #include "pvr2/pvr2.h"
    20 #include "asic.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, 
    32 				      GL_ALWAYS };
    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) == 0 )
    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 /**
    59  * Describes a rendering buffer that's actually held in GL, for when we need
    60  * to fetch the bits back to vram.
    61  */
    62 typedef struct pvr2_render_buffer {
    63     uint32_t render_addr; /* The actual address rendered to in pvr ram */
    64     int width, height;
    65     int colour_format;
    66 } *pvr2_render_buffer_t;
    68 struct pvr2_render_buffer front_buffer;
    69 struct pvr2_render_buffer back_buffer;
    71 struct tile_descriptor {
    72     uint32_t header[6];
    73     struct tile_pointers {
    74 	uint32_t tile_id;
    75 	uint32_t opaque_ptr;
    76 	uint32_t opaque_mod_ptr;
    77 	uint32_t trans_ptr;
    78 	uint32_t trans_mod_ptr;
    79 	uint32_t punchout_ptr;
    80     } tile[0];
    81 };
    83 /* Textured polygon */
    84 struct pvr2_poly {
    85     uint32_t command;
    86     uint32_t poly_cfg; /* Bitmask */
    87     uint32_t poly_mode; /* texture/blending mask */
    88     uint32_t texture; /* texture data */
    89     float alpha;
    90     float red;
    91     float green;
    92     float blue;
    93 };
    95 struct pvr2_specular_highlight {
    96     float base_alpha;
    97     float base_red;
    98     float base_green;
    99     float base_blue;
   100     float offset_alpha;
   101     float offset_red;
   102     float offset_green;
   103     float offset_blue;
   104 };
   107 struct pvr2_vertex_packed {
   108     uint32_t command;
   109     float x, y, z;
   110     float s,t;
   111     uint32_t colour;
   112     float f;
   113 };
   115 struct pvr2_vertex_float {
   116     uint32_t command;
   117     float x,y,z;
   118     float a, r, g, b;
   119 };
   121 union pvr2_vertex {
   122     struct pvr2_vertex_packed pack;
   123     struct pvr2_vertex_float flt;
   124 };
   126 typedef struct pvr2_bgplane_packed {
   127         uint32_t        poly_cfg, poly_mode;
   128         uint32_t        texture_mode;
   129         float           x1, y1, z1;
   130         uint32_t          colour1;
   131         float           x2, y2, z2;
   132         uint32_t          colour2;
   133         float           x3, y3, z3;
   134         uint32_t          colour3;
   135 } *pvr2_bgplane_packed_t;
   139 void pvr2_render_copy_to_sh4( pvr2_render_buffer_t buffer, 
   140 			      gboolean backBuffer );
   142 int pvr2_render_font_list = -1;
   143 int pvr2_render_trace = 0;
   145 int glPrintf( int x, int y, const char *fmt, ... )
   146 {
   147     va_list ap;     /* our argument pointer */
   148     char buf[256];
   149     int len;
   150     if (fmt == NULL)    /* if there is no string to draw do nothing */
   151         return;
   152     va_start(ap, fmt); 
   153     len = vsnprintf(buf, sizeof(buf), fmt, ap);
   154     va_end(ap);
   157     glPushAttrib(GL_LIST_BIT);
   158     glDisable( GL_DEPTH_TEST );
   159     glDisable( GL_BLEND );
   160     glDisable( GL_TEXTURE_2D );
   161     glDisable( GL_ALPHA_TEST );
   162     glListBase(pvr2_render_font_list - 32);
   163     glColor3f( 1.0, 1.0, 1.0 );
   164     glRasterPos2i( x, y );
   165     glCallLists(len, GL_UNSIGNED_BYTE, buf);
   166     glPopAttrib();
   168     return len;
   169 }
   172 gboolean pvr2_render_init( void )
   173 {
   174     front_buffer.render_addr = -1;
   175     back_buffer.render_addr = -1;
   176 }
   178 /**
   179  * Display a rendered frame if one is available.
   180  * @param address An address in PVR ram (0500000 range).
   181  * @return TRUE if a frame was available to be displayed, otherwise false.
   182  */
   183 gboolean pvr2_render_display_frame( uint32_t address )
   184 {
   185     if( front_buffer.render_addr == address ) {
   186 	/* Current front buffer is already displayed, so do nothing
   187 	 * and tell the caller that all is well.
   188 	 */
   189 	return TRUE;
   190     }
   191     if( back_buffer.render_addr == address ) {
   192 	/* The more useful case - back buffer is to be displayed. Swap
   193 	 * the buffers 
   194 	 */
   195 	display_driver->display_back_buffer();
   196 	front_buffer = back_buffer;
   197 	back_buffer.render_addr = -1;
   198 	return TRUE;
   199     }
   200     return FALSE;
   201 }	
   203 /**
   204  * Prepare the OpenGL context to receive instructions for a new frame.
   205  */
   206 static void pvr2_render_prepare_context( sh4addr_t render_addr, 
   207 					 uint32_t width, uint32_t height,
   208 					 uint32_t colour_format, 
   209 					 float bgplanez,
   210 					 gboolean texture_target )
   211 {
   212     /* Select and initialize the render context */
   213     display_driver->set_render_format( width, height, colour_format, texture_target );
   215     if( pvr2_render_font_list == -1 ) {
   216 	pvr2_render_font_list = video_glx_load_font( "-*-helvetica-*-r-normal--16-*-*-*-p-*-iso8859-1");
   217     }
   219     if( back_buffer.render_addr != -1 && 
   220 	back_buffer.render_addr != render_addr ) {
   221 	/* There's a current back buffer, and we're rendering somewhere else -
   222 	 * flush the back buffer back to vram and start a new back buffer
   223 	 */
   224 	pvr2_render_copy_to_sh4( &back_buffer, TRUE );
   225     }
   227     if( front_buffer.render_addr == render_addr ) {
   228 	/* In case we've been asked to render to the current front buffer -
   229 	 * invalidate the front buffer and render to the back buffer, ensuring
   230 	 * we swap at the next frame display.
   231 	 */
   232 	front_buffer.render_addr = -1;
   233     }
   234     back_buffer.render_addr = render_addr;
   235     back_buffer.width = width;
   236     back_buffer.height = height;
   237     back_buffer.colour_format = colour_format;
   239     /* Setup the display model */
   240     glDrawBuffer(GL_BACK);
   241     glShadeModel(GL_SMOOTH);
   242     glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
   243     glViewport( 0, 0, width, height );
   244     glMatrixMode(GL_PROJECTION);
   245     glLoadIdentity();
   246     glOrtho( 0, width, height, 0, bgplanez, -1 );
   247     glMatrixMode(GL_MODELVIEW);
   248     glLoadIdentity();
   249     glCullFace( GL_BACK );
   251     /* Clear out the buffers */
   252     glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
   253     glClearDepth(bgplanez);
   254     glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
   255 }
   257 static void pvr2_dump_display_list( uint32_t * display_list, uint32_t length )
   258 {
   259     uint32_t i;
   260     gboolean vertex = FALSE;
   261     for( i =0; i<length>>2; i++ ) {
   262 	if( (i % 8) == 0 ) {
   263 	    if( i != 0 )
   264 		fprintf( stderr, "\n" );
   265 	    fprintf( stderr, "%08X:", i*4 );
   266 	    if( display_list[i] == 0xE0000000 ||
   267 		display_list[i] == 0xF0000000 ) 
   268 		vertex = TRUE;
   269 	    else vertex = FALSE;
   270 	}
   271 	if( vertex && (i%8) > 0 && (i%8) < 4 )
   272 	    fprintf( stderr, " %f", ((float *)display_list)[i] );
   273 	else
   274 	    fprintf( stderr, " %08X", display_list[i] );
   275     }
   276     fprintf( stderr, "\n" );
   277 }
   279 static void pvr2_render_display_list( uint32_t *display_list, uint32_t length )
   280 {
   281     uint32_t *cmd_ptr = display_list;
   282     int strip_length = 0, vertex_count = 0;
   283     int colour_type;
   284     gboolean textured = FALSE;
   285     gboolean shaded = FALSE;
   286     struct pvr2_poly *poly;
   287     if( pvr2_render_trace ) {
   288 	fprintf( stderr, "-------- %d\n", pvr2_get_frame_count() );
   289 	pvr2_dump_display_list( display_list, length );
   290     }
   291     while( cmd_ptr < display_list+(length>>2) ) {
   292 	unsigned int cmd = *cmd_ptr >> 24;
   293 	switch( cmd ) {
   294 	case PVR2_CMD_POLY_OPAQUE:
   295 	case PVR2_CMD_POLY_TRANS:
   296 	case PVR2_CMD_POLY_PUNCHOUT:
   297 	    poly = (struct pvr2_poly *)cmd_ptr;
   298 	    if( poly->command & PVR2_POLY_TEXTURED ) {
   299 		uint32_t addr = PVR2_TEX_ADDR(poly->texture);
   300 		int width = POLY_TEX_WIDTH(poly);
   301 		int height = POLY_TEX_HEIGHT(poly);
   302 		glEnable( GL_TEXTURE_2D );
   303 		texcache_get_texture( addr, width, height, poly->texture );
   304 		textured = TRUE;
   305 		glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, POLY_TEX_BLEND(poly) );
   306 	    } else {
   307 		textured = FALSE;
   308 		glDisable( GL_TEXTURE_2D );
   309 	    }
   310 	    glBlendFunc( POLY_BLEND_SRC(poly), POLY_BLEND_DEST(poly) );
   311 	    if( poly->command & PVR2_POLY_SPECULAR ) {
   312 		/* Second block expected */
   313 	    }
   314 	    if( POLY_DEPTH_WRITE(poly) ) {
   315 		glEnable( GL_DEPTH_TEST );
   316 		glDepthFunc( POLY_DEPTH_MODE(poly) );
   317 	    } else {
   318 		glDisable( GL_DEPTH_TEST );
   319 	    }
   321 	    switch( (poly->poly_cfg >> 27) & 0x03 ) {
   322 	    case 0:
   323 	    case 1:
   324 		glDisable( GL_CULL_FACE );
   325 		break;
   326 	    case 2:
   327 		glEnable( GL_CULL_FACE );
   328 		glFrontFace( GL_CW );
   329 		break;
   330 	    case 3:
   331 		glEnable( GL_CULL_FACE );
   332 		glFrontFace( GL_CCW );
   333 	    }
   334 	    strip_length = POLY_STRIP_VERTEXES( poly );
   335 	    colour_type = POLY_COLOUR_TYPE( poly );
   336 	    vertex_count = 0;
   337 	    if( poly->command & PVR2_POLY_SHADED ) {
   338 		shaded = TRUE;
   339 	    } else {
   340 		shaded = FALSE;
   341 	    }
   342 	    if( poly->poly_mode & PVR2_POLY_MODE_TEXALPHA ) {
   343 		glDisable( GL_BLEND );
   344 	    } else {
   345 		glEnable( GL_BLEND );
   346 	    }
   348 	    break;
   349 	case PVR2_CMD_MOD_OPAQUE:
   350 	case PVR2_CMD_MOD_TRANS:
   351 	    /* TODO */
   352 	    break;
   353 	case PVR2_CMD_END_OF_LIST:
   354 	    break;
   355 	case PVR2_CMD_VERTEX_LAST:
   356 	case PVR2_CMD_VERTEX:
   357 	    if( vertex_count == 0 ) {
   358 		glBegin( GL_TRIANGLE_STRIP );
   359 	    }
   360 	    vertex_count++;
   362 	    struct pvr2_vertex_packed *vertex = (struct pvr2_vertex_packed *)cmd_ptr;
   363 	    if( textured ) {
   364 		glTexCoord2f( vertex->s, vertex->t );
   366 		if( shaded || vertex_count == 1) {
   367 		    switch( colour_type ) {
   368 		    case POLY_COLOUR_PACKED:
   369 			glColor4ub( vertex->colour >> 16, vertex->colour >> 8,
   370 				    vertex->colour, vertex->colour >> 24 );
   371 			break;
   372 		    }
   373 		}
   374 	    } else {
   375 		if( shaded || vertex_count == 1 ) {
   376 		    switch( colour_type ) {
   377 		    case POLY_COLOUR_PACKED:
   378 			glColor4ub( vertex->colour >> 16, vertex->colour >> 8,
   379 				    vertex->colour, vertex->colour >> 24 );
   380 			break;
   381 		    case POLY_COLOUR_FLOAT: 
   382 			{
   383 			    struct pvr2_vertex_float *v = (struct pvr2_vertex_float *)cmd_ptr;
   384 			    glColor4f( v->r, v->g, v->b, v->a );
   385 			}
   386 			break;
   387 		    }
   388 		}
   389 	    }
   391 	    glVertex3f( vertex->x, vertex->y, vertex->z );
   393 	    if( cmd == PVR2_CMD_VERTEX_LAST ) {
   394 		glEnd();
   395 		vertex_count = 0;
   396 	    }
   397 	    break;
   398 	default:
   399 	    ERROR( "Unhandled command %08X in display list", *cmd_ptr );
   400 	    pvr2_dump_display_list( display_list, length );
   401 	    return;
   402 	}
   403 	cmd_ptr += 8; /* Next record */
   404     }
   405 }
   407 #define MIN3( a,b,c ) ((a) < (b) ? ( (a) < (c) ? (a) : (c) ) : ((b) < (c) ? (b) : (c)) )
   408 #define MAX3( a,b,c ) ((a) > (b) ? ( (a) > (c) ? (a) : (c) ) : ((b) > (c) ? (b) : (c)) )
   410 /**
   411  * Render the background plane as best we can. Unfortunately information
   412  * is a little scant, to say the least.
   413  */
   414 void pvr2_render_draw_backplane( uint32_t mode, uint32_t *poly )
   415 {
   416     if( (mode >> 24) == 0x01 ) {
   417 	/* Packed colour. I think */
   418 	pvr2_bgplane_packed_t bg = (pvr2_bgplane_packed_t)poly;
   419 	if( bg->colour1 != bg->colour2 || bg->colour2 != bg->colour3 ) {
   420 	    WARN( "Multiple background colours specified. Confused" );
   421 	}
   422 	float x1 = MIN3( bg->x1, bg->x2, bg->x3 );
   423 	float y1 = MIN3( bg->y1, bg->y2, bg->y3 );
   424 	float x2 = MAX3( bg->x1, bg->x2, bg->x3 );
   425 	float y2 = MAX3( bg->y1, bg->y2, bg->y3 );
   426 	float z = MIN3( bg->z1, bg->z2, bg->z3 );
   427 	glDisable( GL_TEXTURE_2D );
   428 	glDisable( GL_DEPTH_TEST );
   429 	glColor3ub( (uint8_t)(bg->colour1 >> 16), (uint8_t)(bg->colour1 >> 8), 
   430 		    (uint8_t)bg->colour1 );
   431 	glBegin( GL_QUADS );
   432 	glVertex3f( x1, y1, z );
   433 	glVertex3f( x2, y1, z );
   434 	glVertex3f( x2, y2, z );
   435 	glVertex3f( x1, y2, z );
   436 	glEnd();
   437     } else {
   438 	WARN( "Unknown bgplane mode: %08X", mode );
   439 	fwrite_dump( poly, 48, stderr );
   440     }
   441 }
   443 /**
   444  * Render a complete scene into the OpenGL back buffer.
   445  * Note: this will probably need to be broken up eventually once timings are
   446  * determined.
   447  */
   448 void pvr2_render_scene( )
   449 {
   450     struct tile_descriptor *tile_desc =
   451 	(struct tile_descriptor *)mem_get_region(PVR2_RAM_BASE + MMIO_READ( PVR2, TILEBASE ));
   453     uint32_t render_addr = MMIO_READ( PVR2, RENDADDR1 );
   454     gboolean render_to_tex;
   455     if( render_addr & 0x01000000 ) {
   456 	render_addr = (render_addr & 0x00FFFFFF) + PVR2_RAM_BASE_INT;
   457 	/* Heuristic - if we're rendering to the interlaced region we're
   458 	 * probably creating a texture rather than rendering actual output.
   459 	 * We can optimise for this case a little
   460 	 */
   461 	render_to_tex = TRUE;
   462 	WARN( "Render to texture not supported properly yet" );
   463     } else {
   464 	render_addr = (render_addr & 0x00FFFFFF) + PVR2_RAM_BASE;
   465 	render_to_tex = FALSE;
   466     }
   468     float bgplanez = MMIO_READF( PVR2, BGPLANEZ );
   469     uint32_t render_mode = MMIO_READ( PVR2, RENDMODE );
   470     int width = 640; /* FIXME - get this from the tile buffer */
   471     int height = 480;
   472     int colour_format = pvr2_render_colour_format[render_mode&0x07];
   473     pvr2_render_prepare_context( render_addr, width, height, colour_format, 
   474 				 bgplanez, render_to_tex );
   476     uint32_t *display_list = 
   477 	(uint32_t *)mem_get_region(PVR2_RAM_BASE + MMIO_READ( PVR2, OBJBASE ));
   479     uint32_t display_length = *display_list++;
   481     int clip_x = MMIO_READ( PVR2, HCLIP ) & 0x03FF;
   482     int clip_y = MMIO_READ( PVR2, VCLIP ) & 0x03FF;
   483     int clip_width = ((MMIO_READ( PVR2, HCLIP ) >> 16) & 0x03FF) - clip_x + 1;
   484     int clip_height= ((MMIO_READ( PVR2, VCLIP ) >> 16) & 0x03FF) - clip_y + 1;
   486     if( clip_x == 0 && clip_y == 0 && clip_width == width && clip_height == height ) {
   487 	glDisable( GL_SCISSOR_TEST );
   488     } else {
   489 	glEnable( GL_SCISSOR_TEST );
   490 	glScissor( clip_x, clip_y, clip_width, clip_height );
   491     }
   493     /* Fog setup goes here */
   495     /* Render the background plane */
   496     uint32_t bgplane_mode = MMIO_READ(PVR2, BGPLANE);
   497     uint32_t *bgplane = display_list + (((bgplane_mode & 0x00FFFFFF)) >> 3) - 1;
   498     pvr2_render_draw_backplane( bgplane_mode, bgplane );
   500     /* Render the display list */
   501     pvr2_render_display_list( display_list, display_length );
   503     /* Post-render cleanup and update */
   505     /* Add frame, fps, etc data */
   506     glPrintf( 4, 16, "Frame %d", pvr2_get_frame_count() );
   508     /* Generate end of render event */
   509     asic_event( EVENT_PVR_RENDER_DONE );
   510     DEBUG( "Rendered frame %d", pvr2_get_frame_count() );
   511 }
   514 /**
   515  * Flush the indicated render buffer back to PVR. Caller is responsible for
   516  * tracking whether there is actually anything in the buffer.
   517  *
   518  * @param buffer A render buffer indicating the address to store to, and the
   519  * format the data needs to be in.
   520  * @param backBuffer TRUE to flush the back buffer, FALSE for 
   521  * the front buffer.
   522  */
   523 void pvr2_render_copy_to_sh4( pvr2_render_buffer_t buffer, 
   524 			      gboolean backBuffer )
   525 {
   526     if( buffer->render_addr == -1 )
   527 	return;
   528     GLenum type, format = GL_RGBA;
   529     int size = buffer->width * buffer->height;
   531     switch( buffer->colour_format ) {
   532     case COLFMT_RGB565: 
   533 	type = GL_UNSIGNED_SHORT_5_6_5; 
   534 	format = GL_RGB; 
   535 	size <<= 1;
   536 	break;
   537     case COLFMT_RGB888: 
   538 	type = GL_UNSIGNED_INT; 
   539 	format = GL_RGB;
   540 	size = (size<<1)+size;
   541 	break;
   542     case COLFMT_ARGB1555: 
   543 	type = GL_UNSIGNED_SHORT_5_5_5_1; 
   544 	size <<= 1;
   545 	break;
   546     case COLFMT_ARGB4444: 
   547 	type = GL_UNSIGNED_SHORT_4_4_4_4; 
   548 	size <<= 1;
   549 	break;
   550     case COLFMT_ARGB8888: 
   551 	type = GL_UNSIGNED_INT_8_8_8_8; 
   552 	size <<= 2;
   553 	break;
   554     }
   556     if( backBuffer ) {
   557 	glFinish();
   558 	glReadBuffer( GL_BACK );
   559     } else {
   560 	glReadBuffer( GL_FRONT );
   561     }
   563     if( buffer->render_addr & 0xFF000000 == 0x04000000 ) {
   564 	/* Interlaced buffer. Go the double copy... :( */
   565 	char target[size];
   566 	glReadPixels( 0, 0, buffer->width, buffer->height, format, type, target );
   567 	pvr2_vram64_write( buffer->render_addr, target, size );
   568     } else {
   569 	/* Regular buffer - go direct */
   570 	char *target = mem_get_region( buffer->render_addr );
   571 	glReadPixels( 0, 0, buffer->width, buffer->height, format, type, target );
   572     }
   573 }
   576 /**
   577  * Copy data from PVR ram into the GL render buffer. 
   578  *
   579  * @param buffer A render buffer indicating the address to read from, and the
   580  * format the data is in.
   581  * @param backBuffer TRUE to write the back buffer, FALSE for 
   582  * the front buffer.
   583  */
   584 void pvr2_render_copy_from_sh4( pvr2_render_buffer_t buffer, 
   585 				gboolean backBuffer )
   586 {
   587     if( buffer->render_addr == -1 )
   588 	return;
   589     GLenum type, format = GL_RGBA;
   590     int size = buffer->width * buffer->height;
   592     switch( buffer->colour_format ) {
   593     case COLFMT_RGB565: 
   594 	type = GL_UNSIGNED_SHORT_5_6_5; 
   595 	format = GL_RGB; 
   596 	size <<= 1;
   597 	break;
   598     case COLFMT_RGB888: 
   599 	type = GL_UNSIGNED_INT; 
   600 	format = GL_RGB;
   601 	size = (size<<1)+size;
   602 	break;
   603     case COLFMT_ARGB1555: 
   604 	type = GL_UNSIGNED_SHORT_5_5_5_1; 
   605 	size <<= 1;
   606 	break;
   607     case COLFMT_ARGB4444: 
   608 	type = GL_UNSIGNED_SHORT_4_4_4_4; 
   609 	size <<= 1;
   610 	break;
   611     case COLFMT_ARGB8888: 
   612 	type = GL_UNSIGNED_INT_8_8_8_8; 
   613 	size <<= 2;
   614 	break;
   615     }
   617     if( backBuffer ) {
   618 	glDrawBuffer( GL_BACK );
   619     } else {
   620 	glDrawBuffer( GL_FRONT );
   621     }
   623     glRasterPos2i( 0, 0 );
   624     if( buffer->render_addr & 0xFF000000 == 0x04000000 ) {
   625 	/* Interlaced buffer. Go the double copy... :( */
   626 	char target[size];
   627 	pvr2_vram64_read( target, buffer->render_addr, size );
   628 	glDrawPixels( buffer->width, buffer->height, 
   629 		      format, type, target );
   630     } else {
   631 	/* Regular buffer - go direct */
   632 	char *target = mem_get_region( buffer->render_addr );
   633 	glDrawPixels( buffer->width, buffer->height, 
   634 		      format, type, target );
   635     }
   636 }
.