From 11a4104bdefe9924331283f33d3c9450aa4610ef Mon Sep 17 00:00:00 2001 From: Jake Turner Date: Sat, 27 Sep 2025 08:37:49 +0100 Subject: [PATCH] DXIL Debugger support for thread local global memory --- renderdoc/driver/shaders/dxil/dxil_debug.cpp | 123 ++++++++++--------- renderdoc/driver/shaders/dxil/dxil_debug.h | 6 +- 2 files changed, 69 insertions(+), 60 deletions(-) diff --git a/renderdoc/driver/shaders/dxil/dxil_debug.cpp b/renderdoc/driver/shaders/dxil/dxil_debug.cpp index 26da702c9..a0f96ee9d 100644 --- a/renderdoc/driver/shaders/dxil/dxil_debug.cpp +++ b/renderdoc/driver/shaders/dxil/dxil_debug.cpp @@ -1686,8 +1686,8 @@ void ResourceReferenceInfo::Create(const DXIL::ResourceReference *resRef, uint32 } } -void MemoryTracking::AllocateMemoryForType(const DXIL::Type *type, Id allocId, bool global, - ShaderVariable &var) +void MemoryTracking::AllocateMemoryForType(const DXIL::Type *type, Id allocId, bool globalVar, + bool gsm, ShaderVariable &var) { RDCASSERTEQUAL(type->type, Type::TypeKind::Pointer); ConvertDXILTypeToShaderVariable(type->inner, var); @@ -1696,12 +1696,57 @@ void MemoryTracking::AllocateMemoryForType(const DXIL::Type *type, Id allocId, b size_t byteSize = ComputeDXILTypeByteSize(type->inner); void *backingMem = malloc(byteSize); memset(backingMem, 0, byteSize); - m_Allocations[allocId] = {backingMem, byteSize, global, !global}; + // Invalid: gsm = false and globalVar = true + RDCASSERT(!gsm || globalVar); + m_Allocations[allocId] = {backingMem, byteSize, globalVar, gsm, !globalVar}; // Create a pointer to represent this allocation m_Pointers[allocId] = {allocId, backingMem, byteSize}; } +void MemoryTracking::ConvertGlobalAllocToLocal(Id allocId) +{ + MemoryTracking::Allocation &alloc = m_Allocations[allocId]; + RDCASSERT(alloc.globalVarAlloc); + RDCASSERT(!alloc.localMemory); + void *globalBackingMemory = alloc.backingMemory; + const size_t allocSize = (size_t)alloc.size; + void *localBackingMemory = malloc(allocSize); + memcpy(localBackingMemory, globalBackingMemory, allocSize); + alloc.backingMemory = localBackingMemory; + alloc.localMemory = true; + + // Update the pointer for the base memory allocation + MemoryTracking::Pointer &allocPtr = m_Pointers[allocId]; + allocPtr.memory = localBackingMemory; + RDCASSERTEQUAL(allocPtr.baseMemoryId, allocId); + RDCASSERTEQUAL(allocPtr.size, alloc.size); + + // Update pointers which pointed to within the memory allocation + for(auto &itPtr : m_Pointers) + { + MemoryTracking::Pointer &ptr = itPtr.second; + Id baseMemoryId = ptr.baseMemoryId; + if(baseMemoryId != allocId) + continue; + + Id ptrId = itPtr.first; + // pointers for backing allocations have already have been updated + if(ptrId == baseMemoryId) + continue; + + ptrdiff_t offset = (uintptr_t)ptr.memory - (uintptr_t)globalBackingMemory; + if(offset < 0) + { + RDCERR("Invalid memory allocation offset ptrId %u BaseMemoryId %u", ptrId, baseMemoryId); + continue; + } + void *localMemory = (void *)((uintptr_t)localBackingMemory + offset); + RDCASSERTEQUAL(ptr.baseMemoryId, baseMemoryId); + ptr.memory = localMemory; + } +} + ThreadState::ThreadState(Debugger &debugger, const GlobalState &globalState, uint32_t maxSSAId) : m_Debugger(debugger), m_GlobalState(globalState), @@ -1810,6 +1855,17 @@ void ThreadState::EnterEntryPoint(const Function *function, ShaderDebugState *st // Start with the global memory allocations m_Memory = m_GlobalState.memory; + // Create per thread memory for non-groupshared global memory + for(auto &it : m_Memory.m_Allocations) + { + Id allocId = it.first; + MemoryTracking::Allocation &alloc = it.second; + + RDCASSERT(alloc.globalVarAlloc); + if(!alloc.gsm) + m_Memory.ConvertGlobalAllocToLocal(allocId); + } + m_State = NULL; } @@ -5335,7 +5391,7 @@ bool ThreadState::ExecuteInstruction(DebugAPIWrapper *apiWrapper, case Operation::Alloca: { result.name = DXBC::BasicDemangle(result.name); - m_Memory.AllocateMemoryForType(inst.type, resultId, false, result); + m_Memory.AllocateMemoryForType(inst.type, resultId, false, false, result); break; } case Operation::GetElementPtr: @@ -8854,7 +8910,8 @@ ShaderDebugTrace *Debugger::BeginDebug(uint32_t eventId, const DXBC::DXBCContain DXIL::SanitiseName(n); globalVar.var.name = n; globalVar.id = gv->ssaId; - globalMemory.AllocateMemoryForType(gv->type, globalVar.id, true, globalVar.var); + globalVar.gsm = (gv->type->addrSpace == DXIL::Type::PointerAddrSpace::GroupShared); + globalMemory.AllocateMemoryForType(gv->type, globalVar.id, true, globalVar.gsm, globalVar.var); if(gv->initialiser) { const Constant *initialData = gv->initialiser; @@ -8877,7 +8934,7 @@ ShaderDebugTrace *Debugger::BeginDebug(uint32_t eventId, const DXBC::DXBCContain } } } - if(gv->type->addrSpace == DXIL::Type::PointerAddrSpace::GroupShared) + if(globalVar.gsm) m_GlobalState.groupSharedMemoryIds.push_back(globalVar.id); m_GlobalState.globals.push_back(globalVar); m_LiveGlobals[globalVar.id] = true; @@ -9679,59 +9736,7 @@ rdcarray Debugger::ContinueDebug(DebugAPIWrapper *apiWrapper) // active lane : needs it own local backing memory, copied from global at the start for(Id id : m_GlobalState.groupSharedMemoryIds) - { - MemoryTracking::Allocation &globalAlloc = m_GlobalState.memory.m_Allocations[id]; - RDCASSERT(globalAlloc.globalVarAlloc); - const size_t allocSize = (size_t)globalAlloc.size; - void *localBackingMem = malloc(allocSize); - memcpy(localBackingMem, globalAlloc.backingMemory, allocSize); - active.m_Memory.m_Allocations[id] = {localBackingMem, globalAlloc.size, true, true}; - active.m_Memory.m_Pointers[id] = {id, localBackingMem, globalAlloc.size}; - } - // active lane: update the backing memory pointer of any pointers to the new local allocations - for(const auto &itGlobalPtr : m_GlobalState.memory.m_Pointers) - { - const MemoryTracking::Pointer &globalPtr = itGlobalPtr.second; - Id ptrId = itGlobalPtr.first; - Id baseMemoryId = globalPtr.baseMemoryId; - // pointers for backing allocations have already have been updated - if(ptrId == baseMemoryId) - continue; - - auto itAlloc = m_GlobalState.memory.m_Allocations.find(baseMemoryId); - if(itAlloc == m_GlobalState.memory.m_Allocations.end()) - { - RDCERR("Could not find global backing memory allocation for ptr %u BaseMemoryId %u", ptrId, - baseMemoryId); - continue; - } - const MemoryTracking::Allocation &globalAlloc = itAlloc->second; - ptrdiff_t offset = (uintptr_t)globalPtr.memory - (uintptr_t)globalAlloc.backingMemory; - if(offset < 0) - { - RDCERR("Invalid memory allocation offset ptrId %u BaseMemoryId %u", ptrId, baseMemoryId); - continue; - } - itAlloc = active.m_Memory.m_Allocations.find(baseMemoryId); - if(itAlloc == active.m_Memory.m_Allocations.end()) - { - RDCERR("Could not find local backing memory allocation for ptr %u BaseMemoryId %u", ptrId, - baseMemoryId); - continue; - } - const MemoryTracking::Allocation &localAlloc = itAlloc->second; - void *localMemory = (void *)((uintptr_t)localAlloc.backingMemory + offset); - auto itLocalPtr = active.m_Memory.m_Pointers.find(ptrId); - if(itLocalPtr == active.m_Memory.m_Pointers.end()) - { - RDCERR("Could not find local ptr %u", ptrId); - continue; - } - MemoryTracking::Pointer &localPtr = itLocalPtr->second; - RDCASSERTEQUAL(localPtr.baseMemoryId, baseMemoryId); - RDCASSERTEQUAL(localPtr.size, globalPtr.size); - localPtr.memory = localMemory; - } + active.m_Memory.ConvertGlobalAllocToLocal(id); // globals won't be filled out by entering the entry point, ensure their change is registered. for(const GlobalVariable &gv : m_GlobalState.globals) diff --git a/renderdoc/driver/shaders/dxil/dxil_debug.h b/renderdoc/driver/shaders/dxil/dxil_debug.h index 645e7d2ec..0809a74fb 100644 --- a/renderdoc/driver/shaders/dxil/dxil_debug.h +++ b/renderdoc/driver/shaders/dxil/dxil_debug.h @@ -122,6 +122,7 @@ struct GlobalVariable { Id id; ShaderVariable var; + bool gsm; }; struct GlobalConstant @@ -203,7 +204,9 @@ public: struct MemoryTracking { - void AllocateMemoryForType(const DXIL::Type *type, Id allocId, bool global, ShaderVariable &var); + void AllocateMemoryForType(const DXIL::Type *type, Id allocId, bool globalVar, bool gsm, + ShaderVariable &var); + void ConvertGlobalAllocToLocal(Id allocId); // Represents actual memory allocations (think of it like a memory heap) struct Allocation @@ -212,6 +215,7 @@ struct MemoryTracking void *backingMemory; uint64_t size; bool globalVarAlloc; + bool gsm; bool localMemory; };