glx_context.c 23.8 KB
Newer Older
Camilla Berglund's avatar
Camilla Berglund committed
1
//========================================================================
Camilla Berglund's avatar
Camilla Berglund committed
2
// GLFW 3.3 GLX - www.glfw.org
Camilla Berglund's avatar
Camilla Berglund committed
3
4
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
Camilla Löwy's avatar
Camilla Löwy committed
5
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
Camilla Berglund's avatar
Camilla Berglund committed
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
//    claim that you wrote the original software. If you use this software
//    in a product, an acknowledgment in the product documentation would
//    be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
//    be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
//    distribution.
//
//========================================================================
27
28
// It is fine to use C99 in this file because it will not be built with VS
//========================================================================
Camilla Berglund's avatar
Camilla Berglund committed
29
30
31

#include "internal.h"

Camilla Berglund's avatar
Camilla Berglund committed
32
#include <string.h>
33
#include <stdlib.h>
34
#include <assert.h>
Camilla Berglund's avatar
Camilla Berglund committed
35

36
37
38
39
40
#ifndef GLXBadProfileARB
 #define GLXBadProfileARB 13
#endif


41
42
// Returns the specified attribute of the specified GLXFBConfig
//
43
static int getGLXFBConfigAttrib(GLXFBConfig fbconfig, int attrib)
44
45
{
    int value;
46
    glXGetFBConfigAttrib(_glfw.x11.display, fbconfig, attrib, &value);
47
48
49
    return value;
}

50
// Return the GLXFBConfig most closely matching the specified hints
51
//
52
53
static GLFWbool chooseGLXFBConfig(const _GLFWfbconfig* desired,
                                  GLXFBConfig* result)
