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).
Ryan C. Gordon 2015-02-02 01:05:41 -05:00
parent 86f87bf755
commit ece8d2bb05
2 changed files with 51 additions and 66 deletions

View File

@ -373,6 +373,16 @@ X11_GL_InitExtensions(_THIS)
(int (*)(int)) X11_GL_GetProcAddress(_this, "glXSwapIntervalSGI"); (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 */ /* Check for GLX_EXT_visual_rating */
if (HasExtension("GLX_EXT_visual_rating", extensions)) { if (HasExtension("GLX_EXT_visual_rating", extensions)) {
_this->gl_data->HAS_GLX_EXT_visual_rating = SDL_TRUE; _this->gl_data->HAS_GLX_EXT_visual_rating = SDL_TRUE;
@ -576,7 +586,6 @@ X11_GL_CreateContext(_THIS, SDL_Window * window)
XVisualInfo v, *vinfo; XVisualInfo v, *vinfo;
int n; int n;
GLXContext context = NULL, share_context; GLXContext context = NULL, share_context;
PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribs = NULL;
if (_this->gl_config.share_with_current_context) { if (_this->gl_config.share_with_current_context) {
share_context = (GLXContext)SDL_GL_GetCurrentContext(); share_context = (GLXContext)SDL_GL_GetCurrentContext();
@ -601,11 +610,6 @@ X11_GL_CreateContext(_THIS, SDL_Window * window)
context = context =
_this->gl_data->glXCreateContext(display, vinfo, share_context, True); _this->gl_data->glXCreateContext(display, vinfo, share_context, True);
} else { } 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 */ /* max 8 attributes plus terminator */
int attribs[9] = { int attribs[9] = {
GLX_CONTEXT_MAJOR_VERSION_ARB, GLX_CONTEXT_MAJOR_VERSION_ARB,
@ -631,48 +635,27 @@ X11_GL_CreateContext(_THIS, SDL_Window * window)
attribs[iattr++] = 0; attribs[iattr++] = 0;
/* Get a pointer to the context creation function for GL 3.0 */ /* Get a pointer to the context creation function for GL 3.0 */
glXCreateContextAttribs = if (!_this->gl_data->glXCreateContextAttribsARB) {
(PFNGLXCREATECONTEXTATTRIBSARBPROC) _this->gl_data-> SDL_SetError("OpenGL 3.0 and later are not supported by this system");
glXGetProcAddress((GLubyte *)
"glXCreateContextAttribsARB");
if (!glXCreateContextAttribs) {
SDL_SetError("GL 3.x is not supported");
context = temp_context;
} else { } else {
int glxAttribs[64]; int glxAttribs[64];
/* Create a GL 3.x context */ /* Create a GL 3.x context */
GLXFBConfig *framebuffer_config = NULL; GLXFBConfig *framebuffer_config = NULL;
int fbcount = 0; 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); X11_GL_GetAttributes(_this,display,screen,glxAttribs,64,SDL_TRUE);
if (!glXChooseFBConfig if (!_this->gl_data->glXChooseFBConfig
|| !(framebuffer_config = || !(framebuffer_config =
glXChooseFBConfig(display, _this->gl_data->glXChooseFBConfig(display,
DefaultScreen(display), glxAttribs, DefaultScreen(display), glxAttribs,
&fbcount))) { &fbcount))) {
SDL_SetError SDL_SetError("No good framebuffers found. OpenGL 3.0 and later unavailable");
("No good framebuffers found. GL 3.x disabled");
context = temp_context;
} else { } else {
context = context = _this->gl_data->glXCreateContextAttribsARB(display,
glXCreateContextAttribs(display,
framebuffer_config[0], framebuffer_config[0],
share_context, True, attribs); share_context, True, attribs);
_this->gl_data->glXDestroyContext(display,
temp_context);
}
} }
} }
} }

View File

@ -40,6 +40,8 @@ struct SDL_GLDriverData
void *(*glXGetProcAddress) (const GLubyte*); void *(*glXGetProcAddress) (const GLubyte*);
XVisualInfo *(*glXChooseVisual) (Display*,int,int*); XVisualInfo *(*glXChooseVisual) (Display*,int,int*);
GLXContext (*glXCreateContext) (Display*,XVisualInfo*,GLXContext,Bool); 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); void (*glXDestroyContext) (Display*, GLXContext);
Bool(*glXMakeCurrent) (Display*,GLXDrawable,GLXContext); Bool(*glXMakeCurrent) (Display*,GLXDrawable,GLXContext);
void (*glXSwapBuffers) (Display*, GLXDrawable); void (*glXSwapBuffers) (Display*, GLXDrawable);