Repository navigation
Diagnose non-bool SV_CullPrimitive mesh outputs in Sema - #9073
Abir Deol (apollo-2006) wants to merge 7 commits into
Conversation
The DXIL path rejects a non-bool SV_CullPrimitive with "SV_CullPrimitive must be bool.", but the SPIR-V backend passed the declared type through to the CullPrimitiveEXT builtin, so spirv-val failed with VUID-CullPrimitiveEXT-CullPrimitiveEXT-07036 and DXC asked the user to file a bug. Emit an error for a non-bool SV_CullPrimitive, and make meshshading.ext.triangle.mesh.hlsl declare it as bool. That test only passed with an int because it runs with -fcgl.
|
Azure Pipelines: There may be pipelines that require an authorized user to comment /azp run to run. |
There was a problem hiding this comment.
🟡 Changes recommended
The new check rejects valid scalar-equivalent bool1 and bool1x1 declarations that already lower to SPIR-V boolean scalars.
1 open issue
What changed in this PR
This PR adds an early SPIR-V diagnostic for non-boolean SV_CullPrimitive declarations, replacing a fatal validation failure with a normal compiler error. The related NV mesh-shader limitations remain outside its scope.
Changes:
- Validate the semantic’s element type before stage-specific handling.
- Add a negative regression test and correct the existing mesh test to use
bool. - Document the behavior change in the upcoming release notes.
| File | Description |
|---|---|
| tools/clang/test/CodeGenSPIRV/meshshading.ext.triangle.mesh.hlsl | Use boolean cull values and update SPIR-V checks. |
| tools/clang/test/CodeGenSPIRV/meshshading.ext.cullprimitive.non-bool.hlsl | Test the diagnostic for a uint cull declaration. |
| tools/clang/lib/SPIRV/DeclResultIdMapper.cpp | Check SV_CullPrimitive types before creating stage variables. |
| docs/ReleaseNotes.md | Document the new diagnostic. |
Review effort: Balanced
|
/azp run |
|
Azure Pipelines: Successfully started running 1 pipeline(s). |
| int layer : SV_RenderTargetArrayIndex; // -> Builtin Layer | ||
| int vpIdx : SV_ViewportArrayIndex; // -> Builtin ViewportIndex | ||
| int cullPrim : SV_CullPrimitive; // -> BUiltin CullPrimitiveEXT | ||
| bool cullPrim : SV_CullPrimitive; // -> BUiltin CullPrimitiveEXT |
There was a problem hiding this comment.
super nit:
| bool cullPrim : SV_CullPrimitive; // -> BUiltin CullPrimitiveEXT | |
| bool cullPrim : SV_CullPrimitive; // -> Builtin CullPrimitiveEXT |
| case hlsl::Semantic::Kind::CullPrimitive: { | ||
| QualType elemType = type; | ||
| while (const auto *arrayType = astContext.getAsConstantArrayType(elemType)) | ||
| elemType = arrayType->getElementType(); |
There was a problem hiding this comment.
I tried this code on aggregate types, and it looks like it doesn't quite handle that case.
From what I see, this fails to catch bool cull[2]: DXIL gives the error "rows for system value semantic SV_CullPrimitive must be 1" meanwhile SPIR-V gives "invalid SPIR-V, please file a bug"
If you could fix this and add a test, that be great.
| // be used as MSOut. | ||
| case hlsl::Semantic::Kind::CullPrimitive: { | ||
| QualType elemType = type; | ||
| while (const auto *arrayType = astContext.getAsConstantArrayType(elemType)) |
There was a problem hiding this comment.
The bool check should apply only to MSPOut, I'll make a longer explanation below
|
One interesting side effect of the current implementation is that it rejects Per However, the SPIRV backend doesn't implement this So, the 2 options are to mirror DXIL's replacement with constant Suffice to say though Abir Deol (@apollo-2006), if you could just keep the bool check to only apply to |
DXIL replaces SV_CullPrimitive on pixel shader inputs with a constant 0, so only MSPOut has to be bool. Check the type before the per-primitive array is added, so a bool[2] is rejected like DXIL does, and accept bool1 and bool1x1.
|
Thanks a lot for this (and for the PSIn explanation, that cleared up what I was missing). Here's what changed:
The mesh output cases match DXIL now, and tests and clang-format are clean. Thanks again for making it so easy to fix lol |
There was a problem hiding this comment.
🟢 Approval recommended
No active review issues are reported for the change that replaces fatal validation failures for invalid SV_CullPrimitive types with normal compiler errors.
No open issues 🎉
1 resolved since last review
Review effort: Balanced
|
Great! If you could add a |
Agreed. I would mirror DXIL and replace it with |
Diego Novillo (dnovillo)
left a comment
There was a problem hiding this comment.
Thanks for this fix. I agree with Jonathan Zakharov (@jzakharovnv) about negative tests for bool2.
Chris B (@llvm-beanz) or Gregory Roth (@pow2clk) or Damyan Pepper (@damyanp) could you please approve the CI bot? We still don't have maintainer access to trigger those. Thanks.
| if (stageVarData.semantic->getKind() == hlsl::Semantic::Kind::CullPrimitive && | ||
| stageVarData.sigPoint->GetKind() == hlsl::SigPoint::Kind::MSPOut) { | ||
| QualType scalarType; | ||
| if (!isScalarType(stageVarData.type, &scalarType) || | ||
| !scalarType->isBooleanType()) { | ||
| emitError("semantic CullPrimitive must be a bool scalar", | ||
| stageVarData.semantic->loc); | ||
| return nullptr; | ||
| } | ||
| } |
There was a problem hiding this comment.
nit: Move this to validateShaderStageVarType? Next to SV_InnerCoverage so we do semantic type checks in one place.
…arType Keeps the semantic type checks together, next to SV_InnerCoverage. Adds a bool2 negative test.
|
Moved the check into |
|
/azp run |
|
Azure Pipelines: Successfully started running 1 pipeline(s). |
Gregory Roth (pow2clk)
left a comment
There was a problem hiding this comment.
Hi Abir Deol (@apollo-2006)! I'm afraid I have a rather drastic alternative approach to suggest. While DXC often violates this, there are a lot of advantages to producing errors in Sema. I looked at the way DXIL errors for this and it actually isn't caught until validation, which is far from ideal.
If the error were produced in Sema, it would produce a common error for both DXIL and SPIR-V. I had Claude work up a quick change with a detailed description of how I envisioned the solution: https://github.com/pow2clk/DirectXShaderCompiler/tree/boolcullprim. You are free to take as much or as little of that commit into your change. If you do, please move your excellent tests for expected failures to the SemaHLSL subdirectory with appropriate changes to convert them to validation tests.
The branch: https://github.com/pow2clk/DirectXShaderCompiler/tree/boolcullprim
The commit: pow2clk@1098f70
Note that the test included is in the wrong place. It does demonstrate how you might use different entry point values to consolidate some of your tests though.
Move the check from the SPIR-V backend to Sema so DXIL and SPIR-V give the same error. DXIL only caught it at validation before. Only mesh shader primitive outputs are checked, bool1 and bool1x1 still count as scalar bools, and pixel shader inputs are left alone since DXIL replaces them with 0. The error tests move to SemaHLSL. Co-authored-by: Greg Roth <groth@nvidia.com>
# Conflicts: # docs/ReleaseNotes.md
Head branch was pushed to by a user without write access
|
Thanks, this is way cleaner than doing it per backend. Moved the check into Sema (DXIL and SPIR-V now give the same error) and kept your diagnostic, with you as co-author. Two small differences from your commit:
Error tests are now one |
Look through base classes, check a semantic declared directly on the primitives parameter, and stop at a semantic on an enclosing field or parameter since it overrides the ones inside.
There was a problem hiding this comment.
🟡 Changes recommended
SV_CullPrimitive validation rejects valid struct-wrapped boolean outputs because it checks record types instead of propagating the effective semantic and validating scalar-bool leaves.
1 open issue
3 resolved since last review
Review effort: Balanced
| bool IsScalarBool = | ||
| hlsl::IsHLSLVecMatType(ElemTy) | ||
| ? hlsl::GetElementCount(ElemTy) == 1 && | ||
| hlsl::GetElementTypeOrType(ElemTy)->isBooleanType() | ||
| : ElemTy->isBooleanType(); |

A non-bool
SV_CullPrimitiveon a mesh shader primitive output used to crash SPIR-V codegen with the "please file a bug report" error. DXIL only caught it at validation. It's now a Sema error for both:Following Gregory Roth (@pow2clk)'s suggestion, the check runs in
DiagnoseMeshEntryonout primitivesparams (nested structs and arrays included).bool1andbool1x1count as scalar bools, and pixel shader inputs are left alone since DXIL replaces them with 0.Tests:
SemaHLSL/cullprimitive-type.hlslcovers the rejected and accepted types (fails without the change)meshshading.ext.cullprimitive.bool1.hlslchecks thatbool1still lowers to the builtinmeshshading.ext.triangle.mesh.hlslusedint(it only passed because-fcglskips validation), so it'sboolnowHappy to change anything :)