src/video/x11/SDL_x11opengl.c
author Sam Lantinga <slouken@libsdl.org>
Thu, 11 Jul 2013 22:59:20 -0700
changeset 7412 50211a1fd557
parent 7191 75360622e65f
child 7413 30d42f6f2e8d
permissions -rw-r--r--
Fixed bug 1946 - OpenGL contexts in threads

The SDL OpenGL context code is now properly thread aware. There are two new functions which return the current OpenGL window and context for the current thread.

There are still places in the cocoa driver where the OpenGL context needs to be updated when the view changes. These will need a different solution and still use the last globally set context to avoid changing behavior.
slouken@1952
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@6885
     3
  Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
slouken@1952
     4
slouken@5535
     5
  This software is provided 'as-is', without any express or implied
slouken@5535
     6
  warranty.  In no event will the authors be held liable for any damages
slouken@5535
     7
  arising from the use of this software.
slouken@1952
     8
slouken@5535
     9
  Permission is granted to anyone to use this software for any purpose,
slouken@5535
    10
  including commercial applications, and to alter it and redistribute it
slouken@5535
    11
  freely, subject to the following restrictions:
slouken@1952
    12
slouken@5535
    13
  1. The origin of this software must not be misrepresented; you must not
slouken@5535
    14
     claim that you wrote the original software. If you use this software
slouken@5535
    15
     in a product, an acknowledgment in the product documentation would be
slouken@5535
    16
     appreciated but is not required.
slouken@5535
    17
  2. Altered source versions must be plainly marked as such, and must not be
slouken@5535
    18
     misrepresented as being the original software.
slouken@5535
    19
  3. This notice may not be removed or altered from any source distribution.
slouken@1952
    20
*/
slouken@1952
    21
#include "SDL_config.h"
slouken@6044
    22
slouken@6044
    23
#if SDL_VIDEO_DRIVER_X11
slouken@6044
    24
slouken@1952
    25
#include "SDL_x11video.h"
icculus@5981
    26
#include "SDL_assert.h"
slouken@1952
    27
slouken@1952
    28
/* GLX implementation of SDL OpenGL support */
slouken@1952
    29
slouken@1952
    30
#if SDL_VIDEO_OPENGL_GLX
slouken@1952
    31
#include "SDL_loadso.h"
slouken@6370
    32
#include "SDL_x11opengles.h"
slouken@1952
    33
slouken@1952
    34
#if defined(__IRIX__)
slouken@1952
    35
/* IRIX doesn't have a GL library versioning system */
slouken@7191
    36
#define DEFAULT_OPENGL  "libGL.so"
slouken@1952
    37
#elif defined(__MACOSX__)
slouken@7191
    38
#define DEFAULT_OPENGL  "/usr/X11R6/lib/libGL.1.dylib"
slouken@1952
    39
#elif defined(__QNXNTO__)
slouken@7191
    40
#define DEFAULT_OPENGL  "libGL.so.3"
slouken@1952
    41
#else
slouken@7191
    42
#define DEFAULT_OPENGL  "libGL.so.1"
slouken@1952
    43
#endif
slouken@1952
    44
slouken@3241
    45
#ifndef GLX_NONE_EXT
slouken@3241
    46
#define GLX_NONE_EXT                       0x8000
slouken@3241
    47
#endif
slouken@3241
    48
slouken@1952
    49
#ifndef GLX_ARB_multisample
slouken@1952
    50
#define GLX_ARB_multisample
slouken@1952
    51
#define GLX_SAMPLE_BUFFERS_ARB             100000
slouken@1952
    52
#define GLX_SAMPLES_ARB                    100001
slouken@1952
    53
#endif
slouken@1952
    54
slouken@1952
    55
#ifndef GLX_EXT_visual_rating
slouken@1952
    56
#define GLX_EXT_visual_rating
slouken@1952
    57
#define GLX_VISUAL_CAVEAT_EXT              0x20
slouken@1952
    58
#define GLX_NONE_EXT                       0x8000
slouken@1952
    59
#define GLX_SLOW_VISUAL_EXT                0x8001
slouken@1952
    60
#define GLX_NON_CONFORMANT_VISUAL_EXT      0x800D
slouken@1952
    61
#endif
slouken@1952
    62
mikesart@6570
    63
#ifndef GLX_EXT_visual_info
mikesart@6570
    64
#define GLX_EXT_visual_info
mikesart@6570
    65
#define GLX_X_VISUAL_TYPE_EXT              0x22
mikesart@6570
    66
#define GLX_DIRECT_COLOR_EXT               0x8003
mikesart@6570
    67
#endif
mikesart@6570
    68
slouken@3100
    69
#ifndef GLX_ARB_create_context
slouken@3100
    70
#define GLX_ARB_create_context
slouken@3100
    71
#define GLX_CONTEXT_MAJOR_VERSION_ARB      0x2091
slouken@3100
    72
#define GLX_CONTEXT_MINOR_VERSION_ARB      0x2092
slouken@3100
    73
#define GLX_CONTEXT_FLAGS_ARB              0x2094
slouken@3100
    74
#define GLX_CONTEXT_DEBUG_BIT_ARB          0x0001
slouken@3100
    75
#define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002
slouken@5021
    76
slouken@5021
    77
/* Typedef for the GL 3.0 context creation function */
slouken@5021
    78
typedef GLXContext(*PFNGLXCREATECONTEXTATTRIBSARBPROC) (Display * dpy,
slouken@5021
    79
                                                        GLXFBConfig config,
slouken@5021
    80
                                                        GLXContext
slouken@5021
    81
                                                        share_context,
slouken@5021
    82
                                                        Bool direct,
slouken@5021
    83
                                                        const int
slouken@5021
    84
                                                        *attrib_list);
icculus@6360
    85
#endif
slouken@6296
    86
slouken@6296
    87
#ifndef GLX_ARB_create_context_profile
slouken@6296
    88
#define GLX_ARB_create_context_profile
slouken@6296
    89
#define GLX_CONTEXT_PROFILE_MASK_ARB       0x9126
slouken@6296
    90
