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