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