#define GLX_CONTEXT_CORE_PROFILE_BIT_ARB   0x00000001
slouken@6296
    91
#define GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
slouken@6296
    92
#endif
slouken@6296
    93
slouken@6296
    94
#ifndef GLX_ARB_create_context_robustness
slouken@6296
    95
#define GLX_ARB_create_context_robustness
slouken@6296
    96
#define GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB  0x00000004
slouken@6296
    97
#define GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB     0x8256
slouken@6296
    98
#define GLX_NO_RESET_NOTIFICATION_ARB                   0x8261
slouken@6296
    99
#define GLX_LOSE_CONTEXT_ON_RESET_ARB                   0x8252
slouken@6296
   100
#endif
slouken@6296
   101
slouken@6296
   102
#ifndef GLX_EXT_create_context_es2_profile
slouken@6296
   103
#define GLX_EXT_create_context_es2_profile
icculus@6375
   104
#ifndef GLX_CONTEXT_ES2_PROFILE_BIT_EXT
slouken@6296
   105
#define GLX_CONTEXT_ES2_PROFILE_BIT_EXT    0x00000002
slouken@6296
   106
#endif
icculus@6375
   107
#endif
slouken@6296
   108
slouken@6296
   109
#ifndef GLX_EXT_swap_control
slouken@6296
   110
#define GLX_SWAP_INTERVAL_EXT              0x20F1
slouken@6296
   111
#define GLX_MAX_SWAP_INTERVAL_EXT          0x20F2
slouken@3100
   112
#endif
slouken@3100
   113
icculus@6382
   114
#ifndef GLX_EXT_swap_control_tear
icculus@6382
   115
#define GLX_LATE_SWAPS_TEAR_EXT 0x20F3
icculus@6382
   116
#endif
icculus@6382
   117
slouken@6183
   118
#define OPENGL_REQUIRES_DLOPEN
slouken@6183
   119
#if defined(OPENGL_REQUIRES_DLOPEN) && defined(SDL_LOADSO_DLOPEN)
slouken@1952
   120
#include <dlfcn.h>
slouken@7191
   121
#define GL_LoadObject(X)    dlopen(X, (RTLD_NOW|RTLD_GLOBAL))
slouken@7191
   122
#define GL_LoadFunction     dlsym
slouken@7191
   123
#define GL_UnloadObject     dlclose
slouken@1952
   124
#else
slouken@7191
   125
#define GL_LoadObject   SDL_LoadObject
slouken@7191
   126
#define GL_LoadFunction SDL_LoadFunction
slouken@7191
   127
#define GL_UnloadObject SDL_UnloadObject
slouken@1952
   128
#endif
slouken@1952
   129
slouken@3057
   130
static void X11_GL_InitExtensions(_THIS);
bob@2322
   131
slouken@3100
   132
slouken@1952
   133
int
slouken@1952
   134
X11_GL_LoadLibrary(_THIS, const char *path)
slouken@1952
   135
{
slouken@1952
   136
    void *handle;
slouken@1952
   137
slouken@6370
   138
    if (_this->gl_data) {
icculus@7037
   139
        return SDL_SetError("OpenGL context already created");
slouken@6370
   140
    }
slouken@6370
   141
slouken@6370
   142
    /* If SDL_GL_CONTEXT_EGL has been changed to 1, switch over to X11_GLES functions  */
slouken@6370
   143
    if (_this->gl_config.use_egl == 1) {
slouken@6373
   144
#if SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
slouken@6370
   145
        _this->GL_LoadLibrary = X11_GLES_LoadLibrary;
slouken@6370
   146
        _this->GL_GetProcAddress = X11_GLES_GetProcAddress;
slouken@6370
   147
        _this->GL_UnloadLibrary = X11_GLES_UnloadLibrary;
slouken@6370
   148
        _this->GL_CreateContext = X11_GLES_CreateContext;
slouken@6370
   149
        _this->GL_MakeCurrent = X11_GLES_MakeCurrent;
slouken@6370
   150
        _this->GL_SetSwapInterval = X11_GLES_SetSwapInterval;
slouken@6370
   151
        _this->GL_GetSwapInterval = X11_GLES_GetSwapInterval;
slouken@6370
   152
        _this->GL_SwapWindow = X11_GLES_SwapWindow;
slouken@6370
   153
        _this->GL_DeleteContext = X11_GLES_DeleteContext;
slouken@6370
   154
        return X11_GLES_LoadLibrary(_this, path);
slouken@6373
   155
#else
icculus@7037
   156
        return SDL_SetError("SDL not configured with OpenGL ES/EGL support");
slouken@6373
   157
#endif
slouken@6370
   158
    }
slouken@6370
   159
slouken@6370
   160
slouken@3057
   161
    /* Load the OpenGL library */
slouken@3057
   162
    if (path == NULL) {
slouken@3057
   163
        path = SDL_getenv("SDL_OPENGL_LIBRARY");
slouken@1952
   164
    }
slouken@3057
   165
    if (path == NULL) {
slouken@3057
   166
        path = DEFAULT_OPENGL;
slouken@3057
   167
    }
slouken@6183
   168
    _this->gl_config.dll_handle = GL_LoadObject(path);
slouken@3057
   169
    if (!_this->gl_config.dll_handle) {
slouken@6183
   170
#if defined(OPENGL_REQUIRES_DLOPEN) && defined(SDL_LOADSO_DLOPEN)
slouken@6183
   171
        SDL_SetError("Failed loading %s: %s", path, dlerror());
slouken@6183
   172
#endif
slouken@3057
   173
        return -1;
slouken@3057
   174
    }
slouken@3057
   175
    SDL_strlcpy(_this->gl_config.driver_path, path,
slouken@3057
   176
                SDL_arraysize(_this->gl_config.driver_path));
slouken@2244
   177
slouken@3057
   178
    /* Allocate OpenGL memory */
slouken@3057
   179
    _this->gl_data =
slouken@3057
   180
        (struct SDL_GLDriverData *) SDL_calloc(1,
slouken@3057
   181
                                               sizeof(struct
slouken@3057
   182
                                                      SDL_GLDriverData));
slouken@3057
   183
    if (!_this->gl_data) {
icculus@7037
   184
        return SDL_OutOfMemory();
slouken@3057
   185
    }
slouken@3057
   186
slouken@3057
   187
    /* Load function pointers */
slouken@3057
   188
    handle = _this->gl_config.dll_handle;
slouken@1952
   189
    _this->gl_data->glXGetProcAddress =
slouken@4550
   190
        (void *(*)(const GLubyte *))
slouken@4550
   191
            GL_LoadFunction(handle, "glXGetProcAddressARB");
slouken@1952
   192
    _this->gl_data->glXChooseVisual =
slouken@4550
   193
        (XVisualInfo * (*)(Display *, int, int *))
slouken@4550
   194
            X11_GL_GetProcAddress(_this, "glXChooseVisual");
slouken@1952
   195
    _this->gl_data->glXCreateContext =
slouken@1952
   196
        (GLXContext(*)(Display *, XVisualInfo *, GLXContext, int))
slouken@4550
   197
            X11_GL_GetProcAddress(_this, "glXCreateContext");
slouken@1952
   198
    _this->gl_data->glXDestroyContext =
slouken@4550
   199
        (void (*)(Display *, GLXContext))
slouken@4550
   200
            X11_GL_GetProcAddress(_this, "glXDestroyContext");
slouken@1952
   201
    _this->gl_data->glXMakeCurrent =
slouken@4550
   202
        (int (*)(Display *, GLXDrawable, GLXContext))
slouken@4550
   203
            X11_GL_GetProcAddress(_this, "glXMakeCurrent");
slouken@1952
   204
    _this->gl_data->glXSwapBuffers =
slouken@4550
   205
        (void (*)(Display *, GLXDrawable))
slouken@4550
   206
            X11_GL_GetProcAddress(_this, "glXSwapBuffers");
icculus@5572
   207
    _this->gl_data->glXQueryDrawable =
icculus@5572
   208
        (void (*)(Display*,GLXDrawable,int,unsigned int*))
icculus@5572
   209
            X11_GL_GetProcAddress(_this, "glXQueryDrawable");
slouken@1952
   210
slouken@1952
   211
    if (!_this->gl_data->glXChooseVisual ||
slouken@1952
   212
        !_this->gl_data->glXCreateContext ||
slouken@1952
   213
        !_this->gl_data->glXDestroyContext ||
slouken@4550
   214
        !_this->gl_data->glXMakeCurrent ||
slouken@4550
   215
        !_this->gl_data->glXSwapBuffers) {
icculus@7037
   216
        return SDL_SetError("Could not retrieve OpenGL functions");
slouken@1952
   217
    }
slouken@1952
   218
slouken@3057
   219
    /* Initialize extensions */
slouken@3057
   220
    X11_GL_InitExtensions(_this);
slouken@3057
   221
slouken@1952
   222
    return 0;
slouken@1952
   223
}
slouken@1952
   224
