4 * Common GL code that doesn't depend on a specific implementation
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.
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;
35 static struct video_box_t {
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];
43 void gl_set_video_size( uint32_t width, uint32_t height, int flipped )
46 video_height = height;
48 int x1=0,y1=0,x2=video_width,y2=video_height;
49 int top = 0, bottom = 1;
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;
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;
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;
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);
100 #ifdef HAVE_OPENGL_FIXEDFUNC
102 * Setup the gl context for writes to the display output.
104 void gl_framebuffer_setup()
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 );
118 void gl_framebuffer_cleanup()
120 glDisableClientState( GL_VERTEX_ARRAY );
121 glDisableClientState( GL_COLOR_ARRAY );
122 glDisableClientState( GL_TEXTURE_COORD_ARRAY );
125 void gl_framebuffer_setup()
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);
137 void gl_framebuffer_cleanup()
143 void gl_display_render_buffer( render_buffer_t buffer )
145 gl_texture_window( buffer->width, buffer->height, buffer->buf_id, buffer->inverted );
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.
153 void gl_window_to_system_coords( int *x, int *y )
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;
163 } else if( ah < video_height ) {
164 y1 = (video_height - ah)/2;
167 if( *x < x1 || *x >= x2 || *y < y1 || *y >= y2 ) {
171 *x = (*x - x1) * DISPLAY_WIDTH / (x2-x1);
172 *y = (*y - y1) * DISPLAY_HEIGHT / (y2-y1);
177 * Use quads if we have them, otherwise tri-fans.
180 #define GL_QUADS GL_TRIANGLE_FAN
183 void gl_texture_window( int width, int height, int tex_id, gboolean inverted )
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();
203 void gl_display_blank( uint32_t colour )
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 );
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();
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.
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
240 static void rgba32_to_target( unsigned char *target, const uint32_t *source, int width, int height, int target_stride, int colour_format )
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) );
256 target += target_stride;
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) );
266 target += target_stride;
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) );
277 target += target_stride;
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);
287 target += target_stride;
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);
297 target += target_stride;
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);
309 target += target_stride;
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++;
318 *d++ = (uint8_t)(v >> 8);
319 *d++ = (uint8_t)(v >> 16);
321 target += target_stride;
325 assert( 0 && "Unsupported colour format" );
330 * Convert data into an acceptable form for loading into an RGBA texture.
332 static int target_to_rgba( uint32_t *target, const unsigned char *source, int width, int height, int source_stride, int colour_format )
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++ ) {
343 *d++ = (v >> 15) | (v<<1);
345 source += source_stride;
347 return GL_UNSIGNED_SHORT_5_5_5_1;
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);
358 source += source_stride;
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++ ) {
367 *d++ = (v >> 12) | (v<<4);
369 source += source_stride;
371 return GL_UNSIGNED_SHORT_4_4_4_4;
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);
379 source += source_stride;
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);
389 source += source_stride;
391 return GL_UNSIGNED_BYTE;
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);
399 source += source_stride;
401 return GL_UNSIGNED_BYTE;
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);
409 source += source_stride;
411 return GL_UNSIGNED_BYTE;
413 assert( 0 && "Unsupported colour format" );
420 gboolean gl_read_render_buffer( unsigned char *target, render_buffer_t buffer,
421 int rowstride, int colour_format )
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 );
427 int size = buffer->width * buffer->height;
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 );
436 void gl_frame_buffer_to_tex( frame_buffer_t frame, int tex_id )
438 int size = frame->width * frame->height;
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_frame_buffer_to_tex:glTexSubImage2DBGRA");
449 * Generic GL read_render_buffer. This function assumes that the caller
450 * has already set the appropriate glReadBuffer(); in other words, unless
451 * there's only one buffer this needs to be wrapped.
453 gboolean gl_read_render_buffer( unsigned char *target, render_buffer_t buffer,
454 int rowstride, int colour_format )
457 GLenum type = colour_formats[colour_format].type;
458 GLenum format = colour_formats[colour_format].format;
459 // int line_size = buffer->width * colour_formats[colour_format].bpp;
460 // int size = line_size * buffer->height;
461 int glrowstride = (rowstride / colour_formats[colour_format].bpp) - buffer->width;
462 glPixelStorei( GL_PACK_ROW_LENGTH, glrowstride );
463 glReadPixels( 0, 0, buffer->width, buffer->height, format, type, target );
464 glPixelStorei( GL_PACK_ROW_LENGTH, 0 );
468 void gl_frame_buffer_to_tex( frame_buffer_t frame, int tex_id )
470 GLenum type = colour_formats[frame->colour_format].type;
471 GLenum format = colour_formats[frame->colour_format].format;
472 int bpp = colour_formats[frame->colour_format].bpp;
473 int rowstride = (frame->rowstride / bpp) - frame->width;
475 glPixelStorei( GL_UNPACK_ROW_LENGTH, rowstride );
476 glBindTexture( GL_TEXTURE_2D, tex_id );
477 glTexSubImage2DBGRA( 0, 0,0,
478 frame->width, frame->height, format, type, frame->data, FALSE );
479 glPixelStorei( GL_UNPACK_ROW_LENGTH, 0 );
483 void gl_load_frame_buffer( frame_buffer_t frame, render_buffer_t render )
485 gl_frame_buffer_to_tex( frame, render->tex_id );
489 gboolean gl_init_driver( display_driver_t driver, gboolean need_fbo )
491 /* Use framebuffer objects if available */
492 if( gl_fbo_is_supported() ) {
494 } else if( need_fbo ) {
495 ERROR( "Framebuffer objects not supported - unable to construct an off-screen buffer" );
499 /* Use SL shaders if available */
501 #ifndef HAVE_OPENGL_FIXEDFUNC
502 if( !driver->has_sl ) { /* Shaders are required if we don't have fixed-functionality */
508 /* Use vertex arrays, VBOs, etc, if we have them */
511 driver->capabilities.has_gl = TRUE;
512 driver->capabilities.has_bgra = isGLBGRATextureSupported();
516 static gboolean video_gl_init();
519 * Minimal GL driver (assuming that the GL context is already set up externally)
520 * This requires FBO support (since otherwise we have no way to get a render buffer)
522 struct display_driver display_gl_driver = {
523 "gl", N_("OpenGL driver"), video_gl_init, NULL,
525 NULL, NULL, NULL, NULL,
526 gl_load_frame_buffer, gl_display_render_buffer, gl_display_blank,
527 NULL, gl_read_render_buffer, NULL, NULL
530 static gboolean video_gl_init()
532 return gl_init_driver(&display_gl_driver, TRUE);
.