* This code was significantly different from the old code, enough that it made
more sense to re-implement from scratch than modify the old code.
* Note it doesn't compile yet and is not included in any projects.
* We have a hookset per GL interface - WGL, GLX, and stubbed out CGL for mac. In
addition we have EGL which can be compiled in at the same time as the others.
Each interface has a dispatch table similar to GL for handling its hooks all
together.
* The platform hooksets hook their platform-specific functions like
createcontext, swapbuffers, and makecurrent. For getprocaddress they can call
into a common function that looks up general GL hooks.
* EGL and GLX can populate the GL hooks using eglGetProcAddress /
glXGetProcAddress as soon as the library is loaded, but for WGL we must wait
until the first time a context becomes current.
* We also have an implementation of GLPlatform per type. This takes care of work
that is platform specific - mostly during replay but also somewhat during
capture. This is kept separate from the actual hooks.
* On replay we have a platform-specific replay create entry point which
populuates the relevant dispatch table and calls into a general replay create.
This will do most common work together but calls out to the GLPlatform
implementation to do actual initialisation of the API.
* In particular, populating hooks can't fail because we're just fetching as many
function pointers as we can. Any missing functions have to be handled
elsewhere.
* This simplifies codepaths and makes it easier to track what's going on without
needing to thinkg about failure conditions that can never happen.
* Hooking is now done the same way across platform, with different OS
implementations.
* Regardless of how exactly hooks are implemented, we register libraries to hook
and functions to hook within those libraries, and provide a location to store
the original/onwards function pointer. This allows hooking to work whether
it's done using import hooking that doesn't modify target libraries (so using
dlsym or GetProcAddress will return the same value for the onwards function
pointer) or whether it's implemented with prologue patching and trampolines,
where we'd create an infinite loop if we did that.
* We also provide stronger guarantees - the original function pointers will
_always_ be made available as soon as the library is loaded, whether hooked or
not, no exceptions. This means less uncertainty in hooking code about when or
how onward functions will be available.
* OS-specific hook functions are changed to just be implementations of
LibraryHooks functions rather than indirected through macros and pre-processor
definitions.
* In this commit we provide some temporary functions providing the old interface
to reduce churn - the library-specific hook code will be updated shortly after
* Hooking no longer does anything active immediately when initialised, it just
registers a function to be hooked, which is then deferred and/or continually
re-hooked depending on platform-specific functionality.
* Previously we were going through the hooks for device/factory creation, which
did barely anything actually useful. Instead we can call directly to the real
function and wrap the result manually.
* This wasn't very well supported after D3D11 anyway, and modern tools
(VSGD/PIX/etc) don't respect D3DPERF_SetOptions which was the only route that
actually needed to globally enable/disable hooks.
* D3D11CreateDevices's flag still works to prevent hooking.
* Rather than having a hookset created within the different bits of platform
hooking code and then passed around everywhere, we just make a single global
hookset object that's shared.
* There's no risk of conflict because our GL object handles all possible
contexts, there's no separate instancing or anything.
* We also have places like the GL emulation or unsupported function hooks that
do not handle two separate onward functions, and we undoubtedly have many
assumptions that only one copy of RenderDoc will hook any given API. If we
needed multiple hooksets within the same library a huge amount would need to
change.
* In particular this means that it's safe to compare a ResourceId or similar
against None. It is always not-equal but it's useful to have the comparison
work and return the expected result instead of throwing a null reference
exception.
* This becomes very spammy and there's not much that can be done - we just have
to hope the program bindings are not variable and end up the same on replay as
they were on capture.
* Could be a common pattern with texture streaming to copy a smaller texture's
mips into the mip-tail of a larger texture, then only provide data for higher
mips.
* If we try and match up input variables by location, and the shader has
multiple variables mapped to a single location, we end up leaving one variable
unmapped. We already have the information so we don't have to do this
inaccurate lookup.