slouken@1952
   225
void *
slouken@1952
   226
X11_GL_GetProcAddress(_THIS, const char *proc)
slouken@1952
   227
{
slouken@1952
   228
    if (_this->gl_data->glXGetProcAddress) {
slouken@1952
   229
        return _this->gl_data->glXGetProcAddress((const GLubyte *) proc);
slouken@1952
   230
    }
slouken@4550
   231
    return GL_LoadFunction(_this->gl_config.dll_handle, proc);
slouken@1952
   232
}
slouken@1952
   233
slouken@3057
   234
void
slouken@1952
   235
X11_GL_UnloadLibrary(_THIS)
slouken@1952
   236
{
slouken@3057
   237
    /* Don't actually unload the library, since it may have registered
slouken@3057
   238
     * X11 shutdown hooks, per the notes at:
slouken@3057
   239
     * http://dri.sourceforge.net/doc/DRIuserguide.html
slouken@3057
   240
     */
slouken@3057
   241
#if 0
slouken@3057
   242
    GL_UnloadObject(_this->gl_config.dll_handle);
slouken@3057
   243
    _this->gl_config.dll_handle = NULL;
slouken@3057
   244
#endif
slouken@3057
   245
slouken@3057
   246
    /* Free OpenGL memory */
slouken@6181
   247
    if (_this->gl_data) {
slouken@6181
   248
        SDL_free(_this->gl_data);
slouken@6181
   249
        _this->gl_data = NULL;
slouken@6181
   250
    }
slouken@1952
   251
}
slouken@1952
   252
slouken@1952
   253
static SDL_bool
slouken@1952
   254
HasExtension(const char *extension, const char *extensions)
slouken@1952
   255
{
slouken@1952
   256
    const char *start;
slouken@1952
   257
    const char *where, *terminator;
slouken@1952
   258
slouken@1952
   259
    /* Extension names should not have spaces. */
slouken@1952
   260
    where = SDL_strchr(extension, ' ');
slouken@1952
   261
    if (where || *extension == '\0')
slouken@1952
   262
        return SDL_FALSE;
slouken@1952
   263
slouken@1952
   264
    if (!extensions)
slouken@1952
   265
        return SDL_FALSE;
slouken@1952
   266
slouken@1952
   267
    /* It takes a bit of care to be fool-proof about parsing the
slouken@1952
   268
     * OpenGL extensions string. Don't be fooled by sub-strings,
slouken@1952
   269
     * etc. */
slouken@1952
   270
slouken@1952
   271
    start = extensions;
slouken@1952
   272
slouken@1952
   273
    for (;;) {
slouken@1952
   274
        where = SDL_strstr(start, extension);
slouken@1952
   275
        if (!where)
slouken@1952
   276
            break;
slouken@1952
   277
slouken@1952
   278
        terminator = where + SDL_strlen(extension);
slouken@1952
   279
        if (where == start || *(where - 1) == ' ')
slouken@1952
   280
            if (*terminator == ' ' || *terminator == '\0')
slouken@1952
   281
                return SDL_TRUE;
slouken@1952
   282
slouken@1952
   283
        start = terminator;
slouken@1952
   284
    }
slouken@1952
   285
    return SDL_FALSE;
slouken@1952
   286
}
slouken@1952
   287
