2 ================================================================================
3 Originally posted
by Ryan at:
8 - The Steam Runtime has (at least
in theory)
a really kick-ass build of SDL2,
9 but developers are shipping their own SDL2 with individual Steam games.
10 These games might stop getting updates, but
a newer SDL2 might be needed later.
11 Certainly we
'll always be fixing bugs in SDL, even if a new video target isn't
12 ever needed, and these fixes won
't make it to a game shipping its own SDL.
13 - Even if we replace the SDL2 in those games with a compatible one, that is to
14 say, edit a developer's Steam depot (yuck!), there are developers that are
15 statically linking SDL2 that we can
't do this for. We can't even force the
16 dynamic loader to ignore their SDL2
in this case, of course.
17 - If you don
't ship an SDL2 with the game in some form, people that disabled the
18 Steam Runtime, or just tried to run the game from the command line instead of
19 Steam might find themselves unable to run the game, due to a missing dependency.
20 - If you want to ship on non-Steam platforms like GOG or Humble Bundle, or target
21 generic Linux boxes that may or may not have SDL2 installed, you have to ship
22 the library or risk a total failure to launch. So now, you might have to have
23 a non-Steam build plus a Steam build (that is, one with and one without SDL2
24 included), which is inconvenient if you could have had one universal build
25 that works everywhere.
26 - We like the zlib license, but the biggest complaint from the open source
27 community about the license change is the static linking. The LGPL forced this
28 as a legal, not technical issue, but zlib doesn't care. Even those that aren
't
29 concerned about the GNU freedoms found themselves solving the same problems:
30 swapping in a newer SDL to an older game often times can save the day.
31 Static linking stops this dead.
33 So here's what we did:
35 SDL now has, internally,
a table of
function pointers. So,
this is what
SDL_Init
43 Except that is all
done with
a bunch of macro magic so we don
't have to maintain
46 What is jump_table.SDL_init()? Eventually, that's a function pointer of the real
47 SDL_Init() that you've been calling all this
time. But at startup, it looks more
57 pointers, which means that this _DEFAULT function never gets called again.
58 First call to any SDL function sets the whole thing up.
60 So you might be asking, what was the
value in that? Isn'
t this what the operating
61 system'
s dynamic loader was supposed to do for us? Yes, but now we've got this
62 level of indirection, we can do things like this:
65 ./MyGameThatIsStaticallyLinkedToSDL2
67 And now, this game that is staticallly linked to SDL, can still be overridden
68 with
a newer, or better, SDL. The statically linked
one will only be used as
69 far as calling into the jump
table in this case. But
in cases where no override
70 is desired, the statically linked version will provide its own jump
table,
71 and everyone is happy.
74 - Developers can statically link SDL, and users can still replace it.
75 (We'
d still rather you ship
a shared library, though!)
76 - Developers can ship an SDL with their game, Valve can override it for, say,
77 new features on SteamOS, or distros can override it for their own needs,
78 but it'll also just work
in the default case.
79 - Developers can ship the same package to everyone (Humble Bundle, GOG, etc),
80 and it'll do the
right thing.
81 - End users (and Valve) can update
a game'
s SDL
in almost any case,
82 to keep abandoned games running on newer platforms.
83 - Everyone develops with SDL exactly as they have been doing all along.
84 Same headers, same ABI. Just
get the latest version to
enable this magic.
89 Internally, InitAPI does some locking to make sure everything waits until
a
91 through here before spinning
a thread, too), and then decides if it should use
92 an external SDL library. If not, it sets up the jump table using the current
93 SDL'
s function pointers (which might be statically linked into
a program, or
in
94 a shared library of its own). If so, it loads that library and looks for and
95 calls
a single function:
99 That function takes
a version number (more on that
in a moment), the
address of
100 the jump table, and the
size,
in bytes, of the table.
101 Now, we've got
policy here: this table'
s layout never changes; new stuff gets
103 the needed functions if tablesize <= sizeof its own jump table. If tablesize is
104 bigger (say, SDL 2.0.4 is trying to load SDL 2.0.3), then we know to abort, but
105 if it'
s smaller, we know we can provide the entire API that the caller needs.
107 The version
variable is
a failsafe switch.
108 Right now it'
s always 1. This number changes when there are major API changes
109 (so we know if the tablesize might be smaller, or entries
in it have changed).
111 inconceivable to have
a small dispatch library that only supplies this
one
112 function and loads different, otherwise-incompatible SDL libraries and has the
113 right one initialize the jump table based on the version. For something that
114 must generically catch lots of different versions of SDL over
time, like the
117 Finally,
I'
m sure some people are reading this and thinking,
118 "
I don'
t want that overhead
in my project!"
119 To which
I would point out that the extra function call through the jump table
120 probably wouldn'
t even show up
in a profile, but lucky you: this can all be
121 disabled. You can build SDL without this if you absolutely must, but we would
122 encourage you not to do that. However, on heavily locked down platforms like
123 iOS, or maybe when debugging, it makes sense to disable it. The way this is
124 designed
in SDL, you just have to change
one #define, and the entire system
125 vaporizes out, and SDL functions exactly like it always did. Most of it is
126 macro magic, so the system is contained to
one C file and
a few headers.
127 However,
this is on
by default and you have to edit
a header file to turn it
128 off. Our hopes is that
if we make it easy to disable, but not too easy,
129 everyone will ultimately be able to
get what they want, but we
've gently
130 nudged everyone towards what we think is the best solution.
EGLSetBlobFuncANDROID EGLGetBlobFuncANDROID get
GLenum GLsizei GLenum GLenum const void * table
EGLSurface EGLnsecsANDROID time
SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char const char SDL_SCANF_FORMAT_STRING const char return SDL_ThreadFunction const char void return SDL_Init
SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char const char SDL_SCANF_FORMAT_STRING const char return SDL_ThreadFunction const char void return Uint32 return Uint32 SDL_AssertionHandler void SDL_SpinLock SDL_atomic_t int int return SDL_atomic_t return void void void return void return int return SDL_AudioSpec SDL_AudioSpec return int int return return int SDL_RWops int SDL_AudioSpec Uint8 ** d
static void SDL_InitDynamicAPI(void)
static SDL_DYNAPI_jump_table jump_table
GLsizei const GLfloat * value
GLsizei const void * pointer
Sint32 SDL_DYNAPI_entry(Uint32, void *, Uint32)
GLbitfield GLuint program
GLboolean GLboolean GLboolean GLboolean a
GLuint GLuint64EXT address