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