[HLSL] Require FP8 conversion support in the LinAlg convert gate - #8868
Conversation
The LinAlg convert tests gate on a capability query and classify every outcome as CapabilityGated, so a device that reports no FP8 support skips rather than fails. That is wrong for FP8: proposal 0035 "Emulating FP" states that "the DirectX API specification requires that all implementations support both FP8 formats for matrices, bias, and input vectors", and permits emulation where the hardware lacks native support. The D3D12 runtime feature document agrees - the "Optional" entries in the Tier 1 vector-matrix table are the Native column only, L427 makes the emulation itself required, and the version history records "FP8 is required for tier 1". An implementation that cannot convert to FP8 is non-conformant, so the suite must report it. There is no capability query for the convert operation; the operation type enum covers matrix construction, the three multiply scopes, outer product and atomic accumulate store. The gate therefore proxies through THREAD_VECTOR_MATRIX_MULTIPLY, asking whether any supported configuration advertises FP8 as its VectorInputType. That proxy is sound precisely because 0035 makes FP8-as-input-vector mandatory. queryConvertSupport previously collapsed three distinct outcomes into a single unsupported answer: no linear algebra tier at all, an unsupported source component type, and an unsupported destination. Only the last is a conformance failure. The tier and source results are now reported separately so the caller can downgrade to CapabilityGated for the first two, mirroring matVecMulApplicable. Without that downgrade this change would fail devices that have no linear algebra, or that lack native 16-bit shader operations and so cannot perform an F16 source conversion at all - both strictly worse than the gap being closed. The requirement is passed at the call site, matching how the rest of the file declares mandatory cases. Only the two FP8 destination gates become Mandatory; the I16, I32 and F16 destinations keep their existing CapabilityGated classification, so their behaviour is unchanged. Validation is a per-test differential on preview WARP: 78/76/0/2 with zero per-test movement against the parent commit. That is the expected result and it is not evidence the change works - WARP enumerates VectorInputType=20 and 21, so it never reaches the classification. The evidence is a discriminating control that forces the FP8 destination query to report unsupported: this commit fails both FP8 conversion tests, while the parent skips them. Two further controls confirm the downgrades, with an absent tier and absent native 16-bit support each still skipping. No IHV driver in the loop reports FP8 vector input as unsupported, so the mandatory path is exercised only by forced control on WARP and never by a real driver refusing. This builds on the FP8 datatype mapping fix; without it the gate asserts in toLinAlgDataType before the classification is reached. Assisted-by: GitHub Copilot Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 83725f5d-8e98-4c1d-91ee-ad47629e007b
There was a problem hiding this comment.
Pull request overview
Updates LinAlg conversion applicability so Tier 1 devices must advertise FP8 destinations while unsupported tiers or source types still skip.
Changes:
- Exposes tier and source support from conversion queries.
- Adds configurable mandatory versus capability-gated checks.
- Marks both FP8 conversion destinations mandatory.
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Joshua Batista (bob80905)
left a comment
There was a problem hiding this comment.
LGTM, though for consistency it would be nice if queryTierSupport could set the TierSupported bool itself like how queryConvertSourceSupport sets SourceSupported.
Alex Sepkowski (alsepkow)
left a comment
There was a problem hiding this comment.
LGTM. Just some naming/cleanliness nits
| // A device without linear algebra is outside the Tier 1 requirements, and a | ||
| // mandatory destination is still unreachable when the source type itself is | ||
| // unsupported, so both skip rather than failing. | ||
| const bool QueryAnswered = SUCCEEDED(QueryResult); | ||
| const bool NoLinearAlgebra = QueryAnswered && !TierSupported; | ||
| const bool UnsupportedSource = QueryAnswered && !SourceSupported; | ||
|
|
||
| linalg_test::CapabilityRequirement Effective = Requirement; | ||
| if (NoLinearAlgebra || UnsupportedSource) | ||
| Effective = linalg_test::CapabilityRequirement::CapabilityGated; | ||
|
|
||
| return applyApplicability( | ||
| linalg_test::classifyApplicability(QueryResult, Supported, Effective), | ||
| CaseName); |
There was a problem hiding this comment.
Nit: simplify
| // A device without linear algebra is outside the Tier 1 requirements, and a | |
| // mandatory destination is still unreachable when the source type itself is | |
| // unsupported, so both skip rather than failing. | |
| const bool QueryAnswered = SUCCEEDED(QueryResult); | |
| const bool NoLinearAlgebra = QueryAnswered && !TierSupported; | |
| const bool UnsupportedSource = QueryAnswered && !SourceSupported; | |
| linalg_test::CapabilityRequirement Effective = Requirement; | |
| if (NoLinearAlgebra || UnsupportedSource) | |
| Effective = linalg_test::CapabilityRequirement::CapabilityGated; | |
| return applyApplicability( | |
| linalg_test::classifyApplicability(QueryResult, Supported, Effective), | |
| CaseName); | |
| // A device without linear algebra is outside the Tier 1 requirements, and a | |
| // mandatory destination is unreachable when the source type is unsupported. | |
| // Only successfully queried missing prerequisites should downgrade to a skip. | |
| const bool MissingPrerequisite = | |
| SUCCEEDED(QueryResult) && (!TierSupported || !SourceSupported); | |
| const linalg_test::CapabilityRequirement Effective = | |
| MissingPrerequisite | |
| ? linalg_test::CapabilityRequirement::CapabilityGated | |
| : Requirement |
| bool &Supported) { | ||
| TierSupported = false; | ||
| SourceSupported = false; | ||
| Supported = false; |
There was a problem hiding this comment.
nit:
| Supported = false; | |
| DestinationSupported = false; |
| LPCWSTR CaseName) { | ||
| bool TierSupported = false; | ||
| bool SourceSupported = false; | ||
| bool Supported = false; |
There was a problem hiding this comment.
nit:
| bool Supported = false; | |
| bool DestinationSupported = false; |
| if (FAILED(HR) || !SourceSupported) | ||
| return HR; | ||
|
|
||
| HR = queryConvertDestinationEnumeration(Device, *DestinationType, Supported); |
There was a problem hiding this comment.
nit:
| HR = queryConvertDestinationEnumeration(Device, *DestinationType, DestinationSupported); |
| hlsl_test::LogCommentFmt( | ||
| L"Convert operation enumeration is unavailable; falling back to the " | ||
| L"granular vector-input query"); | ||
| HR = queryConvertDestinationGranular(Device, *DestinationType, Supported); |
There was a problem hiding this comment.
nit:
| HR = queryConvertDestinationGranular(Device, *DestinationType, DestinationSupported); |
| L"granular vector-input query"); | ||
| HR = queryConvertDestinationGranular(Device, *DestinationType, Supported); | ||
| } | ||
| if (SUCCEEDED(HR) && !Supported) |
There was a problem hiding this comment.
nit:
| if (SUCCEEDED(HR) && !DestinationSupported) |
| return false; | ||
| const HRESULT QueryResult = | ||
| queryConvertSupport(Device, SourceCompType, DestinationCompType, | ||
| TierSupported, SourceSupported, Supported); |
There was a problem hiding this comment.
nit:
| TierSupported, SourceSupported, Supported); | |
| TierSupported, SourceSupported, DestinationSupported); |
| Effective = linalg_test::CapabilityRequirement::CapabilityGated; | ||
|
|
||
| return applyApplicability( | ||
| linalg_test::classifyApplicability(QueryResult, Supported, Effective), |
There was a problem hiding this comment.
nit:
| linalg_test::classifyApplicability(QueryResult, Supported, Effective), | |
| linalg_test::classifyApplicability(QueryResult, DestinationSupported, Effective), |
| ComponentType SourceCompType, | ||
| ComponentType DestinationCompType, | ||
| bool &TierSupported, bool &SourceSupported, | ||
| bool &Supported) { |
There was a problem hiding this comment.
nit:
| bool &Supported) { | |
| bool &DestinationSupported) { |
FP8 conversion destinations were classified
CapabilityGated, but there is no capability query for the convert operation —D3D12_LINEAR_ALGEBRA_OPERATION_TYPEhas six values and none is convert, so the gate proxies throughTHREAD_VECTOR_MATRIX_MULTIPLY, and proposal 0035 requires every implementation to support both FP8 formats for matrices, bias and input vectors. This makes those destinationsMandatory, withTierSupportedandSourceSupportedout-params so a device advertising no LinAlg tier, or no native 16-bit shader ops, still skips rather than fails.Assisted-by: GitHub Copilot