Search
lxdream.org :: lxdream/src/pvr2/render.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/pvr2/render.c
changeset 103:9b9cfc5855e0
prev100:995e42e96cc9
next108:565de331ccec
author nkeynes
date Mon Mar 13 12:39:07 2006 +0000 (14 years ago)
permissions -rw-r--r--
last change More rendering work in progress. Almost there now...
file annotate diff log raw
nkeynes@100
     1
/**
nkeynes@103
     2
 * $Id: render.c,v 1.2 2006-03-13 12:39:07 nkeynes Exp $
nkeynes@100
     3
 *
nkeynes@100
     4
 * PVR2 Renderer support. This is where the real work happens.
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
nkeynes@103
    23
#define POLY_COLOUR_ARGB8888 0x00000000
nkeynes@103
    24
#define POLY_COLOUR_ARGBFLOAT 0x00000010
nkeynes@103
    25
nkeynes@103
    26
static int pvr2_poly_vertexes[4] = { 3, 4, 6, 8 };
nkeynes@103
    27
static int pvr2_poly_type[4] = { GL_TRIANGLES, GL_QUADS, GL_TRIANGLE_STRIP, GL_TRIANGLE_STRIP };
nkeynes@103
    28
static int pvr2_poly_depthmode[8] = { GL_NEVER, GL_LESS, GL_EQUAL, GL_LEQUAL,
nkeynes@103
    29
				      GL_GREATER, GL_NOTEQUAL, GL_GEQUAL, 
nkeynes@103
    30
				      GL_ALWAYS };
nkeynes@103
    31
static int pvr2_poly_srcblend[8] = { 
nkeynes@103
    32
    GL_ZERO, GL_ONE, GL_DST_COLOR, GL_ONE_MINUS_DST_COLOR,
nkeynes@103
    33
    GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_DST_ALPHA, 
nkeynes@103
    34
    GL_ONE_MINUS_DST_ALPHA };
nkeynes@103
    35
static int pvr2_poly_dstblend[8] = {
nkeynes@103
    36
    GL_ZERO, GL_ONE, GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR,
nkeynes@103
    37
    GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_DST_ALPHA,
nkeynes@103
    38
    GL_ONE_MINUS_DST_ALPHA };
nkeynes@103
    39
static int pvr2_render_colour_format[8] = {
nkeynes@103
    40
    COLFMT_ARGB1555, COLFMT_RGB565, COLFMT_ARGB4444, COLFMT_ARGB1555,
nkeynes@103
    41
    COLFMT_RGB888, COLFMT_ARGB8888, COLFMT_ARGB8888, COLFMT_ARGB4444 };
nkeynes@103
    42
nkeynes@103
    43
#define POLY_STRIP_TYPE(poly) ( pvr2_poly_type[((poly->command)>>18)&0x03] )
nkeynes@103
    44
#define POLY_STRIP_VERTEXES(poly) ( pvr2_poly_vertexes[((poly->command)>>18)&0x03] )
nkeynes@103
    45
#define POLY_DEPTH_MODE(poly) ( pvr2_poly_depthmode[poly->poly_cfg>>29] )
nkeynes@103
    46
#define POLY_DEPTH_WRITE(poly) (poly->poly_cfg&0x04000000)
nkeynes@103
    47
#define POLY_TEX_WIDTH(poly) ( 1<< (((poly->poly_mode >> 3) & 0x07 ) + 3) )
nkeynes@103
    48
#define POLY_TEX_HEIGHT(poly) ( 1<< (((poly->poly_mode) & 0x07 ) + 3) )
nkeynes@103
    49
#define POLY_BLEND_SRC(poly) ( pvr2_poly_srcblend[(poly->poly_mode) >> 29] )
nkeynes@103
    50
#define POLY_BLEND_DEST(poly) ( pvr2_poly_dstblend[((poly->poly_mode)>>26)&0x07] )
nkeynes@100
    51
nkeynes@100
    52
extern uint32_t pvr2_frame_counter;
nkeynes@100
    53
nkeynes@100
    54
/**
nkeynes@103
    55
 * Describes a rendering buffer that's actually held in GL, for when we need
nkeynes@103
    56
 * to fetch the bits back to vram.
nkeynes@103
    57
 */
