Search
lxdream.org :: lxdream/src/pvr2/render.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/pvr2/render.c
changeset 191:df4441cf3128
prev189:615b70cfd729
next219:dfd3292143f2
author nkeynes
date Wed Aug 02 06:24:08 2006 +0000 (17 years ago)
permissions -rw-r--r--
last change Add more register masks (in line with test case)
Rename renderer registers for consistency
file annotate diff log raw
nkeynes@100
     1
/**
nkeynes@191
     2
 * $Id: render.c,v 1.12 2006-08-02 06:24:08 nkeynes Exp $
nkeynes@100
     3
 *
nkeynes@189
     4
 * PVR2 Renderer support. This part is primarily
nkeynes@100
     5
 *
nkeynes@100
     6
 * Copyright (c) 2005 Nathan Keynes.
nkeynes@100
     7
 *
nkeynes@100
     8
 * This program is free software; you can redistribute it and/or modify
nkeynes@100
     9
 * it under the terms of the GNU General Public License as published by
nkeynes@100
    10
 * the Free Software Foundation; either version 2 of the License, or
nkeynes@100
    11
 * (at your option) any later version.
nkeynes@100
    12
 *
nkeynes@100
    13
 * This program is distributed in the hope that it will be useful,
nkeynes@100
    14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
nkeynes@100
    15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
nkeynes@100
    16
 * GNU General Public License for more details.
nkeynes@100
    17
 */
nkeynes@100
    18
nkeynes@100
    19
#include "pvr2/pvr2.h"
nkeynes@100
    20
#include "asic.h"
nkeynes@103
    21
nkeynes@103
    22
static int pvr2_render_colour_format[8] = {
nkeynes@103
    23
    COLFMT_ARGB1555, COLFMT_RGB565, COLFMT_ARGB4444, COLFMT_ARGB1555,
nkeynes@103
    24
    COLFMT_RGB888, COLFMT_ARGB8888, COLFMT_ARGB8888, COLFMT_ARGB4444 };
nkeynes@103
    25
nkeynes@100
    26
nkeynes@100
    27
/**
nkeynes@103
    28
 * Describes a rendering buffer that's actually held in GL, for when we need
nkeynes@103
    29
 * to fetch the bits back to vram.
nkeynes@103
    30
 */
nkeynes@103
    31
typedef struct pvr2_render_buffer {
nkeynes@161
    32
    sh4addr_t render_addr; /* The actual address rendered to in pvr ram */
nkeynes@161
    33
    uint32_t size; /* Length of rendering region in bytes */
nkeynes@103
    34
    int width, height;
nkeynes@103
    35
    int colour_format;
nkeynes@103
    36
} *pvr2_render_buffer_t;
nkeynes@103
    37
nkeynes@103
    38
struct pvr2_render_buffer front_buffer;
nkeynes@103
    39
struct pvr2_render_buffer back_buffer;
nkeynes@103
    40
nkeynes@128
    41
typedef struct pvr2_bgplane_packed {
nkeynes@128
    42
        uint32_t        poly_cfg, poly_mode;
nkeynes@128
    43
        uint32_t        texture_mode;
nkeynes@128
    44
        float           x1, y1, z1;
nkeynes@128
    45
        uint32_t          colour1;
nkeynes@128
    46
        float           x2, y2, z2;
nkeynes@128
    47
        uint32_t          colour2;
nkeynes@128
    48
        float           x3, y3, z3;
nkeynes@128
    49
        uint32_t          colour3;
nkeynes@128
    50
} *pvr2_bgplane_packed_t;
nkeynes@128
    51
nkeynes@128
    52
nkeynes@103
    53
nkeynes@103
    54
void pvr2_render_copy_to_sh4( pvr2_render_buffer_t buffer, 
nkeynes@103
    55
			      gboolean backBuffer );
nkeynes@103
    56
nkeynes@108
    57
int pvr2_render_font_list = -1;
nkeynes@132
    58
int pvr2_render_trace = 0;
nkeynes@108
    59
nkeynes@132
    60
