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