* Previously we iterated over each bind, and found the matching resources. Now
we iterate over resources and find the matching bind. This matters when there
are multiple overlapping binds so they are only found once (we don't
disambguate which bind was used, as we don't elsewhere currently)
* There seems to be a significant slowdown when using real swapchains, both for
creation and display. Since thumbnails don't update often (only on event
change, or if the panel is resized which is not a regular occurence)
counterintuitively it's better to render and readback the image offscreen and
re-upload it on the CPU.
* The principle here is that on D3D12 it's common to have huge descriptor heaps
in which only a handful of descriptors are changed. By caching the expanded
D3D12Pipe::View results from these unchanging descriptors we don't have to do
that over and over. Any descriptors written in the captured frame may have
different contents depending on where we've replayed up to, so we don't cache
them to keep things simple rather than invalidating the cache.
* We defer destruction of the view objects created until the next flush. In
future this could be smarter about associating resource destructions with a
submitted batch and deferring further until a fence is signalled to avoid
synchronisation.
* UE5 at least currently (as of this commit) re-signs D3D12Core.dll by Epic.
Rather than failing to load all such captures, only fail if the capture is
marked as downloaded since local captures should be implicitly trusted.
Per the Vulkan Spec: "If pPhysicalDeviceCount is less than the number of physical devices available, at most pPhysicalDeviceCount structures will be written, and VK_INCOMPLETE will be returned instead of VK_SUCCESS, to indicate that not all the available physical devices were returned."
* E.g. if a draw is off-screen, the PS might not be invoked. If that's the only
place we expect to see dynamic resources accessed we won't get our valid
marker but the results should still be considered correct.
* The stride these buffers are accessed with in the shader is not guaranteed to
be 4 bytes when used untyped (e.g. structured buffers) so we can't assume it
and bake the offset into element count. Instead fetch data starting at that
offset and list a first element of 0.
* In principle the fake SV_ inputs should be able to come in any order, but it
seems if SV_IsFrontFace is last it can get undefined/wrong results (e.g.
returning 1 when front-face culling is enabled or vice-versa). Moving it to
the first seems to fix the issue, and at least shouldn't make anything any
worse.
* This is mostly relevant for D3D12, where the desc comes from the user and so
may not be normalised and contain values like 0xffffffff to indicate 'all
mips' or 'all slices' in the view.
* Previously we would only process ranges we were interested in when looking for
a descriptor, but we need to process all ranges in a table to properly track
the offset for APPEND.
* This works around an obtuse GL requirement that explicit locations on one side
will cause a break in compatibility with the other side, even if dropping the
location would work otherwise.
* Doing this lets us more consistently reference the color attachments in the
correct indices and makes it easier to match for blends. It also allows the
user to show unused/empty attachments