nkeynes@103
    58
typedef struct pvr2_render_buffer {
nkeynes@103
    59
    uint32_t render_addr; /* The actual address rendered to in pvr ram */
nkeynes@103
    60
    int width, height;
nkeynes@103
    61
    int colour_format;
nkeynes@103
    62
} *pvr2_render_buffer_t;
nkeynes@103
    63
nkeynes@103
    64
struct pvr2_render_buffer front_buffer;
nkeynes@103
    65
struct pvr2_render_buffer back_buffer;
nkeynes@103
    66
nkeynes@103
    67
struct tile_descriptor {
nkeynes@103
    68
    uint32_t header[6];
nkeynes@103
    69
    struct tile_pointers {
nkeynes@103
    70
	uint32_t tile_id;
nkeynes@103
    71
	uint32_t opaque_ptr;
nkeynes@103
    72
	uint32_t opaque_mod_ptr;
nkeynes@103
    73
	uint32_t trans_ptr;
nkeynes@103
    74
	uint32_t trans_mod_ptr;
nkeynes@103
    75
	uint32_t punchout_ptr;
nkeynes@103
    76
    } tile[0];
nkeynes@103
    77
};
nkeynes@103
    78
nkeynes@103
    79
/* Textured polygon */
nkeynes@103
    80
struct pvr2_poly {
nkeynes@103
    81
    uint32_t command;
nkeynes@103
    82
    uint32_t poly_cfg; /* Bitmask */
nkeynes@103
    83
    uint32_t poly_mode; /* texture/blending mask */
nkeynes@103
    84
    uint32_t texture; /* texture data */
nkeynes@103
    85
    float alpha;
nkeynes@103
    86
    float red;
nkeynes@103
    87
    float green;
nkeynes@103
    88
    float blue;
nkeynes@103
    89
};
nkeynes@103
    90
nkeynes@103
    91
struct pvr2_specular_highlight {
nkeynes@103
    92
    float base_alpha;
nkeynes@103
    93
    float base_red;
nkeynes@103
    94
    float base_green;
nkeynes@103
    95
    float base_blue;
nkeynes@103
    96
    float offset_alpha;
nkeynes@103
    97
    float offset_red;
nkeynes@103
    98
    float offset_green;
nkeynes@103
    99
    float offset_blue;
nkeynes@103
   100
};
nkeynes@103
   101
				     
nkeynes@103
   102
nkeynes@103
   103
struct pvr2_vertex_basic {
nkeynes@103
   104
    uint32_t command;
nkeynes@103
   105
    float x, y, z;
nkeynes@103
   106
    float s,t;
nkeynes@103
   107
    uint32_t col;
nkeynes@103
   108
    float f;
nkeynes@103
   109
};
nkeynes@103
   110
nkeynes@103
   111
nkeynes@103
   112
void pvr2_render_copy_to_sh4( pvr2_render_buffer_t buffer, 
nkeynes@103
   113
			      gboolean backBuffer );
nkeynes@103
   114
nkeynes@103
   115
nkeynes@103
   116
gboolean pvr2_render_init( void )
nkeynes@103
   117
{
nkeynes@103
   118
    front_buffer.render_addr = -1;
nkeynes@103
   119
    back_buffer.render_addr = -1;
nkeynes@103
   120
}
nkeynes@103
   121
nkeynes@103
   122
/**
nkeynes@103
   123
 * Display a rendered frame if one is available.
nkeynes@103
   124
 * @param address An address in PVR ram (0500000 range).
nkeynes@103
   125
 * @return TRUE if a frame was available to be displayed, otherwise false.
nkeynes@103
   126
 */
nkeynes@103
   127
