Search
lxdream.org :: lxdream/src/pvr2/render.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/pvr2/render.c
changeset 322:354407942957
prev315:2d8ba198d62c
next331:a6048d3a9a79
author nkeynes
date Thu Jan 25 10:16:32 2007 +0000 (17 years ago)
permissions -rw-r--r--
last change Move PVR2 dma handling (0x10000000-0x13FFFFFF) into pvr2mem.c, minor
register cleanups in asic.c
file annotate diff log raw
nkeynes@100
     1
/**
nkeynes@322
     2
 * $Id: render.c,v 1.19 2007-01-25 08:18:03 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
nkeynes@103
    23
struct pvr2_render_buffer front_buffer;
nkeynes@103
    24
struct pvr2_render_buffer back_buffer;
nkeynes@103
    25
nkeynes@128
    26
typedef struct pvr2_bgplane_packed {
nkeynes@128
    27
        uint32_t        poly_cfg, poly_mode;
nkeynes@128
    28
        uint32_t        texture_mode;
nkeynes@128
    29
        float           x1, y1, z1;
nkeynes@128
    30
        uint32_t          colour1;
nkeynes@128
    31
        float           x2, y2, z2;
nkeynes@128
    32
        uint32_t          colour2;
nkeynes@128
    33
        float           x3, y3, z3;
nkeynes@128
    34
        uint32_t          colour3;
nkeynes@128
    35
} *pvr2_bgplane_packed_t;
nkeynes@128
    36
nkeynes@108
    37
int pvr2_render_font_list = -1;
nkeynes@132
    38
int pvr2_render_trace = 0;
nkeynes@108
    39
nkeynes@132
    40
int glPrintf( int x, int y, const char *fmt, ... )
nkeynes@108
    41
{
nkeynes@108
    42
    va_list ap;     /* our argument pointer */
nkeynes@108
    43
    char buf[256];
nkeynes@108
    44
    int len;
nkeynes@108
    45
    if (fmt == NULL)    /* if there is no string to draw do nothing */
nkeynes@108
    46
        return;
nkeynes@108
    47
    va_start(ap, fmt); 
nkeynes@108
    48
    len = vsnprintf(buf, sizeof(buf), fmt, ap);
nkeynes@108
    49
    va_end(ap);
nkeynes@108
    50
nkeynes@108
    51
nkeynes@108
    52
    glPushAttrib(GL_LIST_BIT);
nkeynes@132
    53
    glDisable( GL_DEPTH_TEST );
nkeynes@132
    54
    glDisable( GL_BLEND );
nkeynes@132
    55
    glDisable( GL_TEXTURE_2D );
nkeynes@132
    56
    glDisable( GL_ALPHA_TEST );
nkeynes@189
    57
    glDisable( GL_CULL_FACE );
nkeynes@108
    58
    glListBase(pvr2_render_font_list - 32);
nkeynes@132
    59
    glColor3f( 1.0, 1.0, 1.0 );
nkeynes@132
    60
    glRasterPos2i( x, y );
nkeynes@108
    61
    glCallLists(len, GL_UNSIGNED_BYTE, buf);
nkeynes@108
    62
    glPopAttrib();
nkeynes@108
    63
nkeynes@108
    64
    return len;
nkeynes@108
    65
}
nkeynes@108
    66
nkeynes@189
    67
void glDrawGrid( int width, int height )
nkeynes@189
    68
{
nkeynes@189
    69
    int i;
nkeynes@189
    70
    glDisable( GL_DEPTH_TEST );
nkeynes@189
    71
    glLineWidth(1);
nkeynes@189
    72
    
nkeynes@189
    73
    glBegin( GL_LINES );
nkeynes@189
    74
    glColor4f( 1.0, 1.0, 1.0, 1.0 );
nkeynes@189
    75
    for( i=32; i<width; i+=32 ) {
nkeynes@189
    76
	glVertex3f( i, 0.0, 3.0 );
nkeynes@189
    77
	glVertex3f( i,height-1, 3.0 );
nkeynes@189
    78
    }
nkeynes@189
    79
nkeynes@189
    80
    for( i=32; i<height; i+=32 ) {
nkeynes@189
    81
	glVertex3f( 0.0, i, 3.0 );
nkeynes@189
    82
	glVertex3f( width, i, 3.0 );
nkeynes@189
    83
    }
nkeynes@189
    84
    glEnd();
nkeynes@189
    85
	
nkeynes@189
    86
}
nkeynes@189
    87
