AllegroGL  0.4.4
glext.c
Go to the documentation of this file.
1 /* This code is (C) AllegroGL contributors, and double licensed under
2  * the GPL and zlib licenses. See gpl.txt or zlib.txt for details.
3  */
8 #include "alleggl.h"
9 #include "allglint.h"
10 #include <string.h>
11 #ifdef ALLEGRO_MACOSX
12 #include <OpenGL/glu.h>
13 #else
14 #include <GL/glu.h>
15 #endif
16 
17 #include <allegro/internal/aintern.h>
18 
19 
20 /* GL extension Structure. Holds the extension pointers for a single context */
21 #define AGL_API(type, name, args) AGL_##name##_t name;
22 typedef struct AGL_EXT {
23 # include "allegrogl/GLext/gl_ext_api.h"
24 #ifdef ALLEGRO_WINDOWS
25 # include "allegrogl/GLext/wgl_ext_api.h"
26 #elif defined ALLEGRO_UNIX
27 # include "allegrogl/GLext/glx_ext_api.h"
28 #endif
29 } AGL_EXT;
30 #undef AGL_API
31 
32 #define PREFIX_I "agl-ext INFO: "
33 #define PREFIX_W "agl-ext WARNING: "
34 #define PREFIX_E "agl-ext ERROR: "
35 
36 
37 /* Current driver info */
38 struct allegro_gl_info allegro_gl_info;
39 
40 
41 
55 struct AGL_EXTENSION_LIST_GL allegro_gl_extensions_GL;
56 
57 
58 
64 #ifdef ALLEGRO_UNIX
65 struct AGL_EXTENSION_LIST_GLX allegro_gl_extensions_GLX;
66 #endif
67 
68 
69 
75 #ifdef ALLEGRO_WINDOWS
76 struct AGL_EXTENSION_LIST_WGL allegro_gl_extensions_WGL;
77 #endif
78 
79 
80 
81 /* Current context */
82 AGL_EXT *agl_extension_table = NULL;
83 
84 
85 #ifdef ALLEGROGL_GENERIC_DRIVER
86 #include "GL/amesa.h"
87 #endif
88 
89 
90 #ifdef ALLEGROGL_HAVE_DYNAMIC_LINK
91 #include <dlfcn.h>
92 
93 /* Handle for dynamic library libGL.so */
94 static void* __agl_handle = NULL;
95 /* Pointer to glXGetProcAddressARB */
96 typedef void* (*GLXGETPROCADDRESSARBPROC) (const GLubyte*);
97 static GLXGETPROCADDRESSARBPROC aglXGetProcAddress;
98 #else
99 /* Tries static linking */
100 #ifdef ALLEGROGL_GLXGETPROCADDRESSARB
101 #define aglXGetProcAddress glXGetProcAddressARB
102 #else
103 #define aglXGetProcAddress glXGetProcAddress
104 #endif
105 #endif
106 
107 
108 #ifdef ALLEGRO_MACOSX
109 #undef TRUE
110 #undef FALSE
111 #include <Carbon/Carbon.h>
112 #undef TRUE
113 #undef FALSE
114 #define TRUE -1
115 #define FALSE 0
116 
117 static CFBundleRef opengl_bundle_ref;
118 #endif
119 
120 
121 
122 /* Define the GL API pointers */
123 #define AGL_API(type, name, args) AGL_##name##_t __agl##name = NULL;
124 # include "allegrogl/GLext/gl_ext_api.h"
125 #undef AGL_API
126 #ifdef ALLEGRO_WINDOWS
127 #define AGL_API(type, name, args) AGL_##name##_t __awgl##name = NULL;
128 # include "allegrogl/GLext/wgl_ext_api.h"
129 #undef AGL_API
130 #elif defined ALLEGRO_UNIX
131 #define AGL_API(type, name, args) AGL_##name##_t __aglX##name = NULL;
132 # include "allegrogl/GLext/glx_ext_api.h"
133 #undef AGL_API
134 #endif
135 
136 
137 
138 /* Create the extension table */
139 AGL_EXT* __allegro_gl_create_extensions() {
140 
141  AGL_EXT *ret = malloc(sizeof(AGL_EXT));
142 
143  if (!ret) {
144  return NULL;
145  }
146 
147  memset(ret, 0, sizeof(AGL_EXT));
148 
149  return ret;
150 }
151 
152 
153 
154 /* Load the extension addresses into the table.
155  * Should only be done on context creation.
156  */
157 void __allegro_gl_load_extensions(AGL_EXT *ext) {
158 
159 #ifdef ALLEGRO_MACOSX
160  CFStringRef function;
161 #endif
162 
163  if (!ext) {
164  return;
165  }
166 #ifdef ALLEGRO_UNIX
167  if (!aglXGetProcAddress) {
168  return;
169  }
170 #endif
171 
172 # ifdef ALLEGRO_WINDOWS
173 # define AGL_API(type, name, args) \
174  ext->name = (AGL_##name##_t)wglGetProcAddress("gl" #name); \
175  if (ext->name) { AGL_LOG(2,"gl" #name " successfully loaded\n"); }
176 # include "allegrogl/GLext/gl_ext_api.h"
177 # undef AGL_API
178 # define AGL_API(type, name, args) \
179  ext->name = (AGL_##name##_t)wglGetProcAddress("wgl" #name); \
180  if (ext->name) { AGL_LOG(2,"wgl" #name " successfully loaded\n"); }
181 # include "allegrogl/GLext/wgl_ext_api.h"
182 # undef AGL_API
183 # elif defined ALLEGRO_UNIX
184 # define AGL_API(type, name, args) \
185  ext->name = (AGL_##name##_t)aglXGetProcAddress((const GLubyte*)"gl" #name); \
186  if (ext->name) { AGL_LOG(2,"gl" #name " successfully loaded\n"); }
187 # include "allegrogl/GLext/gl_ext_api.h"
188 # undef AGL_API
189 # define AGL_API(type, name, args) \
190  ext->name = (AGL_##name##_t)aglXGetProcAddress((const GLubyte*)"glX" #name); \
191  if (ext->name) { AGL_LOG(2,"glX" #name " successfully loaded\n"); }
192 # include "allegrogl/GLext/glx_ext_api.h"
193 # undef AGL_API
194 # elif defined ALLEGRO_MACOSX
195 # define AGL_API(type, name, args) \
196  function = CFStringCreateWithCString(kCFAllocatorDefault, "gl" #name, \
197  kCFStringEncodingASCII); \
198  if (function) { \
199  ext->name = (AGL_##name##_t)CFBundleGetFunctionPointerForName( \
200  opengl_bundle_ref, function); \
201  CFRelease(function); \
202  } \
203  if (ext->name) { AGL_LOG(2,"gl" #name " successfully loaded\n"); }
204 # include "allegrogl/GLext/gl_ext_api.h"
205 # undef AGL_API
206 # endif
207 }
208 
209 
210 
211 /* Set the GL API pointers to the current table
212  * Should only be called on context switches.
213  */
214 void __allegro_gl_set_extensions(AGL_EXT *ext) {
215 
216  if (!ext) {
217  return;
218  }
219 
220 #define AGL_API(type, name, args) __agl##name = ext->name;
221 # include "allegrogl/GLext/gl_ext_api.h"
222 #undef AGL_API
223 #ifdef ALLEGRO_WINDOWS
224 #define AGL_API(type, name, args) __awgl##name = ext->name;
225 # include "allegrogl/GLext/wgl_ext_api.h"
226 #undef AGL_API
227 #elif defined ALLEGRO_UNIX
228 #define AGL_API(type, name, args) __aglX##name = ext->name;
229 # include "allegrogl/GLext/glx_ext_api.h"
230 #undef AGL_API
231 #endif
232 }
233 
234 
235 
236 /* Destroys the extension table */
237 void __allegro_gl_destroy_extensions(AGL_EXT *ext) {
238 
239  if (ext) {
240  if (ext == agl_extension_table) {
241  agl_extension_table = NULL;
242  }
243  free(ext);
244  }
245 }
246 
247 
248 
249 /* __allegro_gl_look_for_an_extension:
250  * This function has been written by Mark J. Kilgard in one of his
251  * tutorials about OpenGL extensions
252  */
253 int __allegro_gl_look_for_an_extension(AL_CONST char *name,
254  AL_CONST GLubyte * extensions)
255 {
256  AL_CONST GLubyte *start;
257  GLubyte *where, *terminator;
258 
259  /* Extension names should not have spaces. */
260  where = (GLubyte *) strchr(name, ' ');
261  if (where || *name == '\0')
262  return FALSE;
263  /* It takes a bit of care to be fool-proof about parsing the
264  * OpenGL extensions string. Don't be fooled by sub-strings, etc.
265  */
266  start = extensions;
267  for (;;) {
268  where = (GLubyte *) strstr((AL_CONST char *) start, name);
269  if (!where)
270  break;
271  terminator = where + strlen(name);
272  if (where == start || *(where - 1) == ' ')
273  if (*terminator == ' ' || *terminator == '\0')
274  return TRUE;
275  start = terminator;
276  }
277  return FALSE;
278 }
279 
280 
281 
282 #ifdef ALLEGRO_WINDOWS
283 static AGL_GetExtensionsStringARB_t __wglGetExtensionsStringARB = NULL;
284 static HDC __hdc = NULL;
285 #elif defined ALLEGRO_UNIX
286 #include <xalleg.h>
287 #endif
288 
289 
290 /* int allegro_gl_is_extension_supported(AL_CONST char *extension) */
306 int allegro_gl_is_extension_supported(AL_CONST char *extension)
307 {
308  int ret;
309 
310  if (!__allegro_gl_valid_context)
311  return FALSE;
312 
313  if (!glGetString(GL_EXTENSIONS))
314  return FALSE;
315 
316  ret = __allegro_gl_look_for_an_extension(extension,
317  glGetString(GL_EXTENSIONS));
318 
319 #ifdef ALLEGRO_WINDOWS
320  if (!ret && strncmp(extension, "WGL", 3) == 0) {
321  if (!__wglGetExtensionsStringARB || __hdc != __allegro_gl_hdc) {
322  __wglGetExtensionsStringARB = (AGL_GetExtensionsStringARB_t)
323  wglGetProcAddress("wglGetExtensionsStringARB");
324  __hdc = __allegro_gl_hdc;
325  }
326  if (__wglGetExtensionsStringARB) {
327  ret = __allegro_gl_look_for_an_extension(extension,
328  (AL_CONST GLubyte*)__wglGetExtensionsStringARB(__allegro_gl_hdc));
329  }
330  }
331 #elif defined ALLEGRO_UNIX
332  if (!ret && strncmp(extension, "GLX", 3) == 0) {
333  XLOCK();
334  ret = __allegro_gl_look_for_an_extension(extension,
335  (const GLubyte*)glXQueryExtensionsString(_xwin.display,
336  _xwin.screen));
337  XUNLOCK();
338  }
339 #endif
340 
341  return ret;
342 }
343 
344 
345 
346 /* void * allegro_gl_get_proc_address(AL_CONST char *name) */
372 void *allegro_gl_get_proc_address(AL_CONST char *name)
373 {
374  void *symbol = NULL;
375 #ifdef ALLEGRO_MACOSX
376  CFStringRef function;
377 #endif
378 
379  if (!__allegro_gl_valid_context)
380  return NULL;
381 
382 #ifdef ALLEGROGL_GENERIC_DRIVER
383  /* AMesa provides a function to get a proc address. It does
384  * not emulate dynamic linking of course...
385  */
386  symbol = AMesaGetProcAddress(name);
387 
388 #elif defined ALLEGRO_WINDOWS
389  /* For once Windows is the easiest platform to use :)
390  * It provides a standardized way to get a function address
391  * But of course there is a drawback : the symbol is only valid
392  * under the current context :P
393  */
394  symbol = wglGetProcAddress(name);
395 #elif defined ALLEGRO_UNIX
396  if (aglXGetProcAddress) {
397  /* This is definitely the *good* way on Unix to get a GL proc
398  * address. Unfortunately glXGetProcAddress is an extension
399  * and may not be available on all platforms
400  */
401  symbol = aglXGetProcAddress((const GLubyte*)name);
402  }
403 #elif defined ALLEGROGL_HAVE_DYNAMIC_LINK
404  else {
405  /* Hack if glXGetProcAddress is not available :
406  * we try to find the symbol into libGL.so
407  */
408  if (__agl_handle) {
409  symbol = dlsym(__agl_handle, name);
410  }
411  }
412 #elif defined ALLEGRO_MACOSX
413  function = CFStringCreateWithCString(kCFAllocatorDefault, name,
414  kCFStringEncodingASCII);
415  if (function) {
416  symbol = CFBundleGetFunctionPointerForName(opengl_bundle_ref, function);
417  CFRelease(function);
418  }
419 #else
420  /* DOS does not support dynamic linking. If the function is not
421  * available at build-time then it will not be available at run-time
422  * Therefore we do not need to look for it...
423  */
424 #endif
425 
426  if (!symbol) {
427 
428 #if defined ALLEGROGL_HAVE_DYNAMIC_LINK
429  if (!aglXGetProcAddress) {
430  TRACE(PREFIX_W "get_proc_address: libdl::dlsym: %s\n",
431  dlerror());
432  }
433 #endif
434 
435  TRACE(PREFIX_W "get_proc_address : Unable to load symbol %s\n",
436  name);
437  }
438  else {
439  TRACE(PREFIX_I "get_proc_address : Symbol %s successfully loaded\n",
440  name);
441  }
442  return symbol;
443 }
444 
445 
446 
447 /* Fills in the AllegroGL info struct for blacklisting video cards.
448  */
449 static void __fill_in_info_struct(const GLubyte *rendereru,
450  struct allegro_gl_info *info) {
451  const char *renderer = (const char*)rendereru;
452 
453  /* Some cards are "special"... */
454  if (strstr(renderer, "3Dfx/Voodoo")) {
455  info->is_voodoo = 1;
456  }
457  else if (strstr(renderer, "Matrox G200")) {
458  info->is_matrox_g200 = 1;
459  }
460  else if (strstr(renderer, "RagePRO")) {
461  info->is_ati_rage_pro = 1;
462  }
463  else if (strstr(renderer, "RADEON 7000")) {
464  info->is_ati_radeon_7000 = 1;
465  }
466  else if (strstr(renderer, "Mesa DRI R200")) {
467  info->is_ati_r200_chip = 1;
468  }
469 
470  if ((strncmp(renderer, "3Dfx/Voodoo3 ", 13) == 0)
471  || (strncmp(renderer, "3Dfx/Voodoo2 ", 13) == 0)
472  || (strncmp(renderer, "3Dfx/Voodoo ", 12) == 0)) {
473  info->is_voodoo3_and_under = 1;
474  }
475 
476  /* Read OpenGL properties */
477  info->version = allegro_gl_opengl_version();
478 
479  return;
480 }
481 
482 
483 
484 /* __allegro_gl_manage_extensions:
485  * This functions fills the __allegro_gl_extensions structure and displays
486  * on the log file which extensions are available
487  */
488 void __allegro_gl_manage_extensions(void)
489 {
490  AL_CONST GLubyte *buf;
491  int i;
492 
493 #ifdef ALLEGRO_MACOSX
494  CFURLRef bundle_url;
495 #endif
496 
497  /* Print out OpenGL extensions */
498 #if LOGLEVEL >= 1
499  AGL_LOG(1, "OpenGL Extensions:\n");
500  __allegro_gl_print_extensions((AL_CONST char*)
501  glGetString(GL_EXTENSIONS));
502 #endif
503 
504  /* Print out GLU version */
505  buf = gluGetString(GLU_VERSION);
506  TRACE(PREFIX_I "GLU Version : %s\n", buf);
507 
508 #ifdef ALLEGROGL_HAVE_DYNAMIC_LINK
509  /* Get glXGetProcAddress entry */
510  __agl_handle = dlopen("libGL.so", RTLD_LAZY);
511  if (__agl_handle) {
512  aglXGetProcAddress = (GLXGETPROCADDRESSARBPROC) dlsym(__agl_handle,
513  "glXGetProcAddressARB");
514  if (!aglXGetProcAddress) {
515  aglXGetProcAddress = (GLXGETPROCADDRESSARBPROC) dlsym(__agl_handle,
516  "glXGetProcAddress");
517  }
518  }
519  else {
520  TRACE(PREFIX_W "Failed to dlopen libGL.so : %s\n", dlerror());
521  }
522  TRACE(PREFIX_I "glXGetProcAddress Extension: %s\n",
523  aglXGetProcAddress ? "Supported" : "Unsupported");
524 #elif defined ALLEGRO_UNIX
525 #ifdef ALLEGROGL_GLXGETPROCADDRESSARB
526  TRACE(PREFIX_I "glXGetProcAddressARB Extension: supported\n");
527 #else
528  TRACE(PREFIX_I "glXGetProcAddress Extension: supported\n");
529 #endif
530 #endif
531 
532 #ifdef ALLEGRO_MACOSX
533  bundle_url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
534  CFSTR("/System/Library/Frameworks/OpenGL.framework"),
535  kCFURLPOSIXPathStyle, true);
536  opengl_bundle_ref = CFBundleCreate(kCFAllocatorDefault, bundle_url);
537  CFRelease(bundle_url);
538 #endif
539 
540  __fill_in_info_struct(glGetString(GL_RENDERER), &allegro_gl_info);
541 
542  /* Load extensions */
543  agl_extension_table = __allegro_gl_create_extensions();
544  __allegro_gl_load_extensions(agl_extension_table);
545  __allegro_gl_set_extensions(agl_extension_table);
546 
547  for (i = 0; i < 5; i++) {
548  __allegro_gl_texture_read_format[i] = -1;
549  __allegro_gl_texture_components[i] = GL_RGB;
550  }
551  __allegro_gl_texture_read_format[3] = GL_UNSIGNED_BYTE;
552  __allegro_gl_texture_read_format[4] = GL_UNSIGNED_BYTE;
553  __allegro_gl_texture_components[4] = GL_RGBA;
554 
555 
556  /* Get extension info for the rest of the lib */
557 # define AGL_EXT(name, ver) { \
558  allegro_gl_extensions_GL.name = \
559  allegro_gl_is_extension_supported("GL_" #name) \
560  || (allegro_gl_info.version >= ver && ver > 0); \
561  }
562 # include "allegrogl/GLext/gl_ext_list.h"
563 # undef AGL_EXT
564 
565 #ifdef ALLEGRO_UNIX
566 # define AGL_EXT(name, ver) { \
567  allegro_gl_extensions_GLX.name = \
568  allegro_gl_is_extension_supported("GLX_" #name) \
569  || (allegro_gl_info.version >= ver && ver > 0); \
570  }
571 # include "allegrogl/GLext/glx_ext_list.h"
572 # undef AGL_EXT
573 #elif defined ALLEGRO_WINDOWS
574 # define AGL_EXT(name, ver) { \
575  allegro_gl_extensions_WGL.name = \
576  allegro_gl_is_extension_supported("WGL_" #name) \
577  || (allegro_gl_info.version >= ver && ver > 0); \
578  }
579 # include "allegrogl/GLext/wgl_ext_list.h"
580 # undef AGL_EXT
581 #endif
582 
583  /* Get number of texture units */
584  if (allegro_gl_extensions_GL.ARB_multitexture) {
585  glGetIntegerv(GL_MAX_TEXTURE_UNITS,
586  (GLint*)&allegro_gl_info.num_texture_units);
587  }
588  else {
589  allegro_gl_info.num_texture_units = 1;
590  }
591 
592  /* Get max texture size */
593  glGetIntegerv(GL_MAX_TEXTURE_SIZE,
594  (GLint*)&allegro_gl_info.max_texture_size);
595 
596  /* Note: Voodoo (even V5) don't seem to correctly support
597  * packed pixel formats. Disabling them for those cards.
598  */
599  allegro_gl_extensions_GL.EXT_packed_pixels &= !allegro_gl_info.is_voodoo;
600 
601 
602  if (allegro_gl_extensions_GL.EXT_packed_pixels) {
603 
604  AGL_LOG(1, "Packed Pixels formats available\n");
605 
606  /* XXX On NV cards, we want to use BGRA instead of RGBA for speed */
607  /* Fills the __allegro_gl_texture_format array */
608  __allegro_gl_texture_read_format[0] = GL_UNSIGNED_BYTE_3_3_2;
609  __allegro_gl_texture_read_format[1] = GL_UNSIGNED_SHORT_5_5_5_1;
610  __allegro_gl_texture_read_format[2] = GL_UNSIGNED_SHORT_5_6_5;
611  }
612 
613  /* NVidia and ATI cards expose OpenGL 2.0 but often don't accelerate
614  * non-power-of-2 textures. This check is how you verify that NP2
615  * textures are hardware accelerated or not.
616  * We should clobber the NPOT support if it's not accelerated.
617  */
618  { const char *vendor = (const char*)glGetString(GL_VENDOR);
619  if (strstr(vendor, "NVIDIA Corporation")) {
620  if (!allegro_gl_extensions_GL.NV_fragment_program2
621  || !allegro_gl_extensions_GL.NV_vertex_program3) {
622  allegro_gl_extensions_GL.ARB_texture_non_power_of_two = 0;
623  }
624  }
625  else if (strstr(vendor, "ATI Technologies")) {
626  if (!strstr((const char*)glGetString(GL_EXTENSIONS),
627  "GL_ARB_texture_non_power_of_two")
628  && allegro_gl_info.version >= 2.0f) {
629  allegro_gl_extensions_GL.ARB_texture_non_power_of_two = 0;
630  }
631  }
632  }
633 }
634 
635 
636 
637 /* __allegro_gl_print_extensions:
638  * Given a string containing extensions (i.e. a NULL terminated string where
639  * each extension are separated by a space and which names do not contain any
640  * space)
641  */
642 void __allegro_gl_print_extensions(AL_CONST char * extension)
643 {
644  char buf[80];
645  char* start;
646 
647  while (*extension != '\0') {
648  start = buf;
649  strncpy(buf, extension, 80);
650  while ((*start != ' ') && (*start != '\0')) {
651  extension++;
652  start++;
653  }
654  *start = '\0';
655  extension ++;
656  TRACE(PREFIX_I "%s\n", buf);
657  }
658 }
659 
660 
661 
662 void __allegro_gl_unmanage_extensions() {
663  __allegro_gl_destroy_extensions(agl_extension_table);
664 #ifdef ALLEGRO_MACOSX
665  CFRelease(opengl_bundle_ref);
666 #endif
667 #ifdef ALLEGROGL_HAVE_DYNAMIC_LINK
668  if (__agl_handle) {
669  dlclose(__agl_handle);
670  __agl_handle = NULL;
671  }
672 #endif
673 }
674 
float allegro_gl_opengl_version(void)
Returns the OpenGL version number of the client (the computer the program is running on)...
Definition: alleggl.c:971
void * allegro_gl_get_proc_address(AL_CONST char *name)
Helper to get the address of an OpenGL symbol.
Definition: glext.c:372
struct AGL_EXTENSION_LIST_GL allegro_gl_extensions_GL
List of OpenGL extensions supported by AllegroGL.
Definition: glext.c:55
AGL_EXT * agl_extension_table
List of GLX extensions supported by AllegroGL.
Definition: glext.c:82
int allegro_gl_is_extension_supported(AL_CONST char *extension)
This function is an helper to determine whether an OpenGL extension is available or not...
Definition: glext.c:306
Main header file for AllegroGL.