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