1 /* ______ ___ ___
2 * /\ _ \ /\_ \ /\_ \
3 * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___
4 * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\
5 * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \
6 * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7 * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
8 * /\____/
9 * \_/__/
10 *
11 * OpenGL extensions management subsystem
12 *
13 * By Elias Pschernig and Milan Mimica.
14 *
15 * Based on AllegroGL extensions management.
16 */
17
18 #include <ctype.h>
19 #include <math.h>
20 #include <stdio.h>
21 #include <string.h>
22
23 #include "allegro5/allegro.h"
24 #include "allegro5/allegro_opengl.h"
25 #include "allegro5/opengl/gl_ext.h"
26 #include "allegro5/internal/aintern.h"
27 #include "allegro5/internal/aintern_opengl.h"
28 #include "allegro5/internal/aintern_display.h"
29 #include "allegro5/internal/aintern_system.h"
30
31 /* We need some driver specific details not worth of a vtable entry. */
32 #if defined ALLEGRO_WINDOWS
33 #include "../win/wgl.h"
34 #elif defined ALLEGRO_UNIX && !defined ALLEGRO_EXCLUDE_GLX
35 #include "allegro5/internal/aintern_xdisplay.h"
36 #include "allegro5/internal/aintern_xsystem.h"
37 #endif
38
39 #if defined ALLEGRO_MACOSX
40 #include <OpenGL/glu.h>
41 #elif !defined ALLEGRO_CFG_OPENGLES
42 #include <GL/glu.h>
43 #endif
44
45 ALLEGRO_DEBUG_CHANNEL("opengl")
46
47
48 #ifdef ALLEGRO_HAVE_DYNAMIC_LINK
49 #include <dlfcn.h>
50 /* Handle for dynamic library libGL.so */
51 static void *__libgl_handle = NULL;
52 /* Pointer to glXGetProcAddressARB */
53 typedef void *(*GLXGETPROCADDRESSARBPROC) (const GLubyte *);
54 static GLXGETPROCADDRESSARBPROC alXGetProcAddress;
55 #else /* #ifdef ALLEGRO_HAVE_DYNAMIC_LINK */
56 /* Tries static linking */
57 /* FIXME: set ALLEGRO_GLXGETPROCADDRESSARB on configure time, if
58 * glXGetProcAddressARB must be used!
59 */
60 #if defined ALLEGRO_GLXGETPROCADDRESSARB
61 #define alXGetProcAddress glXGetProcAddressARB
62 #elif defined ALLEGRO_RASPBERRYPI
63 #define alXGetProcAddress eglGetProcAddress
64 #else
65 #define alXGetProcAddress glXGetProcAddress
66 #endif
67 #endif /* #ifdef ALLEGRO_HAVE_DYNAMIC_LINK */
68
69
70 #ifdef ALLEGRO_MACOSX
71 #include <CoreFoundation/CoreFoundation.h>
72 static CFBundleRef opengl_bundle_ref;
73 #endif
74
75
76 /* Define the GL API pointers.
77 * Example:
78 * _ALLEGRO_glBlendEquation_t _al_glBlendEquation = NULL;
79 */
80 #define AGL_API(type, name, args) _ALLEGRO_gl##name##_t _al_gl##name = NULL;
81 # include "allegro5/opengl/GLext/gl_ext_api.h"
82 #undef AGL_API
83 #ifdef ALLEGRO_WINDOWS
84 #define AGL_API(type, name, args) _ALLEGRO_wgl##name##_t _al_wgl##name = NULL;
85 # include "allegro5/opengl/GLext/wgl_ext_api.h"
86 #undef AGL_API
87 #elif defined ALLEGRO_UNIX
88 #define AGL_API(type, name, args) _ALLEGRO_glX##name##_t _al_glX##name = NULL;
89 # include "allegro5/opengl/GLext/glx_ext_api.h"
90 #undef AGL_API
91 #endif
92
93
94
parse_opengl_version(const char * s)95 static uint32_t parse_opengl_version(const char *s)
96 {
97 char *p = (char *) s;
98 int v[4] = {0, 0, 0, 0};
99 int n;
100 uint32_t ver;
101
102 /* For OpenGL ES version strings have the form:
103 * "OpenGL ES-<profile> <major>.<minor>"
104 * So for example: "OpenGL ES-CM 2.0". We simply skip any non-digit
105 * characters and then parse it like for normal OpenGL.
106 */
107 while (*p && !isdigit(*p)) {
108 p++;
109 }
110
111 /* e.g. "4.0.0 Vendor blah blah" */
112 for (n = 0; n < 4; n++) {
113 char *end;
114 long l;
115
116 errno = 0;
117 l = strtol(p, &end, 10);
118 if (errno)
119 break;
120 v[n] = _ALLEGRO_CLAMP(0, l, 255);
121 if (*end != '.')
122 break;
123 p = end + 1; /* skip dot */
124 }
125
126 ver = (v[0] << 24) | (v[1] << 16) | (v[2] << 8) | v[3];
127 ALLEGRO_DEBUG("Parsed '%s' as 0x%08x\n", s, ver);
128 return ver;
129 }
130
131
132
133 /* Reads version info out of glGetString(GL_VERSION) */
_al_ogl_version(void)134 static uint32_t _al_ogl_version(void)
135 {
136 char const *value = al_get_config_value(al_get_system_config(), "opengl",
137 "force_opengl_version");
138 if (value) {
139 uint32_t v = parse_opengl_version(value);
140 ALLEGRO_INFO("OpenGL version forced to %d.%d.%d.%d.\n",
141 (v >> 24) & 0xff,
142 (v >> 16) & 0xff,
143 (v >> 8) & 0xff,
144 (v & 0xff));
145 return v;
146 }
147
148 const char *str;
149
150 str = (const char *)glGetString(GL_VERSION);
151 if (str) {
152 #ifdef ALLEGRO_CFG_OPENGLES
153 char *str2 = strstr(str, "ES ");
154 if (str2)
155 str = str2 + 3;
156 #endif
157 return parse_opengl_version(str);
158 }
159 else {
160 /* The OpenGL driver does not return a version
161 * number. However it probably supports at least OpenGL 1.0
162 */
163 return _ALLEGRO_OPENGL_VERSION_1_0;
164 }
165
166 }
167
168
169
170 /* print_extensions:
171 * Given a string containing extensions (i.e. a NULL terminated string where
172 * each extension are separated by a space and which names do not contain any
173 * space)
174 */
print_extensions(char const * extension)175 static void print_extensions(char const *extension)
176 {
177 char buf[80];
178 char *start;
179 ASSERT(extension);
180
181 while (*extension != '\0') {
182 start = buf;
183 _al_sane_strncpy(buf, extension, 80);
184 while ((*start != ' ') && (*start != '\0')) {
185 extension++;
186 start++;
187 }
188 *start = '\0';
189 if (*extension != '\0')
190 extension++;
191 ALLEGRO_DEBUG("%s\n", buf);
192 }
193 }
194
195
196
197 #if !defined ALLEGRO_CFG_OPENGLES
198 /* Print all extensions the OpenGL 3.0 way. */
print_extensions_3_0(void)199 static void print_extensions_3_0(void)
200 {
201 int i;
202 GLint n;
203 GLubyte const *name;
204 glGetIntegerv(GL_NUM_EXTENSIONS, &n);
205 for (i = 0; i < n; i++) {
206 name = glGetStringi(GL_EXTENSIONS, i);
207 ALLEGRO_DEBUG("%s\n", name);
208 }
209 }
210 #endif
211
212
213
214 /* Function: al_get_opengl_version
215 */
al_get_opengl_version(void)216 uint32_t al_get_opengl_version(void)
217 {
218 ALLEGRO_DISPLAY *ogl_disp;
219
220 ogl_disp = al_get_current_display();
221 if (!ogl_disp || !ogl_disp->ogl_extras)
222 return 0x0;
223
224 return ogl_disp->ogl_extras->ogl_info.version;
225 }
226
227
228 /* NOTE: al_get_opengl_variant is pretty simple right now but may
229 * eventually need driver support.
230 */
231
232 /* Function: al_get_opengl_variant
233 */
al_get_opengl_variant(void)234 int al_get_opengl_variant(void)
235 {
236 #if defined ALLEGRO_CFG_OPENGLES
237 return ALLEGRO_OPENGL_ES;
238 #else
239 return ALLEGRO_DESKTOP_OPENGL;
240 #endif
241 }
242
243 /* Create the extension list */
create_extension_list(void)244 static ALLEGRO_OGL_EXT_LIST *create_extension_list(void)
245 {
246 ALLEGRO_OGL_EXT_LIST *ret = al_calloc(1, sizeof(ALLEGRO_OGL_EXT_LIST));
247
248 if (!ret) {
249 return NULL;
250 }
251
252 return ret;
253 }
254
255
256
257 /* Create the extension API table */
create_extension_api_table(void)258 static ALLEGRO_OGL_EXT_API *create_extension_api_table(void)
259 {
260 ALLEGRO_OGL_EXT_API *ret = al_calloc(1, sizeof(ALLEGRO_OGL_EXT_API));
261
262 if (!ret) {
263 return NULL;
264 }
265
266 return ret;
267 }
268
269
270
271 typedef void (*VOID_FPTR)(void);
272 /* GCC 4.8.2 and possibly others are really slow at optimizing the 100's of the
273 * if statements in the load_extensions function below, so we extract them to
274 * this function.
275 */
load_extension(const char * name)276 static VOID_FPTR load_extension(const char* name)
277 {
278 VOID_FPTR fptr = NULL;
279 #ifdef ALLEGRO_WINDOWS
280 fptr = (VOID_FPTR)wglGetProcAddress(name);
281 #elif defined ALLEGRO_UNIX
282 fptr = (VOID_FPTR)alXGetProcAddress((const GLubyte*)name);
283 #elif defined ALLEGRO_MACOSX
284 CFStringRef cfstr = CFStringCreateWithCStringNoCopy(NULL, name,
285 kCFStringEncodingUTF8, kCFAllocatorNull);
286 if (cfstr) {
287 fptr = (VOID_FPTR)CFBundleGetFunctionPointerForName(opengl_bundle_ref, cfstr);
288 CFRelease(cfstr);
289 }
290 #elif defined ALLEGRO_SDL
291 fptr = SDL_GL_GetProcAddress(name);
292 #endif
293 if (fptr) {
294 ALLEGRO_DEBUG("%s successfully loaded (%p)\n", name, fptr);
295 }
296 return fptr;
297 }
298
299
300
301 /* Load the extension API addresses into the table.
302 * Should only be done on context creation.
303 */
load_extensions(ALLEGRO_OGL_EXT_API * ext)304 static void load_extensions(ALLEGRO_OGL_EXT_API *ext)
305 {
306 if (!ext) {
307 return;
308 }
309
310 #ifdef ALLEGRO_UNIX
311 #ifdef ALLEGRO_HAVE_DYNAMIC_LINK
312 if (!alXGetProcAddress) {
313 return;
314 }
315 #endif
316 #endif
317
318 #ifdef ALLEGRO_WINDOWS
319
320 #define AGL_API(type, name, args) \
321 ext->name = (_ALLEGRO_gl##name##_t)load_extension("gl" #name);
322
323 #include "allegro5/opengl/GLext/gl_ext_api.h"
324
325 #undef AGL_API
326
327 #define AGL_API(type, name, args) \
328 ext->name = (_ALLEGRO_wgl##name##_t)load_extension("wgl" #name);
329
330 #include "allegro5/opengl/GLext/wgl_ext_api.h"
331
332 #undef AGL_API
333
334 #elif defined ALLEGRO_UNIX
335
336 #define AGL_API(type, name, args) \
337 ext->name = (_ALLEGRO_gl##name##_t)load_extension("gl" #name);
338
339 #include "allegro5/opengl/GLext/gl_ext_api.h"
340
341 #undef AGL_API
342
343 #define AGL_API(type, name, args) \
344 ext->name = (_ALLEGRO_glX##name##_t)load_extension("glX" #name);
345
346 #include "allegro5/opengl/GLext/glx_ext_api.h"
347
348 #undef AGL_API
349
350 #elif defined ALLEGRO_MACOSX
351
352 #define AGL_API(type, name, args) \
353 ext->name = (_ALLEGRO_gl##name##_t)load_extension("gl" # name);
354
355 #include "allegro5/opengl/GLext/gl_ext_api.h"
356
357 #undef AGL_API
358
359 #elif defined ALLEGRO_SDL
360
361 #define AGL_API(type, name, args) \
362 ext->name = (_ALLEGRO_gl##name##_t)load_extension("gl" # name);
363
364 #include "allegro5/opengl/GLext/gl_ext_api.h"
365
366 #undef AGL_API
367
368 #endif
369
370 }
371
372
373
374 /* Set the GL API pointers to the current table
375 * Should only be called on context switches.
376 */
_al_ogl_set_extensions(ALLEGRO_OGL_EXT_API * ext)377 void _al_ogl_set_extensions(ALLEGRO_OGL_EXT_API *ext)
378 {
379 if (!ext) {
380 return;
381 }
382
383 #define AGL_API(type, name, args) _al_gl##name = ext->name;
384 # include "allegro5/opengl/GLext/gl_ext_api.h"
385 #undef AGL_API
386
387 #ifdef ALLEGRO_WINDOWS
388 #define AGL_API(type, name, args) _al_wgl##name = ext->name;
389 # include "allegro5/opengl/GLext/wgl_ext_api.h"
390 #undef AGL_API
391
392 #elif defined ALLEGRO_UNIX
393 #define AGL_API(type, name, args) _al_glX##name = ext->name;
394 # include "allegro5/opengl/GLext/glx_ext_api.h"
395 #undef AGL_API
396 #endif
397 }
398
399
400
401 /* Destroys the extension API table */
destroy_extension_api_table(ALLEGRO_OGL_EXT_API * ext)402 static void destroy_extension_api_table(ALLEGRO_OGL_EXT_API *ext)
403 {
404 if (ext) {
405 al_free(ext);
406 }
407 }
408
409
410
411 /* Destroys the extension list */
destroy_extension_list(ALLEGRO_OGL_EXT_LIST * list)412 static void destroy_extension_list(ALLEGRO_OGL_EXT_LIST *list)
413 {
414 if (list) {
415 al_free(list);
416 }
417 }
418
419
420
421 /* _al_ogl_look_for_an_extension:
422 * This function has been written by Mark J. Kilgard in one of his
423 * tutorials about OpenGL extensions
424 */
_al_ogl_look_for_an_extension(const char * name,const GLubyte * extensions)425 int _al_ogl_look_for_an_extension(const char *name, const GLubyte *extensions)
426 {
427 const GLubyte *start;
428 GLubyte *where, *terminator;
429 ASSERT(extensions);
430
431 /* Extension names should not have spaces. */
432 where = (GLubyte *) strchr(name, ' ');
433 if (where || *name == '\0')
434 return false;
435 /* It takes a bit of care to be fool-proof about parsing the
436 * OpenGL extensions string. Don't be fooled by sub-strings, etc.
437 */
438 start = extensions;
439 for (;;) {
440 where = (GLubyte *) strstr((const char *)start, name);
441 if (!where)
442 break;
443 terminator = where + strlen(name);
444 if (where == start || *(where - 1) == ' ')
445 if (*terminator == ' ' || *terminator == '\0')
446 return true;
447 start = terminator;
448 }
449 return false;
450 }
451
452
453
_ogl_is_extension_supported(const char * extension,ALLEGRO_DISPLAY * disp)454 static bool _ogl_is_extension_supported(const char *extension,
455 ALLEGRO_DISPLAY *disp)
456 {
457 int ret = 0;
458 GLubyte const *ext_str;
459 #if !defined ALLEGRO_CFG_OPENGLES
460 int v = al_get_opengl_version();
461 #endif
462 (void)disp;
463
464 #if !defined ALLEGRO_CFG_OPENGLES
465 if (disp->flags & ALLEGRO_OPENGL_3_0 || v >= _ALLEGRO_OPENGL_VERSION_3_0) {
466 int i;
467 GLint ext_cnt;
468 glGetIntegerv(GL_NUM_EXTENSIONS, &ext_cnt);
469 for (i = 0; i < ext_cnt; i++) {
470 ext_str = glGetStringi(GL_EXTENSIONS, i);
471 if (ext_str && !strcmp(extension, (char*)ext_str)) {
472 ret = 1;
473 break;
474 }
475 }
476 }
477 else
478 #endif
479 {
480 ext_str = glGetString(GL_EXTENSIONS);
481 if (!ext_str)
482 return false;
483 ret = _al_ogl_look_for_an_extension(extension, ext_str);
484 }
485
486 #ifdef ALLEGRO_WINDOWS
487 if (!ret && strncmp(extension, "WGL", 3) == 0) {
488 ALLEGRO_DISPLAY_WGL *wgl_disp = (void*)disp;
489 _ALLEGRO_wglGetExtensionsStringARB_t _wglGetExtensionsStringARB;
490
491 if (!wgl_disp->dc)
492 return false;
493
494 _wglGetExtensionsStringARB = (void *)
495 wglGetProcAddress("wglGetExtensionsStringARB");
496 if (_wglGetExtensionsStringARB) {
497 ret = _al_ogl_look_for_an_extension(extension, (const GLubyte *)
498 _wglGetExtensionsStringARB(wgl_disp->dc));
499 }
500 }
501
502 #elif defined ALLEGRO_UNIX && !defined ALLEGRO_EXCLUDE_GLX
503 if (!ret && strncmp(extension, "GLX", 3) == 0) {
504 ALLEGRO_SYSTEM_XGLX *sys = (void*)al_get_system_driver();
505 ALLEGRO_DISPLAY_XGLX *glx_disp = (void*)disp;
506 char const *ext;
507
508 if (!sys->gfxdisplay)
509 return false;
510
511 ext = glXQueryExtensionsString(sys->gfxdisplay, glx_disp->xscreen);
512 if (!ext) {
513 /* work around driver bugs? */
514 ext = "";
515 }
516 ret = _al_ogl_look_for_an_extension(extension, (const GLubyte *)ext);
517 }
518 #endif
519
520 return ret;
521 }
522
523
524
_ogl_is_extension_with_version_supported(const char * extension,ALLEGRO_DISPLAY * disp,uint32_t ver)525 static bool _ogl_is_extension_with_version_supported(
526 const char *extension, ALLEGRO_DISPLAY *disp, uint32_t ver)
527 {
528 char const *value;
529
530 /* For testing purposes, any OpenGL extension can be disable in
531 * the config by using something like:
532 *
533 * [opengl_disabled_extensions]
534 * GL_ARB_texture_non_power_of_two=0
535 * GL_EXT_framebuffer_object=0
536 *
537 */
538 value = al_get_config_value(al_get_system_config(),
539 "opengl_disabled_extensions", extension);
540 if (value) {
541 ALLEGRO_WARN("%s found in [opengl_disabled_extensions].\n",
542 extension);
543 return false;
544 }
545
546 /* If the extension is included in the OpenGL version, there is no
547 * need to check the extensions list.
548 */
549 if (ver > 0 && disp->ogl_extras->ogl_info.version >= ver) {
550 return true;
551 }
552
553 return _ogl_is_extension_supported(extension, disp);
554 }
555
556
557
558 /* Function: al_have_opengl_extension
559 */
al_have_opengl_extension(const char * extension)560 bool al_have_opengl_extension(const char *extension)
561 {
562 ALLEGRO_DISPLAY *disp;
563
564 disp = al_get_current_display();
565 if (!disp)
566 return false;
567
568 if (!(disp->flags & ALLEGRO_OPENGL))
569 return false;
570
571 return _ogl_is_extension_supported(extension, disp);
572 }
573
574
575
576 /* Function: al_get_opengl_proc_address
577 */
al_get_opengl_proc_address(const char * name)578 void *al_get_opengl_proc_address(const char *name)
579 {
580 void *symbol = NULL;
581 #ifdef ALLEGRO_MACOSX
582 CFStringRef function;
583 #endif
584 ALLEGRO_DISPLAY *disp;
585
586 disp = al_get_current_display();
587 if (!disp)
588 return NULL;
589
590 if (!(disp->flags & ALLEGRO_OPENGL))
591 return NULL;
592
593 #if defined ALLEGRO_WINDOWS
594 /* For once Windows is the easiest platform to use :)
595 * It provides a standardized way to get a function address
596 * But of course there is a drawback : the symbol is only valid
597 * under the current context :P
598 */
599 {
600 ALLEGRO_DISPLAY_WGL *wgl_disp = (void*)disp;
601
602 if (!wgl_disp->dc)
603 return NULL;
604
605 symbol = wglGetProcAddress(name);
606 }
607 #elif defined ALLEGRO_UNIX
608 #if defined ALLEGRO_HAVE_DYNAMIC_LINK
609 if (alXGetProcAddress)
610 #endif
611 {
612 /* This is definitely the *good* way on Unix to get a GL proc
613 * address. Unfortunately glXGetProcAddress is an extension
614 * and may not be available on all platforms
615 */
616 #if defined ALLEGRO_RASPBERRYPI
617 symbol = alXGetProcAddress(name);
618 #else
619 symbol = alXGetProcAddress((const GLubyte *)name);
620 #endif
621 }
622 #elif defined ALLEGRO_HAVE_DYNAMIC_LINK
623 else {
624 /* Hack if glXGetProcAddress is not available :
625 * we try to find the symbol into libGL.so
626 */
627 if (__al_handle) {
628 symbol = dlsym(__al_handle, name);
629 }
630 }
631 #elif defined ALLEGRO_MACOSX
632 function = CFStringCreateWithCString(kCFAllocatorDefault, name,
633 kCFStringEncodingASCII);
634 if (function) {
635 symbol =
636 CFBundleGetFunctionPointerForName(opengl_bundle_ref, function);
637 CFRelease(function);
638 }
639 #endif
640
641 if (!symbol) {
642
643 #if defined ALLEGRO_HAVE_DYNAMIC_LINK
644 if (!alXGetProcAddress) {
645 ALLEGRO_WARN("get_proc_address: libdl::dlsym: %s\n", dlerror());
646 }
647 #endif
648
649 ALLEGRO_WARN("get_proc_address : Unable to load symbol %s\n", name);
650 }
651 else {
652 ALLEGRO_DEBUG("get_proc_address : Symbol %s successfully loaded\n", name);
653 }
654 return symbol;
655 }
656
657
658
659 /* fill_in_info_struct:
660 * Fills in the OPENGL_INFO info struct for blacklisting video cards.
661 */
fill_in_info_struct(const GLubyte * rendereru,OPENGL_INFO * info)662 static void fill_in_info_struct(const GLubyte *rendereru, OPENGL_INFO *info)
663 {
664 const char *renderer = (const char *)rendereru;
665 ASSERT(renderer);
666
667 /* Some cards are "special"... */
668 if (strstr(renderer, "3Dfx/Voodoo")) {
669 info->is_voodoo = 1;
670 }
671 else if (strstr(renderer, "Matrox G200")) {
672 info->is_matrox_g200 = 1;
673 }
674 else if (strstr(renderer, "RagePRO")) {
675 info->is_ati_rage_pro = 1;
676 }
677 else if (strstr(renderer, "RADEON 7000")) {
678 info->is_ati_radeon_7000 = 1;
679 }
680 else if (strstr(renderer, "Mesa DRI R200")) {
681 info->is_ati_r200_chip = 1;
682 }
683 else if (strstr(renderer, "Intel HD Graphics 3000 OpenGL Engine")) {
684 info->is_intel_hd_graphics_3000 = 1;
685 }
686
687 if ((strncmp(renderer, "3Dfx/Voodoo3 ", 13) == 0)
688 || (strncmp(renderer, "3Dfx/Voodoo2 ", 13) == 0)
689 || (strncmp(renderer, "3Dfx/Voodoo ", 12) == 0)) {
690 info->is_voodoo3_and_under = 1;
691 }
692
693 /* Read OpenGL properties */
694 info->version = _al_ogl_version();
695 ALLEGRO_INFO("Assumed OpenGL version: %d.%d.%d.%d\n",
696 (info->version >> 24) & 0xff,
697 (info->version >> 16) & 0xff,
698 (info->version >> 8) & 0xff,
699 (info->version ) & 0xff);
700
701 return;
702 }
703
704
705
706 /* _al_ogl_manage_extensions:
707 * This functions fills the extensions API table and extension list
708 * structures and displays on the log file which extensions are available.
709 */
_al_ogl_manage_extensions(ALLEGRO_DISPLAY * gl_disp)710 void _al_ogl_manage_extensions(ALLEGRO_DISPLAY *gl_disp)
711 {
712 //const GLubyte *buf;
713 #if defined ALLEGRO_MACOSX
714 CFURLRef bundle_url;
715 #endif
716 ALLEGRO_OGL_EXT_API *ext_api;
717 ALLEGRO_OGL_EXT_LIST *ext_list;
718
719 /* Some functions depend on knowing the version of opengl in use */
720 fill_in_info_struct(glGetString(GL_RENDERER), &(gl_disp->ogl_extras->ogl_info));
721
722 /* Print out OpenGL extensions
723 * We should use glGetStringi(GL_EXTENSIONS, i) for OpenGL 3.0+
724 * but it doesn't seem to work until later.
725 */
726 if (gl_disp->ogl_extras->ogl_info.version < _ALLEGRO_OPENGL_VERSION_3_0) {
727 ALLEGRO_DEBUG("OpenGL Extensions:\n");
728 print_extensions((char const *)glGetString(GL_EXTENSIONS));
729 }
730
731 /* Print out GLU version */
732 //buf = gluGetString(GLU_VERSION);
733 //ALLEGRO_INFO("GLU Version : %s\n", buf);
734
735 #ifdef ALLEGRO_HAVE_DYNAMIC_LINK
736 /* Get glXGetProcAddress entry */
737 __libgl_handle = dlopen("libGL.so", RTLD_LAZY);
738 if (__libgl_handle) {
739 alXGetProcAddress = (GLXGETPROCADDRESSARBPROC) dlsym(__libgl_handle,
740 "glXGetProcAddressARB");
741 if (!alXGetProcAddress) {
742 alXGetProcAddress = (GLXGETPROCADDRESSARBPROC) dlsym(__libgl_handle,
743 "glXGetProcAddress");
744 if (!alXGetProcAddress) {
745 alXGetProcAddress = (GLXGETPROCADDRESSARBPROC) dlsym(__libgl_handle,
746 "eglGetProcAddress");
747 }
748 }
749 }
750 else {
751 ALLEGRO_WARN("Failed to dlopen libGL.so : %s\n", dlerror());
752 }
753 ALLEGRO_INFO("glXGetProcAddress Extension: %s\n",
754 alXGetProcAddress ? "Supported" : "Unsupported");
755 #elif defined ALLEGRO_UNIX
756 #ifdef ALLEGROGL_GLXGETPROCADDRESSARB
757 ALLEGRO_INFO("glXGetProcAddressARB Extension: supported\n");
758 #else
759 ALLEGRO_INFO("glXGetProcAddress Extension: supported\n");
760 #endif
761 #endif
762
763 #ifdef ALLEGRO_MACOSX
764 bundle_url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
765 CFSTR
766 ("/System/Library/Frameworks/OpenGL.framework"),
767 kCFURLPOSIXPathStyle, true);
768 opengl_bundle_ref = CFBundleCreate(kCFAllocatorDefault, bundle_url);
769 CFRelease(bundle_url);
770 #endif
771
772 #if defined ALLEGRO_UNIX && !defined ALLEGRO_EXCLUDE_GLX
773 ALLEGRO_DEBUG("GLX Extensions:\n");
774 ALLEGRO_SYSTEM_XGLX *glx_sys = (void*)al_get_system_driver();
775 ALLEGRO_DISPLAY_XGLX *glx_disp = (void *)gl_disp;
776 char const *ext = glXQueryExtensionsString(
777 glx_sys->gfxdisplay, glx_disp->xscreen);
778 if (!ext) {
779 /* work around driver bugs? */
780 ext = "";
781 }
782 print_extensions(ext);
783 #endif
784
785 /* Create & load extension API table */
786 ext_api = create_extension_api_table();
787 load_extensions(ext_api);
788 gl_disp->ogl_extras->extension_api = ext_api;
789
790 #if !defined ALLEGRO_CFG_OPENGLES
791 /* Need that symbol already so can't wait until it is assigned later. */
792 glGetStringi = ext_api->GetStringi;
793
794 if (gl_disp->ogl_extras->ogl_info.version >= _ALLEGRO_OPENGL_VERSION_3_0) {
795 ALLEGRO_DEBUG("OpenGL Extensions:\n");
796 print_extensions_3_0();
797 }
798 #endif
799
800 /* Create the list of supported extensions. */
801 ext_list = create_extension_list();
802 gl_disp->ogl_extras->extension_list = ext_list;
803
804 /* Fill the list. */
805 #define AGL_EXT(name, ver) { \
806 ext_list->ALLEGRO_GL_##name = \
807 _ogl_is_extension_with_version_supported("GL_" #name, gl_disp, \
808 _ALLEGRO_OPENGL_VERSION_##ver); \
809 }
810 #include "allegro5/opengl/GLext/gl_ext_list.h"
811 #undef AGL_EXT
812
813 #ifdef ALLEGRO_UNIX
814 #define AGL_EXT(name, ver) { \
815 ext_list->ALLEGRO_GLX_##name = \
816 _ogl_is_extension_with_version_supported("GLX_" #name, gl_disp, \
817 _ALLEGRO_OPENGL_VERSION_##ver); \
818 }
819 #include "allegro5/opengl/GLext/glx_ext_list.h"
820 #undef AGL_EXT
821 #elif defined ALLEGRO_WINDOWS
822 #define AGL_EXT(name, ver) { \
823 ext_list->ALLEGRO_WGL_##name = \
824 _ogl_is_extension_with_version_supported("WGL_" #name, gl_disp, \
825 _ALLEGRO_OPENGL_VERSION_##ver); \
826 }
827 #include "allegro5/opengl/GLext/wgl_ext_list.h"
828 #undef AGL_EXT
829 #endif
830
831 /* Get max texture size */
832 glGetIntegerv(GL_MAX_TEXTURE_SIZE,
833 (GLint *) & gl_disp->ogl_extras->ogl_info.max_texture_size);
834
835 /* Note: Voodoo (even V5) don't seem to correctly support
836 * packed pixel formats. Disabling them for those cards.
837 */
838 ext_list->ALLEGRO_GL_EXT_packed_pixels &= !gl_disp->ogl_extras->ogl_info.is_voodoo;
839
840
841 if (ext_list->ALLEGRO_GL_EXT_packed_pixels) {
842
843 ALLEGRO_INFO("Packed Pixels formats available\n");
844
845 /* XXX On NV cards, we want to use BGRA instead of RGBA for speed */
846 /* Fills the __allegro_gl_texture_format array */
847 /* TODO: use these somewhere */
848 #if 0
849 __allegro_gl_texture_read_format[0] = GL_UNSIGNED_BYTE_3_3_2;
850 __allegro_gl_texture_read_format[1] = GL_UNSIGNED_SHORT_5_5_5_1;
851 __allegro_gl_texture_read_format[2] = GL_UNSIGNED_SHORT_5_6_5;
852 #endif /* #if 0 */
853 }
854
855 /* NVidia and ATI cards expose OpenGL 2.0 but often don't accelerate
856 * non-power-of-2 textures. This check is how you verify that NP2
857 * textures are hardware accelerated or not.
858 * We should clobber the NPOT support if it's not accelerated.
859 */
860 {
861 const char *vendor = (const char *)glGetString(GL_VENDOR);
862 if (strstr(vendor, "NVIDIA Corporation")) {
863 if (!ext_list->ALLEGRO_GL_NV_fragment_program2
864 || !ext_list->ALLEGRO_GL_NV_vertex_program3) {
865 ext_list->ALLEGRO_GL_ARB_texture_non_power_of_two = 0;
866 }
867 }
868 else if (strstr(vendor, "ATI Technologies")) {
869 if (gl_disp->ogl_extras->ogl_info.version >= _ALLEGRO_OPENGL_VERSION_3_0) {
870 /* Assume okay. */
871 }
872 else if (!strstr((const char *)glGetString(GL_EXTENSIONS),
873 "GL_ARB_texture_non_power_of_two")
874 && gl_disp->ogl_extras->ogl_info.version >= _ALLEGRO_OPENGL_VERSION_2_0) {
875 ext_list->ALLEGRO_GL_ARB_texture_non_power_of_two = 0;
876 }
877 }
878 }
879
880 {
881 int *s = gl_disp->extra_settings.settings;
882 glGetIntegerv(GL_MAX_TEXTURE_SIZE, s + ALLEGRO_MAX_BITMAP_SIZE);
883
884 if (gl_disp->ogl_extras->ogl_info.version >= _ALLEGRO_OPENGL_VERSION_2_0)
885 s[ALLEGRO_SUPPORT_SEPARATE_ALPHA] = 1;
886
887 s[ALLEGRO_SUPPORT_NPOT_BITMAP] =
888 ext_list->ALLEGRO_GL_ARB_texture_non_power_of_two ||
889 ext_list->ALLEGRO_GL_OES_texture_npot;
890 ALLEGRO_INFO("Use of non-power-of-two textures %s.\n",
891 s[ALLEGRO_SUPPORT_NPOT_BITMAP] ? "enabled" : "disabled");
892 #if defined ALLEGRO_CFG_OPENGLES
893 if (gl_disp->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) {
894 s[ALLEGRO_CAN_DRAW_INTO_BITMAP] = true;
895 }
896 else {
897 s[ALLEGRO_CAN_DRAW_INTO_BITMAP] =
898 ext_list->ALLEGRO_GL_OES_framebuffer_object;
899 }
900 ALLEGRO_INFO("Use of FBO to draw to textures %s.\n",
901 s[ALLEGRO_CAN_DRAW_INTO_BITMAP] ? "enabled" :
902 "disabled");
903 #else
904 s[ALLEGRO_CAN_DRAW_INTO_BITMAP] =
905 ext_list->ALLEGRO_GL_EXT_framebuffer_object;
906 ALLEGRO_INFO("Use of FBO to draw to textures %s.\n",
907 s[ALLEGRO_CAN_DRAW_INTO_BITMAP] ? "enabled" :
908 "disabled");
909 #endif
910 }
911 }
912
913
914
915 /* Function: al_get_opengl_extension_list
916 */
al_get_opengl_extension_list(void)917 ALLEGRO_OGL_EXT_LIST *al_get_opengl_extension_list(void)
918 {
919 ALLEGRO_DISPLAY *disp;
920
921 disp = al_get_current_display();
922 ASSERT(disp);
923
924 if (!(disp->flags & ALLEGRO_OPENGL))
925 return NULL;
926
927 ASSERT(disp->ogl_extras);
928 return disp->ogl_extras->extension_list;
929 }
930
931
932
_al_ogl_unmanage_extensions(ALLEGRO_DISPLAY * gl_disp)933 void _al_ogl_unmanage_extensions(ALLEGRO_DISPLAY *gl_disp)
934 {
935 destroy_extension_api_table(gl_disp->ogl_extras->extension_api);
936 destroy_extension_list(gl_disp->ogl_extras->extension_list);
937 gl_disp->ogl_extras->extension_api = NULL;
938 gl_disp->ogl_extras->extension_list = NULL;
939
940 #ifdef ALLEGRO_MACOSX
941 CFRelease(opengl_bundle_ref);
942 #endif
943 #ifdef ALLEGRO_HAVE_DYNAMIC_LINK
944 if (__libgl_handle) {
945 dlclose(__libgl_handle);
946 __libgl_handle = NULL;
947 }
948 #endif
949 }
950
951 /* vim: set sts=3 sw=3 et: */
952