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