With SM5.1 and D3D12, constant buffer arrays can be declared which
are treated as an array of resources on the shader side, and a simple
collection of descriptors on the D3D12 side. DXBCDebug::GlobalState
handles the bridge between these by storing each array resource as a
nested ShaderVariable struct. Accessing the data for instructions
traverses the structure similarly. The shader viewer handles nested
resources and displays them in the appropriate tree view. In the
pipeline viewer, descriptors for CB arrays now indicate the array
index and correctly handle buffer offsets for viewing.
* The ShaderDebugTrace now only sets up the initial state of an opaque
ShaderDebugger handle.
* This handle can then be passed to a new function - ContinueDebug - to
iteratively return N more states. The number of states is implementation
defined and may be a fixed number or it may run for a fixed time.
* The states themselves no longer contain a complete snapshot of all variables,
but instead only the changed variables for that iteration. The changes are
stored as before and after value to make it easier to step forwards and
backwards (only the ShaderDebugState is needed to move forward or backwards,
you don't have to search back for the last set value of a variable to 'undo' a
change).
* The shader viewer shouldn't handle specifics of D3D bytecode, instead it now
works generally with whatever the debug and source variables are.
* VarType::Unknown is used for D3D registers which are typeless.
* cbuffer and input registers no longer have any names elided into them, they
are 'raw' registers. The source mapping provides the information of where they
come from as best as possible.
* Since we're now using source-mapping for constants, fix some source mapping
issues with arrays, nested structs/arrays, and matrix major-ness.
* Moving away from 'registers' explicitly being stored, we now have a single
variable array where the shader representation is responsible for allocating
it.
* In DXBC we calculate the number of each type of mutable variable (temps,
indexable temps, and outputs) and assign slots linearly.
* We also update some naming - high-level variables aren't "locals" since they
could be globals too, and debugging variables aren't "registers" but simply
the variables we use for debugging which may be more complex than float4 for
other APIs.
* The local variable matching by string name is unnecessary for this change
but will be more useful in future after further refactors where there isn't
a single list of variables to index into at the upper level.
* This avoids having the UI need to do a scan and expecting to find
"instruction:" on the start of a line.
* We also move the callstack to be stored per-step, and not in the line info
mapping.
* This is primarily useful for HLSL on Vulkan, but could be used with any other
combination. If multiple tools can perform the conversion, the highest
priority one is used.
* Supported textures are decoded into standard format of YUVA, displayed
visually with Y in green, U in blue, V in red.
* A new texture display mode 'YUVA decode' has been added which does a default
full-range conversion from YUV to RGB.
* Custom shaders can be used to implement a custom decode matrix.
* Instead of just configuring SPIR-V disassemblers and picking only the first
one when we need to edit SPIR-V, we allow setting up any shader processor that
goes between two shader encodings.
* When editing, the default will still be to use embedded source, and then after
that the first tool that goes from the native shader format to a text format,
but the drop-down allows you to pick any of them.
* Similarly in the shader viewer you can configure the compilation options and
method, to choose the compiler you want to use. Embedded command line
parameters in the shader are automatically appended.
* This means e.g. the D3D11 back-end can accept DXBC directly if the UI can
provide it, or compile from HLSL as before.
* More importantly, the Vulkan back-end can take SPIR-V compiled from any
source, or compile from GLSL as before as a fall-back.
* Instead of having an N:N mapping of parts of variables to parts of registers,
instead we gather everything together under each variable and it has a list of
registers that comprise it.
* Any gaps are represented as undefined register mappings, for components that
aren't available in any register.