src/video/x11/SDL_x11opengl.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 18 Jul 2012 15:17:27 -0700
changeset 6370 93187f7f7d5d
parent 6360 efd48af40ec3
child 6373 494e0436525f
permissions -rwxr-xr-x
Improved simultaneous support for OpenGL and OpenGL ES

From Scott Percival

Okay, I think I have something for this. Tested it on GL and GLES
machines, it seems to work okay.

- Add a new SDL GL attribute SDL_GL_CONTEXT_EGL:
- Only useful for the X11 video driver at the moment
- Set to 1 for an EGL context, 0 to use the default for the video driver
- Default is 0, unless library is built for EGL only
- Should be set after SDL init, but before window/context
creation (i.e. same place you'd specify attributes for major/minor GL
version)
- After a lot of agony pondering the least-terrible way to go about
it, made it so that X11_GL_LoadLibrary and X11_GLES_LoadLibrary check
SDL_GL_CONTEXT_EGL. If no GL context exists yet, and the attribute
choice doesn't match with the checking function, then it changes all
the function pointers in the video driver and passes control on to the
new LoadLibrary method.
- Likewise, make X11_CreateWindow check this attribute before firing
off a call to X11_GL_GetVisual/X11_GLES_GetVisual
- Added a sanity check to the start of X11_GL_LoadLibrary
- Tidied up SDL_x11opengles.h
- Moved ownership of the gles_data structure over to
X11_GLES_LoadLibrary/UnloadLibrary
- Should incorporate the 3 fixes posted by Andre Heider

This is obviously quite a bit to take in, but is (at least) a proof of
concept for the approach I think EGL/GLX mingling should take. Any
comments/criticism is much appreciated.
slouken@1952
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@6138
     3
  Copyright (C) 1997-2012 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@1952
    36
#define DEFAULT_OPENGL	"libGL.so"
slouken@1952
    37
#elif defined(__MACOSX__)
slouken@1952
    38
#define DEFAULT_OPENGL	"/usr/X11R6/lib/libGL.1.dylib"
slouken@1952
    39
#elif defined(__QNXNTO__)
slouken@1952
    40
#define DEFAULT_OPENGL	"libGL.so.3"
slouken@1952
    41
#else
slouken@1952
    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
slouken@3100
    63
#ifndef GLX_ARB_create_context
slouken@3100
    64
#define GLX_ARB_create_context
slouken@3100
    65
#define GLX_CONTEXT_MAJOR_VERSION_ARB      0x2091
slouken@3100
    66
#define GLX_CONTEXT_MINOR_VERSION_ARB      0x2092
slouken@3100
    67
#define GLX_CONTEXT_FLAGS_ARB              0x2094
slouken@3100
    68
#define GLX_CONTEXT_DEBUG_BIT_ARB          0x0001
slouken@3100
    69
#define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002
slouken@5021
    70
slouken@5021
    71
/* Typedef for the GL 3.0 context creation function */
slouken@5021
    72
typedef GLXContext(*PFNGLXCREATECONTEXTATTRIBSARBPROC) (Display * dpy,
slouken@5021
    73
                                                        GLXFBConfig config,
slouken@5021
    74
                                                        GLXContext
slouken@5021
    75
                                                        share_context,
slouken@5021
    76
                                                        Bool direct,
slouken@5021
    77
                                                        const int
slouken@5021
    78
                                                        *attrib_list);
icculus@6360
    79
#endif
slouken@6296
    80
slouken@6296
    81
#ifndef GLX_ARB_create_context_profile
slouken@6296
    82
#define GLX_ARB_create_context_profile
slouken@6296
    83
#define GLX_CONTEXT_PROFILE_MASK_ARB       0x9126
slouken@6296
    84
#define GLX_CONTEXT_CORE_PROFILE_BIT_ARB   0x00000001
slouken@6296
    85
#define GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
slouken@6296
    86
#endif
slouken@6296
    87
slouken@6296
    88
#ifndef GLX_ARB_create_context_robustness
slouken@6296
    89
#define GLX_ARB_create_context_robustness
slouken@6296
    90
#define GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB  0x00000004
slouken@6296
    91
#define GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB     0x8256
slouken@6296
    92
#define GLX_NO_RESET_NOTIFICATION_ARB                   0x8261
slouken@6296
    93
#define GLX_LOSE_CONTEXT_ON_RESET_ARB                   0x8252
slouken@6296
    94
#endif
slouken@6296
    95
slouken@6296
    96
#ifndef GLX_EXT_create_context_es2_profile
slouken@6296
    97
#define GLX_EXT_create_context_es2_profile
slouken@6296
    98
#define GLX_CONTEXT_ES2_PROFILE_BIT_EXT    0x00000002
slouken@6296
    99
#endif
slouken@6296
   100
slouken@6296
   101
#ifndef GLX_EXT_swap_control
slouken@6296
   102
#define GLX_SWAP_INTERVAL_EXT              0x20F1
slouken@6296
   103
#define GLX_MAX_SWAP_INTERVAL_EXT          0x20F2
slouken@3100
   104
#endif
slouken@3100
   105