nkeynes@103
    88
nkeynes@103
    89
gboolean pvr2_render_init( void )
nkeynes@103
    90
{
nkeynes@103
    91
    front_buffer.render_addr = -1;
nkeynes@103
    92
    back_buffer.render_addr = -1;
nkeynes@103
    93
}
nkeynes@103
    94
nkeynes@103
    95
/**
nkeynes@161
    96
 * Invalidate any caching on the supplied address. Specifically, if it falls
nkeynes@161
    97
 * within either the front buffer or back buffer, flush the buffer back to
nkeynes@161
    98
 * PVR2 ram (note that front buffer flush may be corrupt under some
nkeynes@161
    99
 * circumstances).
nkeynes@161
   100
 */
nkeynes@315
   101
gboolean pvr2_render_buffer_invalidate( sh4addr_t address )
nkeynes@161
   102
{
nkeynes@161
   103
    address = address & 0x1FFFFFFF;
nkeynes@161
   104
    if( front_buffer.render_addr != -1 &&
nkeynes@161
   105
	front_buffer.render_addr <= address &&
nkeynes@161
   106
	(front_buffer.render_addr + front_buffer.size) > address ) {
nkeynes@315
   107
	pvr2_render_buffer_copy_to_sh4( &front_buffer, FALSE );
nkeynes@161
   108
	front_buffer.render_addr = -1;
nkeynes@161
   109
	return TRUE;
nkeynes@161
   110
    } else if( back_buffer.render_addr != -1 &&
nkeynes@161
   111
	       back_buffer.render_addr <= address &&
nkeynes@161
   112
	       (back_buffer.render_addr + back_buffer.size) > address ) {
nkeynes@315
   113
	pvr2_render_buffer_copy_to_sh4( &back_buffer, TRUE );
nkeynes@161
   114
	back_buffer.render_addr = -1;
nkeynes@161
   115
	return TRUE;
nkeynes@161
   116
    }
nkeynes@161
   117
    return FALSE;
nkeynes@161
   118
}
nkeynes@161
   119
nkeynes@161
   120
/**
nkeynes@103
   121
 * Display a rendered frame if one is available.
nkeynes@103
   122
 * @param address An address in PVR ram (0500000 range).
nkeynes@103
   123
 * @return TRUE if a frame was available to be displayed, otherwise false.
nkeynes@103
   124
 */
nkeynes@103
   125
gboolean pvr2_render_display_frame( uint32_t address )
nkeynes@103
   126
{
nkeynes@103
   127
    if( front_buffer.render_addr == address ) {
nkeynes@103
   128
	/* Current front buffer is already displayed, so do nothing
nkeynes@103
   129
	 * and tell the caller that all is well.
nkeynes@103
   130
	 */
nkeynes@103
   131
	return TRUE;
nkeynes@103
   132
    }
nkeynes@103
   133
    if( back_buffer.render_addr == address ) {
nkeynes@103
   134
	/* The more useful case - back buffer is to be displayed. Swap
nkeynes@103
   135
	 * the buffers 
nkeynes@103
   136
	 */
nkeynes@144
   137
	display_driver->display_back_buffer();
nkeynes@103
   138
	front_buffer = back_buffer;
nkeynes@103
   139
	back_buffer.render_addr = -1;
nkeynes@103
   140
	return TRUE;
nkeynes@103
   141
    }
nkeynes@103
   142
    return FALSE;
nkeynes@108
   143
}	
nkeynes@103
   144
nkeynes@103
   145
/**
nkeynes@103
   146
 * Prepare the OpenGL context to receive instructions for a new frame.
nkeynes@103
   147
 */
nkeynes@103
   148
