cscg22-gearboy

CSCG 2022 Challenge 'Gearboy'
git clone https://git.sinitax.com/sinitax/cscg22-gearboy
Log | Files | Refs | sfeed.txt

SDL_x11opengl.c (28235B)


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