slouken@6183
   106
#define OPENGL_REQUIRES_DLOPEN
slouken@6183
   107
#if defined(OPENGL_REQUIRES_DLOPEN) && defined(SDL_LOADSO_DLOPEN)
slouken@1952
   108
#include <dlfcn.h>
slouken@1952
   109
#define GL_LoadObject(X)	dlopen(X, (RTLD_NOW|RTLD_GLOBAL))
slouken@1952
   110
#define GL_LoadFunction		dlsym
slouken@1952
   111
#define GL_UnloadObject		dlclose
slouken@1952
   112
#else
slouken@1952
   113
#define GL_LoadObject	SDL_LoadObject
slouken@1952
   114
#define GL_LoadFunction	SDL_LoadFunction
slouken@1952
   115
#define GL_UnloadObject	SDL_UnloadObject
slouken@1952
   116
#endif
slouken@1952
   117
slouken@3057
   118
static void X11_GL_InitExtensions(_THIS);
bob@2322
   119
slouken@3100
   120
slouken@1952
   121
int
slouken@1952
   122
X11_GL_LoadLibrary(_THIS, const char *path)
slouken@1952
   123
{
slouken@1952
   124
    void *handle;
slouken@1952
   125
slouken@6370
   126
    if (_this->gl_data) {
slouken@6370
   127
        SDL_SetError("OpenGL context already created");
slouken@6370
   128
        return -1;
slouken@6370
   129
    }
slouken@6370
   130
slouken@6370
   131
#if SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
slouken@6370
   132
    /* If SDL_GL_CONTEXT_EGL has been changed to 1, switch over to X11_GLES functions  */
slouken@6370
   133
    if (_this->gl_config.use_egl == 1) {
slouken@6370
   134
        _this->GL_LoadLibrary = X11_GLES_LoadLibrary;
slouken@6370
   135
        _this->GL_GetProcAddress = X11_GLES_GetProcAddress;
slouken@6370
   136
        _this->GL_UnloadLibrary = X11_GLES_UnloadLibrary;
slouken@6370
   137
        _this->GL_CreateContext = X11_GLES_CreateContext;
slouken@6370
   138
        _this->GL_MakeCurrent = X11_GLES_MakeCurrent;
slouken@6370
   139
        _this->GL_SetSwapInterval = X11_GLES_SetSwapInterval;
slouken@6370
   140
        _this->GL_GetSwapInterval = X11_GLES_GetSwapInterval;
slouken@6370
   141
        _this->GL_SwapWindow = X11_GLES_SwapWindow;
slouken@6370
   142
        _this->GL_DeleteContext = X11_GLES_DeleteContext;
slouken@6370
   143
        return X11_GLES_LoadLibrary(_this, path);
slouken@6370
   144
    }
slouken@6370
   145
#endif
slouken@6370
   146
slouken@6370
   147
slouken@3057
   148
    /* Load the OpenGL library */
slouken@3057
   149
    if (path == NULL) {
slouken@3057
   150
        path = SDL_getenv("SDL_OPENGL_LIBRARY");
slouken@1952
   151
    }
slouken@3057
   152
    if (path == NULL) {
slouken@3057
   153
        path = DEFAULT_OPENGL;
slouken@3057
   154
    }
slouken@6183
   155
    _this->gl_config.dll_handle = GL_LoadObject(path);
slouken@3057
   156
    if (!_this->gl_config.dll_handle) {
slouken@6183
   157
#if defined(OPENGL_REQUIRES_DLOPEN) && defined(SDL_LOADSO_DLOPEN)
slouken@6183
   158
        SDL_SetError("Failed loading %s: %s", path, dlerror());
slouken@6183
   159
#endif
slouken@3057
   160
        return -1;
slouken@3057
   161
    }
slouken@3057
   162
    SDL_strlcpy(_this->gl_config.driver_path, path,
slouken@3057
   163
                SDL_arraysize(_this->gl_config.driver_path));
slouken@2244
   164
slouken@3057
   165
    /* Allocate OpenGL memory */
slouken@3057
   166
    _this->gl_data =
slouken@3057
   167
        (struct SDL_GLDriverData *) SDL_calloc(1,
slouken@3057
   168
                                               sizeof(struct
slouken@3057
   169
                                                      SDL_GLDriverData));
slouken@3057
   170
    if (!_this->gl_data) {
slouken@3057
   171
        SDL_OutOfMemory();
slouken@3057
   172
        return -1;
slouken@3057
   173
    }
slouken@3057
   174
slouken@3057
   175
    /* Load function pointers */
slouken@3057
   176
    handle = _this->gl_config.dll_handle;
slouken@1952
   177
    _this->gl_data->glXGetProcAddress =
slouken@4550
   178
        (void *(*)(const GLubyte *))
slouken@4550
   179
            GL_LoadFunction(handle, "glXGetProcAddressARB");
slouken@1952
   180
    _this->gl_data->glXChooseVisual =
slouken@4550
   181
        (XVisualInfo * (*)(Display *, int, int *))
slouken@4550
   182
            X11_GL_GetProcAddress(_this, "glXChooseVisual");
slouken@1952
   183
    _this->gl_data->glXCreateContext =
slouken@1952
   184
        (GLXContext(*)(Display *, XVisualInfo *, GLXContext, int))
slouken@4550
   185
            X11_GL_GetProcAddress(_this, "glXCreateContext");
slouken@1952
   186
    _this->gl_data->glXDestroyContext =
slouken@4550
   187
        (void (*)(Display *, GLXContext))
slouken@4550
   188
            X11_GL_GetProcAddress(_this, "glXDestroyContext");
slouken@1952
   189
    _this->gl_data->glXMakeCurrent =
slouken@4550
   190
        (int (*)(Display *, GLXDrawable, GLXContext))
slouken@4550
   191
            X11_GL_GetProcAddress(_this, "glXMakeCurrent");
slouken@1952
   192
    _this->gl_data->glXSwapBuffers =
slouken@4550
   193
        (void (*)(Display *, GLXDrawable))
slouken@4550
   194
            X11_GL_GetProcAddress(_this, "glXSwapBuffers");
icculus@5572
   195
    _this->gl_data->glXQueryDrawable =
icculus@5572
   196
        (void (*)(Display*,GLXDrawable,int,unsigned int*))
icculus@5572
   197
            X11_GL_GetProcAddress(_this, "glXQueryDrawable");
slouken@1952
   198
slouken@1952
   199
    if (!_this->gl_data->glXChooseVisual ||
slouken@1952
   200
        !_this->gl_data->glXCreateContext ||
slouken@1952
   201
        !_this->gl_data->glXDestroyContext ||
slouken@4550
   202
        !_this->gl_data->glXMakeCurrent ||
slouken@4550
   203
        !_this->gl_data->glXSwapBuffers) {
slouken@1952
   204
        SDL_SetError("Could not retrieve OpenGL functions");
slouken@1952
   205
        return -1;
slouken@1952
   206
    }
slouken@1952
   207
slouken@3057
   208
    /* Initialize extensions */
slouken@3057
   209
    X11_GL_InitExtensions(_this);
slouken@3057
   210
slouken@1952
   211
    return 0;
slouken@1952
   212
}
slouken@1952
   213
