* 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.
* 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.
* This is based on the GAPID method of injection, using the same steps
to connect with JDWP and debug the application, breakpointing on key
init-time steps to patch vulkan layer search paths and load libraries
from our installed apk.
* We diverge by then using PLT hooks instead of trampolines to hook the
EGL/GL calls - and so we also hook dlopen.
* This should work on any debuggable application - not currently checked
but does not replace/break any of the previous injection, which can
still work.
* Instead of checking on the filename, we look for a specially named
exported symbol somewhere in a module that's already loaded.
* This allows us to mark the python module as a replay program, so if
it's loaded into the python interpreter it will be able to use the
replay API.
* Using OS-specific append writing functions instead of simple fopen/
fwrite/fclose we can guarantee that multiple processes writing to the
same log file won't trash or interleave their log output.
* To make the logs readable the PID is now included along with the
project/timestamp.
* After that, we make sure that when we launch a program we set the
output log to the same file as the parent UI. This keeps all the logs
together and removes user confusion over which logfile is needed.
* We also move all of RenderDoc's temporary files under a RenderDoc
folder in the temp folder, instead of scattering the files in the root
Notes
======
- With no clean way to do string comparisons in the C preprocessor, have a define per-platform. This avoids the clever string concatenation for determining the OS-specic bits, and allows SN-DBS to distribute builds without custom rewrite rules.
- Fix up instances of WIN32, etc., in non-3rdparty sources to refer to this.
- Move the per-platform specific bits into their own subdirs.
* This is kind of arbitrary at the moment, but in future when D3D12 and
Vulkan drivers appear, not everyone who builds RenderDoc will want to
build all drivers, so making them separate projects makes it more easy
to disable/remove them.
* The core class is now responsible for tracking the active window and
cycling through, so it can cycle through multiple APIs.
* For GL we only set up associations for capturable windows, and only
those that present (since helper windows are often created). Since
GL doesn't really have a 'this window is done rendering' call, we just
decay old windows that haven't presented in >5 seconds.
* Also on GL, legacy/uncapturable windows aren't associated so they will
not cycle to at all.
* The embedding API now expects a device pointer and window handle to
set active window or start/end a capture. You can still pass NULLs if
there is only one API active.
* If CreateContextAttribs is not used to create the context, the overlay
will run in super-duper old mode using immediate mode calls and fixed
function pipeline. This way it should display on (in theory) any GL
app. Capturing will be prevented.
* Compatibility profile contexts are still allowed, but a warning is
displayed in the overlay.
* If CreateContextAttribs is used to create a < 3.2 version context, we
go down the same path as for legacy contexts, except with an accurate
overlay message (just that the version isn't supported).
* Note at the time of committing there are still some warnings in MS
headers that you might need to suppress in a couple of files.
* 3rd party code just has the warnings suppressed for ease of merging.
* The majority of warning fixes were for local variables shadowing
other locals, function parameters, or members. In most cases they
weren't a problem, but in some cases it was potentially dangerous!
* We need to copy the X display (by fetching its connection string and
calling XOpenDisplay), so that if the Display* we had gets closed then
nothing will crash.
* Doesn't compile yet! Just splitting this up logically so the change is
a bit easier to digest.
* I've commented and organised a bit better the gl_hookset.h hook list.
* The function hooks are set up for all of the ARB_dsa entry points.
Those that are semnatically identical to EXT_dsa are set up as aliases
(with EXT_ being canonical, so we can fall back if ARB_dsa isn't
supported - see comments in gl_hookset.h).
* Implemented the new functions except for the glTexture* family and the
glCreate* family. No deduplication of code yet.
* As with EXT_dsa we "promote" to the DSA function for serialisation,
but since unlike EXT_dsa we can't assume ARB_dsa is present, instead
we emulate those functions that we might use unconditionally but may
not be present.
* It's not exactly feature parity but it's a start, and any UI would use
this under the hood.
* This means at least linux has a semi user-friendly way to launch and
capture programs - it's limited but you can just use
$ ./bin/renderdoccmd -c /path/to/program "argument string"
from the root of the repository.
* Logfile and capture options (which can't be set yet, but you could easily
hack in something to set them in renderdoccmd.cpp) are passed via
environment variables to the child process.
* To remove renderdoc (e.g. if the API version doesn't match what is
expected), user code can call RENDERDOC_Shutdown() to remove the running
thread and undo any library hooks, then unload the dynamic library.
* This still isn't recommended as there could be unexpected side-effects,
and it will definitely break if this happens after any APIs have been
initialised, but it's an option.
* I will assume for now that any wgl functions I don't explicitly hook have
no effect on the captured frame and we can safely just let them straight
through to the real function.
* Now instead of returning NULL for entry points that we don't support and
hoping the application will handle that or error out, instead we return
a function that will log an error if it is ever called, and then pass
through to the real function. In most cases, the capture will probably be
broken as whichever function isn't saved.
* hookset.pl is much faster too, it outputs the whole gl_hookset_defs.h
file and doesn't do multiple searches over the whole set of headers in
official/ for each function.
* When a compatibility context is created (via the old CreateContext, or
via an appropriate CreateContextAttribs call), we can still do the vendor
checks but we want to make sure we perform them again if we ever create a
core profile context. Note that actually *using* a compatibility context
isn't supported at the moment, but this won't explicitly break that.
* This lets us detect if the FBO/VAO behaviour is different from the main
spec, and so we won't miss deletes or other events if the context is
different since we'll treat them as shared like any other object.