1 | //======================================================================== |
2 | // GLFW 3.2 GLX - www.glfw.org |
3 | //------------------------------------------------------------------------ |
4 | // Copyright (c) 2002-2006 Marcus Geelnard |
5 | // Copyright (c) 2006-2016 Camilla Berglund <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 getFBConfigAttrib(GLXFBConfig fbconfig, int attrib) |
42 | { |
43 | int value; |
44 | glXGetFBConfigAttrib(_glfw.x11.display, fbconfig, attrib, &value); |
45 | return value; |
46 | } |
47 | |
48 | // Return a list of available and usable framebuffer configs |
49 | // |
50 | static GLFWbool chooseFBConfig(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 (strcmp(vendor, "Chromium" ) == 0) |
63 | trustWindowBit = GLFW_FALSE; |
64 | |
65 | nativeConfigs = |
66 | glXGetFBConfigs(_glfw.x11.display, _glfw.x11.screen, &nativeCount); |
67 | if (!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 (!(getFBConfigAttrib(n, GLX_RENDER_TYPE) & GLX_RGBA_BIT)) |
83 | continue; |
84 | |
85 | // Only consider window GLXFBConfigs |
86 | if (!(getFBConfigAttrib(n, GLX_DRAWABLE_TYPE) & GLX_WINDOW_BIT)) |
87 | { |
88 | if (trustWindowBit) |
89 | continue; |
90 | } |
91 | |
92 | u->redBits = getFBConfigAttrib(n, GLX_RED_SIZE); |
93 | u->greenBits = getFBConfigAttrib(n, GLX_GREEN_SIZE); |
94 | u->blueBits = getFBConfigAttrib(n, GLX_BLUE_SIZE); |
95 | |
96 | u->alphaBits = getFBConfigAttrib(n, GLX_ALPHA_SIZE); |
97 | u->depthBits = getFBConfigAttrib(n, GLX_DEPTH_SIZE); |
98 | u->stencilBits = getFBConfigAttrib(n, GLX_STENCIL_SIZE); |
99 | |
100 | u->accumRedBits = getFBConfigAttrib(n, GLX_ACCUM_RED_SIZE); |
101 | u->accumGreenBits = getFBConfigAttrib(n, GLX_ACCUM_GREEN_SIZE); |
102 | u->accumBlueBits = getFBConfigAttrib(n, GLX_ACCUM_BLUE_SIZE); |
103 | u->accumAlphaBits = getFBConfigAttrib(n, GLX_ACCUM_ALPHA_SIZE); |
104 | |
105 | u->auxBuffers = getFBConfigAttrib(n, GLX_AUX_BUFFERS); |
106 | |
107 | if (getFBConfigAttrib(n, GLX_STEREO)) |
108 | u->stereo = GLFW_TRUE; |
109 | if (getFBConfigAttrib(n, GLX_DOUBLEBUFFER)) |
110 | u->doublebuffer = GLFW_TRUE; |
111 | |
112 | if (_glfw.glx.ARB_multisample) |
113 | u->samples = getFBConfigAttrib(n, GLX_SAMPLES); |
114 | |
115 | if (_glfw.glx.ARB_framebuffer_sRGB || _glfw.glx.EXT_framebuffer_sRGB) |
116 | u->sRGB = getFBConfigAttrib(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 createLegacyContext(_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 makeContextCurrent(_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 | _glfwPlatformSetCurrentContext(window); |
169 | } |
170 | |
171 | static void swapBuffers(_GLFWwindow* window) |
172 | { |
173 | glXSwapBuffers(_glfw.x11.display, window->context.glx.window); |
174 | } |
175 | |
176 | static void swapInterval(int interval) |
177 | { |
178 | _GLFWwindow* window = _glfwPlatformGetCurrentContext(); |
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 extensionSupported(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 getProcAddress(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 destroyContext(_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 | for (i = 0; sonames[i]; i++) |
257 | { |
258 | _glfw.glx.handle = dlopen(sonames[i], RTLD_LAZY | RTLD_GLOBAL); |
259 | if (_glfw.glx.handle) |
260 | break; |
261 | } |
262 | |
263 | if (!_glfw.glx.handle) |
264 | { |
265 | _glfwInputError(GLFW_API_UNAVAILABLE, "GLX: Failed to load GLX" ); |
266 | return GLFW_FALSE; |
267 | } |
268 | |
269 | _glfw.glx.GetFBConfigs = |
270 | dlsym(_glfw.glx.handle, "glXGetFBConfigs" ); |
271 | _glfw.glx.GetFBConfigAttrib = |
272 | dlsym(_glfw.glx.handle, "glXGetFBConfigAttrib" ); |
273 | _glfw.glx.GetClientString = |
274 | dlsym(_glfw.glx.handle, "glXGetClientString" ); |
275 | _glfw.glx.QueryExtension = |
276 | dlsym(_glfw.glx.handle, "glXQueryExtension" ); |
277 | _glfw.glx.QueryVersion = |
278 | dlsym(_glfw.glx.handle, "glXQueryVersion" ); |
279 | _glfw.glx.DestroyContext = |
280 | dlsym(_glfw.glx.handle, "glXDestroyContext" ); |
281 | _glfw.glx.MakeCurrent = |
282 | dlsym(_glfw.glx.handle, "glXMakeCurrent" ); |
283 | _glfw.glx.SwapBuffers = |
284 | dlsym(_glfw.glx.handle, "glXSwapBuffers" ); |
285 | _glfw.glx.QueryExtensionsString = |
286 | dlsym(_glfw.glx.handle, "glXQueryExtensionsString" ); |
287 | _glfw.glx.CreateNewContext = |
288 | dlsym(_glfw.glx.handle, "glXCreateNewContext" ); |
289 | _glfw.glx.CreateWindow = |
290 | dlsym(_glfw.glx.handle, "glXCreateWindow" ); |
291 | _glfw.glx.DestroyWindow = |
292 | dlsym(_glfw.glx.handle, "glXDestroyWindow" ); |
293 | _glfw.glx.GetProcAddress = |
294 | dlsym(_glfw.glx.handle, "glXGetProcAddress" ); |
295 | _glfw.glx.GetProcAddressARB = |
296 | dlsym(_glfw.glx.handle, "glXGetProcAddressARB" ); |
297 | _glfw.glx.GetVisualFromFBConfig = |
298 | dlsym(_glfw.glx.handle, "glXGetVisualFromFBConfig" ); |
299 | |
300 | if (!glXQueryExtension(_glfw.x11.display, |
301 | &_glfw.glx.errorBase, |
302 | &_glfw.glx.eventBase)) |
303 | { |
304 | _glfwInputError(GLFW_API_UNAVAILABLE, "GLX: GLX extension not found" ); |
305 | return GLFW_FALSE; |
306 | } |
307 | |
308 | if (!glXQueryVersion(_glfw.x11.display, &_glfw.glx.major, &_glfw.glx.minor)) |
309 | { |
310 | _glfwInputError(GLFW_API_UNAVAILABLE, |
311 | "GLX: Failed to query GLX version" ); |
312 | return GLFW_FALSE; |
313 | } |
314 | |
315 | if (_glfw.glx.major == 1 && _glfw.glx.minor < 3) |
316 | { |
317 | _glfwInputError(GLFW_API_UNAVAILABLE, |
318 | "GLX: GLX version 1.3 is required" ); |
319 | return GLFW_FALSE; |
320 | } |
321 | |
322 | if (extensionSupported("GLX_EXT_swap_control" )) |
323 | { |
324 | _glfw.glx.SwapIntervalEXT = (PFNGLXSWAPINTERVALEXTPROC) |
325 | getProcAddress("glXSwapIntervalEXT" ); |
326 | |
327 | if (_glfw.glx.SwapIntervalEXT) |
328 | _glfw.glx.EXT_swap_control = GLFW_TRUE; |
329 | } |
330 | |
331 | if (extensionSupported("GLX_SGI_swap_control" )) |
332 | { |
333 | _glfw.glx.SwapIntervalSGI = (PFNGLXSWAPINTERVALSGIPROC) |
334 | getProcAddress("glXSwapIntervalSGI" ); |
335 | |
336 | if (_glfw.glx.SwapIntervalSGI) |
337 | _glfw.glx.SGI_swap_control = GLFW_TRUE; |
338 | } |
339 | |
340 | if (extensionSupported("GLX_MESA_swap_control" )) |
341 | { |
342 | _glfw.glx.SwapIntervalMESA = (PFNGLXSWAPINTERVALMESAPROC) |
343 | getProcAddress("glXSwapIntervalMESA" ); |
344 | |
345 | if (_glfw.glx.SwapIntervalMESA) |
346 | _glfw.glx.MESA_swap_control = GLFW_TRUE; |
347 | } |
348 | |
349 | if (extensionSupported("GLX_ARB_multisample" )) |
350 | _glfw.glx.ARB_multisample = GLFW_TRUE; |
351 | |
352 | if (extensionSupported("GLX_ARB_framebuffer_sRGB" )) |
353 | _glfw.glx.ARB_framebuffer_sRGB = GLFW_TRUE; |
354 | |
355 | if (extensionSupported("GLX_EXT_framebuffer_sRGB" )) |
356 | _glfw.glx.EXT_framebuffer_sRGB = GLFW_TRUE; |
357 | |
358 | if (extensionSupported("GLX_ARB_create_context" )) |
359 | { |
360 | _glfw.glx.CreateContextAttribsARB = (PFNGLXCREATECONTEXTATTRIBSARBPROC) |
361 | getProcAddress("glXCreateContextAttribsARB" ); |
362 | |
363 | if (_glfw.glx.CreateContextAttribsARB) |
364 | _glfw.glx.ARB_create_context = GLFW_TRUE; |
365 | } |
366 | |
367 | if (extensionSupported("GLX_ARB_create_context_robustness" )) |
368 | _glfw.glx.ARB_create_context_robustness = GLFW_TRUE; |
369 | |
370 | if (extensionSupported("GLX_ARB_create_context_profile" )) |
371 | _glfw.glx.ARB_create_context_profile = GLFW_TRUE; |
372 | |
373 | if (extensionSupported("GLX_EXT_create_context_es2_profile" )) |
374 | _glfw.glx.EXT_create_context_es2_profile = GLFW_TRUE; |
375 | |
376 | if (extensionSupported("GLX_ARB_context_flush_control" )) |
377 | _glfw.glx.ARB_context_flush_control = GLFW_TRUE; |
378 | |
379 | return GLFW_TRUE; |
380 | } |
381 | |
382 | // Terminate GLX |
383 | // |
384 | void _glfwTerminateGLX(void) |
385 | { |
386 | // NOTE: This function must not call any X11 functions, as it is called |
387 | // after XCloseDisplay (see _glfwPlatformTerminate for details) |
388 | |
389 | if (_glfw.glx.handle) |
390 | { |
391 | dlclose(_glfw.glx.handle); |
392 | _glfw.glx.handle = NULL; |
393 | } |
394 | } |
395 | |
396 | #define setGLXattrib(attribName, attribValue) \ |
397 | { \ |
398 | attribs[index++] = attribName; \ |
399 | attribs[index++] = attribValue; \ |
400 | assert((size_t) index < sizeof(attribs) / sizeof(attribs[0])); \ |
401 | } |
402 | |
403 | // Create the OpenGL or OpenGL ES context |
404 | // |
405 | GLFWbool _glfwCreateContextGLX(_GLFWwindow* window, |
406 | const _GLFWctxconfig* ctxconfig, |
407 | const _GLFWfbconfig* fbconfig) |
408 | { |
409 | int attribs[40]; |
410 | GLXFBConfig native = NULL; |
411 | GLXContext share = NULL; |
412 | |
413 | if (ctxconfig->share) |
414 | share = ctxconfig->share->context.glx.handle; |
415 | |
416 | if (!chooseFBConfig(fbconfig, &native)) |
417 | { |
418 | _glfwInputError(GLFW_FORMAT_UNAVAILABLE, |
419 | "GLX: Failed to find a suitable GLXFBConfig" ); |
420 | return GLFW_FALSE; |
421 | } |
422 | |
423 | if (ctxconfig->client == GLFW_OPENGL_ES_API) |
424 | { |
425 | if (!_glfw.glx.ARB_create_context || |
426 | !_glfw.glx.ARB_create_context_profile || |
427 | !_glfw.glx.EXT_create_context_es2_profile) |
428 | { |
429 | _glfwInputError(GLFW_API_UNAVAILABLE, |
430 | "GLX: OpenGL ES requested but GLX_EXT_create_context_es2_profile is unavailable" ); |
431 | return GLFW_FALSE; |
432 | } |
433 | } |
434 | |
435 | if (ctxconfig->forward) |
436 | { |
437 | if (!_glfw.glx.ARB_create_context) |
438 | { |
439 | _glfwInputError(GLFW_VERSION_UNAVAILABLE, |
440 | "GLX: Forward compatibility requested but GLX_ARB_create_context_profile is unavailable" ); |
441 | return GLFW_FALSE; |
442 | } |
443 | } |
444 | |
445 | if (ctxconfig->profile) |
446 | { |
447 | if (!_glfw.glx.ARB_create_context || |
448 | !_glfw.glx.ARB_create_context_profile) |
449 | { |
450 | _glfwInputError(GLFW_VERSION_UNAVAILABLE, |
451 | "GLX: An OpenGL profile requested but GLX_ARB_create_context_profile is unavailable" ); |
452 | return GLFW_FALSE; |
453 | } |
454 | } |
455 | |
456 | _glfwGrabErrorHandlerX11(); |
457 | |
458 | if (_glfw.glx.ARB_create_context) |
459 | { |
460 | int index = 0, mask = 0, flags = 0; |
461 | |
462 | if (ctxconfig->client == GLFW_OPENGL_API) |
463 | { |
464 | if (ctxconfig->forward) |
465 | flags |= GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB; |
466 | |
467 | if (ctxconfig->profile == GLFW_OPENGL_CORE_PROFILE) |
468 | mask |= GLX_CONTEXT_CORE_PROFILE_BIT_ARB; |
469 | else if (ctxconfig->profile == GLFW_OPENGL_COMPAT_PROFILE) |
470 | mask |= GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; |
471 | } |
472 | else |
473 | mask |= GLX_CONTEXT_ES2_PROFILE_BIT_EXT; |
474 | |
475 | if (ctxconfig->debug) |
476 | flags |= GLX_CONTEXT_DEBUG_BIT_ARB; |
477 | if (ctxconfig->noerror) |
478 | flags |= GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR; |
479 | |
480 | if (ctxconfig->robustness) |
481 | { |
482 | if (_glfw.glx.ARB_create_context_robustness) |
483 | { |
484 | if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION) |
485 | { |
486 | setGLXattrib(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, |
487 | GLX_NO_RESET_NOTIFICATION_ARB); |
488 | } |
489 | else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET) |
490 | { |
491 | setGLXattrib(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, |
492 | GLX_LOSE_CONTEXT_ON_RESET_ARB); |
493 | } |
494 | |
495 | flags |= GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB; |
496 | } |
497 | } |
498 | |
499 | if (ctxconfig->release) |
500 | { |
501 | if (_glfw.glx.ARB_context_flush_control) |
502 | { |
503 | if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_NONE) |
504 | { |
505 | setGLXattrib(GLX_CONTEXT_RELEASE_BEHAVIOR_ARB, |
506 | GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB); |
507 | } |
508 | else if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_FLUSH) |
509 | { |
510 | setGLXattrib(GLX_CONTEXT_RELEASE_BEHAVIOR_ARB, |
511 | GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB); |
512 | } |
513 | } |
514 | } |
515 | |
516 | // NOTE: Only request an explicitly versioned context when necessary, as |
517 | // explicitly requesting version 1.0 does not always return the |
518 | // highest version supported by the driver |
519 | if (ctxconfig->major != 1 || ctxconfig->minor != 0) |
520 | { |
521 | setGLXattrib(GLX_CONTEXT_MAJOR_VERSION_ARB, ctxconfig->major); |
522 | setGLXattrib(GLX_CONTEXT_MINOR_VERSION_ARB, ctxconfig->minor); |
523 | } |
524 | |
525 | if (mask) |
526 | setGLXattrib(GLX_CONTEXT_PROFILE_MASK_ARB, mask); |
527 | |
528 | if (flags) |
529 | setGLXattrib(GLX_CONTEXT_FLAGS_ARB, flags); |
530 | |
531 | setGLXattrib(None, None); |
532 | |
533 | window->context.glx.handle = |
534 | _glfw.glx.CreateContextAttribsARB(_glfw.x11.display, |
535 | native, |
536 | share, |
537 | True, |
538 | attribs); |
539 | |
540 | // HACK: This is a fallback for broken versions of the Mesa |
541 | // implementation of GLX_ARB_create_context_profile that fail |
542 | // default 1.0 context creation with a GLXBadProfileARB error in |
543 | // violation of the extension spec |
544 | if (!window->context.glx.handle) |
545 | { |
546 | if (_glfw.x11.errorCode == _glfw.glx.errorBase + GLXBadProfileARB && |
547 | ctxconfig->client == GLFW_OPENGL_API && |
548 | ctxconfig->profile == GLFW_OPENGL_ANY_PROFILE && |
549 | ctxconfig->forward == GLFW_FALSE) |
550 | { |
551 | window->context.glx.handle = |
552 | createLegacyContext(window, native, share); |
553 | } |
554 | } |
555 | } |
556 | else |
557 | window->context.glx.handle = createLegacyContext(window, native, share); |
558 | |
559 | _glfwReleaseErrorHandlerX11(); |
560 | |
561 | if (!window->context.glx.handle) |
562 | { |
563 | _glfwInputErrorX11(GLFW_VERSION_UNAVAILABLE, "GLX: Failed to create context" ); |
564 | return GLFW_FALSE; |
565 | } |
566 | |
567 | window->context.glx.window = |
568 | glXCreateWindow(_glfw.x11.display, native, window->x11.handle, NULL); |
569 | if (!window->context.glx.window) |
570 | { |
571 | _glfwInputError(GLFW_PLATFORM_ERROR, "GLX: Failed to create window" ); |
572 | return GLFW_FALSE; |
573 | } |
574 | |
575 | window->context.makeCurrent = makeContextCurrent; |
576 | window->context.swapBuffers = swapBuffers; |
577 | window->context.swapInterval = swapInterval; |
578 | window->context.extensionSupported = extensionSupported; |
579 | window->context.getProcAddress = getProcAddress; |
580 | window->context.destroy = destroyContext; |
581 | |
582 | return GLFW_TRUE; |
583 | } |
584 | |
585 | #undef setGLXattrib |
586 | |
587 | // Returns the Visual and depth of the chosen GLXFBConfig |
588 | // |
589 | GLFWbool _glfwChooseVisualGLX(const _GLFWctxconfig* ctxconfig, |
590 | const _GLFWfbconfig* fbconfig, |
591 | Visual** visual, int* depth) |
592 | { |
593 | GLXFBConfig native; |
594 | XVisualInfo* result; |
595 | |
596 | if (!chooseFBConfig(fbconfig, &native)) |
597 | { |
598 | _glfwInputError(GLFW_FORMAT_UNAVAILABLE, |
599 | "GLX: Failed to find a suitable GLXFBConfig" ); |
600 | return GLFW_FALSE; |
601 | } |
602 | |
603 | result = glXGetVisualFromFBConfig(_glfw.x11.display, native); |
604 | if (!result) |
605 | { |
606 | _glfwInputError(GLFW_PLATFORM_ERROR, |
607 | "GLX: Failed to retrieve Visual for GLXFBConfig" ); |
608 | return GLFW_FALSE; |
609 | } |
610 | |
611 | *visual = result->visual; |
612 | *depth = result->depth; |
613 | |
614 | XFree(result); |
615 | return GLFW_TRUE; |
616 | } |
617 | |
618 | |
619 | ////////////////////////////////////////////////////////////////////////// |
620 | ////// GLFW native API ////// |
621 | ////////////////////////////////////////////////////////////////////////// |
622 | |
623 | GLFWAPI GLXContext glfwGetGLXContext(GLFWwindow* handle) |
624 | { |
625 | _GLFWwindow* window = (_GLFWwindow*) handle; |
626 | _GLFW_REQUIRE_INIT_OR_RETURN(NULL); |
627 | |
628 | if (window->context.client == GLFW_NO_API) |
629 | { |
630 | _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); |
631 | return NULL; |
632 | } |
633 | |
634 | return window->context.glx.handle; |
635 | } |
636 | |
637 | GLFWAPI GLXWindow glfwGetGLXWindow(GLFWwindow* handle) |
638 | { |
639 | _GLFWwindow* window = (_GLFWwindow*) handle; |
640 | _GLFW_REQUIRE_INIT_OR_RETURN(None); |
641 | |
642 | if (window->context.client == GLFW_NO_API) |
643 | { |
644 | _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); |
645 | return None; |
646 | } |
647 | |
648 | return window->context.glx.window; |
649 | } |
650 | |
651 | |