54
55
56
57
58
59
{
    GLXFBConfig* nativeConfigs;
    _GLFWfbconfig* usableConfigs;
    const _GLFWfbconfig* closest;
    int i, nativeCount, usableCount;
    const char* vendor;
60
    GLFWbool trustWindowBit = GLFW_TRUE;
61

Camilla Berglund's avatar
Camilla Berglund committed
62
63
    // HACK: This is a (hopefully temporary) workaround for Chromium
    //       (VirtualBox GL) not setting the window bit on any GLXFBConfigs
64
    vendor = glXGetClientString(_glfw.x11.display, GLX_VENDOR);
65
    if (vendor && strcmp(vendor, "Chromium") == 0)
66
        trustWindowBit = GLFW_FALSE;
67

68
69
    nativeConfigs =
        glXGetFBConfigs(_glfw.x11.display, _glfw.x11.screen, &nativeCount);
70
    if (!nativeConfigs || !nativeCount)
71
    {
72
        _glfwInputError(GLFW_API_UNAVAILABLE, "GLX: No GLXFBConfigs returned");
73
        return GLFW_FALSE;
74
75
    }

76
    usableConfigs = calloc(nativeCount, sizeof(_GLFWfbconfig));
77
78
79
80
81
82
83
    usableCount = 0;

    for (i = 0;  i < nativeCount;  i++)
    {
        const GLXFBConfig n = nativeConfigs[i];
        _GLFWfbconfig* u = usableConfigs + usableCount;

Camilla Berglund's avatar
Camilla Berglund committed
84
        // Only consider RGBA GLXFBConfigs
85
        if (!(getGLXFBConfigAttrib(n, GLX_RENDER_TYPE) & GLX_RGBA_BIT))
86
87
            continue;

Camilla Berglund's avatar
Camilla Berglund committed
88
        // Only consider window GLXFBConfigs
89
        if (!(getGLXFBConfigAttrib(n, GLX_DRAWABLE_TYPE) & GLX_WINDOW_BIT))
90
91
92
93
94
        {
            if (trustWindowBit)
                continue;
        }

95
96
97
98
99
100
101
102
        if (desired->transparent)
        {
            XVisualInfo* vi = glXGetVisualFromFBConfig(_glfw.x11.display, n);
            if (vi)
            {
                u->transparent = _glfwIsVisualTransparentX11(vi->visual);
                XFree(vi);
            }
103
104
        }

105
106
107
        u->redBits = getGLXFBConfigAttrib(n, GLX_RED_SIZE);
        u->greenBits = getGLXFBConfigAttrib(n, GLX_GREEN_SIZE);
        u->blueBits = getGLXFBConfigAttrib(n, GLX_BLUE_SIZE);
108

109
110
111
        u->alphaBits = getGLXFBConfigAttrib(n, GLX_ALPHA_SIZE);
        u->depthBits = getGLXFBConfigAttrib(n, GLX_DEPTH_SIZE);
        u->stencilBits = getGLXFBConfigAttrib(n, GLX_STENCIL_SIZE);
112

113
114
115
116
        u->accumRedBits = getGLXFBConfigAttrib(n, GLX_ACCUM_RED_SIZE);
        u->accumGreenBits = getGLXFBConfigAttrib(n, GLX_ACCUM_GREEN_SIZE);
        u->accumBlueBits = getGLXFBConfigAttrib(n, GLX_ACCUM_BLUE_SIZE);
        u->accumAlphaBits = getGLXFBConfigAttrib(n, GLX_ACCUM_ALPHA_SIZE);
117

118
        u->auxBuffers = getGLXFBConfigAttrib(n, GLX_AUX_BUFFERS);
Camilla Berglund's avatar
Camilla Berglund committed
119

120
        if (getGLXFBConfigAttrib(n, GLX_STEREO))
121
            u->stereo = GLFW_TRUE;
122
        if (getGLXFBConfigAttrib(n, GLX_DOUBLEBUFFER))
123
            u->doublebuffer = GLFW_TRUE;
124
125

        if (_glfw.glx.ARB_multisample)
126
            u->samples = getGLXFBConfigAttrib(n, GLX_SAMPLES);
127

128
        if (_glfw.glx.ARB_framebuffer_sRGB || _glfw.glx.EXT_framebuffer_sRGB)
129
            u->sRGB = getGLXFBConfigAttrib(n, GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB);
130

Camilla Berglund's avatar
Cleanup    
Camilla Berglund committed
131
        u->handle = (uintptr_t) n;
132
133
134
135
136
        usableCount++;
    }

    closest = _glfwChooseFBConfig(desired, usableConfigs, usableCount);
    if (closest)
Camilla Berglund's avatar
Cleanup    
Camilla Berglund committed
137
        *result = (GLXFBConfig) closest->handle;
138
139
140
141

    XFree(nativeConfigs);
    free(usableConfigs);

Camilla Berglund's avatar
Cleanup    
Camilla Berglund committed
142
    return closest != NULL;
143
144
}

145
// Create the OpenGL context using legacy API
146
//
147
148
149
static GLXContext createLegacyContextGLX(_GLFWwindow* window,
                                         GLXFBConfig fbconfig,
                                         GLXContext share)
150
{
151
152
153
154
155
    return glXCreateNewContext(_glfw.x11.display,
                               fbconfig,
                               GLX_RGBA_TYPE,
                               share,
                               True);
156
157
}

158
static void makeContextCurrentGLX(_GLFWwindow* window)
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
{
    if (window)
    {
        if (!glXMakeCurrent(_glfw.x11.display,
                            window->context.glx.window,
                            window->context.glx.handle))
        {
            _glfwInputError(GLFW_PLATFORM_ERROR,
                            "GLX: Failed to make context current");
            return;
        }
    }
    else
    {
        if (!glXMakeCurrent(_glfw.x11.display, None, NULL))
        {
            _glfwInputError(GLFW_PLATFORM_ERROR,
                            "GLX: Failed to clear current context");
            return;
        }
    }

181
    _glfwPlatformSetTls(&_glfw.contextSlot, window);
182
183
}

184
static void swapBuffersGLX(_GLFWwindow* window)
185
186
187
188
{
    glXSwapBuffers(_glfw.x11.display, window->context.glx.window);
}