slouken@1952
   288
static void
slouken@1952
   289
X11_GL_InitExtensions(_THIS)
slouken@1952
   290
{
slouken@1952
   291
    Display *display = ((SDL_VideoData *) _this->driverdata)->display;
slouken@5244
   292
    int screen = DefaultScreen(display);
slouken@1952
   293
    XVisualInfo *vinfo;
slouken@1952
   294
    XSetWindowAttributes xattr;
slouken@1952
   295
    Window w;
slouken@1952
   296
    GLXContext context;
slouken@1952
   297
    const char *(*glXQueryExtensionsStringFunc) (Display *, int);
slouken@1952
   298
    const char *extensions;
slouken@1952
   299
slouken@1952
   300
    vinfo = X11_GL_GetVisual(_this, display, screen);
slouken@1952
   301
    if (!vinfo) {
slouken@1952
   302
        return;
slouken@1952
   303
    }
slouken@1952
   304
    xattr.background_pixel = 0;
slouken@1952
   305
    xattr.border_pixel = 0;
slouken@1952
   306
    xattr.colormap =
slouken@1952
   307
        XCreateColormap(display, RootWindow(display, screen), vinfo->visual,
slouken@1952
   308
                        AllocNone);
slouken@1952
   309
    w = XCreateWindow(display, RootWindow(display, screen), 0, 0, 32, 32, 0,
slouken@1952
   310
                      vinfo->depth, InputOutput, vinfo->visual,
slouken@1952
   311
                      (CWBackPixel | CWBorderPixel | CWColormap), &xattr);
slouken@1952
   312
    context = _this->gl_data->glXCreateContext(display, vinfo, NULL, True);
slouken@1952
   313
    if (context) {
slouken@1952
   314
        _this->gl_data->glXMakeCurrent(display, w, context);
slouken@1952
   315
    }
slouken@1952
   316
    XFree(vinfo);
slouken@1952
   317
slouken@1952
   318
    glXQueryExtensionsStringFunc =
slouken@1952
   319
        (const char *(*)(Display *, int)) X11_GL_GetProcAddress(_this,
slouken@1952
   320
                                                                "glXQueryExtensionsString");
slouken@1952
   321
    if (glXQueryExtensionsStringFunc) {
slouken@1952
   322
        extensions = glXQueryExtensionsStringFunc(display, screen);
slouken@1952
   323
    } else {
slouken@1952
   324
        extensions = NULL;
slouken@1952
   325
    }
slouken@1952
   326
icculus@6382
   327
    /* Check for GLX_EXT_swap_control(_tear) */
icculus@6382
   328
    _this->gl_data->HAS_GLX_EXT_swap_control_tear = SDL_FALSE;
icculus@5572
   329
    if (HasExtension("GLX_EXT_swap_control", extensions)) {
icculus@5572
   330
        _this->gl_data->glXSwapIntervalEXT =
slouken@6846
   331
            (void (*)(Display*,GLXDrawable,int))
icculus@5572
   332
                X11_GL_GetProcAddress(_this, "glXSwapIntervalEXT");
icculus@6382
   333
        if (HasExtension("GLX_EXT_swap_control_tear", extensions)) {
icculus@6382
   334
            _this->gl_data->HAS_GLX_EXT_swap_control_tear = SDL_TRUE;
icculus@6382
   335
        }
slouken@1952
   336
    }
slouken@1952
   337
slouken@1952
   338
    /* Check for GLX_MESA_swap_control */
slouken@1952
   339
    if (HasExtension("GLX_MESA_swap_control", extensions)) {
slouken@1952
   340
        _this->gl_data->glXSwapIntervalMESA =
icculus@5572
   341
            (int(*)(int)) X11_GL_GetProcAddress(_this, "glXSwapIntervalMESA");
slouken@1952
   342
        _this->gl_data->glXGetSwapIntervalMESA =
icculus@5572
   343
            (int(*)(void)) X11_GL_GetProcAddress(_this,
slouken@1952
   344
                                                   "glXGetSwapIntervalMESA");
slouken@1952
   345
    }
slouken@1952
   346
icculus@5572
   347
    /* Check for GLX_SGI_swap_control */
icculus@5572
   348
    if (HasExtension("GLX_SGI_swap_control", extensions)) {
icculus@5572
   349
        _this->gl_data->glXSwapIntervalSGI =
icculus@5572
   350
            (int (*)(int)) X11_GL_GetProcAddress(_this, "glXSwapIntervalSGI");
icculus@5572
   351
    }
icculus@5572
   352
slouken@1952
   353
    /* Check for GLX_EXT_visual_rating */
slouken@1952
   354
    if (HasExtension("GLX_EXT_visual_rating", extensions)) {
slouken@1952
   355
        _this->gl_data->HAS_GLX_EXT_visual_rating = SDL_TRUE;
slouken@1952
   356
    }
slouken@1952
   357
mikesart@6570
   358
    /* Check for GLX_EXT_visual_info */
mikesart@6570
   359
    if (HasExtension("GLX_EXT_visual_info", extensions)) {
mikesart@6570
   360
        _this->gl_data->HAS_GLX_EXT_visual_info = SDL_TRUE;
mikesart@6570
   361
    }
mikesart@6570
   362
slouken@1952
   363
    if (context) {
slouken@1952
   364
        _this->gl_data->glXMakeCurrent(display, None, NULL);
slouken@1952
   365
        _this->gl_data->glXDestroyContext(display, context);
slouken@1952
   366
    }
slouken@1952
   367
    XDestroyWindow(display, w);
bob@2323
   368
    X11_PumpEvents(_this);
slouken@1952
   369
}
slouken@1952
   370
slouken@6296
   371
/* glXChooseVisual and glXChooseFBConfig have some small differences in
slouken@7191
   372
 * the attribute encoding, it can be chosen with the for_FBConfig parameter.
slouken@6296
   373
 */
slouken@7191
   374
int
slouken@6296
   375
