docs/README-dynapi.md
author Ryan C. Gordon <icculus@icculus.org>
Fri, 12 Aug 2016 19:59:00 -0400
changeset 10266 c09f06c4e8c8
parent 9756 2069629bd155
permissions -rw-r--r--
emscripten: send fake mouse events for touches, like other targets do. (This really should be handled at the higher level and not in the individual targets, but this fixes the immediate bug.)
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
9023
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
     1
Dynamic API
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
     2
================================================================================
9756
2069629bd155 Moving some whitespace around to test something on the Mercurial server.
Ryan C. Gordon <icculus@icculus.org>
parents: 9754
diff changeset
     3
Originally posted by Ryan at:
2069629bd155 Moving some whitespace around to test something on the Mercurial server.
Ryan C. Gordon <icculus@icculus.org>
parents: 9754
diff changeset
     4
  https://plus.google.com/103391075724026391227/posts/TB8UfnDYu4U
9023
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
     5
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
     6
Background:
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
     7
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
     8
- The Steam Runtime has (at least in theory) a really kick-ass build of SDL2, 
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
     9
  but developers are shipping their own SDL2 with individual Steam games. 
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    10
  These games might stop getting updates, but a newer SDL2 might be needed later. 
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    11
  Certainly we'll always be fixing bugs in SDL, even if a new video target isn't 
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    12
  ever needed, and these fixes won't make it to a game shipping its own SDL.
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    13
- Even if we replace the SDL2 in those games with a compatible one, that is to 
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    14
  say, edit a developer's Steam depot (yuck!), there are developers that are 
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    15
  statically linking SDL2 that we can't do this for. We can't even force the 
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    16
  dynamic loader to ignore their SDL2 in this case, of course.
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    17
- If you don't ship an SDL2 with the game in some form, people that disabled the
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    18
  Steam Runtime, or just tried to run the game from the command line instead of 
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    19
  Steam might find themselves unable to run the game, due to a missing dependency.
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    20
- If you want to ship on non-Steam platforms like GOG or Humble Bundle, or target
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    21
  generic Linux boxes that may or may not have SDL2 installed, you have to ship 
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    22
  the library or risk a total failure to launch. So now, you might have to have 
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    23
  a non-Steam build plus a Steam build (that is, one with and one without SDL2 
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    24
  included), which is inconvenient if you could have had one universal build 
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    25
  that works everywhere.
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    26
- We like the zlib license, but the biggest complaint from the open source 
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    27
  community about the license change is the static linking. The LGPL forced this 
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    28
  as a legal, not technical issue, but zlib doesn't care. Even those that aren't
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    29
  concerned about the GNU freedoms found themselves solving the same problems: 
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    30
  swapping in a newer SDL to an older game often times can save the day. 
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    31
  Static linking stops this dead.
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    32
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    33
So here's what we did:
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    34
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    35
SDL now has, internally, a table of function pointers. So, this is what SDL_Init
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    36
now looks like:
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    37
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    38
    UInt32 SDL_Init(Uint32 flags)
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    39
    {
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    40
        return jump_table.SDL_Init(flags);
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    41
    }
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    42
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    43
Except that is all done with a bunch of macro magic so we don't have to maintain
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    44
every one of these.
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    45
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    46
What is jump_table.SDL_init()? Eventually, that's a function pointer of the real
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    47
SDL_Init() that you've been calling all this time. But at startup, it looks more 
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    48
like this:
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    49
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    50
    Uint32 SDL_Init_DEFAULT(Uint32 flags)
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    51
    {
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    52
        SDL_InitDynamicAPI();
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    53
        return jump_table.SDL_Init(flags);
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    54
    }
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    55
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    56
SDL_InitDynamicAPI() fills in jump_table with all the actual SDL function 
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    57
pointers, which means that this _DEFAULT function never gets called again. 
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    58
First call to any SDL function sets the whole thing up.
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    59
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    60
So you might be asking, what was the value in that? Isn't this what the operating
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    61
system's dynamic loader was supposed to do for us? Yes, but now we've got this 
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    62
level of indirection, we can do things like this:
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    63
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    64
    export SDL_DYNAMIC_API=/my/actual/libSDL-2.0.so.0
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    65
    ./MyGameThatIsStaticallyLinkedToSDL2
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    66
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    67
And now, this game that is staticallly linked to SDL, can still be overridden 
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    68
with a newer, or better, SDL. The statically linked one will only be used as 
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    69
far as calling into the jump table in this case. But in cases where no override
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    70
is desired, the statically linked version will provide its own jump table, 
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    71
and everyone is happy.
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    72
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    73
So now:
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    74
- Developers can statically link SDL, and users can still replace it. 
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    75
  (We'd still rather you ship a shared library, though!)
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    76
- Developers can ship an SDL with their game, Valve can override it for, say, 
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    77
  new features on SteamOS, or distros can override it for their own needs, 
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    78
  but it'll also just work in the default case.
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    79
- Developers can ship the same package to everyone (Humble Bundle, GOG, etc), 
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    80
  and it'll do the right thing.
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    81
- End users (and Valve) can update a game's SDL in almost any case, 
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    82
  to keep abandoned games running on newer platforms.
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    83
- Everyone develops with SDL exactly as they have been doing all along. 
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    84
  Same headers, same ABI. Just get the latest version to enable this magic.
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    85
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    86
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    87
A little more about SDL_InitDynamicAPI():
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    88
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    89
Internally, InitAPI does some locking to make sure everything waits until a 
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    90
single thread initializes everything (although even SDL_CreateThread() goes 
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    91
through here before spinning a thread, too), and then decides if it should use
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    92
an external SDL library. If not, it sets up the jump table using the current 
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    93
SDL's function pointers (which might be statically linked into a program, or in
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    94
a shared library of its own). If so, it loads that library and looks for and 
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    95
calls a single function:
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    96
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    97
    SInt32 SDL_DYNAPI_entry(Uint32 version, void *table, Uint32 tablesize);
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    98
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
    99