gboolean pvr2_render_display_frame( uint32_t address )
nkeynes@103
   128
{
nkeynes@103
   129
    if( front_buffer.render_addr == address ) {
nkeynes@103
   130
	/* Current front buffer is already displayed, so do nothing
nkeynes@103
   131
	 * and tell the caller that all is well.
nkeynes@103
   132
	 */
nkeynes@103
   133
	return TRUE;
nkeynes@103
   134
    }
nkeynes@103
   135
    if( back_buffer.render_addr == address ) {
nkeynes@103
   136
	/* The more useful case - back buffer is to be displayed. Swap
nkeynes@103
   137
	 * the buffers 
nkeynes@103
   138
	 */
nkeynes@103
   139
	video_driver->display_back_buffer();
nkeynes@103
   140
	front_buffer = back_buffer;
nkeynes@103
   141
	back_buffer.render_addr = -1;
nkeynes@103
   142
	return TRUE;
nkeynes@103
   143
    }
nkeynes@103
   144
    return FALSE;
nkeynes@103
   145
}
nkeynes@103
   146
nkeynes@103
   147
/**
nkeynes@103
   148
 * Prepare the OpenGL context to receive instructions for a new frame.
nkeynes@103
   149
 */
nkeynes@103
   150
static void pvr2_render_prepare_context( sh4addr_t render_addr, 
nkeynes@103
   151
					 uint32_t width, uint32_t height,
nkeynes@103
   152
					 uint32_t colour_format, 
nkeynes@103
   153
					 gboolean texture_target )
nkeynes@103
   154
{
nkeynes@103
   155
    /* Select and initialize the render context */
nkeynes@103
   156
    video_driver->set_render_format( width, height, colour_format, texture_target );
nkeynes@103
   157
nkeynes@103
   158
    if( back_buffer.render_addr != -1 && 
nkeynes@103
   159
	back_buffer.render_addr != render_addr ) {
nkeynes@103
   160
	/* There's a current back buffer, and we're rendering somewhere else -
nkeynes@103
   161
	 * flush the back buffer back to vram and start a new back buffer
nkeynes@103
   162
	 */
nkeynes@103
   163
	pvr2_render_copy_to_sh4( &back_buffer, TRUE );
nkeynes@103
   164
    }
nkeynes@103
   165
nkeynes@103
   166
    if( front_buffer.render_addr == render_addr ) {
nkeynes@103
   167
	/* In case we've been asked to render to the current front buffer -
nkeynes@103
   168
	 * invalidate the front buffer and render to the back buffer, ensuring
nkeynes@103
   169
	 * we swap at the next frame display.
nkeynes@103
   170
	 */
nkeynes@103
   171
	front_buffer.render_addr = -1;
nkeynes@103
   172
    }
nkeynes@103
   173
    back_buffer.render_addr = render_addr;
nkeynes@103
   174
    back_buffer.width = width;
nkeynes@103
   175
    back_buffer.height = height;
nkeynes@103
   176
    back_buffer.colour_format = colour_format;
nkeynes@103
   177
nkeynes@103
   178
    /* Setup the display model */
nkeynes@103
   179
    glDrawBuffer(GL_BACK);
nkeynes@103
   180
    glShadeModel(GL_SMOOTH);
nkeynes@103
   181
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
nkeynes@103
   182
    glViewport( 0, 0, width, height );
nkeynes@103
   183
    glMatrixMode(GL_PROJECTION);
nkeynes@103
   184
    glLoadIdentity();
nkeynes@103
   185
    glOrtho( 0, width, height, 0, 0, 65535 );
nkeynes@103
   186
    glMatrixMode(GL_MODELVIEW);
nkeynes@103
   187
    glLoadIdentity();
nkeynes@103
   188
nkeynes@103
   189
    /* Clear out the buffers */
nkeynes@103
   190
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
nkeynes@103
   191
    glClearDepth(1.0f);
nkeynes@103
   192
    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
nkeynes@103
   193
}
nkeynes@103
   194
nkeynes@103
   195