slouken@1952
   214
void *
slouken@1952
   215
X11_GL_GetProcAddress(_THIS, const char *proc)
slouken@1952
   216
{
slouken@1952
   217
    if (_this->gl_data->glXGetProcAddress) {
slouken@1952
   218
        return _this->gl_data->glXGetProcAddress((const GLubyte *) proc);
slouken@1952
   219
    }
slouken@4550
   220
    return GL_LoadFunction(_this->gl_config.dll_handle, proc);
slouken@1952
   221
}
slouken@1952
   222
slouken@3057
   223
void
slouken@1952
   224
X11_GL_UnloadLibrary(_THIS)
slouken@1952
   225
{
slouken@3057
   226
    /* Don't actually unload the library, since it may have registered
slouken@3057
   227
     * X11 shutdown hooks, per the notes at:
slouken@3057
   228
     * http://dri.sourceforge.net/doc/DRIuserguide.html
slouken@3057
   229
     */
slouken@3057
   230
#if 0
slouken@3057
   231
    GL_UnloadObject(_this->gl_config.dll_handle);
slouken@3057
   232
    _this->gl_config.dll_handle = NULL;
slouken@3057
   233
#endif
slouken@3057
   234
slouken@3057
   235
    /* Free OpenGL memory */
slouken@6181
   236
    if (_this->gl_data) {
slouken@6181
   237
        SDL_free(_this->gl_data);
slouken@6181
   238
        _this->gl_data = NULL;
slouken@6181
   239
    }
slouken@1952
   240
}
slouken@1952
   241
slouken@1952
   242
static SDL_bool
slouken@1952
   243
HasExtension(const char *extension, const char *extensions)
slouken@1952
   244
{
slouken@1952
   245
    const char *start;
slouken@1952
   246
    const char *where, *terminator;
slouken@1952
   247
slouken@1952
   248
    /* Extension names should not have spaces. */
slouken@1952
   249
    where = SDL_strchr(extension, ' ');
slouken@1952
   250
    if (where || *extension == '\0')
slouken@1952
   251
        return SDL_FALSE;
slouken@1952
   252
slouken@1952
   253
    if (!extensions)
slouken@1952
   254
        return SDL_FALSE;
slouken@1952
   255
slouken@1952
   256
    /* It takes a bit of care to be fool-proof about parsing the
slouken@1952
   257
     * OpenGL extensions string. Don't be fooled by sub-strings,
slouken@1952
   258
     * etc. */
slouken@1952
   259
slouken@1952
   260
    start = extensions;
slouken@1952
   261
slouken@1952
   262
    for (;;) {
slouken@1952
   263
        where = SDL_strstr(start, extension);
slouken@1952
   264
        if (!where)
slouken@1952
   265
            break;
slouken@1952
   266
slouken@1952
   267
        terminator = where + SDL_strlen(extension);
slouken@1952
   268
        if (where == start || *(where - 1) == ' ')
slouken@1952
   269
            if (*terminator == ' ' || *terminator == '\0')
slouken@1952
   270
                return SDL_TRUE;
slouken@1952
   271
slouken@1952
   272
        start = terminator;
slouken@1952
   273
    }
slouken@1952
   274
    return SDL_FALSE;
slouken@1952
   275
}
slouken@1952
   276