int glPrintf( int x, int y, const char *fmt, ... )
nkeynes@108
    61
{
nkeynes@108
    62
    va_list ap;     /* our argument pointer */
nkeynes@108
    63
    char buf[256];
nkeynes@108
    64
    int len;
nkeynes@108
    65
    if (fmt == NULL)    /* if there is no string to draw do nothing */
nkeynes@108
    66
        return;
nkeynes@108
    67
    va_start(ap, fmt); 
nkeynes@108
    68
    len = vsnprintf(buf, sizeof(buf), fmt, ap);
nkeynes@108
    69
    va_end(ap);
nkeynes@108
    70
nkeynes@108
    71
nkeynes@108
    72
    glPushAttrib(GL_LIST_BIT);
nkeynes@132
    73
    glDisable( GL_DEPTH_TEST );
nkeynes@132
    74
    glDisable( GL_BLEND );
nkeynes@132
    75
    glDisable( GL_TEXTURE_2D );
nkeynes@132
    76
    glDisable( GL_ALPHA_TEST );
nkeynes@189
    77
    glDisable( GL_CULL_FACE );
nkeynes@108
    78
    glListBase(pvr2_render_font_list - 32);
nkeynes@132
    79
    glColor3f( 1.0, 1.0, 1.0 );
nkeynes@132
    80
    glRasterPos2i( x, y );
nkeynes@108
    81
    glCallLists(len, GL_UNSIGNED_BYTE, buf);
nkeynes@108
    82
    glPopAttrib();
nkeynes@108
    83
nkeynes@108
    84
    return len;
nkeynes@108
    85
}
nkeynes@108
    86
nkeynes@189
    87
void glDrawGrid( int width, int height )
nkeynes@189
    88
{
nkeynes@189
    89
    int i;
nkeynes@189
    90
    glDisable( GL_DEPTH_TEST );
nkeynes@189
    91
    glLineWidth(1);
nkeynes@189
    92
    
nkeynes@189
    93
    glBegin( GL_LINES );
nkeynes@189
    94
    glColor4f( 1.0, 1.0, 1.0, 1.0 );
nkeynes@189
    95
    for( i=32; i<width; i+=32 ) {
nkeynes@189
    96
	glVertex3f( i, 0.0, 3.0 );
nkeynes@189
    97
	glVertex3f( i,height-1, 3.0 );
nkeynes@189
    98
    }
nkeynes@189
    99
nkeynes@189
   100
    for( i=32; i<height; i+=32 ) {
nkeynes@189
   101
	glVertex3f( 0.0, i, 3.0 );
nkeynes@189
   102
	glVertex3f( width, i, 3.0 );
nkeynes@189
   103
    }
nkeynes@189
   104
    glEnd();
nkeynes@189
   105
	
nkeynes@189
   106
}
nkeynes@189
   107
nkeynes@103
   108
nkeynes@103
   109
gboolean pvr2_render_init( void )
nkeynes@103
   110
{
nkeynes@103
   111
    front_buffer.render_addr = -1;
nkeynes@103
   112
    back_buffer.render_addr = -1;
nkeynes@103
   113
}
nkeynes@103
   114
nkeynes@103
   115
/**
nkeynes@161
   116
 * Invalidate any caching on the supplied address. Specifically, if it falls
nkeynes@161
   117
 * within either the front buffer or back buffer, flush the buffer back to
nkeynes@161
   118
 * PVR2 ram (note that front buffer flush may be corrupt under some
nkeynes@161
   119
 * circumstances).
nkeynes@161
   120
 */
nkeynes@161
   121
gboolean pvr2_render_invalidate( sh4addr_t address )
nkeynes@161
   122
{
nkeynes@161
   123
    address = address & 0x1FFFFFFF;
nkeynes@161
   124
    if( front_buffer.render_addr != -1 &&
nkeynes@161
   125
	front_buffer.render_addr <= address &&
nkeynes@161
   126
	(front_buffer.render_addr + front_buffer.size) > address ) {
nkeynes@161
   127
	pvr2_render_copy_to_sh4( &front_buffer, FALSE );
nkeynes@161
   128
	front_buffer.render_addr = -1;
nkeynes@161
   129
	return TRUE;
nkeynes@161
   130
    } else if( back_buffer.render_addr != -1 &&
nkeynes@161
   131
	       back_buffer.render_addr <= address &&
nkeynes@161
   132
	       (back_buffer.render_addr + back_buffer.size) > address ) {
nkeynes@161
   133
	pvr2_render_copy_to_sh4( &back_buffer, TRUE );
nkeynes@161
   134
	back_buffer.render_addr = -1;
nkeynes@161
   135
	return TRUE;
nkeynes@161
   136
    }
nkeynes@161
   137
    return FALSE;
nkeynes@161
   138
}
nkeynes@161
   139