189
static void swapIntervalGLX(int interval)
190
{
191
    _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot);
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207

    if (_glfw.glx.EXT_swap_control)
    {
        _glfw.glx.SwapIntervalEXT(_glfw.x11.display,
                                  window->context.glx.window,
                                  interval);
    }
    else if (_glfw.glx.MESA_swap_control)
        _glfw.glx.SwapIntervalMESA(interval);
    else if (_glfw.glx.SGI_swap_control)
    {
        if (interval > 0)
            _glfw.glx.SwapIntervalSGI(interval);
    }
}

208
static int extensionSupportedGLX(const char* extension)
209
210
211
212
213
214
215
216
217
218
219
220
{
    const char* extensions =
        glXQueryExtensionsString(_glfw.x11.display, _glfw.x11.screen);
    if (extensions)
    {
        if (_glfwStringInExtensionString(extension, extensions))
            return GLFW_TRUE;
    }

    return GLFW_FALSE;
}

221
static GLFWglproc getProcAddressGLX(const char* procname)
222
223
224
225
226
227
{
    if (_glfw.glx.GetProcAddress)
        return _glfw.glx.GetProcAddress((const GLubyte*) procname);
    else if (_glfw.glx.GetProcAddressARB)
        return _glfw.glx.GetProcAddressARB((const GLubyte*) procname);
    else
228
        return _glfw_dlsym(_glfw.glx.handle, procname);
229
230
}

231
static void destroyContextGLX(_GLFWwindow* window)
232
233
234
235
236
237
238
239
240
241
242
243
244
245
{
    if (window->context.glx.window)
    {
        glXDestroyWindow(_glfw.x11.display, window->context.glx.window);
        window->context.glx.window = None;
    }

    if (window->context.glx.handle)
    {
        glXDestroyContext(_glfw.x11.display, window->context.glx.handle);
        window->context.glx.handle = NULL;
    }
}

246

247
248
249
250
251
//////////////////////////////////////////////////////////////////////////
//////                       GLFW internal API                      //////
//////////////////////////////////////////////////////////////////////////

