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