Search
lxdream.org :: lxdream/src/pvr2/render.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/pvr2/render.c
changeset 221:cf5c6d326162
prev219:dfd3292143f2
next222:541d9d899aba
author nkeynes
date Tue Sep 12 08:38:38 2006 +0000 (13 years ago)
permissions -rw-r--r--
last change Bug #0010
Move polygon macros to pvr2.h
Implement background rendering more fully
view annotate diff log raw
     1 /**
     2  * $Id: render.c,v 1.14 2006-09-12 08:38:38 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 }
   217 #define MIN3( a,b,c ) ((a) < (b) ? ( (a) < (c) ? (a) : (c) ) : ((b) < (c) ? (b) : (c)) )
   218 #define MAX3( a,b,c ) ((a) > (b) ? ( (a) > (c) ? (a) : (c) ) : ((b) > (c) ? (b) : (c)) )
   220 /**
   221  * Render a complete scene into the OpenGL back buffer.
   222  * Note: this will probably need to be broken up eventually once timings are
   223  * determined.
   224  */
   225 void pvr2_render_scene( )
   226 {
   227     struct tile_descriptor *tile_desc =
   228 	(struct tile_descriptor *)mem_get_region(PVR2_RAM_BASE + MMIO_READ( PVR2, RENDER_TILEBASE ));
   230     uint32_t render_addr = MMIO_READ( PVR2, RENDER_ADDR1 );
   231     gboolean render_to_tex;
   232     if( render_addr & 0x01000000 ) {
   233 	render_addr = (render_addr & 0x00FFFFFF) + PVR2_RAM_BASE_INT;
   234 	/* Heuristic - if we're rendering to the interlaced region we're
   235 	 * probably creating a texture rather than rendering actual output.
   236 	 * We can optimise for this case a little
   237 	 */
   238 	render_to_tex = TRUE;
   239 	WARN( "Render to texture not supported properly yet" );
   240     } else {
   241 	render_addr = (render_addr & 0x00FFFFFF) + PVR2_RAM_BASE;
   242 	render_to_tex = FALSE;
   243     }
   245     float bgplanez = MMIO_READF( PVR2, RENDER_FARCLIP );
   246     uint32_t render_mode = MMIO_READ( PVR2, RENDER_MODE );
   247     int width = 640; /* FIXME - get this from the tile buffer */
   248     int height = 480;
   249     int colour_format = pvr2_render_colour_format[render_mode&0x07];
   250     pvr2_render_prepare_context( render_addr, width, height, colour_format, 
   251 				 bgplanez, render_to_tex );
   253     int clip_x = MMIO_READ( PVR2, RENDER_HCLIP ) & 0x03FF;
   254     int clip_y = MMIO_READ( PVR2, RENDER_VCLIP ) & 0x03FF;
   255     int clip_width = ((MMIO_READ( PVR2, RENDER_HCLIP ) >> 16) & 0x03FF) - clip_x + 1;
   256     int clip_height= ((MMIO_READ( PVR2, RENDER_VCLIP ) >> 16) & 0x03FF) - clip_y + 1;
   258     /* Fog setup goes here */
   260     /* Render the background plane */
   261     uint32_t bgplane_mode = MMIO_READ(PVR2, RENDER_BGPLANE);
   262     uint32_t *display_list = 
   263 	(uint32_t *)mem_get_region(PVR2_RAM_BASE + MMIO_READ( PVR2, RENDER_POLYBASE ));
   265     uint32_t *bgplane = display_list + (((bgplane_mode & 0x00FFFFFF)) >> 3) ;
   266     render_backplane( bgplane, width, height, bgplane_mode );
   268     pvr2_render_tilebuffer( width, height, clip_x, clip_y, 
   269 			    clip_x + clip_width, clip_y + clip_height );
   271     /* Post-render cleanup and update */
   273     /* Add frame, fps, etc data */
   274     //glDrawGrid( width, height );
   275     glPrintf( 4, 16, "Frame %d", pvr2_get_frame_count() );
   276     /* Generate end of render event */
   277     asic_event( EVENT_PVR_RENDER_DONE );
   278     DEBUG( "Rendered frame %d", pvr2_get_frame_count() );
   279 }
   282 /**
   283  * Flush the indicated render buffer back to PVR. Caller is responsible for
   284  * tracking whether there is actually anything in the buffer.
   285  *
   286  * @param buffer A render buffer indicating the address to store to, and the
   287  * format the data needs to be in.
   288  * @param backBuffer TRUE to flush the back buffer, FALSE for 
   289  * the front buffer.
   290  */
   291 void pvr2_render_copy_to_sh4( pvr2_render_buffer_t buffer, 
   292 			      gboolean backBuffer )
   293 {
   294     if( buffer->render_addr == -1 )
   295 	return;
   296     GLenum type, format = GL_RGBA;
   297     int line_size = buffer->width, size;
   299     switch( buffer->colour_format ) {
   300     case COLFMT_RGB565: 
   301 	type = GL_UNSIGNED_SHORT_5_6_5; 
   302 	format = GL_RGB; 
   303 	line_size <<= 1;
   304 	break;
   305     case COLFMT_RGB888: 
   306 	type = GL_UNSIGNED_INT; 
   307 	format = GL_RGB;
   308 	line_size = (line_size<<1)+line_size;
   309 	break;
   310     case COLFMT_ARGB1555: 
   311 	type = GL_UNSIGNED_SHORT_5_5_5_1; 
   312 	line_size <<= 1;
   313 	break;
   314     case COLFMT_ARGB4444: 
   315 	type = GL_UNSIGNED_SHORT_4_4_4_4; 
   316 	line_size <<= 1;
   317 	break;
   318     case COLFMT_ARGB8888: 
   319 	type = GL_UNSIGNED_INT_8_8_8_8; 
   320 	line_size <<= 2;
   321 	break;
   322     }
   323     size = line_size * buffer->height;
   325     if( backBuffer ) {
   326 	glFinish();
   327 	glReadBuffer( GL_BACK );
   328     } else {
   329 	glReadBuffer( GL_FRONT );
   330     }
   332     if( buffer->render_addr & 0xFF000000 == 0x04000000 ) {
   333 	/* Interlaced buffer. Go the double copy... :( */
   334 	char target[size];
   335 	glReadPixels( 0, 0, buffer->width, buffer->height, format, type, target );
   336 	pvr2_vram64_write( buffer->render_addr, target, size );
   337     } else {
   338 	/* Regular buffer */
   339 	char target[size];
   340 	glReadPixels( 0, 0, buffer->width, buffer->height, format, type, target );
   341 	pvr2_vram_write_invert( buffer->render_addr, target, size, line_size );
   342     }
   343 }
   346 /**
   347  * Copy data from PVR ram into the GL render buffer. 
   348  *
   349  * @param buffer A render buffer indicating the address to read from, and the
   350  * format the data is in.
   351  * @param backBuffer TRUE to write the back buffer, FALSE for 
   352  * the front buffer.
   353  */
   354 void pvr2_render_copy_from_sh4( pvr2_render_buffer_t buffer, 
   355 				gboolean backBuffer )
   356 {
   357     if( buffer->render_addr == -1 )
   358 	return;
   359     GLenum type, format = GL_RGBA;
   360     int size = buffer->width * buffer->height;
   362     switch( buffer->colour_format ) {
   363     case COLFMT_RGB565: 
   364 	type = GL_UNSIGNED_SHORT_5_6_5; 
   365 	format = GL_RGB; 
   366 	size <<= 1;
   367 	break;
   368     case COLFMT_RGB888: 
   369 	type = GL_UNSIGNED_INT; 
   370 	format = GL_RGB;
   371 	size = (size<<1)+size;
   372 	break;
   373     case COLFMT_ARGB1555: 
   374 	type = GL_UNSIGNED_SHORT_5_5_5_1; 
   375 	size <<= 1;
   376 	break;
   377     case COLFMT_ARGB4444: 
   378 	type = GL_UNSIGNED_SHORT_4_4_4_4; 
   379 	size <<= 1;
   380 	break;
   381     case COLFMT_ARGB8888: 
   382 	type = GL_UNSIGNED_INT_8_8_8_8; 
   383 	size <<= 2;
   384 	break;
   385     }
   387     if( backBuffer ) {
   388 	glDrawBuffer( GL_BACK );
   389     } else {
   390 	glDrawBuffer( GL_FRONT );
   391     }
   393     glRasterPos2i( 0, 0 );
   394     if( buffer->render_addr & 0xFF000000 == 0x04000000 ) {
   395 	/* Interlaced buffer. Go the double copy... :( */
   396 	char target[size];
   397 	pvr2_vram64_read( target, buffer->render_addr, size );
   398 	glDrawPixels( buffer->width, buffer->height, 
   399 		      format, type, target );
   400     } else {
   401 	/* Regular buffer - go direct */
   402 	char *target = mem_get_region( buffer->render_addr );
   403 	glDrawPixels( buffer->width, buffer->height, 
   404 		      format, type, target );
   405     }
   406 }
.