X11_GL_GetAttributes(_THIS, Display * display, int screen, int * attribs, int size, Bool for_FBConfig)
slouken@1952
   376
{
slouken@5395
   377
    int i = 0;
slouken@7191
   378
    const int MAX_ATTRIBUTES = 64;
slouken@1952
   379
slouken@7191
   380
    /* assert buffer is large enough to hold all SDL attributes. */
mikesart@6570
   381
    SDL_assert(size >= MAX_ATTRIBUTES);
slouken@3139
   382
slouken@1952
   383
    /* Setup our GLX attributes according to the gl_config. */
slouken@6296
   384
    if( for_FBConfig ) {
slouken@6296
   385
        attribs[i++] = GLX_RENDER_TYPE;
slouken@7191
   386
    attribs[i++] = GLX_RGBA_BIT;
slouken@6296
   387
    } else {
slouken@6296
   388
        attribs[i++] = GLX_RGBA;
slouken@6296
   389
    }
slouken@1952
   390
    attribs[i++] = GLX_RED_SIZE;
slouken@1952
   391
    attribs[i++] = _this->gl_config.red_size;
slouken@1952
   392
    attribs[i++] = GLX_GREEN_SIZE;
slouken@1952
   393
    attribs[i++] = _this->gl_config.green_size;
slouken@1952
   394
    attribs[i++] = GLX_BLUE_SIZE;
slouken@1952
   395
    attribs[i++] = _this->gl_config.blue_size;
slouken@1952
   396
slouken@1952
   397
    if (_this->gl_config.alpha_size) {
slouken@1952
   398
        attribs[i++] = GLX_ALPHA_SIZE;
slouken@1952
   399
        attribs[i++] = _this->gl_config.alpha_size;
slouken@1952
   400
    }
slouken@1952
   401
slouken@1952
   402
    if (_this->gl_config.double_buffer) {
slouken@1952
   403
        attribs[i++] = GLX_DOUBLEBUFFER;
slouken@7191
   404
    if( for_FBConfig )
slouken@7191
   405
        attribs[i++] = True;
slouken@1952
   406
    }
slouken@1952
   407
slouken@1952
   408
    attribs[i++] = GLX_DEPTH_SIZE;
slouken@1952
   409
    attribs[i++] = _this->gl_config.depth_size;
slouken@1952
   410
slouken@1952
   411
    if (_this->gl_config.stencil_size) {
slouken@1952
   412
        attribs[i++] = GLX_STENCIL_SIZE;
slouken@1952
   413
        attribs[i++] = _this->gl_config.stencil_size;
slouken@1952
   414
    }
slouken@1952
   415
slouken@1952
   416
    if (_this->gl_config.accum_red_size) {
slouken@1952
   417
        attribs[i++] = GLX_ACCUM_RED_SIZE;
slouken@1952
   418
        attribs[i++] = _this->gl_config.accum_red_size;
slouken@1952
   419
    }
slouken@1952
   420
slouken@1952
   421
    if (_this->gl_config.accum_green_size) {
slouken@1952
   422
        attribs[i++] = GLX_ACCUM_GREEN_SIZE;
slouken@1952
   423
        attribs[i++] = _this->gl_config.accum_green_size;
slouken@1952
   424
    }
slouken@1952
   425
slouken@1952
   426
    if (_this->gl_config.accum_blue_size) {
slouken@1952
   427
        attribs[i++] = GLX_ACCUM_BLUE_SIZE;
slouken@1952
   428
        attribs[i++] = _this->gl_config.accum_blue_size;
slouken@1952
   429
    }
slouken@1952
   430
slouken@1952
   431
    if (_this->gl_config.accum_alpha_size) {
slouken@1952
   432
        attribs[i++] = GLX_ACCUM_ALPHA_SIZE;
slouken@1952
   433
        attribs[i++] = _this->gl_config.accum_alpha_size;
slouken@1952
   434
    }
slouken@1952
   435
slouken@1952
   436
    if (_this->gl_config.stereo) {
slouken@1952
   437
        attribs[i++] = GLX_STEREO;
slouken@7191
   438
    if( for_FBConfig )
slouken@7191
   439
        attribs[i++] = True;
slouken@1952
   440
    }
slouken@1952
   441
slouken@1952
   442
    if (_this->gl_config.multisamplebuffers) {
slouken@1952
   443
        attribs[i++] = GLX_SAMPLE_BUFFERS_ARB;
slouken@1952
   444
        attribs[i++] = _this->gl_config.multisamplebuffers;
slouken@1952
   445
    }
slouken@1952
   446
slouken@1952
   447
    if (_this->gl_config.multisamplesamples) {
slouken@1952
   448
        attribs[i++] = GLX_SAMPLES_ARB;
slouken@1952
   449
        attribs[i++] = _this->gl_config.multisamplesamples;
slouken@1952
   450
    }
slouken@1952
   451
slouken@3571
   452
    if (_this->gl_config.accelerated >= 0 &&
slouken@3571
   453
        _this->gl_data->HAS_GLX_EXT_visual_rating) {
slouken@1952
   454
        attribs[i++] = GLX_VISUAL_CAVEAT_EXT;
slouken@3570
   455
        attribs[i++] = _this->gl_config.accelerated ? GLX_NONE_EXT :
slouken@3570
   456
                                                      GLX_SLOW_VISUAL_EXT;
slouken@1952
   457
    }
slouken@3570
   458
icculus@6817
   459
    /* If we're supposed to use DirectColor visuals, and we've got the
icculus@6817
   460
       EXT_visual_info extension, then add GLX_X_VISUAL_TYPE_EXT. */
mikesart@6570
   461
    if (X11_UseDirectColorVisuals() &&
mikesart@6570
   462
        _this->gl_data->HAS_GLX_EXT_visual_info) {
mikesart@6570
   463
        attribs[i++] = GLX_X_VISUAL_TYPE_EXT;
mikesart@6570
   464
        attribs[i++] = GLX_DIRECT_COLOR_EXT;
mikesart@6570
   465
    }
mikesart@6570
   466
slouken@1952
   467
    attribs[i++] = None;
mikesart@6570
   468
mikesart@6570
   469
    SDL_assert(i <= MAX_ATTRIBUTES);
slouken@7191
   470
slouken@5395
   471
    return i;
slouken@5395
   472
}
slouken@5395
   473
