From 46d79943845ba2ee5d739b8ef4aecdfded3c0d33 Mon Sep 17 00:00:00 2001 From: Chris B Date: Fri, 6 Nov 2026 15:15:29 -0600 Subject: [PATCH] [dxilconv] Allow patch indexing by control pointid @HansKristian-Work reported a crash in dxilconv, which was root caused to a case where InputPatch objects are indexed directly by a control point id. FXC generally doesn't generate this code pattern (it instead stores to a local temporary then uses the temporary), but this pattern doesn't seem to be illegal in the DX 11 spec. The fix here is to handle SV_OutputControlPointID as an input register to DXIL operations. This is done by adding it to `DxbcConverter::LoadOperandIndexRelative`. The test case here is hand-modified dxasm because FXC doesn't readily reproduce this. --- docs/ReleaseNotes.md | 2 + .../lib/DxbcConverter/DxbcConverter.cpp | 10 ++- .../dxbc2dxil-asm/hull-layer-viewport.asm | 63 ++++++++++++++++++ .../dxbc2dxil-asm/hull-layer-viewport.dxbc | Bin 0 -> 896 bytes 4 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 projects/dxilconv/test/dxbc2dxil-asm/hull-layer-viewport.asm create mode 100644 projects/dxilconv/test/dxbc2dxil-asm/hull-layer-viewport.dxbc diff --git a/docs/ReleaseNotes.md b/docs/ReleaseNotes.md index a84fefc05af..d5cdd69843e 100644 --- a/docs/ReleaseNotes.md +++ b/docs/ReleaseNotes.md @@ -89,6 +89,8 @@ line upon naming the release. Refer to previous for appropriate section names. #### Bug Fixes +- Fixed a DXBC-to-DXIL conversion crash when hull shaders index control points + directly with `SV_OutputControlPointID`. - Improved compiler performance by reducing excessive memory-dependence scans during GVN and repeated vector-elimination work. - Fixed GVN load forwarding generating unsupported integer types when optimizing diff --git a/projects/dxilconv/lib/DxbcConverter/DxbcConverter.cpp b/projects/dxilconv/lib/DxbcConverter/DxbcConverter.cpp index b668feb4d98..35e176f34f9 100644 --- a/projects/dxilconv/lib/DxbcConverter/DxbcConverter.cpp +++ b/projects/dxilconv/lib/DxbcConverter/DxbcConverter.cpp @@ -7632,6 +7632,14 @@ Value *DxbcConverter::LoadOperandIndexRelative( Value *pValue = nullptr; switch (OpIndex.m_RelRegType) { + case D3D11_SB_OPERAND_TYPE_OUTPUT_CONTROL_POINT_ID: { + OP::OpCode OpCode = OP::OpCode::OutputControlPointID; + Function *F = m_pOP->GetOpFunc(OpCode, Type::getInt32Ty(m_Ctx)); + Value *Args[] = {m_pOP->GetU32Const((unsigned)OpCode)}; + pValue = m_pBuilder->CreateCall(F, Args); + break; + } + case D3D10_SB_OPERAND_TYPE_TEMP: { unsigned Reg = OpIndex.m_RelIndex; unsigned Comp = OpIndex.m_ComponentName; @@ -7667,7 +7675,7 @@ Value *DxbcConverter::LoadOperandIndexRelative( } default: - DXASSERT_DXBC(false); + IFT(DXC_E_INCORRECT_DXBC); } return pValue; diff --git a/projects/dxilconv/test/dxbc2dxil-asm/hull-layer-viewport.asm b/projects/dxilconv/test/dxbc2dxil-asm/hull-layer-viewport.asm new file mode 100644 index 00000000000..4bfa58104d5 --- /dev/null +++ b/projects/dxilconv/test/dxbc2dxil-asm/hull-layer-viewport.asm @@ -0,0 +1,63 @@ +/*// RUN: %testasm %s /Fo %t.dxbc*/ +// RUN: %dxbc2dxil %t.dxbc /emit-llvm | %FileCheck %s + +// Reproduces the hull shader conversion crash reported in +// https://github.com/HansKristian-Work/vkd3d-proton/pull/3462. +// The accompanying DXBC is extracted from hs_layer_viewport_code_dxbc at +// commit 50c07246e6cf2d7d00e68a2a0adcb986e8d57f21; this is its disassembly. +// FXC cannot assemble Shader Model 5 text. Recompiling the original HLSL with +// FXC removes the identity control-point phase or indexes through a temporary, +// so it does not preserve the direct vOutputControlPointID indexing below. +// Direct control-point ID indexing must lower to dx.op.outputControlPointID +// rather than leaving null vertex-index operands in the generated load calls. + +// Input and output signatures: +// SV_Position 0 xyzw register 0 float +// SV_RenderTargetArrayIndex 0 x register 1 uint +// SV_ViewportArrayIndex 0 y register 1 uint +// Patch constant signature: +// SV_TessFactor 0 x register 0 float (TRIEDGE) +// SV_TessFactor 1 x register 1 float (TRIEDGE) +// SV_TessFactor 2 x register 2 float (TRIEDGE) +// SV_InsideTessFactor 0 x register 3 float (TRIINT) + +// CHECK-LABEL: define void @main() +// CHECK: %[[ID:[0-9]+]] = call i32 @dx.op.outputControlPointID.i32(i32 107) +// CHECK-DAG: call float @dx.op.loadInput.f32(i32 4, i32 0, i32 0, i8 0, i32 %[[ID]]) +// CHECK-DAG: call float @dx.op.loadInput.f32(i32 4, i32 0, i32 0, i8 1, i32 %[[ID]]) +// CHECK-DAG: call float @dx.op.loadInput.f32(i32 4, i32 0, i32 0, i8 2, i32 %[[ID]]) +// CHECK-DAG: call float @dx.op.loadInput.f32(i32 4, i32 0, i32 0, i8 3, i32 %[[ID]]) +// CHECK: %[[LAYERID:[0-9]+]] = call i32 @dx.op.outputControlPointID.i32(i32 107) +// CHECK: call i32 @dx.op.loadInput.i32(i32 4, i32 1, i32 0, i8 0, i32 %[[LAYERID]]) +// CHECK: %[[VIEWPORTID:[0-9]+]] = call i32 @dx.op.outputControlPointID.i32(i32 107) +// CHECK: call i32 @dx.op.loadInput.i32(i32 4, i32 2, i32 0, i8 0, i32 %[[VIEWPORTID]]) + +hs_5_0 +hs_decls +dcl_input_control_point_count 3 +dcl_output_control_point_count 3 +dcl_tessellator_domain domain_tri +dcl_tessellator_partitioning partitioning_integer +dcl_tessellator_output_primitive output_triangle_ccw +hs_control_point_phase +dcl_output o0.xyzw +dcl_output o1.x +dcl_output o1.y +dcl_input v[3][0].xyzw +dcl_input v[3][1].x +dcl_input v[3][1].y +dcl_input vOutputControlPointID +mov o0.xyzw, v[vOutputControlPointID0.x + 0][0].xyzw +mov o1.x, v[vOutputControlPointID0.x + 0][1].xxxx +mov o1.y, v[vOutputControlPointID0.x + 0][1].yyyy +ret +hs_fork_phase +dcl_output_siv o0.x, finalTriUeq0EdgeTessFactor +dcl_output_siv o1.x, finalTriVeq0EdgeTessFactor +dcl_output_siv o2.x, finalTriWeq0EdgeTessFactor +dcl_output_siv o3.x, finalTriInsideTessFactor +mov o0.x, l(1.000000) +mov o1.x, l(1.000000) +mov o2.x, l(1.000000) +mov o3.x, l(1.000000) +ret diff --git a/projects/dxilconv/test/dxbc2dxil-asm/hull-layer-viewport.dxbc b/projects/dxilconv/test/dxbc2dxil-asm/hull-layer-viewport.dxbc new file mode 100644 index 0000000000000000000000000000000000000000..cd73bcd96d098d3ab5456ad1350554b3c23a42c0 GIT binary patch literal 896 zcmbtSJx{_=6ul3{5EG;#8Ye^e1x}9m0RdUGp@e8+fM5Bo>xqbJXci*|Ur_JtdWu9K%)7_=n$KJ`?YgBzSm56kvM5eK? zBAyY4AQK^xf|1|31jeyM5ITa3cgS(YVj>5F)YIUZ7kIRNJ{)k^L(nzK72S5NmSs1X z7tKb^bV^mHZnicZr+QuhZcDF+v$AELo!ZVgzx$WD(Cgc|=6;wf`v1A~jFEppUwTQu zjuBjt9{Q#H{`4r|J-@(TfP+0lo;mC9uyY~xbm%>K_){`nH&;Ds+0MYP-*BPfS~YW| z%Gk~pYZyR>@;-E%kiJ?L)kR!uqHZFhZj+)M@Fv>#lNzc-n8%TGcIGKRui*9jT5|Zl z#Bm?9mN+$zLkd6Kn#fF`om;sVa$MwtJ~P^Y=Lz|sXL<39Ph(COQDw^TV0xQCKtCMZR~sOtvmS8NnB=@~HBsk%C!gb7pBAKmaR2}S literal 0 HcmV?d00001