egl_glx.c revision 78c3a351bc91eed49a07108682013a323d87540e
1/**************************************************************************
2 *
3 * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28
29/**
30 * This is an EGL driver that wraps GLX. This gives the benefit of being
31 * completely agnostic of the direct rendering implementation.
32 *
33 * Authors: Alan Hourihane <alanh@tungstengraphics.com>
34 */
35
36/*
37 * TODO:
38 *
39 * test eglBind/ReleaseTexImage
40 */
41
42
43#include <stdlib.h>
44#include <string.h>
45#include <X11/Xlib.h>
46#include <dlfcn.h>
47
48#include "glxclient.h"
49
50#include "eglconfigutil.h"
51#include "eglconfig.h"
52#include "eglcontext.h"
53#include "egldisplay.h"
54#include "egldriver.h"
55#include "eglglobals.h"
56#include "egllog.h"
57#include "eglsurface.h"
58
59#define CALLOC_STRUCT(T)   (struct T *) calloc(1, sizeof(struct T))
60#define ARRAY_SIZE(a)      (sizeof(a) / sizeof(a[0]))
61
62#ifndef GLX_VERSION_1_4
63#error "GL/glx.h must be equal to or greater than GLX 1.4"
64#endif
65
66/*
67 * report OpenGL ES bits because apps usually forget to specify
68 * EGL_RENDERABLE_TYPE when choosing configs
69 */
70#define GLX_EGL_APIS (EGL_OPENGL_BIT | EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT)
71
72
73/** subclass of _EGLDriver */
74struct GLX_egl_driver
75{
76   _EGLDriver Base;   /**< base class */
77};
78
79
80/** driver data of _EGLDisplay */
81struct GLX_egl_display
82{
83   Display *dpy;
84   XVisualInfo *visuals;
85   GLXFBConfig *fbconfigs;
86
87   int glx_maj, glx_min;
88
89   const char *extensions;
90   EGLBoolean have_1_3;
91   EGLBoolean have_make_current_read;
92   EGLBoolean have_fbconfig;
93   EGLBoolean have_pbuffer;
94
95   /* GLX_SGIX_pbuffer */
96   PFNGLXCREATEGLXPBUFFERSGIXPROC glXCreateGLXPbufferSGIX;
97   PFNGLXDESTROYGLXPBUFFERSGIXPROC glXDestroyGLXPbufferSGIX;
98
99   /* workaround quirks of different GLX implementations */
100   EGLBoolean single_buffered_quirk;
101   EGLBoolean glx_window_quirk;
102
103};
104
105
106/** subclass of _EGLContext */
107struct GLX_egl_context
108{
109   _EGLContext Base;   /**< base class */
110
111   GLXContext context;
112};
113
114
115/** subclass of _EGLSurface */
116struct GLX_egl_surface
117{
118   _EGLSurface Base;   /**< base class */
119
120   GLXDrawable drawable;
121};
122
123
124/** subclass of _EGLConfig */
125struct GLX_egl_config
126{
127   _EGLConfig Base;   /**< base class */
128   EGLBoolean double_buffered;
129   int index;
130};
131
132/** cast wrapper */
133static struct GLX_egl_driver *
134GLX_egl_driver(_EGLDriver *drv)
135{
136   return (struct GLX_egl_driver *) drv;
137}
138
139static struct GLX_egl_display *
140GLX_egl_display(_EGLDisplay *dpy)
141{
142   return (struct GLX_egl_display *) dpy->DriverData;
143}
144
145static struct GLX_egl_context *
146GLX_egl_context(_EGLContext *ctx)
147{
148   return (struct GLX_egl_context *) ctx;
149}
150
151static struct GLX_egl_surface *
152GLX_egl_surface(_EGLSurface *surf)
153{
154   return (struct GLX_egl_surface *) surf;
155}
156
157static int
158GLX_egl_config_index(_EGLConfig *conf)
159{
160   return ((struct GLX_egl_config *) conf)->index;
161}
162
163
164#define MAP_ATTRIB(attr, memb) \
165   { attr, offsetof(__GLcontextModes, memb) }
166
167
168static const struct {
169   int attr;
170   int offset;
171} fbconfig_attributes[] = {
172   /* table 3.1 of GLX 1.4 */
173   MAP_ATTRIB(GLX_FBCONFIG_ID,                  fbconfigID),
174   MAP_ATTRIB(GLX_BUFFER_SIZE,                  rgbBits),
175   MAP_ATTRIB(GLX_LEVEL,                        level),
176   MAP_ATTRIB(GLX_DOUBLEBUFFER,                 doubleBufferMode),
177   MAP_ATTRIB(GLX_STEREO,                       stereoMode),
178   MAP_ATTRIB(GLX_AUX_BUFFERS,                  numAuxBuffers),
179   MAP_ATTRIB(GLX_RED_SIZE,                     redBits),
180   MAP_ATTRIB(GLX_GREEN_SIZE,                   greenBits),
181   MAP_ATTRIB(GLX_BLUE_SIZE,                    blueBits),
182   MAP_ATTRIB(GLX_ALPHA_SIZE,                   alphaBits),
183   MAP_ATTRIB(GLX_DEPTH_SIZE,                   depthBits),
184   MAP_ATTRIB(GLX_STENCIL_SIZE,                 stencilBits),
185   MAP_ATTRIB(GLX_ACCUM_RED_SIZE,               accumRedBits),
186   MAP_ATTRIB(GLX_ACCUM_GREEN_SIZE,             accumGreenBits),
187   MAP_ATTRIB(GLX_ACCUM_BLUE_SIZE,              accumBlueBits),
188   MAP_ATTRIB(GLX_ACCUM_ALPHA_SIZE,             accumAlphaBits),
189   MAP_ATTRIB(GLX_SAMPLE_BUFFERS,               sampleBuffers),
190   MAP_ATTRIB(GLX_SAMPLES,                      samples),
191   MAP_ATTRIB(GLX_RENDER_TYPE,                  renderType),
192   MAP_ATTRIB(GLX_DRAWABLE_TYPE,                drawableType),
193   MAP_ATTRIB(GLX_X_RENDERABLE,                 xRenderable),
194   MAP_ATTRIB(GLX_X_VISUAL_TYPE,                visualType),
195   MAP_ATTRIB(GLX_CONFIG_CAVEAT,                visualRating),
196   MAP_ATTRIB(GLX_TRANSPARENT_TYPE,             transparentPixel),
197   MAP_ATTRIB(GLX_TRANSPARENT_INDEX_VALUE,      transparentIndex),
198   MAP_ATTRIB(GLX_TRANSPARENT_RED_VALUE,        transparentRed),
199   MAP_ATTRIB(GLX_TRANSPARENT_GREEN_VALUE,      transparentGreen),
200   MAP_ATTRIB(GLX_TRANSPARENT_BLUE_VALUE,       transparentBlue),
201   MAP_ATTRIB(GLX_TRANSPARENT_ALPHA_VALUE,      transparentAlpha),
202   MAP_ATTRIB(GLX_MAX_PBUFFER_WIDTH,            maxPbufferWidth),
203   MAP_ATTRIB(GLX_MAX_PBUFFER_HEIGHT,           maxPbufferHeight),
204   MAP_ATTRIB(GLX_MAX_PBUFFER_PIXELS,           maxPbufferPixels),
205   MAP_ATTRIB(GLX_VISUAL_ID,                    visualID),
206};
207
208
209static EGLBoolean
210convert_fbconfig(Display *dpy, GLXFBConfig fbconfig,
211                 struct GLX_egl_config *GLX_conf)
212{
213   __GLcontextModes mode;
214   int err = 0, attr, val, i;
215
216   memset(&mode, 0, sizeof(mode));
217
218   for (i = 0; i < ARRAY_SIZE(fbconfig_attributes); i++) {
219      int offset = fbconfig_attributes[i].offset;
220      attr = fbconfig_attributes[i].attr;
221      err = glXGetFBConfigAttrib(dpy, fbconfig, attr, &val);
222      if (err) {
223         if (err == GLX_BAD_ATTRIBUTE) {
224            err = 0;
225            continue;
226         }
227         break;
228      }
229      *((int *) ((char *) &mode + offset)) = val;
230   }
231   if (err)
232      return EGL_FALSE;
233
234   /* must have rgba bit */
235   if (!(mode.renderType & GLX_RGBA_BIT))
236      return EGL_FALSE;
237
238   /* pixmap and pbuffer surfaces must be single-buffered in EGL */
239   if (mode.doubleBufferMode) {
240      mode.drawableType &= ~(GLX_PIXMAP_BIT | GLX_PBUFFER_BIT);
241      if (!mode.drawableType)
242         return EGL_FALSE;
243   }
244
245   mode.rgbMode = GL_TRUE;
246   mode.haveAccumBuffer = (mode.accumRedBits +
247                           mode.accumGreenBits +
248                           mode.accumBlueBits +
249                           mode.accumAlphaBits > 0);
250   mode.haveDepthBuffer = (mode.depthBits > 0);
251   mode.haveStencilBuffer = (mode.stencilBits > 0);
252
253   GLX_conf->double_buffered = (mode.doubleBufferMode != 0);
254   return _eglConfigFromContextModesRec(&GLX_conf->Base, &mode,
255                                        GLX_EGL_APIS, GLX_EGL_APIS);
256}
257
258
259static const struct {
260   int attr;
261   int offset;
262} visual_attributes[] = {
263   /* table 3.7 of GLX 1.4 */
264   /* no GLX_USE_GL */
265   MAP_ATTRIB(GLX_BUFFER_SIZE,         rgbBits),
266   MAP_ATTRIB(GLX_LEVEL,               level),
267   MAP_ATTRIB(GLX_RGBA,                rgbMode),
268   MAP_ATTRIB(GLX_DOUBLEBUFFER,        doubleBufferMode),
269   MAP_ATTRIB(GLX_STEREO,              stereoMode),
270   MAP_ATTRIB(GLX_AUX_BUFFERS,         numAuxBuffers),
271   MAP_ATTRIB(GLX_RED_SIZE,            redBits),
272   MAP_ATTRIB(GLX_GREEN_SIZE,          greenBits),
273   MAP_ATTRIB(GLX_BLUE_SIZE,           blueBits),
274   MAP_ATTRIB(GLX_ALPHA_SIZE,          alphaBits),
275   MAP_ATTRIB(GLX_DEPTH_SIZE,          depthBits),
276   MAP_ATTRIB(GLX_STENCIL_SIZE,        stencilBits),
277   MAP_ATTRIB(GLX_ACCUM_RED_SIZE,      accumRedBits),
278   MAP_ATTRIB(GLX_ACCUM_GREEN_SIZE,    accumGreenBits),
279   MAP_ATTRIB(GLX_ACCUM_BLUE_SIZE,     accumBlueBits),
280   MAP_ATTRIB(GLX_ACCUM_ALPHA_SIZE,    accumAlphaBits),
281   MAP_ATTRIB(GLX_SAMPLE_BUFFERS,      sampleBuffers),
282   MAP_ATTRIB(GLX_SAMPLES,             samples),
283   MAP_ATTRIB(GLX_FBCONFIG_ID,         fbconfigID),
284   /* GLX_EXT_visual_rating */
285   MAP_ATTRIB(GLX_VISUAL_CAVEAT_EXT,   visualRating),
286};
287
288
289static int
290get_visual_type(const XVisualInfo *vis)
291{
292   int klass;
293
294#if defined(__cplusplus) || defined(c_plusplus)
295   klass = vis->c_class;
296#else
297   klass = vis->class;
298#endif
299
300   switch (klass) {
301   case TrueColor:
302      return GLX_TRUE_COLOR;
303   case DirectColor:
304      return GLX_DIRECT_COLOR;
305   case PseudoColor:
306      return GLX_PSEUDO_COLOR;
307   case StaticColor:
308      return GLX_STATIC_COLOR;
309   case GrayScale:
310      return GLX_GRAY_SCALE;
311   case StaticGray:
312      return GLX_STATIC_GRAY;
313   default:
314      return GLX_NONE;
315   }
316}
317
318
319static EGLBoolean
320convert_visual(Display *dpy, XVisualInfo *vinfo,
321               struct GLX_egl_config *GLX_conf)
322{
323   __GLcontextModes mode;
324   int err, attr, val, i;
325
326   /* the visual must support OpenGL */
327   err = glXGetConfig(dpy, vinfo, GLX_USE_GL, &val);
328   if (err || !val)
329      return EGL_FALSE;
330
331   memset(&mode, 0, sizeof(mode));
332
333   for (i = 0; i < ARRAY_SIZE(visual_attributes); i++) {
334      int offset = visual_attributes[i].offset;
335      attr = visual_attributes[i].attr;
336      err = glXGetConfig(dpy, vinfo, attr, &val);
337      if (err) {
338         if (err == GLX_BAD_ATTRIBUTE) {
339            err = 0;
340            continue;
341         }
342         break;
343      }
344      *((int *) ((char *) &mode + offset)) = val;
345   }
346   if (err)
347      return EGL_FALSE;
348
349   /* must be RGB mode */
350   if (!mode.rgbMode)
351      return EGL_FALSE;
352
353   mode.visualID = vinfo->visualid;
354   mode.visualType = get_visual_type(vinfo);
355   mode.redMask = vinfo->red_mask;
356   mode.greenMask = vinfo->green_mask;
357   mode.blueMask = vinfo->blue_mask;
358
359   mode.drawableType = GLX_WINDOW_BIT;
360   /* pixmap surfaces must be single-buffered in EGL */
361   if (!mode.doubleBufferMode)
362      mode.drawableType |= GLX_PIXMAP_BIT;
363
364   mode.renderType = GLX_RGBA_BIT;
365   mode.xRenderable = GL_TRUE;
366   mode.haveAccumBuffer = (mode.accumRedBits +
367                           mode.accumGreenBits +
368                           mode.accumBlueBits +
369                           mode.accumAlphaBits > 0);
370   mode.haveDepthBuffer = (mode.depthBits > 0);
371   mode.haveStencilBuffer = (mode.stencilBits > 0);
372
373   GLX_conf->double_buffered = (mode.doubleBufferMode != 0);
374   return _eglConfigFromContextModesRec(&GLX_conf->Base, &mode,
375                                        GLX_EGL_APIS, GLX_EGL_APIS);
376}
377
378
379static void
380fix_config(struct GLX_egl_display *GLX_dpy, struct GLX_egl_config *GLX_conf)
381{
382   _EGLConfig *conf = &GLX_conf->Base;
383   EGLint surface_type, r, g, b, a;
384
385   surface_type = GET_CONFIG_ATTRIB(conf, EGL_SURFACE_TYPE);
386   if (!GLX_conf->double_buffered && GLX_dpy->single_buffered_quirk) {
387      /* some GLX impls do not like single-buffered window surface */
388      surface_type &= ~EGL_WINDOW_BIT;
389      /* pbuffer bit is usually not set */
390      if (GLX_dpy->have_pbuffer)
391         surface_type |= EGL_PBUFFER_BIT;
392      SET_CONFIG_ATTRIB(conf, EGL_SURFACE_TYPE, surface_type);
393   }
394
395   /* no visual attribs unless window bit is set */
396   if (!(surface_type & EGL_WINDOW_BIT)) {
397      SET_CONFIG_ATTRIB(conf, EGL_NATIVE_VISUAL_ID, 0);
398      SET_CONFIG_ATTRIB(conf, EGL_NATIVE_VISUAL_TYPE, EGL_NONE);
399   }
400
401   /* make sure buffer size is set correctly */
402   r = GET_CONFIG_ATTRIB(conf, EGL_RED_SIZE);
403   g = GET_CONFIG_ATTRIB(conf, EGL_GREEN_SIZE);
404   b = GET_CONFIG_ATTRIB(conf, EGL_BLUE_SIZE);
405   a = GET_CONFIG_ATTRIB(conf, EGL_ALPHA_SIZE);
406   SET_CONFIG_ATTRIB(conf, EGL_BUFFER_SIZE, r + g + b + a);
407}
408
409
410static EGLBoolean
411create_configs(_EGLDisplay *dpy, struct GLX_egl_display *GLX_dpy,
412               EGLint screen)
413{
414   EGLint num_configs = 0, i;
415   EGLint id = 1;
416
417   if (GLX_dpy->have_fbconfig) {
418      GLX_dpy->fbconfigs = glXGetFBConfigs(GLX_dpy->dpy, screen, &num_configs);
419   }
420   else {
421      XVisualInfo vinfo_template;
422      long mask;
423
424      vinfo_template.screen = screen;
425      mask = VisualScreenMask;
426      GLX_dpy->visuals = XGetVisualInfo(GLX_dpy->dpy, mask, &vinfo_template,
427                                        &num_configs);
428   }
429
430   if (!num_configs)
431      return EGL_FALSE;
432
433   for (i = 0; i < num_configs; i++) {
434      struct GLX_egl_config *GLX_conf, template;
435      EGLBoolean ok;
436
437      memset(&template, 0, sizeof(template));
438      _eglInitConfig(&template.Base, id);
439      if (GLX_dpy->have_fbconfig)
440         ok = convert_fbconfig(GLX_dpy->dpy, GLX_dpy->fbconfigs[i], &template);
441      else
442         ok = convert_visual(GLX_dpy->dpy, &GLX_dpy->visuals[i], &template);
443      if (!ok)
444        continue;
445
446      fix_config(GLX_dpy, &template);
447      if (!_eglValidateConfig(&template.Base, EGL_FALSE)) {
448         _eglLog(_EGL_DEBUG, "GLX: failed to validate config %d", i);
449         continue;
450      }
451
452      GLX_conf = CALLOC_STRUCT(GLX_egl_config);
453      if (GLX_conf) {
454         memcpy(GLX_conf, &template, sizeof(template));
455         GLX_conf->index = i;
456
457         _eglAddConfig(dpy, &GLX_conf->Base);
458         id++;
459      }
460   }
461
462   return EGL_TRUE;
463}
464
465
466static void
467check_extensions(struct GLX_egl_display *GLX_dpy, EGLint screen)
468{
469   GLX_dpy->extensions =
470      glXQueryExtensionsString(GLX_dpy->dpy, screen);
471   if (GLX_dpy->extensions) {
472      /* glXGetProcAddress is assumed */
473
474      if (strstr(GLX_dpy->extensions, "GLX_SGI_make_current_read")) {
475         /* GLX 1.3 entry points are used */
476         GLX_dpy->have_make_current_read = EGL_TRUE;
477      }
478
479      if (strstr(GLX_dpy->extensions, "GLX_SGIX_fbconfig")) {
480         /* GLX 1.3 entry points are used */
481         GLX_dpy->have_fbconfig = EGL_TRUE;
482      }
483
484      if (strstr(GLX_dpy->extensions, "GLX_SGIX_pbuffer")) {
485         GLX_dpy->glXCreateGLXPbufferSGIX = (PFNGLXCREATEGLXPBUFFERSGIXPROC)
486            glXGetProcAddress((const GLubyte *) "glXCreateGLXPbufferSGIX");
487         GLX_dpy->glXDestroyGLXPbufferSGIX = (PFNGLXDESTROYGLXPBUFFERSGIXPROC)
488            glXGetProcAddress((const GLubyte *) "glXDestroyGLXPbufferSGIX");
489
490         if (GLX_dpy->glXCreateGLXPbufferSGIX &&
491             GLX_dpy->glXDestroyGLXPbufferSGIX &&
492             GLX_dpy->have_fbconfig)
493            GLX_dpy->have_pbuffer = EGL_TRUE;
494      }
495   }
496
497   if (GLX_dpy->glx_maj == 1 && GLX_dpy->glx_min >= 3) {
498      GLX_dpy->have_1_3 = EGL_TRUE;
499      GLX_dpy->have_make_current_read = EGL_TRUE;
500      GLX_dpy->have_fbconfig = EGL_TRUE;
501      GLX_dpy->have_pbuffer = EGL_TRUE;
502   }
503}
504
505
506static void
507check_quirks(struct GLX_egl_display *GLX_dpy, EGLint screen)
508{
509   const char *vendor;
510
511   GLX_dpy->single_buffered_quirk = EGL_TRUE;
512   GLX_dpy->glx_window_quirk = EGL_TRUE;
513
514   vendor = glXGetClientString(GLX_dpy->dpy, GLX_VENDOR);
515   if (vendor && strstr(vendor, "NVIDIA")) {
516      vendor = glXQueryServerString(GLX_dpy->dpy, screen, GLX_VENDOR);
517      if (vendor && strstr(vendor, "NVIDIA")) {
518         _eglLog(_EGL_DEBUG, "disable quirks");
519         GLX_dpy->single_buffered_quirk = EGL_FALSE;
520         GLX_dpy->glx_window_quirk = EGL_FALSE;
521      }
522   }
523}
524
525
526/**
527 * Called via eglInitialize(), GLX_drv->API.Initialize().
528 */
529static EGLBoolean
530GLX_eglInitialize(_EGLDriver *drv, _EGLDisplay *disp,
531                   EGLint *major, EGLint *minor)
532{
533   struct GLX_egl_display *GLX_dpy;
534
535   GLX_dpy = CALLOC_STRUCT(GLX_egl_display);
536   if (!GLX_dpy)
537      return _eglError(EGL_BAD_ALLOC, "eglInitialize");
538
539   GLX_dpy->dpy = (Display *) disp->NativeDisplay;
540   if (!GLX_dpy->dpy) {
541      GLX_dpy->dpy = XOpenDisplay(NULL);
542      if (!GLX_dpy->dpy) {
543         _eglLog(_EGL_WARNING, "GLX: XOpenDisplay failed");
544         free(GLX_dpy);
545         return EGL_FALSE;
546      }
547   }
548
549   if (!glXQueryVersion(GLX_dpy->dpy, &GLX_dpy->glx_maj, &GLX_dpy->glx_min)) {
550      _eglLog(_EGL_WARNING, "GLX: glXQueryVersion failed");
551      if (!disp->NativeDisplay)
552         XCloseDisplay(GLX_dpy->dpy);
553      free(GLX_dpy);
554      return EGL_FALSE;
555   }
556
557   check_extensions(GLX_dpy, DefaultScreen(GLX_dpy->dpy));
558   check_quirks(GLX_dpy, DefaultScreen(GLX_dpy->dpy));
559
560   create_configs(disp, GLX_dpy, DefaultScreen(GLX_dpy->dpy));
561   if (!disp->NumConfigs) {
562      _eglLog(_EGL_WARNING, "GLX: failed to create any config");
563      if (!disp->NativeDisplay)
564         XCloseDisplay(GLX_dpy->dpy);
565      free(GLX_dpy);
566      return EGL_FALSE;
567   }
568
569   disp->DriverData = (void *) GLX_dpy;
570   disp->ClientAPIsMask = GLX_EGL_APIS;
571
572   /* we're supporting EGL 1.4 */
573   *major = 1;
574   *minor = 4;
575
576   return EGL_TRUE;
577}
578
579/**
580 * Called via eglTerminate(), drv->API.Terminate().
581 */
582static EGLBoolean
583GLX_eglTerminate(_EGLDriver *drv, _EGLDisplay *disp)
584{
585   struct GLX_egl_display *GLX_dpy = GLX_egl_display(disp);
586
587   _eglReleaseDisplayResources(drv, disp);
588   _eglCleanupDisplay(disp);
589
590   if (GLX_dpy->visuals)
591      XFree(GLX_dpy->visuals);
592   if (GLX_dpy->fbconfigs)
593      XFree(GLX_dpy->fbconfigs);
594
595   if (!disp->NativeDisplay)
596      XCloseDisplay(GLX_dpy->dpy);
597   free(GLX_dpy);
598
599   disp->DriverData = NULL;
600
601   return EGL_TRUE;
602}
603
604
605/**
606 * Called via eglCreateContext(), drv->API.CreateContext().
607 */
608static _EGLContext *
609GLX_eglCreateContext(_EGLDriver *drv, _EGLDisplay *disp, _EGLConfig *conf,
610                      _EGLContext *share_list, const EGLint *attrib_list)
611{
612   struct GLX_egl_context *GLX_ctx = CALLOC_STRUCT(GLX_egl_context);
613   struct GLX_egl_display *GLX_dpy = GLX_egl_display(disp);
614   struct GLX_egl_context *GLX_ctx_shared = GLX_egl_context(share_list);
615
616   if (!GLX_ctx) {
617      _eglError(EGL_BAD_ALLOC, "eglCreateContext");
618      return NULL;
619   }
620
621   if (!_eglInitContext(drv, &GLX_ctx->Base, conf, attrib_list)) {
622      free(GLX_ctx);
623      return NULL;
624   }
625
626#ifdef GLX_VERSION_1_3
627   if (GLX_dpy->fbconfigs)
628      GLX_ctx->context =
629         glXCreateNewContext(GLX_dpy->dpy,
630                             GLX_dpy->fbconfigs[GLX_egl_config_index(conf)],
631                             GLX_RGBA_TYPE,
632                             GLX_ctx_shared ? GLX_ctx_shared->context : NULL,
633                             GL_TRUE);
634   else
635#endif
636      GLX_ctx->context =
637         glXCreateContext(GLX_dpy->dpy,
638                          &GLX_dpy->visuals[GLX_egl_config_index(conf)],
639                          GLX_ctx_shared ? GLX_ctx_shared->context : NULL,
640                          GL_TRUE);
641   if (!GLX_ctx->context) {
642      free(GLX_ctx);
643      return NULL;
644   }
645
646#if 1
647   /* (maybe?) need to have a direct rendering context */
648   if (!glXIsDirect(GLX_dpy->dpy, GLX_ctx->context)) {
649      glXDestroyContext(GLX_dpy->dpy, GLX_ctx->context);
650      free(GLX_ctx);
651      return NULL;
652   }
653#endif
654
655   return &GLX_ctx->Base;
656}
657
658
659/**
660 * Called via eglMakeCurrent(), drv->API.MakeCurrent().
661 */
662static EGLBoolean
663GLX_eglMakeCurrent(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *dsurf,
664                   _EGLSurface *rsurf, _EGLContext *ctx)
665{
666   struct GLX_egl_display *GLX_dpy = GLX_egl_display(disp);
667   struct GLX_egl_surface *GLX_dsurf = GLX_egl_surface(dsurf);
668   struct GLX_egl_surface *GLX_rsurf = GLX_egl_surface(rsurf);
669   struct GLX_egl_context *GLX_ctx = GLX_egl_context(ctx);
670   GLXDrawable ddraw, rdraw;
671   GLXContext cctx;
672
673   if (!_eglMakeCurrent(drv, disp, dsurf, rsurf, ctx))
674      return EGL_FALSE;
675
676   ddraw = (GLX_dsurf) ? GLX_dsurf->drawable : None;
677   rdraw = (GLX_rsurf) ? GLX_rsurf->drawable : None;
678   cctx = (GLX_ctx) ? GLX_ctx->context : NULL;
679
680#ifdef GLX_VERSION_1_3
681   if (glXMakeContextCurrent(GLX_dpy->dpy, ddraw, rdraw, cctx))
682      return EGL_TRUE;
683#endif
684
685   if (ddraw == rdraw && glXMakeCurrent(GLX_dpy->dpy, ddraw, cctx))
686      return EGL_TRUE;
687
688   return EGL_FALSE;
689}
690
691/** Get size of given window */
692static Status
693get_drawable_size(Display *dpy, Drawable d, uint *width, uint *height)
694{
695   Window root;
696   Status stat;
697   int xpos, ypos;
698   unsigned int w, h, bw, depth;
699   stat = XGetGeometry(dpy, d, &root, &xpos, &ypos, &w, &h, &bw, &depth);
700   *width = w;
701   *height = h;
702   return stat;
703}
704
705/**
706 * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
707 */
708static _EGLSurface *
709GLX_eglCreateWindowSurface(_EGLDriver *drv, _EGLDisplay *disp, _EGLConfig *conf,
710                            NativeWindowType window, const EGLint *attrib_list)
711{
712   struct GLX_egl_display *GLX_dpy = GLX_egl_display(disp);
713   struct GLX_egl_surface *GLX_surf;
714   uint width, height;
715
716   GLX_surf = CALLOC_STRUCT(GLX_egl_surface);
717   if (!GLX_surf) {
718      _eglError(EGL_BAD_ALLOC, "eglCreateWindowSurface");
719      return NULL;
720   }
721
722   if (!_eglInitSurface(drv, &GLX_surf->Base, EGL_WINDOW_BIT,
723                        conf, attrib_list)) {
724      free(GLX_surf);
725      return NULL;
726   }
727
728   GLX_surf->drawable = window;
729   get_drawable_size(GLX_dpy->dpy, window, &width, &height);
730   GLX_surf->Base.Width = width;
731   GLX_surf->Base.Height = height;
732
733   return &GLX_surf->Base;
734}
735
736#ifdef GLX_VERSION_1_3
737static _EGLSurface *
738GLX_eglCreatePixmapSurface(_EGLDriver *drv, _EGLDisplay *disp, _EGLConfig *conf,
739			   NativePixmapType pixmap, const EGLint *attrib_list)
740{
741   struct GLX_egl_display *GLX_dpy = GLX_egl_display(disp);
742   struct GLX_egl_surface *GLX_surf;
743   int i;
744
745   /* GLX must >= 1.3 */
746   if (!(GLX_dpy->glx_maj == 1 && GLX_dpy->glx_min >= 3))
747      return NULL;
748
749   GLX_surf = CALLOC_STRUCT(GLX_egl_surface);
750   if (!GLX_surf) {
751      _eglError(EGL_BAD_ALLOC, "eglCreatePixmapSurface");
752      return NULL;
753   }
754
755   if (!_eglInitSurface(drv, &GLX_surf->Base, EGL_PIXMAP_BIT,
756                        conf, attrib_list)) {
757      free(GLX_surf);
758      return NULL;
759   }
760
761   for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i++) {
762      switch (attrib_list[i]) {
763         /* no attribs at this time */
764      default:
765         _eglError(EGL_BAD_ATTRIBUTE, "eglCreatePixmapSurface");
766         free(GLX_surf);
767         return NULL;
768      }
769   }
770
771   GLX_surf->drawable =
772      glXCreatePixmap(GLX_dpy->dpy,
773                      GLX_dpy->fbconfigs[GLX_egl_config_index(conf)],
774                      pixmap, NULL);
775   if (!GLX_surf->drawable) {
776      free(GLX_surf);
777      return NULL;
778   }
779
780   return &GLX_surf->Base;
781}
782
783static _EGLSurface *
784GLX_eglCreatePbufferSurface(_EGLDriver *drv, _EGLDisplay *disp,
785                            _EGLConfig *conf, const EGLint *attrib_list)
786{
787   struct GLX_egl_display *GLX_dpy = GLX_egl_display(disp);
788   struct GLX_egl_surface *GLX_surf;
789   int attribs[5];
790   int i = 0, j = 0;
791
792   /* GLX must >= 1.3 */
793   if (!(GLX_dpy->glx_maj == 1 && GLX_dpy->glx_min >= 3))
794      return NULL;
795
796   GLX_surf = CALLOC_STRUCT(GLX_egl_surface);
797   if (!GLX_surf) {
798      _eglError(EGL_BAD_ALLOC, "eglCreatePbufferSurface");
799      return NULL;
800   }
801
802   if (!_eglInitSurface(drv, &GLX_surf->Base, EGL_PBUFFER_BIT,
803                        conf, attrib_list)) {
804      free(GLX_surf);
805      return NULL;
806   }
807
808   while(attrib_list[i] != EGL_NONE) {
809      switch (attrib_list[i]) {
810         case EGL_WIDTH:
811	    attribs[j++] = GLX_PBUFFER_WIDTH;
812	    attribs[j++] = attrib_list[i+1];
813	    break;
814	 case EGL_HEIGHT:
815	    attribs[j++] = GLX_PBUFFER_HEIGHT;
816	    attribs[j++] = attrib_list[i+1];
817	    break;
818      }
819      i++;
820   }
821   attribs[j++] = 0;
822
823   GLX_surf->drawable =
824      glXCreatePbuffer(GLX_dpy->dpy,
825                       GLX_dpy->fbconfigs[GLX_egl_config_index(conf)],
826                       attribs);
827   if (!GLX_surf->drawable) {
828      free(GLX_surf);
829      return NULL;
830   }
831
832   return &GLX_surf->Base;
833}
834#endif
835
836static EGLBoolean
837GLX_eglDestroySurface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
838{
839   struct GLX_egl_display *GLX_dpy = GLX_egl_display(disp);
840   if (!_eglIsSurfaceBound(surf)) {
841      struct GLX_egl_surface *GLX_surf = GLX_egl_surface(surf);
842      switch (surf->Type) {
843      case EGL_PBUFFER_BIT:
844         glXDestroyPbuffer(GLX_dpy->dpy, GLX_surf->drawable);
845         break;
846      case EGL_PIXMAP_BIT:
847         glXDestroyPixmap(GLX_dpy->dpy, GLX_surf->drawable);
848         break;
849      default:
850         break;
851      }
852      free(surf);
853   }
854
855   return EGL_TRUE;
856}
857
858
859static EGLBoolean
860GLX_eglBindTexImage(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf,
861                     EGLint buffer)
862{
863   struct GLX_egl_display *GLX_dpy = GLX_egl_display(disp);
864   struct GLX_egl_surface *GLX_surf = GLX_egl_surface(surf);
865
866   /* buffer ?? */
867   glXBindTexImageEXT(GLX_dpy->dpy, GLX_surf->drawable,
868                      GLX_FRONT_LEFT_EXT, NULL);
869
870   return EGL_TRUE;
871}
872
873
874static EGLBoolean
875GLX_eglReleaseTexImage(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf,
876                        EGLint buffer)
877{
878   struct GLX_egl_display *GLX_dpy = GLX_egl_display(disp);
879   struct GLX_egl_surface *GLX_surf = GLX_egl_surface(surf);
880
881   /* buffer ?? */
882   glXReleaseTexImageEXT(GLX_dpy->dpy, GLX_surf->drawable,
883                         GLX_FRONT_LEFT_EXT);
884
885   return EGL_TRUE;
886}
887
888
889static EGLBoolean
890GLX_eglSwapBuffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
891{
892   struct GLX_egl_display *GLX_dpy = GLX_egl_display(disp);
893   struct GLX_egl_surface *GLX_surf = GLX_egl_surface(draw);
894
895   _eglLog(_EGL_DEBUG, "GLX: EGL SwapBuffers 0x%x",draw);
896
897   glXSwapBuffers(GLX_dpy->dpy, GLX_surf->drawable);
898
899   return EGL_TRUE;
900}
901
902/*
903 * Called from eglGetProcAddress() via drv->API.GetProcAddress().
904 */
905static _EGLProc
906GLX_eglGetProcAddress(const char *procname)
907{
908   /* This is a bit of a hack to get at the gallium/Mesa state tracker
909    * function st_get_proc_address().  This will probably change at
910    * some point.
911    */
912   _EGLProc (*get_proc_addr)(const char *procname);
913   _EGLProc proc_addr;
914   get_proc_addr = dlsym(NULL, "st_get_proc_address");
915   if (get_proc_addr)
916      return get_proc_addr(procname);
917
918   proc_addr = glXGetProcAddress((const GLubyte *)procname);
919   if (proc_addr)
920      return proc_addr;
921
922   return (_EGLProc)dlsym(NULL, procname);
923}
924
925
926static void
927GLX_Unload(_EGLDriver *drv)
928{
929   struct GLX_egl_driver *GLX_drv = GLX_egl_driver(drv);
930   free(GLX_drv);
931}
932
933
934/**
935 * This is the main entrypoint into the driver, called by libEGL.
936 * Create a new _EGLDriver object and init its dispatch table.
937 */
938_EGLDriver *
939_eglMain(const char *args)
940{
941   struct GLX_egl_driver *GLX_drv = CALLOC_STRUCT(GLX_egl_driver);
942
943   if (!GLX_drv)
944      return NULL;
945
946   _eglInitDriverFallbacks(&GLX_drv->Base);
947   GLX_drv->Base.API.Initialize = GLX_eglInitialize;
948   GLX_drv->Base.API.Terminate = GLX_eglTerminate;
949   GLX_drv->Base.API.CreateContext = GLX_eglCreateContext;
950   GLX_drv->Base.API.MakeCurrent = GLX_eglMakeCurrent;
951   GLX_drv->Base.API.CreateWindowSurface = GLX_eglCreateWindowSurface;
952#ifdef GLX_VERSION_1_3
953   GLX_drv->Base.API.CreatePixmapSurface = GLX_eglCreatePixmapSurface;
954   GLX_drv->Base.API.CreatePbufferSurface = GLX_eglCreatePbufferSurface;
955#endif
956   GLX_drv->Base.API.DestroySurface = GLX_eglDestroySurface;
957   GLX_drv->Base.API.BindTexImage = GLX_eglBindTexImage;
958   GLX_drv->Base.API.ReleaseTexImage = GLX_eglReleaseTexImage;
959   GLX_drv->Base.API.SwapBuffers = GLX_eglSwapBuffers;
960   GLX_drv->Base.API.GetProcAddress = GLX_eglGetProcAddress;
961
962   GLX_drv->Base.Name = "GLX";
963   GLX_drv->Base.Unload = GLX_Unload;
964
965   return &GLX_drv->Base;
966}
967