glx_context.cc (21841B)
1 //======================================================================== 2 // GLFW 3.3 GLX - www.glfw.org 3 //------------------------------------------------------------------------ 4 // Copyright (c) 2002-2006 Marcus Geelnard 5 // Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org> 6 // 7 // This software is provided 'as-is', without any express or implied 8 // warranty. In no event will the authors be held liable for any damages 9 // arising from the use of this software. 10 // 11 // Permission is granted to anyone to use this software for any purpose, 12 // including commercial applications, and to alter it and redistribute it 13 // freely, subject to the following restrictions: 14 // 15 // 1. The origin of this software must not be misrepresented; you must not 16 // claim that you wrote the original software. If you use this software 17 // in a product, an acknowledgment in the product documentation would 18 // be appreciated but is not required. 19 // 20 // 2. Altered source versions must be plainly marked as such, and must not 21 // be misrepresented as being the original software. 22 // 23 // 3. This notice may not be removed or altered from any source 24 // distribution. 25 // 26 //======================================================================== 27 28 #include "internal.h" 29 30 #include <string.h> 31 #include <stdlib.h> 32 #include <assert.h> 33 34 #ifndef GLXBadProfileARB 35 #define GLXBadProfileARB 13 36 #endif 37 38 39 // Returns the specified attribute of the specified GLXFBConfig 40 // 41 static int getGLXFBConfigAttrib(GLXFBConfig fbconfig, int attrib) 42 { 43 int value; 44 glXGetFBConfigAttrib(_glfw.x11.display, fbconfig, attrib, &value); 45 return value; 46 } 47 48 // Return the GLXFBConfig most closely matching the specified hints 49 // 50 static GLFWbool chooseGLXFBConfig(const _GLFWfbconfig* desired, GLXFBConfig* result) 51 { 52 GLXFBConfig* nativeConfigs; 53 _GLFWfbconfig* usableConfigs; 54 const _GLFWfbconfig* closest; 55 int i, nativeCount, usableCount; 56 const char* vendor; 57 GLFWbool trustWindowBit = GLFW_TRUE; 58 59 // HACK: This is a (hopefully temporary) workaround for Chromium 60 // (VirtualBox GL) not setting the window bit on any GLXFBConfigs 61 vendor = glXGetClientString(_glfw.x11.display, GLX_VENDOR); 62 if (vendor && strcmp(vendor, "Chromium") == 0) 63 trustWindowBit = GLFW_FALSE; 64 65 nativeConfigs = 66 glXGetFBConfigs(_glfw.x11.display, _glfw.x11.screen, &nativeCount); 67 if (!nativeConfigs || !nativeCount) 68 { 69 _glfwInputError(GLFW_API_UNAVAILABLE, "GLX: No GLXFBConfigs returned"); 70 return GLFW_FALSE; 71 } 72 73 usableConfigs = calloc(nativeCount, sizeof(_GLFWfbconfig)); 74 usableCount = 0; 75 76 for (i = 0; i < nativeCount; i++) 77 { 78 const GLXFBConfig n = nativeConfigs[i]; 79 _GLFWfbconfig* u = usableConfigs + usableCount; 80 81 // Only consider RGBA GLXFBConfigs 82 if (!(getGLXFBConfigAttrib(n, GLX_RENDER_TYPE) & GLX_RGBA_BIT)) 83 continue; 84 85 // Only consider window GLXFBConfigs 86 if (!(getGLXFBConfigAttrib(n, GLX_DRAWABLE_TYPE) & GLX_WINDOW_BIT)) 87 { 88 if (trustWindowBit) 89 continue; 90 } 91 92 u->redBits = getGLXFBConfigAttrib(n, GLX_RED_SIZE); 93 u->greenBits = getGLXFBConfigAttrib(n, GLX_GREEN_SIZE); 94 u->blueBits = getGLXFBConfigAttrib(n, GLX_BLUE_SIZE); 95 96 u->alphaBits = getGLXFBConfigAttrib(n, GLX_ALPHA_SIZE); 97 u->depthBits = getGLXFBConfigAttrib(n, GLX_DEPTH_SIZE); 98 u->stencilBits = getGLXFBConfigAttrib(n, GLX_STENCIL_SIZE); 99 100 u->accumRedBits = getGLXFBConfigAttrib(n, GLX_ACCUM_RED_SIZE); 101 u->accumGreenBits = getGLXFBConfigAttrib(n, GLX_ACCUM_GREEN_SIZE); 102 u->accumBlueBits = getGLXFBConfigAttrib(n, GLX_ACCUM_BLUE_SIZE); 103 u->accumAlphaBits = getGLXFBConfigAttrib(n, GLX_ACCUM_ALPHA_SIZE); 104 105 u->auxBuffers = getGLXFBConfigAttrib(n, GLX_AUX_BUFFERS); 106 107 if (getGLXFBConfigAttrib(n, GLX_STEREO)) 108 u->stereo = GLFW_TRUE; 109 if (getGLXFBConfigAttrib(n, GLX_DOUBLEBUFFER)) 110 u->doublebuffer = GLFW_TRUE; 111 112 if (_glfw.glx.ARB_multisample) 113 u->samples = getGLXFBConfigAttrib(n, GLX_SAMPLES); 114 115 if (_glfw.glx.ARB_framebuffer_sRGB || _glfw.glx.EXT_framebuffer_sRGB) 116 u->sRGB = getGLXFBConfigAttrib(n, GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB); 117 118 u->handle = (uintptr_t) n; 119 usableCount++; 120 } 121 122 closest = _glfwChooseFBConfig(desired, usableConfigs, usableCount); 123 if (closest) 124 *result = (GLXFBConfig) closest->handle; 125 126 XFree(nativeConfigs); 127 free(usableConfigs); 128 129 return closest != NULL; 130 } 131 132 // Create the OpenGL context using legacy API 133 // 134 static GLXContext createLegacyContextGLX(_GLFWwindow* window, 135 GLXFBConfig fbconfig, 136 GLXContext share) 137 { 138 return glXCreateNewContext(_glfw.x11.display, 139 fbconfig, 140 GLX_RGBA_TYPE, 141 share, 142 True); 143 } 144 145 static void makeContextCurrentGLX(_GLFWwindow* window) 146 { 147 if (window) 148 { 149 if (!glXMakeCurrent(_glfw.x11.display, 150 window->context.glx.window, 151 window->context.glx.handle)) 152 { 153 _glfwInputError(GLFW_PLATFORM_ERROR, 154 "GLX: Failed to make context current"); 155 return; 156 } 157 } 158 else 159 { 160 if (!glXMakeCurrent(_glfw.x11.display, None, NULL)) 161 { 162 _glfwInputError(GLFW_PLATFORM_ERROR, 163 "GLX: Failed to clear current context"); 164 return; 165 } 166 } 167 168 _glfwPlatformSetTls(&_glfw.contextSlot, window); 169 } 170 171 static void swapBuffersGLX(_GLFWwindow* window) 172 { 173 glXSwapBuffers(_glfw.x11.display, window->context.glx.window); 174 } 175 176 static void swapIntervalGLX(int interval) 177 { 178 _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot); 179 180 if (_glfw.glx.EXT_swap_control) 181 { 182 _glfw.glx.SwapIntervalEXT(_glfw.x11.display, 183 window->context.glx.window, 184 interval); 185 } 186 else if (_glfw.glx.MESA_swap_control) 187 _glfw.glx.SwapIntervalMESA(interval); 188 else if (_glfw.glx.SGI_swap_control) 189 { 190 if (interval > 0) 191 _glfw.glx.SwapIntervalSGI(interval); 192 } 193 } 194 195 static int extensionSupportedGLX(const char* extension) 196 { 197 const char* extensions = 198 glXQueryExtensionsString(_glfw.x11.display, _glfw.x11.screen); 199 if (extensions) 200 { 201 if (_glfwStringInExtensionString(extension, extensions)) 202 return GLFW_TRUE; 203 } 204 205 return GLFW_FALSE; 206 } 207 208 static GLFWglproc getProcAddressGLX(const char* procname) 209 { 210 if (_glfw.glx.GetProcAddress) 211 return _glfw.glx.GetProcAddress((const GLubyte*) procname); 212 else if (_glfw.glx.GetProcAddressARB) 213 return _glfw.glx.GetProcAddressARB((const GLubyte*) procname); 214 else 215 return dlsym(_glfw.glx.handle, procname); 216 } 217 218 // Destroy the OpenGL context 219 // 220 static void destroyContextGLX(_GLFWwindow* window) 221 { 222 if (window->context.glx.window) 223 { 224 glXDestroyWindow(_glfw.x11.display, window->context.glx.window); 225 window->context.glx.window = None; 226 } 227 228 if (window->context.glx.handle) 229 { 230 glXDestroyContext(_glfw.x11.display, window->context.glx.handle); 231 window->context.glx.handle = NULL; 232 } 233 } 234 235 236 ////////////////////////////////////////////////////////////////////////// 237 ////// GLFW internal API ////// 238 ////////////////////////////////////////////////////////////////////////// 239 240 // Initialize GLX 241 // 242 GLFWbool _glfwInitGLX(void) 243 { 244 int i; 245 const char* sonames[] = 246 { 247 #if defined(__CYGWIN__) 248 "libGL-1.so", 249 #else 250 "libGL.so.1", 251 "libGL.so", 252 #endif 253 NULL 254 }; 255 256 if (_glfw.glx.handle) 257 return GLFW_TRUE; 258 259 for (i = 0; sonames[i]; i++) 260 { 261 _glfw.glx.handle = dlopen(sonames[i], RTLD_LAZY | RTLD_GLOBAL); 262 if (_glfw.glx.handle) 263 break; 264 } 265 266 if (!_glfw.glx.handle) 267 { 268 _glfwInputError(GLFW_API_UNAVAILABLE, "GLX: Failed to load GLX"); 269 return GLFW_FALSE; 270 } 271 272 _glfw.glx.GetFBConfigs = 273 dlsym(_glfw.glx.handle, "glXGetFBConfigs"); 274 _glfw.glx.GetFBConfigAttrib = 275 dlsym(_glfw.glx.handle, "glXGetFBConfigAttrib"); 276 _glfw.glx.GetClientString = 277 dlsym(_glfw.glx.handle, "glXGetClientString"); 278 _glfw.glx.QueryExtension = 279 dlsym(_glfw.glx.handle, "glXQueryExtension"); 280 _glfw.glx.QueryVersion = 281 dlsym(_glfw.glx.handle, "glXQueryVersion"); 282 _glfw.glx.DestroyContext = 283 dlsym(_glfw.glx.handle, "glXDestroyContext"); 284 _glfw.glx.MakeCurrent = 285 dlsym(_glfw.glx.handle, "glXMakeCurrent"); 286 _glfw.glx.SwapBuffers = 287 dlsym(_glfw.glx.handle, "glXSwapBuffers"); 288 _glfw.glx.QueryExtensionsString = 289 dlsym(_glfw.glx.handle, "glXQueryExtensionsString"); 290 _glfw.glx.CreateNewContext = 291 dlsym(_glfw.glx.handle, "glXCreateNewContext"); 292 _glfw.glx.CreateWindow = 293 dlsym(_glfw.glx.handle, "glXCreateWindow"); 294 _glfw.glx.DestroyWindow = 295 dlsym(_glfw.glx.handle, "glXDestroyWindow"); 296 _glfw.glx.GetProcAddress = 297 dlsym(_glfw.glx.handle, "glXGetProcAddress"); 298 _glfw.glx.GetProcAddressARB = 299 dlsym(_glfw.glx.handle, "glXGetProcAddressARB"); 300 _glfw.glx.GetVisualFromFBConfig = 301 dlsym(_glfw.glx.handle, "glXGetVisualFromFBConfig"); 302 303 if (!_glfw.glx.GetFBConfigs || 304 !_glfw.glx.GetFBConfigAttrib || 305 !_glfw.glx.GetClientString || 306 !_glfw.glx.QueryExtension || 307 !_glfw.glx.QueryVersion || 308 !_glfw.glx.DestroyContext || 309 !_glfw.glx.MakeCurrent || 310 !_glfw.glx.SwapBuffers || 311 !_glfw.glx.QueryExtensionsString || 312 !_glfw.glx.CreateNewContext || 313 !_glfw.glx.CreateWindow || 314 !_glfw.glx.DestroyWindow || 315 !_glfw.glx.GetProcAddress || 316 !_glfw.glx.GetProcAddressARB || 317 !_glfw.glx.GetVisualFromFBConfig) 318 { 319 _glfwInputError(GLFW_PLATFORM_ERROR, 320 "GLX: Failed to load required entry points"); 321 return GLFW_FALSE; 322 } 323 324 if (!glXQueryExtension(_glfw.x11.display, 325 &_glfw.glx.errorBase, 326 &_glfw.glx.eventBase)) 327 { 328 _glfwInputError(GLFW_API_UNAVAILABLE, "GLX: GLX extension not found"); 329 return GLFW_FALSE; 330 } 331 332 if (!glXQueryVersion(_glfw.x11.display, &_glfw.glx.major, &_glfw.glx.minor)) 333 { 334 _glfwInputError(GLFW_API_UNAVAILABLE, 335 "GLX: Failed to query GLX version"); 336 return GLFW_FALSE; 337 } 338 339 if (_glfw.glx.major == 1 && _glfw.glx.minor < 3) 340 { 341 _glfwInputError(GLFW_API_UNAVAILABLE, 342 "GLX: GLX version 1.3 is required"); 343 return GLFW_FALSE; 344 } 345 346 if (extensionSupportedGLX("GLX_EXT_swap_control")) 347 { 348 _glfw.glx.SwapIntervalEXT = (PFNGLXSWAPINTERVALEXTPROC) 349 getProcAddressGLX("glXSwapIntervalEXT"); 350 351 if (_glfw.glx.SwapIntervalEXT) 352 _glfw.glx.EXT_swap_control = GLFW_TRUE; 353 } 354 355 if (extensionSupportedGLX("GLX_SGI_swap_control")) 356 { 357 _glfw.glx.SwapIntervalSGI = (PFNGLXSWAPINTERVALSGIPROC) 358 getProcAddressGLX("glXSwapIntervalSGI"); 359 360 if (_glfw.glx.SwapIntervalSGI) 361 _glfw.glx.SGI_swap_control = GLFW_TRUE; 362 } 363 364 if (extensionSupportedGLX("GLX_MESA_swap_control")) 365 { 366 _glfw.glx.SwapIntervalMESA = (PFNGLXSWAPINTERVALMESAPROC) 367 getProcAddressGLX("glXSwapIntervalMESA"); 368 369 if (_glfw.glx.SwapIntervalMESA) 370 _glfw.glx.MESA_swap_control = GLFW_TRUE; 371 } 372 373 if (extensionSupportedGLX("GLX_ARB_multisample")) 374 _glfw.glx.ARB_multisample = GLFW_TRUE; 375 376 if (extensionSupportedGLX("GLX_ARB_framebuffer_sRGB")) 377 _glfw.glx.ARB_framebuffer_sRGB = GLFW_TRUE; 378 379 if (extensionSupportedGLX("GLX_EXT_framebuffer_sRGB")) 380 _glfw.glx.EXT_framebuffer_sRGB = GLFW_TRUE; 381 382 if (extensionSupportedGLX("GLX_ARB_create_context")) 383 { 384 _glfw.glx.CreateContextAttribsARB = (PFNGLXCREATECONTEXTATTRIBSARBPROC) 385 getProcAddressGLX("glXCreateContextAttribsARB"); 386 387 if (_glfw.glx.CreateContextAttribsARB) 388 _glfw.glx.ARB_create_context = GLFW_TRUE; 389 } 390 391 if (extensionSupportedGLX("GLX_ARB_create_context_robustness")) 392 _glfw.glx.ARB_create_context_robustness = GLFW_TRUE; 393 394 if (extensionSupportedGLX("GLX_ARB_create_context_profile")) 395 _glfw.glx.ARB_create_context_profile = GLFW_TRUE; 396 397 if (extensionSupportedGLX("GLX_EXT_create_context_es2_profile")) 398 _glfw.glx.EXT_create_context_es2_profile = GLFW_TRUE; 399 400 if (extensionSupportedGLX("GLX_ARB_create_context_no_error")) 401 _glfw.glx.ARB_create_context_no_error = GLFW_TRUE; 402 403 if (extensionSupportedGLX("GLX_ARB_context_flush_control")) 404 _glfw.glx.ARB_context_flush_control = GLFW_TRUE; 405 406 return GLFW_TRUE; 407 } 408 409 // Terminate GLX 410 // 411 void _glfwTerminateGLX(void) 412 { 413 // NOTE: This function must not call any X11 functions, as it is called 414 // after XCloseDisplay (see _glfwPlatformTerminate for details) 415 416 if (_glfw.glx.handle) 417 { 418 dlclose(_glfw.glx.handle); 419 _glfw.glx.handle = NULL; 420 } 421 } 422 423 #define setAttrib(a, v) \ 424 { \ 425 assert((size_t) (index + 1) < sizeof(attribs) / sizeof(attribs[0])); \ 426 attribs[index++] = a; \ 427 attribs[index++] = v; \ 428 } 429 430 // Create the OpenGL or OpenGL ES context 431 // 432 GLFWbool _glfwCreateContextGLX(_GLFWwindow* window, 433 const _GLFWctxconfig* ctxconfig, 434 const _GLFWfbconfig* fbconfig) 435 { 436 int attribs[40]; 437 GLXFBConfig native = NULL; 438 GLXContext share = NULL; 439 440 if (ctxconfig->share) 441 share = ctxconfig->share->context.glx.handle; 442 443 if (!chooseGLXFBConfig(fbconfig, &native)) 444 { 445 _glfwInputError(GLFW_FORMAT_UNAVAILABLE, 446 "GLX: Failed to find a suitable GLXFBConfig"); 447 return GLFW_FALSE; 448 } 449 450 if (ctxconfig->client == GLFW_OPENGL_ES_API) 451 { 452 if (!_glfw.glx.ARB_create_context || 453 !_glfw.glx.ARB_create_context_profile || 454 !_glfw.glx.EXT_create_context_es2_profile) 455 { 456 _glfwInputError(GLFW_API_UNAVAILABLE, 457 "GLX: OpenGL ES requested but GLX_EXT_create_context_es2_profile is unavailable"); 458 return GLFW_FALSE; 459 } 460 } 461 462 if (ctxconfig->forward) 463 { 464 if (!_glfw.glx.ARB_create_context) 465 { 466 _glfwInputError(GLFW_VERSION_UNAVAILABLE, 467 "GLX: Forward compatibility requested but GLX_ARB_create_context_profile is unavailable"); 468 return GLFW_FALSE; 469 } 470 } 471 472 if (ctxconfig->profile) 473 { 474 if (!_glfw.glx.ARB_create_context || 475 !_glfw.glx.ARB_create_context_profile) 476 { 477 _glfwInputError(GLFW_VERSION_UNAVAILABLE, 478 "GLX: An OpenGL profile requested but GLX_ARB_create_context_profile is unavailable"); 479 return GLFW_FALSE; 480 } 481 } 482 483 _glfwGrabErrorHandlerX11(); 484 485 if (_glfw.glx.ARB_create_context) 486 { 487 int index = 0, mask = 0, flags = 0; 488 489 if (ctxconfig->client == GLFW_OPENGL_API) 490 { 491 if (ctxconfig->forward) 492 flags |= GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB; 493 494 if (ctxconfig->profile == GLFW_OPENGL_CORE_PROFILE) 495 mask |= GLX_CONTEXT_CORE_PROFILE_BIT_ARB; 496 else if (ctxconfig->profile == GLFW_OPENGL_COMPAT_PROFILE) 497 mask |= GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; 498 } 499 else 500 mask |= GLX_CONTEXT_ES2_PROFILE_BIT_EXT; 501 502 if (ctxconfig->debug) 503 flags |= GLX_CONTEXT_DEBUG_BIT_ARB; 504 505 if (ctxconfig->robustness) 506 { 507 if (_glfw.glx.ARB_create_context_robustness) 508 { 509 if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION) 510 { 511 setAttrib(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, 512 GLX_NO_RESET_NOTIFICATION_ARB); 513 } 514 else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET) 515 { 516 setAttrib(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, 517 GLX_LOSE_CONTEXT_ON_RESET_ARB); 518 } 519 520 flags |= GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB; 521 } 522 } 523 524 if (ctxconfig->release) 525 { 526 if (_glfw.glx.ARB_context_flush_control) 527 { 528 if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_NONE) 529 { 530 setAttrib(GLX_CONTEXT_RELEASE_BEHAVIOR_ARB, 531 GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB); 532 } 533 else if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_FLUSH) 534 { 535 setAttrib(GLX_CONTEXT_RELEASE_BEHAVIOR_ARB, 536 GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB); 537 } 538 } 539 } 540 541 if (ctxconfig->noerror) 542 { 543 if (_glfw.glx.ARB_create_context_no_error) 544 setAttrib(GLX_CONTEXT_OPENGL_NO_ERROR_ARB, GLFW_TRUE); 545 } 546 547 // NOTE: Only request an explicitly versioned context when necessary, as 548 // explicitly requesting version 1.0 does not always return the 549 // highest version supported by the driver 550 if (ctxconfig->major != 1 || ctxconfig->minor != 0) 551 { 552 setAttrib(GLX_CONTEXT_MAJOR_VERSION_ARB, ctxconfig->major); 553 setAttrib(GLX_CONTEXT_MINOR_VERSION_ARB, ctxconfig->minor); 554 } 555 556 if (mask) 557 setAttrib(GLX_CONTEXT_PROFILE_MASK_ARB, mask); 558 559 if (flags) 560 setAttrib(GLX_CONTEXT_FLAGS_ARB, flags); 561 562 setAttrib(None, None); 563 564 window->context.glx.handle = 565 _glfw.glx.CreateContextAttribsARB(_glfw.x11.display, 566 native, 567 share, 568 True, 569 attribs); 570 571 // HACK: This is a fallback for broken versions of the Mesa 572 // implementation of GLX_ARB_create_context_profile that fail 573 // default 1.0 context creation with a GLXBadProfileARB error in 574 // violation of the extension spec 575 if (!window->context.glx.handle) 576 { 577 if (_glfw.x11.errorCode == _glfw.glx.errorBase + GLXBadProfileARB && 578 ctxconfig->client == GLFW_OPENGL_API && 579 ctxconfig->profile == GLFW_OPENGL_ANY_PROFILE && 580 ctxconfig->forward == GLFW_FALSE) 581 { 582 window->context.glx.handle = 583 createLegacyContextGLX(window, native, share); 584 } 585 } 586 } 587 else 588 { 589 window->context.glx.handle = 590 createLegacyContextGLX(window, native, share); 591 } 592 593 _glfwReleaseErrorHandlerX11(); 594 595 if (!window->context.glx.handle) 596 { 597 _glfwInputErrorX11(GLFW_VERSION_UNAVAILABLE, "GLX: Failed to create context"); 598 return GLFW_FALSE; 599 } 600 601 window->context.glx.window = 602 glXCreateWindow(_glfw.x11.display, native, window->x11.handle, NULL); 603 if (!window->context.glx.window) 604 { 605 _glfwInputError(GLFW_PLATFORM_ERROR, "GLX: Failed to create window"); 606 return GLFW_FALSE; 607 } 608 609 window->context.makeCurrent = makeContextCurrentGLX; 610 window->context.swapBuffers = swapBuffersGLX; 611 window->context.swapInterval = swapIntervalGLX; 612 window->context.extensionSupported = extensionSupportedGLX; 613 window->context.getProcAddress = getProcAddressGLX; 614 window->context.destroy = destroyContextGLX; 615 616 return GLFW_TRUE; 617 } 618 619 #undef setAttrib 620 621 // Returns the Visual and depth of the chosen GLXFBConfig 622 // 623 GLFWbool _glfwChooseVisualGLX(const _GLFWctxconfig* ctxconfig, 624 const _GLFWfbconfig* fbconfig, 625 Visual** visual, int* depth) 626 { 627 GLXFBConfig native; 628 XVisualInfo* result; 629 630 if (!chooseGLXFBConfig(fbconfig, &native)) 631 { 632 _glfwInputError(GLFW_FORMAT_UNAVAILABLE, 633 "GLX: Failed to find a suitable GLXFBConfig"); 634 return GLFW_FALSE; 635 } 636 637 result = glXGetVisualFromFBConfig(_glfw.x11.display, native); 638 if (!result) 639 { 640 _glfwInputError(GLFW_PLATFORM_ERROR, 641 "GLX: Failed to retrieve Visual for GLXFBConfig"); 642 return GLFW_FALSE; 643 } 644 645 *visual = result->visual; 646 *depth = result->depth; 647 648 XFree(result); 649 return GLFW_TRUE; 650 } 651 652 653 ////////////////////////////////////////////////////////////////////////// 654 ////// GLFW native API ////// 655 ////////////////////////////////////////////////////////////////////////// 656 657 GLFWAPI GLXContext glfwGetGLXContext(GLFWwindow* handle) 658 { 659 _GLFWwindow* window = (_GLFWwindow*) handle; 660 _GLFW_REQUIRE_INIT_OR_RETURN(NULL); 661 662 if (window->context.client == GLFW_NO_API) 663 { 664 _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); 665 return NULL; 666 } 667 668 return window->context.glx.handle; 669 } 670 671 GLFWAPI GLXWindow glfwGetGLXWindow(GLFWwindow* handle) 672 { 673 _GLFWwindow* window = (_GLFWwindow*) handle; 674 _GLFW_REQUIRE_INIT_OR_RETURN(None); 675 676 if (window->context.client == GLFW_NO_API) 677 { 678 _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); 679 return None; 680 } 681 682 return window->context.glx.window; 683 } 684