slouken@1952
   277
static void
slouken@1952
   278
X11_GL_InitExtensions(_THIS)
slouken@1952
   279
{
slouken@1952
   280
    Display *display = ((SDL_VideoData *) _this->driverdata)->display;
slouken@5244
   281
    int screen = DefaultScreen(display);
slouken@1952
   282
    XVisualInfo *vinfo;
slouken@1952
   283
    XSetWindowAttributes xattr;
slouken@1952
   284
    Window w;
slouken@1952
   285
    GLXContext context;
slouken@1952
   286
    const char *(*glXQueryExtensionsStringFunc) (Display *, int);
slouken@1952
   287
    const char *extensions;
slouken@1952
   288
slouken@1952
   289
    vinfo = X11_GL_GetVisual(_this, display, screen);
slouken@1952
   290
    if (!vinfo) {
slouken@1952
   291
        return;
slouken@1952
   292
    }
slouken@1952
   293
    xattr.background_pixel = 0;
slouken@1952
   294
    xattr.border_pixel = 0;
slouken@1952
   295
    xattr.colormap =
slouken@1952
   296
        XCreateColormap(display, RootWindow(display, screen), vinfo->visual,
slouken@1952
   297
                        AllocNone);
slouken@1952
   298
    w = XCreateWindow(display, RootWindow(display, screen), 0, 0, 32, 32, 0,
slouken@1952
   299
                      vinfo->depth, InputOutput, vinfo->visual,
slouken@1952
   300
                      (CWBackPixel | CWBorderPixel | CWColormap), &xattr);
slouken@1952
   301
    context = _this->gl_data->glXCreateContext(display, vinfo, NULL, True);
slouken@1952
   302
    if (context) {
slouken@1952
   303
        _this->gl_data->glXMakeCurrent(display, w, context);
slouken@1952
   304
    }
slouken@1952
   305
    XFree(vinfo);
slouken@1952
   306
slouken@1952
   307
    glXQueryExtensionsStringFunc =
slouken@1952
   308
        (const char *(*)(Display *, int)) X11_GL_GetProcAddress(_this,
slouken@1952
   309
                                                                "glXQueryExtensionsString");
slouken@1952
   310
    if (glXQueryExtensionsStringFunc) {
slouken@1952
   311
        extensions = glXQueryExtensionsStringFunc(display, screen);
slouken@1952
   312
    } else {
slouken@1952
   313
        extensions = NULL;
slouken@1952
   314
    }
slouken@1952
   315
icculus@5572
   316
    /* Check for GLX_EXT_swap_control */
icculus@5572
   317
    if (HasExtension("GLX_EXT_swap_control", extensions)) {
icculus@5572
   318
        _this->gl_data->glXSwapIntervalEXT =
icculus@5630
   319
            (int (*)(Display*,GLXDrawable,int))
icculus@5572
   320
                X11_GL_GetProcAddress(_this, "glXSwapIntervalEXT");
slouken@1952
   321
    }
slouken@1952
   322
slouken@1952
   323
    /* Check for GLX_MESA_swap_control */
slouken@1952
   324
    if (HasExtension("GLX_MESA_swap_control", extensions)) {
slouken@1952
   325
        _this->gl_data->glXSwapIntervalMESA =
icculus@5572
   326
            (int(*)(int)) X11_GL_GetProcAddress(_this, "glXSwapIntervalMESA");
slouken@1952
   327
        _this->gl_data->glXGetSwapIntervalMESA =
icculus@5572
   328
            (int(*)(void)) X11_GL_GetProcAddress(_this,
slouken@1952
   329
                                                   "glXGetSwapIntervalMESA");
slouken@1952
   330
    }
slouken@1952
   331
icculus@5572
   332
    /* Check for GLX_SGI_swap_control */
icculus@5572
   333
    if (HasExtension("GLX_SGI_swap_control", extensions)) {
icculus@5572
   334
        _this->gl_data->glXSwapIntervalSGI =
icculus@5572
   335
            (int (*)(int)) X11_GL_GetProcAddress(_this, "glXSwapIntervalSGI");
icculus@5572
   336
    }
icculus@5572
   337
slouken@1952
   338
    /* Check for GLX_EXT_visual_rating */
slouken@1952
   339
    if (HasExtension("GLX_EXT_visual_rating", extensions)) {
slouken@1952
   340
        _this->gl_data->HAS_GLX_EXT_visual_rating = SDL_TRUE;
slouken@1952
   341
    }
slouken@1952
   342
slouken@1952
   343
    if (context) {
slouken@1952
   344
        _this->gl_data->glXMakeCurrent(display, None, NULL);
slouken@1952
   345
        _this->gl_data->glXDestroyContext(display, context);
slouken@1952
   346
    }
slouken@1952
   347
    XDestroyWindow(display, w);
bob@2323
   348
    X11_PumpEvents(_this);
slouken@1952
   349
}
slouken@1952
   350
