Search
lxdream.org :: lxdream/src/drivers/video_gl.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/drivers/video_gl.c
changeset 1282:9f445c5e252b
prev1262:4baa34eee6fc
next1298: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 }
.