static void pvr2_render_prepare_context( sh4addr_t render_addr, 
nkeynes@103
   149
					 uint32_t width, uint32_t height,
nkeynes@103
   150
					 uint32_t colour_format, 
nkeynes@322
   151
					 float bgplanez, float nearz,
nkeynes@103
   152
					 gboolean texture_target )
nkeynes@103
   153
{
nkeynes@103
   154
    /* Select and initialize the render context */
nkeynes@144
   155
    display_driver->set_render_format( width, height, colour_format, texture_target );
nkeynes@103
   156
nkeynes@132
   157
    if( pvr2_render_font_list == -1 ) {
nkeynes@132
   158
	pvr2_render_font_list = video_glx_load_font( "-*-helvetica-*-r-normal--16-*-*-*-p-*-iso8859-1");
nkeynes@132
   159
    }
nkeynes@132
   160
nkeynes@103
   161
    if( back_buffer.render_addr != -1 && 
nkeynes@103
   162
	back_buffer.render_addr != render_addr ) {
nkeynes@103
   163
	/* There's a current back buffer, and we're rendering somewhere else -
nkeynes@103
   164
	 * flush the back buffer back to vram and start a new back buffer
nkeynes@103
   165
	 */
nkeynes@315
   166
	pvr2_render_buffer_copy_to_sh4( &back_buffer, TRUE );
nkeynes@103
   167
    }
nkeynes@103
   168
nkeynes@103
   169
    if( front_buffer.render_addr == render_addr ) {
nkeynes@103
   170
	/* In case we've been asked to render to the current front buffer -
nkeynes@103
   171
	 * invalidate the front buffer and render to the back buffer, ensuring
nkeynes@103
   172
	 * we swap at the next frame display.
nkeynes@103
   173
	 */
nkeynes@103
   174
	front_buffer.render_addr = -1;
nkeynes@103
   175
    }
nkeynes@103
   176
    back_buffer.render_addr = render_addr;
nkeynes@103
   177
    back_buffer.width = width;
nkeynes@103
   178
    back_buffer.height = height;
nkeynes@103
   179
    back_buffer.colour_format = colour_format;
nkeynes@161
   180
    back_buffer.size = width * height * colour_format_bytes[colour_format];
nkeynes@103
   181
nkeynes@103
   182
    /* Setup the display model */
nkeynes@103
   183
    glDrawBuffer(GL_BACK);
nkeynes@103
   184
    glShadeModel(GL_SMOOTH);
nkeynes@103
   185
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
nkeynes@103
   186
    glViewport( 0, 0, width, height );
nkeynes@103
   187
    glMatrixMode(GL_PROJECTION);
nkeynes@103
   188
    glLoadIdentity();
nkeynes@322
   189
    glOrtho( 0, width, height, 0, bgplanez, -(nearz+1) );
nkeynes@103
   190
    glMatrixMode(GL_MODELVIEW);
nkeynes@103
   191
    glLoadIdentity();
nkeynes@108
   192
    glCullFace( GL_BACK );
nkeynes@308
   193
    glEnable( GL_BLEND );
nkeynes@103
   194
nkeynes@103
   195
    /* Clear out the buffers */
nkeynes@189
   196
    glDisable( GL_SCISSOR_TEST );
nkeynes@103
   197
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
nkeynes@299
   198
    glClearDepth(0);
nkeynes@103
   199
    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
nkeynes@308
   200
nkeynes@103
   201
}
nkeynes@103
   202
nkeynes@128
   203
/**
nkeynes@103
   204
 * Render a complete scene into the OpenGL back buffer.
nkeynes@103
   205
 * Note: this will probably need to be broken up eventually once timings are
nkeynes@100
   206
 * determined.
nkeynes@100
   207
 */
nkeynes@103
   208