slouken@6296
   351
/* glXChooseVisual and glXChooseFBConfig have some small differences in
slouken@6296
   352
 * the attribute encoding, it can be chosen with the for_FBConfig parameter. 
slouken@6296
   353
 */
slouken@5395
   354
int 
slouken@6296
   355
X11_GL_GetAttributes(_THIS, Display * display, int screen, int * attribs, int size, Bool for_FBConfig)
slouken@1952
   356
{
slouken@5395
   357
    int i = 0;
slouken@1952
   358
slouken@5395
   359
    /* assert buffer is large enough to hold all SDL attributes. */ 
icculus@6281
   360
    SDL_assert(size >= 32);
slouken@3139
   361
slouken@1952
   362
    /* Setup our GLX attributes according to the gl_config. */
slouken@6296
   363
    if( for_FBConfig ) {
slouken@6296
   364
        attribs[i++] = GLX_RENDER_TYPE;
slouken@6296
   365
	attribs[i++] = GLX_RGBA_BIT;
slouken@6296
   366
    } else {
slouken@6296
   367
        attribs[i++] = GLX_RGBA;
slouken@6296
   368
    }
slouken@1952
   369
    attribs[i++] = GLX_RED_SIZE;
slouken@1952
   370
    attribs[i++] = _this->gl_config.red_size;
slouken@1952
   371
    attribs[i++] = GLX_GREEN_SIZE;
slouken@1952
   372
    attribs[i++] = _this->gl_config.green_size;
slouken@1952
   373
    attribs[i++] = GLX_BLUE_SIZE;
slouken@1952
   374
    attribs[i++] = _this->gl_config.blue_size;
slouken@1952
   375
slouken@1952
   376
    if (_this->gl_config.alpha_size) {
slouken@1952
   377
        attribs[i++] = GLX_ALPHA_SIZE;
slouken@1952
   378
        attribs[i++] = _this->gl_config.alpha_size;
slouken@1952
   379
    }
slouken@1952
   380
slouken@1952
   381
    if (_this->gl_config.double_buffer) {
slouken@1952
   382
        attribs[i++] = GLX_DOUBLEBUFFER;
slouken@6296
   383
	if( for_FBConfig )
slouken@6296
   384
	    attribs[i++] = True;
slouken@1952
   385
    }
slouken@1952
   386
slouken@1952
   387
    attribs[i++] = GLX_DEPTH_SIZE;
slouken@1952
   388
    attribs[i++] = _this->gl_config.depth_size;
slouken@1952
   389
slouken@1952
   390
    if (_this->gl_config.stencil_size) {
slouken@1952
   391
        attribs[i++] = GLX_STENCIL_SIZE;
slouken@1952
   392
        attribs[i++] = _this->gl_config.stencil_size;
slouken@1952
   393
    }
slouken@1952
   394
slouken@1952
   395
    if (_this->gl_config.accum_red_size) {
slouken@1952
   396
        attribs[i++] = GLX_ACCUM_RED_SIZE;
slouken@1952
   397
        attribs[i++] = _this->gl_config.accum_red_size;
slouken@1952
   398
    }
slouken@1952
   399
slouken@1952
   400
    if (_this->gl_config.accum_green_size) {
slouken@1952
   401
        attribs[i++] = GLX_ACCUM_GREEN_SIZE;
slouken@1952
   402
        attribs[i++] = _this->gl_config.accum_green_size;
slouken@1952
   403
    }
slouken@1952
   404
slouken@1952
   405
    if (_this->gl_config.accum_blue_size) {
slouken@1952
   406
        attribs[i++] = GLX_ACCUM_BLUE_SIZE;
slouken@1952
   407
        attribs[i++] = _this->gl_config.accum_blue_size;
slouken@1952
   408
    }
slouken@1952
   409
slouken@1952
   410
    if (_this->gl_config.accum_alpha_size) {
slouken@1952
   411
        attribs[i++] = GLX_ACCUM_ALPHA_SIZE;
slouken@1952
   412
        attribs[i++] = _this->gl_config.accum_alpha_size;
slouken@1952
   413
    }
slouken@1952
   414
slouken@1952
   415
    if (_this->gl_config.stereo) {
slouken@1952
   416
        attribs[i++] = GLX_STEREO;
slouken@6296
   417
	if( for_FBConfig )
slouken@6296
   418
	    attribs[i++] = True;
slouken@1952
   419
    }
slouken@1952
   420
slouken@1952
   421
    if (_this->gl_config.multisamplebuffers) {
slouken@1952
   422
        attribs[i++] = GLX_SAMPLE_BUFFERS_ARB;
slouken@1952
   423
        attribs[i++] = _this->gl_config.multisamplebuffers;
slouken@1952
   424
    }
slouken@1952
   425
slouken@1952
   426
    if (_this->gl_config.multisamplesamples) {
slouken@1952
   427
        attribs[i++] = GLX_SAMPLES_ARB;
slouken@1952
   428
        attribs[i++] = _this->gl_config.multisamplesamples;
slouken@1952
   429
    }
slouken@1952
   430
slouken@3571
   431
    if (_this->gl_config.accelerated >= 0 &&
slouken@3571
   432
        _this->gl_data->HAS_GLX_EXT_visual_rating) {
slouken@1952
   433
        attribs[i++] = GLX_VISUAL_CAVEAT_EXT;
slouken@3570
   434
        attribs[i++] = _this->gl_config.accelerated ? GLX_NONE_EXT :
slouken@3570
   435
                                                      GLX_SLOW_VISUAL_EXT;
slouken@1952
   436
    }
slouken@3570
   437
slouken@1952
   438
    attribs[i++] = None;
slouken@5395
   439
 
slouken@5395
   440
    return i;
slouken@5395
   441
}
slouken@5395
   442