// Initialize GLX
252
//
Camilla Berglund's avatar
Camilla Berglund committed
253
GLFWbool _glfwInitGLX(void)
254
{
255
256
257
    int i;
    const char* sonames[] =
    {
258
259
260
#if defined(_GLFW_GLX_LIBRARY)
        _GLFW_GLX_LIBRARY,
#elif defined(__CYGWIN__)
261
        "libGL-1.so",
262
#else
263
264
        "libGL.so.1",
        "libGL.so",
265
#endif
266
267
268
        NULL
    };

269
270
271
    if (_glfw.glx.handle)
        return GLFW_TRUE;

272
273
    for (i = 0;  sonames[i];  i++)
    {
274
        _glfw.glx.handle = _glfw_dlopen(sonames[i]);
275
276
277
278
        if (_glfw.glx.handle)
            break;
    }

279
    if (!_glfw.glx.handle)
280
    {
281
        _glfwInputError(GLFW_API_UNAVAILABLE, "GLX: Failed to load GLX");
282
        return GLFW_FALSE;
283
    }
284

285
    _glfw.glx.GetFBConfigs =
286
        _glfw_dlsym(_glfw.glx.handle, "glXGetFBConfigs");
287
    _glfw.glx.GetFBConfigAttrib =
288
        _glfw_dlsym(_glfw.glx.handle, "glXGetFBConfigAttrib");
289
    _glfw.glx.GetClientString =
290
        _glfw_dlsym(_glfw.glx.handle, "glXGetClientString");
291
    _glfw.glx.QueryExtension =
292
        _glfw_dlsym(_glfw.glx.handle, "glXQueryExtension");
293
    _glfw.glx.QueryVersion =
294
        _glfw_dlsym(_glfw.glx.handle, "glXQueryVersion");
295
    _glfw.glx.DestroyContext =
296
        _glfw_dlsym(_glfw.glx.handle, "glXDestroyContext");
297
    _glfw.glx.MakeCurrent =
298
        _glfw_dlsym(_glfw.glx.handle, "glXMakeCurrent");
299
    _glfw.glx.SwapBuffers =
300
        _glfw_dlsym(_glfw.glx.handle, "glXSwapBuffers");
301
    _glfw.glx.QueryExtensionsString =
302
        _glfw_dlsym(_glfw.glx.handle, "glXQueryExtensionsString");
303
    _glfw.glx.CreateNewContext =
304
        _glfw_dlsym(_glfw.glx.handle, "glXCreateNewContext");
305
    _glfw.glx.CreateWindow =
306
        _glfw_dlsym(_glfw.glx.handle, "glXCreateWindow");
307
    _glfw.glx.DestroyWindow =
308
        _glfw_dlsym(_glfw.glx.handle, "glXDestroyWindow");
309
    _glfw.glx.GetProcAddress =
310
        _glfw_dlsym(_glfw.glx.handle, "glXGetProcAddress");
311
    _glfw.glx.GetProcAddressARB =
312
        _glfw_dlsym(_glfw.glx.handle, "glXGetProcAddressARB");
313
    _glfw.glx.GetVisualFromFBConfig =
314
        _glfw_dlsym(_glfw.glx.handle, "glXGetVisualFromFBConfig");
315

316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
    if (!_glfw.glx.GetFBConfigs ||
        !_glfw.glx.GetFBConfigAttrib ||
        !_glfw.glx.GetClientString ||
        !_glfw.glx.QueryExtension ||
        !_glfw.glx.QueryVersion ||
        !_glfw.glx.DestroyContext ||
        !_glfw.glx.MakeCurrent ||
        !_glfw.glx.SwapBuffers ||
        !_glfw.glx.QueryExtensionsString ||
        !_glfw.glx.CreateNewContext ||
        !_glfw.glx.CreateWindow ||
        !_glfw.glx.DestroyWindow ||
        !_glfw.glx.GetProcAddress ||
        !_glfw.glx.GetProcAddressARB ||
        !_glfw.glx.GetVisualFromFBConfig)
    {
        _glfwInputError(GLFW_PLATFORM_ERROR,
                        "GLX: Failed to load required entry points");
        return GLFW_FALSE;
    }

337
338
339
    if (!glXQueryExtension(_glfw.x11.display,
                           &_glfw.glx.errorBase,
                           &_glfw.glx.eventBase))
340
    {
Camilla Berglund's avatar
Camilla Berglund committed
341
        _glfwInputError(GLFW_API_UNAVAILABLE, "GLX: GLX extension not found");
342
        return GLFW_FALSE;
343
344
    }

345
    if (!glXQueryVersion(_glfw.x11.display, &_glfw.glx.major, &_glfw.glx.minor))
346
    {
347
348
        _glfwInputError(GLFW_API_UNAVAILABLE,
                        "GLX: Failed to query GLX version");
349
        return GLFW_FALSE;
350
    }
351

352
    if (_glfw.glx.major == 1 && _glfw.glx.minor < 3)
Camilla Berglund's avatar
Camilla Berglund committed
353
354
355
    {
        _glfwInputError(GLFW_API_UNAVAILABLE,
                        "GLX: GLX version 1.3 is required");
356
        return GLFW_FALSE;
Camilla Berglund's avatar
Camilla Berglund committed
357
358
    }

359
    if (extensionSupportedGLX("GLX_EXT_swap_control"))
360
    {
361
        _glfw.glx.SwapIntervalEXT = (PFNGLXSWAPINTERVALEXTPROC)
362
            getProcAddressGLX("glXSwapIntervalEXT");
363
364

        if (_glfw.glx.SwapIntervalEXT)
365
            _glfw.glx.EXT_swap_control = GLFW_TRUE;
366
367
    }

368
    if (extensionSupportedGLX("GLX_SGI_swap_control"))
369
    {
370
        _glfw.glx.SwapIntervalSGI = (PFNGLXSWAPINTERVALSGIPROC)
371
            getProcAddressGLX("glXSwapIntervalSGI");
372
373

        if (_glfw.glx.SwapIntervalSGI)
374
            _glfw.glx.SGI_swap_control = GLFW_TRUE;
375
376
    }

377
    if (extensionSupportedGLX("GLX_MESA_swap_control"))
378
    {
379
        _glfw.glx.SwapIntervalMESA = (PFNGLXSWAPINTERVALMESAPROC)
380
            getProcAddressGLX("glXSwapIntervalMESA");
381

382
        if (_glfw.glx.SwapIntervalMESA)
383
            _glfw.glx.MESA_swap_control = GLFW_TRUE;
384
    }
385

386
    if (extensionSupportedGLX("GLX_ARB_multisample"))
387
        _glfw.glx.ARB_multisample = GLFW_TRUE;
388

389
    if (extensionSupportedGLX("GLX_ARB_framebuffer_sRGB"))
390
        _glfw.glx.ARB_framebuffer_sRGB = GLFW_TRUE;
391

392
    if (extensionSupportedGLX("GLX_EXT_framebuffer_sRGB"))
393
        _glfw.glx.EXT_framebuffer_sRGB = GLFW_TRUE;
394

395
    if (extensionSupportedGLX("GLX_ARB_create_context"))
396
397
    {
        _glfw.glx.CreateContextAttribsARB = (PFNGLXCREATECONTEXTATTRIBSARBPROC)
398
            getProcAddressGLX("glXCreateContextAttribsARB");
399

400
        if (_glfw.glx.CreateContextAttribsARB)
401
            _glfw.glx.ARB_create_context = GLFW_TRUE;
402
403
    }

404
    if (extensionSupportedGLX("GLX_ARB_create_context_robustness"))
405
        _glfw.glx.ARB_create_context_robustness = GLFW_TRUE;
406

407
    if (extensionSupportedGLX("GLX_ARB_create_context_profile"))
408
        _glfw.glx.ARB_create_context_profile = GLFW_TRUE;
409

410
    if (extensionSupportedGLX("GLX_EXT_create_context_es2_profile"))
411
        _glfw.glx.EXT_create_context_es2_profile = GLFW_TRUE;
412

413
414
415
    if (extensionSupportedGLX("GLX_ARB_create_context_no_error"))
        _glfw.glx.ARB_create_context_no_error = GLFW_TRUE;

416
    if (extensionSupportedGLX("GLX_ARB_context_flush_control"))
417
        _glfw.glx.ARB_context_flush_control = GLFW_TRUE;
418

419
    return GLFW_TRUE;
420
421
}

