Atlas - SDL_x11opengl.c

Home / ext / SDL / src / video / x11 Lines: 1 | Size: 41991 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)]
[FILE BEGIN]
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2025 Sam Lantinga <[email protected]> 4 Copyright (C) 2021 NVIDIA Corporation 5 6 This software is provided 'as-is', without any express or implied 7 warranty. In no event will the authors be held liable for any damages 8 arising from the use of this software. 9 10 Permission is granted to anyone to use this software for any purpose, 11 including commercial applications, and to alter it and redistribute it 12 freely, subject to the following restrictions: 13 14 1. The origin of this software must not be misrepresented; you must not 15 claim that you wrote the original software. If you use this software 16 in a product, an acknowledgment in the product documentation would be 17 appreciated but is not required. 18 2. Altered source versions must be plainly marked as such, and must not be 19 misrepresented as being the original software. 20 3. This notice may not be removed or altered from any source distribution. 21*/ 22#include "SDL_internal.h" 23 24#ifdef SDL_VIDEO_DRIVER_X11 25 26#include "SDL_x11video.h" 27#include "SDL_x11xsync.h" 28 29// GLX implementation of SDL OpenGL support 30 31#ifdef SDL_VIDEO_OPENGL_GLX 32#include "SDL_x11opengles.h" 33 34#if defined(SDL_PLATFORM_IRIX) || defined(SDL_PLATFORM_NETBSD) || defined(SDL_PLATFORM_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(SDL_PLATFORM_MACOS) 42#define DEFAULT_OPENGL "/opt/X11/lib/libGL.1.dylib" 43#else 44#define DEFAULT_OPENGL "libGL.so.1" 45#endif 46 47#ifndef GLX_NONE_EXT 48#define GLX_NONE_EXT 0x8000 49#endif 50 51#ifndef GLX_ARB_multisample 52#define GLX_ARB_multisample 53#define GLX_SAMPLE_BUFFERS_ARB 100000 54#define GLX_SAMPLES_ARB 100001 55#endif 56 57#ifndef GLX_EXT_visual_rating 58#define GLX_EXT_visual_rating 59#define GLX_VISUAL_CAVEAT_EXT 0x20 60#define GLX_NONE_EXT 0x8000 61#define GLX_SLOW_VISUAL_EXT 0x8001 62#define GLX_NON_CONFORMANT_VISUAL_EXT 0x800D 63#endif 64 65#ifndef GLX_EXT_visual_info 66#define GLX_EXT_visual_info 67#define GLX_X_VISUAL_TYPE_EXT 0x22 68#define GLX_DIRECT_COLOR_EXT 0x8003 69#endif 70 71#ifndef GLX_ARB_create_context 72#define GLX_ARB_create_context 73#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091 74#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092 75#define GLX_CONTEXT_FLAGS_ARB 0x2094 76#define GLX_CONTEXT_DEBUG_BIT_ARB 0x0001 77#define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002 78 79// Typedef for the GL 3.0 context creation function 80typedef GLXContext (*PFNGLXCREATECONTEXTATTRIBSARBPROC)(Display *dpy, 81 GLXFBConfig config, 82 GLXContext 83 share_context, 84 Bool direct, 85 const int 86 *attrib_list); 87#endif 88 89#ifndef GLX_ARB_create_context_profile 90#define GLX_ARB_create_context_profile 91#define GLX_CONTEXT_PROFILE_MASK_ARB 0x9126 92#define GLX_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 93#define GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 94#endif 95 96#ifndef GLX_ARB_create_context_robustness 97#define GLX_ARB_create_context_robustness 98#define GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004 99#define GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 100#define GLX_NO_RESET_NOTIFICATION_ARB 0x8261 101#define GLX_LOSE_CONTEXT_ON_RESET_ARB 0x8252 102#endif 103 104#ifndef GLX_EXT_create_context_es2_profile 105#define GLX_EXT_create_context_es2_profile 106#ifndef GLX_CONTEXT_ES2_PROFILE_BIT_EXT 107#define GLX_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000002 108#endif 109#endif 110 111#ifndef GLX_ARB_framebuffer_sRGB 112#define GLX_ARB_framebuffer_sRGB 113#ifndef GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB 114#define GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20B2 115#endif 116#endif 117 118#ifndef GLX_ARB_fbconfig_float 119#define GLX_ARB_fbconfig_float 120#ifndef GLX_RGBA_FLOAT_TYPE_ARB 121#define GLX_RGBA_FLOAT_TYPE_ARB 0x20B9 122#endif 123#ifndef GLX_RGBA_FLOAT_BIT_ARB 124#define GLX_RGBA_FLOAT_BIT_ARB 0x00000004 125#endif 126#endif 127 128#ifndef GLX_ARB_create_context_no_error 129#define GLX_ARB_create_context_no_error 130#ifndef GLX_CONTEXT_OPENGL_NO_ERROR_ARB 131#define GLX_CONTEXT_OPENGL_NO_ERROR_ARB 0x31B3 132#endif 133#endif 134 135#ifndef GLX_EXT_swap_control 136#define GLX_SWAP_INTERVAL_EXT 0x20F1 137#define GLX_MAX_SWAP_INTERVAL_EXT 0x20F2 138#endif 139 140#ifndef GLX_EXT_swap_control_tear 141#define GLX_LATE_SWAPS_TEAR_EXT 0x20F3 142#endif 143 144#ifndef GLX_ARB_context_flush_control 145#define GLX_ARB_context_flush_control 146#define GLX_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097 147#define GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB 0x0000 148#define GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098 149#endif 150 151#define OPENGL_REQUIRES_DLOPEN 152#if defined(OPENGL_REQUIRES_DLOPEN) && defined(HAVE_DLOPEN) 153#include <dlfcn.h> 154#define GL_LoadObject(X) dlopen(X, (RTLD_NOW | RTLD_GLOBAL)) 155#define GL_LoadFunction dlsym 156#define GL_UnloadObject dlclose 157#else 158#define GL_LoadObject SDL_LoadObject 159#define GL_LoadFunction SDL_LoadFunction 160#define GL_UnloadObject SDL_UnloadObject 161#endif 162 163static void X11_GL_InitExtensions(SDL_VideoDevice *_this); 164 165bool X11_GL_LoadLibrary(SDL_VideoDevice *_this, const char *path) 166{ 167 Display *display; 168 SDL_SharedObject *handle; 169 170 if (_this->gl_data) { 171 return SDL_SetError("OpenGL context already created"); 172 } 173 174 // Load the OpenGL library 175 if (path == NULL) { 176 path = SDL_GetHint(SDL_HINT_OPENGL_LIBRARY); 177 } 178 if (path == NULL) { 179 path = DEFAULT_OPENGL; 180 } 181 _this->gl_config.dll_handle = GL_LoadObject(path); 182 if (!_this->gl_config.dll_handle) { 183#if defined(OPENGL_REQUIRES_DLOPEN) && defined(HAVE_DLOPEN) 184 SDL_SetError("Failed loading %s: %s", path, dlerror()); 185#endif 186 return false; 187 } 188 SDL_strlcpy(_this->gl_config.driver_path, path, 189 SDL_arraysize(_this->gl_config.driver_path)); 190 191 // Allocate OpenGL memory 192 _this->gl_data = 193 (struct SDL_GLDriverData *)SDL_calloc(1, 194 sizeof(struct 195 SDL_GLDriverData)); 196 if (!_this->gl_data) { 197 return false; 198 } 199 200 // Load function pointers 201 handle = _this->gl_config.dll_handle; 202 _this->gl_data->glXQueryExtension = 203 (Bool(*)(Display *, int *, int *)) 204 GL_LoadFunction(handle, "glXQueryExtension"); 205 _this->gl_data->glXGetProcAddress = 206 (__GLXextFuncPtr (*)(const GLubyte *)) 207 GL_LoadFunction(handle, "glXGetProcAddressARB"); 208 _this->gl_data->glXChooseVisual = 209 (XVisualInfo * (*)(Display *, int, int *)) 210 X11_GL_GetProcAddress(_this, "glXChooseVisual"); 211 _this->gl_data->glXCreateContext = 212 (GLXContext(*)(Display *, XVisualInfo *, GLXContext, int)) 213 X11_GL_GetProcAddress(_this, "glXCreateContext"); 214 _this->gl_data->glXDestroyContext = 215 (void (*)(Display *, GLXContext)) 216 X11_GL_GetProcAddress(_this, "glXDestroyContext"); 217 _this->gl_data->glXMakeCurrent = 218 (int (*)(Display *, GLXDrawable, GLXContext)) 219 X11_GL_GetProcAddress(_this, "glXMakeCurrent"); 220 _this->gl_data->glXSwapBuffers = 221 (void (*)(Display *, GLXDrawable)) 222 X11_GL_GetProcAddress(_this, "glXSwapBuffers"); 223 _this->gl_data->glXQueryDrawable = 224 (void (*)(Display *, GLXDrawable, int, unsigned int *)) 225 X11_GL_GetProcAddress(_this, "glXQueryDrawable"); 226 227 if (!_this->gl_data->glXQueryExtension || 228 !_this->gl_data->glXChooseVisual || 229 !_this->gl_data->glXCreateContext || 230 !_this->gl_data->glXDestroyContext || 231 !_this->gl_data->glXMakeCurrent || 232 !_this->gl_data->glXSwapBuffers) { 233 return SDL_SetError("Could not retrieve OpenGL functions"); 234 } 235 236 display = _this->internal->display; 237 if (!_this->gl_data->glXQueryExtension(display, &_this->gl_data->errorBase, &_this->gl_data->eventBase)) { 238 return SDL_SetError("GLX is not supported"); 239 } 240 241 _this->gl_data->swap_interval_tear_behavior = SDL_SWAPINTERVALTEAR_UNTESTED; 242 243 // Initialize extensions 244 /* See lengthy comment about the inc/dec in 245 ../windows/SDL_windowsopengl.c. */ 246 ++_this->gl_config.driver_loaded; 247 X11_GL_InitExtensions(_this); 248 --_this->gl_config.driver_loaded; 249 250 /* If we need a GL ES context and there's no 251 * GLX_EXT_create_context_es2_profile extension, switch over to X11_GLES functions 252 */ 253 if (((_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) || 254 SDL_GetHintBoolean(SDL_HINT_VIDEO_FORCE_EGL, false)) && 255 X11_GL_UseEGL(_this)) { 256#ifdef SDL_VIDEO_OPENGL_EGL 257 X11_GL_UnloadLibrary(_this); 258 _this->GL_LoadLibrary = X11_GLES_LoadLibrary; 259 _this->GL_GetProcAddress = X11_GLES_GetProcAddress; 260 _this->GL_UnloadLibrary = X11_GLES_UnloadLibrary; 261 _this->GL_CreateContext = X11_GLES_CreateContext; 262 _this->GL_MakeCurrent = X11_GLES_MakeCurrent; 263 _this->GL_SetSwapInterval = X11_GLES_SetSwapInterval; 264 _this->GL_GetSwapInterval = X11_GLES_GetSwapInterval; 265 _this->GL_SwapWindow = X11_GLES_SwapWindow; 266 _this->GL_DestroyContext = X11_GLES_DestroyContext; 267 return X11_GLES_LoadLibrary(_this, NULL); 268#else 269 return SDL_SetError("SDL not configured with EGL support"); 270#endif 271 } 272 273 return true; 274} 275 276SDL_FunctionPointer X11_GL_GetProcAddress(SDL_VideoDevice *_this, const char *proc) 277{ 278 if (_this->gl_data->glXGetProcAddress) { 279 return _this->gl_data->glXGetProcAddress((const GLubyte *)proc); 280 } 281 return GL_LoadFunction(_this->gl_config.dll_handle, proc); 282} 283 284void X11_GL_UnloadLibrary(SDL_VideoDevice *_this) 285{ 286 /* Don't actually unload the library, since it may have registered 287 * X11 shutdown hooks, per the notes at: 288 * http://dri.sourceforge.net/doc/DRIuserguide.html 289 */ 290#if 0 291 GL_UnloadObject(_this->gl_config.dll_handle); 292 _this->gl_config.dll_handle = NULL; 293#endif 294 295 // Free OpenGL memory 296 SDL_free(_this->gl_data); 297 _this->gl_data = NULL; 298} 299 300static bool HasExtension(const char *extension, const char *extensions) 301{ 302 const char *start; 303 const char *where, *terminator; 304 305 if (!extensions) { 306 return false; 307 } 308 309 // Extension names should not have spaces. 310 where = SDL_strchr(extension, ' '); 311 if (where || *extension == '\0') { 312 return false; 313 } 314 315 /* It takes a bit of care to be fool-proof about parsing the 316 * OpenGL extensions string. Don't be fooled by sub-strings, 317 * etc. */ 318 319 start = extensions; 320 321 for (;;) { 322 where = SDL_strstr(start, extension); 323 if (!where) { 324 break; 325 } 326 327 terminator = where + SDL_strlen(extension); 328 if (where == start || *(where - 1) == ' ') { 329 if (*terminator == ' ' || *terminator == '\0') { 330 return true; 331 } 332 } 333 334 start = terminator; 335 } 336 return false; 337} 338 339static void X11_GL_InitExtensions(SDL_VideoDevice *_this) 340{ 341 Display *display = _this->internal->display; 342 const int screen = DefaultScreen(display); 343 XVisualInfo *vinfo = NULL; 344 Window w = 0; 345 GLXContext prev_ctx = NULL; 346 GLXDrawable prev_drawable = 0; 347 GLXContext context = NULL; 348 const char *(*glXQueryExtensionsStringFunc)(Display *, int); 349 const char *extensions; 350 351 vinfo = X11_GL_GetVisual(_this, display, screen, false); 352 if (vinfo) { 353 GLXContext (*glXGetCurrentContextFunc)(void) = 354 (GLXContext(*)(void)) 355 X11_GL_GetProcAddress(_this, "glXGetCurrentContext"); 356 357 GLXDrawable (*glXGetCurrentDrawableFunc)(void) = 358 (GLXDrawable(*)(void)) 359 X11_GL_GetProcAddress(_this, "glXGetCurrentDrawable"); 360 361 if (glXGetCurrentContextFunc && glXGetCurrentDrawableFunc) { 362 XSetWindowAttributes xattr; 363 prev_ctx = glXGetCurrentContextFunc(); 364 prev_drawable = glXGetCurrentDrawableFunc(); 365 366 xattr.background_pixel = 0; 367 xattr.border_pixel = 0; 368 xattr.colormap = 369 X11_XCreateColormap(display, RootWindow(display, screen), 370 vinfo->visual, AllocNone); 371 w = X11_XCreateWindow(display, RootWindow(display, screen), 0, 0, 372 32, 32, 0, vinfo->depth, InputOutput, vinfo->visual, 373 (CWBackPixel | CWBorderPixel | CWColormap), &xattr); 374 375 context = _this->gl_data->glXCreateContext(display, vinfo, 376 NULL, True); 377 if (context) { 378 _this->gl_data->glXMakeCurrent(display, w, context); 379 } 380 } 381 382 X11_XFree(vinfo); 383 } 384 385 glXQueryExtensionsStringFunc = 386 (const char *(*)(Display *, int))X11_GL_GetProcAddress(_this, 387 "glXQueryExtensionsString"); 388 if (glXQueryExtensionsStringFunc) { 389 extensions = glXQueryExtensionsStringFunc(display, screen); 390 } else { 391 extensions = NULL; 392 } 393 394 // Check for GLX_EXT_swap_control(_tear) 395 _this->gl_data->HAS_GLX_EXT_swap_control_tear = false; 396 if (HasExtension("GLX_EXT_swap_control", extensions)) { 397 _this->gl_data->glXSwapIntervalEXT = 398 (void (*)(Display *, GLXDrawable, int)) 399 X11_GL_GetProcAddress(_this, "glXSwapIntervalEXT"); 400 if (HasExtension("GLX_EXT_swap_control_tear", extensions)) { 401 _this->gl_data->HAS_GLX_EXT_swap_control_tear = true; 402 } 403 } 404 405 // Check for GLX_MESA_swap_control 406 if (HasExtension("GLX_MESA_swap_control", extensions)) { 407 _this->gl_data->glXSwapIntervalMESA = 408 (int (*)(int))X11_GL_GetProcAddress(_this, "glXSwapIntervalMESA"); 409 _this->gl_data->glXGetSwapIntervalMESA = 410 (int (*)(void))X11_GL_GetProcAddress(_this, 411 "glXGetSwapIntervalMESA"); 412 } 413 414 // Check for GLX_SGI_swap_control 415 if (HasExtension("GLX_SGI_swap_control", extensions)) { 416 _this->gl_data->glXSwapIntervalSGI = 417 (int (*)(int))X11_GL_GetProcAddress(_this, "glXSwapIntervalSGI"); 418 } 419 420 // Check for GLX_ARB_create_context 421 if (HasExtension("GLX_ARB_create_context", extensions)) { 422 _this->gl_data->glXCreateContextAttribsARB = 423 (GLXContext(*)(Display *, GLXFBConfig, GLXContext, Bool, const int *)) 424 X11_GL_GetProcAddress(_this, "glXCreateContextAttribsARB"); 425 _this->gl_data->glXChooseFBConfig = 426 (GLXFBConfig * (*)(Display *, int, const int *, int *)) 427 X11_GL_GetProcAddress(_this, "glXChooseFBConfig"); 428 _this->gl_data->glXGetVisualFromFBConfig = 429 (XVisualInfo * (*)(Display *, GLXFBConfig)) 430 X11_GL_GetProcAddress(_this, "glXGetVisualFromFBConfig"); 431 } 432 433 // Check for GLX_EXT_visual_rating 434 if (HasExtension("GLX_EXT_visual_rating", extensions)) { 435 _this->gl_data->HAS_GLX_EXT_visual_rating = true; 436 } 437 438 // Check for GLX_EXT_visual_info 439 if (HasExtension("GLX_EXT_visual_info", extensions)) { 440 _this->gl_data->HAS_GLX_EXT_visual_info = true; 441 } 442 443 // Check for GLX_EXT_create_context_es2_profile 444 if (HasExtension("GLX_EXT_create_context_es2_profile", extensions)) { 445 // this wants to call glGetString(), so it needs a context. 446 // !!! FIXME: it would be nice not to make a context here though! 447 if (context) { 448 SDL_GL_DeduceMaxSupportedESProfile( 449 &_this->gl_data->es_profile_max_supported_version.major, 450 &_this->gl_data->es_profile_max_supported_version.minor); 451 } 452 } 453 454 // Check for GLX_ARB_context_flush_control 455 if (HasExtension("GLX_ARB_context_flush_control", extensions)) { 456 _this->gl_data->HAS_GLX_ARB_context_flush_control = true; 457 } 458 459 // Check for GLX_ARB_create_context_robustness 460 if (HasExtension("GLX_ARB_create_context_robustness", extensions)) { 461 _this->gl_data->HAS_GLX_ARB_create_context_robustness = true; 462 } 463 464 // Check for GLX_ARB_create_context_no_error 465 if (HasExtension("GLX_ARB_create_context_no_error", extensions)) { 466 _this->gl_data->HAS_GLX_ARB_create_context_no_error = true; 467 } 468 469 // Check for GLX_ARB_framebuffer_sRGB 470 if (HasExtension("GLX_ARB_framebuffer_sRGB", extensions)) { 471 _this->gl_data->HAS_GLX_ARB_framebuffer_sRGB = true; 472 } else if (HasExtension("GLX_EXT_framebuffer_sRGB", extensions)) { // same thing. 473 _this->gl_data->HAS_GLX_ARB_framebuffer_sRGB = true; 474 } 475 476 if (context) { 477 _this->gl_data->glXMakeCurrent(display, None, NULL); 478 _this->gl_data->glXDestroyContext(display, context); 479 if (prev_ctx && prev_drawable) { 480 _this->gl_data->glXMakeCurrent(display, prev_drawable, prev_ctx); 481 } 482 } 483 484 if (w) { 485 X11_XDestroyWindow(display, w); 486 } 487 X11_PumpEvents(_this); 488} 489 490/* glXChooseVisual and glXChooseFBConfig have some small differences in 491 * the attribute encoding, it can be chosen with the for_FBConfig parameter. 492 * Some targets fail if you use GLX_X_VISUAL_TYPE_EXT/GLX_DIRECT_COLOR_EXT, 493 * so it gets specified last if used and is pointed to by *_pvistypeattr. 494 * In case of failure, if that pointer is not NULL, set that pointer to None 495 * and try again. 496 */ 497static int X11_GL_GetAttributes(SDL_VideoDevice *_this, Display *display, int screen, int *attribs, int size, Bool for_FBConfig, int **_pvistypeattr, bool transparent) 498{ 499 int i = 0; 500 const int MAX_ATTRIBUTES = 64; 501 int *pvistypeattr = NULL; 502 503 // assert buffer is large enough to hold all SDL attributes. 504 SDL_assert(size >= MAX_ATTRIBUTES); 505 506 // Setup our GLX attributes according to the gl_config. 507 if (for_FBConfig) { 508 attribs[i++] = GLX_RENDER_TYPE; 509 if (_this->gl_config.floatbuffers) { 510 attribs[i++] = GLX_RGBA_FLOAT_BIT_ARB; 511 } else { 512 attribs[i++] = GLX_RGBA_BIT; 513 } 514 } else { 515 attribs[i++] = GLX_RGBA; 516 } 517 attribs[i++] = GLX_RED_SIZE; 518 attribs[i++] = _this->gl_config.red_size; 519 attribs[i++] = GLX_GREEN_SIZE; 520 attribs[i++] = _this->gl_config.green_size; 521 attribs[i++] = GLX_BLUE_SIZE; 522 attribs[i++] = _this->gl_config.blue_size; 523 524 if (_this->gl_config.alpha_size) { 525 attribs[i++] = GLX_ALPHA_SIZE; 526 attribs[i++] = _this->gl_config.alpha_size; 527 } 528 529 if (_this->gl_config.double_buffer) { 530 attribs[i++] = GLX_DOUBLEBUFFER; 531 if (for_FBConfig) { 532 attribs[i++] = True; 533 } 534 } 535 536 attribs[i++] = GLX_DEPTH_SIZE; 537 attribs[i++] = _this->gl_config.depth_size; 538 539 if (_this->gl_config.stencil_size) { 540 attribs[i++] = GLX_STENCIL_SIZE; 541 attribs[i++] = _this->gl_config.stencil_size; 542 } 543 544 if (_this->gl_config.accum_red_size) { 545 attribs[i++] = GLX_ACCUM_RED_SIZE; 546 attribs[i++] = _this->gl_config.accum_red_size; 547 } 548 549 if (_this->gl_config.accum_green_size) { 550 attribs[i++] = GLX_ACCUM_GREEN_SIZE; 551 attribs[i++] = _this->gl_config.accum_green_size; 552 } 553 554 if (_this->gl_config.accum_blue_size) { 555 attribs[i++] = GLX_ACCUM_BLUE_SIZE; 556 attribs[i++] = _this->gl_config.accum_blue_size; 557 } 558 559 if (_this->gl_config.accum_alpha_size) { 560 attribs[i++] = GLX_ACCUM_ALPHA_SIZE; 561 attribs[i++] = _this->gl_config.accum_alpha_size; 562 } 563 564 if (_this->gl_config.stereo) { 565 attribs[i++] = GLX_STEREO; 566 if (for_FBConfig) { 567 attribs[i++] = True; 568 } 569 } 570 571 if (_this->gl_config.multisamplebuffers) { 572 attribs[i++] = GLX_SAMPLE_BUFFERS_ARB; 573 attribs[i++] = _this->gl_config.multisamplebuffers; 574 } 575 576 if (_this->gl_config.multisamplesamples) { 577 attribs[i++] = GLX_SAMPLES_ARB; 578 attribs[i++] = _this->gl_config.multisamplesamples; 579 } 580 581 if (_this->gl_config.floatbuffers) { 582 attribs[i++] = GLX_RENDER_TYPE; 583 attribs[i++] = GLX_RGBA_FLOAT_TYPE_ARB; 584 } 585 586 if ((_this->gl_config.framebuffer_srgb_capable >= 0) && _this->gl_data->HAS_GLX_ARB_framebuffer_sRGB) { 587 attribs[i++] = GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB; 588 attribs[i++] = _this->gl_config.framebuffer_srgb_capable ? True : False; // always needed, for_FBConfig or not! 589 } 590 591 if (_this->gl_config.accelerated >= 0 && 592 _this->gl_data->HAS_GLX_EXT_visual_rating) { 593 attribs[i++] = GLX_VISUAL_CAVEAT_EXT; 594 attribs[i++] = _this->gl_config.accelerated ? GLX_NONE_EXT : GLX_SLOW_VISUAL_EXT; 595 } 596 597 // Un-wanted when we request a transparent buffer 598 if (!transparent) { 599 /* If we're supposed to use DirectColor visuals, and we've got the 600 EXT_visual_info extension, then add GLX_X_VISUAL_TYPE_EXT. */ 601 if (X11_UseDirectColorVisuals() && _this->gl_data->HAS_GLX_EXT_visual_info) { 602 pvistypeattr = &attribs[i]; 603 attribs[i++] = GLX_X_VISUAL_TYPE_EXT; 604 attribs[i++] = GLX_DIRECT_COLOR_EXT; 605 } 606 } 607 608 attribs[i++] = None; 609 610 SDL_assert(i <= MAX_ATTRIBUTES); 611 612 if (_pvistypeattr) { 613 *_pvistypeattr = pvistypeattr; 614 } 615 616 return i; 617} 618 619//get the first transparent Visual 620static XVisualInfo *X11_GL_GetTransparentVisualInfo(Display *display, int screen) 621{ 622 XVisualInfo *visualinfo = NULL; 623 XVisualInfo vi_in; 624 int out_count = 0; 625 626 vi_in.screen = screen; 627 visualinfo = X11_XGetVisualInfo(display, VisualScreenMask, &vi_in, &out_count); 628 if (visualinfo != NULL) { 629 int i = 0; 630 for (i = 0; i < out_count; i++) { 631 XVisualInfo *v = &visualinfo[i]; 632 Uint32 format = X11_GetPixelFormatFromVisualInfo(display, v); 633 if (SDL_ISPIXELFORMAT_ALPHA(format)) { 634 vi_in.screen = screen; 635 vi_in.visualid = v->visualid; 636 X11_XFree(visualinfo); 637 visualinfo = X11_XGetVisualInfo(display, VisualScreenMask | VisualIDMask, &vi_in, &out_count); 638 break; 639 } 640 } 641 } 642 return visualinfo; 643} 644 645XVisualInfo *X11_GL_GetVisual(SDL_VideoDevice *_this, Display *display, int screen, bool transparent) 646{ 647 // 64 seems nice. 648 int attribs[64]; 649 XVisualInfo *vinfo = NULL; 650 int *pvistypeattr = NULL; 651 652 if (!_this->gl_data) { 653 // The OpenGL library wasn't loaded, SDL_GetError() should have info 654 return NULL; 655 } 656 657 if (_this->gl_data->glXChooseFBConfig && 658 _this->gl_data->glXGetVisualFromFBConfig) { 659 GLXFBConfig *framebuffer_config = NULL; 660 int fbcount = 0; 661 662 X11_GL_GetAttributes(_this, display, screen, attribs, 64, true, &pvistypeattr, transparent); 663 framebuffer_config = _this->gl_data->glXChooseFBConfig(display, screen, attribs, &fbcount); 664 if (!framebuffer_config && (pvistypeattr != NULL)) { 665 *pvistypeattr = None; 666 framebuffer_config = _this->gl_data->glXChooseFBConfig(display, screen, attribs, &fbcount); 667 } 668 669 if (transparent) { 670 // Return the first transparent Visual 671 int i; 672 for (i = 0; i < fbcount; i++) { 673 Uint32 format; 674 vinfo = _this->gl_data->glXGetVisualFromFBConfig(display, framebuffer_config[i]); 675 format = X11_GetPixelFormatFromVisualInfo(display, vinfo); 676 if (SDL_ISPIXELFORMAT_ALPHA(format)) { // found! 677 X11_XFree(framebuffer_config); 678 framebuffer_config = NULL; 679 break; 680 } 681 X11_XFree(vinfo); 682 vinfo = NULL; 683 } 684 } 685 686 if (framebuffer_config) { 687 vinfo = _this->gl_data->glXGetVisualFromFBConfig(display, framebuffer_config[0]); 688 } 689 690 X11_XFree(framebuffer_config); 691 } 692 693 if (!vinfo) { 694 X11_GL_GetAttributes(_this, display, screen, attribs, 64, false, &pvistypeattr, transparent); 695 vinfo = _this->gl_data->glXChooseVisual(display, screen, attribs); 696 697 if (!vinfo && (pvistypeattr != NULL)) { 698 *pvistypeattr = None; 699 vinfo = _this->gl_data->glXChooseVisual(display, screen, attribs); 700 } 701 } 702 703 if (transparent && vinfo) { 704 Uint32 format = X11_GetPixelFormatFromVisualInfo(display, vinfo); 705 if (!SDL_ISPIXELFORMAT_ALPHA(format)) { 706 // not transparent! 707 XVisualInfo *visualinfo = X11_GL_GetTransparentVisualInfo(display, screen); 708 if (visualinfo != NULL) { 709 X11_XFree(vinfo); 710 vinfo = visualinfo; 711 } 712 } 713 } 714 715 if (!vinfo) { 716 SDL_SetError("Couldn't find matching GLX visual"); 717 } 718 return vinfo; 719} 720 721static int (*handler)(Display *, XErrorEvent *) = NULL; 722static const char *errorHandlerOperation = NULL; 723static int errorBase = 0; 724static int errorCode = 0; 725static int X11_GL_ErrorHandler(Display *d, XErrorEvent *e) 726{ 727 char *x11_error = NULL; 728 char x11_error_locale[256]; 729 730 errorCode = e->error_code; 731 if (X11_XGetErrorText(d, errorCode, x11_error_locale, sizeof(x11_error_locale)) == Success) { 732 x11_error = SDL_iconv_string("UTF-8", "", x11_error_locale, SDL_strlen(x11_error_locale) + 1); 733 } 734 735 if (x11_error) { 736 SDL_SetError("Could not %s: %s", errorHandlerOperation, x11_error); 737 SDL_free(x11_error); 738 } else { 739 SDL_SetError("Could not %s: %i (Base %i)", errorHandlerOperation, errorCode, errorBase); 740 } 741 742 return 0; 743} 744 745bool X11_GL_UseEGL(SDL_VideoDevice *_this) 746{ 747 SDL_assert(_this->gl_data != NULL); 748 if (SDL_GetHintBoolean(SDL_HINT_VIDEO_FORCE_EGL, false)) { 749 // use of EGL has been requested, even for desktop GL 750 return true; 751 } 752 753 SDL_assert(_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES); 754 return (SDL_GetHintBoolean(SDL_HINT_OPENGL_ES_DRIVER, false) || _this->gl_config.major_version == 1 // No GLX extension for OpenGL ES 1.x profiles. 755 || _this->gl_config.major_version > _this->gl_data->es_profile_max_supported_version.major || (_this->gl_config.major_version == _this->gl_data->es_profile_max_supported_version.major && _this->gl_config.minor_version > _this->gl_data->es_profile_max_supported_version.minor)); 756} 757 758SDL_GLContext X11_GL_CreateContext(SDL_VideoDevice *_this, SDL_Window *window) 759{ 760 SDL_WindowData *data = window->internal; 761 Display *display = data->videodata->display; 762 int screen = SDL_GetDisplayDriverDataForWindow(window)->screen; 763 XWindowAttributes xattr; 764 XVisualInfo v, *vinfo; 765 int n; 766 SDL_GLContext context = NULL; 767 GLXContext share_context; 768 const int transparent = (window->flags & SDL_WINDOW_TRANSPARENT) ? true : false; 769 770 if (_this->gl_config.share_with_current_context) { 771 share_context = (GLXContext)SDL_GL_GetCurrentContext(); 772 } else { 773 share_context = NULL; 774 } 775 776 // We do this to create a clean separation between X and GLX errors. 777 X11_XSync(display, False); 778 errorHandlerOperation = "create GL context"; 779 errorBase = _this->gl_data->errorBase; 780 errorCode = Success; 781 handler = X11_XSetErrorHandler(X11_GL_ErrorHandler); 782 X11_XGetWindowAttributes(display, data->xwindow, &xattr); 783 v.screen = screen; 784 v.visualid = X11_XVisualIDFromVisual(xattr.visual); 785 vinfo = X11_XGetVisualInfo(display, VisualScreenMask | VisualIDMask, &v, &n); 786 if (vinfo) { 787 if (_this->gl_config.major_version < 3 && 788 _this->gl_config.profile_mask == 0 && 789 _this->gl_config.flags == 0 && !transparent) { 790 // Create legacy context 791 context = 792 (SDL_GLContext)_this->gl_data->glXCreateContext(display, vinfo, share_context, True); 793 } else { 794 // max 14 attributes plus terminator 795 int attribs[15] = { 796 GLX_CONTEXT_MAJOR_VERSION_ARB, 797 _this->gl_config.major_version, 798 GLX_CONTEXT_MINOR_VERSION_ARB, 799 _this->gl_config.minor_version, 800 0 801 }; 802 int iattr = 4; 803 804 // SDL profile bits match GLX profile bits 805 if (_this->gl_config.profile_mask != 0) { 806 attribs[iattr++] = GLX_CONTEXT_PROFILE_MASK_ARB; 807 attribs[iattr++] = _this->gl_config.profile_mask; 808 } 809 810 // SDL flags match GLX flags 811 if (_this->gl_config.flags != 0) { 812 attribs[iattr++] = GLX_CONTEXT_FLAGS_ARB; 813 attribs[iattr++] = _this->gl_config.flags; 814 } 815 816 // only set if glx extension is available and not the default setting 817 if ((_this->gl_data->HAS_GLX_ARB_context_flush_control) && (_this->gl_config.release_behavior == 0)) { 818 attribs[iattr++] = GLX_CONTEXT_RELEASE_BEHAVIOR_ARB; 819 attribs[iattr++] = 820 _this->gl_config.release_behavior ? GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB : GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB; 821 } 822 823 // only set if glx extension is available and not the default setting 824 if ((_this->gl_data->HAS_GLX_ARB_create_context_robustness) && (_this->gl_config.reset_notification != 0)) { 825 attribs[iattr++] = GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB; 826 attribs[iattr++] = 827 _this->gl_config.reset_notification ? GLX_LOSE_CONTEXT_ON_RESET_ARB : GLX_NO_RESET_NOTIFICATION_ARB; 828 } 829 830 // only set if glx extension is available and not the default setting 831 if ((_this->gl_data->HAS_GLX_ARB_create_context_no_error) && (_this->gl_config.no_error != 0)) { 832 attribs[iattr++] = GLX_CONTEXT_OPENGL_NO_ERROR_ARB; 833 attribs[iattr++] = _this->gl_config.no_error; 834 } 835 836 attribs[iattr++] = 0; 837 838 // Get a pointer to the context creation function for GL 3.0 839 if (!_this->gl_data->glXCreateContextAttribsARB) { 840 SDL_SetError("OpenGL 3.0 and later are not supported by this system"); 841 } else { 842 int glxAttribs[64]; 843 844 // Create a GL 3.x context 845 GLXFBConfig *framebuffer_config = NULL; 846 int fbcount = 0; 847 int *pvistypeattr = NULL; 848 849 X11_GL_GetAttributes(_this, display, screen, glxAttribs, 64, true, &pvistypeattr, transparent); 850 851 if (_this->gl_data->glXChooseFBConfig) { 852 framebuffer_config = _this->gl_data->glXChooseFBConfig(display, 853 DefaultScreen(display), glxAttribs, 854 &fbcount); 855 856 if (!framebuffer_config && (pvistypeattr != NULL)) { 857 *pvistypeattr = None; 858 framebuffer_config = _this->gl_data->glXChooseFBConfig(display, 859 DefaultScreen(display), glxAttribs, 860 &fbcount); 861 } 862 863 if (transparent && (framebuffer_config != NULL)) { 864 int i; 865 for (i = 0; i < fbcount; i++) { 866 XVisualInfo *vinfo_temp = _this->gl_data->glXGetVisualFromFBConfig(display, framebuffer_config[i]); 867 if ( vinfo_temp != NULL) { 868 Uint32 format = X11_GetPixelFormatFromVisualInfo(display, vinfo_temp); 869 if (SDL_ISPIXELFORMAT_ALPHA(format)) { 870 // found! 871 context = (SDL_GLContext)_this->gl_data->glXCreateContextAttribsARB(display, 872 framebuffer_config[i], 873 share_context, True, attribs); 874 X11_XFree(framebuffer_config); 875 framebuffer_config = NULL; 876 X11_XFree(vinfo_temp); 877 break; 878 } 879 X11_XFree(vinfo_temp); 880 } 881 } 882 } 883 if (framebuffer_config) { 884 context = (SDL_GLContext)_this->gl_data->glXCreateContextAttribsARB(display, 885 framebuffer_config[0], 886 share_context, True, attribs); 887 X11_XFree(framebuffer_config); 888 } 889 } 890 } 891 } 892 X11_XFree(vinfo); 893 } 894 X11_XSync(display, False); 895 X11_XSetErrorHandler(handler); 896 897 if (!context) { 898 if (errorCode == Success) { 899 SDL_SetError("Could not create GL context"); 900 } 901 return NULL; 902 } 903 904 if (!X11_GL_MakeCurrent(_this, window, context)) { 905 X11_GL_DestroyContext(_this, context); 906 return NULL; 907 } 908 909 return context; 910} 911 912bool X11_GL_MakeCurrent(SDL_VideoDevice *_this, SDL_Window *window, SDL_GLContext context) 913{ 914 Display *display = _this->internal->display; 915 Window drawable = 916 (context ? window->internal->xwindow : None); 917 GLXContext glx_context = (GLXContext)context; 918 int rc; 919 920 if (!_this->gl_data) { 921 return SDL_SetError("OpenGL not initialized"); 922 } 923 924 // We do this to create a clean separation between X and GLX errors. 925 X11_XSync(display, False); 926 errorHandlerOperation = "make GL context current"; 927 errorBase = _this->gl_data->errorBase; 928 errorCode = Success; 929 handler = X11_XSetErrorHandler(X11_GL_ErrorHandler); 930 rc = _this->gl_data->glXMakeCurrent(display, drawable, glx_context); 931 X11_XSetErrorHandler(handler); 932 933 if (errorCode != Success) { // uhoh, an X error was thrown! 934 return false; // the error handler called SDL_SetError() already. 935 } else if (!rc) { // glXMakeCurrent() failed without throwing an X error 936 return SDL_SetError("Unable to make GL context current"); 937 } 938 939 return true; 940} 941 942/* 943 0 is a valid argument to glXSwapInterval(MESA|EXT) and setting it to 0 944 will undo the effect of a previous call with a value that is greater 945 than zero (or at least that is what the docs say). OTOH, 0 is an invalid 946 argument to glXSwapIntervalSGI and it returns an error if you call it 947 with 0 as an argument. 948*/ 949 950static int swapinterval = 0; 951bool X11_GL_SetSwapInterval(SDL_VideoDevice *_this, int interval) 952{ 953 bool result = false; 954 955 if ((interval < 0) && (!_this->gl_data->HAS_GLX_EXT_swap_control_tear)) { 956 return SDL_SetError("Negative swap interval unsupported in this GL"); 957 } else if (_this->gl_data->glXSwapIntervalEXT) { 958 Display *display = _this->internal->display; 959 const SDL_WindowData *windowdata = SDL_GL_GetCurrentWindow()->internal; 960 961 Window drawable = windowdata->xwindow; 962 963 /* 964 * This is a workaround for a bug in NVIDIA drivers. Bug has been reported 965 * and will be fixed in a future release (probably 319.xx). 966 * 967 * There's a bug where glXSetSwapIntervalEXT ignores updates because 968 * it has the wrong value cached. To work around it, we just run a no-op 969 * update to the current value. 970 */ 971 int currentInterval = 0; 972 X11_GL_GetSwapInterval(_this, &currentInterval); 973 _this->gl_data->glXSwapIntervalEXT(display, drawable, currentInterval); 974 _this->gl_data->glXSwapIntervalEXT(display, drawable, interval); 975 result = true; 976 swapinterval = interval; 977 } else if (_this->gl_data->glXSwapIntervalMESA) { 978 const int rc = _this->gl_data->glXSwapIntervalMESA(interval); 979 if (rc == 0) { 980 swapinterval = interval; 981 result = true; 982 } else { 983 result = SDL_SetError("glXSwapIntervalMESA failed"); 984 } 985 } else if (_this->gl_data->glXSwapIntervalSGI) { 986 const int rc = _this->gl_data->glXSwapIntervalSGI(interval); 987 if (rc == 0) { 988 swapinterval = interval; 989 result = true; 990 } else { 991 result = SDL_SetError("glXSwapIntervalSGI failed"); 992 } 993 } else { 994 return SDL_Unsupported(); 995 } 996 return result; 997} 998 999static SDL_GLSwapIntervalTearBehavior CheckSwapIntervalTearBehavior(SDL_VideoDevice *_this, Window drawable, unsigned int current_val, unsigned int current_allow_late) 1000{ 1001 /* Mesa and Nvidia interpret GLX_EXT_swap_control_tear differently, as of this writing, so 1002 figure out which behavior we have. 1003 Technical details: https://github.com/libsdl-org/SDL/issues/8004#issuecomment-1819603282 */ 1004 if (_this->gl_data->swap_interval_tear_behavior == SDL_SWAPINTERVALTEAR_UNTESTED) { 1005 if (!_this->gl_data->HAS_GLX_EXT_swap_control_tear) { 1006 _this->gl_data->swap_interval_tear_behavior = SDL_SWAPINTERVALTEAR_UNKNOWN; 1007 } else { 1008 Display *display = _this->internal->display; 1009 unsigned int allow_late_swap_tearing = 22; 1010 int original_val = (int) current_val; 1011 1012 /* 1013 * This is a workaround for a bug in NVIDIA drivers. Bug has been reported 1014 * and will be fixed in a future release (probably 319.xx). 1015 * 1016 * There's a bug where glXSetSwapIntervalEXT ignores updates because 1017 * it has the wrong value cached. To work around it, we just run a no-op 1018 * update to the current value. 1019 */ 1020 _this->gl_data->glXSwapIntervalEXT(display, drawable, current_val); 1021 1022 // set it to no swap interval and see how it affects GLX_LATE_SWAPS_TEAR_EXT... 1023 _this->gl_data->glXSwapIntervalEXT(display, drawable, 0); 1024 _this->gl_data->glXQueryDrawable(display, drawable, GLX_LATE_SWAPS_TEAR_EXT, &allow_late_swap_tearing); 1025 1026 if (allow_late_swap_tearing == 0) { // GLX_LATE_SWAPS_TEAR_EXT says whether late swapping is currently in use 1027 _this->gl_data->swap_interval_tear_behavior = SDL_SWAPINTERVALTEAR_NVIDIA; 1028 if (current_allow_late) { 1029 original_val = -original_val; 1030 } 1031 } else if (allow_late_swap_tearing == 1) { // GLX_LATE_SWAPS_TEAR_EXT says whether the Drawable can use late swapping at all 1032 _this->gl_data->swap_interval_tear_behavior = SDL_SWAPINTERVALTEAR_MESA; 1033 } else { // unexpected outcome! 1034 _this->gl_data->swap_interval_tear_behavior = SDL_SWAPINTERVALTEAR_UNKNOWN; 1035 } 1036 1037 // set us back to what it was originally... 1038 _this->gl_data->glXSwapIntervalEXT(display, drawable, original_val); 1039 } 1040 } 1041 1042 return _this->gl_data->swap_interval_tear_behavior; 1043} 1044 1045 1046bool X11_GL_GetSwapInterval(SDL_VideoDevice *_this, int *interval) 1047{ 1048 if (_this->gl_data->glXSwapIntervalEXT) { 1049 Display *display = _this->internal->display; 1050 const SDL_WindowData *windowdata = SDL_GL_GetCurrentWindow()->internal; 1051 Window drawable = windowdata->xwindow; 1052 unsigned int allow_late_swap_tearing = 0; 1053 unsigned int val = 0; 1054 1055 if (_this->gl_data->HAS_GLX_EXT_swap_control_tear) { 1056 allow_late_swap_tearing = 22; // set this to nonsense. 1057 _this->gl_data->glXQueryDrawable(display, drawable, 1058 GLX_LATE_SWAPS_TEAR_EXT, 1059 &allow_late_swap_tearing); 1060 } 1061 1062 _this->gl_data->glXQueryDrawable(display, drawable, 1063 GLX_SWAP_INTERVAL_EXT, &val); 1064 1065 *interval = (int)val; 1066 1067 switch (CheckSwapIntervalTearBehavior(_this, drawable, val, allow_late_swap_tearing)) { 1068 case SDL_SWAPINTERVALTEAR_MESA: 1069 *interval = (int)val; // unsigned int cast to signed that generates negative value if necessary. 1070 break; 1071 1072 case SDL_SWAPINTERVALTEAR_NVIDIA: 1073 default: 1074 if ((allow_late_swap_tearing) && (val > 0)) { 1075 *interval = -((int)val); 1076 } 1077 break; 1078 } 1079 1080 return true; 1081 } else if (_this->gl_data->glXGetSwapIntervalMESA) { 1082 int val = _this->gl_data->glXGetSwapIntervalMESA(); 1083 if (val == GLX_BAD_CONTEXT) { 1084 return SDL_SetError("GLX_BAD_CONTEXT"); 1085 } 1086 *interval = val; 1087 return true; 1088 } else { 1089 *interval = swapinterval; 1090 return true; 1091 } 1092} 1093 1094bool X11_GL_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window) 1095{ 1096 SDL_WindowData *data = window->internal; 1097 Display *display = data->videodata->display; 1098 1099 _this->gl_data->glXSwapBuffers(display, data->xwindow); 1100 1101#ifdef SDL_VIDEO_DRIVER_X11_XSYNC 1102 X11_HandlePresent(data->window); 1103#endif /* SDL_VIDEO_DRIVER_X11_XSYNC */ 1104 1105 return true; 1106} 1107 1108bool X11_GL_DestroyContext(SDL_VideoDevice *_this, SDL_GLContext context) 1109{ 1110 Display *display = _this->internal->display; 1111 GLXContext glx_context = (GLXContext)context; 1112 1113 if (!_this->gl_data) { 1114 return true; 1115 } 1116 _this->gl_data->glXDestroyContext(display, glx_context); 1117 X11_XSync(display, False); 1118 return true; 1119} 1120 1121#endif // SDL_VIDEO_OPENGL_GLX 1122 1123#endif // SDL_VIDEO_DRIVER_X11 1124
[FILE END]
(C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.