1/**************************************************************************
2 *
3 * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
4 * Copyright 2009-2010 Chia-I Wu <olvaffe@gmail.com>
5 * Copyright 2010-2011 LunarG, Inc.
6 * All Rights Reserved.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the
10 * "Software"), to deal in the Software without restriction, including
11 * without limitation the rights to use, copy, modify, merge, publish,
12 * distribute, sub license, and/or sell copies of the Software, and to
13 * permit persons to whom the Software is furnished to do so, subject to
14 * the following conditions:
15 *
16 * The above copyright notice and this permission notice (including the
17 * next paragraph) shall be included in all copies or substantial portions
18 * of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
23 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 * DEALINGS IN THE SOFTWARE.
27 *
28 **************************************************************************/
29
30
31/**
32 * This is an EGL driver that wraps GLX. This gives the benefit of being
33 * completely agnostic of the direct rendering implementation.
34 *
35 * Authors: Alan Hourihane <alanh@tungstengraphics.com>
36 */
37
38#include <stdlib.h>
39#include <string.h>
40#include <X11/Xlib.h>
41#include <dlfcn.h>
42#include "GL/glx.h"
43
44#include "eglconfig.h"
45#include "eglcontext.h"
46#include "egldefines.h"
47#include "egldisplay.h"
48#include "egldriver.h"
49#include "eglcurrent.h"
50#include "egllog.h"
51#include "eglsurface.h"
52
53#define CALLOC_STRUCT(T)   (struct T *) calloc(1, sizeof(struct T))
54
55#ifndef GLX_VERSION_1_4
56#error "GL/glx.h must be equal to or greater than GLX 1.4"
57#endif
58
59/* GLX 1.0 */
60typedef GLXContext (*GLXCREATECONTEXTPROC)( Display *dpy, XVisualInfo *vis, GLXContext shareList, Bool direct );
61typedef void (*GLXDESTROYCONTEXTPROC)( Display *dpy, GLXContext ctx );
62typedef Bool (*GLXMAKECURRENTPROC)( Display *dpy, GLXDrawable drawable, GLXContext ctx);
63typedef void (*GLXSWAPBUFFERSPROC)( Display *dpy, GLXDrawable drawable );
64typedef GLXPixmap (*GLXCREATEGLXPIXMAPPROC)( Display *dpy, XVisualInfo *visual, Pixmap pixmap );
65typedef void (*GLXDESTROYGLXPIXMAPPROC)( Display *dpy, GLXPixmap pixmap );
66typedef Bool (*GLXQUERYVERSIONPROC)( Display *dpy, int *maj, int *min );
67typedef int (*GLXGETCONFIGPROC)( Display *dpy, XVisualInfo *visual, int attrib, int *value );
68typedef void (*GLXWAITGLPROC)( void );
69typedef void (*GLXWAITXPROC)( void );
70
71/* GLX 1.1 */
72typedef const char *(*GLXQUERYEXTENSIONSSTRINGPROC)( Display *dpy, int screen );
73typedef const char *(*GLXQUERYSERVERSTRINGPROC)( Display *dpy, int screen, int name );
74typedef const char *(*GLXGETCLIENTSTRINGPROC)( Display *dpy, int name );
75
76/** subclass of _EGLDriver */
77struct GLX_egl_driver
78{
79   _EGLDriver Base;   /**< base class */
80
81   void *handle;
82
83   /* GLX 1.0 */
84   GLXCREATECONTEXTPROC glXCreateContext;
85   GLXDESTROYCONTEXTPROC glXDestroyContext;
86   GLXMAKECURRENTPROC glXMakeCurrent;
87   GLXSWAPBUFFERSPROC glXSwapBuffers;
88   GLXCREATEGLXPIXMAPPROC glXCreateGLXPixmap;
89   GLXDESTROYGLXPIXMAPPROC glXDestroyGLXPixmap;
90   GLXQUERYVERSIONPROC glXQueryVersion;
91   GLXGETCONFIGPROC glXGetConfig;
92   GLXWAITGLPROC glXWaitGL;
93   GLXWAITXPROC glXWaitX;
94
95   /* GLX 1.1 */
96   GLXQUERYEXTENSIONSSTRINGPROC glXQueryExtensionsString;
97   GLXQUERYSERVERSTRINGPROC glXQueryServerString;
98   GLXGETCLIENTSTRINGPROC glXGetClientString;
99
100   /* GLX 1.3 or (GLX_SGI_make_current_read and GLX_SGIX_fbconfig) */
101   PFNGLXGETFBCONFIGSPROC glXGetFBConfigs;
102   PFNGLXGETFBCONFIGATTRIBPROC glXGetFBConfigAttrib;
103   PFNGLXGETVISUALFROMFBCONFIGPROC glXGetVisualFromFBConfig;
104   PFNGLXCREATEWINDOWPROC glXCreateWindow;
105   PFNGLXDESTROYWINDOWPROC glXDestroyWindow;
106   PFNGLXCREATEPIXMAPPROC glXCreatePixmap;
107   PFNGLXDESTROYPIXMAPPROC glXDestroyPixmap;
108   PFNGLXCREATEPBUFFERPROC glXCreatePbuffer;
109   PFNGLXDESTROYPBUFFERPROC glXDestroyPbuffer;
110   PFNGLXCREATENEWCONTEXTPROC glXCreateNewContext;
111   PFNGLXMAKECONTEXTCURRENTPROC glXMakeContextCurrent;
112
113   /* GLX 1.4 or GLX_ARB_get_proc_address */
114   PFNGLXGETPROCADDRESSPROC glXGetProcAddress;
115
116   /* GLX_SGIX_pbuffer */
117   PFNGLXCREATEGLXPBUFFERSGIXPROC glXCreateGLXPbufferSGIX;
118   PFNGLXDESTROYGLXPBUFFERSGIXPROC glXDestroyGLXPbufferSGIX;
119};
120
121
122/** driver data of _EGLDisplay */
123struct GLX_egl_display
124{
125   Display *dpy;
126   XVisualInfo *visuals;
127   GLXFBConfig *fbconfigs;
128
129   int glx_maj, glx_min;
130
131   const char *extensions;
132   EGLBoolean have_1_3;
133   EGLBoolean have_make_current_read;
134   EGLBoolean have_fbconfig;
135   EGLBoolean have_pbuffer;
136
137   /* workaround quirks of different GLX implementations */
138   EGLBoolean single_buffered_quirk;
139   EGLBoolean glx_window_quirk;
140};
141
142
143/** subclass of _EGLContext */
144struct GLX_egl_context
145{
146   _EGLContext Base;   /**< base class */
147
148   GLXContext context;
149};
150
151
152/** subclass of _EGLSurface */
153struct GLX_egl_surface
154{
155   _EGLSurface Base;   /**< base class */
156
157   Drawable drawable;
158   GLXDrawable glx_drawable;
159
160   void (*destroy)(Display *, GLXDrawable);
161};
162
163
164/** subclass of _EGLConfig */
165struct GLX_egl_config
166{
167   _EGLConfig Base;   /**< base class */
168   EGLBoolean double_buffered;
169   int index;
170};
171
172/* standard typecasts */
173_EGL_DRIVER_STANDARD_TYPECASTS(GLX_egl)
174
175static int
176GLX_egl_config_index(_EGLConfig *conf)
177{
178   struct GLX_egl_config *GLX_conf = GLX_egl_config(conf);
179   return GLX_conf->index;
180}
181
182
183static const struct {
184   int attr;
185   int egl_attr;
186} fbconfig_attributes[] = {
187   /* table 3.1 of GLX 1.4 */
188   { GLX_FBCONFIG_ID,                  0 },
189   { GLX_BUFFER_SIZE,                  EGL_BUFFER_SIZE },
190   { GLX_LEVEL,                        EGL_LEVEL },
191   { GLX_DOUBLEBUFFER,                 0 },
192   { GLX_STEREO,                       0 },
193   { GLX_AUX_BUFFERS,                  0 },
194   { GLX_RED_SIZE,                     EGL_RED_SIZE },
195   { GLX_GREEN_SIZE,                   EGL_GREEN_SIZE },
196   { GLX_BLUE_SIZE,                    EGL_BLUE_SIZE },
197   { GLX_ALPHA_SIZE,                   EGL_ALPHA_SIZE },
198   { GLX_DEPTH_SIZE,                   EGL_DEPTH_SIZE },
199   { GLX_STENCIL_SIZE,                 EGL_STENCIL_SIZE },
200   { GLX_ACCUM_RED_SIZE,               0 },
201   { GLX_ACCUM_GREEN_SIZE,             0 },
202   { GLX_ACCUM_BLUE_SIZE,              0 },
203   { GLX_ACCUM_ALPHA_SIZE,             0 },
204   { GLX_SAMPLE_BUFFERS,               EGL_SAMPLE_BUFFERS },
205   { GLX_SAMPLES,                      EGL_SAMPLES },
206   { GLX_RENDER_TYPE,                  0 },
207   { GLX_DRAWABLE_TYPE,                EGL_SURFACE_TYPE },
208   { GLX_X_RENDERABLE,                 EGL_NATIVE_RENDERABLE },
209   { GLX_X_VISUAL_TYPE,                EGL_NATIVE_VISUAL_TYPE },
210   { GLX_CONFIG_CAVEAT,                EGL_CONFIG_CAVEAT },
211   { GLX_TRANSPARENT_TYPE,             EGL_TRANSPARENT_TYPE },
212   { GLX_TRANSPARENT_INDEX_VALUE,      0 },
213   { GLX_TRANSPARENT_RED_VALUE,        EGL_TRANSPARENT_RED_VALUE },
214   { GLX_TRANSPARENT_GREEN_VALUE,      EGL_TRANSPARENT_GREEN_VALUE },
215   { GLX_TRANSPARENT_BLUE_VALUE,       EGL_TRANSPARENT_BLUE_VALUE },
216   { GLX_MAX_PBUFFER_WIDTH,            EGL_MAX_PBUFFER_WIDTH },
217   { GLX_MAX_PBUFFER_HEIGHT,           EGL_MAX_PBUFFER_HEIGHT },
218   { GLX_MAX_PBUFFER_PIXELS,           EGL_MAX_PBUFFER_PIXELS },
219   { GLX_VISUAL_ID,                    EGL_NATIVE_VISUAL_ID }
220};
221
222
223static EGLBoolean
224convert_fbconfig(struct GLX_egl_driver *GLX_drv,
225                 struct GLX_egl_display *GLX_dpy, GLXFBConfig fbconfig,
226                 struct GLX_egl_config *GLX_conf)
227{
228   Display *dpy = GLX_dpy->dpy;
229   int err, attr, val;
230   unsigned i;
231
232   /* must have rgba bit */
233   err = GLX_drv->glXGetFBConfigAttrib(dpy, fbconfig, GLX_RENDER_TYPE, &val);
234   if (err || !(val & GLX_RGBA_BIT))
235      return EGL_FALSE;
236
237   /* must know whether it is double-buffered */
238   err = GLX_drv->glXGetFBConfigAttrib(dpy, fbconfig, GLX_DOUBLEBUFFER, &val);
239   if (err)
240      return EGL_FALSE;
241   GLX_conf->double_buffered = val;
242
243   GLX_conf->Base.RenderableType = EGL_OPENGL_BIT;
244   GLX_conf->Base.Conformant = EGL_OPENGL_BIT;
245
246   for (i = 0; i < ARRAY_SIZE(fbconfig_attributes); i++) {
247      EGLint egl_attr, egl_val;
248
249      attr = fbconfig_attributes[i].attr;
250      egl_attr = fbconfig_attributes[i].egl_attr;
251      if (!egl_attr)
252         continue;
253
254      err = GLX_drv->glXGetFBConfigAttrib(dpy, fbconfig, attr, &val);
255      if (err) {
256         if (err == GLX_BAD_ATTRIBUTE) {
257            err = 0;
258            continue;
259         }
260         break;
261      }
262
263      switch (egl_attr) {
264      case EGL_SURFACE_TYPE:
265         egl_val = 0;
266         if (val & GLX_WINDOW_BIT)
267            egl_val |= EGL_WINDOW_BIT;
268         /* pixmap and pbuffer surfaces must be single-buffered in EGL */
269         if (!GLX_conf->double_buffered) {
270            if (val & GLX_PIXMAP_BIT)
271               egl_val |= EGL_PIXMAP_BIT;
272            if (val & GLX_PBUFFER_BIT)
273               egl_val |= EGL_PBUFFER_BIT;
274         }
275         break;
276      case EGL_NATIVE_VISUAL_TYPE:
277         switch (val) {
278         case GLX_TRUE_COLOR:
279            egl_val = TrueColor;
280            break;
281         case GLX_DIRECT_COLOR:
282            egl_val = DirectColor;
283            break;
284         case GLX_PSEUDO_COLOR:
285            egl_val = PseudoColor;
286            break;
287         case GLX_STATIC_COLOR:
288            egl_val = StaticColor;
289            break;
290         case GLX_GRAY_SCALE:
291            egl_val = GrayScale;
292            break;
293         case GLX_STATIC_GRAY:
294            egl_val = StaticGray;
295            break;
296         default:
297            egl_val = EGL_NONE;
298            break;
299         }
300         break;
301      case EGL_CONFIG_CAVEAT:
302         egl_val = EGL_NONE;
303         if (val == GLX_SLOW_CONFIG) {
304            egl_val = EGL_SLOW_CONFIG;
305         }
306         else if (val == GLX_NON_CONFORMANT_CONFIG) {
307            GLX_conf->Base.Conformant &= ~EGL_OPENGL_BIT;
308            egl_val = EGL_NONE;
309         }
310         break;
311      case EGL_TRANSPARENT_TYPE:
312         egl_val = (val == GLX_TRANSPARENT_RGB) ?
313            EGL_TRANSPARENT_RGB : EGL_NONE;
314         break;
315      default:
316         egl_val = val;
317         break;
318      }
319
320      _eglSetConfigKey(&GLX_conf->Base, egl_attr, egl_val);
321   }
322   if (err)
323      return EGL_FALSE;
324
325   if (!GLX_conf->Base.SurfaceType)
326      return EGL_FALSE;
327
328   return EGL_TRUE;
329}
330
331static const struct {
332   int attr;
333   int egl_attr;
334} visual_attributes[] = {
335   /* table 3.7 of GLX 1.4 */
336   { GLX_USE_GL,              0 },
337   { GLX_BUFFER_SIZE,         EGL_BUFFER_SIZE },
338   { GLX_LEVEL,               EGL_LEVEL },
339   { GLX_RGBA,                0 },
340   { GLX_DOUBLEBUFFER,        0 },
341   { GLX_STEREO,              0 },
342   { GLX_AUX_BUFFERS,         0 },
343   { GLX_RED_SIZE,            EGL_RED_SIZE },
344   { GLX_GREEN_SIZE,          EGL_GREEN_SIZE },
345   { GLX_BLUE_SIZE,           EGL_BLUE_SIZE },
346   { GLX_ALPHA_SIZE,          EGL_ALPHA_SIZE },
347   { GLX_DEPTH_SIZE,          EGL_DEPTH_SIZE },
348   { GLX_STENCIL_SIZE,        EGL_STENCIL_SIZE },
349   { GLX_ACCUM_RED_SIZE,      0 },
350   { GLX_ACCUM_GREEN_SIZE,    0 },
351   { GLX_ACCUM_BLUE_SIZE,     0 },
352   { GLX_ACCUM_ALPHA_SIZE,    0 },
353   { GLX_SAMPLE_BUFFERS,      EGL_SAMPLE_BUFFERS },
354   { GLX_SAMPLES,             EGL_SAMPLES },
355   { GLX_FBCONFIG_ID,         0 },
356   /* GLX_EXT_visual_rating */
357   { GLX_VISUAL_CAVEAT_EXT,   EGL_CONFIG_CAVEAT }
358};
359
360static EGLBoolean
361convert_visual(struct GLX_egl_driver *GLX_drv,
362               struct GLX_egl_display *GLX_dpy, XVisualInfo *vinfo,
363               struct GLX_egl_config *GLX_conf)
364{
365   Display *dpy = GLX_dpy->dpy;
366   int err, attr, val;
367   unsigned i;
368
369   /* the visual must support OpenGL and RGBA buffer */
370   err = GLX_drv->glXGetConfig(dpy, vinfo, GLX_USE_GL, &val);
371   if (!err && val)
372      err = GLX_drv->glXGetConfig(dpy, vinfo, GLX_RGBA, &val);
373   if (err || !val)
374      return EGL_FALSE;
375
376   /* must know whether it is double-buffered */
377   err = GLX_drv->glXGetConfig(dpy, vinfo, GLX_DOUBLEBUFFER, &val);
378   if (err)
379      return EGL_FALSE;
380   GLX_conf->double_buffered = val;
381
382   GLX_conf->Base.RenderableType = EGL_OPENGL_BIT;
383   GLX_conf->Base.Conformant = EGL_OPENGL_BIT;
384   GLX_conf->Base.SurfaceType = EGL_WINDOW_BIT;
385   /* pixmap surfaces must be single-buffered in EGL */
386   if (!GLX_conf->double_buffered)
387      GLX_conf->Base.SurfaceType |= EGL_PIXMAP_BIT;
388
389   GLX_conf->Base.NativeVisualID = vinfo->visualid;
390   GLX_conf->Base.NativeVisualType = vinfo->class;
391   GLX_conf->Base.NativeRenderable = EGL_TRUE;
392
393   for (i = 0; i < ARRAY_SIZE(visual_attributes); i++) {
394      EGLint egl_attr, egl_val;
395
396      attr = visual_attributes[i].attr;
397      egl_attr = visual_attributes[i].egl_attr;
398      if (!egl_attr)
399         continue;
400
401      err = GLX_drv->glXGetConfig(dpy, vinfo, attr, &val);
402      if (err) {
403         if (err == GLX_BAD_ATTRIBUTE) {
404            err = 0;
405            continue;
406         }
407         break;
408      }
409
410      switch (egl_attr) {
411      case EGL_CONFIG_CAVEAT:
412         egl_val = EGL_NONE;
413         if (val == GLX_SLOW_VISUAL_EXT) {
414            egl_val = EGL_SLOW_CONFIG;
415         }
416         else if (val == GLX_NON_CONFORMANT_VISUAL_EXT) {
417            GLX_conf->Base.Conformant &= ~EGL_OPENGL_BIT;
418            egl_val = EGL_NONE;
419         }
420         break;
421         break;
422      default:
423         egl_val = val;
424         break;
425      }
426      _eglSetConfigKey(&GLX_conf->Base, egl_attr, egl_val);
427   }
428
429   return (err) ? EGL_FALSE : EGL_TRUE;
430}
431
432
433static void
434fix_config(struct GLX_egl_display *GLX_dpy, struct GLX_egl_config *GLX_conf)
435{
436   _EGLConfig *conf = &GLX_conf->Base;
437
438   if (!GLX_conf->double_buffered && GLX_dpy->single_buffered_quirk) {
439      /* some GLX impls do not like single-buffered window surface */
440      conf->SurfaceType &= ~EGL_WINDOW_BIT;
441      /* pbuffer bit is usually not set */
442      if (GLX_dpy->have_pbuffer)
443         conf->SurfaceType |= EGL_PBUFFER_BIT;
444   }
445
446   /* no visual attribs unless window bit is set */
447   if (!(conf->SurfaceType & EGL_WINDOW_BIT)) {
448      conf->NativeVisualID = 0;
449      conf->NativeVisualType = EGL_NONE;
450   }
451
452   if (conf->TransparentType != EGL_TRANSPARENT_RGB) {
453      /* some impls set them to -1 (GLX_DONT_CARE) */
454      conf->TransparentRedValue = 0;
455      conf->TransparentGreenValue = 0;
456      conf->TransparentBlueValue = 0;
457   }
458
459   /* make sure buffer size is set correctly */
460   conf->BufferSize =
461      conf->RedSize + conf->GreenSize + conf->BlueSize + conf->AlphaSize;
462}
463
464
465static EGLBoolean
466create_configs(_EGLDriver *drv, _EGLDisplay *dpy, EGLint screen)
467{
468   struct GLX_egl_driver *GLX_drv = GLX_egl_driver(drv);
469   struct GLX_egl_display *GLX_dpy = GLX_egl_display(dpy);
470   EGLint num_configs = 0, i;
471   EGLint id = 1;
472
473   if (GLX_dpy->have_fbconfig) {
474      GLX_dpy->fbconfigs =
475         GLX_drv->glXGetFBConfigs(GLX_dpy->dpy, screen, &num_configs);
476   }
477   else {
478      XVisualInfo vinfo_template;
479      long mask;
480
481      vinfo_template.screen = screen;
482      mask = VisualScreenMask;
483      GLX_dpy->visuals = XGetVisualInfo(GLX_dpy->dpy, mask, &vinfo_template,
484                                        &num_configs);
485   }
486
487   if (!num_configs)
488      return EGL_FALSE;
489
490   for (i = 0; i < num_configs; i++) {
491      struct GLX_egl_config *GLX_conf, template;
492      EGLBoolean ok;
493
494      memset(&template, 0, sizeof(template));
495      _eglInitConfig(&template.Base, dpy, id);
496      if (GLX_dpy->have_fbconfig) {
497         ok = convert_fbconfig(GLX_drv, GLX_dpy,
498               GLX_dpy->fbconfigs[i], &template);
499      }
500      else {
501         ok = convert_visual(GLX_drv, GLX_dpy,
502               &GLX_dpy->visuals[i], &template);
503      }
504      if (!ok)
505        continue;
506
507      fix_config(GLX_dpy, &template);
508      if (!_eglValidateConfig(&template.Base, EGL_FALSE)) {
509         _eglLog(_EGL_DEBUG, "GLX: failed to validate config %d", i);
510         continue;
511      }
512
513      GLX_conf = CALLOC_STRUCT(GLX_egl_config);
514      if (GLX_conf) {
515         memcpy(GLX_conf, &template, sizeof(template));
516         GLX_conf->index = i;
517
518         _eglLinkConfig(&GLX_conf->Base);
519         id++;
520      }
521   }
522
523   return EGL_TRUE;
524}
525
526
527static void
528check_extensions(struct GLX_egl_driver *GLX_drv,
529                 struct GLX_egl_display *GLX_dpy, EGLint screen)
530{
531   GLX_dpy->extensions =
532      GLX_drv->glXQueryExtensionsString(GLX_dpy->dpy, screen);
533   if (GLX_dpy->extensions) {
534      if (strstr(GLX_dpy->extensions, "GLX_SGI_make_current_read")) {
535         /* GLX 1.3 entry points are used */
536         GLX_dpy->have_make_current_read = EGL_TRUE;
537      }
538
539      if (strstr(GLX_dpy->extensions, "GLX_SGIX_fbconfig")) {
540         /* GLX 1.3 entry points are used */
541         GLX_dpy->have_fbconfig = EGL_TRUE;
542      }
543
544      if (strstr(GLX_dpy->extensions, "GLX_SGIX_pbuffer")) {
545         if (GLX_drv->glXCreateGLXPbufferSGIX &&
546             GLX_drv->glXDestroyGLXPbufferSGIX &&
547             GLX_dpy->have_fbconfig)
548            GLX_dpy->have_pbuffer = EGL_TRUE;
549      }
550   }
551
552   if (GLX_dpy->glx_maj == 1 && GLX_dpy->glx_min >= 3) {
553      GLX_dpy->have_1_3 = EGL_TRUE;
554      GLX_dpy->have_make_current_read = EGL_TRUE;
555      GLX_dpy->have_fbconfig = EGL_TRUE;
556      GLX_dpy->have_pbuffer = EGL_TRUE;
557   }
558}
559
560
561static void
562check_quirks(struct GLX_egl_driver *GLX_drv,
563             struct GLX_egl_display *GLX_dpy, EGLint screen)
564{
565   const char *vendor;
566
567   GLX_dpy->single_buffered_quirk = EGL_TRUE;
568   GLX_dpy->glx_window_quirk = EGL_TRUE;
569
570   vendor = GLX_drv->glXGetClientString(GLX_dpy->dpy, GLX_VENDOR);
571   if (vendor && strstr(vendor, "NVIDIA")) {
572      vendor = GLX_drv->glXQueryServerString(GLX_dpy->dpy, screen, GLX_VENDOR);
573      if (vendor && strstr(vendor, "NVIDIA")) {
574         _eglLog(_EGL_DEBUG, "disable quirks");
575         GLX_dpy->single_buffered_quirk = EGL_FALSE;
576         GLX_dpy->glx_window_quirk = EGL_FALSE;
577      }
578   }
579}
580
581
582/**
583 * Called via eglInitialize(), GLX_drv->API.Initialize().
584 */
585static EGLBoolean
586GLX_eglInitialize(_EGLDriver *drv, _EGLDisplay *disp)
587{
588   struct GLX_egl_driver *GLX_drv = GLX_egl_driver(drv);
589   struct GLX_egl_display *GLX_dpy;
590
591   if (disp->Platform != _EGL_PLATFORM_X11)
592      return EGL_FALSE;
593
594   /* this is a fallback driver */
595   if (!disp->Options.UseFallback)
596      return EGL_FALSE;
597
598   if (disp->Options.TestOnly)
599      return EGL_TRUE;
600
601   GLX_dpy = CALLOC_STRUCT(GLX_egl_display);
602   if (!GLX_dpy)
603      return _eglError(EGL_BAD_ALLOC, "eglInitialize");
604
605   GLX_dpy->dpy = (Display *) disp->PlatformDisplay;
606   if (!GLX_dpy->dpy) {
607      GLX_dpy->dpy = XOpenDisplay(NULL);
608      if (!GLX_dpy->dpy) {
609         _eglLog(_EGL_WARNING, "GLX: XOpenDisplay failed");
610         free(GLX_dpy);
611         return EGL_FALSE;
612      }
613   }
614
615   if (!GLX_drv->glXQueryVersion(GLX_dpy->dpy,
616            &GLX_dpy->glx_maj, &GLX_dpy->glx_min)) {
617      _eglLog(_EGL_WARNING, "GLX: glXQueryVersion failed");
618      if (!disp->PlatformDisplay)
619         XCloseDisplay(GLX_dpy->dpy);
620      free(GLX_dpy);
621      return EGL_FALSE;
622   }
623
624   disp->DriverData = (void *) GLX_dpy;
625   disp->ClientAPIs = EGL_OPENGL_BIT;
626
627   check_extensions(GLX_drv, GLX_dpy, DefaultScreen(GLX_dpy->dpy));
628   check_quirks(GLX_drv, GLX_dpy, DefaultScreen(GLX_dpy->dpy));
629
630   create_configs(drv, disp, DefaultScreen(GLX_dpy->dpy));
631   if (!_eglGetArraySize(disp->Configs)) {
632      _eglLog(_EGL_WARNING, "GLX: failed to create any config");
633      if (!disp->PlatformDisplay)
634         XCloseDisplay(GLX_dpy->dpy);
635      free(GLX_dpy);
636      return EGL_FALSE;
637   }
638
639   /* we're supporting EGL 1.4 */
640   disp->VersionMajor = 1;
641   disp->VersionMinor = 4;
642
643   return EGL_TRUE;
644}
645
646
647/**
648 * Called via eglTerminate(), drv->API.Terminate().
649 */
650static EGLBoolean
651GLX_eglTerminate(_EGLDriver *drv, _EGLDisplay *disp)
652{
653   struct GLX_egl_display *GLX_dpy = GLX_egl_display(disp);
654
655   _eglReleaseDisplayResources(drv, disp);
656   _eglCleanupDisplay(disp);
657
658   if (GLX_dpy->visuals)
659      XFree(GLX_dpy->visuals);
660   if (GLX_dpy->fbconfigs)
661      XFree(GLX_dpy->fbconfigs);
662
663   if (!disp->PlatformDisplay)
664      XCloseDisplay(GLX_dpy->dpy);
665   free(GLX_dpy);
666
667   disp->DriverData = NULL;
668
669   return EGL_TRUE;
670}
671
672
673/**
674 * Called via eglCreateContext(), drv->API.CreateContext().
675 */
676static _EGLContext *
677GLX_eglCreateContext(_EGLDriver *drv, _EGLDisplay *disp, _EGLConfig *conf,
678                      _EGLContext *share_list, const EGLint *attrib_list)
679{
680   struct GLX_egl_driver *GLX_drv = GLX_egl_driver(drv);
681   struct GLX_egl_context *GLX_ctx = CALLOC_STRUCT(GLX_egl_context);
682   struct GLX_egl_display *GLX_dpy = GLX_egl_display(disp);
683   struct GLX_egl_context *GLX_ctx_shared = GLX_egl_context(share_list);
684
685   if (!GLX_ctx) {
686      _eglError(EGL_BAD_ALLOC, "eglCreateContext");
687      return NULL;
688   }
689
690   if (!_eglInitContext(&GLX_ctx->Base, disp, conf, attrib_list)) {
691      free(GLX_ctx);
692      return NULL;
693   }
694
695   if (GLX_dpy->have_fbconfig) {
696      GLX_ctx->context = GLX_drv->glXCreateNewContext(GLX_dpy->dpy,
697            GLX_dpy->fbconfigs[GLX_egl_config_index(conf)],
698            GLX_RGBA_TYPE,
699            GLX_ctx_shared ? GLX_ctx_shared->context : NULL,
700            GL_TRUE);
701   }
702   else {
703      GLX_ctx->context = GLX_drv->glXCreateContext(GLX_dpy->dpy,
704            &GLX_dpy->visuals[GLX_egl_config_index(conf)],
705            GLX_ctx_shared ? GLX_ctx_shared->context : NULL,
706            GL_TRUE);
707   }
708   if (!GLX_ctx->context) {
709      free(GLX_ctx);
710      return NULL;
711   }
712
713   return &GLX_ctx->Base;
714}
715
716/**
717 * Called via eglDestroyContext(), drv->API.DestroyContext().
718 */
719static EGLBoolean
720GLX_eglDestroyContext(_EGLDriver *drv, _EGLDisplay *disp, _EGLContext *ctx)
721{
722   struct GLX_egl_driver *GLX_drv = GLX_egl_driver(drv);
723   struct GLX_egl_display *GLX_dpy = GLX_egl_display(disp);
724   struct GLX_egl_context *GLX_ctx = GLX_egl_context(ctx);
725
726   if (_eglPutContext(ctx)) {
727      assert(GLX_ctx);
728      GLX_drv->glXDestroyContext(GLX_dpy->dpy, GLX_ctx->context);
729
730      free(GLX_ctx);
731   }
732
733   return EGL_TRUE;
734}
735
736/**
737 * Destroy a surface.  The display is allowed to be uninitialized.
738 */
739static void
740destroy_surface(_EGLDisplay *disp, _EGLSurface *surf)
741{
742   struct GLX_egl_display *GLX_dpy = GLX_egl_display(disp);
743   struct GLX_egl_surface *GLX_surf = GLX_egl_surface(surf);
744
745   if (GLX_surf->destroy)
746      GLX_surf->destroy(GLX_dpy->dpy, GLX_surf->glx_drawable);
747
748   free(GLX_surf);
749}
750
751
752/**
753 * Called via eglMakeCurrent(), drv->API.MakeCurrent().
754 */
755static EGLBoolean
756GLX_eglMakeCurrent(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *dsurf,
757                   _EGLSurface *rsurf, _EGLContext *ctx)
758{
759   struct GLX_egl_driver *GLX_drv = GLX_egl_driver(drv);
760   struct GLX_egl_display *GLX_dpy = GLX_egl_display(disp);
761   struct GLX_egl_surface *GLX_dsurf = GLX_egl_surface(dsurf);
762   struct GLX_egl_surface *GLX_rsurf = GLX_egl_surface(rsurf);
763   struct GLX_egl_context *GLX_ctx = GLX_egl_context(ctx);
764   _EGLContext *old_ctx;
765   _EGLSurface *old_dsurf, *old_rsurf;
766   GLXDrawable ddraw, rdraw;
767   GLXContext cctx;
768   EGLBoolean ret = EGL_FALSE;
769
770   /* make new bindings */
771   if (!_eglBindContext(ctx, dsurf, rsurf, &old_ctx, &old_dsurf, &old_rsurf))
772      return EGL_FALSE;
773
774   ddraw = (GLX_dsurf) ? GLX_dsurf->glx_drawable : None;
775   rdraw = (GLX_rsurf) ? GLX_rsurf->glx_drawable : None;
776   cctx = (GLX_ctx) ? GLX_ctx->context : NULL;
777
778   if (GLX_dpy->have_make_current_read)
779      ret = GLX_drv->glXMakeContextCurrent(GLX_dpy->dpy, ddraw, rdraw, cctx);
780   else if (ddraw == rdraw)
781      ret = GLX_drv->glXMakeCurrent(GLX_dpy->dpy, ddraw, cctx);
782
783   if (ret) {
784      if (_eglPutSurface(old_dsurf))
785         destroy_surface(disp, old_dsurf);
786      if (_eglPutSurface(old_rsurf))
787         destroy_surface(disp, old_rsurf);
788      /* no destroy? */
789      _eglPutContext(old_ctx);
790   }
791   else {
792      /* undo the previous _eglBindContext */
793      _eglBindContext(old_ctx, old_dsurf, old_rsurf, &ctx, &dsurf, &rsurf);
794      assert(&GLX_ctx->Base == ctx &&
795             &GLX_dsurf->Base == dsurf &&
796             &GLX_rsurf->Base == rsurf);
797
798      _eglPutSurface(dsurf);
799      _eglPutSurface(rsurf);
800      _eglPutContext(ctx);
801
802      _eglPutSurface(old_dsurf);
803      _eglPutSurface(old_rsurf);
804      _eglPutContext(old_ctx);
805   }
806
807   return ret;
808}
809
810/** Get size of given window */
811static Status
812get_drawable_size(Display *dpy, Drawable d, unsigned *width, unsigned *height)
813{
814   Window root;
815   Status stat;
816   int xpos, ypos;
817   unsigned int w, h, bw, depth;
818   stat = XGetGeometry(dpy, d, &root, &xpos, &ypos, &w, &h, &bw, &depth);
819   *width = w;
820   *height = h;
821   return stat;
822}
823
824/**
825 * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
826 */
827static _EGLSurface *
828GLX_eglCreateWindowSurface(_EGLDriver *drv, _EGLDisplay *disp,
829                           _EGLConfig *conf, EGLNativeWindowType window,
830                           const EGLint *attrib_list)
831{
832   struct GLX_egl_driver *GLX_drv = GLX_egl_driver(drv);
833   struct GLX_egl_display *GLX_dpy = GLX_egl_display(disp);
834   struct GLX_egl_surface *GLX_surf;
835   unsigned width, height;
836
837   GLX_surf = CALLOC_STRUCT(GLX_egl_surface);
838   if (!GLX_surf) {
839      _eglError(EGL_BAD_ALLOC, "eglCreateWindowSurface");
840      return NULL;
841   }
842
843   if (!_eglInitSurface(&GLX_surf->Base, disp, EGL_WINDOW_BIT,
844                        conf, attrib_list)) {
845      free(GLX_surf);
846      return NULL;
847   }
848
849   GLX_surf->drawable = window;
850
851   if (GLX_dpy->have_1_3 && !GLX_dpy->glx_window_quirk) {
852      GLX_surf->glx_drawable = GLX_drv->glXCreateWindow(GLX_dpy->dpy,
853            GLX_dpy->fbconfigs[GLX_egl_config_index(conf)],
854            GLX_surf->drawable, NULL);
855   }
856   else {
857      GLX_surf->glx_drawable = GLX_surf->drawable;
858   }
859
860   if (!GLX_surf->glx_drawable) {
861      free(GLX_surf);
862      return NULL;
863   }
864
865   if (GLX_dpy->have_1_3 && !GLX_dpy->glx_window_quirk)
866      GLX_surf->destroy = GLX_drv->glXDestroyWindow;
867
868   get_drawable_size(GLX_dpy->dpy, window, &width, &height);
869   GLX_surf->Base.Width = width;
870   GLX_surf->Base.Height = height;
871
872   return &GLX_surf->Base;
873}
874
875static _EGLSurface *
876GLX_eglCreatePixmapSurface(_EGLDriver *drv, _EGLDisplay *disp,
877                           _EGLConfig *conf, EGLNativePixmapType pixmap,
878                           const EGLint *attrib_list)
879{
880   struct GLX_egl_driver *GLX_drv = GLX_egl_driver(drv);
881   struct GLX_egl_display *GLX_dpy = GLX_egl_display(disp);
882   struct GLX_egl_surface *GLX_surf;
883   unsigned width, height;
884
885   GLX_surf = CALLOC_STRUCT(GLX_egl_surface);
886   if (!GLX_surf) {
887      _eglError(EGL_BAD_ALLOC, "eglCreatePixmapSurface");
888      return NULL;
889   }
890
891   if (!_eglInitSurface(&GLX_surf->Base, disp, EGL_PIXMAP_BIT,
892                        conf, attrib_list)) {
893      free(GLX_surf);
894      return NULL;
895   }
896
897   GLX_surf->drawable = pixmap;
898
899   if (GLX_dpy->have_1_3) {
900      GLX_surf->glx_drawable = GLX_drv->glXCreatePixmap(GLX_dpy->dpy,
901            GLX_dpy->fbconfigs[GLX_egl_config_index(conf)],
902            GLX_surf->drawable, NULL);
903   }
904   else if (GLX_dpy->have_fbconfig) {
905      GLXFBConfig fbconfig = GLX_dpy->fbconfigs[GLX_egl_config_index(conf)];
906      XVisualInfo *vinfo;
907
908      vinfo = GLX_drv->glXGetVisualFromFBConfig(GLX_dpy->dpy, fbconfig);
909      if (vinfo) {
910         GLX_surf->glx_drawable = GLX_drv->glXCreateGLXPixmap(GLX_dpy->dpy,
911               vinfo, GLX_surf->drawable);
912         XFree(vinfo);
913      }
914   }
915   else {
916      GLX_surf->glx_drawable = GLX_drv->glXCreateGLXPixmap(GLX_dpy->dpy,
917            &GLX_dpy->visuals[GLX_egl_config_index(conf)],
918            GLX_surf->drawable);
919   }
920
921   if (!GLX_surf->glx_drawable) {
922      free(GLX_surf);
923      return NULL;
924   }
925
926   GLX_surf->destroy = (GLX_dpy->have_1_3) ?
927      GLX_drv->glXDestroyPixmap : GLX_drv->glXDestroyGLXPixmap;
928
929   get_drawable_size(GLX_dpy->dpy, pixmap, &width, &height);
930   GLX_surf->Base.Width = width;
931   GLX_surf->Base.Height = height;
932
933   return &GLX_surf->Base;
934}
935
936static _EGLSurface *
937GLX_eglCreatePbufferSurface(_EGLDriver *drv, _EGLDisplay *disp,
938                            _EGLConfig *conf, const EGLint *attrib_list)
939{
940   struct GLX_egl_driver *GLX_drv = GLX_egl_driver(drv);
941   struct GLX_egl_display *GLX_dpy = GLX_egl_display(disp);
942   struct GLX_egl_surface *GLX_surf;
943   int attribs[5];
944   int i;
945
946   GLX_surf = CALLOC_STRUCT(GLX_egl_surface);
947   if (!GLX_surf) {
948      _eglError(EGL_BAD_ALLOC, "eglCreatePbufferSurface");
949      return NULL;
950   }
951
952   if (!_eglInitSurface(&GLX_surf->Base, disp, EGL_PBUFFER_BIT,
953                        conf, attrib_list)) {
954      free(GLX_surf);
955      return NULL;
956   }
957
958   i = 0;
959   attribs[i] = None;
960
961   GLX_surf->drawable = None;
962
963   if (GLX_dpy->have_1_3) {
964      /* put geometry in attribs */
965      if (GLX_surf->Base.Width) {
966         attribs[i++] = GLX_PBUFFER_WIDTH;
967         attribs[i++] = GLX_surf->Base.Width;
968      }
969      if (GLX_surf->Base.Height) {
970         attribs[i++] = GLX_PBUFFER_HEIGHT;
971         attribs[i++] = GLX_surf->Base.Height;
972      }
973      attribs[i] = None;
974
975      GLX_surf->glx_drawable = GLX_drv->glXCreatePbuffer(GLX_dpy->dpy,
976            GLX_dpy->fbconfigs[GLX_egl_config_index(conf)], attribs);
977   }
978   else if (GLX_dpy->have_pbuffer) {
979      GLX_surf->glx_drawable = GLX_drv->glXCreateGLXPbufferSGIX(GLX_dpy->dpy,
980            GLX_dpy->fbconfigs[GLX_egl_config_index(conf)],
981            GLX_surf->Base.Width,
982            GLX_surf->Base.Height,
983            attribs);
984   }
985
986   if (!GLX_surf->glx_drawable) {
987      free(GLX_surf);
988      return NULL;
989   }
990
991   GLX_surf->destroy = (GLX_dpy->have_1_3) ?
992      GLX_drv->glXDestroyPbuffer : GLX_drv->glXDestroyGLXPbufferSGIX;
993
994   return &GLX_surf->Base;
995}
996
997
998static EGLBoolean
999GLX_eglDestroySurface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
1000{
1001   (void) drv;
1002
1003   if (_eglPutSurface(surf))
1004      destroy_surface(disp, surf);
1005
1006   return EGL_TRUE;
1007}
1008
1009
1010static EGLBoolean
1011GLX_eglSwapBuffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
1012{
1013   struct GLX_egl_driver *GLX_drv = GLX_egl_driver(drv);
1014   struct GLX_egl_display *GLX_dpy = GLX_egl_display(disp);
1015   struct GLX_egl_surface *GLX_surf = GLX_egl_surface(draw);
1016
1017   GLX_drv->glXSwapBuffers(GLX_dpy->dpy, GLX_surf->glx_drawable);
1018
1019   return EGL_TRUE;
1020}
1021
1022/*
1023 * Called from eglGetProcAddress() via drv->API.GetProcAddress().
1024 */
1025static _EGLProc
1026GLX_eglGetProcAddress(_EGLDriver *drv, const char *procname)
1027{
1028   struct GLX_egl_driver *GLX_drv = GLX_egl_driver(drv);
1029
1030   return (_EGLProc) GLX_drv->glXGetProcAddress((const GLubyte *) procname);
1031}
1032
1033static EGLBoolean
1034GLX_eglWaitClient(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx)
1035{
1036   struct GLX_egl_driver *GLX_drv = GLX_egl_driver(drv);
1037
1038   (void) dpy;
1039   (void) ctx;
1040
1041   GLX_drv->glXWaitGL();
1042   return EGL_TRUE;
1043}
1044
1045static EGLBoolean
1046GLX_eglWaitNative(_EGLDriver *drv, _EGLDisplay *dpy, EGLint engine)
1047{
1048   struct GLX_egl_driver *GLX_drv = GLX_egl_driver(drv);
1049
1050   (void) dpy;
1051
1052   if (engine != EGL_CORE_NATIVE_ENGINE)
1053      return _eglError(EGL_BAD_PARAMETER, "eglWaitNative");
1054   GLX_drv->glXWaitX();
1055   return EGL_TRUE;
1056}
1057
1058static void
1059GLX_Unload(_EGLDriver *drv)
1060{
1061   struct GLX_egl_driver *GLX_drv = GLX_egl_driver(drv);
1062
1063   if (GLX_drv->handle)
1064      dlclose(GLX_drv->handle);
1065   free(GLX_drv);
1066}
1067
1068
1069static EGLBoolean
1070GLX_Load(_EGLDriver *drv)
1071{
1072   struct GLX_egl_driver *GLX_drv = GLX_egl_driver(drv);
1073   void *handle = NULL;
1074
1075   GLX_drv->glXGetProcAddress = dlsym(RTLD_DEFAULT, "glXGetProcAddress");
1076   if (!GLX_drv->glXGetProcAddress)
1077      GLX_drv->glXGetProcAddress = dlsym(RTLD_DEFAULT, "glXGetProcAddressARB");
1078   if (!GLX_drv->glXGetProcAddress) {
1079      handle = dlopen("libGL.so", RTLD_LAZY | RTLD_LOCAL);
1080      if (!handle)
1081         goto fail;
1082
1083      GLX_drv->glXGetProcAddress = dlsym(handle, "glXGetProcAddress");
1084      if (!GLX_drv->glXGetProcAddress)
1085         GLX_drv->glXGetProcAddress = dlsym(handle, "glXGetProcAddressARB");
1086      if (!GLX_drv->glXGetProcAddress)
1087         goto fail;
1088   }
1089
1090#define GET_PROC(proc_type, proc_name, check)                        \
1091   do {                                                              \
1092      GLX_drv->proc_name = (proc_type)                               \
1093         GLX_drv->glXGetProcAddress((const GLubyte *) #proc_name);   \
1094      if (check && !GLX_drv->proc_name) goto fail;                   \
1095   } while (0)
1096
1097   /* GLX 1.0 */
1098   GET_PROC(GLXCREATECONTEXTPROC, glXCreateContext, EGL_TRUE);
1099   GET_PROC(GLXDESTROYCONTEXTPROC, glXDestroyContext, EGL_TRUE);
1100   GET_PROC(GLXMAKECURRENTPROC, glXMakeCurrent, EGL_TRUE);
1101   GET_PROC(GLXSWAPBUFFERSPROC, glXSwapBuffers, EGL_TRUE);
1102   GET_PROC(GLXCREATEGLXPIXMAPPROC, glXCreateGLXPixmap, EGL_TRUE);
1103   GET_PROC(GLXDESTROYGLXPIXMAPPROC, glXDestroyGLXPixmap, EGL_TRUE);
1104   GET_PROC(GLXQUERYVERSIONPROC, glXQueryVersion, EGL_TRUE);
1105   GET_PROC(GLXGETCONFIGPROC, glXGetConfig, EGL_TRUE);
1106   GET_PROC(GLXWAITGLPROC, glXWaitGL, EGL_TRUE);
1107   GET_PROC(GLXWAITXPROC, glXWaitX, EGL_TRUE);
1108
1109   /* GLX 1.1 */
1110   GET_PROC(GLXQUERYEXTENSIONSSTRINGPROC, glXQueryExtensionsString, EGL_TRUE);
1111   GET_PROC(GLXQUERYSERVERSTRINGPROC, glXQueryServerString, EGL_TRUE);
1112   GET_PROC(GLXGETCLIENTSTRINGPROC, glXGetClientString, EGL_TRUE);
1113
1114   /* GLX 1.3 */
1115   GET_PROC(PFNGLXGETFBCONFIGSPROC, glXGetFBConfigs, EGL_FALSE);
1116   GET_PROC(PFNGLXGETFBCONFIGATTRIBPROC, glXGetFBConfigAttrib, EGL_FALSE);
1117   GET_PROC(PFNGLXGETVISUALFROMFBCONFIGPROC, glXGetVisualFromFBConfig, EGL_FALSE);
1118   GET_PROC(PFNGLXCREATEWINDOWPROC, glXCreateWindow, EGL_FALSE);
1119   GET_PROC(PFNGLXDESTROYWINDOWPROC, glXDestroyWindow, EGL_FALSE);
1120   GET_PROC(PFNGLXCREATEPIXMAPPROC, glXCreatePixmap, EGL_FALSE);
1121   GET_PROC(PFNGLXDESTROYPIXMAPPROC, glXDestroyPixmap, EGL_FALSE);
1122   GET_PROC(PFNGLXCREATEPBUFFERPROC, glXCreatePbuffer, EGL_FALSE);
1123   GET_PROC(PFNGLXDESTROYPBUFFERPROC, glXDestroyPbuffer, EGL_FALSE);
1124   GET_PROC(PFNGLXCREATENEWCONTEXTPROC, glXCreateNewContext, EGL_FALSE);
1125   GET_PROC(PFNGLXMAKECONTEXTCURRENTPROC, glXMakeContextCurrent, EGL_FALSE);
1126
1127   /* GLX_SGIX_pbuffer */
1128   GET_PROC(PFNGLXCREATEGLXPBUFFERSGIXPROC,
1129         glXCreateGLXPbufferSGIX, EGL_FALSE);
1130   GET_PROC(PFNGLXDESTROYGLXPBUFFERSGIXPROC,
1131         glXDestroyGLXPbufferSGIX, EGL_FALSE);
1132#undef GET_PROC
1133
1134   GLX_drv->handle = handle;
1135
1136   return EGL_TRUE;
1137
1138fail:
1139   if (handle)
1140      dlclose(handle);
1141   return EGL_FALSE;
1142}
1143
1144
1145/**
1146 * This is the main entrypoint into the driver, called by libEGL.
1147 * Create a new _EGLDriver object and init its dispatch table.
1148 */
1149_EGLDriver *
1150_eglBuiltInDriverGLX(const char *args)
1151{
1152   struct GLX_egl_driver *GLX_drv = CALLOC_STRUCT(GLX_egl_driver);
1153
1154   (void) args;
1155
1156   if (!GLX_drv)
1157      return NULL;
1158
1159   if (!GLX_Load(&GLX_drv->Base)) {
1160      _eglLog(_EGL_WARNING, "GLX: failed to load GLX");
1161      free(GLX_drv);
1162      return NULL;
1163   }
1164
1165   _eglInitDriverFallbacks(&GLX_drv->Base);
1166   GLX_drv->Base.API.Initialize = GLX_eglInitialize;
1167   GLX_drv->Base.API.Terminate = GLX_eglTerminate;
1168   GLX_drv->Base.API.CreateContext = GLX_eglCreateContext;
1169   GLX_drv->Base.API.DestroyContext = GLX_eglDestroyContext;
1170   GLX_drv->Base.API.MakeCurrent = GLX_eglMakeCurrent;
1171   GLX_drv->Base.API.CreateWindowSurface = GLX_eglCreateWindowSurface;
1172   GLX_drv->Base.API.CreatePixmapSurface = GLX_eglCreatePixmapSurface;
1173   GLX_drv->Base.API.CreatePbufferSurface = GLX_eglCreatePbufferSurface;
1174   GLX_drv->Base.API.DestroySurface = GLX_eglDestroySurface;
1175   GLX_drv->Base.API.SwapBuffers = GLX_eglSwapBuffers;
1176   GLX_drv->Base.API.GetProcAddress = GLX_eglGetProcAddress;
1177   GLX_drv->Base.API.WaitClient = GLX_eglWaitClient;
1178   GLX_drv->Base.API.WaitNative = GLX_eglWaitNative;
1179
1180   GLX_drv->Base.Name = "GLX";
1181   GLX_drv->Base.Unload = GLX_Unload;
1182
1183   return &GLX_drv->Base;
1184}
1185