422
// Terminate GLX
423
//
424
void _glfwTerminateGLX(void)
425
{
426
427
    // NOTE: This function must not call any X11 functions, as it is called
    //       after XCloseDisplay (see _glfwPlatformTerminate for details)
428

429
    if (_glfw.glx.handle)
430
    {
431
        _glfw_dlclose(_glfw.glx.handle);
432
        _glfw.glx.handle = NULL;
433
434
435
    }
}

Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
436
#define setAttrib(a, v) \
437
{ \
438
    assert(((size_t) index + 1) < sizeof(attribs) / sizeof(attribs[0])); \
Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
439
440
    attribs[index++] = a; \
    attribs[index++] = v; \
441
}
442

Doug Binks's avatar
Doug Binks committed
443
444

// Create the OpenGL or OpenGL ES context for the window fbConfig
445
//
Doug Binks's avatar
Doug Binks committed
446
447
448
GLFWbool _glfwCreateContextForFBGLX(_GLFWwindow* window,
                                    const _GLFWctxconfig* ctxconfig,
                                    GLXContext* context)
449
450
451
452
{
    int attribs[40];
    GLXContext share = NULL;

453
    if (ctxconfig->share)
454
        share = ctxconfig->share->context.glx.handle;
455

456
    if (ctxconfig->client == GLFW_OPENGL_ES_API)
457
    {
458
459
460
        if (!_glfw.glx.ARB_create_context ||
            !_glfw.glx.ARB_create_context_profile ||
            !_glfw.glx.EXT_create_context_es2_profile)
461
        {
462
            _glfwInputError(GLFW_API_UNAVAILABLE,
Camilla Berglund's avatar
Camilla Berglund committed
463
                            "GLX: OpenGL ES requested but GLX_EXT_create_context_es2_profile is unavailable");
464
            return GLFW_FALSE;
465
        }
Camilla Berglund's avatar
Camilla Berglund committed
466
    }
467

468
    if (ctxconfig->forward)
Camilla Berglund's avatar
Camilla Berglund committed
469
    {
470
        if (!_glfw.glx.ARB_create_context)
471
        {
472
            _glfwInputError(GLFW_VERSION_UNAVAILABLE,
Camilla Berglund's avatar
Camilla Berglund committed
473
                            "GLX: Forward compatibility requested but GLX_ARB_create_context_profile is unavailable");
474
            return GLFW_FALSE;
475
        }
Camilla Berglund's avatar
Camilla Berglund committed
476
    }
477

478
    if (ctxconfig->profile)
Camilla Berglund's avatar
Camilla Berglund committed
479
    {
480
481
        if (!_glfw.glx.ARB_create_context ||
            !_glfw.glx.ARB_create_context_profile)
482
        {
483
            _glfwInputError(GLFW_VERSION_UNAVAILABLE,
Camilla Berglund's avatar
Camilla Berglund committed
484
                            "GLX: An OpenGL profile requested but GLX_ARB_create_context_profile is unavailable");
485
            return GLFW_FALSE;
Camilla Berglund's avatar
Camilla Berglund committed
486
487
488
        }
    }

489
    _glfwGrabErrorHandlerX11();
490

491
    if (_glfw.glx.ARB_create_context)
Camilla Berglund's avatar
Camilla Berglund committed
492
    {
493
        int index = 0, mask = 0, flags = 0;
494

495
        if (ctxconfig->client == GLFW_OPENGL_API)
Camilla Berglund's avatar
Camilla Berglund committed
496
        {
497
            if (ctxconfig->forward)
498
499
                flags |= GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;

500
501
502
503
            if (ctxconfig->profile == GLFW_OPENGL_CORE_PROFILE)
                mask |= GLX_CONTEXT_CORE_PROFILE_BIT_ARB;
            else if (ctxconfig->profile == GLFW_OPENGL_COMPAT_PROFILE)
                mask |= GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
504
        }
Camilla Berglund's avatar
Camilla Berglund committed
505
506
        else
            mask |= GLX_CONTEXT_ES2_PROFILE_BIT_EXT;
507

508
509
510
        if (ctxconfig->debug)
            flags |= GLX_CONTEXT_DEBUG_BIT_ARB;

511
        if (ctxconfig->robustness)
512
        {
513
            if (_glfw.glx.ARB_create_context_robustness)
514
            {
515
                if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION)
516
                {
Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
517
518
                    setAttrib(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB,
                              GLX_NO_RESET_NOTIFICATION_ARB);
519
                }
520
                else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET)
521
                {
Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
522
523
                    setAttrib(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB,
                              GLX_LOSE_CONTEXT_ON_RESET_ARB);
524
                }
525

Camilla Berglund's avatar
Camilla Berglund committed
526
527
                flags |= GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB;
            }
528
529
        }

