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