static void pvr2_render_display_list( uint32_t *display_list, uint32_t length )
nkeynes@103
   196
{
nkeynes@103
   197
    uint32_t *cmd_ptr = display_list;
nkeynes@103
   198
    int expect_vertexes = 0;
nkeynes@103
   199
    gboolean textured = FALSE;
nkeynes@103
   200
    struct pvr2_poly *poly;
nkeynes@103
   201
    while( cmd_ptr < display_list+length ) {
nkeynes@103
   202
	switch( *cmd_ptr >> 24 ) {
nkeynes@103
   203
	case PVR2_CMD_POLY_OPAQUE:
nkeynes@103
   204
	    poly = (struct pvr2_poly *)cmd_ptr;
nkeynes@103
   205
	    
nkeynes@103
   206
	    if( poly->command & PVR2_POLY_TEXTURED ) {
nkeynes@103
   207
		uint32_t addr = PVR2_TEX_ADDR(poly->texture);
nkeynes@103
   208
		int width = POLY_TEX_WIDTH(poly);
nkeynes@103
   209
		int height = POLY_TEX_HEIGHT(poly);
nkeynes@103
   210
		texcache_get_texture( addr, width, height, poly->texture );
nkeynes@103
   211
		textured = TRUE;
nkeynes@103
   212
		glEnable( GL_TEXTURE_2D );
nkeynes@103
   213
	    } else {
nkeynes@103
   214
		textured = FALSE;
nkeynes@103
   215
		glDisable( GL_TEXTURE_2D );
nkeynes@103
   216
	    }
nkeynes@103
   217
	    glBlendFunc( POLY_BLEND_SRC(poly), POLY_BLEND_DEST(poly) );
nkeynes@103
   218
	    if( poly->command & PVR2_POLY_SPECULAR ) {
nkeynes@103
   219
		/* Second block expected */
nkeynes@103
   220
	    }
nkeynes@103
   221
	    if( POLY_DEPTH_WRITE(poly) ) {
nkeynes@103
   222
		glEnable( GL_DEPTH_TEST );
nkeynes@103
   223
		glDepthFunc( POLY_DEPTH_MODE(poly) );
nkeynes@103
   224
	    } else {
nkeynes@103
   225
		glDisable( GL_DEPTH_TEST );
nkeynes@103
   226
	    }
nkeynes@103
   227
nkeynes@103
   228
	    expect_vertexes = POLY_STRIP_VERTEXES( poly );
nkeynes@103
   229
	    if( expect_vertexes == 3 )
nkeynes@103
   230
		glBegin( GL_TRIANGLES );
nkeynes@103
   231
	    else if( expect_vertexes == 4 )
nkeynes@103
   232
		glBegin( GL_QUADS );
nkeynes@103
   233
	    else 
nkeynes@103
   234
		glBegin( GL_TRIANGLE_STRIP );
nkeynes@103
   235
	    break;
nkeynes@103
   236
	case PVR2_CMD_VERTEX_LAST:
nkeynes@103
   237
	case PVR2_CMD_VERTEX:
nkeynes@103
   238
	    if( expect_vertexes == 0 ) {
nkeynes@103
   239
		ERROR( "Unexpected vertex!" );
nkeynes@103
   240
		return;
nkeynes@103
   241
	    }
nkeynes@103
   242
	    expect_vertexes--;
nkeynes@103
   243
	    struct pvr2_vertex_basic *vertex = (struct pvr2_vertex_basic *)cmd_ptr;
nkeynes@103
   244
	    if( textured ) {
nkeynes@103
   245
		glTexCoord2f( vertex->s, vertex->t );
nkeynes@103
   246
	    }
nkeynes@103
   247
	    glVertex3f( vertex->x, vertex->y, vertex->z );
nkeynes@103
   248
	    
nkeynes@103
   249
	    if( expect_vertexes == 0 )
nkeynes@103
   250
		glEnd();
nkeynes@103
   251
	    break;
nkeynes@103
   252
	}
nkeynes@103
   253
	cmd_ptr += 8; /* Next record */
nkeynes@103
   254
    }
nkeynes@103
   255
}
nkeynes@103
   256
