Commit ece8d2bb056aad9f6937509abae636effb053fc0

Ryan C. Gordon 2015-02-02T01:05:41

X11: Fixes for OpenGL 3.0 and later context creation. - Don't create a temporary context first; this was probably due to Windows needing one to get the address of wglCreateContextAttribsARB(), but that's a unique quirk of WGL, and doesn't apply to glX. The glX spec explicitly says you have to get a function pointer that works with any context from glXGetProcAddress(), including when no context exists. - Properly check for the GLX_ARB_create_context instead of just looking for a non-NULL glXCreateContextAttribsARB()...some implementations, like Mesa, never return NULL for function lookups (Mesa returns pointers into a jump table that is filled out when the GL is initialized; since you can look up functions before you have a valid context, it can't definitely say a function isn't valid at that point).

diff --git a/src/video/x11/SDL_x11opengl.c b/src/video/x11/SDL_x11opengl.c
index 1e94b04..c46710f 100644
--- a/src/video/x11/SDL_x11opengl.c
+++ b/src/video/x11/SDL_x11opengl.c
@@ -373,6 +373,16 @@ X11_GL_InitExtensions(_THIS)
             (int (*)(int)) X11_GL_GetProcAddress(_this, "glXSwapIntervalSGI");
     }
 
+    /* Check for GLX_ARB_create_context */
+    if (HasExtension("GLX_ARB_create_context", extensions)) {
+        _this->gl_data->glXCreateContextAttribsARB =
+            (GLXContext (*)(Display*,GLXFBConfig,GLXContext,Bool,const int *))
+                X11_GL_GetProcAddress(_this, "glXCreateContextAttribsARB");
+        _this->gl_data->glXChooseFBConfig =
+            (GLXFBConfig *(*)(Display *, int, const int *, int *))
+                X11_GL_GetProcAddress(_this, "glXChooseFBConfig");
+    }
+
     /* Check for GLX_EXT_visual_rating */
     if (HasExtension("GLX_EXT_visual_rating", extensions)) {
         _this->gl_data->HAS_GLX_EXT_visual_rating = SDL_TRUE;
@@ -576,7 +586,6 @@ X11_GL_CreateContext(_THIS, SDL_Window * window)
     XVisualInfo v, *vinfo;
     int n;
     GLXContext context = NULL, share_context;
-    PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribs = NULL;
 
     if (_this->gl_config.share_with_current_context) {
         share_context = (GLXContext)SDL_GL_GetCurrentContext();
@@ -601,78 +610,52 @@ X11_GL_CreateContext(_THIS, SDL_Window * window)
             context =
                 _this->gl_data->glXCreateContext(display, vinfo, share_context, True);
         } else {
-            /* If we want a GL 3.0 context or later we need to get a temporary
-               context to grab the new context creation function */
-            GLXContext temp_context =
-                _this->gl_data->glXCreateContext(display, vinfo, NULL, True);
-            if (temp_context) {
-                /* max 8 attributes plus terminator */
-                int attribs[9] = {
-                    GLX_CONTEXT_MAJOR_VERSION_ARB,
-                    _this->gl_config.major_version,
-                    GLX_CONTEXT_MINOR_VERSION_ARB,
-                    _this->gl_config.minor_version,
-                    0
-                };
-                int iattr = 4;
-
-                /* SDL profile bits match GLX profile bits */
-                if( _this->gl_config.profile_mask != 0 ) {
-                    attribs[iattr++] = GLX_CONTEXT_PROFILE_MASK_ARB;
-                    attribs[iattr++] = _this->gl_config.profile_mask;
-                }
+            /* max 8 attributes plus terminator */
+            int attribs[9] = {
+                GLX_CONTEXT_MAJOR_VERSION_ARB,
+                _this->gl_config.major_version,
+                GLX_CONTEXT_MINOR_VERSION_ARB,
+                _this->gl_config.minor_version,
+                0
+            };
+            int iattr = 4;
+
+            /* SDL profile bits match GLX profile bits */
+            if( _this->gl_config.profile_mask != 0 ) {
+                attribs[iattr++] = GLX_CONTEXT_PROFILE_MASK_ARB;
+                attribs[iattr++] = _this->gl_config.profile_mask;
+            }
 
-                /* SDL flags match GLX flags */
-                if( _this->gl_config.flags != 0 ) {
-                    attribs[iattr++] = GLX_CONTEXT_FLAGS_ARB;
-                    attribs[iattr++] = _this->gl_config.flags;
-                }
+            /* SDL flags match GLX flags */
+            if( _this->gl_config.flags != 0 ) {
+                attribs[iattr++] = GLX_CONTEXT_FLAGS_ARB;
+                attribs[iattr++] = _this->gl_config.flags;
+            }
+
+            attribs[iattr++] = 0;
+
+            /* Get a pointer to the context creation function for GL 3.0 */
+            if (!_this->gl_data->glXCreateContextAttribsARB) {
+                SDL_SetError("OpenGL 3.0 and later are not supported by this system");
+            } else {
+                int glxAttribs[64];
+
+                /* Create a GL 3.x context */
+                GLXFBConfig *framebuffer_config = NULL;
+                int fbcount = 0;
 
-                attribs[iattr++] = 0;
+                X11_GL_GetAttributes(_this,display,screen,glxAttribs,64,SDL_TRUE);
 
-                /* Get a pointer to the context creation function for GL 3.0 */
-                glXCreateContextAttribs =
-                    (PFNGLXCREATECONTEXTATTRIBSARBPROC) _this->gl_data->
-                    glXGetProcAddress((GLubyte *)
-                                      "glXCreateContextAttribsARB");
-                if (!glXCreateContextAttribs) {
-                    SDL_SetError("GL 3.x is not supported");
-                    context = temp_context;
+                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 {
-                    int glxAttribs[64];
-
-                    /* Create a GL 3.x context */
-                    GLXFBConfig *framebuffer_config = NULL;
-                    int fbcount = 0;
-                    GLXFBConfig *(*glXChooseFBConfig) (Display * disp,
-                                                       int screen,
-                                                       const int *attrib_list,
-                                                       int *nelements);
-
-                    glXChooseFBConfig =
-                        (GLXFBConfig *
-                         (*)(Display *, int, const int *,
-                             int *)) _this->gl_data->
-                        glXGetProcAddress((GLubyte *) "glXChooseFBConfig");
-
-                    X11_GL_GetAttributes(_this,display,screen,glxAttribs,64,SDL_TRUE);
-
-                    if (!glXChooseFBConfig
-                        || !(framebuffer_config =
-                             glXChooseFBConfig(display,
-                                               DefaultScreen(display), glxAttribs,
-                                               &fbcount))) {
-                        SDL_SetError
-                            ("No good framebuffers found. GL 3.x disabled");
-                        context = temp_context;
-                    } else {
-                        context =
-                            glXCreateContextAttribs(display,
+                    context = _this->gl_data->glXCreateContextAttribsARB(display,
                                                     framebuffer_config[0],
                                                     share_context, True, attribs);
-                        _this->gl_data->glXDestroyContext(display,
-                                                          temp_context);
-                    }
                 }
             }
         }
diff --git a/src/video/x11/SDL_x11opengl.h b/src/video/x11/SDL_x11opengl.h
index ed7f292..b3410fd 100644
--- a/src/video/x11/SDL_x11opengl.h
+++ b/src/video/x11/SDL_x11opengl.h
@@ -40,6 +40,8 @@ struct SDL_GLDriverData
     void *(*glXGetProcAddress) (const GLubyte*);
     XVisualInfo *(*glXChooseVisual) (Display*,int,int*);
     GLXContext (*glXCreateContext) (Display*,XVisualInfo*,GLXContext,Bool);
+    GLXContext (*glXCreateContextAttribsARB) (Display*,GLXFBConfig,GLXContext,Bool,const int *);
+    GLXFBConfig *(*glXChooseFBConfig) (Display*,int,const int *,int *);
     void (*glXDestroyContext) (Display*, GLXContext);
     Bool(*glXMakeCurrent) (Display*,GLXDrawable,GLXContext);
     void (*glXSwapBuffers) (Display*, GLXDrawable);