530
531
532
533
534
535
        if (ctxconfig->release)
        {
            if (_glfw.glx.ARB_context_flush_control)
            {
                if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_NONE)
                {
Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
536
537
                    setAttrib(GLX_CONTEXT_RELEASE_BEHAVIOR_ARB,
                              GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB);
538
539
540
                }
                else if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_FLUSH)
                {
Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
541
542
                    setAttrib(GLX_CONTEXT_RELEASE_BEHAVIOR_ARB,
                              GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB);
543
544
545
546
                }
            }
        }

547
548
549
        if (ctxconfig->noerror)
        {
            if (_glfw.glx.ARB_create_context_no_error)
Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
550
                setAttrib(GLX_CONTEXT_OPENGL_NO_ERROR_ARB, GLFW_TRUE);
551
552
        }

Camilla Berglund's avatar
Camilla Berglund committed
553
554
555
        // NOTE: Only request an explicitly versioned context when necessary, as
        //       explicitly requesting version 1.0 does not always return the
        //       highest version supported by the driver
556
        if (ctxconfig->major != 1 || ctxconfig->minor != 0)
557
        {
Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
558
559
            setAttrib(GLX_CONTEXT_MAJOR_VERSION_ARB, ctxconfig->major);
            setAttrib(GLX_CONTEXT_MINOR_VERSION_ARB, ctxconfig->minor);
Camilla Berglund's avatar
Camilla Berglund committed
560
        }