nkeynes@103
   257
/**
nkeynes@103
   258
 * Render a complete scene into the OpenGL back buffer.
nkeynes@103
   259
 * Note: this will probably need to be broken up eventually once timings are
nkeynes@100
   260
 * determined.
nkeynes@100
   261
 */
nkeynes@103
   262
void pvr2_render_scene( )
nkeynes@100
   263
{
nkeynes@103
   264
    struct tile_descriptor *tile_desc =
nkeynes@103
   265
	(struct tile_descriptor *)mem_get_region(PVR2_RAM_BASE + MMIO_READ( PVR2, TILEBASE ));
nkeynes@100
   266
nkeynes@103
   267
    uint32_t render_addr = MMIO_READ( PVR2, RENDADDR1 );
nkeynes@103
   268
    gboolean render_to_tex;
nkeynes@103
   269
    if( render_addr & 0x01000000 ) {
nkeynes@103
   270
	render_addr = (render_addr & 0x00FFFFFF) + PVR2_RAM_BASE_INT;
nkeynes@103
   271
	/* Heuristic - if we're rendering to the interlaced region we're
nkeynes@103
   272
	 * probably creating a texture rather than rendering actual output.
nkeynes@103
   273
	 * We can optimise for this case a little
nkeynes@103
   274
	 */
nkeynes@103
   275
	render_to_tex = TRUE;
nkeynes@103
   276
    } else {
nkeynes@103
   277
	render_addr = (render_addr & 0x00FFFFFF) + PVR2_RAM_BASE;
nkeynes@103
   278
	render_to_tex = FALSE;
nkeynes@103
   279
    }
nkeynes@103
   280
    uint32_t render_mode = MMIO_READ( PVR2, RENDMODE );
nkeynes@103
   281
    int width = 640; /* FIXME - get this from the tile buffer */
nkeynes@103
   282
    int height = 480;
nkeynes@103
   283
    int colour_format = pvr2_render_colour_format[render_mode&0x07];
nkeynes@103
   284
    pvr2_render_prepare_context( render_addr, width, height, colour_format, 
nkeynes@103
   285
				 render_to_tex );
nkeynes@103
   286
nkeynes@103
   287
    uint32_t *display_list = 
nkeynes@103
   288
	(uint32_t *)mem_get_region(PVR2_RAM_BASE + MMIO_READ( PVR2, OBJBASE ));
nkeynes@103
   289
    uint32_t display_length = *display_list++;
nkeynes@103
   290
nkeynes@103
   291
    int clip_x = MMIO_READ( PVR2, HCLIP ) & 0x03FF;
nkeynes@103
   292
    int clip_y = MMIO_READ( PVR2, VCLIP ) & 0x03FF;
nkeynes@103
   293
    int clip_width = ((MMIO_READ( PVR2, HCLIP ) >> 16) & 0x03FF) - clip_x + 1;
nkeynes@103
   294
    int clip_height= ((MMIO_READ( PVR2, VCLIP ) >> 16) & 0x03FF) - clip_y + 1;
nkeynes@103
   295
nkeynes@103
   296
    if( clip_x == 0 && clip_y == 0 && clip_width == width && clip_height == height ) {
nkeynes@103
   297
	glDisable( GL_SCISSOR_TEST );
nkeynes@103
   298
    } else {
nkeynes@103
   299
	glEnable( GL_SCISSOR_TEST );
nkeynes@103
   300
	glScissor( clip_x, clip_y, clip_width, clip_height );
nkeynes@103
   301
    }
nkeynes@103
   302
nkeynes@103
   303
    /* Fog setup goes here */
nkeynes@103
   304
nkeynes@103
   305
    /* Render the display list */
nkeynes@103
   306
    pvr2_render_display_list( display_list, display_length );
nkeynes@103
   307
nkeynes@103
   308
    /* Post-render cleanup and update */
nkeynes@103
   309
nkeynes@103
   310
    
nkeynes@103
   311
    /* Generate end of render event */
nkeynes@100
   312
    asic_event( EVENT_PVR_RENDER_DONE );
nkeynes@100
   313
    DEBUG( "Rendered frame %d", pvr2_frame_counter );
nkeynes@100
   314
}
nkeynes@103
   315
