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