561

Camilla Berglund's avatar
Camilla Berglund committed
562
        if (mask)
Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
563
            setAttrib(GLX_CONTEXT_PROFILE_MASK_ARB, mask);
564

Camilla Berglund's avatar
Camilla Berglund committed
565
        if (flags)
Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
566
            setAttrib(GLX_CONTEXT_FLAGS_ARB, flags);
Camilla Berglund's avatar
Camilla Berglund committed
567

Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
568
        setAttrib(None, None);
569

Doug Binks's avatar
Doug Binks committed
570
        *context =
571
            _glfw.glx.CreateContextAttribsARB(_glfw.x11.display,
Doug Binks's avatar
Doug Binks committed
572
                                              window->context.glx.fbconfig,
573
574
575
                                              share,
                                              True,
                                              attribs);
576

Camilla Berglund's avatar
Camilla Berglund committed
577
578
579
580
        // HACK: This is a fallback for broken versions of the Mesa
        //       implementation of GLX_ARB_create_context_profile that fail
        //       default 1.0 context creation with a GLXBadProfileARB error in
        //       violation of the extension spec
Doug Binks's avatar
Doug Binks committed
581
        if (!(*context))
582
        {
583
            if (_glfw.x11.errorCode == _glfw.glx.errorBase + GLXBadProfileARB &&
584
                ctxconfig->client == GLFW_OPENGL_API &&
585
                ctxconfig->profile == GLFW_OPENGL_ANY_PROFILE &&
586
                ctxconfig->forward == GLFW_FALSE)
587
            {
Doug Binks's avatar
Doug Binks committed
588
589
                *context =
                    createLegacyContextGLX(window, window->context.glx.fbconfig, share);
590
            }
591
592
        }
    }
593
    else
594
    {
Doug Binks's avatar
Doug Binks committed
595
596
        *context =
            createLegacyContextGLX(window, window->context.glx.fbconfig, share);
597
    }
598

599
    _glfwReleaseErrorHandlerX11();
600

Doug Binks's avatar
Doug Binks committed
601
    if (!(*context))
602
    {
603
        _glfwInputErrorX11(GLFW_VERSION_UNAVAILABLE, "GLX: Failed to create context");
604
        return GLFW_FALSE;
605
606
    }

Doug Binks's avatar
Doug Binks committed
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
    return GLFW_TRUE;
}

// Create the OpenGL or OpenGL ES context
//
GLFWbool _glfwCreateContextGLX(_GLFWwindow* window,
                               const _GLFWctxconfig* ctxconfig,
                               const _GLFWfbconfig* fbconfig)
{

    if (!chooseGLXFBConfig(fbconfig, &window->context.glx.fbconfig))
    {
        _glfwInputError(GLFW_FORMAT_UNAVAILABLE,
                        "GLX: Failed to find a suitable GLXFBConfig");
        return GLFW_FALSE;
    }

    if(!_glfwCreateContextForFBGLX(window,ctxconfig,&window->context.glx.handle))
    {
        return GLFW_FALSE;
    }

629
    window->context.glx.window =
Doug Binks's avatar
Doug Binks committed
630
        glXCreateWindow(_glfw.x11.display, window->context.glx.fbconfig, window->x11.handle, NULL);
631
    if (!window->context.glx.window)
632
633
634
635
636
    {
        _glfwInputError(GLFW_PLATFORM_ERROR, "GLX: Failed to create window");
        return GLFW_FALSE;
    }

637
638
639
640
641
642
    window->context.makeCurrent = makeContextCurrentGLX;
    window->context.swapBuffers = swapBuffersGLX;
    window->context.swapInterval = swapIntervalGLX;
    window->context.extensionSupported = extensionSupportedGLX;
    window->context.getProcAddress = getProcAddressGLX;
    window->context.destroy = destroyContextGLX;
643

644
    return GLFW_TRUE;
645
646
}

Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
647
#undef setAttrib
648