slouken@5395
   443
XVisualInfo *
slouken@5395
   444
X11_GL_GetVisual(_THIS, Display * display, int screen)
slouken@5395
   445
{
slouken@5395
   446
    XVisualInfo *vinfo;
slouken@5395
   447
slouken@5395
   448
    /* 64 seems nice. */
slouken@6296
   449
    int attribs[64];
icculus@6359
   450
    X11_GL_GetAttributes(_this,display,screen,attribs,64,SDL_FALSE);
slouken@1952
   451
slouken@6181
   452
    if (!_this->gl_data) {
slouken@6181
   453
        /* The OpenGL library wasn't loaded, SDL_GetError() should have info */
slouken@6181
   454
        return NULL;
slouken@6181
   455
    }
slouken@6181
   456
slouken@1952
   457
    vinfo = _this->gl_data->glXChooseVisual(display, screen, attribs);
slouken@1952
   458
    if (!vinfo) {
slouken@1952
   459
        SDL_SetError("Couldn't find matching GLX visual");
slouken@1952
   460
    }
slouken@1952
   461
    return vinfo;
slouken@1952
   462
}
slouken@1952
   463
slouken@1952
   464
SDL_GLContext
slouken@1952
   465
X11_GL_CreateContext(_THIS, SDL_Window * window)
slouken@1952
   466
{
slouken@1952
   467
    SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
slouken@1952
   468
    Display *display = data->videodata->display;
slouken@1952
   469
    int screen =
slouken@5246
   470
        ((SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata)->screen;
slouken@1952
   471
    XWindowAttributes xattr;
slouken@1952
   472
    XVisualInfo v, *vinfo;
slouken@1952
   473
    int n;
slouken@1952
   474
    GLXContext context = NULL;
slouken@1952
   475
slouken@1955
   476
    /* We do this to create a clean separation between X and GLX errors. */
slouken@1952
   477
    XSync(display, False);
slouken@3685
   478
    XGetWindowAttributes(display, data->xwindow, &xattr);
slouken@1952
   479
    v.screen = screen;
slouken@1952
   480
    v.visualid = XVisualIDFromVisual(xattr.visual);
slouken@1952
   481
    vinfo = XGetVisualInfo(display, VisualScreenMask | VisualIDMask, &v, &n);
slouken@1952
   482
    if (vinfo) {
slouken@3139
   483
        if (_this->gl_config.major_version < 3) {
slouken@3100
   484
            context =
slouken@3100
   485
                _this->gl_data->glXCreateContext(display, vinfo, NULL, True);
slouken@3100
   486
        } else {
slouken@3100
   487
            /* If we want a GL 3.0 context or later we need to get a temporary
slouken@3100
   488
               context to grab the new context creation function */
slouken@3139
   489
            GLXContext temp_context =
slouken@3139
   490
                _this->gl_data->glXCreateContext(display, vinfo, NULL, True);
slouken@3100
   491
            if (!temp_context) {
slouken@3139
   492
                SDL_SetError("Could not create GL context");
slouken@3100
   493
                return NULL;
slouken@3100
   494
            } else {
slouken@6296
   495
	        /* max 8 attributes plus terminator */
slouken@6296
   496
                int attribs[9] = {
slouken@3139
   497
                    GLX_CONTEXT_MAJOR_VERSION_ARB,
slouken@3139
   498
                    _this->gl_config.major_version,
slouken@3139
   499
                    GLX_CONTEXT_MINOR_VERSION_ARB,
slouken@3139
   500
                    _this->gl_config.minor_version,
slouken@3139
   501
                    0
slouken@3100
   502
                };
slouken@6296
   503
		int iattr = 4;
slouken@6296
   504
slouken@6296
   505
		/* SDL profile bits match GLX profile bits */
slouken@6296
   506
		if( _this->gl_config.profile_mask != 0 ) {
slouken@6296
   507
		    attribs[iattr++] = GLX_CONTEXT_PROFILE_MASK_ARB;
slouken@6296
   508
		    attribs[iattr++] = _this->gl_config.profile_mask;
slouken@6296
   509
		}
slouken@6296
   510
slouken@6296
   511
		/* SDL flags match GLX flags */
slouken@6296
   512
		if( _this->gl_config.flags != 0 ) {
slouken@6296
   513
		    attribs[iattr++] = GLX_CONTEXT_FLAGS_ARB;
slouken@6296
   514
		    attribs[iattr++] = _this->gl_config.flags;
slouken@6296
   515
		}
slouken@6296
   516
slouken@6296
   517
		attribs[iattr++] = 0;
slouken@3139
   518
slouken@3100
   519
                /* Get a pointer to the context creation function for GL 3.0 */
slouken@3139
   520
                PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribs =
slouken@3139
   521
                    (PFNGLXCREATECONTEXTATTRIBSARBPROC) _this->gl_data->
slouken@3139
   522
                    glXGetProcAddress((GLubyte *)
slouken@3139
   523
                                      "glXCreateContextAttribsARB");
slouken@3100
   524
                if (!glXCreateContextAttribs) {
slouken@3100
   525
                    SDL_SetError("GL 3.x is not supported");
slouken@3100
   526
                    context = temp_context;
slouken@3100
   527
                } else {
slouken@5395
   528
                    int glxAttribs[64];
slouken@5395
   529
slouken@3105
   530
                    /* Create a GL 3.x context */
slouken@3100
   531
                    GLXFBConfig *framebuffer_config = NULL;
slouken@3139
   532
                    int fbcount = 0;
slouken@3139
   533
                    GLXFBConfig *(*glXChooseFBConfig) (Display * disp,
slouken@3139
   534
                                                       int screen,
slouken@3139
   535
                                                       const int *attrib_list,
slouken@3139
   536
                                                       int *nelements);
slouken@3105
   537
slouken@3139
   538
                    glXChooseFBConfig =
slouken@3139
   539
                        (GLXFBConfig *
slouken@3139
   540
                         (*)(Display *, int, const int *,
slouken@3139
   541
                             int *)) _this->gl_data->
slouken@3139
   542
                        glXGetProcAddress((GLubyte *) "glXChooseFBConfig");
slouken@3105
   543
slouken@6296
   544
                    X11_GL_GetAttributes(_this,display,screen,glxAttribs,64,SDL_TRUE);
slouken@5395
   545
slouken@3139
   546
                    if (!glXChooseFBConfig
slouken@3139
   547
                        || !(framebuffer_config =
slouken@3139
   548
                             glXChooseFBConfig(display,
slouken@5395
   549
                                               DefaultScreen(display), glxAttribs,
slouken@3139
   550
                                               &fbcount))) {
slouken@3139
   551
                        SDL_SetError
slouken@3139
   552
                            ("No good framebuffers found. GL 3.x disabled");
slouken@3100
   553
                        context = temp_context;
slouken@3139
   554
                    } else {
slouken@3139
   555
                        context =
slouken@3139
   556
                            glXCreateContextAttribs(display,
slouken@3139
   557
                                                    framebuffer_config[0],
slouken@3139
   558
                                                    NULL, True, attribs);
slouken@3139
   559
                        _this->gl_data->glXDestroyContext(display,
slouken@3139
   560
                                                          temp_context);
slouken@3100
   561
                    }
slouken@3100
   562
                }
slouken@3100
   563
            }
slouken@3100
   564
        }
slouken@1952
   565
        XFree(vinfo);
slouken@1952
   566
    }
slouken@1952
   567
    XSync(display, False);
slouken@1952
   568
slouken@1952
   569
    if (!context) {
slouken@1952
   570
        SDL_SetError("Could not create GL context");
slouken@2178
   571
        return NULL;
slouken@1952
   572
    }
slouken@2178
   573
slouken@2178
   574
    if (X11_GL_MakeCurrent(_this, window, context) < 0) {
slouken@2178
   575
        X11_GL_DeleteContext(_this, context);
slouken@2178
   576
        return NULL;
slouken@2178
   577
    }
slouken@2178
   578
slouken@2178
   579
    return context;
slouken@1952
   580
}
slouken@1952
   581
slouken@1952
   582
int
slouken@1952
   583
X11_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
slouken@1952
   584
{
slouken@1952
   585
    Display *display = ((SDL_VideoData *) _this->driverdata)->display;
slouken@1952
   586
    Window drawable =
slouken@3685
   587
        (window ? ((SDL_WindowData *) window->driverdata)->xwindow : None);
slouken@1952
   588
    GLXContext glx_context = (GLXContext) context;
slouken@1952
   589
    int status;
slouken@1952
   590
slouken@1952
   591
    status = 0;
slouken@1952
   592
    if (!_this->gl_data->glXMakeCurrent(display, drawable, glx_context)) {
slouken@1952
   593
        SDL_SetError("Unable to make GL context current");
slouken@1952
   594
        status = -1;
slouken@1952
   595
    }
slouken@1952
   596
    XSync(display, False);
slouken@1952
   597
slouken@1952
   598
    return (status);
slouken@1952
   599
}
slouken@1952
   600
bob@2327
   601
/* 
icculus@5572
   602
   0 is a valid argument to glxSwapInterval(MESA|EXT) and setting it to 0
icculus@5572
   603
   will undo the effect of a previous call with a value that is greater
icculus@5572
   604
   than zero (or at least that is what the docs say). OTOH, 0 is an invalid
icculus@5572
   605
   argument to glxSwapIntervalSGI and it returns an error if you call it
icculus@5572
   606
   with 0 as an argument.
bob@2327
   607
*/
bob@2327
   608
bob@2327
   609
static int swapinterval = -1;
slouken@1952
   610
int
slouken@1952
   611
X11_GL_SetSwapInterval(_THIS, int interval)
slouken@1952
   612
{
slouken@1952
   613
    int status;
slouken@1952
   614
icculus@5572
   615
    if (_this->gl_data->glXSwapIntervalEXT) {
icculus@5572
   616
        Display *display = ((SDL_VideoData *) _this->driverdata)->display;
icculus@5572
   617
        const SDL_WindowData *windowdata = (SDL_WindowData *)
icculus@5572
   618
            _this->current_glwin->driverdata;
icculus@5572
   619
        Window drawable = windowdata->xwindow;
icculus@5630
   620
        status = _this->gl_data->glXSwapIntervalEXT(display,drawable,interval);
icculus@5630
   621
        if (status != 0) {
icculus@5630
   622
            SDL_SetError("glxSwapIntervalEXT failed");
icculus@5630
   623
            status = -1;
icculus@5630
   624
        } else {
icculus@5630
   625
            swapinterval = interval;
icculus@5630
   626
        }
icculus@5572
   627
    } else if (_this->gl_data->glXSwapIntervalMESA) {
slouken@1952
   628
        status = _this->gl_data->glXSwapIntervalMESA(interval);
slouken@1952
   629
        if (status != 0) {
slouken@1952
   630
            SDL_SetError("glxSwapIntervalMESA failed");
slouken@1952
   631
            status = -1;
bob@2327
   632
        } else {
bob@2327
   633
            swapinterval = interval;
slouken@1952
   634
        }
slouken@1952
   635
    } else if (_this->gl_data->glXSwapIntervalSGI) {
slouken@1952
   636
        status = _this->gl_data->glXSwapIntervalSGI(interval);
slouken@1952
   637
        if (status != 0) {
slouken@1952
   638
            SDL_SetError("glxSwapIntervalSGI failed");
slouken@1952
   639
            status = -1;
bob@2327
   640
        } else {
bob@2327
   641
            swapinterval = interval;
slouken@1952
   642
        }
slouken@1952
   643
    } else {
slouken@1952
   644
        SDL_Unsupported();
slouken@1952
   645
        status = -1;
slouken@1952
   646
    }
slouken@1952
   647
    return status;
slouken@1952
   648
}
slouken@1952
   649
slouken@1952
   650
int
slouken@1952
   651
X11_GL_GetSwapInterval(_THIS)
slouken@1952
   652
{
icculus@5572
   653
    if (_this->gl_data->glXSwapIntervalEXT) {
icculus@5572
   654
        Display *display = ((SDL_VideoData *) _this->driverdata)->display;
icculus@5572
   655
        const SDL_WindowData *windowdata = (SDL_WindowData *)
icculus@5572
   656
            _this->current_glwin->driverdata;
icculus@5572
   657
        Window drawable = windowdata->xwindow;
icculus@5572
   658
        unsigned int value = 0;
icculus@5572
   659
        _this->gl_data->glXQueryDrawable(display, drawable,
icculus@5572
   660
                                         GLX_SWAP_INTERVAL_EXT, &value);
icculus@5572
   661
        return (int) value;
icculus@5572
   662
    } else if (_this->gl_data->glXGetSwapIntervalMESA) {
slouken@1952
   663
        return _this->gl_data->glXGetSwapIntervalMESA();
slouken@1952
   664
    } else {
bob@2327
   665
        return swapinterval;
slouken@1952
   666
    }
slouken@1952
   667
}
slouken@1952
   668
slouken@1952
   669
void
slouken@1952
   670
X11_GL_SwapWindow(_THIS, SDL_Window * window)
slouken@1952
   671
{
slouken@1952
   672
    SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
slouken@1952
   673
    Display *display = data->videodata->display;
slouken@1952
   674
slouken@3685
   675
    _this->gl_data->glXSwapBuffers(display, data->xwindow);
slouken@1952
   676
}
slouken@1952
   677
slouken@1952
   678
void
slouken@1952
   679
X11_GL_DeleteContext(_THIS, SDL_GLContext context)
slouken@1952
   680
{
slouken@1952
   681
    Display *display = ((SDL_VideoData *) _this->driverdata)->display;
slouken@1952
   682
    GLXContext glx_context = (GLXContext) context;
slouken@1952
   683
slouken@1952
   684
    _this->gl_data->glXDestroyContext(display, glx_context);
bob@2324
   685
    XSync(display, False);
slouken@1952
   686
}
slouken@1952
   687
slouken@1952
   688
#endif /* SDL_VIDEO_OPENGL_GLX */
slouken@1952
   689
slouken@6044
   690
#endif /* SDL_VIDEO_DRIVER_X11 */
slouken@6044
   691
slouken@1952
   692
/* vi: set ts=4 sw=4 expandtab: */