Some work for shader debugging is identical to setting up the quad
overlay, so I've moved that logic to their own functions.
Some portions of creating a global shader debug state, and the
entirety of the initial shader debug state were agnostic of D3D API,
so they now exist in DXBC code.
* We already handle the case where e.g. D3D12_RENDER_TARGET_VIEW_DESC is NULL
and we need to substitute in a typed descriptor for backbuffers. We didn't
handle the case where
* Most of the interfaces are not supported - protected sessions, raytracing,
etc.
* We also split apart the 1/2/3/4 wrapped implementations to avoid uber files.
* Split up old uber-cbuffers used for unrelated shaders into shader-specific
cbuffers (DebugPixelCBufferData -> TexDisplayPSCBuffer / CheckerboardCBuffer /
MeshPixelCBuffer).
* Split up HLSL files so not everything is lumped into 'debugdisplay.hlsl' but
has separate files as appropriate.
* Use #include in GLSL and HLSL to better organise shader code together rather
than relying on lumping files together on the C++ side.
* Renamed files like 'debugcbuffers.h' to 'hlsl_cbuffers.h'.
* Trimmed out some extensions/cruft that isn't needed in the GLSL side since we
no longer use separable shaders.
* Combine some shaders like Outline/Checkerboard that were similar into central
place.
* On D3D the implementation was severely complicated by two parallel paths - one
that 'flattened' vec4s out into easy-to-consume format for debugging. Instead
we do this as a post-process transformation now in the debugging itself.
* Similarly D3D's implementation used DXBC data directly to fetch data, when all
of the information needed is in the ShaderConstant arrays and used by Vulkan.
This allows us to share the implementation.
* Only GL still needs its own implementation since it needs to query the API for
offsets etc as it can change unreliably and can't easily produce a standard
reflection data. We do share the 'read from buffer data' implementation
though.
* We also pick the output pixel in the CBuffer_Zoo tests to ensure the API
agrees with our interpretation of the data.
* Follow-up commit will tidy D3D cbuffer code that needs it.
* Instead of baking these into the overlay texture and trying to decode them
afterwards, we instead write a grayscale 16F value into the overlay texture,
and add a special decode display mode that will use the heatmap and bucketing
provided.
* This means that saving these overlay textures now saves grayscale. When saving
to an 8-bit format, we remap to 0-255 so that greater than 1.0 values are
mapped lower.
* The problem with storing resource pointers in descriptors is that it can be
invalidated without detection - a kind of A-B-A problem - if the resource is
deleted and then another resource is allocated with the same pointer.
* Descriptor creation in D3D12 is extremely complex and there are many ways a
resource could become incompatible with the descriptor metadata struct.
Detecting all possible ways a new resource could be incompatible is not
feasible.
* As a solution, we store the ResourceId which we know is immutable, serialise
via the pointer, and keep the live ResourceId on replay. If the resource was
deleted, the serialisation will fail because we look up the pointer at the
point of serialise, and a deleted resource will end up being NULL.
* To try and abstract this away and avoid potential confusion with the
ResourceIds, we make the descriptor contents private and provide accessors.
* For Clear*View and OMSetRenderTargetViews, the CPU descriptor handles
used are read immediately, the heap can be modified or even deleted
after the call.
* So we save the contents of the descriptor, ignore the heap, and then
fill a temporary heap with the descriptor whenever it's needed.
* In many cases (particularly on D3D11/D3D12) the replay would simply
forward functions as-is to the debug manager for implementation. This
meant that change any of those function signatures required more
tedious copy-pasting than was necessary, and didn't make much sense.
* Now the replay class is responsible for implementing all the
functionality and owns any debug-only API resources, but can still use
the debug manager for any indirect utility functions like caching,
etc.
* The API resources are better organised by task in the replay class
rather than being all over the place.
* Finally on vulkan, added some helper functions to reduce the
boilerplate involved in initialising objects.
* We track the progress through making a capture as well as the progress
we already tracked loading a capture.
* Also incidentally fix a copy-paste bug that was calculating the wrong
progress for loading captures by applying FileInitialRead instead of
FrameEventsRead for the frame replay.
* We enforce a naming scheme more strongly - types, member functions,
and enum values must be UpperCaseCamel, and member variables must be
lowerCaseCamel. No underscores allowed.
* eventId not eventID or EID, and Id preferred to ID in general. Also
for resourceId.
* Removed some lingering hungarian m_Foo naming.
* Some pipeline state structs that are almost identical between the
different APIs are pulled out into common structs. Where something
doesn't make sense (e.g. viewport enable for vulkan) it will just be
set to a sensible default (in that case always true).
* Changed scissors to be x/y & width/height instead of sometimes
left/top/right/bottom
* Abbreviations are discouraged, e.g. operation not op, function not
func.
* Previously we'd cache a copy of each command buffer at load time, and
submit it any time we're not partially re-recording. This has a couple
of drawbacks though:
- Technically we do some things that invalidate those command buffers,
like updating descriptor sets (with initial state application) and
so for 100% correctness we'd need to re-record.
- It also means that any edits we apply, like modified shaders, don't
properly apply to the whole frame, they only apply to whichever
command buffer is currently being partially recorded.
* We refactor out the 're-record all commands' behaviour previously
reserved just for applying GPU counters, and use that for re-recording
any command buffers that are wholly or partially submitted. Note that
it's still true that only one primary and one secondary at most are
actually *partially* re-recorded. The others are re-recorded in their
entirety.
* Reported by Coverity Scan. In all cases, should not be a problem, but
with an upcast happening anyway we might as well ensure calculation
happens at a higher precision.
* For now, resource replacement implicitly means shader edits, but other
replacements could also affect the results of PostVS (e.g. buffer or
state changes). Trying to capture all this state in the cache key is
not very useful.
* The PostVS cache will be re-filled immediately after, as any
replacement does a force-refresh of the current event.
* Note that while this is public and uses std::string, because it's a
template with specialisations in a .inl the string never crosses a
module boundary - each including module has its own implementation.
* This will be used as part of the upcoming serialisation refactor.
* Some POD structs are still given ToStr implementations as we haven't
yet switched over the serialisation system to expect all structs to
have serialise functions.
* For the most part the interface is stl-compatible, but we have a few
little changes of our own for convenience.
* This class is still needed after deleting the C# UI, because we don't
want to pass C++ stl structs over module boundaries and possibly run
into hard to diagnose incompatibilities.