649
650
// Returns the Visual and depth of the chosen GLXFBConfig
//
651
GLFWbool _glfwChooseVisualGLX(const _GLFWwndconfig* wndconfig,
Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
652
                              const _GLFWctxconfig* ctxconfig,
653
654
                              const _GLFWfbconfig* fbconfig,
                              Visual** visual, int* depth)
655
656
657
658
{
    GLXFBConfig native;
    XVisualInfo* result;

659
    if (!chooseGLXFBConfig(fbconfig, &native))
660
661
662
663
664
665
    {
        _glfwInputError(GLFW_FORMAT_UNAVAILABLE,
                        "GLX: Failed to find a suitable GLXFBConfig");
        return GLFW_FALSE;
    }

666
    result = glXGetVisualFromFBConfig(_glfw.x11.display, native);
667
668
669
670
671
672
673
674
    if (!result)
    {
        _glfwInputError(GLFW_PLATFORM_ERROR,
                        "GLX: Failed to retrieve Visual for GLXFBConfig");
        return GLFW_FALSE;
    }

    *visual = result->visual;
675
    *depth  = result->depth;
676
677
678
679
680

    XFree(result);
    return GLFW_TRUE;
}

Doug Binks's avatar
Doug Binks committed
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
//////////////////////////////////////////////////////////////////////////
//////                       GLFW platform API                      //////
//////////////////////////////////////////////////////////////////////////

_GLFWusercontext* _glfwPlatformCreateUserContext(_GLFWwindow* window)
{
    _GLFWusercontext* context;
    _GLFWctxconfig ctxconfig;

    context = calloc(1, sizeof(_GLFWusercontext));
    context->window = window;

    ctxconfig = _glfw.hints.context;
    ctxconfig.share = window;

    if(!_glfwCreateContextForFBGLX(window,&ctxconfig,&context->handle))
    {
        _glfwInputError(GLFW_PLATFORM_ERROR,
                                "GLX: Failed to create user OpenGL context");
        free(context);
        return NULL;
    }

    return context;
}

void _glfwPlatformDestroyUserContext(_GLFWusercontext* context)
{
    glXDestroyContext(_glfw.x11.display, context->handle);
    free(context);
}

void _glfwPlatformMakeUserContextCurrent(_GLFWusercontext* context)
{
    if(context)
    {
        if(!glXMakeCurrent(_glfw.x11.display, context->window->context.glx.window,context->handle))
        {
            _glfwInputError(GLFW_PLATFORM_ERROR,
                                 "GLX: Failed to set current user context");
        }
    }
    else
    {
        if (!glXMakeCurrent(_glfw.x11.display, None, NULL))
        {
            _glfwInputError(GLFW_PLATFORM_ERROR,
                                 "GLX: Failed to clear current context");
        }
    }
}
732

733
734
735
736
737
738
739
//////////////////////////////////////////////////////////////////////////
//////                        GLFW native API                       //////
//////////////////////////////////////////////////////////////////////////

GLFWAPI GLXContext glfwGetGLXContext(GLFWwindow* handle)
{
    _GLFWwindow* window = (_GLFWwindow*) handle;
740
    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
741

742
    if (window->context.client == GLFW_NO_API)
743
744
745
746
747
    {
        _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
        return NULL;
    }

748
    return window->context.glx.handle;
749
750
}

Camilla Berglund's avatar
Camilla Berglund committed
751
752
753
754
755
GLFWAPI GLXWindow glfwGetGLXWindow(GLFWwindow* handle)
{
    _GLFWwindow* window = (_GLFWwindow*) handle;
    _GLFW_REQUIRE_INIT_OR_RETURN(None);

756
    if (window->context.client == GLFW_NO_API)
Camilla Berglund's avatar
Camilla Berglund committed
757
758
759
760
761
762
763
764
    {
        _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
        return None;
    }

    return window->context.glx.window;
}