nkeynes@103
   316
nkeynes@103
   317
/**
nkeynes@103
   318
 * Flush the indicated render buffer back to PVR. Caller is responsible for
nkeynes@103
   319
 * tracking whether there is actually anything in the buffer.
nkeynes@103
   320
 *
nkeynes@103
   321
 * @param buffer A render buffer indicating the address to store to, and the
nkeynes@103
   322
 * format the data needs to be in.
nkeynes@103
   323
 * @param backBuffer TRUE to flush the back buffer, FALSE for 
nkeynes@103
   324
 * the front buffer.
nkeynes@103
   325
 */
nkeynes@103
   326
void pvr2_render_copy_to_sh4( pvr2_render_buffer_t buffer, 
nkeynes@103
   327
			      gboolean backBuffer )
nkeynes@103
   328
{
nkeynes@103
   329
    if( buffer->render_addr == -1 )
nkeynes@103
   330
	return;
nkeynes@103
   331
    GLenum type, format = GL_RGBA;
nkeynes@103
   332
    int size = buffer->width * buffer->height;
nkeynes@103
   333
nkeynes@103
   334
    switch( buffer->colour_format ) {
nkeynes@103
   335
    case COLFMT_RGB565: 
nkeynes@103
   336
	type = GL_UNSIGNED_SHORT_5_6_5; 
nkeynes@103
   337
	format = GL_RGB; 
nkeynes@103
   338
	size <<= 1;
nkeynes@103
   339
	break;
nkeynes@103
   340
    case COLFMT_RGB888: 
nkeynes@103
   341
	type = GL_UNSIGNED_INT; 
nkeynes@103
   342
	format = GL_RGB;
nkeynes@103
   343
	size = (size<<1)+size;
nkeynes@103
   344
	break;
nkeynes@103
   345
    case COLFMT_ARGB1555: 
nkeynes@103
   346
	type = GL_UNSIGNED_SHORT_5_5_5_1; 
nkeynes@103
   347
	size <<= 1;
nkeynes@103
   348
	break;
nkeynes@103
   349
    case COLFMT_ARGB4444: 
nkeynes@103
   350
	type = GL_UNSIGNED_SHORT_4_4_4_4; 
nkeynes@103
   351
	size <<= 1;
nkeynes@103
   352
	break;
nkeynes@103
   353
    case COLFMT_ARGB8888: 
nkeynes@103
   354
	type = GL_UNSIGNED_INT_8_8_8_8; 
nkeynes@103
   355
	size <<= 2;
nkeynes@103
   356
	break;
nkeynes@103
   357
    }
nkeynes@103
   358
    
nkeynes@103
   359
    if( backBuffer ) {
nkeynes@103
   360
	glFinish();
nkeynes@103
   361
	glReadBuffer( GL_BACK );
nkeynes@103
   362
    } else {
nkeynes@103
   363
	glReadBuffer( GL_FRONT );
nkeynes@103
   364
    }
nkeynes@103
   365
nkeynes@103
   366
    if( buffer->render_addr & 0xFF000000 == 0x04000000 ) {
nkeynes@103
   367
	/* Interlaced buffer. Go the double copy... :( */
nkeynes@103
   368
	char target[size];
nkeynes@103
   369
	glReadPixels( 0, 0, buffer->width, buffer->height, format, type, target );
nkeynes@103
   370
	pvr2_vram64_write( buffer->render_addr, target, size );
nkeynes@103
   371
    } else {
nkeynes@103
   372
	/* Regular buffer - go direct */
nkeynes@103
   373
	char *target = mem_get_region( buffer->render_addr );
nkeynes@103
   374
	glReadPixels( 0, 0, buffer->width, buffer->height, format, type, target );
nkeynes@103
   375
    }
nkeynes@103
   376
}
nkeynes@103
   377