nkeynes@161
   140
/**
nkeynes@103
   141
 * Display a rendered frame if one is available.
nkeynes@103
   142
 * @param address An address in PVR ram (0500000 range).
nkeynes@103
   143
 * @return TRUE if a frame was available to be displayed, otherwise false.
nkeynes@103
   144
 */
nkeynes@103
   145
gboolean pvr2_render_display_frame( uint32_t address )
nkeynes@103
   146
{
nkeynes@103
   147
    if( front_buffer.render_addr == address ) {
nkeynes@103
   148
	/* Current front buffer is already displayed, so do nothing
nkeynes@103
   149
	 * and tell the caller that all is well.
nkeynes@103
   150
	 */
nkeynes@103
   151
	return TRUE;
nkeynes@103
   152
    }
nkeynes@103
   153
    if( back_buffer.render_addr == address ) {
nkeynes@103
   154
	/* The more useful case - back buffer is to be displayed. Swap
nkeynes@103
   155
	 * the buffers 
nkeynes@103
   156
	 */
nkeynes@144
   157
	display_driver->display_back_buffer();
nkeynes@103
   158
	front_buffer = back_buffer;
nkeynes@103
   159
	back_buffer.render_addr = -1;
nkeynes@103
   160
	return TRUE;
nkeynes@103
   161
    }
nkeynes@103
   162
    return FALSE;
nkeynes@108
   163
}	
nkeynes@103
   164
nkeynes@103
   165
/**
nkeynes@103
   166
 * Prepare the OpenGL context to receive instructions for a new frame.
nkeynes@103
   167
 */
nkeynes@103
   168
static void pvr2_render_prepare_context( sh4addr_t render_addr, 
nkeynes@103
   169
					 uint32_t width, uint32_t height,
nkeynes@103
   170
					 uint32_t colour_format, 
nkeynes@128
   171
					 float bgplanez,
nkeynes@103
   172
					 gboolean texture_target )
nkeynes@103
   173
{
nkeynes@103
   174
    /* Select and initialize the render context */
nkeynes@144
   175
    display_driver->set_render_format( width, height, colour_format, texture_target );
nkeynes@103
   176
nkeynes@132
   177
    if( pvr2_render_font_list == -1 ) {
nkeynes@132
   178
	pvr2_render_font_list = video_glx_load_font( "-*-helvetica-*-r-normal--16-*-*-*-p-*-iso8859-1");
nkeynes@132
   179
    }
nkeynes@132
   180
nkeynes@103
   181
    if( back_buffer.render_addr != -1 && 
nkeynes@103
   182
	back_buffer.render_addr != render_addr ) {
nkeynes@103
   183
	/* There's a current back buffer, and we're rendering somewhere else -
nkeynes@103
   184
	 * flush the back buffer back to vram and start a new back buffer
nkeynes@103
   185
	 */
nkeynes@103
   186
	pvr2_render_copy_to_sh4( &back_buffer, TRUE );
nkeynes@103
   187
    }
nkeynes@103
   188
nkeynes@103
   189
    if( front_buffer.render_addr == render_addr ) {
nkeynes@103
   190
	/* In case we've been asked to render to the current front buffer -
nkeynes@103
   191
	 * invalidate the front buffer and render to the back buffer, ensuring
nkeynes@103
   192
	 * we swap at the next frame display.
nkeynes@103
   193
	 */
nkeynes@103
   194
	front_buffer.render_addr = -1;
nkeynes@103
   195
    }
nkeynes@103
   196
    back_buffer.render_addr = render_addr;
nkeynes@103
   197
    back_buffer.width = width;
nkeynes@103
   198
    back_buffer.height = height;
nkeynes@103
   199
    back_buffer.colour_format = colour_format;
nkeynes@161
   200
    back_buffer.size = width * height * colour_format_bytes[colour_format];
nkeynes@103
   201
nkeynes@103
   202
    /* Setup the display model */
nkeynes@103
   203
    glDrawBuffer(GL_BACK);
nkeynes@103
   204
    glShadeModel(GL_SMOOTH);
nkeynes@103
   205
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
nkeynes@103
   206
    glViewport( 0, 0, width, height );
nkeynes@103
   207
    glMatrixMode(GL_PROJECTION);
nkeynes@103
   208
    glLoadIdentity();
nkeynes@169
   209
    glOrtho( 0, width, height, 0, bgplanez, -4 );
nkeynes@103
   210
    glMatrixMode(GL_MODELVIEW);
nkeynes@103
   211
    glLoadIdentity();
nkeynes@108
   212
    glCullFace( GL_BACK );
nkeynes@103
   213
nkeynes@103
   214
    /* Clear out the buffers */
nkeynes@189
   215
    glDisable( GL_SCISSOR_TEST );
nkeynes@103
   216
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
nkeynes@128
   217
    glClearDepth(bgplanez);
nkeynes@103
   218
    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
nkeynes@103
   219
}
nkeynes@103
   220
