docs/README-dynapi.md
author Sam Lantinga
Sun, 05 Apr 2020 08:58:47 -0700
changeset 13689 c3055b205671
parent 11720 9cbb45a5874f
permissions -rw-r--r--
Fixed bug 5015 - SDL_RenderReadPixels on DirectX 11.1 backend seems to be broken

Konrad

It appears that I cannot use SDL_RenderReadPixels on a bound framebuffer (SDL_Texture set as render target) as it simply results in gibberish data. However, drawing that framebuffer into the default target (window surface) does render it correctly. Other backends (OpenGL, software, Direct3D) do work fine.

It looks to me like D3D11_RenderReadPixels just gets the general backbuffer and not the current render target and its backbuffer.

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