glext.c

Go to the documentation of this file.
00001 /* This code is (C) AllegroGL contributors, and double licensed under
00002  * the GPL and zlib licenses. See gpl.txt or zlib.txt for details.
00003  */
00008 #include "alleggl.h"
00009 #include "allglint.h"
00010 #include <string.h>
00011 #ifdef ALLEGRO_MACOSX
00012 #include <OpenGL/glu.h>
00013 #else
00014 #include <GL/glu.h>
00015 #endif
00016 
00017 #include <allegro/internal/aintern.h>
00018 
00019 
00020 /* GL extension Structure. Holds the extension pointers for a single context */
00021 #define AGL_API(type, name, args) AGL_##name##_t name;
00022 typedef struct AGL_EXT {
00023 #   include "allegrogl/GLext/gl_ext_api.h"
00024 #ifdef ALLEGRO_WINDOWS
00025 #   include "allegrogl/GLext/wgl_ext_api.h"
00026 #elif defined ALLEGRO_UNIX
00027 #   include "allegrogl/GLext/glx_ext_api.h"
00028 #endif
00029 } AGL_EXT;
00030 #undef AGL_API
00031 
00032 #define PREFIX_I                "agl-ext INFO: "
00033 #define PREFIX_W                "agl-ext WARNING: "
00034 #define PREFIX_E                "agl-ext ERROR: "
00035 
00036 
00037 /* Current driver info */
00038 struct allegro_gl_info allegro_gl_info;
00039 
00040 
00041 
00055 struct AGL_EXTENSION_LIST_GL allegro_gl_extensions_GL;
00056 
00057 
00058 
00064 #ifdef ALLEGRO_UNIX
00065 struct AGL_EXTENSION_LIST_GLX allegro_gl_extensions_GLX;
00066 #endif
00067 
00068 
00069 
00075 #ifdef ALLEGRO_WINDOWS
00076 struct AGL_EXTENSION_LIST_WGL allegro_gl_extensions_WGL;
00077 #endif
00078 
00079 
00080 
00081 /* Current context */
00082 AGL_EXT *agl_extension_table = NULL;
00083 
00084 
00085 #ifdef ALLEGROGL_GENERIC_DRIVER
00086 #include "GL/amesa.h"
00087 #endif
00088 
00089 
00090 #ifdef ALLEGROGL_HAVE_DYNAMIC_LINK
00091 #include <dlfcn.h>
00092 
00093 /* Handle for dynamic library libGL.so */
00094 static void* __agl_handle = NULL;
00095 /* Pointer to glXGetProcAddressARB */
00096 typedef void* (*GLXGETPROCADDRESSARBPROC) (const GLubyte*);
00097 static GLXGETPROCADDRESSARBPROC aglXGetProcAddress;
00098 #else
00099 /* Tries static linking */
00100 #ifdef ALLEGROGL_GLXGETPROCADDRESSARB
00101 #define aglXGetProcAddress glXGetProcAddressARB
00102 #else
00103 #define aglXGetProcAddress glXGetProcAddress
00104 #endif
00105 #endif
00106 
00107 
00108 #ifdef ALLEGRO_MACOSX
00109 #undef TRUE
00110 #undef FALSE
00111 #include <Carbon/Carbon.h>
00112 #undef TRUE
00113 #undef FALSE
00114 #define TRUE  -1
00115 #define FALSE 0
00116 
00117 static CFBundleRef opengl_bundle_ref;
00118 #endif
00119 
00120 
00121 
00122 /* Define the GL API pointers */
00123 #define AGL_API(type, name, args) AGL_##name##_t __agl##name = NULL;
00124 #   include "allegrogl/GLext/gl_ext_api.h"
00125 #undef AGL_API
00126 #ifdef ALLEGRO_WINDOWS
00127 #define AGL_API(type, name, args) AGL_##name##_t __awgl##name = NULL;
00128 #   include "allegrogl/GLext/wgl_ext_api.h"
00129 #undef AGL_API
00130 #elif defined ALLEGRO_UNIX
00131 #define AGL_API(type, name, args) AGL_##name##_t __aglX##name = NULL;
00132 #   include "allegrogl/GLext/glx_ext_api.h"
00133 #undef AGL_API
00134 #endif
00135 
00136 
00137 
00138 /* Create the extension table */
00139 AGL_EXT* __allegro_gl_create_extensions() {
00140 
00141     AGL_EXT *ret = malloc(sizeof(AGL_EXT));
00142 
00143     if (!ret) {
00144         return NULL;
00145     }
00146 
00147     memset(ret, 0, sizeof(AGL_EXT));
00148 
00149     return ret;
00150 }
00151 
00152 
00153 
00154 /* Load the extension addresses into the table.
00155  * Should only be done on context creation.
00156  */
00157 void __allegro_gl_load_extensions(AGL_EXT *ext) {
00158 
00159 #ifdef ALLEGRO_MACOSX
00160     CFStringRef function;
00161 #endif
00162 
00163     if (!ext) {
00164         return;
00165     }
00166 #ifdef ALLEGRO_UNIX
00167     if (!aglXGetProcAddress) {
00168         return;
00169     }
00170 #endif
00171 
00172 #   ifdef ALLEGRO_WINDOWS
00173 #   define AGL_API(type, name, args) \
00174         ext->name = (AGL_##name##_t)wglGetProcAddress("gl" #name); \
00175         if (ext->name) { AGL_LOG(2,"gl" #name " successfully loaded\n"); }
00176 #   include "allegrogl/GLext/gl_ext_api.h"
00177 #   undef AGL_API
00178 #   define AGL_API(type, name, args) \
00179         ext->name = (AGL_##name##_t)wglGetProcAddress("wgl" #name); \
00180         if (ext->name) { AGL_LOG(2,"wgl" #name " successfully loaded\n"); }
00181 #   include "allegrogl/GLext/wgl_ext_api.h"
00182 #   undef AGL_API
00183 #   elif defined ALLEGRO_UNIX
00184 #   define AGL_API(type, name, args) \
00185         ext->name = (AGL_##name##_t)aglXGetProcAddress((const GLubyte*)"gl" #name); \
00186         if (ext->name) { AGL_LOG(2,"gl" #name " successfully loaded\n"); }
00187 #   include "allegrogl/GLext/gl_ext_api.h"
00188 #   undef AGL_API
00189 #   define AGL_API(type, name, args) \
00190         ext->name = (AGL_##name##_t)aglXGetProcAddress((const GLubyte*)"glX" #name); \
00191         if (ext->name) { AGL_LOG(2,"glX" #name " successfully loaded\n"); }
00192 #   include "allegrogl/GLext/glx_ext_api.h"
00193 #   undef AGL_API
00194 #   elif defined ALLEGRO_MACOSX
00195 #   define AGL_API(type, name, args)                                          \
00196         function = CFStringCreateWithCString(kCFAllocatorDefault, "gl" #name, \
00197                                                      kCFStringEncodingASCII); \
00198         if (function) {                                                       \
00199             ext->name = (AGL_##name##_t)CFBundleGetFunctionPointerForName(    \
00200                                              opengl_bundle_ref, function);    \
00201             CFRelease(function);                                              \
00202         }                                                                     \
00203         if (ext->name) { AGL_LOG(2,"gl" #name " successfully loaded\n"); }
00204 #   include "allegrogl/GLext/gl_ext_api.h"
00205 #   undef AGL_API
00206 #   endif
00207 }
00208 
00209 
00210 
00211 /* Set the GL API pointers to the current table 
00212  * Should only be called on context switches.
00213  */
00214 void __allegro_gl_set_extensions(AGL_EXT *ext) {
00215 
00216     if (!ext) {
00217         return;
00218     }
00219 
00220 #define AGL_API(type, name, args) __agl##name = ext->name;
00221 #   include "allegrogl/GLext/gl_ext_api.h"
00222 #undef AGL_API
00223 #ifdef ALLEGRO_WINDOWS
00224 #define AGL_API(type, name, args) __awgl##name = ext->name;
00225 #   include "allegrogl/GLext/wgl_ext_api.h"
00226 #undef AGL_API
00227 #elif defined ALLEGRO_UNIX
00228 #define AGL_API(type, name, args) __aglX##name = ext->name;
00229 #   include "allegrogl/GLext/glx_ext_api.h"
00230 #undef AGL_API
00231 #endif
00232 }
00233 
00234 
00235 
00236 /* Destroys the extension table */
00237 void __allegro_gl_destroy_extensions(AGL_EXT *ext) {
00238 
00239     if (ext) {
00240         if (ext == agl_extension_table) {
00241             agl_extension_table = NULL;
00242         }
00243         free(ext);
00244     }
00245 }
00246 
00247 
00248 
00249 /* __allegro_gl_look_for_an_extension:
00250  * This function has been written by Mark J. Kilgard in one of his
00251  * tutorials about OpenGL extensions
00252  */
00253 int __allegro_gl_look_for_an_extension(AL_CONST char *name,
00254                                                   AL_CONST GLubyte * extensions)
00255 {
00256     AL_CONST GLubyte *start;
00257     GLubyte *where, *terminator;
00258 
00259     /* Extension names should not have spaces. */
00260     where = (GLubyte *) strchr(name, ' ');
00261     if (where || *name == '\0')
00262         return FALSE;
00263     /* It takes a bit of care to be fool-proof about parsing the
00264      * OpenGL extensions string. Don't be fooled by sub-strings, etc.
00265      */
00266     start = extensions;
00267     for (;;) {
00268         where = (GLubyte *) strstr((AL_CONST char *) start, name);
00269         if (!where)
00270         break;
00271         terminator = where + strlen(name);
00272         if (where == start || *(where - 1) == ' ')
00273             if (*terminator == ' ' || *terminator == '\0')
00274                 return TRUE;
00275         start = terminator;
00276     }
00277     return FALSE;
00278 }
00279 
00280 
00281 
00282 #ifdef ALLEGRO_WINDOWS
00283 static AGL_GetExtensionsStringARB_t __wglGetExtensionsStringARB = NULL;
00284 static HDC __hdc = NULL;
00285 #elif defined ALLEGRO_UNIX
00286 #include <xalleg.h>
00287 #endif
00288 
00289 
00290 /* int allegro_gl_is_extension_supported(AL_CONST char *extension) */
00306 int allegro_gl_is_extension_supported(AL_CONST char *extension)
00307 {
00308     int ret;
00309     
00310     if (!__allegro_gl_valid_context)
00311         return FALSE;
00312 
00313     if (!glGetString(GL_EXTENSIONS))
00314         return FALSE;
00315 
00316     ret = __allegro_gl_look_for_an_extension(extension,
00317                                                   glGetString(GL_EXTENSIONS));
00318 
00319 #ifdef ALLEGRO_WINDOWS
00320     if (!ret && strncmp(extension, "WGL", 3) == 0) {
00321         if (!__wglGetExtensionsStringARB || __hdc != __allegro_gl_hdc) {
00322             __wglGetExtensionsStringARB = (AGL_GetExtensionsStringARB_t)
00323                                wglGetProcAddress("wglGetExtensionsStringARB");
00324             __hdc = __allegro_gl_hdc;
00325         }
00326         if (__wglGetExtensionsStringARB) {
00327             ret = __allegro_gl_look_for_an_extension(extension,
00328                                __wglGetExtensionsStringARB(__allegro_gl_hdc));
00329         }
00330     }
00331 #elif defined ALLEGRO_UNIX
00332     if (!ret && strncmp(extension, "GLX", 3) == 0) {
00333         XLOCK();
00334         ret = __allegro_gl_look_for_an_extension(extension,
00335                 (const GLubyte*)glXQueryExtensionsString(_xwin.display,
00336                                                          _xwin.screen));
00337         XUNLOCK();
00338     }
00339 #endif
00340 
00341     return ret;
00342 }
00343 
00344 
00345 
00346 /* void * allegro_gl_get_proc_address(AL_CONST char *name) */
00372 void *allegro_gl_get_proc_address(AL_CONST char *name)
00373 {
00374     void *symbol = NULL;
00375 #ifdef ALLEGRO_MACOSX
00376     CFStringRef function;
00377 #endif
00378 
00379     if (!__allegro_gl_valid_context)
00380         return NULL;
00381 
00382 #ifdef ALLEGROGL_GENERIC_DRIVER
00383     /* AMesa provides a function to get a proc address. It does
00384      * not emulate dynamic linking of course...
00385      */
00386     symbol = AMesaGetProcAddress(name);
00387 
00388 #elif defined ALLEGRO_WINDOWS
00389     /* For once Windows is the easiest platform to use :)
00390      * It provides a standardized way to get a function address
00391      * But of course there is a drawback : the symbol is only valid
00392      * under the current context :P
00393      */
00394     symbol = wglGetProcAddress(name);
00395 #elif defined ALLEGRO_UNIX
00396     if (aglXGetProcAddress) {
00397         /* This is definitely the *good* way on Unix to get a GL proc
00398          * address. Unfortunately glXGetProcAddress is an extension
00399          * and may not be available on all platforms
00400          */
00401         symbol = aglXGetProcAddress((const GLubyte*)name);
00402     }
00403 #elif defined ALLEGROGL_HAVE_DYNAMIC_LINK
00404     else {
00405         /* Hack if glXGetProcAddress is not available :
00406          * we try to find the symbol into libGL.so
00407          */
00408         if (__agl_handle) {
00409             symbol = dlsym(__agl_handle, name);
00410         }
00411     }
00412 #elif defined ALLEGRO_MACOSX
00413     function = CFStringCreateWithCString(kCFAllocatorDefault, name,
00414                                          kCFStringEncodingASCII);
00415     if (function) {
00416         symbol = CFBundleGetFunctionPointerForName(opengl_bundle_ref, function);
00417         CFRelease(function);
00418     }
00419 #else
00420     /* DOS does not support dynamic linking. If the function is not
00421      * available at build-time then it will not be available at run-time
00422      * Therefore we do not need to look for it...
00423      */
00424 #endif
00425 
00426     if (!symbol) {
00427 
00428 #if defined ALLEGROGL_HAVE_DYNAMIC_LINK
00429         if (!aglXGetProcAddress) {
00430             TRACE(PREFIX_W "get_proc_address: libdl::dlsym: %s\n",
00431                   dlerror());
00432         }
00433 #endif
00434         
00435         TRACE(PREFIX_W "get_proc_address : Unable to load symbol %s\n",
00436               name);
00437     }
00438     else {
00439         TRACE(PREFIX_I "get_proc_address : Symbol %s successfully loaded\n",
00440               name);
00441     }
00442     return symbol;
00443 }
00444 
00445 
00446 
00447 /* Fills in the AllegroGL info struct for blacklisting video cards.
00448  */
00449 static void __fill_in_info_struct(const GLubyte *rendereru,
00450                                   struct allegro_gl_info *info) {
00451     const char *renderer = (const char*)rendereru;
00452     
00453     /* Some cards are "special"... */
00454     if (strstr(renderer, "3Dfx/Voodoo")) {
00455         info->is_voodoo = 1;
00456     }
00457     else if (strstr(renderer, "Matrox G200")) {
00458         info->is_matrox_g200 = 1;
00459     }
00460     else if (strstr(renderer, "RagePRO")) {
00461         info->is_ati_rage_pro = 1;
00462     }
00463     else if (strstr(renderer, "RADEON 7000")) {
00464         info->is_ati_radeon_7000 = 1;
00465     }
00466     else if (strstr(renderer, "Mesa DRI R200")) {
00467         info->is_ati_r200_chip = 1;
00468     }
00469 
00470     if ((strncmp(renderer, "3Dfx/Voodoo3 ", 13) == 0)
00471      || (strncmp(renderer, "3Dfx/Voodoo2 ", 13) == 0) 
00472      || (strncmp(renderer, "3Dfx/Voodoo ", 12) == 0)) {
00473         info->is_voodoo3_and_under = 1;
00474     }
00475 
00476     /* Read OpenGL properties */    
00477     info->version = allegro_gl_opengl_version();
00478 
00479     return;
00480 }
00481 
00482 
00483 
00484 /* __allegro_gl_manage_extensions:
00485  * This functions fills the __allegro_gl_extensions structure and displays
00486  * on the log file which extensions are available
00487  */
00488 void __allegro_gl_manage_extensions(void)
00489 {
00490     AL_CONST GLubyte *buf;
00491     int i;
00492 
00493 #ifdef ALLEGRO_MACOSX
00494     CFURLRef bundle_url;
00495 #endif
00496 
00497     /* Print out OpenGL extensions */
00498 #if LOGLEVEL >= 1
00499     AGL_LOG(1, "OpenGL Extensions:\n");
00500              __allegro_gl_print_extensions((AL_CONST char*)
00501             glGetString(GL_EXTENSIONS));
00502 #endif
00503     
00504     /* Print out GLU version */
00505     buf = gluGetString(GLU_VERSION);
00506     TRACE(PREFIX_I "GLU Version : %s\n", buf);
00507 
00508 #ifdef ALLEGROGL_HAVE_DYNAMIC_LINK
00509     /* Get glXGetProcAddress entry */
00510     __agl_handle = dlopen("libGL.so", RTLD_LAZY);
00511     if (__agl_handle) {
00512         aglXGetProcAddress = (GLXGETPROCADDRESSARBPROC) dlsym(__agl_handle,
00513                                                         "glXGetProcAddressARB");
00514         if (!aglXGetProcAddress) {
00515             aglXGetProcAddress = (GLXGETPROCADDRESSARBPROC) dlsym(__agl_handle,
00516                                                            "glXGetProcAddress");
00517         }
00518     }
00519     else {
00520         TRACE(PREFIX_W "Failed to dlopen libGL.so : %s\n", dlerror());
00521     }
00522     TRACE(PREFIX_I "glXGetProcAddress Extension: %s\n",
00523                            aglXGetProcAddress ? "Supported" : "Unsupported");
00524 #elif defined ALLEGRO_UNIX
00525 #ifdef ALLEGROGL_GLXGETPROCADDRESSARB
00526     TRACE(PREFIX_I "glXGetProcAddressARB Extension: supported\n");
00527 #else
00528     TRACE(PREFIX_I "glXGetProcAddress Extension: supported\n");
00529 #endif
00530 #endif
00531     
00532 #ifdef ALLEGRO_MACOSX
00533     bundle_url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
00534                          CFSTR("/System/Library/Frameworks/OpenGL.framework"),
00535                          kCFURLPOSIXPathStyle, true);
00536     opengl_bundle_ref = CFBundleCreate(kCFAllocatorDefault, bundle_url);
00537     CFRelease(bundle_url);
00538 #endif
00539 
00540     __fill_in_info_struct(glGetString(GL_RENDERER), &allegro_gl_info);
00541 
00542     /* Load extensions */
00543     agl_extension_table = __allegro_gl_create_extensions();
00544     __allegro_gl_load_extensions(agl_extension_table);
00545     __allegro_gl_set_extensions(agl_extension_table);
00546     
00547     for (i = 0; i < 5; i++) {
00548         __allegro_gl_texture_read_format[i] = -1;
00549         __allegro_gl_texture_components[i] = GL_RGB;
00550     }
00551     __allegro_gl_texture_read_format[3] = GL_UNSIGNED_BYTE;
00552     __allegro_gl_texture_read_format[4] = GL_UNSIGNED_BYTE;
00553     __allegro_gl_texture_components[4] = GL_RGBA;
00554 
00555     
00556     /* Get extension info for the rest of the lib */
00557 #    define AGL_EXT(name, ver) {                               \
00558         allegro_gl_extensions_GL.name =                        \
00559               allegro_gl_is_extension_supported("GL_" #name)   \
00560           || (allegro_gl_info.version >= ver && ver > 0);      \
00561     }
00562 #   include "allegrogl/GLext/gl_ext_list.h"
00563 #   undef AGL_EXT
00564 
00565 #ifdef ALLEGRO_UNIX
00566 #    define AGL_EXT(name, ver) {                               \
00567         allegro_gl_extensions_GLX.name =                       \
00568               allegro_gl_is_extension_supported("GLX_" #name)  \
00569           || (allegro_gl_info.version >= ver && ver > 0);      \
00570     }
00571 #   include "allegrogl/GLext/glx_ext_list.h"
00572 #   undef AGL_EXT
00573 #elif defined ALLEGRO_WINDOWS
00574 #    define AGL_EXT(name, ver) {                               \
00575         allegro_gl_extensions_WGL.name =                       \
00576               allegro_gl_is_extension_supported("WGL_" #name)  \
00577           || (allegro_gl_info.version >= ver && ver > 0);      \
00578     }
00579 #   include "allegrogl/GLext/wgl_ext_list.h"
00580 #   undef AGL_EXT
00581 #endif
00582     
00583     /* Get number of texture units */
00584     if (allegro_gl_extensions_GL.ARB_multitexture) {
00585         glGetIntegerv(GL_MAX_TEXTURE_UNITS,
00586                       (GLint*)&allegro_gl_info.num_texture_units);
00587     }
00588     else {
00589         allegro_gl_info.num_texture_units = 1;
00590     }
00591 
00592     /* Get max texture size */
00593     glGetIntegerv(GL_MAX_TEXTURE_SIZE,
00594                   (GLint*)&allegro_gl_info.max_texture_size);
00595 
00596     /* Note: Voodoo (even V5) don't seem to correctly support
00597      * packed pixel formats. Disabling them for those cards.
00598      */
00599     allegro_gl_extensions_GL.EXT_packed_pixels &= !allegro_gl_info.is_voodoo;
00600 
00601     
00602     if (allegro_gl_extensions_GL.EXT_packed_pixels) {
00603 
00604         AGL_LOG(1, "Packed Pixels formats available\n");
00605 
00606         /* XXX On NV cards, we want to use BGRA instead of RGBA for speed */
00607         /* Fills the __allegro_gl_texture_format array */
00608         __allegro_gl_texture_read_format[0] = GL_UNSIGNED_BYTE_3_3_2;
00609         __allegro_gl_texture_read_format[1] = GL_UNSIGNED_SHORT_5_5_5_1;
00610         __allegro_gl_texture_read_format[2] = GL_UNSIGNED_SHORT_5_6_5;
00611     }
00612 
00613     /* NVidia and ATI cards expose OpenGL 2.0 but often don't accelerate
00614      * non-power-of-2 textures. This check is how you verify that NP2
00615      * textures are hardware accelerated or not.
00616      * We should clobber the NPOT support if it's not accelerated.
00617      */
00618     {   const char *vendor = (const char*)glGetString(GL_VENDOR);
00619         if (strstr(vendor, "NVIDIA Corporation")) {
00620             if (!allegro_gl_extensions_GL.NV_fragment_program2
00621              || !allegro_gl_extensions_GL.NV_vertex_program3) {
00622                 allegro_gl_extensions_GL.ARB_texture_non_power_of_two = 0;
00623             }
00624         }
00625         else if (strstr(vendor, "ATI Technologies")) {
00626             if (!strstr((const char*)glGetString(GL_EXTENSIONS),
00627                         "GL_ARB_texture_non_power_of_two")
00628              && allegro_gl_info.version >= 2.0f) {
00629                 allegro_gl_extensions_GL.ARB_texture_non_power_of_two = 0;
00630             }
00631         }
00632     }
00633 }
00634 
00635 
00636 
00637 /* __allegro_gl_print_extensions:
00638  * Given a string containing extensions (i.e. a NULL terminated string where
00639  * each extension are separated by a space and which names do not contain any
00640  * space)
00641  */
00642 void __allegro_gl_print_extensions(AL_CONST char * extension)
00643 {
00644         char buf[80];
00645         char* start;
00646 
00647         while (*extension != '\0') {
00648                 start = buf;
00649                 strncpy(buf, extension, 80);
00650                 while ((*start != ' ') && (*start != '\0')) {
00651                         extension++;
00652                         start++;
00653                 }
00654                 *start = '\0';
00655                 extension ++;
00656                 TRACE(PREFIX_I "%s\n", buf);
00657         }
00658 }
00659 
00660 
00661 
00662 void __allegro_gl_unmanage_extensions() {
00663     __allegro_gl_destroy_extensions(agl_extension_table);
00664 #ifdef ALLEGRO_MACOSX
00665     CFRelease(opengl_bundle_ref);
00666 #endif
00667 #ifdef ALLEGROGL_HAVE_DYNAMIC_LINK
00668     if (__agl_handle) {
00669         dlclose(__agl_handle);
00670         __agl_handle = NULL;
00671     }
00672 #endif
00673 }
00674 

Generated on Sun Nov 11 15:52:55 2007 for AllegroGL by  doxygen 1.5.2