nkeynes@103
   378
nkeynes@103
   379
/**
nkeynes@103
   380
 * Copy data from PVR ram into the GL render buffer. 
nkeynes@103
   381
 *
nkeynes@103
   382
 * @param buffer A render buffer indicating the address to read from, and the
nkeynes@103
   383
 * format the data is in.
nkeynes@103
   384
 * @param backBuffer TRUE to write the back buffer, FALSE for 
nkeynes@103
   385
 * the front buffer.
nkeynes@103
   386
 */
nkeynes@103
   387
void pvr2_render_copy_from_sh4( pvr2_render_buffer_t buffer, 
nkeynes@103
   388
				gboolean backBuffer )
nkeynes@103
   389
{
nkeynes@103
   390
    if( buffer->render_addr == -1 )
nkeynes@103
   391
	return;
nkeynes@103
   392
    GLenum type, format = GL_RGBA;
nkeynes@103
   393
    int size = buffer->width * buffer->height;
nkeynes@103
   394
nkeynes@103
   395
    switch( buffer->colour_format ) {
nkeynes@103
   396
    case COLFMT_RGB565: 
nkeynes@103
   397
	type = GL_UNSIGNED_SHORT_5_6_5; 
nkeynes@103
   398
	format = GL_RGB; 
nkeynes@103
   399
	size <<= 1;
nkeynes@103
   400
	break;
nkeynes@103
   401
    case COLFMT_RGB888: 
nkeynes@103
   402
	type = GL_UNSIGNED_INT; 
nkeynes@103
   403
	format = GL_RGB;
nkeynes@103
   404
	size = (size<<1)+size;
nkeynes@103
   405
	break;
nkeynes@103
   406
    case COLFMT_ARGB1555: 
nkeynes@103
   407
	type = GL_UNSIGNED_SHORT_5_5_5_1; 
nkeynes@103
   408
	size <<= 1;
nkeynes@103
   409
	break;
nkeynes@103
   410
    case COLFMT_ARGB4444: 
nkeynes@103
   411
	type = GL_UNSIGNED_SHORT_4_4_4_4; 
nkeynes@103
   412
	size <<= 1;
nkeynes@103
   413
	break;
nkeynes@103
   414
    case COLFMT_ARGB8888: 
nkeynes@103
   415
	type = GL_UNSIGNED_INT_8_8_8_8; 
nkeynes@103
   416
	size <<= 2;
nkeynes@103
   417
	break;
nkeynes@103
   418
    }
nkeynes@103
   419
    
nkeynes@103
   420
    if( backBuffer ) {
nkeynes@103
   421
	glDrawBuffer( GL_BACK );
nkeynes@103
   422
    } else {
nkeynes@103
   423
	glDrawBuffer( GL_FRONT );
nkeynes@103
   424
    }
nkeynes@103
   425
nkeynes@103
   426
    glRasterPos2i( 0, 0 );
nkeynes@103
   427
    if( buffer->render_addr & 0xFF000000 == 0x04000000 ) {
nkeynes@103
   428
	/* Interlaced buffer. Go the double copy... :( */
nkeynes@103
   429
	char target[size];
nkeynes@103
   430
	pvr2_vram64_read( target, buffer->render_addr, size );
nkeynes@103
   431
	glDrawPixels( buffer->width, buffer->height, 
nkeynes@103
   432
		      format, type, target );
nkeynes@103
   433
    } else {
nkeynes@103
   434
	/* Regular buffer - go direct */
nkeynes@103
   435
	char *target = mem_get_region( buffer->render_addr );
nkeynes@103
   436
	glDrawPixels( buffer->width, buffer->height, 
nkeynes@103
   437
		      format, type, target );
nkeynes@103
   438
    }
nkeynes@103
   439
}
.