2 * $Id: render.c,v 1.21 2007-01-27 06:21:35 nkeynes Exp $
4 * PVR2 Renderer support. This part is primarily
6 * Copyright (c) 2005 Nathan Keynes.
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.
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.
19 #include "pvr2/pvr2.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;
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, ... )
42 va_list ap; /* our argument pointer */
45 if (fmt == NULL) /* if there is no string to draw do nothing */
48 len = vsnprintf(buf, sizeof(buf), fmt, 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);
67 void glDrawGrid( int width, int height )
70 glDisable( GL_DEPTH_TEST );
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 );
80 for( i=32; i<height; i+=32 ) {
81 glVertex3f( 0.0, i, 3.0 );
82 glVertex3f( width, i, 3.0 );
89 gboolean pvr2_render_init( void )
91 front_buffer.render_addr = -1;
92 back_buffer.render_addr = -1;
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
101 gboolean pvr2_render_buffer_invalidate( sh4addr_t address )
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;
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;
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.
125 gboolean pvr2_render_display_frame( uint32_t address )
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.
133 if( back_buffer.render_addr == address ) {
134 /* The more useful case - back buffer is to be displayed. Swap
137 display_driver->display_back_buffer();
138 front_buffer = back_buffer;
139 back_buffer.render_addr = -1;
146 * Prepare the OpenGL context to receive instructions for a new frame.
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 )
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");
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
166 pvr2_render_buffer_copy_to_sh4( &back_buffer, TRUE );
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.
174 front_buffer.render_addr = -1;
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.scale = MMIO_READ( PVR2, RENDER_SCALER );
181 back_buffer.size = width * height * colour_format_bytes[colour_format];
183 /* Setup the display model */
184 glDrawBuffer(GL_BACK);
185 glShadeModel(GL_SMOOTH);
186 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
187 glViewport( 0, 0, width, height );
188 glMatrixMode(GL_PROJECTION);
190 glOrtho( 0, width, height, 0, -bgplanez, -nearz );
191 glMatrixMode(GL_MODELVIEW);
193 glCullFace( GL_BACK );
194 glEnable( GL_BLEND );
196 /* Clear out the buffers */
197 glDisable( GL_SCISSOR_TEST );
198 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
200 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
205 * Render a complete scene into the OpenGL back buffer.
206 * Note: this will probably need to be broken up eventually once timings are
209 void pvr2_render_scene( )
211 struct tile_descriptor *tile_desc =
212 (struct tile_descriptor *)mem_get_region(PVR2_RAM_BASE + MMIO_READ( PVR2, RENDER_TILEBASE ));
214 uint32_t render_addr = MMIO_READ( PVR2, RENDER_ADDR1 );
215 gboolean render_to_tex;
216 if( render_addr & 0x01000000 ) {
217 render_addr = (render_addr & 0x00FFFFFF) + PVR2_RAM_BASE_INT;
218 /* Heuristic - if we're rendering to the interlaced region we're
219 * probably creating a texture rather than rendering actual output.
220 * We can optimise for this case a little
222 render_to_tex = TRUE;
223 WARN( "Render to texture not supported properly yet" );
225 render_addr = (render_addr & 0x00FFFFFF) + PVR2_RAM_BASE;
226 render_to_tex = FALSE;
229 float bgplanez = 1/MMIO_READF( PVR2, RENDER_FARCLIP );
230 uint32_t render_mode = MMIO_READ( PVR2, RENDER_MODE );
231 int width = 640; /* FIXME - get this from the tile buffer */
233 int colour_format = pvr2_render_colour_format[render_mode&0x07];
234 float maxz = pvr2_render_find_maximum_z();
235 pvr2_render_prepare_context( render_addr, width, height, colour_format,
236 bgplanez, maxz, render_to_tex );
238 int clip_x = MMIO_READ( PVR2, RENDER_HCLIP ) & 0x03FF;
239 int clip_y = MMIO_READ( PVR2, RENDER_VCLIP ) & 0x03FF;
240 int clip_width = ((MMIO_READ( PVR2, RENDER_HCLIP ) >> 16) & 0x03FF) - clip_x + 1;
241 int clip_height= ((MMIO_READ( PVR2, RENDER_VCLIP ) >> 16) & 0x03FF) - clip_y + 1;
243 /* Fog setup goes here */
245 /* Render the background plane */
246 uint32_t bgplane_mode = MMIO_READ(PVR2, RENDER_BGPLANE);
247 uint32_t *display_list =
248 (uint32_t *)mem_get_region(PVR2_RAM_BASE + MMIO_READ( PVR2, RENDER_POLYBASE ));
250 uint32_t *bgplane = display_list + (((bgplane_mode & 0x00FFFFFF)) >> 3) ;
251 render_backplane( bgplane, width, height, bgplane_mode );
253 pvr2_render_tilebuffer( width, height, clip_x, clip_y,
254 clip_x + clip_width, clip_y + clip_height );
256 /* Post-render cleanup and update */
258 /* Add frame, fps, etc data */
259 //glDrawGrid( width, height );
260 glPrintf( 4, 16, "Frame %d", pvr2_get_frame_count() );
261 /* Generate end of render event */
262 asic_event( EVENT_PVR_RENDER_DONE );
263 DEBUG( "Rendered frame %d", pvr2_get_frame_count() );
.