1 /* GdkGLExt - OpenGL Extension to GDK
2  * Copyright (C) 2002-2004  Naofumi Yasufuku
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA.
17  */
18 
19 #include <string.h>
20 
21 #ifdef __APPLE__
22 #include <mach-o/dyld.h>
23 #else  /* __APPLE__ */
24 #include <gmodule.h>
25 #endif /* __APPLE__ */
26 
27 #include "gdkglx.h"
28 #include "gdkglprivate-x11.h"
29 #include "gdkglconfig-x11.h"
30 #include "gdkglquery.h"
31 
32 #ifdef GDKGLEXT_MULTIHEAD_SUPPORT
33 #include <gdk/gdkdisplay.h>
34 #endif /* GDKGLEXT_MULTIHEAD_SUPPORT */
35 
36 /**
37  * gdk_gl_query_extension:
38  *
39  * Indicates whether the window system supports the OpenGL extension
40  * (GLX, WGL, etc.).
41  *
42  * Return value: TRUE if OpenGL is supported, FALSE otherwise.
43  **/
44 gboolean
gdk_gl_query_extension(void)45 gdk_gl_query_extension (void)
46 {
47 #ifdef GDKGLEXT_MULTIHEAD_SUPPORT
48   return glXQueryExtension (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
49                             NULL, NULL);
50 #else  /* GDKGLEXT_MULTIHEAD_SUPPORT */
51   return glXQueryExtension (gdk_x11_get_default_xdisplay (),
52                             NULL, NULL);
53 #endif /* GDKGLEXT_MULTIHEAD_SUPPORT */
54 }
55 
56 #ifdef GDKGLEXT_MULTIHEAD_SUPPORT
57 
58 /**
59  * gdk_gl_query_extension_for_display:
60  * @display: the #GdkDisplay where the query is sent to.
61  *
62  * Indicates whether the window system supports the OpenGL extension
63  * (GLX, WGL, etc.).
64  *
65  * Return value: TRUE if OpenGL is supported, FALSE otherwise.
66  **/
67 gboolean
gdk_gl_query_extension_for_display(GdkDisplay * display)68 gdk_gl_query_extension_for_display (GdkDisplay *display)
69 {
70   g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
71 
72   return glXQueryExtension (GDK_DISPLAY_XDISPLAY (display),
73                             NULL, NULL);
74 }
75 
76 #endif /* GDKGLEXT_MULTIHEAD_SUPPORT */
77 
78 /**
79  * gdk_gl_query_version:
80  * @major: returns the major version number of the OpenGL extension.
81  * @minor: returns the minor version number of the OpenGL extension.
82  *
83  * Returns the version numbers of the OpenGL extension to the window system.
84  *
85  * In the X Window System, it returns the GLX version.
86  *
87  * In the Microsoft Windows, it returns the Windows version.
88  *
89  * Return value: FALSE if it fails, TRUE otherwise.
90  **/
91 gboolean
gdk_gl_query_version(int * major,int * minor)92 gdk_gl_query_version (int *major,
93                       int *minor)
94 {
95 #ifdef GDKGLEXT_MULTIHEAD_SUPPORT
96   return glXQueryVersion (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
97                           major, minor);
98 #else  /* GDKGLEXT_MULTIHEAD_SUPPORT */
99   return glXQueryVersion (gdk_x11_get_default_xdisplay (),
100                           major, minor);
101 #endif /* GDKGLEXT_MULTIHEAD_SUPPORT */
102 }
103 
104 #ifdef GDKGLEXT_MULTIHEAD_SUPPORT
105 
106 /**
107  * gdk_gl_query_version_for_display:
108  * @display: the #GdkDisplay where the query is sent to.
109  * @major: returns the major version number of the OpenGL extension.
110  * @minor: returns the minor version number of the OpenGL extension.
111  *
112  * Returns the version numbers of the OpenGL extension to the window system.
113  *
114  * In the X Window System, it returns the GLX version.
115  *
116  * In the Microsoft Windows, it returns the Windows version.
117  *
118  * Return value: FALSE if it fails, TRUE otherwise.
119  **/
120 gboolean
gdk_gl_query_version_for_display(GdkDisplay * display,int * major,int * minor)121 gdk_gl_query_version_for_display (GdkDisplay *display,
122                                   int        *major,
123                                   int        *minor)
124 {
125   g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
126 
127   return glXQueryVersion (GDK_DISPLAY_XDISPLAY (display),
128                           major, minor);
129 }
130 
131 #endif /* GDKGLEXT_MULTIHEAD_SUPPORT */
132 
133 /*
134  * This code is based on __glutIsSupportedByGLX().
135  */
136 
137 /**
138  * gdk_x11_gl_query_glx_extension:
139  * @glconfig: a #GdkGLConfig.
140  * @extension: name of GLX extension.
141  *
142  * Determines whether a given GLX extension is supported.
143  *
144  * Return value: TRUE if the GLX extension is supported, FALSE if not
145  *               supported.
146  **/
147 gboolean
gdk_x11_gl_query_glx_extension(GdkGLConfig * glconfig,const char * extension)148 gdk_x11_gl_query_glx_extension (GdkGLConfig *glconfig,
149                                 const char  *extension)
150 {
151   static const char *extensions = NULL;
152   const char *start;
153   char *where, *terminator;
154   int major, minor;
155 
156   g_return_val_if_fail (GDK_IS_GL_CONFIG_IMPL_X11 (glconfig), FALSE);
157 
158   /* Extension names should not have spaces. */
159   where = strchr (extension, ' ');
160   if (where || *extension == '\0')
161     return FALSE;
162 
163   if (extensions == NULL)
164     {
165       /* Be careful not to call glXQueryExtensionsString if it
166          looks like the server doesn't support GLX 1.1.
167          Unfortunately, the original GLX 1.0 didn't have the notion
168          of GLX extensions. */
169 
170       glXQueryVersion (GDK_GL_CONFIG_XDISPLAY (glconfig),
171                        &major, &minor);
172 
173       if ((major == 1 && minor < 1) || (major < 1))
174         return FALSE;
175 
176       extensions = glXQueryExtensionsString (GDK_GL_CONFIG_XDISPLAY (glconfig),
177                                              GDK_GL_CONFIG_SCREEN_XNUMBER (glconfig));
178     }
179 
180   /* It takes a bit of care to be fool-proof about parsing
181      the GLX extensions string.  Don't be fooled by
182      sub-strings,  etc. */
183   start = extensions;
184   for (;;)
185     {
186       where = strstr (start, extension);
187       if (where == NULL)
188         break;
189 
190       terminator = where + strlen (extension);
191 
192       if (where == start || *(where - 1) == ' ')
193         if (*terminator == ' ' || *terminator == '\0')
194           {
195             GDK_GL_NOTE (MISC, g_message (" - %s - supported", extension));
196             return TRUE;
197           }
198 
199       start = terminator;
200     }
201 
202   GDK_GL_NOTE (MISC, g_message (" - %s - not supported", extension));
203 
204   return FALSE;
205 }
206 
207 /**
208  * gdk_gl_get_proc_address:
209  * @proc_name: function name.
210  *
211  * Returns the address of the OpenGL, GLU, or GLX function.
212  *
213  * Return value: the address of the function named by @proc_name.
214  **/
215 
216 #ifdef __APPLE__
217 
218 #define _GDK_GL_LIBGL_PATH  "/usr/X11R6/lib/libGL.1.dylib"
219 #define _GDK_GL_LIBGLU_PATH "/usr/X11R6/lib/libGLU.1.dylib"
220 
221 GdkGLProc
gdk_gl_get_proc_address(const char * proc_name)222 gdk_gl_get_proc_address (const char *proc_name)
223 {
224   typedef GdkGLProc (*__glXGetProcAddressProc) (const GLubyte *);
225   static __glXGetProcAddressProc glx_get_proc_address = (__glXGetProcAddressProc) -1;
226   const char *image_name;
227   static const struct mach_header *libgl_image = NULL;
228   static const struct mach_header *libglu_image = NULL;
229   NSSymbol symbol;
230   char *symbol_name;
231   GdkGLProc proc_address;
232 
233   GDK_GL_NOTE_FUNC ();
234 
235   if (strncmp ("glu", proc_name, 3) != 0)
236     {
237       /* libGL */
238 
239       if (libgl_image == NULL)
240         {
241           image_name = g_getenv ("GDK_GL_LIBGL_PATH");
242           if (image_name == NULL)
243             image_name = _GDK_GL_LIBGL_PATH;
244 
245           GDK_GL_NOTE (MISC, g_message (" - Add Mach-O image %s", image_name));
246 
247           libgl_image = NSAddImage (image_name, NSADDIMAGE_OPTION_RETURN_ON_ERROR);
248           if (libgl_image == NULL)
249             {
250               g_warning ("Cannot add Mach-O image %s", image_name);
251               return NULL;
252             }
253         }
254 
255       if (glx_get_proc_address == (__glXGetProcAddressProc) -1)
256         {
257           /*
258            * Look up glXGetProcAddress () function.
259            */
260 
261           symbol = NSLookupSymbolInImage (libgl_image,
262                                           "_glXGetProcAddress",
263                                           NSLOOKUPSYMBOLINIMAGE_OPTION_BIND |
264                                           NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
265           if (symbol == NULL)
266             {
267               symbol = NSLookupSymbolInImage (libgl_image,
268                                               "_glXGetProcAddressARB",
269                                               NSLOOKUPSYMBOLINIMAGE_OPTION_BIND |
270                                               NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
271               if (symbol == NULL)
272                 {
273                   symbol = NSLookupSymbolInImage (libgl_image,
274                                                   "_glXGetProcAddressEXT",
275                                                   NSLOOKUPSYMBOLINIMAGE_OPTION_BIND |
276                                                   NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
277                 }
278             }
279           GDK_GL_NOTE (MISC, g_message (" - glXGetProcAddress () - %s",
280                                         symbol ? "supported" : "not supported"));
281           if (symbol != NULL)
282             glx_get_proc_address = NSAddressOfSymbol (symbol);
283           else
284             glx_get_proc_address = NULL;
285         }
286 
287       /* Try glXGetProcAddress () */
288 
289       if (glx_get_proc_address != NULL)
290         {
291           proc_address = glx_get_proc_address (proc_name);
292           GDK_GL_NOTE (IMPL, g_message (" ** glXGetProcAddress () - %s",
293                                         proc_address ? "succeeded" : "failed"));
294           if (proc_address != NULL)
295             return proc_address;
296         }
297 
298       /* Try Mach-O dyld */
299 
300       symbol_name = g_strconcat ("_", proc_name, NULL);
301 
302       symbol = NSLookupSymbolInImage (libgl_image,
303                                       symbol_name,
304                                       NSLOOKUPSYMBOLINIMAGE_OPTION_BIND |
305                                       NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
306       GDK_GL_NOTE (MISC, g_message (" - NSLookupSymbolInImage () - %s",
307                                     symbol ? "succeeded" : "failed"));
308 
309       g_free (symbol_name);
310 
311       if (symbol != NULL)
312         return NSAddressOfSymbol (symbol);
313     }
314   else
315     {
316       /* libGLU */
317 
318       if (libglu_image == NULL)
319         {
320           image_name = g_getenv ("GDK_GL_LIBGLU_PATH");
321           if (image_name == NULL)
322             image_name = _GDK_GL_LIBGLU_PATH;
323 
324           GDK_GL_NOTE (MISC, g_message (" - Add Mach-O image %s", image_name));
325 
326           libglu_image = NSAddImage (image_name, NSADDIMAGE_OPTION_RETURN_ON_ERROR);
327           if (libglu_image == NULL)
328             {
329               g_warning ("Cannot add Mach-O image %s", image_name);
330               return NULL;
331             }
332         }
333 
334       symbol_name = g_strconcat ("_", proc_name, NULL);
335 
336       symbol = NSLookupSymbolInImage (libglu_image,
337                                       symbol_name,
338                                       NSLOOKUPSYMBOLINIMAGE_OPTION_BIND |
339                                       NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
340       GDK_GL_NOTE (MISC, g_message (" - NSLookupSymbolInImage () - %s",
341                                     symbol ? "succeeded" : "failed"));
342 
343       g_free (symbol_name);
344 
345       if (symbol != NULL)
346         return NSAddressOfSymbol (symbol);
347     }
348 
349   return NULL;
350 }
351 
352 #else  /* __APPLE__ */
353 
354 GdkGLProc
gdk_gl_get_proc_address(const char * proc_name)355 gdk_gl_get_proc_address (const char *proc_name)
356 {
357   typedef GdkGLProc (*__glXGetProcAddressProc) (const GLubyte *);
358   static __glXGetProcAddressProc glx_get_proc_address = (__glXGetProcAddressProc) -1;
359   gchar *file_name;
360   GModule *module;
361   GdkGLProc proc_address = NULL;
362 
363   GDK_GL_NOTE_FUNC ();
364 
365   if (strncmp ("glu", proc_name, 3) != 0)
366     {
367       if (glx_get_proc_address == (__glXGetProcAddressProc) -1)
368         {
369           /*
370            * Look up glXGetProcAddress () function.
371            */
372 
373           file_name = g_module_build_path (NULL, "GL");
374           GDK_GL_NOTE (MISC, g_message (" - Open %s", file_name));
375           module = g_module_open (file_name, G_MODULE_BIND_LAZY);
376           g_free (file_name);
377 
378           if (module != NULL)
379             {
380               g_module_symbol (module, "glXGetProcAddress",
381                                (gpointer) &glx_get_proc_address);
382               if (glx_get_proc_address == NULL)
383                 {
384                   g_module_symbol (module, "glXGetProcAddressARB",
385                                    (gpointer) &glx_get_proc_address);
386                   if (glx_get_proc_address == NULL)
387                     {
388                       g_module_symbol (module, "glXGetProcAddressEXT",
389                                        (gpointer) &glx_get_proc_address);
390                     }
391                 }
392               GDK_GL_NOTE (MISC, g_message (" - glXGetProcAddress () - %s",
393                                             glx_get_proc_address ? "supported" : "not supported"));
394               g_module_close (module);
395             }
396           else
397             {
398               g_warning ("Cannot open %s", file_name);
399               glx_get_proc_address = NULL;
400               return NULL;
401             }
402         }
403 
404       /* Try glXGetProcAddress () */
405 
406       if (glx_get_proc_address != NULL)
407         {
408           proc_address = glx_get_proc_address (proc_name);
409           GDK_GL_NOTE (IMPL, g_message (" ** glXGetProcAddress () - %s",
410                                         proc_address ? "succeeded" : "failed"));
411           if (proc_address != NULL)
412             return proc_address;
413         }
414 
415       /* Try g_module_symbol () */
416 
417       /* libGL */
418       file_name = g_module_build_path (NULL, "GL");
419       GDK_GL_NOTE (MISC, g_message (" - Open %s", file_name));
420       module = g_module_open (file_name, G_MODULE_BIND_LAZY);
421       g_free (file_name);
422 
423       if (module != NULL)
424         {
425           g_module_symbol (module, proc_name, (gpointer) &proc_address);
426           GDK_GL_NOTE (MISC, g_message (" - g_module_symbol () - %s",
427                                         proc_address ? "succeeded" : "failed"));
428           g_module_close (module);
429         }
430       else
431         {
432           g_warning ("Cannot open %s", file_name);
433         }
434 
435       if (proc_address == NULL)
436         {
437           /* libGLcore */
438           file_name = g_module_build_path (NULL, "GLcore");
439           GDK_GL_NOTE (MISC, g_message (" - Open %s", file_name));
440           module = g_module_open (file_name, G_MODULE_BIND_LAZY);
441           g_free (file_name);
442 
443           if (module != NULL)
444             {
445               g_module_symbol (module, proc_name, (gpointer) &proc_address);
446               GDK_GL_NOTE (MISC, g_message (" - g_module_symbol () - %s",
447                                             proc_address ? "succeeded" : "failed"));
448               g_module_close (module);
449             }
450         }
451     }
452   else
453     {
454       /* libGLU */
455       file_name = g_module_build_path (NULL, "GLU");
456       GDK_GL_NOTE (MISC, g_message (" - Open %s", file_name));
457       module = g_module_open (file_name, G_MODULE_BIND_LAZY);
458       g_free (file_name);
459 
460       if (module != NULL)
461         {
462           g_module_symbol (module, proc_name, (gpointer) &proc_address);
463           GDK_GL_NOTE (MISC, g_message (" - g_module_symbol () - %s",
464                                         proc_address ? "succeeded" : "failed"));
465           g_module_close (module);
466         }
467       else
468         {
469           g_warning ("Cannot open %s", file_name);
470         }
471     }
472 
473   return proc_address;
474 }
475 
476 #endif /* __APPLE__ */
477 
478 /*< private >*/
479 void
_gdk_x11_gl_print_glx_info(Display * xdisplay,int screen_num)480 _gdk_x11_gl_print_glx_info (Display *xdisplay,
481                             int      screen_num)
482 {
483   static gboolean done = FALSE;
484 
485   if (!done)
486     {
487       g_message (" -- Server GLX_VENDOR     : %s",
488                  glXQueryServerString (xdisplay, screen_num, GLX_VENDOR));
489       g_message (" -- Server GLX_VERSION    : %s",
490                  glXQueryServerString (xdisplay, screen_num, GLX_VERSION));
491       g_message (" -- Server GLX_EXTENSIONS : %s",
492                  glXQueryServerString (xdisplay, screen_num, GLX_EXTENSIONS));
493 
494       g_message (" -- Client GLX_VENDOR     : %s",
495                  glXGetClientString (xdisplay, GLX_VENDOR));
496       g_message (" -- Client GLX_VERSION    : %s",
497                  glXGetClientString (xdisplay, GLX_VERSION));
498       g_message (" -- Client GLX_EXTENSIONS : %s",
499                  glXGetClientString (xdisplay, GLX_EXTENSIONS));
500 
501       done = TRUE;
502     }
503 }
504