From 7d5ff1a16e9e7572e98a5691bfb924d09d01efcb Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Thu, 27 Apr 2006 09:09:48 +0000 Subject: [PATCH] SDL-trunk-1.3-merge-1 --- WhatsNew | 4 ++ include/SDL_video.h | 4 +- src/video/SDL_sysvideo.h | 2 + src/video/SDL_video.c | 8 +++ src/video/maccommon/SDL_macgl.c | 7 +- src/video/quartz/SDL_QuartzGL.m | 34 +++++++++- src/video/wincommon/SDL_wingl.c | 46 ++++++++++++++ src/video/wincommon/SDL_wingl_c.h | 2 + src/video/x11/SDL_x11gl.c | 102 ++++++++++++++++++++++++++++-- src/video/x11/SDL_x11gl_c.h | 5 +- test/testgl.c | 32 ++++++++-- 11 files changed, 234 insertions(+), 12 deletions(-) diff --git a/WhatsNew b/WhatsNew index 2a1206b0f..e6444926b 100644 --- a/WhatsNew +++ b/WhatsNew @@ -4,6 +4,10 @@ This is a list of API changes in SDL's version history. Version 1.0: 1.2.10: + Added SDL_GL_SWAP_CONTROL to wait for vsync in OpenGL applications. + + Added SDL_GL_ACCELERATED_VISUAL to guarantee hardware acceleration. + Added current_w and current_h to the SDL_VideoInfo structure, which is set to the desktop resolution during video intialization, and then set to the current resolution when a video mode is set. diff --git a/include/SDL_video.h b/include/SDL_video.h index d4d2cd56d..b6dcbbfc5 100644 --- a/include/SDL_video.h +++ b/include/SDL_video.h @@ -213,7 +213,9 @@ typedef enum { SDL_GL_ACCUM_ALPHA_SIZE, SDL_GL_STEREO, SDL_GL_MULTISAMPLEBUFFERS, - SDL_GL_MULTISAMPLESAMPLES + SDL_GL_MULTISAMPLESAMPLES, + SDL_GL_ACCELERATED_VISUAL, + SDL_GL_SWAP_CONTROL } SDL_GLattr; /* flags for SDL_SetPalette() */ diff --git a/src/video/SDL_sysvideo.h b/src/video/SDL_sysvideo.h index cc2954b11..e1568a7db 100644 --- a/src/video/SDL_sysvideo.h +++ b/src/video/SDL_sysvideo.h @@ -292,6 +292,8 @@ struct SDL_VideoDevice { int stereo; int multisamplebuffers; int multisamplesamples; + int accelerated; + int swap_control; int driver_loaded; char driver_path[256]; void* dll_handle; diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c index 9fed29f0b..07eb1230b 100644 --- a/src/video/SDL_video.c +++ b/src/video/SDL_video.c @@ -229,6 +229,8 @@ int SDL_VideoInit (const char *driver_name, Uint32 flags) video->gl_config.stereo = 0; video->gl_config.multisamplebuffers = 0; video->gl_config.multisamplesamples = 0; + video->gl_config.accelerated = -1; /* not known, don't set */ + video->gl_config.swap_control = -1; /* not known, don't set */ /* Initialize the video subsystem */ SDL_memset(&vformat, 0, sizeof(vformat)); @@ -1393,6 +1395,12 @@ int SDL_GL_SetAttribute( SDL_GLattr attr, int value ) case SDL_GL_MULTISAMPLESAMPLES: video->gl_config.multisamplesamples = value; break; + case SDL_GL_ACCELERATED_VISUAL: + video->gl_config.accelerated = value; + break; + case SDL_GL_SWAP_CONTROL: + video->gl_config.swap_control = value; + break; default: SDL_SetError("Unknown OpenGL attribute"); retval = -1; diff --git a/src/video/maccommon/SDL_macgl.c b/src/video/maccommon/SDL_macgl.c index 27bf4ad86..063ab417b 100644 --- a/src/video/maccommon/SDL_macgl.c +++ b/src/video/maccommon/SDL_macgl.c @@ -34,7 +34,7 @@ int Mac_GL_Init(_THIS) #if SDL_VIDEO_OPENGL AGLPixelFormat format; int i = 0; - GLint attributes [ 24 ]; /* 24 is max possible in this setup */ + GLint attributes [ 26 ]; /* 26 is max possible in this setup */ GLboolean noerr; /* load the gl driver from a default path */ @@ -95,6 +95,11 @@ int Mac_GL_Init(_THIS) attributes[i++] = this->gl_config.multisamplesamples; } #endif + if ( this->gl_config.accelerated > 0 ) { + attributes[i++] = AGL_ACCELERATED; + attributes[i++] = AGL_NO_RECOVERY; + } + attributes[i++] = AGL_ALL_RENDERERS; attributes[i] = AGL_NONE; diff --git a/src/video/quartz/SDL_QuartzGL.m b/src/video/quartz/SDL_QuartzGL.m index 63b5e66c1..ef447451b 100644 --- a/src/video/quartz/SDL_QuartzGL.m +++ b/src/video/quartz/SDL_QuartzGL.m @@ -112,6 +112,10 @@ int QZ_SetupOpenGL (_THIS, int bpp, Uint32 flags) { attr[i++] = NSOpenGLPFANoRecovery; } + if ( this->gl_config.accelerated > 0 ) { + attr[i++] = NSOpenGLPFAAccelerated; + } + attr[i++] = NSOpenGLPFAScreenMask; attr[i++] = CGDisplayIDToOpenGLDisplayMask (display_id); attr[i] = 0; @@ -132,6 +136,17 @@ int QZ_SetupOpenGL (_THIS, int bpp, Uint32 flags) { return 0; } + /* Synchronize QZ_GL_SwapBuffers() to vertical retrace. + * (Apple's documentation is not completely clear about what this setting + * exactly does, IMHO - for a detailed explanation see + * http://lists.apple.com/archives/mac-opengl/2006/Jan/msg00080.html ) + */ + if ( this->gl_config.swap_control >= 0 ) { + long value; + value = this->gl_config.swap_control; + [ gl_context setValues: &value forParameter: NSOpenGLCPSwapInterval ]; + } + /* * Wisdom from Apple engineer in reference to UT2003's OpenGL performance: * "You are blowing a couple of the internal OpenGL function caches. This @@ -231,8 +246,25 @@ int QZ_GL_GetAttribute (_THIS, SDL_GLattr attrib, int* value) { glGetIntegerv (GL_ALPHA_BITS, &component); bits += component; *value = bits; + return 0; + } + case SDL_GL_ACCELERATED_VISUAL: + { + long val; + /* FIXME: How do we get this information here? + [fmt getValues: &val forAttribute: NSOpenGLPFAAccelerated attr forVirtualScreen: 0]; + */ + val = (this->gl_config.accelerated != 0);; + *value = val; + return 0; + } + case SDL_GL_SWAP_CONTROL: + { + long val; + [ gl_context getValues: &val forParameter: NSOpenGLCPSwapInterval ]; + *value = val; + return 0; } - return 0; } glGetIntegerv (attr, (GLint *)value); diff --git a/src/video/wincommon/SDL_wingl.c b/src/video/wincommon/SDL_wingl.c index 0ff2d6d9a..9de5b0102 100644 --- a/src/video/wincommon/SDL_wingl.c +++ b/src/video/wincommon/SDL_wingl.c @@ -177,6 +177,7 @@ int WIN_GL_SetupWindow(_THIS) int iAttribs[64]; int *iAttr; float fAttribs[1] = { 0 }; + const char *wglext; /* load the gl driver from a default path */ if ( ! this->gl_config.driver_loaded ) { @@ -289,6 +290,11 @@ int WIN_GL_SetupWindow(_THIS) *iAttr++ = this->gl_config.multisamplesamples; } + if ( this->gl_config.accelerated >= 0 ) { + *iAttr++ = WGL_ACCELERATION_ARB; + *iAttr++ = (this->gl_config.accelerated ? WGL_GENERIC_ACCELERATION_ARB : WGL_NO_ACCELERATION_ARB); + } + *iAttr = 0; /* Choose and set the closest available pixel format */ @@ -323,7 +329,25 @@ int WIN_GL_SetupWindow(_THIS) SDL_SetError("Unable to create GL context"); return(-1); } + if ( WIN_GL_MakeCurrent(this) < 0 ) { + return(-1); + } gl_active = 1; + + /* Vsync control under Windows. Checking glGetString here is + * somewhat a documented and reliable hack - it was originally + * as a feature added by mistake, but since so many people rely + * on it, it will not be removed. strstr should be safe here.*/ + wglext = (const char *)this->glGetString(GL_EXTENSIONS); + if ( !SDL_strstr(wglext, "WGL_EXT_swap_control") ) { + this->gl_data->wglSwapIntervalEXT = NULL; + this->gl_data->wglGetSwapIntervalEXT = NULL; + } + if ( this->gl_config.swap_control >= 0 ) { + if ( this->gl_data->wglSwapIntervalEXT ) { + this->gl_data->wglSwapIntervalEXT(this->gl_config.swap_control); + } + } #else SDL_SetError("WIN driver not configured with OpenGL"); #endif @@ -423,6 +447,22 @@ int WIN_GL_GetAttribute(_THIS, SDL_GLattr attrib, int* value) case SDL_GL_MULTISAMPLESAMPLES: wgl_attrib = WGL_SAMPLES_ARB; break; + case SDL_GL_ACCELERATED_VISUAL: + wgl_attrib = WGL_ACCELERATION_ARB; + this->gl_data->wglGetPixelFormatAttribivARB(GL_hdc, pixel_format, 0, 1, &wgl_attrib, value); + if ( *value == WGL_NO_ACCELERATION_ARB ) { + *value = SDL_FALSE; + } else { + *value = SDL_TRUE; + } + return 0; + break; + case SDL_GL_SWAP_CONTROL: + if ( this->gl_data->wglGetSwapIntervalEXT ) { + return this->gl_data->wglGetSwapIntervalEXT(); + } else { + return -1; + } default: return(-1); } @@ -509,6 +549,8 @@ void WIN_GL_UnloadLibrary(_THIS) this->gl_data->wglMakeCurrent = NULL; this->gl_data->wglChoosePixelFormatARB = NULL; this->gl_data->wglGetPixelFormatAttribivARB = NULL; + this->gl_data->wglSwapIntervalEXT = NULL; + this->gl_data->wglGetSwapIntervalEXT = NULL; this->gl_config.dll_handle = NULL; this->gl_config.driver_loaded = 0; @@ -547,6 +589,10 @@ int WIN_GL_LoadLibrary(_THIS, const char* path) GetProcAddress(handle, "wglDeleteContext"); this->gl_data->wglMakeCurrent = (BOOL (WINAPI *)(HDC, HGLRC)) GetProcAddress(handle, "wglMakeCurrent"); + this->gl_data->wglSwapIntervalEXT = (void (WINAPI *)(int)) + GetProcAddress(handle, "wglSwapIntervalEXT"); + this->gl_data->wglGetSwapIntervalEXT = (int (WINAPI *)(void)) + GetProcAddress(handle, "wglGetSwapIntervalEXT"); if ( (this->gl_data->wglGetProcAddress == NULL) || (this->gl_data->wglCreateContext == NULL) || diff --git a/src/video/wincommon/SDL_wingl_c.h b/src/video/wincommon/SDL_wingl_c.h index 795b7981d..5a1fd2277 100644 --- a/src/video/wincommon/SDL_wingl_c.h +++ b/src/video/wincommon/SDL_wingl_c.h @@ -53,6 +53,8 @@ struct SDL_PrivateGLData { UINT nAttributes, const int *piAttributes, int *piValues); + void (WINAPI *wglSwapIntervalEXT)(int interval); + int (WINAPI *wglGetSwapIntervalEXT)(void); #endif /* SDL_VIDEO_OPENGL */ }; diff --git a/src/video/x11/SDL_x11gl.c b/src/video/x11/SDL_x11gl.c index 54c1f9387..99ffbc88d 100644 --- a/src/video/x11/SDL_x11gl.c +++ b/src/video/x11/SDL_x11gl.c @@ -43,6 +43,47 @@ #define GLX_SAMPLES_ARB 100001 #endif +#ifndef GLX_EXT_visual_rating +#define GLX_EXT_visual_rating +#define GLX_VISUAL_CAVEAT_EXT 0x20 +#define GLX_SLOW_VISUAL_EXT 0x8001 +#define GLX_NON_CONFORMANT_VISUAL_EXT 0x800D +#endif + +#if SDL_VIDEO_OPENGL_GLX +static int glXExtensionSupported(_THIS, const char *extension) +{ + const char *extensions; + const char *start; + const char *where, *terminator; + + /* Extension names should not have spaces. */ + where = SDL_strchr(extension, ' '); + if ( where || *extension == '\0' ) { + return 0; + } + + extensions = this->gl_data->glXQueryExtensionsString(GFX_Display,SDL_Screen); + /* It takes a bit of care to be fool-proof about parsing the + * OpenGL extensions string. Don't be fooled by sub-strings, etc. + */ + + start = extensions; + + for (;;) { + where = SDL_strstr(start, extension); + if (!where) break; + + terminator = where + strlen(extension); + if (where == start || *(where - 1) == ' ') + if (*terminator == ' ' || *terminator == '\0') return 1; + + start = terminator; + } + return 0; +} +#endif /* SDL_VIDEO_OPENGL_GLX */ + XVisualInfo *X11_GL_GetVisual(_THIS) { #if SDL_VIDEO_OPENGL_GLX @@ -138,6 +179,12 @@ XVisualInfo *X11_GL_GetVisual(_THIS) attribs[i++] = this->gl_config.multisamplesamples; } + if( this->gl_config.accelerated >= 0 && + glXExtensionSupported(this, "GLX_EXT_visual_rating") ) { + attribs[i++] = GLX_VISUAL_CAVEAT_EXT; + attribs[i++] = this->gl_config.accelerated ? GLX_NONE : GLX_DONT_CARE; + } + #ifdef GLX_DIRECT_COLOR /* Try for a DirectColor visual for gamma support */ if ( !SDL_getenv("SDL_VIDEO_X11_NODIRECTCOLOR") ) { attribs[i++] = GLX_X_VISUAL_TYPE; @@ -205,18 +252,36 @@ int X11_GL_CreateContext(_THIS) { int retval; #if SDL_VIDEO_OPENGL_GLX + /* We do this to create a clean separation between X and GLX errors. */ XSync( SDL_Display, False ); glx_context = this->gl_data->glXCreateContext(GFX_Display, glx_visualinfo, NULL, True); XSync( GFX_Display, False ); - if (glx_context == NULL) { + if ( glx_context == NULL ) { SDL_SetError("Could not create GL context"); - return -1; + return(-1); + } + if ( X11_GL_MakeCurrent(this) < 0 ) { + return(-1); } - gl_active = 1; + + if ( !glXExtensionSupported(this, "SGI_swap_control") ) { + this->gl_data->glXSwapIntervalSGI = NULL; + } + if ( !glXExtensionSupported(this, "GLX_MESA_swap_control") ) { + this->gl_data->glXSwapIntervalMESA = NULL; + this->gl_data->glXGetSwapIntervalMESA = NULL; + } + if ( this->gl_config.swap_control >= 0 ) { + if ( this->gl_data->glXSwapIntervalMESA ) { + this->gl_data->glXSwapIntervalMESA(this->gl_config.swap_control); + } else if ( this->gl_data->glXSwapIntervalSGI ) { + this->gl_data->glXSwapIntervalSGI(this->gl_config.swap_control); + } + } #else SDL_SetError("X11 driver not configured with OpenGL"); #endif @@ -319,6 +384,27 @@ int X11_GL_GetAttribute(_THIS, SDL_GLattr attrib, int* value) case SDL_GL_MULTISAMPLESAMPLES: glx_attrib = GLX_SAMPLES_ARB; break; + case SDL_GL_ACCELERATED_VISUAL: + if ( glXExtensionSupported(this, "GLX_EXT_visual_rating") ) { + glx_attrib = GLX_VISUAL_CAVEAT_EXT; + retval = this->gl_data->glXGetConfig(GFX_Display, glx_visualinfo, glx_attrib, value); + if ( *value == GLX_SLOW_VISUAL_EXT ) { + *value = SDL_FALSE; + } else { + *value = SDL_TRUE; + } + return retval; + } else { + return(-1); + } + break; + case SDL_GL_SWAP_CONTROL: + if ( this->gl_data->glXGetSwapIntervalMESA ) { + return this->gl_data->glXGetSwapIntervalMESA(); + } else { + return(-1)/*(this->gl_config.swap_control > 0)*/; + } + break; default: return(-1); } @@ -348,6 +434,9 @@ void X11_GL_UnloadLibrary(_THIS) this->gl_data->glXDestroyContext = NULL; this->gl_data->glXMakeCurrent = NULL; this->gl_data->glXSwapBuffers = NULL; + this->gl_data->glXSwapIntervalSGI = NULL; + this->gl_data->glXSwapIntervalMESA = NULL; + this->gl_data->glXGetSwapIntervalMESA = NULL; this->gl_config.dll_handle = NULL; this->gl_config.driver_loaded = 0; @@ -400,7 +489,12 @@ int X11_GL_LoadLibrary(_THIS, const char* path) (int (*)(Display *, XVisualInfo *, int, int *)) SDL_LoadFunction(handle, "glXGetConfig"); this->gl_data->glXQueryExtensionsString = (const char *(*)(Display *, int)) SDL_LoadFunction(handle, "glXQueryExtensionsString"); - + this->gl_data->glXSwapIntervalSGI = + (int (*)(int)) SDL_LoadFunction(handle, "glXSwapIntervalSGI"); + this->gl_data->glXSwapIntervalMESA = + (GLint (*)(unsigned)) SDL_LoadFunction(handle, "glXSwapIntervalMESA"); + this->gl_data->glXGetSwapIntervalMESA = + (GLint (*)(void)) SDL_LoadFunction(handle, "glXGetSwapIntervalMESA"); if ( (this->gl_data->glXChooseVisual == NULL) || (this->gl_data->glXCreateContext == NULL) || diff --git a/src/video/x11/SDL_x11gl_c.h b/src/video/x11/SDL_x11gl_c.h index 0535678de..4cca3781e 100644 --- a/src/video/x11/SDL_x11gl_c.h +++ b/src/video/x11/SDL_x11gl_c.h @@ -71,7 +71,10 @@ struct SDL_PrivateGLData { ( Display* dpy, int screen ); - + int (*glXSwapIntervalSGI) ( int interval ); + GLint (*glXSwapIntervalMESA) ( unsigned interval ); + GLint (*glXGetSwapIntervalMESA) ( void ); + #endif /* SDL_VIDEO_OPENGL_GLX */ }; diff --git a/test/testgl.c b/test/testgl.c index 283d7fe26..551cdf6af 100644 --- a/test/testgl.c +++ b/test/testgl.c @@ -361,7 +361,7 @@ void DrawLogoTexture(void) } int RunGLTest( int argc, char* argv[], - int logo, int logocursor, int slowly, int bpp, float gamma, int noframe, int fsaa ) + int logo, int logocursor, int slowly, int bpp, float gamma, int noframe, int fsaa, int sync, int accel ) { int i; int rgb_size[3]; @@ -443,6 +443,14 @@ int RunGLTest( int argc, char* argv[], SDL_GL_SetAttribute( SDL_GL_MULTISAMPLEBUFFERS, 1 ); SDL_GL_SetAttribute( SDL_GL_MULTISAMPLESAMPLES, fsaa ); } + if ( accel ) { + SDL_GL_SetAttribute( SDL_GL_ACCELERATED_VISUAL, 1 ); + } + if ( sync ) { + SDL_GL_SetAttribute( SDL_GL_SWAP_CONTROL, 1 ); + } else { + SDL_GL_SetAttribute( SDL_GL_SWAP_CONTROL, 0 ); + } if ( SDL_SetVideoMode( w, h, bpp, video_flags ) == NULL ) { fprintf(stderr, "Couldn't set GL mode: %s\n", SDL_GetError()); SDL_Quit(); @@ -469,9 +477,17 @@ int RunGLTest( int argc, char* argv[], printf( "SDL_GL_DOUBLEBUFFER: requested 1, got %d\n", value ); if ( fsaa ) { SDL_GL_GetAttribute( SDL_GL_MULTISAMPLEBUFFERS, &value ); - printf( "SDL_GL_MULTISAMPLEBUFFERS: requested 1, got %d\n", value ); + printf("SDL_GL_MULTISAMPLEBUFFERS: requested 1, got %d\n", value ); SDL_GL_GetAttribute( SDL_GL_MULTISAMPLESAMPLES, &value ); - printf( "SDL_GL_MULTISAMPLESAMPLES: requested %d, got %d\n", fsaa, value ); + printf("SDL_GL_MULTISAMPLESAMPLES: requested %d, got %d\n", fsaa, value ); + } + if ( accel ) { + SDL_GL_GetAttribute( SDL_GL_ACCELERATED_VISUAL, &value ); + printf( "SDL_GL_ACCELERATED_VISUAL: requested 1, got %d\n", value ); + } + if ( sync ) { + SDL_GL_GetAttribute( SDL_GL_SWAP_CONTROL, &value ); + printf( "SDL_GL_SWAP_CONTROL: requested 1, got %d\n", value ); } /* Set the window manager title bar */ @@ -678,6 +694,8 @@ int main(int argc, char *argv[]) float gamma = 0.0; int noframe = 0; int fsaa = 0; + int accel = 0; + int sync = 0; logo = 0; slowly = 0; @@ -707,6 +725,12 @@ int main(int argc, char *argv[]) if ( strcmp(argv[i], "-fsaa") == 0 ) { ++fsaa; } + if ( strcmp(argv[i], "-accel") == 0 ) { + ++accel; + } + if ( strcmp(argv[i], "-sync") == 0 ) { + ++sync; + } if ( strncmp(argv[i], "-h", 2) == 0 ) { printf( "Usage: %s [-twice] [-logo] [-logocursor] [-slow] [-bpp n] [-gamma n] [-noframe] [-fsaa] [-fullscreen]\n", @@ -715,7 +739,7 @@ int main(int argc, char *argv[]) } } for ( i=0; i