filename | src/pvr2/render.c |
changeset | 144:7f0714e89aaa |
prev | 132:48a8cc541742 |
next | 161:408b9210395f |
author | nkeynes |
date | Tue May 23 13:10:28 2006 +0000 (17 years ago) |
permissions | -rw-r--r-- |
last change | Add texcache invalidates on direct writes to 64-bit vram. Technically we should do it on direct writes to 32-bit vram as well, but noone (sane) is going to try to write a texture there... |
view | annotate | diff | log | raw |
1 /**
2 * $Id: render.c,v 1.8 2006-05-15 08:28:52 nkeynes Exp $
3 *
4 * PVR2 Renderer support. This is where the real work happens.
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 #define POLY_COLOUR_PACKED 0x00000000
24 #define POLY_COLOUR_FLOAT 0x00000010
25 #define POLY_COLOUR_INTENSITY 0x00000020
26 #define POLY_COLOUR_INTENSITY_PREV 0x00000030
28 static int pvr2_poly_vertexes[4] = { 3, 4, 6, 8 };
29 static int pvr2_poly_type[4] = { GL_TRIANGLES, GL_QUADS, GL_TRIANGLE_STRIP, GL_TRIANGLE_STRIP };
30 static int pvr2_poly_depthmode[8] = { GL_NEVER, GL_LESS, GL_EQUAL, GL_LEQUAL,
31 GL_GREATER, GL_NOTEQUAL, GL_GEQUAL,
32 GL_ALWAYS };
33 static int pvr2_poly_srcblend[8] = {
34 GL_ZERO, GL_ONE, GL_DST_COLOR, GL_ONE_MINUS_DST_COLOR,
35 GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_DST_ALPHA,
36 GL_ONE_MINUS_DST_ALPHA };
37 static int pvr2_poly_dstblend[8] = {
38 GL_ZERO, GL_ONE, GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR,
39 GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_DST_ALPHA,
40 GL_ONE_MINUS_DST_ALPHA };
41 static int pvr2_poly_texblend[4] = {
42 GL_REPLACE, GL_BLEND, GL_DECAL, GL_MODULATE };
43 static int pvr2_render_colour_format[8] = {
44 COLFMT_ARGB1555, COLFMT_RGB565, COLFMT_ARGB4444, COLFMT_ARGB1555,
45 COLFMT_RGB888, COLFMT_ARGB8888, COLFMT_ARGB8888, COLFMT_ARGB4444 };
47 #define POLY_STRIP_TYPE(poly) ( pvr2_poly_type[((poly->command)>>18)&0x03] )
48 #define POLY_STRIP_VERTEXES(poly) ( pvr2_poly_vertexes[((poly->command)>>18)&0x03] )
49 #define POLY_DEPTH_MODE(poly) ( pvr2_poly_depthmode[poly->poly_cfg>>29] )
50 #define POLY_DEPTH_WRITE(poly) ((poly->poly_cfg&0x04000000) == 0 )
51 #define POLY_TEX_WIDTH(poly) ( 1<< (((poly->poly_mode >> 3) & 0x07 ) + 3) )
52 #define POLY_TEX_HEIGHT(poly) ( 1<< (((poly->poly_mode) & 0x07 ) + 3) )
53 #define POLY_BLEND_SRC(poly) ( pvr2_poly_srcblend[(poly->poly_mode) >> 29] )
54 #define POLY_BLEND_DEST(poly) ( pvr2_poly_dstblend[((poly->poly_mode)>>26)&0x07] )
55 #define POLY_TEX_BLEND(poly) ( pvr2_poly_texblend[((poly->poly_mode) >> 6)&0x03] )
56 #define POLY_COLOUR_TYPE(poly) ( poly->command & 0x00000030 )
58 /**
59 * Describes a rendering buffer that's actually held in GL, for when we need
60 * to fetch the bits back to vram.
61 */
62 typedef struct pvr2_render_buffer {
63 uint32_t render_addr; /* The actual address rendered to in pvr ram */
64 int width, height;
65 int colour_format;
66 } *pvr2_render_buffer_t;
68 struct pvr2_render_buffer front_buffer;
69 struct pvr2_render_buffer back_buffer;
71 struct tile_descriptor {
72 uint32_t header[6];
73 struct tile_pointers {
74 uint32_t tile_id;
75 uint32_t opaque_ptr;
76 uint32_t opaque_mod_ptr;
77 uint32_t trans_ptr;
78 uint32_t trans_mod_ptr;
79 uint32_t punchout_ptr;
80 } tile[0];
81 };
83 /* Textured polygon */
84 struct pvr2_poly {
85 uint32_t command;
86 uint32_t poly_cfg; /* Bitmask */
87 uint32_t poly_mode; /* texture/blending mask */
88 uint32_t texture; /* texture data */
89 float alpha;
90 float red;
91 float green;
92 float blue;
93 };
95 struct pvr2_specular_highlight {
96 float base_alpha;
97 float base_red;
98 float base_green;
99 float base_blue;
100 float offset_alpha;
101 float offset_red;
102 float offset_green;
103 float offset_blue;
104 };
107 struct pvr2_vertex_packed {
108 uint32_t command;
109 float x, y, z;
110 float s,t;
111 uint32_t colour;
112 float f;
113 };
115 struct pvr2_vertex_float {
116 uint32_t command;
117 float x,y,z;
118 float a, r, g, b;
119 };
121 union pvr2_vertex {
122 struct pvr2_vertex_packed pack;
123 struct pvr2_vertex_float flt;
124 };
126 typedef struct pvr2_bgplane_packed {
127 uint32_t poly_cfg, poly_mode;
128 uint32_t texture_mode;
129 float x1, y1, z1;
130 uint32_t colour1;
131 float x2, y2, z2;
132 uint32_t colour2;
133 float x3, y3, z3;
134 uint32_t colour3;
135 } *pvr2_bgplane_packed_t;
139 void pvr2_render_copy_to_sh4( pvr2_render_buffer_t buffer,
140 gboolean backBuffer );
142 int pvr2_render_font_list = -1;
143 int pvr2_render_trace = 0;
145 int glPrintf( int x, int y, const char *fmt, ... )
146 {
147 va_list ap; /* our argument pointer */
148 char buf[256];
149 int len;
150 if (fmt == NULL) /* if there is no string to draw do nothing */
151 return;
152 va_start(ap, fmt);
153 len = vsnprintf(buf, sizeof(buf), fmt, ap);
154 va_end(ap);
157 glPushAttrib(GL_LIST_BIT);
158 glDisable( GL_DEPTH_TEST );
159 glDisable( GL_BLEND );
160 glDisable( GL_TEXTURE_2D );
161 glDisable( GL_ALPHA_TEST );
162 glListBase(pvr2_render_font_list - 32);
163 glColor3f( 1.0, 1.0, 1.0 );
164 glRasterPos2i( x, y );
165 glCallLists(len, GL_UNSIGNED_BYTE, buf);
166 glPopAttrib();
168 return len;
169 }
172 gboolean pvr2_render_init( void )
173 {
174 front_buffer.render_addr = -1;
175 back_buffer.render_addr = -1;
176 }
178 /**
179 * Display a rendered frame if one is available.
180 * @param address An address in PVR ram (0500000 range).
181 * @return TRUE if a frame was available to be displayed, otherwise false.
182 */
183 gboolean pvr2_render_display_frame( uint32_t address )
184 {
185 if( front_buffer.render_addr == address ) {
186 /* Current front buffer is already displayed, so do nothing
187 * and tell the caller that all is well.
188 */
189 return TRUE;
190 }
191 if( back_buffer.render_addr == address ) {
192 /* The more useful case - back buffer is to be displayed. Swap
193 * the buffers
194 */
195 display_driver->display_back_buffer();
196 front_buffer = back_buffer;
197 back_buffer.render_addr = -1;
198 return TRUE;
199 }
200 return FALSE;
201 }
203 /**
204 * Prepare the OpenGL context to receive instructions for a new frame.
205 */
206 static void pvr2_render_prepare_context( sh4addr_t render_addr,
207 uint32_t width, uint32_t height,
208 uint32_t colour_format,
209 float bgplanez,
210 gboolean texture_target )
211 {
212 /* Select and initialize the render context */
213 display_driver->set_render_format( width, height, colour_format, texture_target );
215 if( pvr2_render_font_list == -1 ) {
216 pvr2_render_font_list = video_glx_load_font( "-*-helvetica-*-r-normal--16-*-*-*-p-*-iso8859-1");
217 }
219 if( back_buffer.render_addr != -1 &&
220 back_buffer.render_addr != render_addr ) {
221 /* There's a current back buffer, and we're rendering somewhere else -
222 * flush the back buffer back to vram and start a new back buffer
223 */
224 pvr2_render_copy_to_sh4( &back_buffer, TRUE );
225 }
227 if( front_buffer.render_addr == render_addr ) {
228 /* In case we've been asked to render to the current front buffer -
229 * invalidate the front buffer and render to the back buffer, ensuring
230 * we swap at the next frame display.
231 */
232 front_buffer.render_addr = -1;
233 }
234 back_buffer.render_addr = render_addr;
235 back_buffer.width = width;
236 back_buffer.height = height;
237 back_buffer.colour_format = colour_format;
239 /* Setup the display model */
240 glDrawBuffer(GL_BACK);
241 glShadeModel(GL_SMOOTH);
242 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
243 glViewport( 0, 0, width, height );
244 glMatrixMode(GL_PROJECTION);
245 glLoadIdentity();
246 glOrtho( 0, width, height, 0, bgplanez, -1 );
247 glMatrixMode(GL_MODELVIEW);
248 glLoadIdentity();
249 glCullFace( GL_BACK );
251 /* Clear out the buffers */
252 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
253 glClearDepth(bgplanez);
254 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
255 }
257 static void pvr2_dump_display_list( uint32_t * display_list, uint32_t length )
258 {
259 uint32_t i;
260 gboolean vertex = FALSE;
261 for( i =0; i<length>>2; i++ ) {
262 if( (i % 8) == 0 ) {
263 if( i != 0 )
264 fprintf( stderr, "\n" );
265 fprintf( stderr, "%08X:", i*4 );
266 if( display_list[i] == 0xE0000000 ||
267 display_list[i] == 0xF0000000 )
268 vertex = TRUE;
269 else vertex = FALSE;
270 }
271 if( vertex && (i%8) > 0 && (i%8) < 4 )
272 fprintf( stderr, " %f", ((float *)display_list)[i] );
273 else
274 fprintf( stderr, " %08X", display_list[i] );
275 }
276 fprintf( stderr, "\n" );
277 }
279 static void pvr2_render_display_list( uint32_t *display_list, uint32_t length )
280 {
281 uint32_t *cmd_ptr = display_list;
282 int strip_length = 0, vertex_count = 0;
283 int colour_type;
284 gboolean textured = FALSE;
285 gboolean shaded = FALSE;
286 struct pvr2_poly *poly;
287 if( pvr2_render_trace ) {
288 fprintf( stderr, "-------- %d\n", pvr2_get_frame_count() );
289 pvr2_dump_display_list( display_list, length );
290 }
291 while( cmd_ptr < display_list+(length>>2) ) {
292 unsigned int cmd = *cmd_ptr >> 24;
293 switch( cmd ) {
294 case PVR2_CMD_POLY_OPAQUE:
295 case PVR2_CMD_POLY_TRANS:
296 case PVR2_CMD_POLY_PUNCHOUT:
297 poly = (struct pvr2_poly *)cmd_ptr;
298 if( poly->command & PVR2_POLY_TEXTURED ) {
299 uint32_t addr = PVR2_TEX_ADDR(poly->texture);
300 int width = POLY_TEX_WIDTH(poly);
301 int height = POLY_TEX_HEIGHT(poly);
302 glEnable( GL_TEXTURE_2D );
303 texcache_get_texture( addr, width, height, poly->texture );
304 textured = TRUE;
305 glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, POLY_TEX_BLEND(poly) );
306 } else {
307 textured = FALSE;
308 glDisable( GL_TEXTURE_2D );
309 }
310 glBlendFunc( POLY_BLEND_SRC(poly), POLY_BLEND_DEST(poly) );
311 if( poly->command & PVR2_POLY_SPECULAR ) {
312 /* Second block expected */
313 }
314 if( POLY_DEPTH_WRITE(poly) ) {
315 glEnable( GL_DEPTH_TEST );
316 glDepthFunc( POLY_DEPTH_MODE(poly) );
317 } else {
318 glDisable( GL_DEPTH_TEST );
319 }
321 switch( (poly->poly_cfg >> 27) & 0x03 ) {
322 case 0:
323 case 1:
324 glDisable( GL_CULL_FACE );
325 break;
326 case 2:
327 glEnable( GL_CULL_FACE );
328 glFrontFace( GL_CW );
329 break;
330 case 3:
331 glEnable( GL_CULL_FACE );
332 glFrontFace( GL_CCW );
333 }
334 strip_length = POLY_STRIP_VERTEXES( poly );
335 colour_type = POLY_COLOUR_TYPE( poly );
336 vertex_count = 0;
337 if( poly->command & PVR2_POLY_SHADED ) {
338 shaded = TRUE;
339 } else {
340 shaded = FALSE;
341 }
342 if( poly->poly_mode & PVR2_POLY_MODE_TEXALPHA ) {
343 glDisable( GL_BLEND );
344 } else {
345 glEnable( GL_BLEND );
346 }
348 break;
349 case PVR2_CMD_MOD_OPAQUE:
350 case PVR2_CMD_MOD_TRANS:
351 /* TODO */
352 break;
353 case PVR2_CMD_END_OF_LIST:
354 break;
355 case PVR2_CMD_VERTEX_LAST:
356 case PVR2_CMD_VERTEX:
357 if( vertex_count == 0 ) {
358 glBegin( GL_TRIANGLE_STRIP );
359 }
360 vertex_count++;
362 struct pvr2_vertex_packed *vertex = (struct pvr2_vertex_packed *)cmd_ptr;
363 if( textured ) {
364 glTexCoord2f( vertex->s, vertex->t );
366 if( shaded || vertex_count == 1) {
367 switch( colour_type ) {
368 case POLY_COLOUR_PACKED:
369 glColor4ub( vertex->colour >> 16, vertex->colour >> 8,
370 vertex->colour, vertex->colour >> 24 );
371 break;
372 }
373 }
374 } else {
375 if( shaded || vertex_count == 1 ) {
376 switch( colour_type ) {
377 case POLY_COLOUR_PACKED:
378 glColor4ub( vertex->colour >> 16, vertex->colour >> 8,
379 vertex->colour, vertex->colour >> 24 );
380 break;
381 case POLY_COLOUR_FLOAT:
382 {
383 struct pvr2_vertex_float *v = (struct pvr2_vertex_float *)cmd_ptr;
384 glColor4f( v->r, v->g, v->b, v->a );
385 }
386 break;
387 }
388 }
389 }
391 glVertex3f( vertex->x, vertex->y, vertex->z );
393 if( cmd == PVR2_CMD_VERTEX_LAST ) {
394 glEnd();
395 vertex_count = 0;
396 }
397 break;
398 default:
399 ERROR( "Unhandled command %08X in display list", *cmd_ptr );
400 pvr2_dump_display_list( display_list, length );
401 return;
402 }
403 cmd_ptr += 8; /* Next record */
404 }
405 }
407 #define MIN3( a,b,c ) ((a) < (b) ? ( (a) < (c) ? (a) : (c) ) : ((b) < (c) ? (b) : (c)) )
408 #define MAX3( a,b,c ) ((a) > (b) ? ( (a) > (c) ? (a) : (c) ) : ((b) > (c) ? (b) : (c)) )
410 /**
411 * Render the background plane as best we can. Unfortunately information
412 * is a little scant, to say the least.
413 */
414 void pvr2_render_draw_backplane( uint32_t mode, uint32_t *poly )
415 {
416 if( (mode >> 24) == 0x01 ) {
417 /* Packed colour. I think */
418 pvr2_bgplane_packed_t bg = (pvr2_bgplane_packed_t)poly;
419 if( bg->colour1 != bg->colour2 || bg->colour2 != bg->colour3 ) {
420 WARN( "Multiple background colours specified. Confused" );
421 }
422 float x1 = MIN3( bg->x1, bg->x2, bg->x3 );
423 float y1 = MIN3( bg->y1, bg->y2, bg->y3 );
424 float x2 = MAX3( bg->x1, bg->x2, bg->x3 );
425 float y2 = MAX3( bg->y1, bg->y2, bg->y3 );
426 float z = MIN3( bg->z1, bg->z2, bg->z3 );
427 glDisable( GL_TEXTURE_2D );
428 glDisable( GL_DEPTH_TEST );
429 glColor3ub( (uint8_t)(bg->colour1 >> 16), (uint8_t)(bg->colour1 >> 8),
430 (uint8_t)bg->colour1 );
431 glBegin( GL_QUADS );
432 glVertex3f( x1, y1, z );
433 glVertex3f( x2, y1, z );
434 glVertex3f( x2, y2, z );
435 glVertex3f( x1, y2, z );
436 glEnd();
437 } else {
438 WARN( "Unknown bgplane mode: %08X", mode );
439 fwrite_dump( poly, 48, stderr );
440 }
441 }
443 /**
444 * Render a complete scene into the OpenGL back buffer.
445 * Note: this will probably need to be broken up eventually once timings are
446 * determined.
447 */
448 void pvr2_render_scene( )
449 {
450 struct tile_descriptor *tile_desc =
451 (struct tile_descriptor *)mem_get_region(PVR2_RAM_BASE + MMIO_READ( PVR2, TILEBASE ));
453 uint32_t render_addr = MMIO_READ( PVR2, RENDADDR1 );
454 gboolean render_to_tex;
455 if( render_addr & 0x01000000 ) {
456 render_addr = (render_addr & 0x00FFFFFF) + PVR2_RAM_BASE_INT;
457 /* Heuristic - if we're rendering to the interlaced region we're
458 * probably creating a texture rather than rendering actual output.
459 * We can optimise for this case a little
460 */
461 render_to_tex = TRUE;
462 WARN( "Render to texture not supported properly yet" );
463 } else {
464 render_addr = (render_addr & 0x00FFFFFF) + PVR2_RAM_BASE;
465 render_to_tex = FALSE;
466 }
468 float bgplanez = MMIO_READF( PVR2, BGPLANEZ );
469 uint32_t render_mode = MMIO_READ( PVR2, RENDMODE );
470 int width = 640; /* FIXME - get this from the tile buffer */
471 int height = 480;
472 int colour_format = pvr2_render_colour_format[render_mode&0x07];
473 pvr2_render_prepare_context( render_addr, width, height, colour_format,
474 bgplanez, render_to_tex );
476 uint32_t *display_list =
477 (uint32_t *)mem_get_region(PVR2_RAM_BASE + MMIO_READ( PVR2, OBJBASE ));
479 uint32_t display_length = *display_list++;
481 int clip_x = MMIO_READ( PVR2, HCLIP ) & 0x03FF;
482 int clip_y = MMIO_READ( PVR2, VCLIP ) & 0x03FF;
483 int clip_width = ((MMIO_READ( PVR2, HCLIP ) >> 16) & 0x03FF) - clip_x + 1;
484 int clip_height= ((MMIO_READ( PVR2, VCLIP ) >> 16) & 0x03FF) - clip_y + 1;
486 if( clip_x == 0 && clip_y == 0 && clip_width == width && clip_height == height ) {
487 glDisable( GL_SCISSOR_TEST );
488 } else {
489 glEnable( GL_SCISSOR_TEST );
490 glScissor( clip_x, clip_y, clip_width, clip_height );
491 }
493 /* Fog setup goes here */
495 /* Render the background plane */
496 uint32_t bgplane_mode = MMIO_READ(PVR2, BGPLANE);
497 uint32_t *bgplane = display_list + (((bgplane_mode & 0x00FFFFFF)) >> 3) - 1;
498 pvr2_render_draw_backplane( bgplane_mode, bgplane );
500 /* Render the display list */
501 pvr2_render_display_list( display_list, display_length );
503 /* Post-render cleanup and update */
505 /* Add frame, fps, etc data */
506 glPrintf( 4, 16, "Frame %d", pvr2_get_frame_count() );
508 /* Generate end of render event */
509 asic_event( EVENT_PVR_RENDER_DONE );
510 DEBUG( "Rendered frame %d", pvr2_get_frame_count() );
511 }
514 /**
515 * Flush the indicated render buffer back to PVR. Caller is responsible for
516 * tracking whether there is actually anything in the buffer.
517 *
518 * @param buffer A render buffer indicating the address to store to, and the
519 * format the data needs to be in.
520 * @param backBuffer TRUE to flush the back buffer, FALSE for
521 * the front buffer.
522 */
523 void pvr2_render_copy_to_sh4( pvr2_render_buffer_t buffer,
524 gboolean backBuffer )
525 {
526 if( buffer->render_addr == -1 )
527 return;
528 GLenum type, format = GL_RGBA;
529 int size = buffer->width * buffer->height;
531 switch( buffer->colour_format ) {
532 case COLFMT_RGB565:
533 type = GL_UNSIGNED_SHORT_5_6_5;
534 format = GL_RGB;
535 size <<= 1;
536 break;
537 case COLFMT_RGB888:
538 type = GL_UNSIGNED_INT;
539 format = GL_RGB;
540 size = (size<<1)+size;
541 break;
542 case COLFMT_ARGB1555:
543 type = GL_UNSIGNED_SHORT_5_5_5_1;
544 size <<= 1;
545 break;
546 case COLFMT_ARGB4444:
547 type = GL_UNSIGNED_SHORT_4_4_4_4;
548 size <<= 1;
549 break;
550 case COLFMT_ARGB8888:
551 type = GL_UNSIGNED_INT_8_8_8_8;
552 size <<= 2;
553 break;
554 }
556 if( backBuffer ) {
557 glFinish();
558 glReadBuffer( GL_BACK );
559 } else {
560 glReadBuffer( GL_FRONT );
561 }
563 if( buffer->render_addr & 0xFF000000 == 0x04000000 ) {
564 /* Interlaced buffer. Go the double copy... :( */
565 char target[size];
566 glReadPixels( 0, 0, buffer->width, buffer->height, format, type, target );
567 pvr2_vram64_write( buffer->render_addr, target, size );
568 } else {
569 /* Regular buffer - go direct */
570 char *target = mem_get_region( buffer->render_addr );
571 glReadPixels( 0, 0, buffer->width, buffer->height, format, type, target );
572 }
573 }
576 /**
577 * Copy data from PVR ram into the GL render buffer.
578 *
579 * @param buffer A render buffer indicating the address to read from, and the
580 * format the data is in.
581 * @param backBuffer TRUE to write the back buffer, FALSE for
582 * the front buffer.
583 */
584 void pvr2_render_copy_from_sh4( pvr2_render_buffer_t buffer,
585 gboolean backBuffer )
586 {
587 if( buffer->render_addr == -1 )
588 return;
589 GLenum type, format = GL_RGBA;
590 int size = buffer->width * buffer->height;
592 switch( buffer->colour_format ) {
593 case COLFMT_RGB565:
594 type = GL_UNSIGNED_SHORT_5_6_5;
595 format = GL_RGB;
596 size <<= 1;
597 break;
598 case COLFMT_RGB888:
599 type = GL_UNSIGNED_INT;
600 format = GL_RGB;
601 size = (size<<1)+size;
602 break;
603 case COLFMT_ARGB1555:
604 type = GL_UNSIGNED_SHORT_5_5_5_1;
605 size <<= 1;
606 break;
607 case COLFMT_ARGB4444:
608 type = GL_UNSIGNED_SHORT_4_4_4_4;
609 size <<= 1;
610 break;
611 case COLFMT_ARGB8888:
612 type = GL_UNSIGNED_INT_8_8_8_8;
613 size <<= 2;
614 break;
615 }
617 if( backBuffer ) {
618 glDrawBuffer( GL_BACK );
619 } else {
620 glDrawBuffer( GL_FRONT );
621 }
623 glRasterPos2i( 0, 0 );
624 if( buffer->render_addr & 0xFF000000 == 0x04000000 ) {
625 /* Interlaced buffer. Go the double copy... :( */
626 char target[size];
627 pvr2_vram64_read( target, buffer->render_addr, size );
628 glDrawPixels( buffer->width, buffer->height,
629 format, type, target );
630 } else {
631 /* Regular buffer - go direct */
632 char *target = mem_get_region( buffer->render_addr );
633 glDrawPixels( buffer->width, buffer->height,
634 format, type, target );
635 }
636 }
.