nkeynes@103
   221
nkeynes@128
   222
#define MIN3( a,b,c ) ((a) < (b) ? ( (a) < (c) ? (a) : (c) ) : ((b) < (c) ? (b) : (c)) )
nkeynes@128
   223
#define MAX3( a,b,c ) ((a) > (b) ? ( (a) > (c) ? (a) : (c) ) : ((b) > (c) ? (b) : (c)) )
nkeynes@128
   224
nkeynes@128
   225
/**
nkeynes@128
   226
 * Render the background plane as best we can. Unfortunately information
nkeynes@128
   227
 * is a little scant, to say the least.
nkeynes@128
   228
 */
nkeynes@128
   229
void pvr2_render_draw_backplane( uint32_t mode, uint32_t *poly )
nkeynes@128
   230
{
nkeynes@189
   231
    
nkeynes@128
   232
    if( (mode >> 24) == 0x01 ) {
nkeynes@128
   233
	/* Packed colour. I think */
nkeynes@128
   234
	pvr2_bgplane_packed_t bg = (pvr2_bgplane_packed_t)poly;
nkeynes@128
   235
	if( bg->colour1 != bg->colour2 || bg->colour2 != bg->colour3 ) {
nkeynes@128
   236
	    WARN( "Multiple background colours specified. Confused" );
nkeynes@189
   237
	    fprintf( stderr, "bgplane mode: %08X PBUF: %08X\n", mode,
nkeynes@191
   238
		     MMIO_READ( PVR2, RENDER_POLYBASE ) );
nkeynes@189
   239
	    fwrite_dump( poly, 80, stderr );
nkeynes@128
   240
	}
nkeynes@128
   241
	float x1 = MIN3( bg->x1, bg->x2, bg->x3 );
nkeynes@128
   242
	float y1 = MIN3( bg->y1, bg->y2, bg->y3 );
nkeynes@128
   243
	float x2 = MAX3( bg->x1, bg->x2, bg->x3 );
nkeynes@128
   244
	float y2 = MAX3( bg->y1, bg->y2, bg->y3 );
nkeynes@128
   245
	float z = MIN3( bg->z1, bg->z2, bg->z3 );
nkeynes@128
   246
	glDisable( GL_TEXTURE_2D );
nkeynes@128
   247
	glDisable( GL_DEPTH_TEST );
nkeynes@128
   248
	glColor3ub( (uint8_t)(bg->colour1 >> 16), (uint8_t)(bg->colour1 >> 8), 
nkeynes@128
   249
		    (uint8_t)bg->colour1 );
nkeynes@128
   250
	glBegin( GL_QUADS );
nkeynes@128
   251
	glVertex3f( x1, y1, z );
nkeynes@128
   252
	glVertex3f( x2, y1, z );
nkeynes@128
   253
	glVertex3f( x2, y2, z );
nkeynes@128
   254
	glVertex3f( x1, y2, z );
nkeynes@128
   255
	glEnd();
nkeynes@128
   256
    } else {
nkeynes@128
   257
	WARN( "Unknown bgplane mode: %08X", mode );
nkeynes@128
   258
	fwrite_dump( poly, 48, stderr );
nkeynes@128
   259
    }
nkeynes@128
   260
}
nkeynes@128
   261
