Mac and Linux SDL2 binary snapshots
Edward Rudd
2018-08-19 561f0d614098a95527367cc3f911e476f35643d6
source/src/video/x11/SDL_x11opengl.c
@@ -1,6 +1,6 @@
/*
  Simple DirectMedia Layer
  Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
  This software is provided 'as-is', without any express or implied
  warranty.  In no event will the authors be held liable for any damages
@@ -24,6 +24,7 @@
#include "SDL_x11video.h"
#include "SDL_assert.h"
#include "SDL_hints.h"
/* GLX implementation of SDL OpenGL support */
@@ -113,6 +114,13 @@
#endif
#endif
#ifndef GLX_ARB_create_context_no_error
#define GLX_ARB_create_context_no_error
#ifndef GLX_CONTEXT_OPENGL_NO_ERROR_ARB
#define GLX_CONTEXT_OPENGL_NO_ERROR_ARB                 0x31B3
#endif
#endif
#ifndef GLX_EXT_swap_control
#define GLX_SWAP_INTERVAL_EXT              0x20F1
#define GLX_MAX_SWAP_INTERVAL_EXT          0x20F2
@@ -142,7 +150,6 @@
#endif
static void X11_GL_InitExtensions(_THIS);
int
X11_GL_LoadLibrary(_THIS, const char *path)
@@ -222,13 +229,17 @@
    }
    /* Initialize extensions */
    /* See lengthy comment about the inc/dec in
       ../windows/SDL_windowsopengl.c. */
    ++_this->gl_config.driver_loaded;
    X11_GL_InitExtensions(_this);
    --_this->gl_config.driver_loaded;
    
    /* If we need a GL ES context and there's no  
     * GLX_EXT_create_context_es2_profile extension, switch over to X11_GLES functions  
     */
    if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES && 
        ! _this->gl_data->HAS_GLX_EXT_create_context_es2_profile ) {
        X11_GL_UseEGL(_this) ) {
#if SDL_VIDEO_OPENGL_EGL
        X11_GL_UnloadLibrary(_this);
        /* Better avoid conflicts! */
@@ -320,8 +331,47 @@
{
    Display *display = ((SDL_VideoData *) _this->driverdata)->display;
    const int screen = DefaultScreen(display);
    XVisualInfo *vinfo = NULL;
    Window w = 0;
    GLXContext prev_ctx = 0;
    GLXDrawable prev_drawable = 0;
    GLXContext context = 0;
    const char *(*glXQueryExtensionsStringFunc) (Display *, int);
    const char *extensions;
    vinfo = X11_GL_GetVisual(_this, display, screen);
    if (vinfo) {
        GLXContext (*glXGetCurrentContextFunc) (void) =
            (GLXContext(*)(void))
                X11_GL_GetProcAddress(_this, "glXGetCurrentContext");
        GLXDrawable (*glXGetCurrentDrawableFunc) (void) =
            (GLXDrawable(*)(void))
                X11_GL_GetProcAddress(_this, "glXGetCurrentDrawable");
        if (glXGetCurrentContextFunc && glXGetCurrentDrawableFunc) {
            XSetWindowAttributes xattr;
            prev_ctx = glXGetCurrentContextFunc();
            prev_drawable = glXGetCurrentDrawableFunc();
            xattr.background_pixel = 0;
            xattr.border_pixel = 0;
            xattr.colormap =
                X11_XCreateColormap(display, RootWindow(display, screen),
                                    vinfo->visual, AllocNone);
            w = X11_XCreateWindow(display, RootWindow(display, screen), 0, 0,
                        32, 32, 0, vinfo->depth, InputOutput, vinfo->visual,
                        (CWBackPixel | CWBorderPixel | CWColormap), &xattr);
            context = _this->gl_data->glXCreateContext(display, vinfo,
                                                        NULL, True);
            if (context) {
                _this->gl_data->glXMakeCurrent(display, w, context);
            }
        }
        X11_XFree(vinfo);
    }
    glXQueryExtensionsStringFunc =
        (const char *(*)(Display *, int)) X11_GL_GetProcAddress(_this,
@@ -380,23 +430,58 @@
    
    /* Check for GLX_EXT_create_context_es2_profile */
    if (HasExtension("GLX_EXT_create_context_es2_profile", extensions)) {
        _this->gl_data->HAS_GLX_EXT_create_context_es2_profile = SDL_TRUE;
        /* this wants to call glGetString(), so it needs a context. */
        /* !!! FIXME: it would be nice not to make a context here though! */
        if (context) {
            SDL_GL_DeduceMaxSupportedESProfile(
                &_this->gl_data->es_profile_max_supported_version.major,
                &_this->gl_data->es_profile_max_supported_version.minor
            );
        }
    }
    /* Check for GLX_ARB_context_flush_control */
    if (HasExtension("GLX_ARB_context_flush_control", extensions)) {
        _this->gl_data->HAS_GLX_ARB_context_flush_control = SDL_TRUE;
    }
    /* Check for GLX_ARB_create_context_robustness */
    if (HasExtension("GLX_ARB_create_context_robustness", extensions)) {
        _this->gl_data->HAS_GLX_ARB_create_context_robustness = SDL_TRUE;
    }
    /* Check for GLX_ARB_create_context_no_error */
    if (HasExtension("GLX_ARB_create_context_no_error", extensions)) {
        _this->gl_data->HAS_GLX_ARB_create_context_no_error = SDL_TRUE;
    }
    if (context) {
        _this->gl_data->glXMakeCurrent(display, None, NULL);
        _this->gl_data->glXDestroyContext(display, context);
        if (prev_ctx && prev_drawable) {
            _this->gl_data->glXMakeCurrent(display, prev_drawable, prev_ctx);
        }
    }
    if (w) {
        X11_XDestroyWindow(display, w);
    }
    X11_PumpEvents(_this);
}
/* glXChooseVisual and glXChooseFBConfig have some small differences in
 * the attribute encoding, it can be chosen with the for_FBConfig parameter.
 * Some targets fail if you use GLX_X_VISUAL_TYPE_EXT/GLX_DIRECT_COLOR_EXT,
 *  so it gets specified last if used and is pointed to by *_pvistypeattr.
 *  In case of failure, if that pointer is not NULL, set that pointer to None
 *  and try again.
 */
static int
X11_GL_GetAttributes(_THIS, Display * display, int screen, int * attribs, int size, Bool for_FBConfig)
X11_GL_GetAttributes(_THIS, Display * display, int screen, int * attribs, int size, Bool for_FBConfig, int **_pvistypeattr)
{
    int i = 0;
    const int MAX_ATTRIBUTES = 64;
    int *pvistypeattr = NULL;
    /* assert buffer is large enough to hold all SDL attributes. */
    SDL_assert(size >= MAX_ATTRIBUTES);
@@ -488,6 +573,7 @@
       EXT_visual_info extension, then add GLX_X_VISUAL_TYPE_EXT. */
    if (X11_UseDirectColorVisuals() &&
        _this->gl_data->HAS_GLX_EXT_visual_info) {
        pvistypeattr = &attribs[i];
        attribs[i++] = GLX_X_VISUAL_TYPE_EXT;
        attribs[i++] = GLX_DIRECT_COLOR_EXT;
    }
@@ -495,6 +581,10 @@
    attribs[i++] = None;
    SDL_assert(i <= MAX_ATTRIBUTES);
    if (_pvistypeattr) {
        *_pvistypeattr = pvistypeattr;
    }
    return i;
}
@@ -505,29 +595,27 @@
    /* 64 seems nice. */
    int attribs[64];
    XVisualInfo *vinfo;
    int *pvistypeattr = NULL;
    if (!_this->gl_data) {
        /* The OpenGL library wasn't loaded, SDL_GetError() should have info */
        return NULL;
    }
    X11_GL_GetAttributes(_this, display, screen, attribs, 64, SDL_FALSE);
    X11_GL_GetAttributes(_this, display, screen, attribs, 64, SDL_FALSE, &pvistypeattr);
    vinfo = _this->gl_data->glXChooseVisual(display, screen, attribs);
    if (!vinfo && (pvistypeattr != NULL)) {
        *pvistypeattr = None;
        vinfo = _this->gl_data->glXChooseVisual(display, screen, attribs);
    }
    if (!vinfo) {
        SDL_SetError("Couldn't find matching GLX visual");
    }
    return vinfo;
}
#ifndef GLXBadContext
#define GLXBadContext 0
#endif
#ifndef GLXBadFBConfig
#define GLXBadFBConfig 9
#endif
#ifndef GLXBadProfileARB
#define GLXBadProfileARB 13
#endif
static int (*handler) (Display *, XErrorEvent *) = NULL;
static const char *errorHandlerOperation = NULL;
static int errorBase = 0;
@@ -551,10 +639,23 @@
    }
    else
    {
        SDL_SetError("Could not %s: %i (Base %i)\n", errorHandlerOperation, errorCode, errorBase);
        SDL_SetError("Could not %s: %i (Base %i)", errorHandlerOperation, errorCode, errorBase);
    }
    return (0);
}
SDL_bool
X11_GL_UseEGL(_THIS)
{
    SDL_assert(_this->gl_data != NULL);
    SDL_assert(_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES);
    return (SDL_GetHintBoolean(SDL_HINT_OPENGL_ES_DRIVER, SDL_FALSE)
            || _this->gl_config.major_version == 1 /* No GLX extension for OpenGL ES 1.x profiles. */
            || _this->gl_config.major_version > _this->gl_data->es_profile_max_supported_version.major
            || (_this->gl_config.major_version == _this->gl_data->es_profile_max_supported_version.major
                && _this->gl_config.minor_version > _this->gl_data->es_profile_max_supported_version.minor));
}
SDL_GLContext
@@ -593,8 +694,8 @@
            context =
                _this->gl_data->glXCreateContext(display, vinfo, share_context, True);
        } else {
            /* max 10 attributes plus terminator */
            int attribs[11] = {
            /* max 14 attributes plus terminator */
            int attribs[15] = {
                GLX_CONTEXT_MAJOR_VERSION_ARB,
                _this->gl_config.major_version,
                GLX_CONTEXT_MINOR_VERSION_ARB,
@@ -624,6 +725,21 @@
                    GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB;
            }
            /* only set if glx extension is available */
            if( _this->gl_data->HAS_GLX_ARB_create_context_robustness ) {
                attribs[iattr++] = GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB;
                attribs[iattr++] =
                    _this->gl_config.reset_notification ?
                    GLX_LOSE_CONTEXT_ON_RESET_ARB :
                    GLX_NO_RESET_NOTIFICATION_ARB;
            }
            /* only set if glx extension is available */
            if( _this->gl_data->HAS_GLX_ARB_create_context_no_error ) {
                attribs[iattr++] = GLX_CONTEXT_OPENGL_NO_ERROR_ARB;
                attribs[iattr++] = _this->gl_config.no_error;
            }
            attribs[iattr++] = 0;
            /* Get a pointer to the context creation function for GL 3.0 */
@@ -635,19 +751,28 @@
                /* Create a GL 3.x context */
                GLXFBConfig *framebuffer_config = NULL;
                int fbcount = 0;
                int *pvistypeattr = NULL;
                X11_GL_GetAttributes(_this,display,screen,glxAttribs,64,SDL_TRUE);
                X11_GL_GetAttributes(_this,display,screen,glxAttribs,64,SDL_TRUE,&pvistypeattr);
                if (!_this->gl_data->glXChooseFBConfig
                    || !(framebuffer_config =
                        _this->gl_data->glXChooseFBConfig(display,
                if (_this->gl_data->glXChooseFBConfig) {
                    framebuffer_config = _this->gl_data->glXChooseFBConfig(display,
                                          DefaultScreen(display), glxAttribs,
                                          &fbcount))) {
                    SDL_SetError("No good framebuffers found. OpenGL 3.0 and later unavailable");
                } else {
                    context = _this->gl_data->glXCreateContextAttribsARB(display,
                                                    framebuffer_config[0],
                                                    share_context, True, attribs);
                                          &fbcount);
                    if (!framebuffer_config && (pvistypeattr != NULL)) {
                        *pvistypeattr = None;
                        framebuffer_config = _this->gl_data->glXChooseFBConfig(display,
                                          DefaultScreen(display), glxAttribs,
                                          &fbcount);
                    }
                    if (framebuffer_config) {
                        context = _this->gl_data->glXCreateContextAttribsARB(display,
                                                        framebuffer_config[0],
                                                        share_context, True, attribs);
                        X11_XFree(framebuffer_config);
                    }
                }
            }
        }
@@ -791,13 +916,14 @@
    }
}
void
int
X11_GL_SwapWindow(_THIS, SDL_Window * window)
{
    SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
    Display *display = data->videodata->display;
    _this->gl_data->glXSwapBuffers(display, data->xwindow);
    return 0;
}
void