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