filename | src/drivers/video_gl.c |
changeset | 1282:9f445c5e252b |
prev | 1262:4baa34eee6fc |
next | 1298:d0eb2307b847 |
author | nkeynes |
date | Sat Aug 04 08:46:28 2012 +1000 (11 years ago) |
permissions | -rw-r--r-- |
last change | Handle corner case in pvr2_run_slice when we've previously slightly overrun the end of the time slice |
view | annotate | diff | log | raw |
1 /**
2 * $Id$
3 *
4 * Common GL code that doesn't depend on a specific implementation
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 <assert.h>
20 #include <sys/time.h>
22 #include "display.h"
23 #include "pvr2/pvr2.h"
24 #include "pvr2/glutil.h"
25 #include "pvr2/shaders.h"
26 #include "drivers/video_gl.h"
28 uint32_t video_width, video_height;
29 struct video_vertex {
30 float x,y;
31 float u,v;
32 float r,g,b,a;
33 };
35 static struct video_box_t {
36 float viewMatrix[16];
37 struct video_vertex gap1[4];
38 struct video_vertex gap2[4];
39 struct video_vertex video_view[4];
40 struct video_vertex invert_view[4];
41 } video_box;
43 void gl_set_video_size( uint32_t width, uint32_t height, int flipped )
44 {
45 video_width = width;
46 video_height = height;
48 int x1=0,y1=0,x2=video_width,y2=video_height;
49 int top = 0, bottom = 1;
51 if( flipped ) {
52 top = 1;
53 bottom = 0;
54 }
56 int ah = video_width * 0.75;
58 if( ah > video_height ) {
59 int w = (video_height/0.75);
60 x1 = (video_width - w)/2;
61 x2 -= x1;
62 video_box.gap1[0].x = 0; video_box.gap1[0].y = 0;
63 video_box.gap1[1].x = x1; video_box.gap1[1].y = 0;
64 video_box.gap1[2].x = x1; video_box.gap1[2].y = video_height;
65 video_box.gap1[3].x = 0; video_box.gap1[3].y = video_height;
66 video_box.gap2[0].x = x2; video_box.gap2[0].y = 0;
67 video_box.gap2[1].x = video_width; video_box.gap2[1].y = 0;
68 video_box.gap2[2].x = video_width; video_box.gap2[2].y = video_height;
69 video_box.gap2[3].x = x2; video_box.gap2[3].y = video_height;
70 } else if( ah < video_height ) {
71 y1 = (video_height - ah)/2;
72 y2 -= y1;
74 video_box.gap1[0].x = 0; video_box.gap1[0].y = 0;
75 video_box.gap1[1].x = video_width; video_box.gap1[1].y = 0;
76 video_box.gap1[2].x = video_width; video_box.gap1[2].y = y1;
77 video_box.gap1[3].x = 0; video_box.gap1[3].y = y1;
78 video_box.gap2[0].x = 0; video_box.gap2[0].y = y2;
79 video_box.gap2[1].x = video_width; video_box.gap2[1].y = y2;
80 video_box.gap2[2].x = video_width; video_box.gap2[2].y = video_height;
81 video_box.gap2[3].x = 0; video_box.gap2[3].y = video_height;
82 }
84 video_box.video_view[0].x = x1; video_box.video_view[0].y = y1;
85 video_box.video_view[0].u = 0; video_box.video_view[0].v = top;
86 video_box.video_view[1].x = x2; video_box.video_view[1].y = y1;
87 video_box.video_view[1].u = 1; video_box.video_view[1].v = top;
88 video_box.video_view[2].x = x2; video_box.video_view[2].y = y2;
89 video_box.video_view[2].u = 1; video_box.video_view[2].v = bottom;
90 video_box.video_view[3].x = x1; video_box.video_view[3].y = y2;
91 video_box.video_view[3].u = 0; video_box.video_view[3].v = bottom;
93 memcpy( &video_box.invert_view, &video_box.video_view, sizeof(video_box.video_view) );
94 video_box.invert_view[0].v = bottom; video_box.invert_view[1].v = bottom;
95 video_box.invert_view[2].v = top; video_box.invert_view[3].v = top;
97 defineOrthoMatrix(video_box.viewMatrix, video_width, video_height, 0, 65535);
98 }
100 #ifdef HAVE_OPENGL_FIXEDFUNC
101 /**
102 * Setup the gl context for writes to the display output.
103 */
104 void gl_framebuffer_setup()
105 {
106 glViewport( 0, 0, video_width, video_height );
107 glLoadMatrixf(video_box.viewMatrix);
108 glBlendFunc( GL_ONE, GL_ZERO );
109 glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
110 glVertexPointer(2, GL_FLOAT, sizeof(struct video_vertex), &video_box.gap1[0].x);
111 glColorPointer(3, GL_FLOAT, sizeof(struct video_vertex), &video_box.gap1[0].r);
112 glTexCoordPointer(2, GL_FLOAT, sizeof(struct video_vertex), &video_box.gap1[0].u);
113 glEnableClientState( GL_VERTEX_ARRAY );
114 glEnableClientState( GL_COLOR_ARRAY );
115 glEnableClientState( GL_TEXTURE_COORD_ARRAY );
116 }
118 void gl_framebuffer_cleanup()
119 {
120 glDisableClientState( GL_VERTEX_ARRAY );
121 glDisableClientState( GL_COLOR_ARRAY );
122 glDisableClientState( GL_TEXTURE_COORD_ARRAY );
123 }
124 #else
125 void gl_framebuffer_setup()
126 {
127 glViewport( 0, 0, video_width, video_height );
128 glBlendFunc( GL_ONE, GL_ZERO );
129 glsl_use_basic_shader();
130 glsl_set_basic_shader_view_matrix(video_box.viewMatrix);
131 glsl_set_basic_shader_in_vertex_pointer(&video_box.gap1[0].x, sizeof(struct video_vertex));
132 glsl_set_basic_shader_in_colour_pointer(&video_box.gap1[0].r, sizeof(struct video_vertex));
133 glsl_set_basic_shader_in_texcoord_pointer(&video_box.gap1[0].u, sizeof(struct video_vertex));
134 glsl_set_basic_shader_primary_texture(0);
135 }
137 void gl_framebuffer_cleanup()
138 {
139 glsl_clear_shader();
140 }
141 #endif
143 void gl_display_render_buffer( render_buffer_t buffer )
144 {
145 gl_texture_window( buffer->width, buffer->height, buffer->buf_id, buffer->inverted );
146 }
148 /**
149 * Convert window coordinates to dreamcast device coords (640x480) using the
150 * same viewable area as gl_texture_window.
151 * If the coordinates are outside the viewable area, the result is -1,-1.
152 */
153 void gl_window_to_system_coords( int *x, int *y )
154 {
155 int x1=0,y1=0,x2=video_width,y2=video_height;
157 int ah = video_width * 0.75;
159 if( ah > video_height ) {
160 int w = (video_height/0.75);
161 x1 = (video_width - w)/2;
162 x2 -= x1;
163 } else if( ah < video_height ) {
164 y1 = (video_height - ah)/2;
165 y2 -= y1;
166 }
167 if( *x < x1 || *x >= x2 || *y < y1 || *y >= y2 ) {
168 *x = -1;
169 *y = -1;
170 } else {
171 *x = (*x - x1) * DISPLAY_WIDTH / (x2-x1);
172 *y = (*y - y1) * DISPLAY_HEIGHT / (y2-y1);
173 }
174 }
176 /**
177 * Use quads if we have them, otherwise tri-fans.
178 */
179 #ifndef GL_QUADS
180 #define GL_QUADS GL_TRIANGLE_FAN
181 #endif
183 void gl_texture_window( int width, int height, int tex_id, gboolean inverted )
184 {
185 /* Set video box tex alpha to 1 */
186 video_box.video_view[0].a = video_box.video_view[1].a = video_box.video_view[2].a = video_box.video_view[3].a = 1;
187 video_box.invert_view[0].a = video_box.invert_view[1].a = video_box.invert_view[2].a = video_box.invert_view[3].a = 1;
189 /* Reset display parameters */
190 gl_framebuffer_setup();
191 glDrawArrays(GL_QUADS, 0, 4);
192 glDrawArrays(GL_QUADS, 4, 4);
193 glEnable(GL_TEXTURE_2D);
194 glBindTexture(GL_TEXTURE_2D,tex_id);
195 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
196 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
197 glDrawArrays(GL_QUADS, inverted ? 12 : 8, 4);
198 glDisable(GL_TEXTURE_2D);
199 gl_framebuffer_cleanup();
200 glFlush();
201 }
203 void gl_display_blank( uint32_t colour )
204 {
205 /* Set the video_box background colour */
206 video_box.video_view[0].r = ((float)(((colour >> 16) & 0xFF) + 1)) / 256.0;
207 video_box.video_view[0].g = ((float)(((colour >> 8) & 0xFF) + 1)) / 256.0;
208 video_box.video_view[0].b = ((float)((colour & 0xFF) + 1)) / 256.0;
209 video_box.video_view[0].a = 0;
210 memcpy( &video_box.video_view[1].r, &video_box.video_view[0].r, sizeof(float)*3 );
211 memcpy( &video_box.video_view[2].r, &video_box.video_view[0].r, sizeof(float)*3 );
212 memcpy( &video_box.video_view[3].r, &video_box.video_view[0].r, sizeof(float)*3 );
214 /* And render */
215 gl_framebuffer_setup();
216 glDrawArrays(GL_QUADS, 0, 4);
217 glDrawArrays(GL_QUADS, 4, 4);
218 glDrawArrays(GL_QUADS, 8, 4);
219 gl_framebuffer_cleanup();
220 glFlush();
221 }
224 #ifdef HAVE_GLES2
225 /* Note: OpenGL ES only officialy supports glReadPixels for the RGBA32 format
226 * (and doesn't necessarily support glPixelStore(GL_PACK_ROW_LENGTH) either.
227 * As a result, we end up needed to do the format conversion ourselves.
228 */
230 /**
231 * Swizzle 32-bit RGBA to specified target format, truncating components where
232 * necessary. Target may == source.
233 * @param target destination buffer
234 * @param Source buffer, which must be in 8-bit-per-component RGBA format, fully packed.
235 * @param width width of image in pixels
236 * @param height height of image in pixels
237 * @param target_stride Stride of target buffer, in bytes
238 * @param colour_format
239 */
240 static void rgba32_to_target( unsigned char *target, const uint32_t *source, int width, int height, int target_stride, int colour_format )
241 {
242 int x,y;
244 if( target_stride == 0 )
245 target_stride = width * colour_formats[colour_format].bpp;
247 switch( colour_format ) {
248 case COLFMT_BGRA1555:
249 for( y=0; y<height; y++ ) {
250 uint16_t *d = (uint16_t *)target;
251 for( x=0; x<width; x++ ) {
252 uint32_t v = *source++;
253 *d++ = (uint16_t)( ((v & 0x80000000) >> 16) | ((v & 0x00F80000) >> 19) |
254 ((v & 0x0000F800)>>6) | ((v & 0x000000F8) << 7) );
255 }
256 target += target_stride;
257 }
258 break;
259 case COLFMT_RGB565:
260 for( y=0; y<height; y++ ) {
261 uint16_t *d = (uint16_t *)target;
262 for( x=0; x<width; x++ ) {
263 uint32_t v = *source++;
264 *d++ = (uint16_t)( ((v & 0x00F80000) >> 19) | ((v & 0x0000FC00) >> 5) | ((v & 0x000000F8)<<8) );
265 }
266 target += target_stride;
267 }
268 break;
269 case COLFMT_BGRA4444:
270 for( y=0; y<height; y++ ) {
271 uint16_t *d = (uint16_t *)target;
272 for( x=0; x<width; x++ ) {
273 uint32_t v = *source++;
274 *d++ = (uint16_t)( ((v & 0xF0000000) >> 16) | ((v & 0x00F00000) >> 20) |
275 ((v & 0x0000F000) >> 8) | ((v & 0x000000F0)<<4) );
276 }
277 target += target_stride;
278 }
279 break;
280 case COLFMT_BGRA8888:
281 for( y=0; y<height; y++ ) {
282 uint32_t *d = (uint32_t *)target;
283 for( x=0; x<width; x++ ) {
284 uint32_t v = *source++;
285 *d++ = (v & 0xFF00FF00) | ((v & 0x00FF0000) >> 16) | ((v & 0x000000FF)<<16);
286 }
287 target += target_stride;
288 }
289 break;
290 case COLFMT_BGR0888:
291 for( y=0; y<height; y++ ) {
292 uint32_t *d = (uint32_t *)target;
293 for( x=0; x<width; x++ ) {
294 uint32_t v = *source++;
295 *d++ = ((v & 0x00FF0000) >> 16) | (v & 0x0000FF00) | ((v & 0x000000FF)<<16);
296 }
297 target += target_stride;
298 }
299 break;
300 case COLFMT_BGR888:
301 for( y=0; y<height; y++ ) {
302 uint8_t *d = (uint8_t *)target;
303 for( x=0; x<width; x++ ) {
304 uint32_t v = *source++;
305 *d++ = (uint8_t)(v >> 16);
306 *d++ = (uint8_t)(v >> 8);
307 *d++ = (uint8_t)(v);
308 }
309 target += target_stride;
310 }
311 break;
312 case COLFMT_RGB888:
313 for( y=0; y<height; y++ ) {
314 uint8_t *d = (uint8_t *)target;
315 for( x=0; x<width; x++ ) {
316 uint32_t v = *source++;
317 *d++ = (uint8_t)(v);
318 *d++ = (uint8_t)(v >> 8);
319 *d++ = (uint8_t)(v >> 16);
320 }
321 target += target_stride;
322 }
323 break;
324 default:
325 assert( 0 && "Unsupported colour format" );
326 }
327 }
329 /**
330 * Convert data into an acceptable form for loading into an RGBA texture.
331 */
332 static int target_to_rgba( uint32_t *target, const unsigned char *source, int width, int height, int source_stride, int colour_format )
333 {
334 int x,y;
335 uint16_t *d;
336 switch( colour_format ) {
337 case COLFMT_BGRA1555:
338 d = (uint16_t *)target;
339 for( y=0; y<height; y++ ) {
340 uint16_t *s = (uint16_t *)source;
341 for( x=0; x<width; x++ ) {
342 uint16_t v = *s++;
343 *d++ = (v >> 15) | (v<<1);
344 }
345 source += source_stride;
346 }
347 return GL_UNSIGNED_SHORT_5_5_5_1;
348 break;
349 case COLFMT_RGB565:
350 /* Need to expand to RGBA32 in order to have room for an alpha component */
351 for( y=0; y<height; y++ ) {
352 uint16_t *s = (uint16_t *)source;
353 for( x=0; x<width; x++ ) {
354 uint32_t v = (uint32_t)*s++;
355 *target++ = ((v & 0xF800)>>8) | ((v & 0x07E0) <<5) | ((v & 0x001F) << 19) |
356 ((v & 0xE000) >> 13) | ((v &0x0600) >> 1) | ((v & 0x001C) << 14);
357 }
358 source += source_stride;
359 }
360 return GL_UNSIGNED_BYTE;
361 case COLFMT_BGRA4444:
362 d = (uint16_t *)target;
363 for( y=0; y<height; y++ ) {
364 uint16_t *s = (uint16_t *)source;
365 for( x=0; x<width; x++ ) {
366 uint16_t v = *s++;
367 *d++ = (v >> 12) | (v<<4);
368 }
369 source += source_stride;
370 }
371 return GL_UNSIGNED_SHORT_4_4_4_4;
372 case COLFMT_RGB888:
373 for( y=0; y<height; y++ ) {
374 uint8_t *s = (uint8_t *)source;
375 for( x=0; x<width; x++ ) {
376 *target++ = s[0] | (s[1]<<8) | (s[2]<<16);
377 s += 3;
378 }
379 source += source_stride;
380 }
381 return GL_UNSIGNED_BYTE;
382 case COLFMT_BGRA8888:
383 for( y=0; y<height; y++ ) {
384 uint32_t *s = (uint32_t *)source;
385 for( x=0; x<width; x++ ) {
386 uint32_t v = (uint32_t)*s++;
387 *target++ = (v & 0xFF00FF00) | ((v & 0x00FF0000) >> 16) | ((v & 0x000000FF) << 16);
388 }
389 source += source_stride;
390 }
391 return GL_UNSIGNED_BYTE;
392 case COLFMT_BGR0888:
393 for( y=0; y<height; y++ ) {
394 uint32_t *s = (uint32_t *)source;
395 for( x=0; x<width; x++ ) {
396 uint32_t v = (uint32_t)*s++;
397 *target++ = (v & 0x0000FF00) | ((v & 0x00FF0000) >> 16) | ((v & 0x000000FF) << 16);
398 }
399 source += source_stride;
400 }
401 return GL_UNSIGNED_BYTE;
402 case COLFMT_BGR888:
403 for( y=0; y<height; y++ ) {
404 uint8_t *s = (uint8_t *)source;
405 for( x=0; x<width; x++ ) {
406 *target++ = s[2] | (s[1]<<8) | (s[0]<<16);
407 s += 3;
408 }
409 source += source_stride;
410 }
411 return GL_UNSIGNED_BYTE;
412 default:
413 assert( 0 && "Unsupported colour format" );
414 }
417 }
420 gboolean gl_read_render_buffer( unsigned char *target, render_buffer_t buffer,
421 int rowstride, int colour_format )
422 {
423 if( colour_formats[colour_format].bpp == 4 && (rowstride == 0 || rowstride == buffer->width*4) ) {
424 glReadPixels( 0, 0, buffer->width, buffer->height, GL_RGBA, GL_UNSIGNED_BYTE, target );
425 rgba32_to_target( target, (uint32_t *)target, buffer->width, buffer->height, rowstride, colour_format );
426 } else {
427 int size = buffer->width * buffer->height;
428 uint32_t tmp[size];
430 glReadPixels( 0, 0, buffer->width, buffer->height, GL_RGBA, GL_UNSIGNED_BYTE, tmp );
431 rgba32_to_target( target, tmp, buffer->width, buffer->height, rowstride, colour_format );
432 }
433 return TRUE;
434 }
436 gboolean gl_load_frame_buffer( frame_buffer_t frame, int tex_id )
437 {
438 int size = frame->width * frame->height;
439 uint32_t tmp[size];
441 GLenum type = target_to_rgba( tmp, frame->data, frame->width, frame->height, frame->rowstride, frame->colour_format );
442 glBindTexture( GL_TEXTURE_2D, tex_id );
443 glTexSubImage2D( GL_TEXTURE_2D, 0, 0,0, frame->width, frame->height, GL_RGBA, type, tmp );
444 gl_check_error("gl_load_frame_buffer:glTexSubImage2DBGRA");
445 return TRUE;
446 }
448 #else
449 /**
450 * Generic GL read_render_buffer. This function assumes that the caller
451 * has already set the appropriate glReadBuffer(); in other words, unless
452 * there's only one buffer this needs to be wrapped.
453 */
454 gboolean gl_read_render_buffer( unsigned char *target, render_buffer_t buffer,
455 int rowstride, int colour_format )
456 {
457 glFinish();
458 GLenum type = colour_formats[colour_format].type;
459 GLenum format = colour_formats[colour_format].format;
460 // int line_size = buffer->width * colour_formats[colour_format].bpp;
461 // int size = line_size * buffer->height;
462 int glrowstride = (rowstride / colour_formats[colour_format].bpp) - buffer->width;
463 glPixelStorei( GL_PACK_ROW_LENGTH, glrowstride );
464 glReadPixels( 0, 0, buffer->width, buffer->height, format, type, target );
465 glPixelStorei( GL_PACK_ROW_LENGTH, 0 );
466 return TRUE;
467 }
469 gboolean gl_load_frame_buffer( frame_buffer_t frame, int tex_id )
470 {
471 GLenum type = colour_formats[frame->colour_format].type;
472 GLenum format = colour_formats[frame->colour_format].format;
473 int bpp = colour_formats[frame->colour_format].bpp;
474 int rowstride = (frame->rowstride / bpp) - frame->width;
476 glPixelStorei( GL_UNPACK_ROW_LENGTH, rowstride );
477 glBindTexture( GL_TEXTURE_2D, tex_id );
478 glTexSubImage2DBGRA( 0, 0,0,
479 frame->width, frame->height, format, type, frame->data, FALSE );
480 glPixelStorei( GL_UNPACK_ROW_LENGTH, 0 );
481 return TRUE;
482 }
483 #endif
486 gboolean gl_init_driver( display_driver_t driver, gboolean need_fbo )
487 {
488 /* Use framebuffer objects if available */
489 if( gl_fbo_is_supported() ) {
490 gl_fbo_init(driver);
491 } else if( need_fbo ) {
492 ERROR( "Framebuffer objects not supported - unable to construct an off-screen buffer" );
493 return FALSE;
494 }
496 /* Use SL shaders if available */
497 gboolean have_shaders = glsl_init(driver);
498 #ifndef HAVE_OPENGL_FIXEDFUNC
499 if( !have_shaders ) { /* Shaders are required if we don't have fixed-functionality */
500 gl_fbo_shutdown();
501 return FALSE;
502 }
503 #endif
505 /* Use vertex arrays, VBOs, etc, if we have them */
506 gl_vbo_init(driver);
508 driver->capabilities.has_gl = TRUE;
509 driver->capabilities.has_bgra = isGLBGRATextureSupported();
510 return TRUE;
511 }
513 static gboolean video_gl_init();
515 /**
516 * Minimal GL driver (assuming that the GL context is already set up externally)
517 * This requires FBO support (since otherwise we have no way to get a render buffer)
518 */
519 struct display_driver display_gl_driver = {
520 "gl", N_("OpenGL driver"), video_gl_init, NULL,
521 NULL, NULL, NULL,
522 NULL, NULL, NULL, NULL,
523 gl_load_frame_buffer, gl_display_render_buffer, gl_display_blank,
524 NULL, gl_read_render_buffer, NULL, NULL
525 };
527 static gboolean video_gl_init()
528 {
529 return gl_init_driver(&display_gl_driver, TRUE);
530 }
.