From 1595f2451b7a1eb9cc6101cb6e573206fa3ad0e0 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Sun, 12 Aug 2012 11:16:24 -0700 Subject: [PATCH] Fixed bug 1565 - some small GL context creation enhancements Matthias Bentrup 2012-08-09 12:53:17 PDT With OpenGL 4.3 the ARB added a new context flag for context reset isolation and renamed the existing ES2 profile bit to ES profile bit, as it can be used to request GLES 3 compatible contexts, too. This patch adds these changes to SDL on Linux and Windows. Also SDL lacks the ability to create shared contexts. This patch also adds a new GL attribute to enable context sharing. As casting a GL context to int is not portable, I added only a boolean attribute SDL_GL_SHARE_WITH_CURRENT_CONTEXT, which makes the new context share resources with the context current on the creating thread. --- include/SDL_video.h | 7 +++-- src/video/SDL_sysvideo.h | 1 + src/video/SDL_video.c | 25 ++++++++++++++++ src/video/windows/SDL_windowsopengl.c | 25 ++++++++++++++-- src/video/windows/SDL_windowsopengl.h | 1 + src/video/x11/SDL_x11opengl.c | 43 ++++++++++++++++----------- 6 files changed, 80 insertions(+), 22 deletions(-) diff --git a/include/SDL_video.h b/include/SDL_video.h index ba366903e..4f485d72f 100644 --- a/include/SDL_video.h +++ b/include/SDL_video.h @@ -185,13 +185,15 @@ typedef enum SDL_GL_CONTEXT_MINOR_VERSION, SDL_GL_CONTEXT_EGL, SDL_GL_CONTEXT_FLAGS, - SDL_GL_CONTEXT_PROFILE_MASK + SDL_GL_CONTEXT_PROFILE_MASK, + SDL_GL_SHARE_WITH_CURRENT_CONTEXT } SDL_GLattr; typedef enum { SDL_GL_CONTEXT_PROFILE_CORE = 0x0001, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY = 0x0002, + SDL_GL_CONTEXT_PROFILE_ES = 0x0004, SDL_GL_CONTEXT_PROFILE_ES2 = 0x0004 } SDL_GLprofile; @@ -199,7 +201,8 @@ typedef enum { SDL_GL_CONTEXT_DEBUG_FLAG = 0x0001, SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG = 0x0002, - SDL_GL_CONTEXT_ROBUST_ACCESS_FLAG = 0x0004 + SDL_GL_CONTEXT_ROBUST_ACCESS_FLAG = 0x0004, + SDL_GL_CONTEXT_RESET_ISOLATION_FLAG = 0x0008 } SDL_GLcontextFlag; diff --git a/src/video/SDL_sysvideo.h b/src/video/SDL_sysvideo.h index 26e51ba22..2f5c59053 100755 --- a/src/video/SDL_sysvideo.h +++ b/src/video/SDL_sysvideo.h @@ -280,6 +280,7 @@ struct SDL_VideoDevice int flags; int profile_mask; int use_egl; + int share_with_current_context; int retained_backing; int driver_loaded; char driver_path[256]; diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c index f40856959..057a5a010 100755 --- a/src/video/SDL_video.c +++ b/src/video/SDL_video.c @@ -505,6 +505,7 @@ SDL_VideoInit(const char *driver_name) #endif _this->gl_config.flags = 0; _this->gl_config.profile_mask = 0; + _this->gl_config.share_with_current_context = 0; /* Initialize the video subsystem */ if (_this->VideoInit(_this) < 0) { @@ -2309,11 +2310,30 @@ SDL_GL_SetAttribute(SDL_GLattr attr, int value) _this->gl_config.use_egl = value; break; case SDL_GL_CONTEXT_FLAGS: + if( value & ~(SDL_GL_CONTEXT_DEBUG_FLAG | + SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG | + SDL_GL_CONTEXT_ROBUST_ACCESS_FLAG | + SDL_GL_CONTEXT_RESET_ISOLATION_FLAG) ) { + SDL_SetError("Unknown OpenGL context flag %d", value); + retval = -1; + break; + } _this->gl_config.flags = value; break; case SDL_GL_CONTEXT_PROFILE_MASK: + if( value != 0 && + value != SDL_GL_CONTEXT_PROFILE_CORE && + value != SDL_GL_CONTEXT_PROFILE_COMPATIBILITY && + value != SDL_GL_CONTEXT_PROFILE_ES ) { + SDL_SetError("Unknown OpenGL context profile %d", value); + retval = -1; + break; + } _this->gl_config.profile_mask = value; break; + case SDL_GL_SHARE_WITH_CURRENT_CONTEXT: + _this->gl_config.share_with_current_context = value; + break; default: SDL_SetError("Unknown OpenGL attribute"); retval = -1; @@ -2475,6 +2495,11 @@ SDL_GL_GetAttribute(SDL_GLattr attr, int *value) *value = _this->gl_config.profile_mask; return 0; } + case SDL_GL_SHARE_WITH_CURRENT_CONTEXT: + { + *value = _this->gl_config.share_with_current_context; + return 0; + } default: SDL_SetError("Unknown OpenGL attribute"); return -1; diff --git a/src/video/windows/SDL_windowsopengl.c b/src/video/windows/SDL_windowsopengl.c index 2f8478c1b..f95a90872 100755 --- a/src/video/windows/SDL_windowsopengl.c +++ b/src/video/windows/SDL_windowsopengl.c @@ -61,6 +61,11 @@ #define WGL_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004 #endif +#ifndef WGL_EXT_create_context_es_profile +#define WGL_EXT_create_context_es_profile +#define WGL_CONTEXT_ES_PROFILE_BIT_EXT 0x00000004 +#endif + typedef HGLRC(APIENTRYP PFNWGLCREATECONTEXTATTRIBSARBPROC) (HDC hDC, HGLRC hShareContext, @@ -112,6 +117,8 @@ WIN_GL_LoadLibrary(_THIS, const char *path) GetProcAddress(handle, "wglDeleteContext"); _this->gl_data->wglMakeCurrent = (BOOL(WINAPI *) (HDC, HGLRC)) GetProcAddress(handle, "wglMakeCurrent"); + _this->gl_data->wglShareLists = (BOOL(WINAPI *) (HGLRC, HGLRC)) + GetProcAddress(handle, "wglShareLists"); if (!_this->gl_data->wglGetProcAddress || !_this->gl_data->wglCreateContext || @@ -519,10 +526,22 @@ SDL_GLContext WIN_GL_CreateContext(_THIS, SDL_Window * window) { HDC hdc = ((SDL_WindowData *) window->driverdata)->hdc; - HGLRC context; + HGLRC context, share_context; + + if (_this->gl_config.share_with_current_context) { + share_context = (HGLRC)(_this->current_glctx); + } else { + share_context = 0; + } - if (_this->gl_config.major_version < 3) { + if (_this->gl_config.major_version < 3 && + _this->gl_config.profile_mask == 0 && + _this->gl_config.flags == 0) { + /* Create legacy context */ context = _this->gl_data->wglCreateContext(hdc); + if( share_context != 0 ) { + _this->gl_data->wglShareLists(share_context, hdc); + } } else { PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB; HGLRC temp_context = _this->gl_data->wglCreateContext(hdc); @@ -567,7 +586,7 @@ WIN_GL_CreateContext(_THIS, SDL_Window * window) attribs[iattr++] = 0; /* Create the GL 3.x context */ - context = wglCreateContextAttribsARB(hdc, 0, attribs); + context = wglCreateContextAttribsARB(hdc, share_context, attribs); /* Delete the GL 2.x context */ _this->gl_data->wglDeleteContext(temp_context); } diff --git a/src/video/windows/SDL_windowsopengl.h b/src/video/windows/SDL_windowsopengl.h index e6bcab887..31b25ec3c 100755 --- a/src/video/windows/SDL_windowsopengl.h +++ b/src/video/windows/SDL_windowsopengl.h @@ -34,6 +34,7 @@ struct SDL_GLDriverData HGLRC(WINAPI * wglCreateContext) (HDC hdc); BOOL(WINAPI * wglDeleteContext) (HGLRC hglrc); BOOL(WINAPI * wglMakeCurrent) (HDC hdc, HGLRC hglrc); + BOOL(WINAPI * wglShareLists) (HGLRC hglrc1, HGLRC hglrc2); BOOL(WINAPI * wglChoosePixelFormatARB) (HDC hdc, const int *piAttribIList, const FLOAT * pfAttribFList, diff --git a/src/video/x11/SDL_x11opengl.c b/src/video/x11/SDL_x11opengl.c index 0678875bd..c9f391fc0 100755 --- a/src/video/x11/SDL_x11opengl.c +++ b/src/video/x11/SDL_x11opengl.c @@ -484,7 +484,13 @@ X11_GL_CreateContext(_THIS, SDL_Window * window) XWindowAttributes xattr; XVisualInfo v, *vinfo; int n; - GLXContext context = NULL; + GLXContext context = NULL, share_context; + + if (_this->gl_config.share_with_current_context) { + share_context = (GLXContext)(_this->current_glctx); + } else { + share_context = NULL; + } /* We do this to create a clean separation between X and GLX errors. */ XSync(display, False); @@ -493,9 +499,12 @@ X11_GL_CreateContext(_THIS, SDL_Window * window) v.visualid = XVisualIDFromVisual(xattr.visual); vinfo = XGetVisualInfo(display, VisualScreenMask | VisualIDMask, &v, &n); if (vinfo) { - if (_this->gl_config.major_version < 3) { + if (_this->gl_config.major_version < 3 && + _this->gl_config.profile_mask == 0 && + _this->gl_config.flags == 0) { + /* Create legacy context */ context = - _this->gl_data->glXCreateContext(display, vinfo, NULL, True); + _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 */ @@ -505,7 +514,7 @@ X11_GL_CreateContext(_THIS, SDL_Window * window) SDL_SetError("Could not create GL context"); return NULL; } else { - /* max 8 attributes plus terminator */ + /* max 8 attributes plus terminator */ int attribs[9] = { GLX_CONTEXT_MAJOR_VERSION_ARB, _this->gl_config.major_version, @@ -513,21 +522,21 @@ X11_GL_CreateContext(_THIS, SDL_Window * window) _this->gl_config.minor_version, 0 }; - int iattr = 4; + 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 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; + attribs[iattr++] = 0; /* Get a pointer to the context creation function for GL 3.0 */ PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribs = @@ -568,7 +577,7 @@ X11_GL_CreateContext(_THIS, SDL_Window * window) context = glXCreateContextAttribs(display, framebuffer_config[0], - NULL, True, attribs); + share_context, True, attribs); _this->gl_data->glXDestroyContext(display, temp_context); }