That function takes a version number (more on that in a moment), the address of
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
   100
the jump table, and the size, in bytes, of the table. 
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
   101
Now, we've got policy here: this table's layout never changes; new stuff gets 
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
   102
added to the end. Therefore SDL_DYNAPI_entry() knows that it can provide all 
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
   103
the needed functions if tablesize <= sizeof its own jump table. If tablesize is
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
   104
bigger (say, SDL 2.0.4 is trying to load SDL 2.0.3), then we know to abort, but
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
   105
if it's smaller, we know we can provide the entire API that the caller needs.
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
   106
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
   107
The version variable is a failsafe switch. 
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
   108
Right now it's always 1. This number changes when there are major API changes 
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
   109
(so we know if the tablesize might be smaller, or entries in it have changed). 
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
   110
Right now SDL_DYNAPI_entry gives up if the version doesn't match, but it's not 
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
   111
inconceivable to have a small dispatch library that only supplies this one 
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
   112
function and loads different, otherwise-incompatible SDL libraries and has the
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
   113
right one initialize the jump table based on the version. For something that 
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
   114
must generically catch lots of different versions of SDL over time, like the 
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
   115
Steam Client, this isn't a bad option.
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
   116
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
   117
Finally, I'm sure some people are reading this and thinking,
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
   118
"I don't want that overhead in my project!"  
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
   119
To which I would point out that the extra function call through the jump table 
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
   120
probably wouldn't even show up in a profile, but lucky you: this can all be 
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
   121
disabled. You can build SDL without this if you absolutely must, but we would 
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
   122
encourage you not to do that. However, on heavily locked down platforms like 
9754
fe6acfd4652c Whitespace fix.
Ryan C. Gordon <icculus@icculus.org>
parents: 9025
diff changeset
   123
iOS, or maybe when debugging, it makes sense to disable it. The way this is
9023
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
   124
designed in SDL, you just have to change one #define, and the entire system 
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
   125
vaporizes out, and SDL functions exactly like it always did. Most of it is 
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
   126
macro magic, so the system is contained to one C file and a few headers. 
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
   127
However, this is on by default and you have to edit a header file to turn it 
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
   128
off. Our hopes is that if we make it easy to disable, but not too easy, 
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
   129
everyone will ultimately be able to get what they want, but we've gently 
276802355854 Rearrange documentation
Gabriel Jacobo <gabomdq@gmail.com>
parents:
diff changeset
   130
nudged everyone towards what we think is the best solution.