vkd3d-shader: Handle 16-bit minimum-precision in the DXIL parser instead of the backend.
Where the VSIR validator expects types to be of equal width, emitting 16-bit registers to represent minimum-precision registers can result in validation failure due to mixed widths. It is much simpler to handle these in the DXIL parser than to make the validator check the validity of mixed widths, and this also simplifies the implementation of native 16-bit support in backends.
This resolves validation failures reported in !1108 (in the one shader I tested from the collection).
The half_to_float()
and convert_raw_constant32()
functions are copied unmodified from the SPIR-V backend.
Merge request reports
Activity
I'm trying to sum up all my knowledge about 16-bit and minimum precision type to understand better what's going on. Please correct me where needed.
- Using a native 16-bit type (signed, unsigned or float) in VSIR implies that registers should be exactly 16 bit wide (or at least only 16 bit should be used) and operations are expected to behave following 16-bit semantics.
- Using a 32-bit type with a minimum precision annotation implies that operations are expected to happen using 32-bit semantics, but when the register is loaded and stored it is allowed to drop some bits, as long as at least 16 bit (or whatever is indicated by the minimum precision annotation) are retained. Presumably that's done to allow the implementation to use less memory and less bandwidth.
- The SPIR-V backend currently ignores minimum precision annotations. So minimum precision types are effectively treated as 32-bit types: this is correct, because minimum precision is understood as just a hint. Native 16-bit types are treated as their 32-bit counterpart too (and 16-bit constant registers and ICBs are converted in order to make everything work): this is instead wrong, in itself, because a shader has the right to rely on 16-bit semantics, and we're breaking this. However that's not currently an end-to-end problem because:
- D3DBC and TPF frontends never generate VSIR code with native 16-bit types, because they do not exist in D3DBC and TPF (the "half" type that exists in HLSL doesn't map to a 16-bit type, it always mean a usual 32-bit float anyway).
- The DXIL frontend currently only supports SM 6.0, while native 16-bit types where introduced in SM 6.2. For SM 6.0 (and indeed all SM 6.* if all 16-bit
VKD3DSGF_FORCE_NATIVE_LOW_PRECISION
is not specified, which corresponds to-enable-16bit-types
with DXC) all 16-bit types are implicitly understood as 32-bit with minimum precision, so in practice the SPIR-V backend behavior is correct.
If understand correctly, the proposed changes basically keep the current end-to-end behavior while redistributing responsibilities correctly between the frontend and backend.
- The DXIL frontend doesn't generate native 16-bit types any more, but always generate 32-bit types with minumum precision, which is allowed by our current SM support.
- The SPIR-V backend doesn't pretend any more to support native 16-bit types, but doesn't need anymore because we'd have no frontend anymore able to generate such VSIR code.
Correspondingly, the road map for supporting DXIL native 16-bit types would be (not necessarily in this chronological order):
- Add native 16-bit type support to the SPIR-V backend, that must map to proper native 16-bit SPIR-V types, and fail when they are not available. The SPIR-V backend still remains oblivious to minimum precision qualifiers, but that's allowed.
- Change the DXIL frontend so that it doesn't emit minimum precision types anymore when
VKD3DSGF_FORCE_NATIVE_LOW_PRECISION
is specified, but only emits native types.
Does all of this make sense?
For the record, beside reading the code, those pages were useful to understand the purported behavior for Microsoft formats:
10529 10637 10530 10638 dxil_block_destroy(&sm6->root_block); 10531 10639 10640 vsir_program_convert_min_precision(program); It guarantees we catch them all. It should be ok to handle it in
vkd3d_data_type_from_sm6_type()
, but then we would need to ensure the minimum precision flag is set anywhere a data type from that function is used in a register. A late pass seems like a simple and robust way to do it.Ideally the guarantee that we catch all of them should come from the fact that there is some helper every code path that creates a register goes through, and that is the place where uniform behavior can be ensured. A late pass also guarantees uniformity, but makes everything more indirect and more complicated to understand. To the code reader, that fact that a register is created in a way and than at some point is something else might look magical, and it might be a bit harder to spot where the transformation happened. Sometimes we have to resort to first generate invalid code and then fix it up, but we should do that as little as possible.
I think this MR is overall an improvement anyway, and I wouldn't delay it too much because other stuff depends on this, but if possible it would be nice to eventually handle this differently.
I tried this but I think it's too fragile, and a bit complicated. Also I added commits to handle indexable temps and TGSMs. These were still handled in the backend but should be done for completeness. I added a comment about why register fixups are done at the end:
Handling minimum-precision types during parsing would involve passing an additional parameter wherever a vsir_register is initialised, to allow a warning to be emitted if 16-bit types are used and native 16-bit is enabled, and to suppress conversion in the latter case when support is implemented. An additional complication is that the metadata refers to registers in the SSA value table, and converting these before we are done with metadata may have side effects which would make metadata handling fragile. Instead, we convert only registers used in the final instruction array.
added 6 commits
- 04ca642f - vkd3d-shader: Handle 16-bit minimum-precision registers in the DXIL parser instead of the backend.
- 9dedba40 - vkd3d-shader/dxil: Handle 16-bit minimum-precision immediate constant buffers...
- 210db126 - vkd3d-shader/dxil: Handle 16-bit minimum-precision indexable temp declarations...
- d813c840 - vkd3d-shader/dxil: Handle 16-bit minimum-precision TGSM declarations in the...
- 85182c51 - vkd3d-shader/dxil: Set the register minimum precision flag for I/O registers.
- bf986ad3 - vkd3d-shader/dxil: Emit a fixme if native 16-bit types are emitted as 32-bit.
Toggle commit listadded 6 commits
- 59c64d8d - vkd3d-shader/dxil: Handle 16-bit minimum-precision registers in the DXIL...
- 0653d3be - vkd3d-shader/dxil: Handle 16-bit minimum-precision immediate constant buffers...
- 8634c28d - vkd3d-shader/dxil: Handle 16-bit minimum-precision indexable temp declarations...
- 3b650c81 - vkd3d-shader/dxil: Handle 16-bit minimum-precision TGSM declarations in the...
- 10888bca - vkd3d-shader/dxil: Set the register minimum precision flag for I/O registers.
- 5e04427f - vkd3d-shader/dxil: Emit a fixme if native 16-bit types are emitted as 32-bit.
Toggle commit listadded 159 commits
-
5e04427f...cd249a47 - 153 commits from branch
wine:master
- b06e8e02 - vkd3d-shader/dxil: Handle 16-bit minimum-precision registers in the DXIL...
- 8a756314 - vkd3d-shader/dxil: Handle 16-bit minimum-precision immediate constant buffers...
- 42a501f5 - vkd3d-shader/dxil: Handle 16-bit minimum-precision indexable temp declarations...
- cc4b36f9 - vkd3d-shader/dxil: Handle 16-bit minimum-precision TGSM declarations in the...
- 1b37a877 - vkd3d-shader/dxil: Set the register minimum precision flag for I/O registers.
- 9dd5006b - vkd3d-shader/dxil: Emit a fixme if native 16-bit types are emitted as 32-bit.
Toggle commit list-
5e04427f...cd249a47 - 153 commits from branch
added 162 commits
-
9dd5006b...5eff8bf9 - 156 commits from branch
wine:master
- 11cf5c56 - vkd3d-shader/dxil: Handle 16-bit minimum-precision registers in the DXIL...
- 8101fc19 - vkd3d-shader/dxil: Handle 16-bit minimum-precision immediate constant buffers...
- e7b585cc - vkd3d-shader/dxil: Handle 16-bit minimum-precision indexable temp declarations...
- 7e289bd7 - vkd3d-shader/dxil: Handle 16-bit minimum-precision TGSM declarations in the...
- 7c7b59ba - vkd3d-shader/dxil: Set the register minimum precision flag for I/O registers.
- ed11db85 - vkd3d-shader/dxil: Emit a fixme if native 16-bit types are emitted as 32-bit.
Toggle commit list-
9dd5006b...5eff8bf9 - 156 commits from branch
added 386 commits
-
ed11db85...b60995b1 - 380 commits from branch
wine:master
- a2cc5ac9 - vkd3d-shader/dxil: Handle 16-bit minimum-precision registers in the DXIL...
- 4ba2cb07 - vkd3d-shader/dxil: Handle 16-bit minimum-precision immediate constant buffers...
- 2f656381 - vkd3d-shader/dxil: Handle 16-bit minimum-precision indexable temp declarations...
- 9783bdec - vkd3d-shader/dxil: Handle 16-bit minimum-precision TGSM declarations in the...
- 507b3da8 - vkd3d-shader/dxil: Set the register minimum precision flag for I/O registers.
- 0fdd6072 - vkd3d-shader/dxil: Emit a fixme if native 16-bit types are emitted as 32-bit.
Toggle commit list-
ed11db85...b60995b1 - 380 commits from branch
added 107 commits
-
0fdd6072...fe52e696 - 102 commits from branch
wine:master
- e6e65e63 - vkd3d-shader/ir: Handle 16-bit minimum-precision registers in an IR pass instead of in the backend.
- 1a0d84a9 - vkd3d-shader/ir: Handle 16-bit minimum-precision immediate constant buffers in...
- e933dcf7 - vkd3d-shader/ir: Handle 16-bit minimum-precision indexable temp declarations...
- cf05efef - vkd3d-shader/ir: Handle 16-bit minimum-precision TGSM declarations in an IR...
- 2b2a8f21 - vkd3d-shader/dxil: Set the register minimum precision flag for I/O registers.
Toggle commit list-
0fdd6072...fe52e696 - 102 commits from branch
added 5 commits
- 158da01e - vkd3d-shader/ir: Handle 16-bit minimum-precision registers in an IR pass instead of in the backend.
- 677e36f6 - vkd3d-shader/ir: Handle 16-bit minimum-precision immediate constant buffers in...
- 7855a7ab - vkd3d-shader/ir: Handle 16-bit minimum-precision indexable temp declarations...
- f5a33a9f - vkd3d-shader/ir: Handle 16-bit minimum-precision TGSM declarations in an IR...
- 7487d86c - vkd3d-shader/dxil: Set the register minimum precision flag for I/O registers.
Toggle commit listadded 5 commits
- 0dcf5343 - vkd3d-shader/ir: Handle 16-bit minimum-precision registers in an IR pass instead of in the backend.
- 57c6bfca - vkd3d-shader/ir: Handle 16-bit minimum-precision immediate constant buffers in...
- d033f008 - vkd3d-shader/ir: Handle 16-bit minimum-precision indexable temp declarations...
- b2a06686 - vkd3d-shader/ir: Handle 16-bit minimum-precision TGSM declarations in an IR...
- bde62fdb - vkd3d-shader/dxil: Set the register minimum precision flag for I/O registers.
Toggle commit list