Skip to content

Commit 3693755

Browse files
authored
PIX: Updates to shader debugging pass to support DXR hit groups/miss shaders (microsoft#5499)
Two main themes: -Add instrumentation to the DXR hit group and miss shader types -Return a bit more info to the caller (PIX) via output text
1 parent 786268e commit 3693755

File tree

5 files changed

+188
-49
lines changed

5 files changed

+188
-49
lines changed

lib/DxilPIXPasses/DxilAnnotateWithVirtualRegister.cpp

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,16 @@ void DxilAnnotateWithVirtualRegister::applyOptions(llvm::PassOptions O) {
107107

108108
char DxilAnnotateWithVirtualRegister::ID = 0;
109109

110+
static llvm::StringRef
111+
PrintableSubsetOfMangledFunctionName(llvm::StringRef mangled) {
112+
llvm::StringRef printableNameSubset = mangled;
113+
if (mangled.size() > 2 && mangled[0] == '\1' && mangled[1] == '?') {
114+
printableNameSubset =
115+
llvm::StringRef(mangled.data() + 2, mangled.size() - 2);
116+
}
117+
return printableNameSubset;
118+
}
119+
110120
bool DxilAnnotateWithVirtualRegister::runOnModule(llvm::Module &M) {
111121
Init(M);
112122
if (m_DM == nullptr) {
@@ -120,39 +130,37 @@ bool DxilAnnotateWithVirtualRegister::runOnModule(llvm::Module &M) {
120130
}
121131

122132
std::uint32_t InstNum = m_StartInstruction;
123-
std::map<llvm::StringRef, std::pair<int, int>> InstructionRangeByFunctionName;
124133

125134
auto instrumentableFunctions = PIXPassHelpers::GetAllInstrumentableFunctions(*m_DM);
126135

127136
for (auto * F : instrumentableFunctions) {
128-
auto &EndInstruction = InstructionRangeByFunctionName[F->getName()];
129-
EndInstruction.first = InstNum;
137+
int InstructionRangeStart = InstNum;
138+
int InstructionRangeEnd = InstNum;
130139
for (auto &block : F->getBasicBlockList()) {
131140
for (llvm::Instruction &I : block.getInstList()) {
132141
if (!llvm::isa<llvm::DbgDeclareInst>(&I)) {
133142
pix_dxil::PixDxilInstNum::AddMD(M.getContext(), &I, InstNum++);
134-
EndInstruction.second = InstNum;
143+
InstructionRangeEnd = InstNum;
135144
}
136145
}
137146
}
147+
if (OSOverride != nullptr) {
148+
auto shaderKind = PIXPassHelpers::GetFunctionShaderKind(*m_DM, F);
149+
std::string FunctioNamePlusKind =
150+
F->getName().str() + " " + hlsl::ShaderModel::GetKindName(shaderKind);
151+
*OSOverride << "InstructionRange: ";
152+
llvm::StringRef printableNameSubset =
153+
PrintableSubsetOfMangledFunctionName(FunctioNamePlusKind);
154+
*OSOverride << InstructionRangeStart << " " << InstructionRangeEnd << " "
155+
<< printableNameSubset << "\n";
156+
}
138157
}
139158

140159
if (OSOverride != nullptr) {
141160
// Print a set of strings of the exemplary form "InstructionCount: <n> <fnName>"
161+
if (m_DM->GetShaderModel()->GetKind() == hlsl::ShaderModel::Kind::Library)
162+
*OSOverride << "\nIsLibrary\n";
142163
*OSOverride << "\nInstructionCount:" << InstNum << "\n";
143-
for (auto const &fn : InstructionRangeByFunctionName) {
144-
*OSOverride << "InstructionRange: ";
145-
int skipOverLeadingUnprintableCharacters = 0;
146-
if (fn.first.size() > 2 && fn.first[0] == '\1' && fn.first[1] == '?') {
147-
skipOverLeadingUnprintableCharacters = 2;
148-
}
149-
*OSOverride << fn.second.first << " " << fn.second.second << " "
150-
<< (fn.first.str().c_str() +
151-
skipOverLeadingUnprintableCharacters)
152-
<< "\n";
153-
}
154-
155-
*OSOverride << "\nBegin - dxil values to virtual register mapping\n";
156164
}
157165

158166
for (auto * F : instrumentableFunctions) {
@@ -171,10 +179,6 @@ bool DxilAnnotateWithVirtualRegister::runOnModule(llvm::Module &M) {
171179
}
172180
}
173181

174-
if (OSOverride != nullptr) {
175-
*OSOverride << "\nEnd - dxil values to virtual register mapping\n";
176-
}
177-
178182
m_DM = nullptr;
179183
return m_uVReg > 0;
180184
}

lib/DxilPIXPasses/DxilDebugInstrumentation.cpp

Lines changed: 37 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -216,9 +216,9 @@ class DxilDebugInstrumentation : public ModulePass {
216216
uint64_t m_UAVSize = 1024 * 1024;
217217
struct PerFunctionValues
218218
{
219-
CallInst *UAVHandle;
220-
Constant *CounterOffset;
221-
Value *InvocationId;
219+
CallInst *UAVHandle = nullptr;
220+
Constant *CounterOffset = nullptr;
221+
Value *InvocationId = nullptr;
222222
// Together these two values allow branchless writing to the UAV. An
223223
// invocation of the shader is either of interest or not (e.g. it writes to
224224
// the pixel the user selected for debugging or it doesn't). If not of
@@ -227,11 +227,11 @@ class DxilDebugInstrumentation : public ModulePass {
227227
// will be written to the UAV at sequentially increasing offsets.
228228
// This value will either be one or zero (one if the invocation is of
229229
// interest, zero otherwise)
230-
Value *OffsetMultiplicand;
230+
Value *OffsetMultiplicand = nullptr;
231231
// This will either be zero (if the invocation is of interest) or
232232
// (UAVSize)-(SmallValue) if not.
233-
Value *OffsetAddend;
234-
Constant *OffsetMask;
233+
Value *OffsetAddend = nullptr;
234+
Constant *OffsetMask = nullptr;
235235
Value *SelectionCriterion = nullptr;
236236
Value *CurrentIndex = nullptr;
237237
};
@@ -341,10 +341,10 @@ DxilDebugInstrumentation::SystemValueIndices
341341
case DXIL::ShaderKind::Mesh:
342342
case DXIL::ShaderKind::Compute:
343343
case DXIL::ShaderKind::RayGeneration:
344-
//case DXIL::ShaderKind::Intersection:
345-
//case DXIL::ShaderKind::AnyHit:
346-
//case DXIL::ShaderKind::ClosestHit:
347-
//case DXIL::ShaderKind::Miss:
344+
case DXIL::ShaderKind::Intersection:
345+
case DXIL::ShaderKind::AnyHit:
346+
case DXIL::ShaderKind::ClosestHit:
347+
case DXIL::ShaderKind::Miss:
348348
// Dispatch* thread Id is not in the input signature
349349
break;
350350
case DXIL::ShaderKind::Vertex: {
@@ -448,9 +448,11 @@ Value *DxilDebugInstrumentation::addRaygenShaderProlog(BuilderContext &BC) {
448448
auto CompareToX = BC.Builder.CreateICmpEQ(
449449
RayX, BC.HlslOP->GetU32Const(m_Parameters.ComputeShader.ThreadIdX),
450450
"CompareToThreadIdX");
451+
451452
auto CompareToY = BC.Builder.CreateICmpEQ(
452453
RayY, BC.HlslOP->GetU32Const(m_Parameters.ComputeShader.ThreadIdY),
453454
"CompareToThreadIdY");
455+
454456
auto CompareToZ = BC.Builder.CreateICmpEQ(
455457
RayZ, BC.HlslOP->GetU32Const(m_Parameters.ComputeShader.ThreadIdZ),
456458
"CompareToThreadIdZ");
@@ -619,15 +621,15 @@ void DxilDebugInstrumentation::addInvocationSelectionProlog(
619621
Value *ParameterTestResult = nullptr;
620622
switch (shaderKind) {
621623
case DXIL::ShaderKind::RayGeneration:
624+
case DXIL::ShaderKind::ClosestHit:
625+
case DXIL::ShaderKind::Intersection:
626+
case DXIL::ShaderKind::AnyHit:
627+
case DXIL::ShaderKind::Miss:
622628
ParameterTestResult = addRaygenShaderProlog(BC);
623629
break;
624630
case DXIL::ShaderKind::Compute:
625631
case DXIL::ShaderKind::Amplification:
626632
case DXIL::ShaderKind::Mesh:
627-
//case DXIL::ShaderKind::Intersection:
628-
//case DXIL::ShaderKind::AnyHit:
629-
//case DXIL::ShaderKind::ClosestHit:
630-
//case DXIL::ShaderKind::Miss:
631633
ParameterTestResult = addDispatchedShaderProlog(BC);
632634
break;
633635
case DXIL::ShaderKind::Geometry:
@@ -806,7 +808,6 @@ void DxilDebugInstrumentation::addInvocationStartMarker(BuilderContext &BC) {
806808

807809
marker.Header.Details.SizeDwords =
808810
DebugShaderModifierRecordPayloadSizeDwords(sizeof(marker));
809-
;
810811
marker.Header.Details.Flags = 0;
811812
marker.Header.Details.Type =
812813
DebugShaderModifierRecordTypeInvocationStartMarker;
@@ -980,16 +981,9 @@ bool DxilDebugInstrumentation::RunOnFunction(
980981
DxilModule &DM,
981982
llvm::Function * entryFunction)
982983
{
983-
DXIL::ShaderKind shaderKind = DXIL::ShaderKind::Invalid;
984-
if (!DM.HasDxilFunctionProps(entryFunction)) {
985-
auto ShaderModel = DM.GetShaderModel();
986-
shaderKind = ShaderModel->GetKind();
987-
} else {
988-
hlsl::DxilFunctionProps const &props =
989-
DM.GetDxilFunctionProps(entryFunction);
990-
shaderKind = props.shaderKind;
991-
}
992-
984+
DXIL::ShaderKind shaderKind =
985+
PIXPassHelpers::GetFunctionShaderKind(DM, entryFunction);
986+
993987
switch (shaderKind) {
994988
case DXIL::ShaderKind::Amplification:
995989
case DXIL::ShaderKind::Mesh:
@@ -1000,12 +994,11 @@ bool DxilDebugInstrumentation::RunOnFunction(
1000994
case DXIL::ShaderKind::RayGeneration:
1001995
case DXIL::ShaderKind::Hull:
1002996
case DXIL::ShaderKind::Domain:
1003-
break;
1004-
//todo:
1005997
case DXIL::ShaderKind::Intersection:
1006998
case DXIL::ShaderKind::AnyHit:
1007999
case DXIL::ShaderKind::ClosestHit:
10081000
case DXIL::ShaderKind::Miss:
1001+
break;
10091002
default:
10101003
return false;
10111004
}
@@ -1042,8 +1035,24 @@ bool DxilDebugInstrumentation::RunOnFunction(
10421035

10431036
auto &values = m_FunctionToValues[BC.Builder.GetInsertBlock()->getParent()];
10441037

1038+
// PIX binds two UAVs when running this instrumentation: one for raygen shaders
1039+
// and another for the hitgroups and miss shaders. Since PIX invokes this pass
1040+
// at the library level, which may contain examples of both types, PIX can't really
1041+
// specify which UAV index to use per-shader. This pass therefore just has to know this:
1042+
constexpr unsigned int RayGenUAVRegister = 0;
1043+
constexpr unsigned int HitGroupAndMissUAVRegister = 1;
1044+
unsigned int UAVRegisterId = RayGenUAVRegister;
1045+
switch (shaderKind) {
1046+
case DXIL::ShaderKind::ClosestHit:
1047+
case DXIL::ShaderKind::Intersection:
1048+
case DXIL::ShaderKind::AnyHit:
1049+
case DXIL::ShaderKind::Miss:
1050+
UAVRegisterId = HitGroupAndMissUAVRegister;
1051+
break;
1052+
}
1053+
10451054
values.UAVHandle = PIXPassHelpers::CreateUAV(
1046-
DM, Builder, 0,
1055+
DM, Builder, UAVRegisterId,
10471056
"PIX_DebugUAV_Handle");
10481057
values.CounterOffset = BC.HlslOP->GetU32Const(UAVDumpingGroundOffset() + CounterOffsetBeyondUsefulData);
10491058

lib/DxilPIXPasses/PixPassHelpers.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,20 @@ GetAllInstrumentableFunctions(hlsl::DxilModule &DM) {
337337
return ret;
338338
}
339339

340+
hlsl::DXIL::ShaderKind GetFunctionShaderKind(hlsl::DxilModule &DM,
341+
llvm::Function *fn) {
342+
hlsl::DXIL::ShaderKind shaderKind = hlsl::DXIL::ShaderKind::Invalid;
343+
if (!DM.HasDxilFunctionProps(fn)) {
344+
auto ShaderModel = DM.GetShaderModel();
345+
shaderKind = ShaderModel->GetKind();
346+
} else {
347+
hlsl::DxilFunctionProps const &props =
348+
DM.GetDxilFunctionProps(fn);
349+
shaderKind = props.shaderKind;
350+
}
351+
return shaderKind;
352+
}
353+
340354
std::vector<llvm::BasicBlock*> GetAllBlocks(hlsl::DxilModule& DM) {
341355
std::vector<llvm::BasicBlock*> ret;
342356
auto entryPoints = DM.GetExportedFunctions();

lib/DxilPIXPasses/PixPassHelpers.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ namespace PIXPassHelpers
3030
llvm::Function* GetEntryFunction(hlsl::DxilModule& DM);
3131
std::vector<llvm::BasicBlock*> GetAllBlocks(hlsl::DxilModule& DM);
3232
std::vector<llvm::Function*> GetAllInstrumentableFunctions(hlsl::DxilModule& DM);
33+
hlsl::DXIL::ShaderKind GetFunctionShaderKind(hlsl::DxilModule &DM,
34+
llvm::Function *fn);
3335
#ifdef PIX_DEBUG_DUMP_HELPER
3436
void Log(const char* format, ...);
3537
void LogPartialLine(const char* format, ...);
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
// RUN: %dxc -T lib_6_3 %s | %opt -S -hlsl-dxil-debug-instrumentation,parameter0=10,parameter1=20,parameter2=30 | %FileCheck %s
2+
3+
4+
// Just check that the selection prolog was added to each shader:
5+
6+
// CHECK: call i32 @dx.op.dispatchRaysIndex.i32(i32 145, i8 0)
7+
// CHECK: call i32 @dx.op.dispatchRaysIndex.i32(i32 145, i8 1)
8+
// CHECK: call i32 @dx.op.dispatchRaysIndex.i32(i32 145, i8 2)
9+
// CHECK: call i32 @dx.op.dispatchRaysIndex.i32(i32 145, i8 0)
10+
11+
// There must be three compares:
12+
// CHECK: = icmp eq i32
13+
// CHECK: = icmp eq i32
14+
// CHECK: = icmp eq i32
15+
16+
// Two ANDs of these bools:
17+
// CHECK: and i1
18+
// CHECK: and i1
19+
20+
//-----------------------------------------------------------------------------
21+
struct cb_push_test_raytracing_t
22+
{
23+
uint m_rt_index;
24+
uint m_raytracing_acc_struct_index;
25+
uint m_per_view_index;
26+
};
27+
28+
//-----------------------------------------------------------------------------
29+
struct cb_view_t
30+
{
31+
float4x4 m_view;
32+
float4x4 m_proj;
33+
float4x4 m_inv_view_proj;
34+
float3 m_camera_pos;
35+
};
36+
37+
RaytracingAccelerationStructure g_bindless_raytracing_acc_struct[] : register(t0, space200);
38+
ConstantBuffer<cb_push_test_raytracing_t> g_push_constants : register(b0, space999);
39+
ConstantBuffer<cb_view_t> g_view[] : register(b0, space100);
40+
RWTexture2D<float4> g_output[] : register(u0, space100);
41+
42+
//-----------------------------------------------------------------------------
43+
// Payloads
44+
//-----------------------------------------------------------------------------
45+
46+
struct ray_payload_t
47+
{
48+
float3 m_color;
49+
};
50+
51+
//-----------------------------------------------------------------------------
52+
// Ray generation
53+
//-----------------------------------------------------------------------------
54+
55+
[shader("raygeneration")]
56+
void raygen_shader()
57+
{
58+
if( g_push_constants.m_rt_index != 0xFFFFFFFF &&
59+
g_push_constants.m_raytracing_acc_struct_index != 0xFFFFFFFF &&
60+
g_push_constants.m_per_view_index != 0xFFFFFFFF)
61+
{
62+
RaytracingAccelerationStructure l_acc_struct = g_bindless_raytracing_acc_struct[g_push_constants.m_raytracing_acc_struct_index];
63+
RWTexture2D<float4> l_output = g_output[g_push_constants.m_rt_index];
64+
cb_view_t l_per_view = g_view[g_push_constants.m_per_view_index];
65+
66+
uint3 l_launch_index = DispatchRaysIndex();
67+
68+
// Ray dsc
69+
RayDesc ray;
70+
ray.Origin = l_per_view.m_camera_pos; // THIS LINE CAUSES AN ACCESS VIOLATION. Replacing l_per_view.m_camera_pos with a constant makes it compile fine
71+
//ray.Origin = 0;
72+
ray.Direction = float3(0, 1.0, 0);
73+
ray.TMin = 0;
74+
ray.TMax = 100000;
75+
76+
ray_payload_t l_payload;
77+
TraceRay(l_acc_struct, 0 /*rayFlags*/, 0xFF, 0 /* ray index*/, 0, 0, ray, l_payload);
78+
l_output[l_launch_index.xy] = float4(l_payload.m_color, 1.0);
79+
}
80+
}
81+
82+
//-----------------------------------------------------------------------------
83+
// Primary rays
84+
//-----------------------------------------------------------------------------
85+
86+
[shader("miss")]
87+
void miss_shader(inout ray_payload_t l_payload)
88+
{
89+
l_payload.m_color = float3(0.4, 0.0, 0.0);
90+
}
91+
92+
[shader("closesthit")]
93+
void closest_hit_shader(inout ray_payload_t l_payload, in BuiltInTriangleIntersectionAttributes l_attribs)
94+
{
95+
l_payload.m_color = 1.0f;
96+
}
97+
98+
99+
struct MyAttributes {
100+
float2 bary;
101+
uint id;
102+
};
103+
104+
[shader("intersection")]
105+
void intersection1()
106+
{
107+
float hitT = RayTCurrent();
108+
MyAttributes attr = (MyAttributes)0;
109+
bool bReported = ReportHit(hitT, 0, attr);
110+
}

0 commit comments

Comments
 (0)