nkeynes@103
   262
/**
nkeynes@103
   263
 * Render a complete scene into the OpenGL back buffer.
nkeynes@103
   264
 * Note: this will probably need to be broken up eventually once timings are
nkeynes@100
   265
 * determined.
nkeynes@100
   266
 */
nkeynes@103
   267
void pvr2_render_scene( )
nkeynes@100
   268
{
nkeynes@103
   269
    struct tile_descriptor *tile_desc =
nkeynes@191
   270
	(struct tile_descriptor *)mem_get_region(PVR2_RAM_BASE + MMIO_READ( PVR2, RENDER_TILEBASE ));
nkeynes@100
   271
nkeynes@191
   272
    uint32_t render_addr = MMIO_READ( PVR2, RENDER_ADDR1 );
nkeynes@103
   273
    gboolean render_to_tex;
nkeynes@103
   274
    if( render_addr & 0x01000000 ) {
nkeynes@103
   275
	render_addr = (render_addr & 0x00FFFFFF) + PVR2_RAM_BASE_INT;
nkeynes@103
   276
	/* Heuristic - if we're rendering to the interlaced region we're
nkeynes@103
   277
	 * probably creating a texture rather than rendering actual output.
nkeynes@103
   278
	 * We can optimise for this case a little
nkeynes@103
   279
	 */
nkeynes@103
   280
	render_to_tex = TRUE;
nkeynes@118
   281
	WARN( "Render to texture not supported properly yet" );
nkeynes@103
   282
    } else {
nkeynes@103
   283
	render_addr = (render_addr & 0x00FFFFFF) + PVR2_RAM_BASE;
nkeynes@103
   284
	render_to_tex = FALSE;
nkeynes@103
   285
    }
nkeynes@128
   286
    
nkeynes@191
   287
    float bgplanez = MMIO_READF( PVR2, RENDER_FARCLIP );
nkeynes@191
   288
    uint32_t render_mode = MMIO_READ( PVR2, RENDER_MODE );
nkeynes@103
   289
    int width = 640; /* FIXME - get this from the tile buffer */
nkeynes@103
   290
    int height = 480;
nkeynes@103
   291
    int colour_format = pvr2_render_colour_format[render_mode&0x07];
nkeynes@103
   292
    pvr2_render_prepare_context( render_addr, width, height, colour_format, 
nkeynes@128
   293
				 bgplanez, render_to_tex );
nkeynes@103
   294
nkeynes@191
   295
    int clip_x = MMIO_READ( PVR2, RENDER_HCLIP ) & 0x03FF;
nkeynes@191
   296
    int clip_y = MMIO_READ( PVR2, RENDER_VCLIP ) & 0x03FF;
nkeynes@191
   297
    int clip_width = ((MMIO_READ( PVR2, RENDER_HCLIP ) >> 16) & 0x03FF) - clip_x + 1;
nkeynes@191
   298
    int clip_height= ((MMIO_READ( PVR2, RENDER_VCLIP ) >> 16) & 0x03FF) - clip_y + 1;
nkeynes@103
   299
nkeynes@103
   300
    /* Fog setup goes here */
nkeynes@103
   301
nkeynes@128
   302
    /* Render the background plane */
nkeynes@191
   303
    uint32_t bgplane_mode = MMIO_READ(PVR2, RENDER_BGPLANE);
nkeynes@189
   304
    uint32_t *display_list = 
nkeynes@191
   305
	(uint32_t *)mem_get_region(PVR2_RAM_BASE + MMIO_READ( PVR2, RENDER_POLYBASE ));
nkeynes@189
   306
nkeynes@189
   307
    uint32_t *bgplane = display_list + (((bgplane_mode & 0x00FFFFFF)) >> 3) ;
nkeynes@128
   308
    pvr2_render_draw_backplane( bgplane_mode, bgplane );
nkeynes@128
   309
nkeynes@189
   310
    pvr2_render_tilebuffer( width, height, clip_x, clip_y, 
nkeynes@189
   311
			    clip_x + clip_width, clip_y + clip_height );
nkeynes@103
   312
nkeynes@103
   313
    /* Post-render cleanup and update */
nkeynes@103
   314
nkeynes@108
   315
    /* Add frame, fps, etc data */
nkeynes@189
   316
    //glDrawGrid( width, height );
nkeynes@132
   317
    glPrintf( 4, 16, "Frame %d", pvr2_get_frame_count() );
nkeynes@103
   318
    /* Generate end of render event */
nkeynes@100
   319
    asic_event( EVENT_PVR_RENDER_DONE );
nkeynes@132
   320
    DEBUG( "Rendered frame %d", pvr2_get_frame_count() );
nkeynes@100
   321
}
nkeynes@103
   322
