diff --git a/renderdoc/driver/shaders/spirv/spirv_debug.cpp b/renderdoc/driver/shaders/spirv/spirv_debug.cpp index 6b3f994af..bc1cc9cf5 100644 --- a/renderdoc/driver/shaders/spirv/spirv_debug.cpp +++ b/renderdoc/driver/shaders/spirv/spirv_debug.cpp @@ -5142,3 +5142,16 @@ rdcstr DoStringise(const rdcspv::StepThreadMode &el) } END_ENUM_STRINGISE(); }; + +template <> +rdcstr DoStringise(const rdcspv::DeviceOpResult &el) +{ + BEGIN_ENUM_STRINGISE(rdcspv::DeviceOpResult) + { + STRINGISE_ENUM_CLASS(Unknown) + STRINGISE_ENUM_CLASS(Succeeded) + STRINGISE_ENUM_CLASS(Failed) + STRINGISE_ENUM_CLASS(NeedsDevice) + } + END_ENUM_STRINGISE(); +}; diff --git a/renderdoc/driver/shaders/spirv/spirv_debug.h b/renderdoc/driver/shaders/spirv/spirv_debug.h index ee329b60c..e3807dc49 100644 --- a/renderdoc/driver/shaders/spirv/spirv_debug.h +++ b/renderdoc/driver/shaders/spirv/spirv_debug.h @@ -58,6 +58,14 @@ enum class ThreadProperty : uint32_t ITERABLE_OPERATORS(ThreadProperty); +enum class DeviceOpResult : uint32_t +{ + Unknown, + Succeeded, + Failed, + NeedsDevice, +}; + inline void AtomicStore(int32_t *var, int32_t newVal) { int32_t oldVal = *var; @@ -372,6 +380,7 @@ struct ThreadState AtomicStore(&atomic_isSimulationStepActive, 1); AtomicStore(&atomic_stepNeedsGpuSampleGatherOp, 0); AtomicStore(&atomic_stepNeedsGpuMathOp, 0); + AtomicStore(&atomic_stepNeedsDeviceThread, 0); } void SetStepNeedsGpuSampleGatherOp() { @@ -388,6 +397,12 @@ struct ThreadState SetPendingResultStatus(PendingResultStatus::Pending); } bool StepNeedsGpuMathOp() const { return (AtomicLoad(&atomic_stepNeedsGpuMathOp) == 1); } + void SetStepNeedsDeviceThread() + { + AtomicStore(&atomic_stepNeedsDeviceThread, 1); + SetPendingResultStatus(PendingResultStatus::Pending); + } + bool StepNeedsDeviceThread() const { return (AtomicLoad(&atomic_stepNeedsDeviceThread) == 1); } const GpuMathOperation &GetQueuedGpuMathOp() const { RDCASSERT(AtomicLoad(&atomic_stepNeedsGpuMathOp)); @@ -455,6 +470,7 @@ private: int32_t atomic_pendingResultStatus = (int32_t)PendingResultStatus::Unknown; int32_t atomic_stepNeedsGpuSampleGatherOp = 0; int32_t atomic_stepNeedsGpuMathOp = 0; + int32_t atomic_stepNeedsDeviceThread = 0; int32_t atomic_isSimulationStepActive = 0; }; @@ -757,6 +773,9 @@ private: void ClampScalars(const ShaderVariable &var, uint8_t &scalar0) const; void ClampScalars(const ShaderVariable &var, uint8_t &scalar0, uint8_t &scalar1) const; + void QueueDeviceThreadStep(uint32_t lane); + void ProcessQueuedDeviceThreadSteps(); + void QueueJob(uint32_t lane, rdcarray *ret); void StepThread(uint32_t lane, StepThreadMode stepMode, rdcarray *ret); void InternalStepThread(uint32_t lane, rdcarray *ret); @@ -772,6 +791,7 @@ private: mutable rdcarray queuedDebugMessages; rdcarray queuedGpuMathOps; rdcarray queuedGpuSampleGatherOps; + rdcarray queuedDeviceThreadSteps; rdcarray *shaderChangesReturn; bool retireIDs = true; @@ -792,3 +812,4 @@ void AssignValue(ShaderVariable &dst, const ShaderVariable &src); DECLARE_REFLECTION_ENUM(rdcspv::ThreadState::PendingResultStatus); DECLARE_REFLECTION_ENUM(rdcspv::StepThreadMode); +DECLARE_REFLECTION_ENUM(rdcspv::DeviceOpResult); diff --git a/renderdoc/driver/shaders/spirv/spirv_debug_setup.cpp b/renderdoc/driver/shaders/spirv/spirv_debug_setup.cpp index d0018b9d5..1cb6e3a7c 100644 --- a/renderdoc/driver/shaders/spirv/spirv_debug_setup.cpp +++ b/renderdoc/driver/shaders/spirv/spirv_debug_setup.cpp @@ -1024,12 +1024,14 @@ ShaderDebugTrace *Debugger::BeginDebug(DebugAPIWrapper *api, const ShaderStage s stage = shaderStage; apiWrapper = api; + queuedDeviceThreadSteps.resize(threadsInWorkgroup); queuedGpuMathOps.resize(threadsInWorkgroup); queuedGpuSampleGatherOps.resize(threadsInWorkgroup); pendingLanes.resize(threadsInWorkgroup); for(uint32_t i = 0; i < threadsInWorkgroup; i++) { workgroup.push_back(ThreadState(*this, global)); + queuedDeviceThreadSteps[i] = false; queuedGpuMathOps[i] = false; queuedGpuSampleGatherOps[i] = false; pendingLanes[i] = false; @@ -2693,6 +2695,7 @@ rdcarray Debugger::ContinueDebug() do { ProcessQueuedDebugMessages(); + ProcessQueuedDeviceThreadSteps(); // Convert the simulation threads queued operations into pending operations i.e. GPU commands ProcessQueuedOps(); // Sync any pending GPU operations and set the results to the pending threads @@ -4669,6 +4672,8 @@ void Debugger::StepThread(uint32_t lane, StepThreadMode stepMode, rdcarray *ret return; if(thread.StepNeedsGpuMathOp()) return; + if(thread.StepNeedsDeviceThread()) + return; if(!thread.IsPendingResultPending()) { @@ -4821,6 +4834,8 @@ void Debugger::InternalStepThread(uint32_t lane, rdcarray *ret return; if(thread.StepNeedsGpuMathOp()) return; + if(thread.StepNeedsDeviceThread()) + return; } } @@ -4856,6 +4871,32 @@ void Debugger::AddDebugMessage(MessageCategory c, MessageSeverity sv, MessageSou queuedDebugMessages.push_back({c, sv, src, d}); } +// Can be called from any thread +void Debugger::QueueDeviceThreadStep(uint32_t lane) +{ + ThreadState &thread = workgroup[lane]; + RDCASSERT(thread.IsSimulationStepActive()); + thread.SetStepQueued(); + RDCASSERT(!queuedDeviceThreadSteps[lane]); + 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 < queuedDeviceThreadSteps.size(); ++lane) + { + if(queuedDeviceThreadSteps[lane]) + { + queuedDeviceThreadSteps[lane] = false; + ThreadState &thread = workgroup[lane]; + thread.SetPendingResultUnknown(); + RDCASSERT(thread.IsSimulationStepActive()); + StepThread(lane, StepThreadMode::QUEUE_MULTIPLE_STEPS, shaderChangesReturn); + } + } +} }; // namespace rdcspv #if ENABLED(ENABLE_UNIT_TESTS)