slouken@5395
   474
XVisualInfo *
slouken@5395
   475
X11_GL_GetVisual(_THIS, Display * display, int screen)
slouken@5395
   476
{
slouken@5395
   477
    XVisualInfo *vinfo;
slouken@5395
   478
slouken@5395
   479
    /* 64 seems nice. */
slouken@6296
   480
    int attribs[64];
icculus@6359
   481
    X11_GL_GetAttributes(_this,display,screen,attribs,64,SDL_FALSE);
slouken@1952
   482
slouken@6181
   483
    if (!_this->gl_data) {
slouken@6181
   484
        /* The OpenGL library wasn't loaded, SDL_GetError() should have info */
slouken@6181
   485
        return NULL;
slouken@6181
   486
    }
slouken@6181
   487
slouken@1952
   488
    vinfo = _this->gl_data->glXChooseVisual(display, screen, attribs);
slouken@1952
   489
    if (!vinfo) {
slouken@1952
   490
        SDL_SetError("Couldn't find matching GLX visual");
slouken@1952
   491
    }
slouken@1952
   492
    return vinfo;
slouken@1952
   493
}
slouken@1952
   494
slouken@6988
   495
#ifndef GLXBadContext
slouken@6988
   496
#define GLXBadContext 0
slouken@6988
   497
#endif
slouken@6988
   498
#ifndef GLXBadFBConfig
slouken@6988
   499
#define GLXBadFBConfig 9
slouken@6988
   500
#endif
slouken@6988
   501
#ifndef GLXBadProfileARB
slouken@6988
   502
#define GLXBadProfileARB 13
slouken@6988
   503
#endif
slouken@6988
   504
static int (*handler) (Display *, XErrorEvent *) = NULL;
slouken@6988
   505
static int
slouken@6988
   506
X11_GL_CreateContextErrorHandler(Display * d, XErrorEvent * e)
slouken@6988
   507
{
slouken@6988
   508
    switch (e->error_code) {
slouken@6988
   509
    case GLXBadContext:
slouken@6988
   510
    case GLXBadFBConfig:
slouken@6988
   511
    case GLXBadProfileARB:
slouken@6988
   512
    case BadRequest:
slouken@6988
   513
    case BadMatch:
slouken@6988
   514
    case BadValue:
slouken@6988
   515
    case BadAlloc:
slouken@6988
   516
        return (0);
slouken@6988
   517
    default:
slouken@6988
   518
        return (handler(d, e));
slouken@6988
   519
    }
slouken@6988
   520
}
slouken@6988
   521
slouken@1952
   522
SDL_GLContext
slouken@1952
   523
