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