Skip to content

Commit 80e4d5e

Browse files
committed
Support for DXIL Constants created using GetElementPtr
Stop ignoring DXIL global variables which start with "dx.nothing." Do not process constants from instructions which are counted as a nop by the simulation
1 parent 853097d commit 80e4d5e

File tree

2 files changed

+173
-30
lines changed

2 files changed

+173
-30
lines changed

renderdoc/driver/shaders/dxil/dxil_debug.cpp

+170-27
Original file line numberDiff line numberDiff line change
@@ -32,23 +32,22 @@ RDOC_CONFIG(bool, D3D12_DXILShaderDebugger_Logging, false,
3232
"Debug logging for the DXIL shader debugger");
3333

3434
// TODO: Remove asserts using ^
35-
// TODO: Support global shared memory pointers created as Constants using getElementPtr inside the constant
35+
// TODO: Extend support for Compound Constants: arithmetic, logical ops
3636
// TODO: re-implement callstacks using scopes and inlined at metadata
3737
// TODO: Assert m_Block in ThreadState is correct per instruction
3838
// TODO: Automatically execute phi instructions after a branch
3939
// TODO: Support MSAA
4040
// TODO: Support UAVs with counter
41-
// TODO: Extend support for Compound Constants: Vector, GetElementPtr
42-
// TODO: Extend debug data parsing for DW_TAG_array_type for the base element type
43-
// TODO: Extend debug data parsing: N-dimensional arrays, mapping covers whole sub-array
41+
// TODO: Extend debug data parsing: DW_TAG_array_type for the base element type
42+
// TODO: Extend debug data parsing: N-dimensional arrays, mapping covers whole sub-array
4443

4544
// Notes:
4645
// The phi node capture variables are not shown in the UI
4746
// LLVM poison values are not supported
4847
// Does it make sense to use ShaderVariable GPU pointers
4948
// ExtractVal: only handles one index
5049
// ComputeDXILTypeByteSize does not consider byte alignment
51-
// GetElementPtr: only handles a two indexes
50+
// GetElementPtr: only handles two indexes
5251
// Sample*: Argument 10 which is called Clamp is not used
5352
// ShuffleVector: mask entries might be undef meaning "don't care"
5453

@@ -94,6 +93,36 @@ inline bool RDCISNORMAL(double input)
9493
using namespace DXIL;
9594
using namespace DXDebug;
9695

