AllegroGL 0.4.4
|
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 (AL_CONST GLubyte*)__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