X11_GL_CreateContext(_THIS, SDL_Window * window)
slouken@1952
   524
{
slouken@1952
   525
    SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
slouken@1952
   526
    Display *display = data->videodata->display;
slouken@1952
   527
    int screen =
slouken@5246
   528
        ((SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata)->screen;
slouken@1952
   529
    XWindowAttributes xattr;
slouken@1952
   530
    XVisualInfo v, *vinfo;
slouken@1952
   531
    int n;
slouken@6393
   532
    GLXContext context = NULL, share_context;
slouken@6393
   533
slouken@6393
   534
    if (_this->gl_config.share_with_current_context) {
slouken@7412
   535
        share_context = SDL_GL_GetCurrentContext();
slouken@6393
   536
    } else {
slouken@6393
   537
        share_context = NULL;
slouken@6393
   538
    }
slouken@1952
   539
slouken@1955
   540
    /* We do this to create a clean separation between X and GLX errors. */
slouken@1952
   541
    XSync(display, False);
slouken@6988
   542
    handler = XSetErrorHandler(X11_GL_CreateContextErrorHandler);
slouken@3685
   543
    XGetWindowAttributes(display, data->xwindow, &xattr);
slouken@1952
   544
    v.screen = screen;
slouken@1952
   545
    v.visualid = XVisualIDFromVisual(xattr.visual);
slouken@1952
   546
    vinfo = XGetVisualInfo(display, VisualScreenMask | VisualIDMask, &v, &n);
slouken@1952
   547
    if (vinfo) {
slouken@6393
   548
        if (_this->gl_config.major_version < 3 &&
slouken@6393
   549
            _this->gl_config.profile_mask == 0 &&
slouken@6393
   550
            _this->gl_config.flags == 0) {
slouken@6393
   551
            /* Create legacy context */
slouken@3100
   552
            context =
slouken@6393
   553
                _this->gl_data->glXCreateContext(display, vinfo, share_context, True);
slouken@3100
   554
        } else {
slouken@3100
   555
            /* If we want a GL 3.0 context or later we need to get a temporary
slouken@3100
   556
               context to grab the new context creation function */
slouken@3139
   557
            GLXContext temp_context =
slouken@3139
   558
                _this->gl_data->glXCreateContext(display, vinfo, NULL, True);
slouken@6988
   559
            if (temp_context) {
slouken@6393
   560
                /* max 8 attributes plus terminator */
slouken@6296
   561
                int attribs[9] = {
slouken@3139
   562
                    GLX_CONTEXT_MAJOR_VERSION_ARB,
slouken@3139
   563
                    _this->gl_config.major_version,
slouken@3139
   564
                    GLX_CONTEXT_MINOR_VERSION_ARB,
slouken@3139
   565
                    _this->gl_config.minor_version,
slouken@3139
   566
                    0
slouken@3100
   567
                };
slouken@6393
   568
                int iattr = 4;
slouken@6296
   569
slouken@6393
   570
                /* SDL profile bits match GLX profile bits */
slouken@6393
   571
                if( _this->gl_config.profile_mask != 0 ) {
slouken@6393
   572
                    attribs[iattr++] = GLX_CONTEXT_PROFILE_MASK_ARB;
slouken@6393
   573
                    attribs[iattr++] = _this->gl_config.profile_mask;
slouken@6393
   574
                }
slouken@6296
   575
slouken@6393
   576
                /* SDL flags match GLX flags */
slouken@6393
   577
                if( _this->gl_config.flags != 0 ) {
slouken@6393
   578
                    attribs[iattr++] = GLX_CONTEXT_FLAGS_ARB;
slouken@6393
   579
                    attribs[iattr++] = _this->gl_config.flags;
slouken@6393
   580
                }
slouken@6296
   581
slouken@6393
   582
                attribs[iattr++] = 0;
slouken@3139
   583
slouken@3100
   584
                /* Get a pointer to the context creation function for GL 3.0 */
slouken@3139
   585
                PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribs =
slouken@3139
   586
                    (PFNGLXCREATECONTEXTATTRIBSARBPROC) _this->gl_data->
slouken@3139
   587
                    glXGetProcAddress((GLubyte *)
slouken@3139
   588
                                      "glXCreateContextAttribsARB");
slouken@3100
   589
                if (!glXCreateContextAttribs) {
slouken@3100
   590
                    SDL_SetError("GL 3.x is not supported");
slouken@3100
   591
                    context = temp_context;
slouken@3100
   592
                } else {
slouken@5395
   593
                    int glxAttribs[64];
slouken@5395
   594
slouken@3105
   595
                    /* Create a GL 3.x context */
slouken@3100
   596
                    GLXFBConfig *framebuffer_config = NULL;
slouken@3139
   597
                    int fbcount = 0;
slouken@3139
   598
                    GLXFBConfig *(*glXChooseFBConfig) (Display * disp,
slouken@3139
   599
                                                       int screen,
slouken@3139
   600
                                                       const int *attrib_list,
slouken@3139
   601
                                                       int *nelements);
slouken@3105
   602
slouken@3139
   603
                    glXChooseFBConfig =
slouken@3139
   604
                        (GLXFBConfig *
slouken@3139
   605
                         (*)(Display *, int, const int *,
slouken@3139
   606
                             int *)) _this->gl_data->
slouken@3139
   607
                        glXGetProcAddress((GLubyte *) "glXChooseFBConfig");
slouken@3105
   608
slouken@6296
   609
                    X11_GL_GetAttributes(_this,display,screen,glxAttribs,64,SDL_TRUE);
slouken@5395
   610
slouken@3139
   611
                    if (!glXChooseFBConfig
slouken@3139
   612
                        || !(framebuffer_config =
slouken@3139
   613
                             glXChooseFBConfig(display,
slouken@5395
   614
                                               DefaultScreen(display), glxAttribs,
slouken@3139
   615
                                               &fbcount))) {
slouken@3139
   616
                        SDL_SetError
slouken@3139
   617
                            ("No good framebuffers found. GL 3.x disabled");
slouken@3100
   618
                        context = temp_context;
slouken@3139
   619
                    } else {
slouken@3139
   620
                        context =
slouken@3139
   621
                            glXCreateContextAttribs(display,
slouken@3139
   622
                                                    framebuffer_config[0],
slouken@6393
   623
                                                    share_context, True, attribs);
slouken@3139
   624
                        _this->gl_data->glXDestroyContext(display,
slouken@3139
   625
                                                          temp_context);
slouken@3100
   626
                    }
slouken@3100
   627
                }
slouken@3100
   628
            }
slouken@3100
   629
        }
slouken@1952
   630
        XFree(vinfo);
slouken@1952
   631
    }
slouken@1952
   632
    XSync(display, False);
slouken@6988
   633
    XSetErrorHandler(handler);
slouken@7191
   634
slouken@1952
   635
    if (!context) {
slouken@1952
   636
        SDL_SetError("Could not create GL context");
slouken@2178
   637
        return NULL;
slouken@1952
   638
    }
slouken@2178
   639
slouken@2178
   640
    if (X11_GL_MakeCurrent(_this, window, context) < 0) {
slouken@2178
   641
        X11_GL_DeleteContext(_this, context);
slouken@2178
   642
        return NULL;
slouken@2178
   643
    }
slouken@2178
   644
slouken@2178
   645
    return context;
slouken@1952
   646
}
slouken@1952
   647
slouken@1952
   648
int
slouken@1952
   649
X11_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
slouken@1952
   650
{
slouken@1952
   651
    Display *display = ((SDL_VideoData *) _this->driverdata)->display;
slouken@1952
   652
    Window drawable =
urkle@6794
   653
        (context ? ((SDL_WindowData *) window->driverdata)->xwindow : None);
slouken@1952
   654
    GLXContext glx_context = (GLXContext) context;
slouken@1952
   655
slouken@6522
   656
    if (!_this->gl_data) {
icculus@7037
   657
        return SDL_SetError("OpenGL not initialized");
slouken@6522
   658
    }
slouken@6522
   659
slouken@1952
   660
    if (!_this->gl_data->glXMakeCurrent(display, drawable, glx_context)) {
icculus@7037
   661
        return SDL_SetError("Unable to make GL context current");
slouken@1952
   662
    }
slouken@1952
   663
icculus@7037
   664
    return 0;
slouken@1952
   665
}
slouken@1952
   666
slouken@7191
   667
/*
icculus@5572
   668
   0 is a valid argument to glxSwapInterval(MESA|EXT) and setting it to 0
icculus@5572
   669
   will undo the effect of a previous call with a value that is greater
icculus@5572
   670
   than zero (or at least that is what the docs say). OTOH, 0 is an invalid
icculus@5572
   671
   argument to glxSwapIntervalSGI and it returns an error if you call it
icculus@5572
   672
   with 0 as an argument.
bob@2327
   673
*/
bob@2327
   674
bob@2327
   675
static int swapinterval = -1;
slouken@1952
   676
int
slouken@1952
   677
X11_GL_SetSwapInterval(_THIS, int interval)
slouken@1952
   678
{
icculus@6382
   679
    int status = -1;
slouken@1952
   680
icculus@6382
   681
    if ((interval < 0) && (!_this->gl_data->HAS_GLX_EXT_swap_control_tear)) {
icculus@6382
   682
        SDL_SetError("Negative swap interval unsupported in this GL");
icculus@6382
   683
    } else if (_this->gl_data->glXSwapIntervalEXT) {
icculus@5572
   684
        Display *display = ((SDL_VideoData *) _this->driverdata)->display;
icculus@5572
   685
        const SDL_WindowData *windowdata = (SDL_WindowData *)
slouken@7412
   686
            SDL_GL_GetCurrentWindow()->driverdata;
slouken@6846
   687
icculus@5572
   688
        Window drawable = windowdata->xwindow;
slouken@6846
   689
slouken@6846
   690
        /*
slouken@6846
   691
         * This is a workaround for a bug in NVIDIA drivers. Bug has been reported
slouken@6846
   692
         * and will be fixed in a future release (probably 319.xx).
slouken@6846
   693
         *
slouken@6846
   694
         * There's a bug where glXSetSwapIntervalEXT ignores updates because
slouken@6846
   695
         * it has the wrong value cached. To work around it, we just run a no-op
slouken@6846
   696
         * update to the current value.
slouken@6846
   697
         */
slouken@6851
   698
        int currentInterval = X11_GL_GetSwapInterval(_this);
slouken@6846
   699
        _this->gl_data->glXSwapIntervalEXT(display, drawable, currentInterval);
slouken@6846
   700
        _this->gl_data->glXSwapIntervalEXT(display, drawable, interval);
slouken@6846
   701
slouken@6846
   702
        status = 0;
slouken@6846
   703
        swapinterval = interval;
icculus@5572
   704
    } else if (_this->gl_data->glXSwapIntervalMESA) {
slouken@1952
   705
        status = _this->gl_data->glXSwapIntervalMESA(interval);
slouken@1952
   706
        if (status != 0) {
slouken@1952
   707
            SDL_SetError("glxSwapIntervalMESA failed");
bob@2327
   708
        } else {
bob@2327
   709
            swapinterval = interval;
slouken@1952
   710
        }
slouken@1952
   711
    } else if (_this->gl_data->glXSwapIntervalSGI) {
slouken@1952
   712
        status = _this->gl_data->glXSwapIntervalSGI(interval);
slouken@1952
   713
        if (status != 0) {
slouken@1952
   714
            SDL_SetError("glxSwapIntervalSGI failed");
bob@2327
   715
        } else {
bob@2327
   716
            swapinterval = interval;
slouken@1952
   717
        }
slouken@1952
   718
    } else {
slouken@1952
   719
        SDL_Unsupported();
slouken@1952
   720
    }
slouken@1952
   721
    return status;
slouken@1952
   722
}
slouken@1952
   723
slouken@1952
   724
int
slouken@1952
   725
X11_GL_GetSwapInterval(_THIS)
slouken@1952
   726
{
icculus@5572
   727
    if (_this->gl_data->glXSwapIntervalEXT) {
icculus@5572
   728
        Display *display = ((SDL_VideoData *) _this->driverdata)->display;
icculus@5572
   729
        const SDL_WindowData *windowdata = (SDL_WindowData *)
slouken@7412
   730
            SDL_GL_GetCurrentWindow()->driverdata;
icculus@5572
   731
        Window drawable = windowdata->xwindow;
icculus@6382
   732
        unsigned int allow_late_swap_tearing = 0;
icculus@6382
   733
        unsigned int interval = 0;
icculus@6382
   734
icculus@6382
   735
        if (_this->gl_data->HAS_GLX_EXT_swap_control_tear) {
icculus@6382
   736
            _this->gl_data->glXQueryDrawable(display, drawable,
icculus@6382
   737
                                            GLX_LATE_SWAPS_TEAR_EXT,
icculus@6382
   738
                                            &allow_late_swap_tearing);
icculus@6382
   739
        }
icculus@6382
   740
icculus@5572
   741
        _this->gl_data->glXQueryDrawable(display, drawable,
icculus@6382
   742
                                         GLX_SWAP_INTERVAL_EXT, &interval);
icculus@6382
   743
icculus@6382
   744
        if ((allow_late_swap_tearing) && (interval > 0)) {
icculus@6382
   745
            return -((int) interval);
icculus@6382
   746
        }
icculus@6382
   747
icculus@6382
   748
        return (int) interval;
icculus@5572
   749
    } else if (_this->gl_data->glXGetSwapIntervalMESA) {
slouken@1952
   750
        return _this->gl_data->glXGetSwapIntervalMESA();
slouken@1952
   751
    } else {
bob@2327
   752
        return swapinterval;
slouken@1952
   753
    }
slouken@1952
   754
}
slouken@1952
   755
slouken@1952
   756
void
slouken@1952
   757
X11_GL_SwapWindow(_THIS, SDL_Window * window)
slouken@1952
   758
{
slouken@1952
   759
    SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
slouken@1952
   760
    Display *display = data->videodata->display;
slouken@1952
   761
slouken@3685
   762
    _this->gl_data->glXSwapBuffers(display, data->xwindow);
slouken@1952
   763
}
slouken@1952
   764
slouken@1952
   765
void
slouken@1952
   766
X11_GL_DeleteContext(_THIS, SDL_GLContext context)
slouken@1952
   767
{
slouken@1952
   768
    Display *display = ((SDL_VideoData *) _this->driverdata)->display;
slouken@1952
   769
    GLXContext glx_context = (GLXContext) context;
slouken@1952
   770
slouken@6522
   771
    if (!_this->gl_data) {
slouken@6522
   772
        return;
slouken@6522
   773
    }
slouken@1952
   774
    _this->gl_data->glXDestroyContext(display, glx_context);
bob@2324
   775
    XSync(display, False);
slouken@1952
   776
}
slouken@1952
   777
slouken@1952
   778
#endif /* SDL_VIDEO_OPENGL_GLX */
slouken@1952
   779
slouken@6044
   780
#endif /* SDL_VIDEO_DRIVER_X11 */
slouken@6044
   781
slouken@1952
   782
/* vi: set ts=4 sw=4 expandtab: */