* The current filter is preserved across runs even if it's not explicitly saved.
Saved filters are only updated with an explicit save - loading a filter then
making a change just cahnges the current scratch filter, it doesn't update the
saved filter until the user explicitly saves it.
* This is a little bit inconsistent because they are technically draws, but
they're only draws so they can include the trailing API events in a region.
* Think of it this way:
Imagine we instead made PopMarker just a normal API event (which is how we want to treat it) and instead inserted a second 'internal' draw at the end of each region to contain the popmarker. This internal draw would be hardcoded to never show up in filters no matter what - even with an empty include-all filter. But it contains the other API events so they can be selected individually and filtered in/out.
In this scenario it's functionally equivalent to just using the PopMarker as that 'internal' draw containing its own API event and making it fail all draw filters. The only difference is that users can manually filter in the PopMarker draw with flags if they want.
* We can't use the exact same interface because we want builtin filters to be
able to return specialised lambdas, but we at least register them by name.
This is helpful for ensuring the completion doesn't get out of sync, and we'll
use it next to provide function-specific completion
* Fake markers now need a real event ID. We don't want to have to remap all
events in a capture between UI and replay driver, so instead we assign non-
contiguous events above the normal range and expect the UI to handle it.
* These map more naturally to python tuples and are easier to wrap in and out.
* We also tidy up the FloatVecVal etc and standardise the members of
ShaderValue.
* We instead always have 3rdparty/ in the relevant include search paths and rely
on that. Each library still has its own unique base dir within 3rdparty to
clarify where the include is coming from.