96+
const uint32_t POINTER_MAGIC = 0xBEAFDEAF;
97+
98+
static void EncodePointer(DXILDebug::Id ptrId, uint64_t offset, uint64_t size, ShaderVariable &var)
99+
{
100+
var.type = VarType::GPUPointer;
101+
var.value.u32v[0] = ptrId;
102+
var.value.u32v[1] = POINTER_MAGIC;
103+
var.value.u64v[1] = offset;
104+
var.value.u64v[2] = size;
105+
}
106+
107+
static bool DecodePointer(DXILDebug::Id &ptrId, uint64_t &offset, uint64_t &size,
108+
const ShaderVariable &var)
109+
{
110+
if(var.type != VarType::GPUPointer)
111+
{
112+
RDCERR("Calling DecodePointer on non-pointer type %s", ToStr(var.type).c_str());
113+
return false;
114+
}
115+
if(var.value.u32v[1] != POINTER_MAGIC)
116+
{
117+
RDCERR("Calling DecodePointer on non encoded pointer type %u", var.value.u32v[1]);
118+
return false;
119+
}
120+
ptrId = var.value.u32v[0];
121+
offset = var.value.u64v[1];
122+
size = var.value.u64v[2];
123+
return true;
124+
}
125+
97126
static bool OperationFlushing(const Operation op, DXOp dxOpCode)
98127
{
99128
if(dxOpCode != DXOp::NumOpCodes)
@@ -848,13 +877,98 @@ static bool ConvertDXILConstantToShaderVariable(const Constant *constant, Shader
848877
const rdcarray<DXIL::Value *> &members = constant->getMembers();
849878
value = members[0];
850879
}
851-
if(constant->op == Operation::GetElementPtr)
880+
if(constant->op == Operation::NoOp)
852881
{
853-
RDCLOG("Unsupported Constant Op %s", ToStr(constant->op).c_str());
882+
RDCASSERT(ConvertDXILValueToShaderValue(value, var.type, 0, var.value));
854883
return true;
855884
}
856-
RDCASSERT(ConvertDXILValueToShaderValue(value, var.type, 0, var.value));
857-
return true;
885+
else if(constant->op == Operation::GetElementPtr)
886+
{
887+
const rdcarray<DXIL::Value *> &members = constant->getMembers();
888+
RDCASSERT(members.size() >= 3, members.size());
889+
value = members[0];
890+
const GlobalVar *gv = cast<GlobalVar>(value);
891+
if(!gv)
892+
{
893+
RDCERR("Constant GetElementPtr first member is not a GlobalVar");
894+
return false;
895+
}
896+
const DXIL::Type *elementType = gv->type;
897+
if(elementType->type != Type::TypeKind::Pointer)
898+
{
899+
RDCERR("Constant GetElementPtr global variable is not a Pointer");
900+
return false;
901+
}
902+
elementType = elementType->inner;
903+
VarType baseType = ConvertDXILTypeToVarType(elementType);
904+
uint32_t elementSize = GetElementByteSize(baseType);
905+
uint32_t countElems = RDCMAX(1U, elementType->elemCount);
906+
uint64_t size = countElems * GetElementByteSize(baseType);
907+
908+
DXILDebug::Id ptrId = gv->ssaId;
909+
// members[1..] : indices 1...N
910+
rdcarray<uint64_t> indexes;
911+
indexes.reserve(members.size() - 1);
912+
for(uint32_t a = 1; a < members.size(); ++a)
913+
{
914+
value = members[a];
915+
VarType argType = ConvertDXILTypeToVarType(value->type);
916+
ShaderValue argValue;
917+
memset(&argValue, 0, sizeof(argValue));
918+
RDCASSERT(ConvertDXILValueToShaderValue(value, argType, 0, argValue));
919+
indexes.push_back(argValue.u64v[0]);
920+
}
921+
// Index 0 is in ptr terms as if pointer was an array of pointers
922+
RDCASSERTEQUAL(indexes[0], 0);
923+
uint64_t offset = 0;
924+
925+
if(indexes.size() > 1)
926+
offset += indexes[1] * elementSize;
927+
RDCASSERT(indexes.size() <= 2);
928+
// Encode the pointer allocation: ptrId, offset, size
929+
EncodePointer(ptrId, offset, size, var);
930+
return true;
931+
}
932+
// case Operation::Trunc:
933+
// case Operation::ZExt:
934+
// case Operation::SExt:
935+
// case Operation::FToU:
936+
// case Operation::FToS:
937+
// case Operation::UToF:
938+
// case Operation::SToF:
939+
// case Operation::FPTrunc:
940+
// case Operation::FPExt:
941+
// case Operation::PtrToI:
942+
// case Operation::IToPtr:
943+
// case Operation::Bitcast:
944+
// case Operation::AddrSpaceCast:
945+
// case Operation::Select:
946+
// case Operation::IEqual:
947+
// plus other integer comparisons
948+
// case Operation::FOrdEqual:
949+
// plus other fp comparisons
950+
// case Operation::ExtractElement:
951+
// case Operation::ExtractVal:
952+
// case Operation::FAdd:
953+
// case Operation::FSub:
954+
// case Operation::FMul:
955+
// case Operation::FDiv:
956+
// case Operation::FRem:
957+
// case Operation::Add:
958+
// case Operation::Sub:
959+
// case Operation::Mul:
960+
// case Operation::UDiv:
961+
// case Operation::SDiv:
962+
// case Operation::URem:
963+
// case Operation::SRem:
964+
// case Operation::ShiftLeft:
965+
// case Operation::LogicalShiftRight:
966+
// case Operation::ArithShiftRight:
967+
// case Operation::And:
968+
// case Operation::Or:
969+
// case Operation::Xor:
970+
RDCLOG("Unsupported Constant Op %s", ToStr(constant->op).c_str());
971+
return false;
858972
}
859973
return false;
860974
}
@@ -4152,7 +4266,7 @@ bool ThreadState::ExecuteInstruction(DebugAPIWrapper *apiWrapper,
41524266
// Store(ptr, value)
41534267
Id baseMemoryId = DXILDebug::INVALID_ID;
41544268
void *baseMemoryBackingPtr = NULL;
4155-
size_t allocSize = 0;
4269+
uint64_t allocSize = 0;
41564270
void *allocMemoryBackingPtr = NULL;
41574271
Id ptrId = GetArgumentId(0);
41584272
if(ptrId == DXILDebug::INVALID_ID)
@@ -4267,8 +4381,8 @@ bool ThreadState::ExecuteInstruction(DebugAPIWrapper *apiWrapper,
42674381
backingMemory += offset;
42684382
m_Memory.m_AllocPointers[resultId] = {ptrId, backingMemory, size};
42694383

4270-
RDCASSERT(size < sizeof(result.value.f32v));
4271-
if(size < sizeof(ShaderValue))
4384+
RDCASSERT(size <= sizeof(ShaderValue));
4385+
if(size <= sizeof(ShaderValue))
42724386
memcpy(&result.value, backingMemory, size);
42734387
else
42744388
RDCERR("Size %u too large MAX %u for GetElementPtr", size, sizeof(ShaderValue));
@@ -5133,7 +5247,7 @@ bool ThreadState::ExecuteInstruction(DebugAPIWrapper *apiWrapper,
51335247
case Operation::AtomicUMin:
51345248
case Operation::CompareExchange:
51355249
{
5136-
size_t allocSize = 0;
5250+
uint64_t allocSize = 0;
51375251
void *allocMemoryBackingPtr = NULL;
51385252
void *baseMemoryBackingPtr = NULL;
51395253
Id baseMemoryId = DXILDebug::INVALID_ID;
@@ -5617,7 +5731,7 @@ void ThreadState::MarkResourceAccess(const rdcstr &name, const ResourceReference
56175731
accessed.push_back(resRefInfo.binding);
56185732
}
56195733

5620-
void ThreadState::UpdateBackingMemoryFromVariable(void *ptr, size_t &allocSize,
5734+
void ThreadState::UpdateBackingMemoryFromVariable(void *ptr, uint64_t &allocSize,
56215735
const ShaderVariable &var)
56225736
{
56235737
// Memory copy from value to backing memory
@@ -5626,7 +5740,7 @@ void ThreadState::UpdateBackingMemoryFromVariable(void *ptr, size_t &allocSize,
56265740
RDCASSERTEQUAL(var.rows, 1);
56275741
const size_t elementSize = GetElementByteSize(var.type);
56285742
RDCASSERT(elementSize <= allocSize);
5629-
RDCASSERT(elementSize < sizeof(var.value.f32v));
5743+
RDCASSERT(elementSize <= sizeof(ShaderValue));
56305744
const size_t varMemSize = var.columns * elementSize;
56315745
memcpy(ptr, &var.value.f32v[0], varMemSize);
56325746
allocSize -= varMemSize;
@@ -5654,7 +5768,7 @@ void ThreadState::UpdateMemoryVariableFromBackingMemory(Id memoryId, const void
56545768
{
56555769
RDCASSERTEQUAL(baseMemory.rows, 1);
56565770
RDCASSERTEQUAL(baseMemory.columns, 1);
5657-
if(elementSize < sizeof(ShaderValue))
5771+
if(elementSize <= sizeof(ShaderValue))
56585772
memcpy(&baseMemory.value, src, elementSize);
56595773
else
56605774
RDCERR("Updating MemoryVariable elementSize %u too large max %u", elementSize,
@@ -5664,7 +5778,7 @@ void ThreadState::UpdateMemoryVariableFromBackingMemory(Id memoryId, const void
56645778
{
56655779
for(uint32_t i = 0; i < baseMemory.members.size(); ++i)
56665780
{
5667-
if(elementSize < sizeof(ShaderValue))
5781+
if(elementSize <= sizeof(ShaderValue))
56685782
memcpy(&baseMemory.members[i].value, src, elementSize);
56695783
else
56705784
RDCERR("Updating MemoryVariable member %u elementSize %u too large max %u", i, elementSize,
@@ -6131,6 +6245,7 @@ ShaderValue ThreadState::DDY(bool fine, Operation opCode, DXOp dxOpCode,
61316245
}
61326246

61336247
ShaderValue ret;
6248+
memset(&ret, 0, sizeof(ret));
61346249
ShaderVariable a;
61356250
ShaderVariable b;
61366251
RDCASSERT(quad[index + 2].GetShaderVariable(dxilValue, opCode, dxOpCode, a));
@@ -7633,10 +7748,6 @@ ShaderDebugTrace *Debugger::BeginDebug(uint32_t eventId, const DXBC::DXBCContain
76337748
MemoryTracking &globalMemory = m_GlobalState.memory;
76347749
for(const DXIL::GlobalVar *gv : m_Program->m_GlobalVars)
76357750
{
7636-
// Ignore DXIL global variables which start with "dx.nothing."
7637-
if(gv->name.beginsWith("dx.nothing."))
7638-
continue;
7639-
76407751
GlobalVariable globalVar;
76417752
rdcstr n = DXBC::BasicDemangle(gv->name);
76427753
DXIL::SanitiseName(n);
@@ -7656,7 +7767,7 @@ ShaderDebugTrace *Debugger::BeginDebug(uint32_t eventId, const DXBC::DXBCContain
76567767
RDCASSERT(itAlloc != globalMemory.m_Allocs.end());
76577768
const MemoryTracking::Alloc &alloc = itAlloc->second;
76587769
void *allocMemoryBackingPtr = alloc.backingMemory;
7659-
size_t allocSize = alloc.size;
7770+
uint64_t allocSize = alloc.size;
76607771
state.UpdateBackingMemoryFromVariable(allocMemoryBackingPtr, allocSize, globalVar.var);
76617772
RDCASSERTEQUAL(allocSize, 0);
76627773
}
@@ -7672,6 +7783,8 @@ ShaderDebugTrace *Debugger::BeginDebug(uint32_t eventId, const DXBC::DXBCContain
76727783
{
76737784
for(Instruction *inst : f->instructions)
76747785
{
7786+
if(IsNopInstruction(*inst))
7787+
continue;
76757788
for(const Value *arg : inst->args)
76767789
{
76777790
if(arg && arg->kind() == ValueKind::Constant)
@@ -7684,14 +7797,44 @@ ShaderDebugTrace *Debugger::BeginDebug(uint32_t eventId, const DXBC::DXBCContain
76847797
}
76857798

76867799
GlobalConstant constantVar;
7687-
ConvertDXILTypeToShaderVariable(c->type, constantVar.var);
7688-
ConvertDXILConstantToShaderVariable(c, constantVar.var);
7689-
constantVar.var.name = m_Program->GetArgumentName(c);
7690-
constantVar.id = c->ssaId;
7800+
ShaderVariable &var = constantVar.var;
7801+
ConvertDXILTypeToShaderVariable(c->type, var);
7802+
ConvertDXILConstantToShaderVariable(c, var);
7803+
var.name = m_Program->GetArgumentName(c);
76917804
Id id = c->ssaId;
76927805
RDCASSERTNOTEQUAL(id, DXILDebug::INVALID_ID);
7806+
constantVar.id = id;
7807+
if(var.type == VarType::GPUPointer)
7808+
{
7809+
Id ptrId;
7810+
uint64_t offset;
7811+
uint64_t size;
7812+
// Decode the pointer allocation: ptrId, offset, size
7813+
RDCASSERT(DecodePointer(ptrId, offset, size, var));
7814+
7815+
auto it = globalMemory.m_Allocs.find(ptrId);
7816+
if(it != globalMemory.m_Allocs.end())
7817+
{
7818+
const MemoryTracking::Alloc &alloc = it->second;
7819+
uint8_t *backingMemory = (uint8_t *)alloc.backingMemory;
7820+
RDCASSERT(offset + size <= alloc.size);
7821+
if(offset + size <= alloc.size)
7822+
{
7823+
backingMemory += offset;
7824+
globalMemory.m_AllocPointers[id] = {ptrId, backingMemory, size};
7825+
}
7826+
else
7827+
{
7828+
RDCERR("Invalid GEP offset %u size %u for alloc size %u", offset, size, alloc.size);
7829+
}
7830+
}
7831+
else
7832+
{
7833+
RDCERR("Failed to find allocation for Constant global variable pointer %u", ptrId);
7834+
}
7835+
}
76937836
m_GlobalState.constants.push_back(constantVar);
7694-
m_LiveGlobals[constantVar.id] = true;
7837+
m_LiveGlobals[id] = true;
76957838
}
76967839
}
76977840
}

renderdoc/driver/shaders/dxil/dxil_debug.h

+3-3
Original file line numberDiff line numberDiff line change
@@ -192,15 +192,15 @@ struct MemoryTracking
192192
struct Alloc
193193
{
194194
void *backingMemory;
195-
size_t size;
195+
uint64_t size;
196196
bool global;
197197
};
198198

199199
struct AllocPointer
200200
{
201201
Id baseMemoryId;
202202
void *backingMemory;
203-
size_t size;
203+
uint64_t size;
204204
};
205205

206206
std::map<Id, Alloc> m_Allocs;
@@ -251,7 +251,7 @@ struct ThreadState
251251
bool GetPhiVariable(const Id &id, DXIL::Operation opCode, DXIL::DXOp dxOpCode,
252252
ShaderVariable &var) const;
253253
bool GetVariableHelper(DXIL::Operation op, DXIL::DXOp dxOpCode, ShaderVariable &var) const;
254-
void UpdateBackingMemoryFromVariable(void *ptr, size_t &allocSize, const ShaderVariable &var);
254+
void UpdateBackingMemoryFromVariable(void *ptr, uint64_t &allocSize, const ShaderVariable &var);
255255
void UpdateMemoryVariableFromBackingMemory(Id memoryId, const void *ptr);
256256

257257
void PerformGPUResourceOp(const rdcarray<ThreadState> &workgroups, DXIL::Operation opCode,

0 commit comments

Comments
 (0)