From 516dec8e17a1094f7185ba17f19e08e5b07caf15 Mon Sep 17 00:00:00 2001 From: Jake Turner Date: Sat, 4 Oct 2025 11:56:08 +0100 Subject: [PATCH] DXIL debugger support for queue and run simulation on Device Thread --- renderdoc/driver/shaders/dxil/dxil_debug.cpp | 210 ++++++++++++++---- renderdoc/driver/shaders/dxil/dxil_debug.h | 88 +++++++- .../driver/shaders/dxil/dxil_stringise.cpp | 13 ++ 3 files changed, 262 insertions(+), 49 deletions(-) diff --git a/renderdoc/driver/shaders/dxil/dxil_debug.cpp b/renderdoc/driver/shaders/dxil/dxil_debug.cpp index 9a8bd9f2b..039bb5517 100644 --- a/renderdoc/driver/shaders/dxil/dxil_debug.cpp +++ b/renderdoc/driver/shaders/dxil/dxil_debug.cpp @@ -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 &oldLive, const rdcarray &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 &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 &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 &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 &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 &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 &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 &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 &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 &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 &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 &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 &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> &threadsBuiltins = @@ -10063,6 +10129,8 @@ rdcarray 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 diff --git a/renderdoc/driver/shaders/dxil/dxil_debug.h b/renderdoc/driver/shaders/dxil/dxil_debug.h index 1e4e64244..59802953a 100644 --- a/renderdoc/driver/shaders/dxil/dxil_debug.h +++ b/renderdoc/driver/shaders/dxil/dxil_debug.h @@ -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 &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 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 *m_ShaderChangesReturn = NULL; ShaderDebugState m_ActiveDebugState; + rdcarray m_QueuedDeviceThreadSteps; + // the live mutable global variables, to initialise a stack frame's live list rdcarray 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); diff --git a/renderdoc/driver/shaders/dxil/dxil_stringise.cpp b/renderdoc/driver/shaders/dxil/dxil_stringise.cpp index e859ec263..41b22c99b 100644 --- a/renderdoc/driver/shaders/dxil/dxil_stringise.cpp +++ b/renderdoc/driver/shaders/dxil/dxil_stringise.cpp @@ -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(); +};