void pvr2_render_scene( )
nkeynes@100
   209
{
nkeynes@103
   210
    struct tile_descriptor *tile_desc =
nkeynes@191
   211
	(struct tile_descriptor *)mem_get_region(PVR2_RAM_BASE + MMIO_READ( PVR2, RENDER_TILEBASE ));
nkeynes@100
   212
nkeynes@191
   213
    uint32_t render_addr = MMIO_READ( PVR2, RENDER_ADDR1 );
nkeynes@103
   214
    gboolean render_to_tex;
nkeynes@103
   215
    if( render_addr & 0x01000000 ) {
nkeynes@103
   216
	render_addr = (render_addr & 0x00FFFFFF) + PVR2_RAM_BASE_INT;
nkeynes@103
   217
	/* Heuristic - if we're rendering to the interlaced region we're
nkeynes@103
   218
	 * probably creating a texture rather than rendering actual output.
nkeynes@103
   219
	 * We can optimise for this case a little
nkeynes@103
   220
	 */
nkeynes@103
   221
	render_to_tex = TRUE;
nkeynes@118
   222
	WARN( "Render to texture not supported properly yet" );
nkeynes@103
   223
    } else {
nkeynes@103
   224
	render_addr = (render_addr & 0x00FFFFFF) + PVR2_RAM_BASE;
nkeynes@103
   225
	render_to_tex = FALSE;
nkeynes@103
   226
    }
nkeynes@128
   227
    
nkeynes@191
   228
    float bgplanez = MMIO_READF( PVR2, RENDER_FARCLIP );
nkeynes@191
   229
    uint32_t render_mode = MMIO_READ( PVR2, RENDER_MODE );
nkeynes@103
   230
    int width = 640; /* FIXME - get this from the tile buffer */
nkeynes@103
   231
    int height = 480;
nkeynes@103
   232
    int colour_format = pvr2_render_colour_format[render_mode&0x07];
nkeynes@322
   233
    float maxz = pvr2_render_find_maximum_z();
nkeynes@103
   234
    pvr2_render_prepare_context( render_addr, width, height, colour_format, 
nkeynes@322
   235
				 bgplanez, maxz, render_to_tex );
nkeynes@103
   236
nkeynes@191
   237
    int clip_x = MMIO_READ( PVR2, RENDER_HCLIP ) & 0x03FF;
nkeynes@191
   238
    int clip_y = MMIO_READ( PVR2, RENDER_VCLIP ) & 0x03FF;
nkeynes@191
   239
    int clip_width = ((MMIO_READ( PVR2, RENDER_HCLIP ) >> 16) & 0x03FF) - clip_x + 1;
nkeynes@191
   240
    int clip_height= ((MMIO_READ( PVR2, RENDER_VCLIP ) >> 16) & 0x03FF) - clip_y + 1;
nkeynes@103
   241
nkeynes@103
   242
    /* Fog setup goes here */
nkeynes@103
   243
nkeynes@128
   244
    /* Render the background plane */
nkeynes@191
   245
    uint32_t bgplane_mode = MMIO_READ(PVR2, RENDER_BGPLANE);
nkeynes@189
   246
    uint32_t *display_list = 
nkeynes@191
   247
	(uint32_t *)mem_get_region(PVR2_RAM_BASE + MMIO_READ( PVR2, RENDER_POLYBASE ));
nkeynes@189
   248
nkeynes@189
   249
    uint32_t *bgplane = display_list + (((bgplane_mode & 0x00FFFFFF)) >> 3) ;
nkeynes@219
   250
    render_backplane( bgplane, width, height, bgplane_mode );
nkeynes@128
   251
nkeynes@189
   252
    pvr2_render_tilebuffer( width, height, clip_x, clip_y, 
nkeynes@189
   253
			    clip_x + clip_width, clip_y + clip_height );
nkeynes@103
   254
nkeynes@103
   255
    /* Post-render cleanup and update */
nkeynes@103
   256
nkeynes@108
   257
    /* Add frame, fps, etc data */
nkeynes@189
   258
    //glDrawGrid( width, height );
nkeynes@132
   259
    glPrintf( 4, 16, "Frame %d", pvr2_get_frame_count() );
nkeynes@103
   260
    /* Generate end of render event */
nkeynes@100
   261
    asic_event( EVENT_PVR_RENDER_DONE );
nkeynes@132
   262
    DEBUG( "Rendered frame %d", pvr2_get_frame_count() );
nkeynes@100
   263
}
.