Search
lxdream.org :: lxdream/src/drivers/video_glx.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/drivers/video_glx.c
changeset 863:a5e5310061e2
prev806:6ef1ce4a9dbc
next982:2d6b3f29f878
author nkeynes
date Sun Sep 28 01:09:51 2008 +0000 (13 years ago)
permissions -rw-r--r--
last change Initial shadow volume implementation for opaque polygons (stencil isn't quite
right, but we get some kind of shadows now)
view annotate diff log raw
     1 /**
     2  * $Id$
     3  *
     4  * Shared functions for all X11-based display drivers.
     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 <stdlib.h>
    20 #include <string.h>
    21 #include "display.h"
    22 #include <X11/Xlib.h>
    23 #include <GL/glx.h>
    24 #include "pvr2/pvr2.h"
    25 #include "pvr2/glutil.h"
    26 #include "drivers/video_glx.h"
    27 #include "drivers/video_gl.h"
    29 /**
    30  * General X11 parameters. The front-end driver is expected to set this up
    31  * by calling video_glx_init after initializing itself.
    32  */
    33 Display *video_x11_display = NULL;
    34 Window video_x11_window = 0;
    36 static int glx_version = 100;
    37 static XVisualInfo *glx_visual = NULL;
    38 static GLXFBConfig glx_fbconfig;
    39 static GLXContext glx_context = NULL;
    40 static gboolean glx_is_initialized = FALSE;
    41 static gboolean glx_fbconfig_supported = FALSE;
    42 static gboolean glx_pbuffer_supported = FALSE;
    43 static GLuint glx_pbuffer_texture = 0; 
    45 /* Prototypes for pbuffer support methods */
    46 static void glx_pbuffer_init( display_driver_t driver );
    47 static render_buffer_t glx_pbuffer_create_render_buffer( uint32_t width, uint32_t height, GLuint tex_id );
    48 static void glx_pbuffer_destroy_render_buffer( render_buffer_t buffer );
    49 static gboolean glx_pbuffer_set_render_target( render_buffer_t buffer );
    50 static void glx_pbuffer_finish_render( render_buffer_t buffer );
    51 static void glx_pbuffer_display_render_buffer( render_buffer_t buffer );
    52 static void glx_pbuffer_load_frame_buffer( frame_buffer_t frame, render_buffer_t buffer );
    53 static void glx_pbuffer_display_blank( uint32_t colour );
    54 static gboolean glx_pbuffer_read_render_buffer( unsigned char *target, render_buffer_t buffer, int rowstride, int format );
    56 /**
    57  * Test if a specific extension is supported. From opengl.org
    58  * @param extension extension name to check for
    59  * @return TRUE if supported, otherwise FALSE.
    60  */
    61 gboolean isServerGLXExtensionSupported( Display *display, int screen, 
    62                                         const char *extension )
    63 {
    64     const char *extensions = NULL;
    65     const char *start;
    66     char *where, *terminator;
    68     /* Extension names should not have spaces. */
    69     where = strchr(extension, ' ');
    70     if (where || *extension == '\0')
    71         return 0;
    72     extensions = glXQueryServerString(display, screen, GLX_EXTENSIONS);
    73     start = extensions;
    74     for (;;) {
    75         where = strstr((const char *) start, extension);
    76         if (!where)
    77             break;
    78         terminator = where + strlen(extension);
    79         if (where == start || *(where - 1) == ' ')
    80             if (*terminator == ' ' || *terminator == '\0')
    81                 return TRUE;
    82         start = terminator;
    83     }
    84     return FALSE;
    85 }
    87 gboolean video_glx_init( Display *display, int screen )
    88 {
    89     int major, minor;
    91     if( glx_is_initialized ) {
    92         return TRUE;
    93     }
    95     Bool result = glXQueryVersion( display, &major, &minor );
    96     if( result != False ) {
    97         glx_version = (major*100) + minor;
    98     }
    99 #ifdef APPLE_BUILD
   100     /* fbconfig is broken on at least the 10.5 GLX implementation */
   101     glx_fbconfig_supported = FALSE;
   102 #else
   103     glx_fbconfig_supported = (glx_version >= 103 || 
   104             isServerGLXExtensionSupported(display, screen,
   105                     "GLX_SGIX_fbconfig") );
   106 #endif
   107     glx_pbuffer_supported = (glx_version >= 103 ||
   108             isServerGLXExtensionSupported(display, screen,
   109                     "GLX_SGIX_pbuffer") );
   110 //    glx_fbconfig_supported = FALSE;
   111     if( glx_fbconfig_supported ) {
   112         int nelem;
   113         int fb_attribs[] = { GLX_DRAWABLE_TYPE, 
   114                 GLX_PBUFFER_BIT|GLX_WINDOW_BIT, 
   115                 GLX_RENDER_TYPE, GLX_RGBA_BIT, 
   116                 GLX_DEPTH_SIZE, 24, 
   117                 GLX_STENCIL_SIZE, 8, 0 };
   118         GLXFBConfig *configs = glXChooseFBConfig( display, screen, 
   119                 fb_attribs, &nelem );
   121         if( configs == NULL || nelem == 0 ) {
   122             /* Try a 16-bit depth buffer and see if it helps */
   123             fb_attribs[5] = 16;
   124             configs = glXChooseFBConfig( display, screen, fb_attribs, &nelem );
   125             if( nelem > 0 ) {
   126                 WARN( "Using a 16-bit depth buffer - expect video glitches" );
   127             }
   129         }
   130         if( configs == NULL || nelem == 0 ) {
   131             /* Still didn't work. Fallback to 1.2 methods */
   132             glx_fbconfig_supported = FALSE;
   133             glx_pbuffer_supported = FALSE;
   134         } else {
   135             glx_fbconfig = configs[0];
   136             glx_visual = glXGetVisualFromFBConfig(display, glx_fbconfig);
   137             XFree(configs);
   138         }
   139     }
   141     if( !glx_fbconfig_supported ) {
   142         int attribs[] = { GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_STENCIL_SIZE, 8, 0 };
   143         glx_visual = glXChooseVisual( display, screen, attribs );
   144         if( glx_visual == NULL ) {
   145             /* Try the 16-bit fallback here too */
   146             attribs[2] = 16;
   147             glx_visual = glXChooseVisual( display, screen, attribs );
   148             if( glx_visual != NULL ) {
   149                 WARN( "Using a 16-bit depth buffer - expect video glitches" );
   150             }
   151         }
   152     }
   154     if( glx_visual == NULL ) {
   155         return FALSE;
   156     }
   158     glx_is_initialized = TRUE;
   159     return TRUE;
   160 }
   162 gboolean video_glx_init_context( Display *display, Window window )
   163 {
   164     if( glx_fbconfig_supported ) {
   165         glx_context = glXCreateNewContext( display, glx_fbconfig, 
   166                 GLX_RGBA_TYPE, NULL, True );
   167         if( glx_context == NULL ) {
   168             ERROR( "Unable to create a GLX Context.");
   169             return FALSE;
   170         }
   172         if( glXMakeContextCurrent( display, window, window, 
   173                 glx_context ) == False ) {
   174             ERROR( "Unable to prepare GLX context for drawing" );
   175             glXDestroyContext( display, glx_context );
   176             return FALSE;
   177         }
   178     } else {
   179         glx_context = glXCreateContext( display, glx_visual, None, True );
   180         if( glx_context == NULL ) {
   181             ERROR( "Unable to create a GLX Context.");
   182             return FALSE;
   183         }
   185         if( glXMakeCurrent( display, window, glx_context ) == False ) {
   186             ERROR( "Unable to prepare GLX context for drawing" );
   187             glXDestroyContext( display, glx_context );
   188             return FALSE;
   189         }
   190     }
   192     if( !glXIsDirect(display, glx_context) ) {
   193         WARN( "Not using direct rendering - this is likely to be slow" );
   194     }
   196     video_x11_display = display;
   197     video_x11_window = window;
   199     return TRUE;
   200 }
   202 gboolean video_glx_init_driver( display_driver_t driver )
   203 {
   204     if( gl_fbo_is_supported() ) { // First preference
   205         gl_fbo_init(driver);
   206     } else if( glx_pbuffer_supported ) {
   207         glx_pbuffer_init(driver);
   208     } else {
   209         ERROR( "Unable to create render buffers (requires either EXT_framebuffer_object or GLX 1.3+)" );
   210         video_glx_shutdown();
   211         return FALSE;
   212     }
   213     return TRUE;
   214 }
   217 void video_glx_shutdown()
   218 {
   219     //    texcache_gl_shutdown();
   220     glx_is_initialized = FALSE;
   221     if( glx_context != NULL ) {
   222         glXDestroyContext( video_x11_display, glx_context );
   223         glx_context = NULL;
   224     }
   225     if( glx_visual != NULL ) {
   226         XFree(glx_visual);
   227         glx_visual = NULL;
   228     }
   229 }
   232 XVisualInfo *video_glx_get_visual()
   233 {
   234     return glx_visual;
   235 }
   238 int video_glx_load_font( const gchar *font_name )
   239 {
   240     int lists;
   241     XFontStruct *font = XLoadQueryFont(video_x11_display, font_name );
   242     if (font == NULL)
   243         return -1;
   245     lists = glGenLists(96);
   246     glXUseXFont(font->fid, 32, 96, lists);
   247     XFreeFont(video_x11_display, font);
   248     return lists;
   249 }
   252 void video_glx_swap_buffers( void )
   253 {
   254     glXSwapBuffers( video_x11_display, video_x11_window );
   255 }
   257 void video_glx_make_window_current( void )
   258 {
   259     glXMakeCurrent( video_x11_display, video_x11_window, glx_context );
   260 }
   263 // Pbuffer support
   265 /**
   266  * Construct the initial frame buffers and allocate ids for everything.
   267  * The render handling driver methods are set to the fbo versions.
   268  */
   269 static void glx_pbuffer_init( display_driver_t driver ) 
   270 {
   271     GLint stencil_bits = 0;
   273     /* Retrieve the number of stencil bits */
   274     glGetIntegerv( GL_STENCIL_BITS, &stencil_bits );
   275     driver->capabilities.stencil_bits = stencil_bits;
   277     glGenTextures( 1, &glx_pbuffer_texture );
   278     driver->create_render_buffer = glx_pbuffer_create_render_buffer;
   279     driver->destroy_render_buffer = glx_pbuffer_destroy_render_buffer;
   280     driver->set_render_target = glx_pbuffer_set_render_target;
   281     driver->finish_render = glx_pbuffer_finish_render;
   282     driver->display_render_buffer = glx_pbuffer_display_render_buffer;
   283     driver->load_frame_buffer = glx_pbuffer_load_frame_buffer;
   284     driver->display_blank = glx_pbuffer_display_blank;
   285     driver->read_render_buffer = glx_pbuffer_read_render_buffer;
   286 }
   288 void glx_pbuffer_shutdown()
   289 {
   290     glDeleteTextures( 1, &glx_pbuffer_texture );
   291 }
   293 static render_buffer_t glx_pbuffer_create_render_buffer( uint32_t width, uint32_t height, GLuint tex_id )
   294 {
   295     int attribs[] = { GLX_PBUFFER_WIDTH, width, GLX_PBUFFER_HEIGHT, height,
   296             GLX_PRESERVED_CONTENTS, True, 0 };
   297     GLXPbuffer pb = glXCreatePbuffer( video_x11_display, glx_fbconfig, attribs );
   298     if( pb == (GLXPbuffer)NULL ) {
   299         ERROR( "Unable to create pbuffer" );
   300         return NULL;
   301     }
   302     render_buffer_t buffer = calloc( sizeof(struct render_buffer), 1 );
   303     buffer->width = width;
   304     buffer->height = height;
   305     buffer->buf_id = pb;
   306     buffer->tex_id = tex_id;
   307     return buffer;
   308 }
   310 static void glx_pbuffer_destroy_render_buffer( render_buffer_t buffer )
   311 {
   312     glXDestroyPbuffer( video_x11_display, (GLXPbuffer)buffer->buf_id );
   313     buffer->buf_id = 0;
   314     free( buffer );
   315 }
   317 static gboolean glx_pbuffer_set_render_target( render_buffer_t buffer )
   318 {
   319     glFinish();
   320     if( glXMakeContextCurrent( video_x11_display, (GLXPbuffer)buffer->buf_id, (GLXPbuffer)buffer->buf_id, glx_context ) == False ) {
   321         ERROR( "Make context current (pbuffer) failed!" );
   322     }
   323     /* setup the gl context */
   324     glViewport( 0, 0, buffer->width, buffer->height );
   325     glDrawBuffer(GL_FRONT);
   327     return TRUE;
   328 }
   330 static void glx_pbuffer_finish_render( render_buffer_t buffer )
   331 {
   332     glFinish();
   333     if( buffer->tex_id != 0 ) {
   334         // The pbuffer should already be the current context, but just in case...
   335         glXMakeContextCurrent( video_x11_display, (GLXPbuffer)buffer->buf_id, (GLXPbuffer)buffer->buf_id, glx_context );
   336         glBindTexture( GL_TEXTURE_RECTANGLE_ARB, buffer->tex_id );
   337         glCopyTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, 0, 0, buffer->width, buffer->height, 0 );
   338     }
   339 }
   342 /**
   343  * Render the texture holding the given buffer to the front window
   344  * buffer.
   345  */
   346 static void glx_pbuffer_display_render_buffer( render_buffer_t buffer )
   347 {
   348     glFinish();
   349     glReadBuffer( GL_FRONT );
   350     glDrawBuffer( GL_FRONT );
   351     glXMakeContextCurrent( video_x11_display, (GLXPbuffer)buffer->buf_id, (GLXPbuffer)buffer->buf_id, glx_context );
   352     glBindTexture( GL_TEXTURE_RECTANGLE_ARB, glx_pbuffer_texture );
   353     glCopyTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, 0, 0, buffer->width, buffer->height, 0 );
   354     video_glx_make_window_current();
   355     gl_texture_window( buffer->width, buffer->height, glx_pbuffer_texture, buffer->inverted );
   356 }
   358 static void glx_pbuffer_load_frame_buffer( frame_buffer_t frame, render_buffer_t buffer )
   359 {
   360     glFinish();
   361     glXMakeContextCurrent( video_x11_display, (GLXPbuffer)buffer->buf_id, (GLXPbuffer)buffer->buf_id, glx_context );
   362     GLenum type = colour_formats[frame->colour_format].type;
   363     GLenum format = colour_formats[frame->colour_format].format;
   364     int bpp = colour_formats[frame->colour_format].bpp;
   365     int rowstride = (frame->rowstride / bpp) - frame->width;
   367     gl_reset_state();
   368     glPixelStorei( GL_UNPACK_ROW_LENGTH, rowstride );
   369     glRasterPos2f(0.375, frame->height-0.375);
   370     glPixelZoom( 1.0, 1.0 );
   371     glDrawPixels( frame->width, frame->height, format, type, frame->data );
   372     glFlush();
   373 }
   375 static void glx_pbuffer_display_blank( uint32_t colour )
   376 {
   377     glFinish();
   378     video_glx_make_window_current();
   379     gl_display_blank( colour );
   380 }
   382 static gboolean glx_pbuffer_read_render_buffer( unsigned char *target, render_buffer_t buffer, 
   383                                                 int rowstride, int format )
   384 {
   385     glXMakeCurrent( video_x11_display, (GLXDrawable)buffer->buf_id, glx_context );
   386     glReadBuffer( GL_FRONT );
   387     return gl_read_render_buffer( target, buffer, rowstride, format );
   388 }
.