2 * $Id: render.c,v 1.13 2006-08-29 08:12:13 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"
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 };
28 * Describes a rendering buffer that's actually held in GL, for when we need
29 * to fetch the bits back to vram.
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 */
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;
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, ... )
62 va_list ap; /* our argument pointer */
65 if (fmt == NULL) /* if there is no string to draw do nothing */
68 len = vsnprintf(buf, sizeof(buf), fmt, 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);
87 void glDrawGrid( int width, int height )
90 glDisable( GL_DEPTH_TEST );
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 );
100 for( i=32; i<height; i+=32 ) {
101 glVertex3f( 0.0, i, 3.0 );
102 glVertex3f( width, i, 3.0 );
109 gboolean pvr2_render_init( void )
111 front_buffer.render_addr = -1;
112 back_buffer.render_addr = -1;
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
121 gboolean pvr2_render_invalidate( sh4addr_t address )
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;
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;
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.
145 gboolean pvr2_render_display_frame( uint32_t address )
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.
153 if( back_buffer.render_addr == address ) {
154 /* The more useful case - back buffer is to be displayed. Swap
157 display_driver->display_back_buffer();
158 front_buffer = back_buffer;
159 back_buffer.render_addr = -1;
166 * Prepare the OpenGL context to receive instructions for a new frame.
168 static void pvr2_render_prepare_context( sh4addr_t render_addr,
169 uint32_t width, uint32_t height,
170 uint32_t colour_format,
172 gboolean texture_target )
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");
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
186 pvr2_render_copy_to_sh4( &back_buffer, TRUE );
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.
194 front_buffer.render_addr = -1;
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);
209 glOrtho( 0, width, height, 0, bgplanez, -4 );
210 glMatrixMode(GL_MODELVIEW);
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 );
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)) )
226 * Render a complete scene into the OpenGL back buffer.
227 * Note: this will probably need to be broken up eventually once timings are
230 void pvr2_render_scene( )
232 struct tile_descriptor *tile_desc =
233 (struct tile_descriptor *)mem_get_region(PVR2_RAM_BASE + MMIO_READ( PVR2, RENDER_TILEBASE ));
235 uint32_t render_addr = MMIO_READ( PVR2, RENDER_ADDR1 );
236 gboolean render_to_tex;
237 if( render_addr & 0x01000000 ) {
238 render_addr = (render_addr & 0x00FFFFFF) + PVR2_RAM_BASE_INT;
239 /* Heuristic - if we're rendering to the interlaced region we're
240 * probably creating a texture rather than rendering actual output.
241 * We can optimise for this case a little
243 render_to_tex = TRUE;
244 WARN( "Render to texture not supported properly yet" );
246 render_addr = (render_addr & 0x00FFFFFF) + PVR2_RAM_BASE;
247 render_to_tex = FALSE;
250 float bgplanez = MMIO_READF( PVR2, RENDER_FARCLIP );
251 uint32_t render_mode = MMIO_READ( PVR2, RENDER_MODE );
252 int width = 640; /* FIXME - get this from the tile buffer */
254 int colour_format = pvr2_render_colour_format[render_mode&0x07];
255 pvr2_render_prepare_context( render_addr, width, height, colour_format,
256 bgplanez, render_to_tex );
258 int clip_x = MMIO_READ( PVR2, RENDER_HCLIP ) & 0x03FF;
259 int clip_y = MMIO_READ( PVR2, RENDER_VCLIP ) & 0x03FF;
260 int clip_width = ((MMIO_READ( PVR2, RENDER_HCLIP ) >> 16) & 0x03FF) - clip_x + 1;
261 int clip_height= ((MMIO_READ( PVR2, RENDER_VCLIP ) >> 16) & 0x03FF) - clip_y + 1;
263 /* Fog setup goes here */
265 /* Render the background plane */
266 uint32_t bgplane_mode = MMIO_READ(PVR2, RENDER_BGPLANE);
267 uint32_t *display_list =
268 (uint32_t *)mem_get_region(PVR2_RAM_BASE + MMIO_READ( PVR2, RENDER_POLYBASE ));
270 uint32_t *bgplane = display_list + (((bgplane_mode & 0x00FFFFFF)) >> 3) ;
271 render_backplane( bgplane, width, height, bgplane_mode );
273 pvr2_render_tilebuffer( width, height, clip_x, clip_y,
274 clip_x + clip_width, clip_y + clip_height );
276 /* Post-render cleanup and update */
278 /* Add frame, fps, etc data */
279 //glDrawGrid( width, height );
280 glPrintf( 4, 16, "Frame %d", pvr2_get_frame_count() );
281 /* Generate end of render event */
282 asic_event( EVENT_PVR_RENDER_DONE );
283 DEBUG( "Rendered frame %d", pvr2_get_frame_count() );
288 * Flush the indicated render buffer back to PVR. Caller is responsible for
289 * tracking whether there is actually anything in the buffer.
291 * @param buffer A render buffer indicating the address to store to, and the
292 * format the data needs to be in.
293 * @param backBuffer TRUE to flush the back buffer, FALSE for
296 void pvr2_render_copy_to_sh4( pvr2_render_buffer_t buffer,
297 gboolean backBuffer )
299 if( buffer->render_addr == -1 )
301 GLenum type, format = GL_RGBA;
302 int line_size = buffer->width, size;
304 switch( buffer->colour_format ) {
306 type = GL_UNSIGNED_SHORT_5_6_5;
311 type = GL_UNSIGNED_INT;
313 line_size = (line_size<<1)+line_size;
315 case COLFMT_ARGB1555:
316 type = GL_UNSIGNED_SHORT_5_5_5_1;
319 case COLFMT_ARGB4444:
320 type = GL_UNSIGNED_SHORT_4_4_4_4;
323 case COLFMT_ARGB8888:
324 type = GL_UNSIGNED_INT_8_8_8_8;
328 size = line_size * buffer->height;
332 glReadBuffer( GL_BACK );
334 glReadBuffer( GL_FRONT );
337 if( buffer->render_addr & 0xFF000000 == 0x04000000 ) {
338 /* Interlaced buffer. Go the double copy... :( */
340 glReadPixels( 0, 0, buffer->width, buffer->height, format, type, target );
341 pvr2_vram64_write( buffer->render_addr, target, size );
345 glReadPixels( 0, 0, buffer->width, buffer->height, format, type, target );
346 pvr2_vram_write_invert( buffer->render_addr, target, size, line_size );
352 * Copy data from PVR ram into the GL render buffer.
354 * @param buffer A render buffer indicating the address to read from, and the
355 * format the data is in.
356 * @param backBuffer TRUE to write the back buffer, FALSE for
359 void pvr2_render_copy_from_sh4( pvr2_render_buffer_t buffer,
360 gboolean backBuffer )
362 if( buffer->render_addr == -1 )
364 GLenum type, format = GL_RGBA;
365 int size = buffer->width * buffer->height;
367 switch( buffer->colour_format ) {
369 type = GL_UNSIGNED_SHORT_5_6_5;
374 type = GL_UNSIGNED_INT;
376 size = (size<<1)+size;
378 case COLFMT_ARGB1555:
379 type = GL_UNSIGNED_SHORT_5_5_5_1;
382 case COLFMT_ARGB4444:
383 type = GL_UNSIGNED_SHORT_4_4_4_4;
386 case COLFMT_ARGB8888:
387 type = GL_UNSIGNED_INT_8_8_8_8;
393 glDrawBuffer( GL_BACK );
395 glDrawBuffer( GL_FRONT );
398 glRasterPos2i( 0, 0 );
399 if( buffer->render_addr & 0xFF000000 == 0x04000000 ) {
400 /* Interlaced buffer. Go the double copy... :( */
402 pvr2_vram64_read( target, buffer->render_addr, size );
403 glDrawPixels( buffer->width, buffer->height,
404 format, type, target );
406 /* Regular buffer - go direct */
407 char *target = mem_get_region( buffer->render_addr );
408 glDrawPixels( buffer->width, buffer->height,
409 format, type, target );
.