SDL_x11opengl.c (28235B)
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org> 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20*/ 21#include "../../SDL_internal.h" 22 23#if SDL_VIDEO_DRIVER_X11 24 25#include "SDL_x11video.h" 26#include "SDL_assert.h" 27 28/* GLX implementation of SDL OpenGL support */ 29 30#if SDL_VIDEO_OPENGL_GLX 31#include "SDL_loadso.h" 32#include "SDL_x11opengles.h" 33 34#if defined(__IRIX__) 35/* IRIX doesn't have a GL library versioning system */ 36#define DEFAULT_OPENGL "libGL.so" 37#elif defined(__MACOSX__) 38#define DEFAULT_OPENGL "/usr/X11R6/lib/libGL.1.dylib" 39#elif defined(__QNXNTO__) 40#define DEFAULT_OPENGL "libGL.so.3" 41#else 42#define DEFAULT_OPENGL "libGL.so.1" 43#endif 44 45#ifndef GLX_NONE_EXT 46#define GLX_NONE_EXT 0x8000 47#endif 48 49#ifndef GLX_ARB_multisample 50#define GLX_ARB_multisample 51#define GLX_SAMPLE_BUFFERS_ARB 100000 52#define GLX_SAMPLES_ARB 100001 53#endif 54 55#ifndef GLX_EXT_visual_rating 56#define GLX_EXT_visual_rating 57#define GLX_VISUAL_CAVEAT_EXT 0x20 58#define GLX_NONE_EXT 0x8000 59#define GLX_SLOW_VISUAL_EXT 0x8001 60#define GLX_NON_CONFORMANT_VISUAL_EXT 0x800D 61#endif 62 63#ifndef GLX_EXT_visual_info 64#define GLX_EXT_visual_info 65#define GLX_X_VISUAL_TYPE_EXT 0x22 66#define GLX_DIRECT_COLOR_EXT 0x8003 67#endif 68 69#ifndef GLX_ARB_create_context 70#define GLX_ARB_create_context 71#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091 72#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092 73#define GLX_CONTEXT_FLAGS_ARB 0x2094 74#define GLX_CONTEXT_DEBUG_BIT_ARB 0x0001 75#define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002 76 77/* Typedef for the GL 3.0 context creation function */ 78typedef GLXContext(*PFNGLXCREATECONTEXTATTRIBSARBPROC) (Display * dpy, 79 GLXFBConfig config, 80 GLXContext 81 share_context, 82 Bool direct, 83 const int 84 *attrib_list); 85#endif 86 87#ifndef GLX_ARB_create_context_profile 88#define GLX_ARB_create_context_profile 89#define GLX_CONTEXT_PROFILE_MASK_ARB 0x9126 90#define GLX_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 91#define GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 92#endif 93 94#ifndef GLX_ARB_create_context_robustness 95#define GLX_ARB_create_context_robustness 96#define GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004 97#define GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 98#define GLX_NO_RESET_NOTIFICATION_ARB 0x8261 99#define GLX_LOSE_CONTEXT_ON_RESET_ARB 0x8252 100#endif 101 102#ifndef GLX_EXT_create_context_es2_profile 103#define GLX_EXT_create_context_es2_profile 104#ifndef GLX_CONTEXT_ES2_PROFILE_BIT_EXT 105#define GLX_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000002 106#endif 107#endif 108 109#ifndef GLX_ARB_framebuffer_sRGB 110#define GLX_ARB_framebuffer_sRGB 111#ifndef GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB 112#define GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20B2 113#endif 114#endif 115 116#ifndef GLX_EXT_swap_control 117#define GLX_SWAP_INTERVAL_EXT 0x20F1 118#define GLX_MAX_SWAP_INTERVAL_EXT 0x20F2 119#endif 120 121#ifndef GLX_EXT_swap_control_tear 122#define GLX_LATE_SWAPS_TEAR_EXT 0x20F3 123#endif 124 125#define OPENGL_REQUIRES_DLOPEN 126#if defined(OPENGL_REQUIRES_DLOPEN) && defined(SDL_LOADSO_DLOPEN) 127#include <dlfcn.h> 128#define GL_LoadObject(X) dlopen(X, (RTLD_NOW|RTLD_GLOBAL)) 129#define GL_LoadFunction dlsym 130#define GL_UnloadObject dlclose 131#else 132#define GL_LoadObject SDL_LoadObject 133#define GL_LoadFunction SDL_LoadFunction 134#define GL_UnloadObject SDL_UnloadObject 135#endif 136 137static void X11_GL_InitExtensions(_THIS); 138 139 140int 141X11_GL_LoadLibrary(_THIS, const char *path) 142{ 143 Display *display; 144 void *handle; 145 146 if (_this->gl_data) { 147 return SDL_SetError("OpenGL context already created"); 148 } 149 150 /* Load the OpenGL library */ 151 if (path == NULL) { 152 path = SDL_getenv("SDL_OPENGL_LIBRARY"); 153 } 154 if (path == NULL) { 155 path = DEFAULT_OPENGL; 156 } 157 _this->gl_config.dll_handle = GL_LoadObject(path); 158 if (!_this->gl_config.dll_handle) { 159#if defined(OPENGL_REQUIRES_DLOPEN) && defined(SDL_LOADSO_DLOPEN) 160 SDL_SetError("Failed loading %s: %s", path, dlerror()); 161#endif 162 return -1; 163 } 164 SDL_strlcpy(_this->gl_config.driver_path, path, 165 SDL_arraysize(_this->gl_config.driver_path)); 166 167 /* Allocate OpenGL memory */ 168 _this->gl_data = 169 (struct SDL_GLDriverData *) SDL_calloc(1, 170 sizeof(struct 171 SDL_GLDriverData)); 172 if (!_this->gl_data) { 173 return SDL_OutOfMemory(); 174 } 175 176 /* Load function pointers */ 177 handle = _this->gl_config.dll_handle; 178 _this->gl_data->glXQueryExtension = 179 (Bool (*)(Display *, int *, int *)) 180 GL_LoadFunction(handle, "glXQueryExtension"); 181 _this->gl_data->glXGetProcAddress = 182 (void *(*)(const GLubyte *)) 183 GL_LoadFunction(handle, "glXGetProcAddressARB"); 184 _this->gl_data->glXChooseVisual = 185 (XVisualInfo * (*)(Display *, int, int *)) 186 X11_GL_GetProcAddress(_this, "glXChooseVisual"); 187 _this->gl_data->glXCreateContext = 188 (GLXContext(*)(Display *, XVisualInfo *, GLXContext, int)) 189 X11_GL_GetProcAddress(_this, "glXCreateContext"); 190 _this->gl_data->glXDestroyContext = 191 (void (*)(Display *, GLXContext)) 192 X11_GL_GetProcAddress(_this, "glXDestroyContext"); 193 _this->gl_data->glXMakeCurrent = 194 (int (*)(Display *, GLXDrawable, GLXContext)) 195 X11_GL_GetProcAddress(_this, "glXMakeCurrent"); 196 _this->gl_data->glXSwapBuffers = 197 (void (*)(Display *, GLXDrawable)) 198 X11_GL_GetProcAddress(_this, "glXSwapBuffers"); 199 _this->gl_data->glXQueryDrawable = 200 (void (*)(Display*,GLXDrawable,int,unsigned int*)) 201 X11_GL_GetProcAddress(_this, "glXQueryDrawable"); 202 203 if (!_this->gl_data->glXQueryExtension || 204 !_this->gl_data->glXChooseVisual || 205 !_this->gl_data->glXCreateContext || 206 !_this->gl_data->glXDestroyContext || 207 !_this->gl_data->glXMakeCurrent || 208 !_this->gl_data->glXSwapBuffers) { 209 return SDL_SetError("Could not retrieve OpenGL functions"); 210 } 211 212 display = ((SDL_VideoData *) _this->driverdata)->display; 213 if (!_this->gl_data->glXQueryExtension(display, &_this->gl_data->errorBase, &_this->gl_data->eventBase)) { 214 return SDL_SetError("GLX is not supported"); 215 } 216 217 /* Initialize extensions */ 218 X11_GL_InitExtensions(_this); 219 220 /* If we need a GL ES context and there's no 221 * GLX_EXT_create_context_es2_profile extension, switch over to X11_GLES functions 222 */ 223 if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES && 224 ! _this->gl_data->HAS_GLX_EXT_create_context_es2_profile ) { 225#if SDL_VIDEO_OPENGL_EGL 226 X11_GL_UnloadLibrary(_this); 227 /* Better avoid conflicts! */ 228 if (_this->gl_config.dll_handle != NULL ) { 229 GL_UnloadObject(_this->gl_config.dll_handle); 230 _this->gl_config.dll_handle = NULL; 231 } 232 _this->GL_LoadLibrary = X11_GLES_LoadLibrary; 233 _this->GL_GetProcAddress = X11_GLES_GetProcAddress; 234 _this->GL_UnloadLibrary = X11_GLES_UnloadLibrary; 235 _this->GL_CreateContext = X11_GLES_CreateContext; 236 _this->GL_MakeCurrent = X11_GLES_MakeCurrent; 237 _this->GL_SetSwapInterval = X11_GLES_SetSwapInterval; 238 _this->GL_GetSwapInterval = X11_GLES_GetSwapInterval; 239 _this->GL_SwapWindow = X11_GLES_SwapWindow; 240 _this->GL_DeleteContext = X11_GLES_DeleteContext; 241 return X11_GLES_LoadLibrary(_this, NULL); 242#else 243 return SDL_SetError("SDL not configured with EGL support"); 244#endif 245 } 246 247 return 0; 248} 249 250void * 251X11_GL_GetProcAddress(_THIS, const char *proc) 252{ 253 if (_this->gl_data->glXGetProcAddress) { 254 return _this->gl_data->glXGetProcAddress((const GLubyte *) proc); 255 } 256 return GL_LoadFunction(_this->gl_config.dll_handle, proc); 257} 258 259void 260X11_GL_UnloadLibrary(_THIS) 261{ 262 /* Don't actually unload the library, since it may have registered 263 * X11 shutdown hooks, per the notes at: 264 * http://dri.sourceforge.net/doc/DRIuserguide.html 265 */ 266#if 0 267 GL_UnloadObject(_this->gl_config.dll_handle); 268 _this->gl_config.dll_handle = NULL; 269#endif 270 271 /* Free OpenGL memory */ 272 SDL_free(_this->gl_data); 273 _this->gl_data = NULL; 274} 275 276static SDL_bool 277HasExtension(const char *extension, const char *extensions) 278{ 279 const char *start; 280 const char *where, *terminator; 281 282 /* Extension names should not have spaces. */ 283 where = SDL_strchr(extension, ' '); 284 if (where || *extension == '\0') 285 return SDL_FALSE; 286 287 if (!extensions) 288 return SDL_FALSE; 289 290 /* It takes a bit of care to be fool-proof about parsing the 291 * OpenGL extensions string. Don't be fooled by sub-strings, 292 * etc. */ 293 294 start = extensions; 295 296 for (;;) { 297 where = SDL_strstr(start, extension); 298 if (!where) 299 break; 300 301 terminator = where + SDL_strlen(extension); 302 if (where == start || *(where - 1) == ' ') 303 if (*terminator == ' ' || *terminator == '\0') 304 return SDL_TRUE; 305 306 start = terminator; 307 } 308 return SDL_FALSE; 309} 310 311static void 312X11_GL_InitExtensions(_THIS) 313{ 314 Display *display = ((SDL_VideoData *) _this->driverdata)->display; 315 int screen = DefaultScreen(display); 316 XVisualInfo *vinfo; 317 XSetWindowAttributes xattr; 318 Window w; 319 GLXContext context; 320 const char *(*glXQueryExtensionsStringFunc) (Display *, int); 321 const char *extensions; 322 323 vinfo = X11_GL_GetVisual(_this, display, screen); 324 if (!vinfo) { 325 return; 326 } 327 xattr.background_pixel = 0; 328 xattr.border_pixel = 0; 329 xattr.colormap = 330 X11_XCreateColormap(display, RootWindow(display, screen), vinfo->visual, 331 AllocNone); 332 w = X11_XCreateWindow(display, RootWindow(display, screen), 0, 0, 32, 32, 0, 333 vinfo->depth, InputOutput, vinfo->visual, 334 (CWBackPixel | CWBorderPixel | CWColormap), &xattr); 335 context = _this->gl_data->glXCreateContext(display, vinfo, NULL, True); 336 if (context) { 337 _this->gl_data->glXMakeCurrent(display, w, context); 338 } 339 X11_XFree(vinfo); 340 341 glXQueryExtensionsStringFunc = 342 (const char *(*)(Display *, int)) X11_GL_GetProcAddress(_this, 343 "glXQueryExtensionsString"); 344 if (glXQueryExtensionsStringFunc) { 345 extensions = glXQueryExtensionsStringFunc(display, screen); 346 } else { 347 extensions = NULL; 348 } 349 350 /* Check for GLX_EXT_swap_control(_tear) */ 351 _this->gl_data->HAS_GLX_EXT_swap_control_tear = SDL_FALSE; 352 if (HasExtension("GLX_EXT_swap_control", extensions)) { 353 _this->gl_data->glXSwapIntervalEXT = 354 (void (*)(Display*,GLXDrawable,int)) 355 X11_GL_GetProcAddress(_this, "glXSwapIntervalEXT"); 356 if (HasExtension("GLX_EXT_swap_control_tear", extensions)) { 357 _this->gl_data->HAS_GLX_EXT_swap_control_tear = SDL_TRUE; 358 } 359 } 360 361 /* Check for GLX_MESA_swap_control */ 362 if (HasExtension("GLX_MESA_swap_control", extensions)) { 363 _this->gl_data->glXSwapIntervalMESA = 364 (int(*)(int)) X11_GL_GetProcAddress(_this, "glXSwapIntervalMESA"); 365 _this->gl_data->glXGetSwapIntervalMESA = 366 (int(*)(void)) X11_GL_GetProcAddress(_this, 367 "glXGetSwapIntervalMESA"); 368 } 369 370 /* Check for GLX_SGI_swap_control */ 371 if (HasExtension("GLX_SGI_swap_control", extensions)) { 372 _this->gl_data->glXSwapIntervalSGI = 373 (int (*)(int)) X11_GL_GetProcAddress(_this, "glXSwapIntervalSGI"); 374 } 375 376 /* Check for GLX_EXT_visual_rating */ 377 if (HasExtension("GLX_EXT_visual_rating", extensions)) { 378 _this->gl_data->HAS_GLX_EXT_visual_rating = SDL_TRUE; 379 } 380 381 /* Check for GLX_EXT_visual_info */ 382 if (HasExtension("GLX_EXT_visual_info", extensions)) { 383 _this->gl_data->HAS_GLX_EXT_visual_info = SDL_TRUE; 384 } 385 386 /* Check for GLX_EXT_create_context_es2_profile */ 387 if (HasExtension("GLX_EXT_create_context_es2_profile", extensions)) { 388 _this->gl_data->HAS_GLX_EXT_create_context_es2_profile = SDL_TRUE; 389 } 390 391 if (context) { 392 _this->gl_data->glXMakeCurrent(display, None, NULL); 393 _this->gl_data->glXDestroyContext(display, context); 394 } 395 X11_XDestroyWindow(display, w); 396 X11_PumpEvents(_this); 397} 398 399/* glXChooseVisual and glXChooseFBConfig have some small differences in 400 * the attribute encoding, it can be chosen with the for_FBConfig parameter. 401 */ 402int 403X11_GL_GetAttributes(_THIS, Display * display, int screen, int * attribs, int size, Bool for_FBConfig) 404{ 405 int i = 0; 406 const int MAX_ATTRIBUTES = 64; 407 408 /* assert buffer is large enough to hold all SDL attributes. */ 409 SDL_assert(size >= MAX_ATTRIBUTES); 410 411 /* Setup our GLX attributes according to the gl_config. */ 412 if( for_FBConfig ) { 413 attribs[i++] = GLX_RENDER_TYPE; 414 attribs[i++] = GLX_RGBA_BIT; 415 } else { 416 attribs[i++] = GLX_RGBA; 417 } 418 attribs[i++] = GLX_RED_SIZE; 419 attribs[i++] = _this->gl_config.red_size; 420 attribs[i++] = GLX_GREEN_SIZE; 421 attribs[i++] = _this->gl_config.green_size; 422 attribs[i++] = GLX_BLUE_SIZE; 423 attribs[i++] = _this->gl_config.blue_size; 424 425 if (_this->gl_config.alpha_size) { 426 attribs[i++] = GLX_ALPHA_SIZE; 427 attribs[i++] = _this->gl_config.alpha_size; 428 } 429 430 if (_this->gl_config.double_buffer) { 431 attribs[i++] = GLX_DOUBLEBUFFER; 432 if( for_FBConfig ) { 433 attribs[i++] = True; 434 } 435 } 436 437 attribs[i++] = GLX_DEPTH_SIZE; 438 attribs[i++] = _this->gl_config.depth_size; 439 440 if (_this->gl_config.stencil_size) { 441 attribs[i++] = GLX_STENCIL_SIZE; 442 attribs[i++] = _this->gl_config.stencil_size; 443 } 444 445 if (_this->gl_config.accum_red_size) { 446 attribs[i++] = GLX_ACCUM_RED_SIZE; 447 attribs[i++] = _this->gl_config.accum_red_size; 448 } 449 450 if (_this->gl_config.accum_green_size) { 451 attribs[i++] = GLX_ACCUM_GREEN_SIZE; 452 attribs[i++] = _this->gl_config.accum_green_size; 453 } 454 455 if (_this->gl_config.accum_blue_size) { 456 attribs[i++] = GLX_ACCUM_BLUE_SIZE; 457 attribs[i++] = _this->gl_config.accum_blue_size; 458 } 459 460 if (_this->gl_config.accum_alpha_size) { 461 attribs[i++] = GLX_ACCUM_ALPHA_SIZE; 462 attribs[i++] = _this->gl_config.accum_alpha_size; 463 } 464 465 if (_this->gl_config.stereo) { 466 attribs[i++] = GLX_STEREO; 467 if( for_FBConfig ) { 468 attribs[i++] = True; 469 } 470 } 471 472 if (_this->gl_config.multisamplebuffers) { 473 attribs[i++] = GLX_SAMPLE_BUFFERS_ARB; 474 attribs[i++] = _this->gl_config.multisamplebuffers; 475 } 476 477 if (_this->gl_config.multisamplesamples) { 478 attribs[i++] = GLX_SAMPLES_ARB; 479 attribs[i++] = _this->gl_config.multisamplesamples; 480 } 481 482 if (_this->gl_config.framebuffer_srgb_capable) { 483 attribs[i++] = GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB; 484 if( for_FBConfig ) { 485 attribs[i++] = True; 486 } 487 } 488 489 if (_this->gl_config.accelerated >= 0 && 490 _this->gl_data->HAS_GLX_EXT_visual_rating) { 491 attribs[i++] = GLX_VISUAL_CAVEAT_EXT; 492 attribs[i++] = _this->gl_config.accelerated ? GLX_NONE_EXT : 493 GLX_SLOW_VISUAL_EXT; 494 } 495 496 /* If we're supposed to use DirectColor visuals, and we've got the 497 EXT_visual_info extension, then add GLX_X_VISUAL_TYPE_EXT. */ 498 if (X11_UseDirectColorVisuals() && 499 _this->gl_data->HAS_GLX_EXT_visual_info) { 500 attribs[i++] = GLX_X_VISUAL_TYPE_EXT; 501 attribs[i++] = GLX_DIRECT_COLOR_EXT; 502 } 503 504 attribs[i++] = None; 505 506 SDL_assert(i <= MAX_ATTRIBUTES); 507 508 return i; 509} 510 511XVisualInfo * 512X11_GL_GetVisual(_THIS, Display * display, int screen) 513{ 514 /* 64 seems nice. */ 515 int attribs[64]; 516 XVisualInfo *vinfo; 517 518 if (!_this->gl_data) { 519 /* The OpenGL library wasn't loaded, SDL_GetError() should have info */ 520 return NULL; 521 } 522 523 X11_GL_GetAttributes(_this, display, screen, attribs, 64, SDL_FALSE); 524 vinfo = _this->gl_data->glXChooseVisual(display, screen, attribs); 525 if (!vinfo) { 526 SDL_SetError("Couldn't find matching GLX visual"); 527 } 528 return vinfo; 529} 530 531#ifndef GLXBadContext 532#define GLXBadContext 0 533#endif 534#ifndef GLXBadFBConfig 535#define GLXBadFBConfig 9 536#endif 537#ifndef GLXBadProfileARB 538#define GLXBadProfileARB 13 539#endif 540static int (*handler) (Display *, XErrorEvent *) = NULL; 541static int errorBase = 0; 542static int errorCode = 0; 543static int 544X11_GL_CreateContextErrorHandler(Display * d, XErrorEvent * e) 545{ 546 char *x11_error = NULL; 547 char x11_error_locale[256]; 548 549 errorCode = e->error_code; 550 if (X11_XGetErrorText(d, errorCode, x11_error_locale, sizeof(x11_error_locale)) == Success) 551 { 552 x11_error = SDL_iconv_string("UTF-8", "", x11_error_locale, SDL_strlen(x11_error_locale)+1); 553 } 554 555 if (x11_error) 556 { 557 SDL_SetError("Could not create GL context: %s", x11_error); 558 SDL_free(x11_error); 559 } 560 else 561 { 562 SDL_SetError("Could not create GL context: %i (Base %i)\n", errorCode, errorBase); 563 } 564 565 return (0); 566} 567 568SDL_GLContext 569X11_GL_CreateContext(_THIS, SDL_Window * window) 570{ 571 SDL_WindowData *data = (SDL_WindowData *) window->driverdata; 572 Display *display = data->videodata->display; 573 int screen = 574 ((SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata)->screen; 575 XWindowAttributes xattr; 576 XVisualInfo v, *vinfo; 577 int n; 578 GLXContext context = NULL, share_context; 579 PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribs = NULL; 580 581 if (_this->gl_config.share_with_current_context) { 582 share_context = (GLXContext)SDL_GL_GetCurrentContext(); 583 } else { 584 share_context = NULL; 585 } 586 587 /* We do this to create a clean separation between X and GLX errors. */ 588 X11_XSync(display, False); 589 errorBase = _this->gl_data->errorBase; 590 errorCode = Success; 591 handler = X11_XSetErrorHandler(X11_GL_CreateContextErrorHandler); 592 X11_XGetWindowAttributes(display, data->xwindow, &xattr); 593 v.screen = screen; 594 v.visualid = X11_XVisualIDFromVisual(xattr.visual); 595 vinfo = X11_XGetVisualInfo(display, VisualScreenMask | VisualIDMask, &v, &n); 596 if (vinfo) { 597 if (_this->gl_config.major_version < 3 && 598 _this->gl_config.profile_mask == 0 && 599 _this->gl_config.flags == 0) { 600 /* Create legacy context */ 601 context = 602 _this->gl_data->glXCreateContext(display, vinfo, share_context, True); 603 } else { 604 /* If we want a GL 3.0 context or later we need to get a temporary 605 context to grab the new context creation function */ 606 GLXContext temp_context = 607 _this->gl_data->glXCreateContext(display, vinfo, NULL, True); 608 if (temp_context) { 609 /* max 8 attributes plus terminator */ 610 int attribs[9] = { 611 GLX_CONTEXT_MAJOR_VERSION_ARB, 612 _this->gl_config.major_version, 613 GLX_CONTEXT_MINOR_VERSION_ARB, 614 _this->gl_config.minor_version, 615 0 616 }; 617 int iattr = 4; 618 619 /* SDL profile bits match GLX profile bits */ 620 if( _this->gl_config.profile_mask != 0 ) { 621 attribs[iattr++] = GLX_CONTEXT_PROFILE_MASK_ARB; 622 attribs[iattr++] = _this->gl_config.profile_mask; 623 } 624 625 /* SDL flags match GLX flags */ 626 if( _this->gl_config.flags != 0 ) { 627 attribs[iattr++] = GLX_CONTEXT_FLAGS_ARB; 628 attribs[iattr++] = _this->gl_config.flags; 629 } 630 631 attribs[iattr++] = 0; 632 633 /* Get a pointer to the context creation function for GL 3.0 */ 634 glXCreateContextAttribs = 635 (PFNGLXCREATECONTEXTATTRIBSARBPROC) _this->gl_data-> 636 glXGetProcAddress((GLubyte *) 637 "glXCreateContextAttribsARB"); 638 if (!glXCreateContextAttribs) { 639 SDL_SetError("GL 3.x is not supported"); 640 context = temp_context; 641 } else { 642 int glxAttribs[64]; 643 644 /* Create a GL 3.x context */ 645 GLXFBConfig *framebuffer_config = NULL; 646 int fbcount = 0; 647 GLXFBConfig *(*glXChooseFBConfig) (Display * disp, 648 int screen, 649 const int *attrib_list, 650 int *nelements); 651 652 glXChooseFBConfig = 653 (GLXFBConfig * 654 (*)(Display *, int, const int *, 655 int *)) _this->gl_data-> 656 glXGetProcAddress((GLubyte *) "glXChooseFBConfig"); 657 658 X11_GL_GetAttributes(_this,display,screen,glxAttribs,64,SDL_TRUE); 659 660 if (!glXChooseFBConfig 661 || !(framebuffer_config = 662 glXChooseFBConfig(display, 663 DefaultScreen(display), glxAttribs, 664 &fbcount))) { 665 SDL_SetError 666 ("No good framebuffers found. GL 3.x disabled"); 667 context = temp_context; 668 } else { 669 context = 670 glXCreateContextAttribs(display, 671 framebuffer_config[0], 672 share_context, True, attribs); 673 _this->gl_data->glXDestroyContext(display, 674 temp_context); 675 } 676 } 677 } 678 } 679 X11_XFree(vinfo); 680 } 681 X11_XSync(display, False); 682 X11_XSetErrorHandler(handler); 683 684 if (!context) { 685 if (errorCode == Success) { 686 SDL_SetError("Could not create GL context"); 687 } 688 return NULL; 689 } 690 691 if (X11_GL_MakeCurrent(_this, window, context) < 0) { 692 X11_GL_DeleteContext(_this, context); 693 return NULL; 694 } 695 696 return context; 697} 698 699int 700X11_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context) 701{ 702 Display *display = ((SDL_VideoData *) _this->driverdata)->display; 703 Window drawable = 704 (context ? ((SDL_WindowData *) window->driverdata)->xwindow : None); 705 GLXContext glx_context = (GLXContext) context; 706 707 if (!_this->gl_data) { 708 return SDL_SetError("OpenGL not initialized"); 709 } 710 711 if (!_this->gl_data->glXMakeCurrent(display, drawable, glx_context)) { 712 return SDL_SetError("Unable to make GL context current"); 713 } 714 715 return 0; 716} 717 718/* 719 0 is a valid argument to glxSwapInterval(MESA|EXT) and setting it to 0 720 will undo the effect of a previous call with a value that is greater 721 than zero (or at least that is what the docs say). OTOH, 0 is an invalid 722 argument to glxSwapIntervalSGI and it returns an error if you call it 723 with 0 as an argument. 724*/ 725 726static int swapinterval = -1; 727int 728X11_GL_SetSwapInterval(_THIS, int interval) 729{ 730 int status = -1; 731 732 if ((interval < 0) && (!_this->gl_data->HAS_GLX_EXT_swap_control_tear)) { 733 SDL_SetError("Negative swap interval unsupported in this GL"); 734 } else if (_this->gl_data->glXSwapIntervalEXT) { 735 Display *display = ((SDL_VideoData *) _this->driverdata)->display; 736 const SDL_WindowData *windowdata = (SDL_WindowData *) 737 SDL_GL_GetCurrentWindow()->driverdata; 738 739 Window drawable = windowdata->xwindow; 740 741 /* 742 * This is a workaround for a bug in NVIDIA drivers. Bug has been reported 743 * and will be fixed in a future release (probably 319.xx). 744 * 745 * There's a bug where glXSetSwapIntervalEXT ignores updates because 746 * it has the wrong value cached. To work around it, we just run a no-op 747 * update to the current value. 748 */ 749 int currentInterval = X11_GL_GetSwapInterval(_this); 750 _this->gl_data->glXSwapIntervalEXT(display, drawable, currentInterval); 751 _this->gl_data->glXSwapIntervalEXT(display, drawable, interval); 752 753 status = 0; 754 swapinterval = interval; 755 } else if (_this->gl_data->glXSwapIntervalMESA) { 756 status = _this->gl_data->glXSwapIntervalMESA(interval); 757 if (status != 0) { 758 SDL_SetError("glxSwapIntervalMESA failed"); 759 } else { 760 swapinterval = interval; 761 } 762 } else if (_this->gl_data->glXSwapIntervalSGI) { 763 status = _this->gl_data->glXSwapIntervalSGI(interval); 764 if (status != 0) { 765 SDL_SetError("glxSwapIntervalSGI failed"); 766 } else { 767 swapinterval = interval; 768 } 769 } else { 770 SDL_Unsupported(); 771 } 772 return status; 773} 774 775int 776X11_GL_GetSwapInterval(_THIS) 777{ 778 if (_this->gl_data->glXSwapIntervalEXT) { 779 Display *display = ((SDL_VideoData *) _this->driverdata)->display; 780 const SDL_WindowData *windowdata = (SDL_WindowData *) 781 SDL_GL_GetCurrentWindow()->driverdata; 782 Window drawable = windowdata->xwindow; 783 unsigned int allow_late_swap_tearing = 0; 784 unsigned int interval = 0; 785 786 if (_this->gl_data->HAS_GLX_EXT_swap_control_tear) { 787 _this->gl_data->glXQueryDrawable(display, drawable, 788 GLX_LATE_SWAPS_TEAR_EXT, 789 &allow_late_swap_tearing); 790 } 791 792 _this->gl_data->glXQueryDrawable(display, drawable, 793 GLX_SWAP_INTERVAL_EXT, &interval); 794 795 if ((allow_late_swap_tearing) && (interval > 0)) { 796 return -((int) interval); 797 } 798 799 return (int) interval; 800 } else if (_this->gl_data->glXGetSwapIntervalMESA) { 801 return _this->gl_data->glXGetSwapIntervalMESA(); 802 } else { 803 return swapinterval; 804 } 805} 806 807void 808X11_GL_SwapWindow(_THIS, SDL_Window * window) 809{ 810 SDL_WindowData *data = (SDL_WindowData *) window->driverdata; 811 Display *display = data->videodata->display; 812 813 _this->gl_data->glXSwapBuffers(display, data->xwindow); 814} 815 816void 817X11_GL_DeleteContext(_THIS, SDL_GLContext context) 818{ 819 Display *display = ((SDL_VideoData *) _this->driverdata)->display; 820 GLXContext glx_context = (GLXContext) context; 821 822 if (!_this->gl_data) { 823 return; 824 } 825 _this->gl_data->glXDestroyContext(display, glx_context); 826 X11_XSync(display, False); 827} 828 829#endif /* SDL_VIDEO_OPENGL_GLX */ 830 831#endif /* SDL_VIDEO_DRIVER_X11 */ 832 833/* vi: set ts=4 sw=4 expandtab: */