From 30b17e7382b4fc8be84505914702c9db1700a33c Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Mon, 20 Feb 2012 23:37:57 -0500 Subject: [PATCH] Add OpenGL 3.X context creation support Matthias Bentrup 2011-10-30 03:58:24 PDT I've updated the context creation patch to include the bugfixes by Martin Schreiber and also included a profile bit to request a ES2 compatible profile. The wgl context creation may use 2 call to wglChoosePixelFormat if no acceleration attribute is selected, this should work around a bug with buggy AMD drivers (see #1254). --- include/SDL_video.h | 18 ++++++- src/video/SDL_sysvideo.h | 2 + src/video/SDL_video.c | 18 +++++++ src/video/windows/SDL_windowsopengl.c | 56 ++++++++++++++++++--- src/video/x11/SDL_x11opengl.c | 72 ++++++++++++++++++++++----- 5 files changed, 144 insertions(+), 22 deletions(-) diff --git a/include/SDL_video.h b/include/SDL_video.h index 6b818b60e..878c053f0 100644 --- a/include/SDL_video.h +++ b/include/SDL_video.h @@ -182,9 +182,25 @@ typedef enum SDL_GL_ACCELERATED_VISUAL, SDL_GL_RETAINED_BACKING, SDL_GL_CONTEXT_MAJOR_VERSION, - SDL_GL_CONTEXT_MINOR_VERSION + SDL_GL_CONTEXT_MINOR_VERSION, + SDL_GL_CONTEXT_FLAGS, + SDL_GL_CONTEXT_PROFILE_MASK } SDL_GLattr; +typedef enum +{ + SDL_GL_CONTEXT_PROFILE_CORE = 0x0001, + SDL_GL_CONTEXT_PROFILE_COMPATIBILITY = 0x0002, + SDL_GL_CONTEXT_PROFILE_ES2 = 0x0004 +} SDL_GLprofile; + +typedef enum +{ + SDL_GL_CONTEXT_DEBUG_FLAG = 0x0001, + SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG = 0x0002, + SDL_GL_CONTEXT_ROBUST_ACCESS_FLAG = 0x0004 +} SDL_GLcontextFlag; + /* Function prototypes */ diff --git a/src/video/SDL_sysvideo.h b/src/video/SDL_sysvideo.h index c8344298e..679be4bf8 100755 --- a/src/video/SDL_sysvideo.h +++ b/src/video/SDL_sysvideo.h @@ -270,6 +270,8 @@ struct SDL_VideoDevice int accelerated; int major_version; int minor_version; + int flags; + int profile_mask; 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 92a5f034d..61941d3d2 100755 --- a/src/video/SDL_video.c +++ b/src/video/SDL_video.c @@ -500,6 +500,8 @@ SDL_VideoInit(const char *driver_name) _this->gl_config.major_version = 2; _this->gl_config.minor_version = 0; #endif + _this->gl_config.flags = 0; + _this->gl_config.profile_mask = 0; /* Initialize the video subsystem */ if (_this->VideoInit(_this) < 0) { @@ -2300,6 +2302,12 @@ SDL_GL_SetAttribute(SDL_GLattr attr, int value) case SDL_GL_CONTEXT_MINOR_VERSION: _this->gl_config.minor_version = value; break; + case SDL_GL_CONTEXT_FLAGS: + _this->gl_config.flags = value; + break; + case SDL_GL_CONTEXT_PROFILE_MASK: + _this->gl_config.profile_mask = value; + break; default: SDL_SetError("Unknown OpenGL attribute"); retval = -1; @@ -2446,6 +2454,16 @@ SDL_GL_GetAttribute(SDL_GLattr attr, int *value) *value = _this->gl_config.minor_version; return 0; } + case SDL_GL_CONTEXT_FLAGS: + { + *value = _this->gl_config.flags; + return 0; + } + case SDL_GL_CONTEXT_PROFILE_MASK: + { + *value = _this->gl_config.profile_mask; + 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 439234370..5674d903b 100755 --- a/src/video/windows/SDL_windowsopengl.c +++ b/src/video/windows/SDL_windowsopengl.c @@ -39,6 +39,26 @@ #define WGL_CONTEXT_FLAGS_ARB 0x2093 #define WGL_CONTEXT_DEBUG_BIT_ARB 0x0001 #define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002 + +#ifndef WGL_ARB_create_context_profile +#define WGL_ARB_create_context_profile +#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 +#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 +#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 +#endif + +#ifndef WGL_ARB_create_context_robustness +#define WGL_ARB_create_context_robustness +#define WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004 +#define WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 +#define WGL_NO_RESET_NOTIFICATION_ARB 0x8261 +#define WGL_LOSE_CONTEXT_ON_RESET_ARB 0x8252 +#endif +#endif + +#ifndef WGL_EXT_create_context_es2_profile +#define WGL_EXT_create_context_es2_profile +#define WGL_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004 #endif typedef HGLRC(APIENTRYP PFNWGLCREATECONTEXTATTRIBSARBPROC) (HDC hDC, @@ -398,7 +418,7 @@ WIN_GL_SetupWindow(_THIS, SDL_Window * window) { HDC hdc = ((SDL_WindowData *) window->driverdata)->hdc; PIXELFORMATDESCRIPTOR pfd; - int pixel_format; + int pixel_format = 0; int iAttribs[64]; int *iAttr; float fAttribs[1] = { 0 }; @@ -468,16 +488,19 @@ WIN_GL_SetupWindow(_THIS, SDL_Window * window) *iAttr++ = _this->gl_config.multisamplesamples; } - if (_this->gl_config.accelerated >= 0) { - *iAttr++ = WGL_ACCELERATION_ARB; - *iAttr++ = (_this->gl_config.accelerated ? WGL_FULL_ACCELERATION_ARB : - WGL_NO_ACCELERATION_ARB); - } + *iAttr++ = WGL_ACCELERATION_ARB; + *iAttr++ = WGL_FULL_ACCELERATION_ARB; *iAttr = 0; /* Choose and set the closest available pixel format */ - pixel_format = WIN_GL_ChoosePixelFormatARB(_this, iAttribs, fAttribs); + if (_this->gl_config.accelerated != 0) { + pixel_format = WIN_GL_ChoosePixelFormatARB(_this, iAttribs, fAttribs); + } + if (!pixel_format && _this->gl_config.accelerated != 1) { + iAttr[-1] = WGL_NO_ACCELERATION_ARB; + pixel_format = WIN_GL_ChoosePixelFormatARB(_this, iAttribs, fAttribs); + } if (!pixel_format) { pixel_format = WIN_GL_ChoosePixelFormat(hdc, &pfd); } @@ -521,11 +544,28 @@ WIN_GL_CreateContext(_THIS, SDL_Window * window) SDL_SetError("GL 3.x is not supported"); context = temp_context; } else { - int attribs[] = { + /* max 8 attributes plus terminator */ + int attribs[9] = { WGL_CONTEXT_MAJOR_VERSION_ARB, _this->gl_config.major_version, WGL_CONTEXT_MINOR_VERSION_ARB, _this->gl_config.minor_version, 0 }; + int iattr = 4; + + /* SDL profile bits match WGL profile bits */ + if( _this->gl_config.profile_mask != 0 ) { + attribs[iattr++] = WGL_CONTEXT_PROFILE_MASK_ARB; + attribs[iattr++] = _this->gl_config.profile_mask; + } + + /* SDL flags match WGL flags */ + if( _this->gl_config.flags != 0 ) { + attribs[iattr++] = WGL_CONTEXT_FLAGS_ARB; + attribs[iattr++] = _this->gl_config.flags; + } + + attribs[iattr++] = 0; + /* Create the GL 3.x context */ context = wglCreateContextAttribsARB(hdc, 0, attribs); /* Delete the GL 2.x context */ diff --git a/src/video/x11/SDL_x11opengl.c b/src/video/x11/SDL_x11opengl.c index 39847ca20..90b1e73b9 100755 --- a/src/video/x11/SDL_x11opengl.c +++ b/src/video/x11/SDL_x11opengl.c @@ -67,11 +67,6 @@ #define GLX_CONTEXT_DEBUG_BIT_ARB 0x0001 #define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002 -#ifndef GLX_EXT_swap_control -#define GLX_SWAP_INTERVAL_EXT 0x20F1 -#define GLX_MAX_SWAP_INTERVAL_EXT 0x20F2 -#endif - /* Typedef for the GL 3.0 context creation function */ typedef GLXContext(*PFNGLXCREATECONTEXTATTRIBSARBPROC) (Display * dpy, GLXFBConfig config, @@ -80,6 +75,31 @@ typedef GLXContext(*PFNGLXCREATECONTEXTATTRIBSARBPROC) (Display * dpy, Bool direct, const int *attrib_list); + +#ifndef GLX_ARB_create_context_profile +#define GLX_ARB_create_context_profile +#define GLX_CONTEXT_PROFILE_MASK_ARB 0x9126 +#define GLX_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 +#define GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 +#endif + +#ifndef GLX_ARB_create_context_robustness +#define GLX_ARB_create_context_robustness +#define GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004 +#define GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 +#define GLX_NO_RESET_NOTIFICATION_ARB 0x8261 +#define GLX_LOSE_CONTEXT_ON_RESET_ARB 0x8252 +#endif +#endif + +#ifndef GLX_EXT_create_context_es2_profile +#define GLX_EXT_create_context_es2_profile +#define GLX_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000002 +#endif + +#ifndef GLX_EXT_swap_control +#define GLX_SWAP_INTERVAL_EXT 0x20F1 +#define GLX_MAX_SWAP_INTERVAL_EXT 0x20F2 #endif #define OPENGL_REQUIRES_DLOPEN @@ -305,8 +325,11 @@ X11_GL_InitExtensions(_THIS) X11_PumpEvents(_this); } +/* glXChooseVisual and glXChooseFBConfig have some small differences in + * the attribute encoding, it can be chosen with the for_FBConfig parameter. + */ int -X11_GL_GetAttributes(_THIS, Display * display, int screen, int * attribs, int size) +X11_GL_GetAttributes(_THIS, Display * display, int screen, int * attribs, int size, Bool for_FBConfig) { int i = 0; @@ -314,7 +337,12 @@ X11_GL_GetAttributes(_THIS, Display * display, int screen, int * attribs, int si SDL_assert(size >= 32); /* Setup our GLX attributes according to the gl_config. */ - attribs[i++] = GLX_RGBA; + if( for_FBConfig ) { + attribs[i++] = GLX_RENDER_TYPE; + attribs[i++] = GLX_RGBA_BIT; + } else { + attribs[i++] = GLX_RGBA; + } attribs[i++] = GLX_RED_SIZE; attribs[i++] = _this->gl_config.red_size; attribs[i++] = GLX_GREEN_SIZE; @@ -329,6 +357,8 @@ X11_GL_GetAttributes(_THIS, Display * display, int screen, int * attribs, int si if (_this->gl_config.double_buffer) { attribs[i++] = GLX_DOUBLEBUFFER; + if( for_FBConfig ) + attribs[i++] = True; } attribs[i++] = GLX_DEPTH_SIZE; @@ -361,6 +391,8 @@ X11_GL_GetAttributes(_THIS, Display * display, int screen, int * attribs, int si if (_this->gl_config.stereo) { attribs[i++] = GLX_STEREO; + if( for_FBConfig ) + attribs[i++] = True; } if (_this->gl_config.multisamplebuffers) { @@ -391,10 +423,8 @@ X11_GL_GetVisual(_THIS, Display * display, int screen) XVisualInfo *vinfo; /* 64 seems nice. */ - const int max_attrs = 64; - int attribs[max_attrs]; - const int i = X11_GL_GetAttributes(_this,display,screen,attribs,max_attrs); - SDL_assert(i <= max_attrs); + int attribs[64]; + int i = X11_GL_GetAttributes(_this,display,screen,attribs,64,SDL_FALSE); if (!_this->gl_data) { /* The OpenGL library wasn't loaded, SDL_GetError() should have info */ @@ -439,13 +469,29 @@ X11_GL_CreateContext(_THIS, SDL_Window * window) SDL_SetError("Could not create GL context"); return NULL; } else { - int attribs[] = { + /* 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; + } + + attribs[iattr++] = 0; /* Get a pointer to the context creation function for GL 3.0 */ PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribs = @@ -472,7 +518,7 @@ X11_GL_CreateContext(_THIS, SDL_Window * window) int *)) _this->gl_data-> glXGetProcAddress((GLubyte *) "glXChooseFBConfig"); - X11_GL_GetAttributes(_this,display,screen,glxAttribs,64); + X11_GL_GetAttributes(_this,display,screen,glxAttribs,64,SDL_TRUE); if (!glXChooseFBConfig || !(framebuffer_config =