From a70482830358eb587463b74820ddf7222e3864fc Mon Sep 17 00:00:00 2001 From: Jake Turner Date: Wed, 8 Oct 2025 15:52:55 +0100 Subject: [PATCH] DXIL Debugger Load operations copy from backing memory Don't use the cached value, fixes problems with GSM on a POD type (not array) Atomic operations always load GSM from global backing memory --- renderdoc/driver/shaders/dxil/dxil_debug.cpp | 72 ++++++++++++++++---- renderdoc/driver/shaders/dxil/dxil_debug.h | 7 +- 2 files changed, 64 insertions(+), 15 deletions(-) diff --git a/renderdoc/driver/shaders/dxil/dxil_debug.cpp b/renderdoc/driver/shaders/dxil/dxil_debug.cpp index d3d6f2f85..4f81e417a 100644 --- a/renderdoc/driver/shaders/dxil/dxil_debug.cpp +++ b/renderdoc/driver/shaders/dxil/dxil_debug.cpp @@ -5201,11 +5201,11 @@ bool ThreadState::ExecuteInstruction(const rdcarray &workgroup) result.value = arg.value; break; } - case Operation::Load: OperationLoad(inst, opCode, dxOpCode, resultId, result); break; + case Operation::Load: OperationLoad(false, inst, opCode, dxOpCode, resultId, result); break; case Operation::LoadAtomic: { SCOPED_LOCK(m_Debugger.GetAtomicMemoryLock()); - OperationLoad(inst, opCode, dxOpCode, resultId, result); + OperationLoad(true, inst, opCode, dxOpCode, resultId, result); break; } case Operation::Store: @@ -6571,6 +6571,38 @@ void ThreadState::UpdateGlobalBackingMemory(Id ptrId, const MemoryTracking::Poin } } +bool ThreadState::LoadGSMFromGlobalBackingMemory(const MemoryTracking::Pointer &ptr, + const MemoryTracking::Allocation &allocation, + ShaderVariable &var) +{ + const Id baseMemoryId = ptr.baseMemoryId; + auto globalMem = m_GlobalState.memory.m_Allocations.find(baseMemoryId); + if(globalMem != m_GlobalState.memory.m_Allocations.end()) + { + // Compute the local pointer offset and apply it to the global base memory + ptrdiff_t offset = (uintptr_t)ptr.memory - (uintptr_t)allocation.backingMemory; + if(offset >= 0) + { + const void *globalBackingMemory = globalMem->second.backingMemory; + void *globalMemory = (void *)((uintptr_t)globalBackingMemory + offset); + RDCASSERT(ptr.size <= sizeof(ShaderValue)); + if(ptr.size <= sizeof(ShaderValue)) + memcpy(&var.value, globalMemory, (size_t)ptr.size); + } + else + { + RDCERR("Invalid memory allocation offset baseMemoryId %u", baseMemoryId); + return false; + } + } + else + { + RDCERR("Invalid GSM baseMemoryId %u", baseMemoryId); + return false; + } + return true; +} + bool ThreadState::PerformGPUResourceOp(const rdcarray &workgroup, Operation opCode, DXOp dxOpCode, const ResourceReferenceInfo &resRefInfo, const DXIL::Instruction &inst, ShaderVariable &result) @@ -7350,7 +7382,7 @@ void ThreadState::QueueSampleGather(DXIL::DXOp dxOp, const SampleGatherResourceD SetStepNeedsGpuSampleGatherOp(); } -void ThreadState::OperationLoad(const DXIL::Instruction &inst, DXIL::Operation opCode, +void ThreadState::OperationLoad(bool isAtomic, const DXIL::Instruction &inst, DXIL::Operation opCode, DXIL::DXOp dxOpCode, Id &resultId, ShaderVariable &result) { if(DXIL::IsDXCNop(inst)) @@ -7381,18 +7413,22 @@ void ThreadState::OperationLoad(const DXIL::Instruction &inst, DXIL::Operation o RDCERR("Unknown memory allocation Id %u", baseMemoryId); return; } + const MemoryTracking::Allocation &allocation = itAlloc->second; - ShaderVariable arg; - if(allocation.globalVarAlloc && !IsVariableAssigned(ptrId)) + // active lane: Atomic Load for GSM then read from the global backing memory + if(m_HasDebugState && isAtomic && allocation.gsm) { - RDCASSERT(IsVariableAssigned(baseMemoryId)); - arg = m_Variables[baseMemoryId]; + if(!LoadGSMFromGlobalBackingMemory(ptr, allocation, result)) + RDCERR("OperationLoad: LoadGSMFromGlobalBackingMemory failed ptrId %u", ptrId); + return; } + + // Load from local backing memory + RDCASSERT(ptr.size <= sizeof(ShaderValue)); + if(ptr.size <= sizeof(ShaderValue)) + memcpy(&result.value, ptr.memory, (size_t)ptr.size); else - { - RDCASSERT(GetShaderVariable(inst.args[0], opCode, dxOpCode, arg)); - } - result.value = arg.value; + RDCERR("Size %u too large MAX %u for OperationLoad", ptr.size, sizeof(ShaderValue)); } void ThreadState::OperationStore(const DXIL::Instruction &inst, DXIL::Operation opCode, @@ -7440,7 +7476,7 @@ void ThreadState::OperationStore(const DXIL::Instruction &inst, DXIL::Operation UpdateMemoryVariableFromBackingMemory(baseMemoryId, allocation.backingMemory); // active lane : writes to a GSM variable, write to local and global backing memory - if(m_HasDebugState) + if(m_HasDebugState && allocation.gsm) UpdateGlobalBackingMemory(ptrId, ptr, allocation, val); // record the change to the base memory variable if it is not the ptrId variable @@ -7517,6 +7553,16 @@ void ThreadState::OperationAtomic(const DXIL::Instruction &inst, DXIL::Operation a = m_Variables[ptrId]; } + // GSM variable, read from the global backing memory + if(allocation.gsm) + { + if(!LoadGSMFromGlobalBackingMemory(ptr, allocation, a)) + { + RDCERR("OperationAtomic: LoadGSMFromGlobalBackingMemory failed ptrId %u", ptrId); + return; + } + } + size_t newValueArgIdx = (opCode == Operation::CompareExchange) ? 2 : 1; ShaderVariable b; RDCASSERT(GetShaderVariable(inst.args[newValueArgIdx], opCode, dxOpCode, b)); @@ -7639,7 +7685,7 @@ void ThreadState::OperationAtomic(const DXIL::Instruction &inst, DXIL::Operation UpdateMemoryVariableFromBackingMemory(baseMemoryId, allocMemoryBackingPtr); // active lane : writes to a GSM variable, write to local and global backing memory - if(m_HasDebugState) + if(m_HasDebugState && allocation.gsm) UpdateGlobalBackingMemory(ptrId, ptr, allocation, res); // record the change to the base memory variable diff --git a/renderdoc/driver/shaders/dxil/dxil_debug.h b/renderdoc/driver/shaders/dxil/dxil_debug.h index 94eda3e4d..c35d8e58f 100644 --- a/renderdoc/driver/shaders/dxil/dxil_debug.h +++ b/renderdoc/driver/shaders/dxil/dxil_debug.h @@ -624,6 +624,9 @@ private: void UpdateGlobalBackingMemory(Id ptrId, const MemoryTracking::Pointer &ptr, const MemoryTracking::Allocation &allocation, const ShaderVariable &val); + bool LoadGSMFromGlobalBackingMemory(const MemoryTracking::Pointer &ptr, + const MemoryTracking::Allocation &allocation, + ShaderVariable &var); bool PerformGPUResourceOp(const rdcarray &workgroup, DXIL::Operation opCode, DXIL::DXOp dxOpCode, const ResourceReferenceInfo &resRef, @@ -663,8 +666,8 @@ private: const int8_t texelOffsets[3], int multisampleIndex, float lodValue, float compareValue, GatherChannel gatherChannel, uint32_t instructionIdx, ShaderVariable &result); - void OperationLoad(const DXIL::Instruction &inst, DXIL::Operation opCode, DXIL::DXOp dxOpCode, - Id &resultId, ShaderVariable &result); + void OperationLoad(bool isAtomic, const DXIL::Instruction &inst, DXIL::Operation opCode, + DXIL::DXOp dxOpCode, Id &resultId, ShaderVariable &result); void OperationStore(const DXIL::Instruction &inst, DXIL::Operation opCode, DXIL::DXOp dxOpCode); void OperationAtomic(const DXIL::Instruction &inst, DXIL::Operation opCode, DXIL::DXOp dxOpCode, Id &resultId, ShaderVariable &result);