DXIL debugger support for queue and run simulation on Device Thread

This commit is contained in:
Jake Turner
2025-10-04 11:56:08 +01:00
parent 0243927d43
commit 516dec8e17
3 changed files with 262 additions and 49 deletions
+171 -39
View File
@@ -1838,14 +1838,15 @@ bool ThreadState::InUniformBlock() const
return m_FunctionInfo->uniformBlocks.contains(m_Block);
}
// Must be called from the replay manager thread (the debugger thread)
// Must run on the device thread for the active simulation thread
void ThreadState::ProcessScopeChange(const rdcarray<bool> &oldLive, const rdcarray<bool> &newLive)
{
THREADSTATE_CHECK_DEBUGGER_THREAD();
// nothing to do if we aren't tracking into a state
if(!m_HasDebugState)
return;
THREADSTATE_CHECK_DEBUGGER_THREAD();
// all oldLive (except globals) are going out of scope. all newLive (except globals) are coming
// into scope
@@ -1868,10 +1869,12 @@ void ThreadState::ProcessScopeChange(const rdcarray<bool> &oldLive, const rdcarr
}
}
// Must be called from the replay manager thread (the debugger thread)
// Must run on the device thread for the active simulation thread
void ThreadState::EnterFunction(const Function *function, const rdcarray<Value *> &args)
{
THREADSTATE_CHECK_DEBUGGER_THREAD();
if(m_HasDebugState)
THREADSTATE_CHECK_DEBUGGER_THREAD();
StackFrame *frame = new StackFrame(function);
m_FunctionInstructionIdx = 0;
m_FunctionInfo = m_Debugger.GetFunctionInfo(function);
@@ -2179,7 +2182,8 @@ bool ThreadState::ExecuteInstruction(const rdcarray<ThreadState> &workgroup)
// GetDimensions(handle,mipLevel)
Id handleId = GetArgumentId(1);
bool annotatedHandle;
ResourceReferenceInfo resRefInfo = GetResource(handleId, annotatedHandle);
ShaderVariable handleVar;
ResourceReferenceInfo resRefInfo = GetResource(handleId, annotatedHandle, handleVar);
if(!resRefInfo.Valid())
break;
@@ -2192,7 +2196,13 @@ bool ThreadState::ExecuteInstruction(const rdcarray<ThreadState> &workgroup)
RDCASSERT(GetShaderVariable(inst.args[2], opCode, dxOpCode, arg));
mipLevel = arg.value.u32v[0];
}
data = m_Debugger.GetResourceInfo(resRefInfo.resClass, binding, mipLevel);
if(m_Debugger.GetResourceInfo(resRefInfo.resClass, binding, mipLevel, data) ==
DeviceOpResult::NeedsDevice)
{
SetStepNeedsDeviceThread();
break;
}
MarkResourceAccess(handleVar);
// Returns a vector with: w, h, d, numLevels
result.value = data.value;
@@ -2212,15 +2222,22 @@ bool ThreadState::ExecuteInstruction(const rdcarray<ThreadState> &workgroup)
// Texture2DMSGetSamplePosition(srv,index)
Id handleId = GetArgumentId(1);
bool annotatedHandle;
ResourceReferenceInfo resRefInfo = GetResource(handleId, annotatedHandle);
ShaderVariable handleVar;
ResourceReferenceInfo resRefInfo = GetResource(handleId, annotatedHandle, handleVar);
if(!resRefInfo.Valid())
break;
ShaderVariable arg;
RDCASSERT(GetShaderVariable(inst.args[2], opCode, dxOpCode, arg));
const char *opString = ToStr(dxOpCode).c_str();
ShaderVariable data =
m_Debugger.GetSampleInfo(resRefInfo.resClass, resRefInfo.binding, opString);
ShaderVariable data;
if(m_Debugger.GetSampleInfo(resRefInfo.resClass, resRefInfo.binding, opString, data) ==
DeviceOpResult::NeedsDevice)
{
SetStepNeedsDeviceThread();
break;
}
MarkResourceAccess(handleVar);
uint32_t sampleCount = data.value.u32v[0];
uint32_t sampleIndex = arg.value.u32v[0];
@@ -2240,14 +2257,24 @@ bool ThreadState::ExecuteInstruction(const rdcarray<ThreadState> &workgroup)
case DXOp::RenderTargetGetSampleCount:
{
const char *opString = ToStr(dxOpCode).c_str();
ShaderVariable data = m_Debugger.GetRenderTargetSampleInfo(opString);
ShaderVariable data;
if(m_Debugger.GetRenderTargetSampleInfo(opString, data) == DeviceOpResult::NeedsDevice)
{
SetStepNeedsDeviceThread();
break;
}
result.value.u32v[0] = data.value.u32v[0];
break;
}
case DXOp::RenderTargetGetSamplePosition:
{
const char *opString = ToStr(dxOpCode).c_str();
ShaderVariable data = m_Debugger.GetRenderTargetSampleInfo(opString);
ShaderVariable data;
if(m_Debugger.GetRenderTargetSampleInfo(opString, data) == DeviceOpResult::NeedsDevice)
{
SetStepNeedsDeviceThread();
break;
}
ShaderVariable arg;
RDCASSERT(GetShaderVariable(inst.args[1], opCode, dxOpCode, arg));
@@ -2281,9 +2308,11 @@ bool ThreadState::ExecuteInstruction(const rdcarray<ThreadState> &workgroup)
{
Id handleId = GetArgumentId(1);
bool annotatedHandle;
ResourceReferenceInfo resRefInfo = GetResource(handleId, annotatedHandle);
ShaderVariable handleVar;
ResourceReferenceInfo resRefInfo = GetResource(handleId, annotatedHandle, handleVar);
if(!resRefInfo.Valid())
break;
MarkResourceAccess(handleVar);
PerformGPUResourceOp(workgroup, opCode, dxOpCode, resRefInfo, inst, result);
eventFlags |= ShaderEvents::SampleLoadGather;
@@ -2304,9 +2333,11 @@ bool ThreadState::ExecuteInstruction(const rdcarray<ThreadState> &workgroup)
// RawBufferStore(uav,index,elementOffset,value0,value1,value2,value3,mask,alignment)
const Id handleId = GetArgumentId(1);
bool annotatedHandle;
ResourceReferenceInfo resRefInfo = GetResource(handleId, annotatedHandle);
ShaderVariable handleVar;
ResourceReferenceInfo resRefInfo = GetResource(handleId, annotatedHandle, handleVar);
if(!resRefInfo.Valid())
break;
MarkResourceAccess(handleVar);
ResourceClass resClass = resRefInfo.resClass;
// SRV TextureLoad is done on the GPU
@@ -2590,11 +2621,22 @@ bool ThreadState::ExecuteInstruction(const rdcarray<ThreadState> &workgroup)
// convert the direct heap access binding into ResourceReferenceIndo
BindingSlot slot(heapType, descriptorIndex);
ResourceReferenceInfo resRefInfo = m_Debugger.GetResourceReferenceInfo(slot);
ResourceReferenceInfo resRefInfo;
if(m_Debugger.GetResourceReferenceInfo(slot, resRefInfo) == DeviceOpResult::NeedsDevice)
{
SetStepNeedsDeviceThread();
break;
}
ShaderDirectAccess access;
if(m_Debugger.GetShaderDirectAccess(resRefInfo.descType, slot, access) ==
DeviceOpResult::NeedsDevice)
{
SetStepNeedsDeviceThread();
break;
}
RDCASSERT(m_DirectHeapAccessBindings.count(resultId) == 0);
m_DirectHeapAccessBindings[resultId] = resRefInfo;
ShaderDirectAccess access = m_Debugger.GetShaderDirectAccess(resRefInfo.descType, slot);
// Default to unannotated handle
ClearAnnotatedHandle(result);
rdcstr resName = m_Program.GetHandleAlias(result.name);
@@ -3513,9 +3555,11 @@ bool ThreadState::ExecuteInstruction(const rdcarray<ThreadState> &workgroup)
// AtomicCompareExchange(handle,offset0,offset1,offset2,compareValue,newValue)
const Id handleId = GetArgumentId(1);
bool annotatedHandle;
ResourceReferenceInfo resRefInfo = GetResource(handleId, annotatedHandle);
ShaderVariable handleVar;
ResourceReferenceInfo resRefInfo = GetResource(handleId, annotatedHandle, handleVar);
if(!resRefInfo.Valid())
break;
MarkResourceAccess(handleVar);
ResourceClass resClass = resRefInfo.resClass;
// handle must be a UAV
@@ -6662,6 +6706,18 @@ bool ThreadState::ExecuteInstruction(const rdcarray<ThreadState> &workgroup)
case Operation::InsertValue: RDCERR("Unhandled LLVM opcode %s", ToStr(opCode).c_str()); break;
};
// Waiting for result i.e. from the GPU or replay thread
if(IsPendingResultPending())
{
m_FunctionInstructionIdx--;
// This instruction is being deferred clear the pending debug state
if(m_HasDebugState)
ClearPendingDebugState();
m_HasDebugState = false;
return true;
}
SetPendingResultUnknown();
// Update the result variable
if(resultId == DXILDebug::INVALID_ID)
RDCASSERT(result.name.empty());
@@ -7158,9 +7214,11 @@ void ThreadState::PerformGPUResourceOp(const rdcarray<ThreadState> &workgroup, O
// Sampler is in arg 2
Id samplerId = GetArgumentId(2);
bool annotatedHandle;
ResourceReferenceInfo samplerRef = GetResource(samplerId, annotatedHandle);
ShaderVariable handleVar;
ResourceReferenceInfo samplerRef = GetResource(samplerId, annotatedHandle, handleVar);
if(!samplerRef.Valid())
return;
MarkResourceAccess(handleVar);
RDCASSERTEQUAL(samplerRef.resClass, ResourceClass::Sampler);
// samplerRef->resourceBase must be a Sampler
@@ -7382,14 +7440,15 @@ DXILDebug::Id ThreadState::GetArgumentId(uint32_t i) const
return GetSSAId(arg);
}
ResourceReferenceInfo ThreadState::GetResource(Id handleId, bool &annotatedHandle)
ResourceReferenceInfo ThreadState::GetResource(Id handleId, bool &annotatedHandle,
ShaderVariable &handleVar) const
{
ResourceReferenceInfo resRefInfo;
if(IsVariableAssigned(handleId))
{
RDCASSERT(m_Live[handleId]);
RDCASSERT(IsVariableAssigned(handleId));
const ShaderVariable &handleVar = m_Variables[handleId];
handleVar = m_Variables[handleId];
bool directAccess = handleVar.IsDirectAccess();
ShaderBindIndex bindIndex;
ShaderDirectAccess access;
@@ -7423,7 +7482,6 @@ ResourceReferenceInfo ThreadState::GetResource(Id handleId, bool &annotatedHandl
}
resRefInfo = directHeapAccessBinding->second;
}
MarkResourceAccess(handleVar);
return resRefInfo;
}
@@ -7696,6 +7754,10 @@ bool ThreadState::CanRunAnotherStep() const
if(!m_PartialConvergencePoints.empty())
return false;
// Any pending result i.e. pending GPU math operation, need to run on the device thread
if(IsPendingResultPending())
return false;
// current instructions that require full lockstep
const Instruction *inst = m_CurrentInstruction;
Operation opCode = inst->op;
@@ -9079,6 +9141,7 @@ ShaderDebugTrace *Debugger::BeginDebug(DebugAPIWrapper *apiWrapper, uint32_t eve
m_Steps = 0;
m_Stage = shaderStage;
m_EntryPointInterface = m_Program->GetEntryPointInterface();
m_QueuedDeviceThreadSteps.resize(threadsInWorkgroup);
uint32_t outputSSAId = m_Program->m_NextSSAId;
uint32_t maxSSAId = outputSSAId + 1;
@@ -9093,7 +9156,10 @@ ShaderDebugTrace *Debugger::BeginDebug(DebugAPIWrapper *apiWrapper, uint32_t eve
m_GlobalState.constantBlocksDatas = apiWrapper->GetConstantBlocksDatas();
for(uint32_t i = 0; i < threadsInWorkgroup; i++)
{
m_Workgroup.push_back(ThreadState(*this, m_GlobalState, maxSSAId, i, threadsInWorkgroup));
m_QueuedDeviceThreadSteps[i] = false;
}
// Get the thread state from the API wrapper
const rdcarray<rdcflatmap<ShaderBuiltin, ShaderVariable>> &threadsBuiltins =
@@ -10063,6 +10129,8 @@ rdcarray<ShaderDebugState> Debugger::ContinueDebug()
do
{
ProcessQueuedDeviceThreadSteps();
allStepsCompleted = true;
for(const Tangle &tangle : tangles)
{
@@ -10259,42 +10327,64 @@ bool Debugger::CalculateSampleGather(DXIL::DXOp dxOp, SampleGatherResourceData r
gatherChannel, instructionIdx, output);
}
// Must be called from the replay manager thread (the debugger thread)
ShaderVariable Debugger::GetResourceInfo(DXIL::ResourceClass resClass,
const DXDebug::BindingSlot &slot, uint32_t mipLevel) const
// Called from any thread
DeviceOpResult Debugger::GetResourceInfo(DXIL::ResourceClass resClass,
const DXDebug::BindingSlot &slot, uint32_t mipLevel,
ShaderVariable &result) const
{
if(!IsDeviceThread())
return DeviceOpResult::NeedsDevice;
CHECK_DEBUGGER_THREAD();
return m_ApiWrapper->GetResourceInfo(resClass, slot, mipLevel);
result = m_ApiWrapper->GetResourceInfo(resClass, slot, mipLevel);
return DeviceOpResult::Succeeded;
}
// Must be called from the replay manager thread (the debugger thread)
ShaderVariable Debugger::GetSampleInfo(DXIL::ResourceClass resClass,
const DXDebug::BindingSlot &slot, const char *opString) const
// Called from any thread
DeviceOpResult Debugger::GetSampleInfo(DXIL::ResourceClass resClass, const DXDebug::BindingSlot &slot,
const char *opString, ShaderVariable &result) const
{
if(!IsDeviceThread())
return DeviceOpResult::NeedsDevice;
CHECK_DEBUGGER_THREAD();
return m_ApiWrapper->GetSampleInfo(resClass, slot, opString);
result = m_ApiWrapper->GetSampleInfo(resClass, slot, opString);
return DeviceOpResult::Succeeded;
}
// Must be called from the replay manager thread (the debugger thread)
ShaderVariable Debugger::GetRenderTargetSampleInfo(const char *opString) const
// Called from any thread
DeviceOpResult Debugger::GetRenderTargetSampleInfo(const char *opString, ShaderVariable &result) const
{
if(!IsDeviceThread())
return DeviceOpResult::NeedsDevice;
CHECK_DEBUGGER_THREAD();
return m_ApiWrapper->GetRenderTargetSampleInfo(opString);
result = m_ApiWrapper->GetRenderTargetSampleInfo(opString);
return DeviceOpResult::Succeeded;
}
// Must be called from the replay manager thread (the debugger thread)
ResourceReferenceInfo Debugger::GetResourceReferenceInfo(const DXDebug::BindingSlot &slot) const
// Called from any thread
DeviceOpResult Debugger::GetResourceReferenceInfo(const DXDebug::BindingSlot &slot,
ResourceReferenceInfo &result) const
{
if(!IsDeviceThread())
return DeviceOpResult::NeedsDevice;
CHECK_DEBUGGER_THREAD();
return m_ApiWrapper->GetResourceReferenceInfo(slot);
result = m_ApiWrapper->GetResourceReferenceInfo(slot);
return DeviceOpResult::Succeeded;
}
// Must be called from the replay manager thread (the debugger thread)
ShaderDirectAccess Debugger::GetShaderDirectAccess(DescriptorType type,
const DXDebug::BindingSlot &slot) const
// Called from any thread
DeviceOpResult Debugger::GetShaderDirectAccess(DescriptorType type, const DXDebug::BindingSlot &slot,
ShaderDirectAccess &result) const
{
if(!IsDeviceThread())
return DeviceOpResult::NeedsDevice;
CHECK_DEBUGGER_THREAD();
return m_ApiWrapper->GetShaderDirectAccess(type, slot);
result = m_ApiWrapper->GetShaderDirectAccess(type, slot);
return DeviceOpResult::Succeeded;
}
// Called from any thread
@@ -10316,6 +10406,8 @@ void Debugger::StepThread(uint32_t lane, StepThreadMode stepMode)
InternalStepThread(lane);
thread.ClearPendingDebugState();
}
if(thread.StepNeedsDeviceThread())
break;
if(isActiveThread)
curActiveSteps++;
@@ -10343,6 +10435,14 @@ void Debugger::StepThread(uint32_t lane, StepThreadMode stepMode)
DXIL_DEBUG_RDCASSERT(thread.IsSimulationStepActive());
// The queueing has to be when the thread is not being simulated
if(thread.StepNeedsDeviceThread())
{
DXIL_DEBUG_RDCASSERT(!simulateStep);
QueueDeviceThreadStep(lane);
return;
}
if(simulateStep)
{
DXIL_DEBUG_RDCASSERTEQUAL(stepMode, StepThreadMode::QUEUE_MULTIPLE_STEPS);
@@ -10367,6 +10467,8 @@ void Debugger::InternalStepThread(uint32_t lane)
thread.ClearPendingDebugState();
}
thread.StepNext(true, m_Workgroup);
if(thread.StepNeedsDeviceThread())
return;
m_ActiveDebugState.nextInstruction = thread.GetActiveGlobalInstructionIdx();
thread.FillCallstack(m_ActiveDebugState);
@@ -10388,6 +10490,8 @@ void Debugger::InternalStepThread(uint32_t lane)
else
{
thread.StepNext(false, m_Workgroup);
if(thread.StepNeedsDeviceThread())
return;
}
}
@@ -10397,6 +10501,34 @@ void Debugger::QueueJob(uint32_t lane)
CHECK_DEBUGGER_THREAD();
ThreadState &thread = m_Workgroup[lane];
thread.SetStepQueued();
StepThread(lane, StepThreadMode::RUN_MULTIPLE_STEPS);
// StepThread(lane, StepThreadMode::RUN_MULTIPLE_STEPS);
StepThread(lane, StepThreadMode::RUN_SINGLE_STEP);
}
// Can be called from any thread
void Debugger::QueueDeviceThreadStep(uint32_t lane)
{
ThreadState &thread = m_Workgroup[lane];
DXIL_DEBUG_RDCASSERT(thread.IsSimulationStepActive());
thread.SetStepQueued();
DXIL_DEBUG_RDCASSERT(!m_QueuedDeviceThreadSteps[lane]);
m_QueuedDeviceThreadSteps[lane] = true;
}
// Must be called from the replay manager thread (the debugger thread)
void Debugger::ProcessQueuedDeviceThreadSteps()
{
CHECK_DEBUGGER_THREAD();
for(uint32_t lane = 0; lane < m_QueuedDeviceThreadSteps.size(); ++lane)
{
if(m_QueuedDeviceThreadSteps[lane])
{
m_QueuedDeviceThreadSteps[lane] = false;
ThreadState &thread = m_Workgroup[lane];
thread.SetPendingResultUnknown();
DXIL_DEBUG_RDCASSERT(thread.IsSimulationStepActive());
StepThread(lane, StepThreadMode::QUEUE_MULTIPLE_STEPS);
}
}
}
}; // namespace DXILDebug
+78 -10
View File
@@ -67,6 +67,14 @@ struct GlobalState;
// D3D12 descriptors are equal sized and treated as effectively one byte in size
const uint32_t D3D12_DESCRIPTOR_BYTESIZE = 1;
enum class DeviceOpResult : uint32_t
{
Unknown,
Succeeded,
Failed,
NeedsDevice,
};
inline void AtomicStore(int32_t *var, int32_t newVal)
{
int32_t oldVal = *var;
@@ -385,6 +393,7 @@ struct ThreadState
return &m_PartialConvergencePoints;
}
const ShaderDebugState &GetPendingDebugState() const { return m_PendingDebugState; }
bool StepNeedsDeviceThread() const { return (AtomicLoad(&atomic_stepNeedsDeviceThread) == 1); }
void SetBuiltins(const BuiltinInputs &builtins) { m_Builtins = builtins; }
void SetInput(const ShaderVariable &input) { m_Input = input; }
@@ -410,7 +419,12 @@ struct ThreadState
m_CurrentBlock = m_Block;
}
void SetSimulationStepCompleted() { AtomicStore(&atomic_isSimulationStepActive, 0); }
void SetStepQueued() { AtomicStore(&atomic_isSimulationStepActive, 1); }
void SetStepQueued()
{
AtomicStore(&atomic_isSimulationStepActive, 1);
AtomicStore(&atomic_stepNeedsDeviceThread, 0);
}
void SetPendingResultUnknown() { SetPendingResultStatus(PendingResultStatus::Unknown); }
void InitialiseFromActive(const ThreadState &active)
{
@@ -428,7 +442,50 @@ struct ThreadState
m_PendingDebugState.flags = ShaderEvents::NoEvent;
m_PendingDebugState.nextInstruction = 0;
}
enum class PendingResultStatus : int32_t
{
Unknown,
Pending,
Ready,
Stepped,
};
private:
PendingResultStatus GetPendingResultStatus() const
{
return (PendingResultStatus)AtomicLoad(&atomic_pendingResultStatus);
}
void SetPendingResultStatus(PendingResultStatus status)
{
AtomicStore(&atomic_pendingResultStatus, (int32_t)status);
}
bool IsPendingResultPending() const
{
return GetPendingResultStatus() == PendingResultStatus::Pending;
}
bool IsPendingResultReady() const
{
return GetPendingResultStatus() == PendingResultStatus::Ready;
}
void SetPendingResultReady()
{
DXIL_DEBUG_RDCASSERTEQUAL(GetPendingResultStatus(), PendingResultStatus::Pending);
SetPendingResultStatus(PendingResultStatus::Ready);
}
const ShaderVariable &GetPendingResult() const
{
DXIL_DEBUG_RDCASSERTEQUAL(GetPendingResultStatus(), PendingResultStatus::Ready);
return m_PendingResultData;
}
void SetStepNeedsDeviceThread()
{
AtomicStore(&atomic_stepNeedsDeviceThread, 1);
SetPendingResultStatus(PendingResultStatus::Pending);
}
void EnterFunction(const DXIL::Function *function, const rdcarray<DXIL::Value *> &args);
bool InUniformBlock() const;
@@ -441,7 +498,8 @@ private:
ShaderEvents flags);
rdcstr GetArgumentName(uint32_t i) const;
Id GetArgumentId(uint32_t i) const;
ResourceReferenceInfo GetResource(Id handleId, bool &annotatedHandle);
ResourceReferenceInfo GetResource(Id handleId, bool &annotatedHandle,
ShaderVariable &handleVar) const;
// This must be a thread safe operation using only thread safe containers
bool GetShaderVariableFromLane(const ThreadState &lane, const DXIL::Value *dxilValue,
@@ -543,6 +601,7 @@ private:
rdcarray<bool> m_ActiveMask;
ShaderDebugState m_PendingDebugState;
ShaderVariable m_PendingResultData;
// Track memory allocations
// For stack allocations do not bother freeing when leaving functions
@@ -585,6 +644,8 @@ private:
bool m_Helper = false;
// These need to be accessed using atomics
int32_t atomic_pendingResultStatus = (int32_t)PendingResultStatus::Unknown;
int32_t atomic_stepNeedsDeviceThread = 0;
int32_t atomic_isSimulationStepActive = 0;
};
@@ -744,14 +805,15 @@ public:
const int8_t texelOffsets[3], int multisampleIndex, float lodValue,
float compareValue, GatherChannel gatherChannel,
uint32_t instructionIdx, ShaderVariable &output) const;
ShaderVariable GetResourceInfo(DXIL::ResourceClass resClass, const DXDebug::BindingSlot &slot,
uint32_t mipLeveldim) const;
ShaderVariable GetSampleInfo(DXIL::ResourceClass resClass, const DXDebug::BindingSlot &slot,
const char *opString) const;
ShaderVariable GetRenderTargetSampleInfo(const char *opString) const;
ResourceReferenceInfo GetResourceReferenceInfo(const DXDebug::BindingSlot &slot) const;
ShaderDirectAccess GetShaderDirectAccess(DescriptorType type,
const DXDebug::BindingSlot &slot) const;
DeviceOpResult GetResourceInfo(DXIL::ResourceClass resClass, const DXDebug::BindingSlot &slot,
uint32_t mipLevel, ShaderVariable &result) const;
DeviceOpResult GetSampleInfo(DXIL::ResourceClass resClass, const DXDebug::BindingSlot &slot,
const char *opString, ShaderVariable &result) const;
DeviceOpResult GetRenderTargetSampleInfo(const char *opString, ShaderVariable &result) const;
DeviceOpResult GetResourceReferenceInfo(const DXDebug::BindingSlot &slot,
ResourceReferenceInfo &result) const;
DeviceOpResult GetShaderDirectAccess(DescriptorType type, const DXDebug::BindingSlot &slot,
ShaderDirectAccess &result) const;
bool IsDeviceThread() const { return Threading::GetCurrentID() == m_DeviceThreadID; }
private:
@@ -771,6 +833,8 @@ private:
void StepThread(uint32_t lane, StepThreadMode stepMode);
void InternalStepThread(uint32_t lane);
void SimulationJobHelper();
void QueueDeviceThreadStep(uint32_t lane);
void ProcessQueuedDeviceThreadSteps();
DebugAPIWrapper *m_ApiWrapper = NULL;
@@ -781,6 +845,8 @@ private:
rdcarray<ShaderDebugState> *m_ShaderChangesReturn = NULL;
ShaderDebugState m_ActiveDebugState;
rdcarray<bool> m_QueuedDeviceThreadSteps;
// the live mutable global variables, to initialise a stack frame's live list
rdcarray<bool> m_LiveGlobals;
@@ -808,3 +874,5 @@ private:
}; // namespace DXILDebug
DECLARE_REFLECTION_ENUM(DXILDebug::StepThreadMode);
DECLARE_REFLECTION_ENUM(DXILDebug::DeviceOpResult);
DECLARE_REFLECTION_ENUM(DXILDebug::ThreadState::PendingResultStatus);
@@ -903,3 +903,16 @@ rdcstr DoStringise(const DXILDebug::StepThreadMode &el)
}
END_ENUM_STRINGISE();
};
template <>
rdcstr DoStringise(const DXILDebug::DeviceOpResult &el)
{
BEGIN_ENUM_STRINGISE(DXILDebug::DeviceOpResult)
{
STRINGISE_ENUM_CLASS(Unknown)
STRINGISE_ENUM_CLASS(Succeeded)
STRINGISE_ENUM_CLASS(Failed)
STRINGISE_ENUM_CLASS(NeedsDevice)
}
END_ENUM_STRINGISE();
};