nkeynes@103
   323
nkeynes@103
   324
/**
nkeynes@103
   325
 * Flush the indicated render buffer back to PVR. Caller is responsible for
nkeynes@103
   326
 * tracking whether there is actually anything in the buffer.
nkeynes@103
   327
 *
nkeynes@103
   328
 * @param buffer A render buffer indicating the address to store to, and the
nkeynes@103
   329
 * format the data needs to be in.
nkeynes@103
   330
 * @param backBuffer TRUE to flush the back buffer, FALSE for 
nkeynes@103
   331
 * the front buffer.
nkeynes@103
   332
 */
nkeynes@103
   333
void pvr2_render_copy_to_sh4( pvr2_render_buffer_t buffer, 
nkeynes@103
   334
			      gboolean backBuffer )
nkeynes@103
   335
{
nkeynes@103
   336
    if( buffer->render_addr == -1 )
nkeynes@103
   337
	return;
nkeynes@103
   338
    GLenum type, format = GL_RGBA;
nkeynes@103
   339
    int size = buffer->width * buffer->height;
nkeynes@103
   340
nkeynes@103
   341
    switch( buffer->colour_format ) {
nkeynes@103
   342
    case COLFMT_RGB565: 
nkeynes@103
   343
	type = GL_UNSIGNED_SHORT_5_6_5; 
nkeynes@103
   344
	format = GL_RGB; 
nkeynes@103
   345
	size <<= 1;
nkeynes@103
   346
	break;
nkeynes@103
   347
    case COLFMT_RGB888: 
nkeynes@103
   348
	type = GL_UNSIGNED_INT; 
nkeynes@103
   349
	format = GL_RGB;
nkeynes@103
   350
	size = (size<<1)+size;
nkeynes@103
   351
	break;
nkeynes@103
   352
    case COLFMT_ARGB1555: 
nkeynes@103
   353
	type = GL_UNSIGNED_SHORT_5_5_5_1; 
nkeynes@103
   354
	size <<= 1;
nkeynes@103
   355
	break;
nkeynes@103
   356
    case COLFMT_ARGB4444: 
nkeynes@103
   357
	type = GL_UNSIGNED_SHORT_4_4_4_4; 
nkeynes@103
   358
	size <<= 1;
nkeynes@103
   359
	break;
nkeynes@103
   360
    case COLFMT_ARGB8888: 
nkeynes@103
   361
	type = GL_UNSIGNED_INT_8_8_8_8; 
nkeynes@103
   362
	size <<= 2;
nkeynes@103
   363
	break;
nkeynes@103
   364
    }
nkeynes@103
   365
    
nkeynes@103
   366
    if( backBuffer ) {
nkeynes@103
   367
	glFinish();
nkeynes@103
   368
	glReadBuffer( GL_BACK );
nkeynes@103
   369
    } else {
nkeynes@103
   370
	glReadBuffer( GL_FRONT );
nkeynes@103
   371
    }
nkeynes@103
   372
nkeynes@103
   373
    if( buffer->render_addr & 0xFF000000 == 0x04000000 ) {
nkeynes@103
   374
	/* Interlaced buffer. Go the double copy... :( */
nkeynes@103
   375
	char target[size];
nkeynes@103
   376
	glReadPixels( 0, 0, buffer->width, buffer->height, format, type, target );
nkeynes@103
   377
	pvr2_vram64_write( buffer->render_addr, target, size );
nkeynes@103
   378
    } else {
nkeynes@103
   379
	/* Regular buffer - go direct */
nkeynes@103
   380
	char *target = mem_get_region( buffer->render_addr );
nkeynes@103
   381
	glReadPixels( 0, 0, buffer->width, buffer->height, format, type, target );
nkeynes@103
   382
    }
nkeynes@103
   383
}
nkeynes@103
   384
