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