Atlas - SDL_x11opengl.c

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