nkeynes@103
   385
nkeynes@103
   386
/**
nkeynes@103
   387
 * Copy data from PVR ram into the GL render buffer. 
nkeynes@103
   388
 *
nkeynes@103
   389
 * @param buffer A render buffer indicating the address to read from, and the
nkeynes@103
   390
 * format the data is in.
nkeynes@103
   391
 * @param backBuffer TRUE to write the back buffer, FALSE for 
nkeynes@103
   392
 * the front buffer.
nkeynes@103
   393
 */
nkeynes@103
   394
void pvr2_render_copy_from_sh4( pvr2_render_buffer_t buffer, 
nkeynes@103
   395
				gboolean backBuffer )
nkeynes@103
   396
{
nkeynes@103
   397
    if( buffer->render_addr == -1 )
nkeynes@103
   398
	return;
nkeynes@103
   399
    GLenum type, format = GL_RGBA;
nkeynes@103
   400
    int size = buffer->width * buffer->height;
nkeynes@103
   401
nkeynes@103
   402
    switch( buffer->colour_format ) {
nkeynes@103
   403
    case COLFMT_RGB565: 
nkeynes@103
   404
	type = GL_UNSIGNED_SHORT_5_6_5; 
nkeynes@103
   405
	format = GL_RGB; 
nkeynes@103
   406
	size <<= 1;
nkeynes@103
   407
	break;
nkeynes@103
   408
    case COLFMT_RGB888: 
nkeynes@103
   409
	type = GL_UNSIGNED_INT; 
nkeynes@103
   410
	format = GL_RGB;
nkeynes@103
   411
	size = (size<<1)+size;
nkeynes@103
   412
	break;
nkeynes@103
   413
    case COLFMT_ARGB1555: 
nkeynes@103
   414
	type = GL_UNSIGNED_SHORT_5_5_5_1; 
nkeynes@103
   415
	size <<= 1;
nkeynes@103
   416
	break;
nkeynes@103
   417
    case COLFMT_ARGB4444: 
nkeynes@103
   418
	type = GL_UNSIGNED_SHORT_4_4_4_4; 
nkeynes@103
   419
	size <<= 1;
nkeynes@103
   420
	break;
nkeynes@103
   421
    case COLFMT_ARGB8888: 
nkeynes@103
   422
	type = GL_UNSIGNED_INT_8_8_8_8; 
nkeynes@103
   423
	size <<= 2;
nkeynes@103
   424
	break;
nkeynes@103
   425
    }
nkeynes@103
   426
    
nkeynes@103
   427
    if( backBuffer ) {
nkeynes@103
   428
	glDrawBuffer( GL_BACK );
nkeynes@103
   429
    } else {
nkeynes@103
   430
	glDrawBuffer( GL_FRONT );
nkeynes@103
   431
    }
nkeynes@103
   432
nkeynes@103
   433
    glRasterPos2i( 0, 0 );
nkeynes@103
   434
    if( buffer->render_addr & 0xFF000000 == 0x04000000 ) {
nkeynes@103
   435
	/* Interlaced buffer. Go the double copy... :( */
nkeynes@103
   436
	char target[size];
nkeynes@103
   437
	pvr2_vram64_read( target, buffer->render_addr, size );
nkeynes@103
   438
	glDrawPixels( buffer->width, buffer->height, 
nkeynes@103
   439
		      format, type, target );
nkeynes@103
   440
    } else {
nkeynes@103
   441
	/* Regular buffer - go direct */
nkeynes@103
   442
	char *target = mem_get_region( buffer->render_addr );
nkeynes@103
   443
	glDrawPixels( buffer->width, buffer->height, 
nkeynes@103
   444
		      format, type, target );
nkeynes@103
   445
    }
nkeynes@103
   446
}
.