Atlas - SDL_dynapi.c

Home / ext / SDL / src / dynapi Lines: 6 | Size: 35784 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)]
[FILE BEGIN]
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2026 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 22#include "SDL_build_config.h" 23#include "SDL_dynapi.h" 24#include "SDL_dynapi_unsupported.h" 25 26#if SDL_DYNAMIC_API 27 28#define SDL_DYNAMIC_API_ENVVAR "SDL3_DYNAMIC_API" 29#define SDL_SLOW_MEMCPY 30#define SDL_SLOW_MEMMOVE 31#define SDL_SLOW_MEMSET 32 33#ifdef HAVE_STDIO_H 34#include <stdio.h> 35#endif 36#ifdef HAVE_STDLIB_H 37#include <stdlib.h> 38#endif 39 40#include <SDL3/SDL.h> 41#include <SDL3/SDL_openxr.h> 42#define SDL_MAIN_NOIMPL // don't drag in header-only implementation of SDL_main 43#include <SDL3/SDL_main.h> 44#include "../core/SDL_core_unsupported.h" 45#include "../video/SDL_video_unsupported.h" 46 47 48// These headers have system specific definitions, so aren't included above 49#include <SDL3/SDL_vulkan.h> 50 51#if defined(WIN32) || defined(_WIN32) || defined(SDL_PLATFORM_CYGWIN) 52#ifndef WIN32_LEAN_AND_MEAN 53#define WIN32_LEAN_AND_MEAN 1 54#endif 55#include <windows.h> 56#endif 57 58/* This is the version of the dynamic API. This doesn't match the SDL version 59 and should not change until there's been a major revamp in API/ABI. 60 So 2.0.5 adds functions over 2.0.4? This number doesn't change; 61 the sizeof(jump_table) changes instead. But 2.1.0 changes how a function 62 works in an incompatible way or removes a function? This number changes, 63 since sizeof(jump_table) isn't sufficient anymore. It's likely 64 we'll forget to bump every time we add a function, so this is the 65 failsafe switch for major API change decisions. Respect it and use it 66 sparingly. */ 67#define SDL_DYNAPI_VERSION 2 68 69#ifdef __cplusplus 70extern "C" { 71#endif 72 73static void SDL_InitDynamicAPI(void); 74 75/* BE CAREFUL CALLING ANY SDL CODE IN HERE, IT WILL BLOW UP. 76 Even self-contained stuff might call SDL_SetError() and break everything. */ 77 78// behold, the macro salsa! 79 80// Can't use the macro for varargs nonsense. This is atrocious. 81#define SDL_DYNAPI_VARARGS_LOGFN(_static, name, initcall, logname, prio) \ 82 _static void SDLCALL SDL_Log##logname##name(int category, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) \ 83 { \ 84 va_list ap; \ 85 initcall; \ 86 va_start(ap, fmt); \ 87 jump_table.SDL_LogMessageV(category, SDL_LOG_PRIORITY_##prio, fmt, ap); \ 88 va_end(ap); \ 89 } 90 91#define SDL_DYNAPI_VARARGS(_static, name, initcall) \ 92 _static bool SDLCALL SDL_SetError##name(SDL_PRINTF_FORMAT_STRING const char *fmt, ...) \ 93 { \ 94 char buf[128], *str = buf; \ 95 int result; \ 96 va_list ap; \ 97 initcall; \ 98 va_start(ap, fmt); \ 99 result = jump_table.SDL_vsnprintf(buf, sizeof(buf), fmt, ap); \ 100 va_end(ap); \ 101 if (result >= 0 && (size_t)result >= sizeof(buf)) { \ 102 str = NULL; \ 103 va_start(ap, fmt); \ 104 result = jump_table.SDL_vasprintf(&str, fmt, ap); \ 105 va_end(ap); \ 106 } \ 107 if (result >= 0) { \ 108 jump_table.SDL_SetError("%s", str); \ 109 } \ 110 if (str != buf) { \ 111 jump_table.SDL_free(str); \ 112 } \ 113 return false; \ 114 } \ 115 _static int SDLCALL SDL_sscanf##name(const char *buf, SDL_SCANF_FORMAT_STRING const char *fmt, ...) \ 116 { \ 117 int result; \ 118 va_list ap; \ 119 initcall; \ 120 va_start(ap, fmt); \ 121 result = jump_table.SDL_vsscanf(buf, fmt, ap); \ 122 va_end(ap); \ 123 return result; \ 124 } \ 125 _static int SDLCALL SDL_snprintf##name(SDL_OUT_Z_CAP(maxlen) char *buf, size_t maxlen, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) \ 126 { \ 127 int result; \ 128 va_list ap; \ 129 initcall; \ 130 va_start(ap, fmt); \ 131 result = jump_table.SDL_vsnprintf(buf, maxlen, fmt, ap); \ 132 va_end(ap); \ 133 return result; \ 134 } \ 135 _static int SDLCALL SDL_swprintf##name(SDL_OUT_Z_CAP(maxlen) wchar_t *buf, size_t maxlen, SDL_PRINTF_FORMAT_STRING const wchar_t *fmt, ...) \ 136 { \ 137 int result; \ 138 va_list ap; \ 139 initcall; \ 140 va_start(ap, fmt); \ 141 result = jump_table.SDL_vswprintf(buf, maxlen, fmt, ap); \ 142 va_end(ap); \ 143 return result; \ 144 } \ 145 _static int SDLCALL SDL_asprintf##name(char **strp, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) \ 146 { \ 147 int result; \ 148 va_list ap; \ 149 initcall; \ 150 va_start(ap, fmt); \ 151 result = jump_table.SDL_vasprintf(strp, fmt, ap); \ 152 va_end(ap); \ 153 return result; \ 154 } \ 155 _static size_t SDLCALL SDL_IOprintf##name(SDL_IOStream *context, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) \ 156 { \ 157 size_t result; \ 158 va_list ap; \ 159 initcall; \ 160 va_start(ap, fmt); \ 161 result = jump_table.SDL_IOvprintf(context, fmt, ap); \ 162 va_end(ap); \ 163 return result; \ 164 } \ 165 _static bool SDLCALL SDL_RenderDebugTextFormat##name(SDL_Renderer *renderer, float x, float y, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) \ 166 { \ 167 char buf[128], *str = buf; \ 168 int result; \ 169 va_list ap; \ 170 initcall; \ 171 va_start(ap, fmt); \ 172 result = jump_table.SDL_vsnprintf(buf, sizeof(buf), fmt, ap); \ 173 va_end(ap); \ 174 if (result >= 0 && (size_t)result >= sizeof(buf)) { \ 175 str = NULL; \ 176 va_start(ap, fmt); \ 177 result = jump_table.SDL_vasprintf(&str, fmt, ap); \ 178 va_end(ap); \ 179 } \ 180 bool retval = false; \ 181 if (result >= 0) { \ 182 retval = jump_table.SDL_RenderDebugTextFormat(renderer, x, y, "%s", str); \ 183 } \ 184 if (str != buf) { \ 185 jump_table.SDL_free(str); \ 186 } \ 187 return retval; \ 188 } \ 189 _static void SDLCALL SDL_Log##name(SDL_PRINTF_FORMAT_STRING const char *fmt, ...) \ 190 { \ 191 va_list ap; \ 192 initcall; \ 193 va_start(ap, fmt); \ 194 jump_table.SDL_LogMessageV(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, fmt, ap); \ 195 va_end(ap); \ 196 } \ 197 _static void SDLCALL SDL_LogMessage##name(int category, SDL_LogPriority priority, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) \ 198 { \ 199 va_list ap; \ 200 initcall; \ 201 va_start(ap, fmt); \ 202 jump_table.SDL_LogMessageV(category, priority, fmt, ap); \ 203 va_end(ap); \ 204 } \ 205 SDL_DYNAPI_VARARGS_LOGFN(_static, name, initcall, Trace, TRACE) \ 206 SDL_DYNAPI_VARARGS_LOGFN(_static, name, initcall, Verbose, VERBOSE) \ 207 SDL_DYNAPI_VARARGS_LOGFN(_static, name, initcall, Debug, DEBUG) \ 208 SDL_DYNAPI_VARARGS_LOGFN(_static, name, initcall, Info, INFO) \ 209 SDL_DYNAPI_VARARGS_LOGFN(_static, name, initcall, Warn, WARN) \ 210 SDL_DYNAPI_VARARGS_LOGFN(_static, name, initcall, Error, ERROR) \ 211 SDL_DYNAPI_VARARGS_LOGFN(_static, name, initcall, Critical, CRITICAL) 212 213// Typedefs for function pointers for jump table, and predeclare funcs 214// The DEFAULT funcs will init jump table and then call real function. 215// The REAL funcs are the actual functions, name-mangled to not clash. 216#define SDL_DYNAPI_PROC(rc, fn, params, args, ret) \ 217 typedef rc (SDLCALL *SDL_DYNAPIFN_##fn) params;\ 218 static rc SDLCALL fn##_DEFAULT params; \ 219 extern rc SDLCALL fn##_REAL params; 220#include "SDL_dynapi_procs.h" 221#undef SDL_DYNAPI_PROC 222 223// The jump table! 224typedef struct 225{ 226#define SDL_DYNAPI_PROC(rc, fn, params, args, ret) SDL_DYNAPIFN_##fn fn; 227#include "SDL_dynapi_procs.h" 228#undef SDL_DYNAPI_PROC 229} SDL_DYNAPI_jump_table; 230 231// The actual jump table. 232static SDL_DYNAPI_jump_table jump_table = { 233#define SDL_DYNAPI_PROC(rc, fn, params, args, ret) fn##_DEFAULT, 234#include "SDL_dynapi_procs.h" 235#undef SDL_DYNAPI_PROC 236}; 237 238// Default functions init the function table then call right thing. 239#define SDL_DYNAPI_PROC(rc, fn, params, args, ret) \ 240 static rc SDLCALL fn##_DEFAULT params \ 241 { \ 242 SDL_InitDynamicAPI(); \ 243 ret jump_table.fn args; \ 244 } 245#define SDL_DYNAPI_PROC_NO_VARARGS 1 246#include "SDL_dynapi_procs.h" 247#undef SDL_DYNAPI_PROC 248#undef SDL_DYNAPI_PROC_NO_VARARGS 249SDL_DYNAPI_VARARGS(static, _DEFAULT, SDL_InitDynamicAPI()) 250 251// Public API functions to jump into the jump table. 252#define SDL_DYNAPI_PROC(rc, fn, params, args, ret) \ 253 rc SDLCALL fn params \ 254 { \ 255 ret jump_table.fn args; \ 256 } 257#define SDL_DYNAPI_PROC_NO_VARARGS 1 258#include "SDL_dynapi_procs.h" 259#undef SDL_DYNAPI_PROC 260#undef SDL_DYNAPI_PROC_NO_VARARGS 261SDL_DYNAPI_VARARGS(, , ) 262 263#define ENABLE_SDL_CALL_LOGGING 0 264#if ENABLE_SDL_CALL_LOGGING 265static bool SDLCALL SDL_SetError_LOGSDLCALLS(SDL_PRINTF_FORMAT_STRING const char *fmt, ...) 266{ 267 char buf[512]; // !!! FIXME: dynamic allocation 268 va_list ap; 269 SDL_Log_REAL("SDL3CALL SDL_SetError"); 270 va_start(ap, fmt); 271 SDL_vsnprintf_REAL(buf, sizeof(buf), fmt, ap); 272 va_end(ap); 273 return SDL_SetError_REAL("%s", buf); 274} 275static int SDLCALL SDL_sscanf_LOGSDLCALLS(const char *buf, SDL_SCANF_FORMAT_STRING const char *fmt, ...) 276{ 277 int result; 278 va_list ap; 279 SDL_Log_REAL("SDL3CALL SDL_sscanf"); 280 va_start(ap, fmt); 281 result = SDL_vsscanf_REAL(buf, fmt, ap); 282 va_end(ap); 283 return result; 284} 285static int SDLCALL SDL_snprintf_LOGSDLCALLS(SDL_OUT_Z_CAP(maxlen) char *buf, size_t maxlen, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) 286{ 287 int result; 288 va_list ap; 289 SDL_Log_REAL("SDL3CALL SDL_snprintf"); 290 va_start(ap, fmt); 291 result = SDL_vsnprintf_REAL(buf, maxlen, fmt, ap); 292 va_end(ap); 293 return result; 294} 295static int SDLCALL SDL_asprintf_LOGSDLCALLS(char **strp, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) 296{ 297 int result; 298 va_list ap; 299 SDL_Log_REAL("SDL3CALL SDL_asprintf"); 300 va_start(ap, fmt); 301 result = SDL_vasprintf_REAL(strp, fmt, ap); 302 va_end(ap); 303 return result; 304} 305static int SDLCALL SDL_swprintf_LOGSDLCALLS(SDL_OUT_Z_CAP(maxlen) wchar_t *buf, size_t maxlen, SDL_PRINTF_FORMAT_STRING const wchar_t *fmt, ...) 306{ 307 int result; 308 va_list ap; 309 SDL_Log_REAL("SDL3CALL SDL_swprintf"); 310 va_start(ap, fmt); 311 result = SDL_vswprintf_REAL(buf, maxlen, fmt, ap); 312 va_end(ap); 313 return result; 314} 315static size_t SDLCALL SDL_IOprintf_LOGSDLCALLS(SDL_IOStream *context, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) 316{ 317 size_t result; 318 va_list ap; 319 SDL_Log_REAL("SDL3CALL SDL_IOprintf"); 320 va_start(ap, fmt); 321 result = SDL_IOvprintf_REAL(context, fmt, ap); 322 va_end(ap); 323 return result; 324} 325static bool SDLCALL SDL_RenderDebugTextFormat_LOGSDLCALLS(SDL_Renderer *renderer, float x, float y, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) 326{ 327 char buf[128], *str = buf; 328 int result; 329 va_list ap; 330 SDL_Log_REAL("SDL3CALL SDL_RenderDebugTextFormat"); 331 va_start(ap, fmt); 332 result = jump_table.SDL_vsnprintf(buf, sizeof(buf), fmt, ap); 333 va_end(ap); 334 if (result >= 0 && (size_t)result >= sizeof(buf)) { 335 str = NULL; 336 va_start(ap, fmt); 337 result = SDL_vasprintf_REAL(&str, fmt, ap); 338 va_end(ap); 339 } 340 bool retval = false; 341 if (result >= 0) { 342 retval = SDL_RenderDebugTextFormat_REAL(renderer, x, y, "%s", str); 343 } 344 if (str != buf) { 345 jump_table.SDL_free(str); 346 } 347 return retval; 348} 349static void SDLCALL SDL_Log_LOGSDLCALLS(SDL_PRINTF_FORMAT_STRING const char *fmt, ...) 350{ 351 va_list ap; 352 SDL_Log_REAL("SDL3CALL SDL_Log"); 353 va_start(ap, fmt); 354 SDL_LogMessageV_REAL(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, fmt, ap); 355 va_end(ap); 356} 357static void SDLCALL SDL_LogMessage_LOGSDLCALLS(int category, SDL_LogPriority priority, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) 358{ 359 va_list ap; 360 SDL_Log_REAL("SDL3CALL SDL_LogMessage"); 361 va_start(ap, fmt); 362 SDL_LogMessageV_REAL(category, priority, fmt, ap); 363 va_end(ap); 364} 365#define SDL_DYNAPI_VARARGS_LOGFN_LOGSDLCALLS(logname, prio) \ 366 static void SDLCALL SDL_Log##logname##_LOGSDLCALLS(int category, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) \ 367 { \ 368 va_list ap; \ 369 va_start(ap, fmt); \ 370 SDL_Log_REAL("SDL3CALL SDL_Log%s", #logname); \ 371 SDL_LogMessageV_REAL(category, SDL_LOG_PRIORITY_##prio, fmt, ap); \ 372 va_end(ap); \ 373 } 374SDL_DYNAPI_VARARGS_LOGFN_LOGSDLCALLS(Trace, TRACE) 375SDL_DYNAPI_VARARGS_LOGFN_LOGSDLCALLS(Verbose, VERBOSE) 376SDL_DYNAPI_VARARGS_LOGFN_LOGSDLCALLS(Debug, DEBUG) 377SDL_DYNAPI_VARARGS_LOGFN_LOGSDLCALLS(Info, INFO) 378SDL_DYNAPI_VARARGS_LOGFN_LOGSDLCALLS(Warn, WARN) 379SDL_DYNAPI_VARARGS_LOGFN_LOGSDLCALLS(Error, ERROR) 380SDL_DYNAPI_VARARGS_LOGFN_LOGSDLCALLS(Critical, CRITICAL) 381#define SDL_DYNAPI_PROC(rc, fn, params, args, ret) \ 382 rc SDLCALL fn##_LOGSDLCALLS params \ 383 { \ 384 SDL_Log_REAL("SDL3CALL %s", #fn); \ 385 ret fn##_REAL args; \ 386 } 387#define SDL_DYNAPI_PROC_NO_VARARGS 1 388#include "SDL_dynapi_procs.h" 389#undef SDL_DYNAPI_PROC 390#undef SDL_DYNAPI_PROC_NO_VARARGS 391#endif 392 393/* we make this a static function so we can call the correct one without the 394 system's dynamic linker resolving to the wrong version of this. */ 395static Sint32 initialize_jumptable(Uint32 apiver, void *table, Uint32 tablesize) 396{ 397 SDL_DYNAPI_jump_table *output_jump_table = (SDL_DYNAPI_jump_table *)table; 398 399 if (apiver != SDL_DYNAPI_VERSION) { 400 // !!! FIXME: can maybe handle older versions? 401 return -1; // not compatible. 402 } else if (tablesize > sizeof(jump_table)) { 403 return -1; // newer version of SDL with functions we can't provide. 404 } 405 406// Init our jump table first. 407#if ENABLE_SDL_CALL_LOGGING 408 { 409 const char *env = SDL_getenv_unsafe_REAL("SDL_DYNAPI_LOG_CALLS"); 410 const bool log_calls = (env && SDL_atoi_REAL(env)); 411 if (log_calls) { 412#define SDL_DYNAPI_PROC(rc, fn, params, args, ret) jump_table.fn = fn##_LOGSDLCALLS; 413#include "SDL_dynapi_procs.h" 414#undef SDL_DYNAPI_PROC 415 } else { 416#define SDL_DYNAPI_PROC(rc, fn, params, args, ret) jump_table.fn = fn##_REAL; 417#include "SDL_dynapi_procs.h" 418#undef SDL_DYNAPI_PROC 419 } 420 } 421#else 422#define SDL_DYNAPI_PROC(rc, fn, params, args, ret) jump_table.fn = fn##_REAL; 423#include "SDL_dynapi_procs.h" 424#undef SDL_DYNAPI_PROC 425#endif 426 427 // Then the external table... 428 if (output_jump_table != &jump_table) { 429 jump_table.SDL_memcpy(output_jump_table, &jump_table, tablesize); 430 } 431 432 // Safe to call SDL functions now; jump table is initialized! 433 434 return 0; // success! 435} 436 437// Here's the exported entry point that fills in the jump table. 438// Use specific types when an "int" might suffice to keep this sane. 439typedef Sint32 (SDLCALL *SDL_DYNAPI_ENTRYFN)(Uint32 apiver, void *table, Uint32 tablesize); 440extern SDL_DECLSPEC Sint32 SDLCALL SDL_DYNAPI_entry(Uint32, void *, Uint32); 441 442Sint32 SDL_DYNAPI_entry(Uint32 apiver, void *table, Uint32 tablesize) 443{ 444 return initialize_jumptable(apiver, table, tablesize); 445} 446 447#ifdef __cplusplus 448} 449#endif 450 451 452// Obviously we can't use SDL_LoadObject() to load SDL. :) 453// Also obviously, we never close the loaded library, once we accept it. 454#if defined(WIN32) || defined(_WIN32) || defined(SDL_PLATFORM_CYGWIN) 455static HMODULE sdlapi_lib = NULL; // The handle to the other SDL library, loaded with SDL_DYNAMIC_API_ENVVAR 456 457static SDL_INLINE void unload_sdlapi_library(void) 458{ 459 if (sdlapi_lib) { 460 FreeLibrary(sdlapi_lib); 461 sdlapi_lib = NULL; 462 } 463} 464 465static SDL_INLINE void *get_sdlapi_entry(const char *fname, const char *sym) 466{ 467 sdlapi_lib = LoadLibraryA(fname); 468 void *result = NULL; 469 if (sdlapi_lib) { 470 result = (void *) GetProcAddress(sdlapi_lib, sym); 471 if (!result) { 472 unload_sdlapi_library(); 473 } 474 } 475 return result; 476} 477 478#elif defined(SDL_PLATFORM_UNIX) || defined(SDL_PLATFORM_APPLE) || defined(SDL_PLATFORM_HAIKU) 479#include <dlfcn.h> 480static void *sdlapi_lib = NULL; // The handle to the other SDL library, loaded with SDL_DYNAMIC_API_ENVVAR 481 482static SDL_INLINE void unload_sdlapi_library(void) 483{ 484 if (sdlapi_lib) { 485 dlclose(sdlapi_lib); 486 sdlapi_lib = NULL; 487 } 488} 489 490static SDL_INLINE void *get_sdlapi_entry(const char *fname, const char *sym) 491{ 492 sdlapi_lib = dlopen(fname, RTLD_NOW | RTLD_LOCAL); 493 void *result = NULL; 494 if (sdlapi_lib) { 495 result = dlsym(sdlapi_lib, sym); 496 if (!result) { 497 unload_sdlapi_library(); 498 } 499 } 500 return result; 501} 502 503#else 504#error Please define your platform. 505#endif 506 507static void dynapi_warn(const char *msg) 508{ 509 const char *caption = "SDL Dynamic API Failure!"; 510 (void)caption; 511// SDL_ShowSimpleMessageBox() is a too heavy for here. 512#if (defined(WIN32) || defined(_WIN32) || defined(SDL_PLATFORM_CYGWIN)) && !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES) 513 MessageBoxA(NULL, msg, caption, MB_OK | MB_ICONERROR); 514#elif defined(HAVE_STDIO_H) 515 fprintf(stderr, "\n\n%s\n%s\n\n", caption, msg); 516 fflush(stderr); 517#endif 518} 519 520/* This is not declared in any header, although it is shared between some 521 parts of SDL, because we don't want anything calling it without an 522 extremely good reason. */ 523#ifdef __cplusplus 524extern "C" { 525#endif 526extern SDL_NORETURN void SDL_ExitProcess(int exitcode); 527#ifdef __cplusplus 528} 529#endif 530 531static void SDL_InitDynamicAPILocked(void) 532{ 533 // this can't use SDL_getenv_unsafe_REAL, because it might allocate memory before the app can set their allocator. 534#if defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__) 535 // We've always used LoadLibraryA for this, so this has never worked with Unicode paths on Windows. Sorry. 536 char envbuf[512]; // overflows will just report as environment variable being unset, but LoadLibraryA has a MAX_PATH of 260 anyhow, apparently. 537 const DWORD rc = GetEnvironmentVariableA(SDL_DYNAMIC_API_ENVVAR, envbuf, (DWORD) sizeof (envbuf)); 538 char *libname = ((rc != 0) && (rc < sizeof (envbuf))) ? envbuf : NULL; 539#else 540 char *libname = getenv(SDL_DYNAMIC_API_ENVVAR); // This should NOT be SDL_getenv() 541#endif 542 543 SDL_DYNAPI_ENTRYFN entry = NULL; // funcs from here by default. 544 bool use_internal = true; 545 546 if (libname) { 547 while (*libname && !entry) { 548 // This is evil, but we're not making any permanent changes... 549 char *ptr = (char *)libname; 550 while (true) { 551 char ch = *ptr; 552 if ((ch == ',') || (ch == '\0')) { 553 *ptr = '\0'; 554 entry = (SDL_DYNAPI_ENTRYFN)get_sdlapi_entry(libname, "SDL_DYNAPI_entry"); 555 *ptr = ch; 556 libname = (ch == '\0') ? ptr : (ptr + 1); 557 break; 558 } else { 559 ptr++; 560 } 561 } 562 } 563 if (!entry) { 564 dynapi_warn("Couldn't load an overriding SDL library. Please fix or remove the " SDL_DYNAMIC_API_ENVVAR " environment variable. Using the default SDL."); 565 // Just fill in the function pointers from this library, later. 566 } 567 } 568 569 if (entry) { 570 if (entry(SDL_DYNAPI_VERSION, &jump_table, sizeof(jump_table)) < 0) { 571 dynapi_warn("Couldn't override SDL library. Using a newer SDL build might help. Please fix or remove the " SDL_DYNAMIC_API_ENVVAR " environment variable. Using the default SDL."); 572 573 // unload the failed SDL library 574 unload_sdlapi_library(); 575 576 // Just fill in the function pointers from this library, later. 577 } else { 578 use_internal = false; // We overrode SDL! Don't use the internal version! 579 } 580 } 581 582 // Just fill in the function pointers from this library. 583 if (use_internal) { 584 if (initialize_jumptable(SDL_DYNAPI_VERSION, &jump_table, sizeof(jump_table)) < 0) { 585 // Now we're screwed. Should definitely abort now. 586 dynapi_warn("Failed to initialize internal SDL dynapi. As this would otherwise crash, we have to abort now."); 587#ifndef NDEBUG 588 SDL_TriggerBreakpoint(); 589#endif 590 SDL_ExitProcess(86); 591 } 592 } 593 594 // we intentionally never close the newly-loaded lib, of course. 595} 596 597static void SDL_InitDynamicAPI(void) 598{ 599 /* So the theory is that every function in the jump table defaults to 600 * calling this function, and then replaces itself with a version that 601 * doesn't call this function anymore. But it's possible that, in an 602 * extreme corner case, you can have a second thread hit this function 603 * while the jump table is being initialized by the first. 604 * In this case, a spinlock is really painful compared to what spinlocks 605 * _should_ be used for, but this would only happen once, and should be 606 * insanely rare, as you would have to spin a thread outside of SDL (as 607 * SDL_CreateThread() would also call this function before building the 608 * new thread). 609 */ 610 static bool already_initialized = false; 611 612 static SDL_SpinLock lock = 0; 613 SDL_LockSpinlock_REAL(&lock); 614 615 if (!already_initialized) { 616 SDL_InitDynamicAPILocked(); 617 already_initialized = true; 618 } 619 620 SDL_UnlockSpinlock_REAL(&lock); 621} 622 623#else // SDL_DYNAMIC_API 624 625#include <SDL3/SDL.h> 626#include <SDL3/SDL_openxr.h> 627 628Sint32 SDL_DYNAPI_entry(Uint32 apiver, void *table, Uint32 tablesize); 629Sint32 SDL_DYNAPI_entry(Uint32 apiver, void *table, Uint32 tablesize) 630{ 631 (void)apiver; 632 (void)table; 633 (void)tablesize; 634 return -1; // not compatible. 635} 636 637#endif // SDL_DYNAMIC_API 638
[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.