From 0e20fbf9fb010f34b983691cdc98621454d2f959 Mon Sep 17 00:00:00 2001 From: Jake Turner Date: Tue, 30 Sep 2025 16:20:43 +0100 Subject: [PATCH] Added caching to DXIL APIWrapper and Debugger Added TypedUAV Load/Store to APIWrapper --- renderdoc/driver/d3d12/d3d12_dxil_debug.cpp | 688 ++++++++++++++++--- renderdoc/driver/d3d12/d3d12_dxil_debug.h | 87 ++- renderdoc/driver/shaders/dxil/dxil_debug.cpp | 457 +++--------- renderdoc/driver/shaders/dxil/dxil_debug.h | 56 +- 4 files changed, 824 insertions(+), 464 deletions(-) diff --git a/renderdoc/driver/d3d12/d3d12_dxil_debug.cpp b/renderdoc/driver/d3d12/d3d12_dxil_debug.cpp index cae75bf7a..7fe58bd76 100644 --- a/renderdoc/driver/d3d12/d3d12_dxil_debug.cpp +++ b/renderdoc/driver/d3d12/d3d12_dxil_debug.cpp @@ -27,6 +27,7 @@ #include "d3d12_dxil_debug.h" #include "data/hlsl/hlsl_cbuffers.h" #include "driver/dxgi/dxgi_common.h" +#include "maths/formatpacking.h" #include "d3d12_command_queue.h" #include "d3d12_debug.h" #include "d3d12_replay.h" @@ -45,6 +46,300 @@ using namespace DXILDebug; namespace DXILDebug { +static ShaderValue TypedUAVLoad(const DXILDebug::ViewFmt &fmt, const byte *base, uint64_t offset) +{ + const byte *data = base + offset; + ShaderValue result; + result.f32v[0] = 0.0f; + result.f32v[1] = 0.0f; + result.f32v[2] = 0.0f; + result.f32v[3] = 0.0f; + + if(fmt.byteWidth == 10) + { + uint32_t u; + memcpy(&u, data, sizeof(uint32_t)); + + if(fmt.compType == CompType::UInt) + { + result.u32v[0] = (u >> 0) & 0x3ff; + result.u32v[1] = (u >> 10) & 0x3ff; + result.u32v[2] = (u >> 20) & 0x3ff; + result.u32v[3] = (u >> 30) & 0x003; + } + else if(fmt.compType == CompType::UNorm) + { + Vec4f res = ConvertFromR10G10B10A2(u); + result.f32v[0] = res.x; + result.f32v[1] = res.y; + result.f32v[2] = res.z; + result.f32v[3] = res.w; + } + else + { + RDCERR("Unexpected format type on buffer resource"); + } + } + else if(fmt.byteWidth == 11) + { + uint32_t u; + memcpy(&u, data, sizeof(uint32_t)); + + Vec3f res = ConvertFromR11G11B10(u); + result.f32v[0] = res.x; + result.f32v[1] = res.y; + result.f32v[2] = res.z; + result.f32v[3] = 1.0f; + } + else + { + if(fmt.byteWidth == 4) + { + const uint32_t *u = (const uint32_t *)data; + + for(int c = 0; c < fmt.numComps; c++) + result.u32v[c] = u[c]; + } + else if(fmt.byteWidth == 2) + { + if(fmt.compType == CompType::Float) + { + const uint16_t *u = (const uint16_t *)data; + + for(int c = 0; c < fmt.numComps; c++) + result.f32v[c] = ConvertFromHalf(u[c]); + } + else if(fmt.compType == CompType::UInt) + { + const uint16_t *u = (const uint16_t *)data; + + for(int c = 0; c < fmt.numComps; c++) + result.u32v[c] = u[c]; + } + else if(fmt.compType == CompType::SInt) + { + const int16_t *in = (const int16_t *)data; + + for(int c = 0; c < fmt.numComps; c++) + result.s32v[c] = in[c]; + } + else if(fmt.compType == CompType::UNorm || fmt.compType == CompType::UNormSRGB) + { + const uint16_t *u = (const uint16_t *)data; + + for(int c = 0; c < fmt.numComps; c++) + result.f32v[c] = float(u[c]) / float(0xffff); + } + else if(fmt.compType == CompType::SNorm) + { + const int16_t *in = (const int16_t *)data; + + for(int c = 0; c < fmt.numComps; c++) + { + // -32768 is mapped to -1, then -32767 to -32767 are mapped to -1 to 1 + if(in[c] == -32768) + result.f32v[c] = -1.0f; + else + result.f32v[c] = float(in[c]) / 32767.0f; + } + } + else + { + RDCERR("Unexpected format type on buffer resource"); + } + } + else if(fmt.byteWidth == 1) + { + if(fmt.compType == CompType::UInt) + { + const uint8_t *u = (const uint8_t *)data; + + for(int c = 0; c < fmt.numComps; c++) + result.u32v[c] = u[c]; + } + else if(fmt.compType == CompType::SInt) + { + const int8_t *in = (const int8_t *)data; + + for(int c = 0; c < fmt.numComps; c++) + result.s32v[c] = in[c]; + } + else if(fmt.compType == CompType::UNorm || fmt.compType == CompType::UNormSRGB) + { + const uint8_t *u = (const uint8_t *)data; + + for(int c = 0; c < fmt.numComps; c++) + result.f32v[c] = float(u[c]) / float(0xff); + } + else if(fmt.compType == CompType::SNorm) + { + const int8_t *in = (const int8_t *)data; + + for(int c = 0; c < fmt.numComps; c++) + { + // -128 is mapped to -1, then -127 to -127 are mapped to -1 to 1 + if(in[c] == -128) + result.f32v[c] = -1.0f; + else + result.f32v[c] = float(in[c]) / 127.0f; + } + } + else + { + RDCERR("Unexpected format type on buffer resource"); + } + } + + // fill in alpha with 1.0 or 1 as appropriate + if(fmt.numComps < 4) + { + if(fmt.compType == CompType::UNorm || fmt.compType == CompType::UNormSRGB || + fmt.compType == CompType::SNorm || fmt.compType == CompType::Float) + result.f32v[3] = 1.0f; + else + result.u32v[3] = 1; + } + } + + return result; +} + +static void TypedUAVStore(const DXILDebug::ViewFmt &fmt, byte *base, uint64_t offset, + const ShaderValue &value) +{ + byte *data = base + offset; + if(fmt.byteWidth == 10) + { + uint32_t u = 0; + + if(fmt.compType == CompType::UInt) + { + u |= (value.u32v[0] & 0x3ff) << 0; + u |= (value.u32v[1] & 0x3ff) << 10; + u |= (value.u32v[2] & 0x3ff) << 20; + u |= (value.u32v[3] & 0x3) << 30; + } + else if(fmt.compType == CompType::UNorm) + { + u = ConvertToR10G10B10A2(Vec4f(value.f32v[0], value.f32v[1], value.f32v[2], value.f32v[3])); + } + else + { + RDCERR("Unexpected format type on buffer resource"); + } + memcpy(data, &u, sizeof(uint32_t)); + } + else if(fmt.byteWidth == 11) + { + uint32_t u = ConvertToR11G11B10(Vec3f(value.f32v[0], value.f32v[1], value.f32v[2])); + memcpy(data, &u, sizeof(uint32_t)); + } + else if(fmt.byteWidth == 4) + { + uint32_t *u = (uint32_t *)data; + + for(int c = 0; c < fmt.numComps; c++) + u[c] = value.u32v[c]; + } + else if(fmt.byteWidth == 2) + { + if(fmt.compType == CompType::Float) + { + uint16_t *u = (uint16_t *)data; + + for(int c = 0; c < fmt.numComps; c++) + u[c] = ConvertToHalf(value.f32v[c]); + } + else if(fmt.compType == CompType::UInt) + { + uint16_t *u = (uint16_t *)data; + + for(int c = 0; c < fmt.numComps; c++) + u[c] = value.u32v[c] & 0xffff; + } + else if(fmt.compType == CompType::SInt) + { + int16_t *i = (int16_t *)data; + + for(int c = 0; c < fmt.numComps; c++) + i[c] = (int16_t)RDCCLAMP(value.s32v[c], (int32_t)INT16_MIN, (int32_t)INT16_MAX); + } + else if(fmt.compType == CompType::UNorm || fmt.compType == CompType::UNormSRGB) + { + uint16_t *u = (uint16_t *)data; + + for(int c = 0; c < fmt.numComps; c++) + { + float f = RDCCLAMP(value.f32v[c], 0.0f, 1.0f) * float(0xffff) + 0.5f; + u[c] = uint16_t(f); + } + } + else if(fmt.compType == CompType::SNorm) + { + int16_t *i = (int16_t *)data; + + for(int c = 0; c < fmt.numComps; c++) + { + float f = RDCCLAMP(value.f32v[c], -1.0f, 1.0f) * 0x7fff; + + if(f < 0.0f) + i[c] = int16_t(f - 0.5f); + else + i[c] = int16_t(f + 0.5f); + } + } + else + { + RDCERR("Unexpected format type on buffer resource"); + } + } + else if(fmt.byteWidth == 1) + { + if(fmt.compType == CompType::UInt) + { + uint8_t *u = (uint8_t *)data; + + for(int c = 0; c < fmt.numComps; c++) + u[c] = value.u32v[c] & 0xff; + } + else if(fmt.compType == CompType::SInt) + { + int8_t *i = (int8_t *)data; + + for(int c = 0; c < fmt.numComps; c++) + i[c] = (int8_t)RDCCLAMP(value.s32v[c], (int32_t)INT8_MIN, (int32_t)INT8_MAX); + } + else if(fmt.compType == CompType::UNorm || fmt.compType == CompType::UNormSRGB) + { + uint8_t *u = (uint8_t *)data; + + for(int c = 0; c < fmt.numComps; c++) + { + float f = RDCCLAMP(value.f32v[c], 0.0f, 1.0f) * float(0xff) + 0.5f; + u[c] = uint8_t(f); + } + } + else if(fmt.compType == CompType::SNorm) + { + int8_t *i = (int8_t *)data; + + for(int c = 0; c < fmt.numComps; c++) + { + float f = RDCCLAMP(value.f32v[c], -1.0f, 1.0f) * 0x7f; + + if(f < 0.0f) + i[c] = int8_t(f - 0.5f); + else + i[c] = int8_t(f + 0.5f); + } + } + else + { + RDCERR("Unexpected format type on buffer resource"); + } + } +} + static DXBC::ResourceRetType ConvertCompTypeToResourceRetType(const CompType compType) { switch(compType) @@ -721,11 +1016,45 @@ void D3D12APIWrapper::AddCBufferToGlobalState(const BindingSlot &slot, bytebuf & } } +// Called from any thread +// Resource must be cached +ShaderValue D3D12APIWrapper::TypedSRVLoad(const BindingSlot &slot, const DXILDebug::ViewFmt &fmt, + uint64_t dataOffset) const +{ + SCOPED_READLOCK(m_SRVsLock); + auto it = m_SRVBuffers.find(slot); + if(it == m_SRVBuffers.end()) + { + RDCERR("Load SRV slot %u space %u no cached data", slot.shaderRegister, slot.registerSpace); + return ShaderValue(); + } + const bytebuf &data = it->second; + return DXILDebug::TypedUAVLoad(fmt, data.data(), dataOffset); +} + +// Called from any thread +// Resource must be cached +bool D3D12APIWrapper::TypedSRVStore(const BindingSlot &slot, const DXILDebug::ViewFmt &fmt, + uint64_t dataOffset, const ShaderValue &value) +{ + SCOPED_READLOCK(m_SRVsLock); + auto it = m_SRVBuffers.find(slot); + if(it == m_SRVBuffers.end()) + { + RDCERR("Store SRV slot %u space %u no cached data", slot.shaderRegister, slot.registerSpace); + return false; + } + bytebuf &data = it->second; + DXILDebug::TypedUAVStore(fmt, data.data(), dataOffset, value); + return true; +} + // Must be called from the replay manager thread (the debugger thread) -SRVData &D3D12APIWrapper::FetchSRV(const D3D12Descriptor *resDescriptor, const BindingSlot &slot) +SRVInfo D3D12APIWrapper::FetchSRV(const D3D12Descriptor *resDescriptor, const BindingSlot &slot) { CHECK_DEVICE_THREAD(); - SRVData &srvData = m_SRVs[slot]; + SRVInfo srvData; + bytebuf data; if(resDescriptor) { D3D12ResourceManager *rm = m_Device->GetResourceManager(); @@ -760,16 +1089,25 @@ SRVData &D3D12APIWrapper::FetchSRV(const D3D12Descriptor *resDescriptor, const B if(mdStride != 0) srvData.resInfo.format.stride = mdStride; - m_Device->GetDebugManager()->GetBufferData(pResource, 0, 0, srvData.data); + m_Device->GetDebugManager()->GetBufferData(pResource, 0, 0, data); } // Textures are sampled via a pixel shader, so there's no need to copy their data } } + srvData.resInfo.hasData = data.data() != NULL; + srvData.resInfo.dataSize = data.size(); + { + SCOPED_WRITELOCK(m_SRVsLock); + auto it = m_SRVInfos.insert(std::make_pair(slot, srvData)); + RDCASSERT(it.second); + auto bufferIt = m_SRVBuffers.insert(std::make_pair(slot, data)); + RDCASSERT(bufferIt.second); + } return srvData; } // Must be called from the replay manager thread (the debugger thread) -SRVData &D3D12APIWrapper::FetchSRV(const BindingSlot &slot) +SRVInfo D3D12APIWrapper::FetchSRV(const BindingSlot &slot) { CHECK_DEVICE_THREAD(); // the resources might be dirty from side-effects, replay back to right before it. @@ -785,6 +1123,8 @@ SRVData &D3D12APIWrapper::FetchSRV(const BindingSlot &slot) return FetchSRV(&srvDesc, slot); } + SRVInfo srvData; + bytebuf data; const D3D12RenderState &rs = m_Device->GetQueue()->GetCommandData()->m_RenderState; D3D12ResourceManager *rm = m_Device->GetResourceManager(); @@ -819,7 +1159,6 @@ SRVData &D3D12APIWrapper::FetchSRV(const BindingSlot &slot) if(param.Descriptor.ShaderRegister == slot.shaderRegister && param.Descriptor.RegisterSpace == slot.registerSpace) { - SRVData &srvData = m_SRVs[slot]; // Found the requested SRV ID3D12Resource *pResource = rm->GetCurrentAs(element.id); if(pResource) @@ -848,10 +1187,18 @@ SRVData &D3D12APIWrapper::FetchSRV(const BindingSlot &slot) DXILDebug::GetSRVBufferStrideFromShaderMetadata(m_EntryPointInterface, slot); if(mdStride != 0) srvData.resInfo.format.stride = mdStride; - m_Device->GetDebugManager()->GetBufferData(pResource, element.offset, 0, - srvData.data); + m_Device->GetDebugManager()->GetBufferData(pResource, element.offset, 0, data); } } + srvData.resInfo.hasData = data.data() != NULL; + srvData.resInfo.dataSize = data.size(); + { + SCOPED_WRITELOCK(m_SRVsLock); + auto it = m_SRVInfos.insert(std::make_pair(slot, srvData)); + RDCASSERT(it.second); + auto bufferIt = m_SRVBuffers.insert(std::make_pair(slot, data)); + RDCASSERT(bufferIt.second); + } return srvData; } } @@ -906,19 +1253,61 @@ SRVData &D3D12APIWrapper::FetchSRV(const BindingSlot &slot) RDCERR("Couldn't find root signature parameter corresponding to SRV %u in space %u", slot.shaderRegister, slot.registerSpace); - return m_SRVs[slot]; + { + SCOPED_WRITELOCK(m_SRVsLock); + m_SRVInfos[slot] = srvData; + } + return srvData; } RDCERR("No root signature bound, couldn't identify SRV %u in space %u", slot.shaderRegister, slot.registerSpace); - return m_SRVs[slot]; + { + SCOPED_WRITELOCK(m_SRVsLock); + m_SRVInfos[slot] = srvData; + } + return srvData; +} + +// Called from any thread +// Resource must be cached +ShaderValue D3D12APIWrapper::TypedUAVLoad(const BindingSlot &slot, const DXILDebug::ViewFmt &fmt, + uint64_t dataOffset) const +{ + SCOPED_READLOCK(m_UAVsLock); + auto it = m_UAVBuffers.find(slot); + if(it == m_UAVBuffers.end()) + { + RDCERR("Load UAV slot %u space %u no cached data", slot.shaderRegister, slot.registerSpace); + return ShaderValue(); + } + const bytebuf &data = it->second; + return DXILDebug::TypedUAVLoad(fmt, data.data(), dataOffset); +} + +// Called from any thread +// Resource must be cached +bool D3D12APIWrapper::TypedUAVStore(const BindingSlot &slot, const DXILDebug::ViewFmt &fmt, + uint64_t dataOffset, const ShaderValue &value) +{ + SCOPED_READLOCK(m_UAVsLock); + auto it = m_UAVBuffers.find(slot); + if(it == m_UAVBuffers.end()) + { + RDCERR("Store UAV slot %u space %u no cached data", slot.shaderRegister, slot.registerSpace); + return false; + } + bytebuf &data = it->second; + DXILDebug::TypedUAVStore(fmt, data.data(), dataOffset, value); + return true; } // Must be called from the replay manager thread (the debugger thread) -UAVData &D3D12APIWrapper::FetchUAV(const D3D12Descriptor *resDescriptor, const BindingSlot &slot) +UAVInfo D3D12APIWrapper::FetchUAV(const D3D12Descriptor *resDescriptor, const BindingSlot &slot) { CHECK_DEVICE_THREAD(); - UAVData &uavData = m_UAVs[slot]; + UAVInfo uavData; + bytebuf data; if(resDescriptor) { D3D12ResourceManager *rm = m_Device->GetResourceManager(); @@ -950,13 +1339,12 @@ UAVData &D3D12APIWrapper::FetchUAV(const D3D12Descriptor *resDescriptor, const B if(mdStride != 0) uavData.resInfo.format.stride = mdStride; - m_Device->GetDebugManager()->GetBufferData(pResource, 0, 0, uavData.data); + m_Device->GetDebugManager()->GetBufferData(pResource, 0, 0, data); } else { uavData.tex = true; - m_Device->GetReplay()->GetTextureData(uavId, Subresource(), GetTextureDataParams(), - uavData.data); + m_Device->GetReplay()->GetTextureData(uavId, Subresource(), GetTextureDataParams(), data); uavDesc.Format = D3D12ShaderDebug::GetUAVResourceFormat(uavDesc, pResource); DXILDebug::FillViewFmtFromResourceFormat(uavDesc.Format, uavData.resInfo.format); @@ -967,11 +1355,20 @@ UAVData &D3D12APIWrapper::FetchUAV(const D3D12Descriptor *resDescriptor, const B } } } + uavData.resInfo.hasData = data.data() != NULL; + uavData.resInfo.dataSize = data.size(); + { + SCOPED_WRITELOCK(m_UAVsLock); + auto it = m_UAVInfos.insert(std::make_pair(slot, uavData)); + RDCASSERT(it.second); + auto bufferIt = m_UAVBuffers.insert(std::make_pair(slot, data)); + RDCASSERT(bufferIt.second); + } return uavData; } // Must be called from the replay manager thread (the debugger thread) -UAVData &D3D12APIWrapper::FetchUAV(const BindingSlot &slot) +UAVInfo D3D12APIWrapper::FetchUAV(const BindingSlot &slot) { CHECK_DEVICE_THREAD(); // the resources might be dirty from side-effects, replay back to right before it. @@ -987,6 +1384,8 @@ UAVData &D3D12APIWrapper::FetchUAV(const BindingSlot &slot) return FetchUAV(&uavDesc, slot); } + UAVInfo uavData; + bytebuf data; const D3D12RenderState &rs = m_Device->GetQueue()->GetCommandData()->m_RenderState; D3D12ResourceManager *rm = m_Device->GetResourceManager(); @@ -1023,7 +1422,6 @@ UAVData &D3D12APIWrapper::FetchUAV(const BindingSlot &slot) { // Found the requested UAV ID3D12Resource *pResource = rm->GetCurrentAs(element.id); - UAVData &uavData = m_UAVs[slot]; if(pResource) { @@ -1052,11 +1450,19 @@ UAVData &D3D12APIWrapper::FetchUAV(const BindingSlot &slot) DXILDebug::GetUAVBufferStrideFromShaderMetadata(m_EntryPointInterface, slot); if(mdStride != 0) uavData.resInfo.format.stride = mdStride; - m_Device->GetDebugManager()->GetBufferData(pResource, element.offset, 0, - uavData.data); + m_Device->GetDebugManager()->GetBufferData(pResource, element.offset, 0, data); } } + uavData.resInfo.hasData = data.data() != NULL; + uavData.resInfo.dataSize = data.size(); + { + SCOPED_WRITELOCK(m_UAVsLock); + auto it = m_UAVInfos.insert(std::make_pair(slot, uavData)); + RDCASSERT(it.second); + auto bufferIt = m_UAVBuffers.insert(std::make_pair(slot, data)); + RDCASSERT(bufferIt.second); + } return uavData; } } @@ -1111,60 +1517,60 @@ UAVData &D3D12APIWrapper::FetchUAV(const BindingSlot &slot) RDCERR("Couldn't find root signature parameter corresponding to UAV %u in space %u", slot.shaderRegister, slot.registerSpace); - return m_UAVs[slot]; + { + SCOPED_WRITELOCK(m_UAVsLock); + m_UAVInfos[slot] = uavData; + } + return uavData; } RDCERR("No root signature bound, couldn't identify UAV %u in space %u", slot.shaderRegister, slot.registerSpace); - return m_UAVs[slot]; -} - -// Called from any thread -bool D3D12APIWrapper::IsSRVCached(const BindingSlot &slot) -{ - SCOPED_READLOCK(m_SRVsLock); - return m_SRVs.find(slot) != m_SRVs.end(); -} - -// Must be called from the replay manager thread (the debugger thread) -const SRVData &D3D12APIWrapper::GetSRVData(const BindingSlot &slot) -{ - CHECK_DEVICE_THREAD(); - { - SCOPED_READLOCK(m_SRVsLock); - auto it = m_SRVs.find(slot); - if(it != m_SRVs.end()) - return it->second; - } - - { - SCOPED_WRITELOCK(m_SRVsLock); - return FetchSRV(slot); - } -} - -// Called from any thread -bool D3D12APIWrapper::IsUAVCached(const BindingSlot &slot) -{ - SCOPED_READLOCK(m_UAVsLock); - return m_UAVs.find(slot) != m_UAVs.end(); -} - -// Must be called from the replay manager thread (the debugger thread) -const UAVData &D3D12APIWrapper::GetUAVData(const BindingSlot &slot) -{ - CHECK_DEVICE_THREAD(); - { - SCOPED_READLOCK(m_UAVsLock); - auto it = m_UAVs.find(slot); - if(it != m_UAVs.end()) - return it->second; - } - { SCOPED_WRITELOCK(m_UAVsLock); - return FetchUAV(slot); + m_UAVInfos[slot] = uavData; } + return uavData; +} + +// Called from any thread +bool D3D12APIWrapper::IsSRVCached(const BindingSlot &slot) const +{ + SCOPED_READLOCK(m_SRVsLock); + return m_SRVInfos.find(slot) != m_SRVInfos.end(); +} + +// Called from any thread +SRVInfo D3D12APIWrapper::GetSRV(const BindingSlot &slot) +{ + { + SCOPED_READLOCK(m_SRVsLock); + auto it = m_SRVInfos.find(slot); + if(it != m_SRVInfos.end()) + return it->second; + } + + return FetchSRV(slot); +} + +// Called from any thread +bool D3D12APIWrapper::IsUAVCached(const BindingSlot &slot) const +{ + SCOPED_READLOCK(m_UAVsLock); + return m_UAVInfos.find(slot) != m_UAVInfos.end(); +} + +// Called from any thread +UAVInfo D3D12APIWrapper::GetUAV(const BindingSlot &slot) +{ + { + SCOPED_READLOCK(m_UAVsLock); + auto it = m_UAVInfos.find(slot); + if(it != m_UAVInfos.end()) + return it->second; + } + + return FetchUAV(slot); } // Must be called from the replay manager thread (the debugger thread) @@ -1242,10 +1648,38 @@ bool D3D12APIWrapper::CalculateSampleGather( instructionIdx, opString, output); } -// Must be called from the replay manager thread (the debugger thread) +// Called from any thread +bool D3D12APIWrapper::IsResourceInfoCached(const DXDebug::BindingSlot &slot, uint32_t mipLevel) +{ + SCOPED_READLOCK(m_ResourceInfosLock); + ResourceInfoMiplevel resInfoMip = {slot, mipLevel}; + return m_ResourceInfos.find(resInfoMip) != m_ResourceInfos.end(); +} + +// Called from any thread +// Caller guarantees that if the data is not cached then we are on the device thread ShaderVariable D3D12APIWrapper::GetResourceInfo(DXIL::ResourceClass resClass, - const DXDebug::BindingSlot &slot, - uint32_t mipLevel) const + const DXDebug::BindingSlot &slot, uint32_t mipLevel) +{ + ResourceInfoMiplevel resInfoMip = {slot, mipLevel}; + { + SCOPED_READLOCK(m_ResourceInfosLock); + auto it = m_ResourceInfos.find(resInfoMip); + if(it != m_ResourceInfos.end()) + return it->second; + } + CHECK_DEVICE_THREAD(); + ShaderVariable resourceInfo = FetchResourceInfo(resClass, slot, mipLevel); + { + SCOPED_WRITELOCK(m_ResourceInfosLock); + m_ResourceInfos[resInfoMip] = resourceInfo; + return resourceInfo; + } +} + +// Must be called from the replay manager thread (the debugger thread) +ShaderVariable D3D12APIWrapper::FetchResourceInfo(DXIL::ResourceClass resClass, + const DXDebug::BindingSlot &slot, uint32_t mipLevel) { CHECK_DEVICE_THREAD(); D3D12_DESCRIPTOR_RANGE_TYPE descType; @@ -1264,10 +1698,37 @@ ShaderVariable D3D12APIWrapper::GetResourceInfo(DXIL::ResourceClass resClass, true); } -// Must be called from the replay manager thread (the debugger thread) +// Called from any thread +bool D3D12APIWrapper::IsSampleInfoCached(const DXDebug::BindingSlot &slot) +{ + SCOPED_READLOCK(m_SampleInfosLock); + return m_SampleInfos.find(slot) != m_SampleInfos.end(); +} + +// Called from any thread +// Caller guarantees that if the data is not cached then we are on the device thread ShaderVariable D3D12APIWrapper::GetSampleInfo(DXIL::ResourceClass resClass, - const DXDebug::BindingSlot &slot, - const char *opString) const + const DXDebug::BindingSlot &slot, const char *opString) +{ + { + SCOPED_READLOCK(m_SampleInfosLock); + auto it = m_SampleInfos.find(slot); + if(it != m_SampleInfos.end()) + return it->second; + } + CHECK_DEVICE_THREAD(); + ShaderVariable sampleInfo = FetchSampleInfo(resClass, slot, opString); + { + SCOPED_WRITELOCK(m_SampleInfosLock); + m_SampleInfos[slot] = sampleInfo; + return sampleInfo; + } +} + +// Must be called from the replay manager thread (the debugger thread) +ShaderVariable D3D12APIWrapper::FetchSampleInfo(DXIL::ResourceClass resClass, + const DXDebug::BindingSlot &slot, + const char *opString) { CHECK_DEVICE_THREAD(); D3D12_DESCRIPTOR_RANGE_TYPE descType; @@ -1284,15 +1745,61 @@ ShaderVariable D3D12APIWrapper::GetSampleInfo(DXIL::ResourceClass resClass, return D3D12ShaderDebug::GetSampleInfo(m_Device, descType, slot, m_ShaderType, opString); } -// Must be called from the replay manager thread (the debugger thread) -ShaderVariable D3D12APIWrapper::GetRenderTargetSampleInfo(const char *opString) const +// Called from any thread +bool D3D12APIWrapper::IsRenderTargetSampleInfoCached() { + SCOPED_READLOCK(m_RenderTargetSampleInfoLock); + return m_RenderTargetSampleInfoValid; +} + +// Called from any thread +// Caller guarantees that if the data is not cached then we are on the device thread +ShaderVariable D3D12APIWrapper::GetRenderTargetSampleInfo(const char *opString) +{ + { + SCOPED_READLOCK(m_RenderTargetSampleInfoLock); + if(m_RenderTargetSampleInfoValid) + return m_RenderTargetSampleInfo; + } CHECK_DEVICE_THREAD(); - return D3D12ShaderDebug::GetRenderTargetSampleInfo(m_Device, m_ShaderType, opString); + ShaderVariable renderTargetSampleInfo = + D3D12ShaderDebug::GetRenderTargetSampleInfo(m_Device, m_ShaderType, opString); + { + SCOPED_WRITELOCK(m_RenderTargetSampleInfoLock); + m_RenderTargetSampleInfoValid = true; + m_RenderTargetSampleInfo = renderTargetSampleInfo; + return m_RenderTargetSampleInfo; + } +} + +// Called from any thread +bool D3D12APIWrapper::IsResourceReferenceInfoCached(const DXDebug::BindingSlot &slot) +{ + SCOPED_READLOCK(m_ResourceReferenceInfosLock); + return m_ResourceReferenceInfos.find(slot) != m_ResourceReferenceInfos.end(); +} + +// Called from any thread +// Caller guarantees that if the data is not cached then we are on the device thread +ResourceReferenceInfo D3D12APIWrapper::GetResourceReferenceInfo(const DXDebug::BindingSlot &slot) +{ + { + SCOPED_READLOCK(m_ResourceReferenceInfosLock); + auto it = m_ResourceReferenceInfos.find(slot); + if(it != m_ResourceReferenceInfos.end()) + return it->second; + } + CHECK_DEVICE_THREAD(); + ResourceReferenceInfo resRefInfo = FetchResourceReferenceInfo(slot); + { + SCOPED_WRITELOCK(m_ResourceReferenceInfosLock); + m_ResourceReferenceInfos[slot] = resRefInfo; + return resRefInfo; + } } // Must be called from the replay manager thread (the debugger thread) -ResourceReferenceInfo D3D12APIWrapper::GetResourceReferenceInfo(const DXDebug::BindingSlot &slot) const +ResourceReferenceInfo D3D12APIWrapper::FetchResourceReferenceInfo(const DXDebug::BindingSlot &slot) { CHECK_DEVICE_THREAD(); const HeapDescriptorType heapType = slot.heapType; @@ -1390,9 +1897,36 @@ ResourceReferenceInfo D3D12APIWrapper::GetResourceReferenceInfo(const DXDebug::B return resRefInfo; } -// Must be called from the replay manager thread (the debugger thread) +// Called from any thread +bool D3D12APIWrapper::IsShaderDirectAccessCached(const DXDebug::BindingSlot &slot) +{ + SCOPED_READLOCK(m_ShaderDirectAccessesLock); + return m_ShaderDirectAccesses.find(slot) != m_ShaderDirectAccesses.end(); +} + +// Called from any thread +// Caller guarantees that if the data is not cached then we are on the device thread ShaderDirectAccess D3D12APIWrapper::GetShaderDirectAccess(DescriptorType type, - const DXDebug::BindingSlot &slot) const + const DXDebug::BindingSlot &slot) +{ + { + SCOPED_READLOCK(m_ShaderDirectAccessesLock); + auto it = m_ShaderDirectAccesses.find(slot); + if(it != m_ShaderDirectAccesses.end()) + return it->second; + } + CHECK_DEVICE_THREAD(); + ShaderDirectAccess access = FetchShaderDirectAccess(type, slot); + { + SCOPED_WRITELOCK(m_ShaderDirectAccessesLock); + m_ShaderDirectAccesses[slot] = access; + return access; + } +} + +// Must be called from the replay manager thread (the debugger thread) +ShaderDirectAccess D3D12APIWrapper::FetchShaderDirectAccess(DescriptorType type, + const DXDebug::BindingSlot &slot) { CHECK_DEVICE_THREAD(); const HeapDescriptorType heapType = slot.heapType; diff --git a/renderdoc/driver/d3d12/d3d12_dxil_debug.h b/renderdoc/driver/d3d12/d3d12_dxil_debug.h index 0d3701b37..b17ffbce5 100644 --- a/renderdoc/driver/d3d12/d3d12_dxil_debug.h +++ b/renderdoc/driver/d3d12/d3d12_dxil_debug.h @@ -43,8 +43,16 @@ public: void FetchConstantBufferData(const D3D12RenderState::RootSignature &rootsig); - const UAVData &GetUAVData(const BindingSlot &slot) override; - const SRVData &GetSRVData(const BindingSlot &slot) override; + ShaderValue TypedUAVLoad(const BindingSlot &slot, const DXILDebug::ViewFmt &fmt, + uint64_t dataOffset) const override; + ShaderValue TypedSRVLoad(const BindingSlot &slot, const DXILDebug::ViewFmt &fmt, + uint64_t dataOffset) const override; + bool TypedUAVStore(const BindingSlot &slot, const DXILDebug::ViewFmt &fmt, uint64_t dataOffset, + const ShaderValue &value) override; + bool TypedSRVStore(const BindingSlot &slot, const DXILDebug::ViewFmt &fmt, uint64_t dataOffset, + const ShaderValue &value) override; + UAVInfo GetUAV(const BindingSlot &slot) override; + SRVInfo GetSRV(const BindingSlot &slot) override; bool CalculateMathIntrinsic(DXIL::DXOp dxOp, const ShaderVariable &input, ShaderVariable &output) override; @@ -56,16 +64,21 @@ public: uint32_t instructionIdx, ShaderVariable &output) override; ShaderVariable GetResourceInfo(DXIL::ResourceClass resClass, const DXDebug::BindingSlot &slot, - uint32_t mipLevel) const override; + uint32_t mipLevel) override; ShaderVariable GetSampleInfo(DXIL::ResourceClass resClass, const DXDebug::BindingSlot &slot, - const char *opString) const override; - ShaderVariable GetRenderTargetSampleInfo(const char *opString) const override; - ResourceReferenceInfo GetResourceReferenceInfo(const DXDebug::BindingSlot &slot) const override; + const char *opString) override; + ShaderVariable GetRenderTargetSampleInfo(const char *opString) override; + ResourceReferenceInfo GetResourceReferenceInfo(const DXDebug::BindingSlot &slot) override; ShaderDirectAccess GetShaderDirectAccess(DescriptorType type, - const DXDebug::BindingSlot &slot) const override; + const DXDebug::BindingSlot &slot) override; - bool IsSRVCached(const DXDebug::BindingSlot &slot) override; - bool IsUAVCached(const DXDebug::BindingSlot &slot) override; + bool IsSRVCached(const DXDebug::BindingSlot &slot) const override; + bool IsUAVCached(const DXDebug::BindingSlot &slot) const override; + bool IsResourceInfoCached(const DXDebug::BindingSlot &slot, uint32_t mipLevel) override; + bool IsSampleInfoCached(const DXDebug::BindingSlot &slot) override; + bool IsRenderTargetSampleInfoCached() override; + bool IsResourceReferenceInfoCached(const DXDebug::BindingSlot &slot) override; + bool IsShaderDirectAccessCached(const DXDebug::BindingSlot &slot) override; void ResetReplay(); @@ -119,11 +132,18 @@ private: const rdcarray &invars, rdcarray &outvars, const rdcstr &prefix, uint32_t baseOffset); - SRVData &FetchSRV(const BindingSlot &slot); - SRVData &FetchSRV(const D3D12Descriptor *resDescriptor, const BindingSlot &slot); + SRVInfo FetchSRV(const BindingSlot &slot); + SRVInfo FetchSRV(const D3D12Descriptor *resDescriptor, const BindingSlot &slot); - UAVData &FetchUAV(const BindingSlot &slot); - UAVData &FetchUAV(const D3D12Descriptor *resDescriptor, const BindingSlot &slot); + UAVInfo FetchUAV(const BindingSlot &slot); + UAVInfo FetchUAV(const D3D12Descriptor *resDescriptor, const BindingSlot &slot); + + ShaderVariable FetchResourceInfo(DXIL::ResourceClass resClass, const DXDebug::BindingSlot &slot, + uint32_t mipLevel); + ShaderVariable FetchSampleInfo(DXIL::ResourceClass resClass, const DXDebug::BindingSlot &slot, + const char *opString); + ResourceReferenceInfo FetchResourceReferenceInfo(const DXDebug::BindingSlot &slot); + ShaderDirectAccess FetchShaderDirectAccess(DescriptorType type, const DXDebug::BindingSlot &slot); BuiltinInputs m_Builtins; rdcarray m_WorkgroupProperties; @@ -135,10 +155,43 @@ private: ShaderVariable m_InputPlaceholder; uint32_t m_SubgroupSize = 1; - Threading::RWLock m_UAVsLock; - std::map m_UAVs; - Threading::RWLock m_SRVsLock; - std::map m_SRVs; + struct ResourceInfoMiplevel + { + BindingSlot slot; + uint32_t mipLevel; + + bool operator<(const ResourceInfoMiplevel &o) const + { + if(mipLevel == o.mipLevel) + return slot < o.slot; + return mipLevel < o.mipLevel; + } + + bool operator==(const ResourceInfoMiplevel &o) const + { + return slot == o.slot && mipLevel == o.mipLevel; + } + }; + + mutable Threading::RWLock m_UAVsLock; + std::map m_UAVInfos; + std::map m_UAVBuffers; + mutable Threading::RWLock m_SRVsLock; + std::map m_SRVInfos; + std::map m_SRVBuffers; + Threading::RWLock m_ResourceInfosLock; + std::map m_ResourceInfos; + Threading::RWLock m_SampleInfosLock; + std::map m_SampleInfos; + Threading::RWLock m_ResourceReferenceInfosLock; + std::map m_ResourceReferenceInfos; + + Threading::RWLock m_RenderTargetSampleInfoLock; + ShaderVariable m_RenderTargetSampleInfo; + bool m_RenderTargetSampleInfoValid = false; + + Threading::RWLock m_ShaderDirectAccessesLock; + std::map m_ShaderDirectAccesses; const ShaderReflection &m_Reflection; WrappedID3D12Device *m_Device = NULL; diff --git a/renderdoc/driver/shaders/dxil/dxil_debug.cpp b/renderdoc/driver/shaders/dxil/dxil_debug.cpp index 2d6ce56ae..a7aea61d1 100644 --- a/renderdoc/driver/shaders/dxil/dxil_debug.cpp +++ b/renderdoc/driver/shaders/dxil/dxil_debug.cpp @@ -1240,297 +1240,6 @@ static size_t ComputeDXILTypeByteSize(const Type *type) return byteSize; } -static void TypedUAVStore(DXILDebug::ViewFmt &fmt, byte *d, const ShaderValue &value) -{ - if(fmt.byteWidth == 10) - { - uint32_t u = 0; - - if(fmt.compType == CompType::UInt) - { - u |= (value.u32v[0] & 0x3ff) << 0; - u |= (value.u32v[1] & 0x3ff) << 10; - u |= (value.u32v[2] & 0x3ff) << 20; - u |= (value.u32v[3] & 0x3) << 30; - } - else if(fmt.compType == CompType::UNorm) - { - u = ConvertToR10G10B10A2(Vec4f(value.f32v[0], value.f32v[1], value.f32v[2], value.f32v[3])); - } - else - { - RDCERR("Unexpected format type on buffer resource"); - } - memcpy(d, &u, sizeof(uint32_t)); - } - else if(fmt.byteWidth == 11) - { - uint32_t u = ConvertToR11G11B10(Vec3f(value.f32v[0], value.f32v[1], value.f32v[2])); - memcpy(d, &u, sizeof(uint32_t)); - } - else if(fmt.byteWidth == 4) - { - uint32_t *u = (uint32_t *)d; - - for(int c = 0; c < fmt.numComps; c++) - u[c] = value.u32v[c]; - } - else if(fmt.byteWidth == 2) - { - if(fmt.compType == CompType::Float) - { - uint16_t *u = (uint16_t *)d; - - for(int c = 0; c < fmt.numComps; c++) - u[c] = ConvertToHalf(value.f32v[c]); - } - else if(fmt.compType == CompType::UInt) - { - uint16_t *u = (uint16_t *)d; - - for(int c = 0; c < fmt.numComps; c++) - u[c] = value.u32v[c] & 0xffff; - } - else if(fmt.compType == CompType::SInt) - { - int16_t *i = (int16_t *)d; - - for(int c = 0; c < fmt.numComps; c++) - i[c] = (int16_t)RDCCLAMP(value.s32v[c], (int32_t)INT16_MIN, (int32_t)INT16_MAX); - } - else if(fmt.compType == CompType::UNorm || fmt.compType == CompType::UNormSRGB) - { - uint16_t *u = (uint16_t *)d; - - for(int c = 0; c < fmt.numComps; c++) - { - float f = RDCCLAMP(value.f32v[c], 0.0f, 1.0f) * float(0xffff) + 0.5f; - u[c] = uint16_t(f); - } - } - else if(fmt.compType == CompType::SNorm) - { - int16_t *i = (int16_t *)d; - - for(int c = 0; c < fmt.numComps; c++) - { - float f = RDCCLAMP(value.f32v[c], -1.0f, 1.0f) * 0x7fff; - - if(f < 0.0f) - i[c] = int16_t(f - 0.5f); - else - i[c] = int16_t(f + 0.5f); - } - } - else - { - RDCERR("Unexpected format type on buffer resource"); - } - } - else if(fmt.byteWidth == 1) - { - if(fmt.compType == CompType::UInt) - { - uint8_t *u = (uint8_t *)d; - - for(int c = 0; c < fmt.numComps; c++) - u[c] = value.u32v[c] & 0xff; - } - else if(fmt.compType == CompType::SInt) - { - int8_t *i = (int8_t *)d; - - for(int c = 0; c < fmt.numComps; c++) - i[c] = (int8_t)RDCCLAMP(value.s32v[c], (int32_t)INT8_MIN, (int32_t)INT8_MAX); - } - else if(fmt.compType == CompType::UNorm || fmt.compType == CompType::UNormSRGB) - { - uint8_t *u = (uint8_t *)d; - - for(int c = 0; c < fmt.numComps; c++) - { - float f = RDCCLAMP(value.f32v[c], 0.0f, 1.0f) * float(0xff) + 0.5f; - u[c] = uint8_t(f); - } - } - else if(fmt.compType == CompType::SNorm) - { - int8_t *i = (int8_t *)d; - - for(int c = 0; c < fmt.numComps; c++) - { - float f = RDCCLAMP(value.f32v[c], -1.0f, 1.0f) * 0x7f; - - if(f < 0.0f) - i[c] = int8_t(f - 0.5f); - else - i[c] = int8_t(f + 0.5f); - } - } - else - { - RDCERR("Unexpected format type on buffer resource"); - } - } -} - -static ShaderValue TypedUAVLoad(DXILDebug::ViewFmt &fmt, const byte *d) -{ - ShaderValue result; - result.f32v[0] = 0.0f; - result.f32v[1] = 0.0f; - result.f32v[2] = 0.0f; - result.f32v[3] = 0.0f; - - if(fmt.byteWidth == 10) - { - uint32_t u; - memcpy(&u, d, sizeof(uint32_t)); - - if(fmt.compType == CompType::UInt) - { - result.u32v[0] = (u >> 0) & 0x3ff; - result.u32v[1] = (u >> 10) & 0x3ff; - result.u32v[2] = (u >> 20) & 0x3ff; - result.u32v[3] = (u >> 30) & 0x003; - } - else if(fmt.compType == CompType::UNorm) - { - Vec4f res = ConvertFromR10G10B10A2(u); - result.f32v[0] = res.x; - result.f32v[1] = res.y; - result.f32v[2] = res.z; - result.f32v[3] = res.w; - } - else - { - RDCERR("Unexpected format type on buffer resource"); - } - } - else if(fmt.byteWidth == 11) - { - uint32_t u; - memcpy(&u, d, sizeof(uint32_t)); - - Vec3f res = ConvertFromR11G11B10(u); - result.f32v[0] = res.x; - result.f32v[1] = res.y; - result.f32v[2] = res.z; - result.f32v[3] = 1.0f; - } - else - { - if(fmt.byteWidth == 4) - { - const uint32_t *u = (const uint32_t *)d; - - for(int c = 0; c < fmt.numComps; c++) - result.u32v[c] = u[c]; - } - else if(fmt.byteWidth == 2) - { - if(fmt.compType == CompType::Float) - { - const uint16_t *u = (const uint16_t *)d; - - for(int c = 0; c < fmt.numComps; c++) - result.f32v[c] = ConvertFromHalf(u[c]); - } - else if(fmt.compType == CompType::UInt) - { - const uint16_t *u = (const uint16_t *)d; - - for(int c = 0; c < fmt.numComps; c++) - result.u32v[c] = u[c]; - } - else if(fmt.compType == CompType::SInt) - { - const int16_t *in = (const int16_t *)d; - - for(int c = 0; c < fmt.numComps; c++) - result.s32v[c] = in[c]; - } - else if(fmt.compType == CompType::UNorm || fmt.compType == CompType::UNormSRGB) - { - const uint16_t *u = (const uint16_t *)d; - - for(int c = 0; c < fmt.numComps; c++) - result.f32v[c] = float(u[c]) / float(0xffff); - } - else if(fmt.compType == CompType::SNorm) - { - const int16_t *in = (const int16_t *)d; - - for(int c = 0; c < fmt.numComps; c++) - { - // -32768 is mapped to -1, then -32767 to -32767 are mapped to -1 to 1 - if(in[c] == -32768) - result.f32v[c] = -1.0f; - else - result.f32v[c] = float(in[c]) / 32767.0f; - } - } - else - { - RDCERR("Unexpected format type on buffer resource"); - } - } - else if(fmt.byteWidth == 1) - { - if(fmt.compType == CompType::UInt) - { - const uint8_t *u = (const uint8_t *)d; - - for(int c = 0; c < fmt.numComps; c++) - result.u32v[c] = u[c]; - } - else if(fmt.compType == CompType::SInt) - { - const int8_t *in = (const int8_t *)d; - - for(int c = 0; c < fmt.numComps; c++) - result.s32v[c] = in[c]; - } - else if(fmt.compType == CompType::UNorm || fmt.compType == CompType::UNormSRGB) - { - const uint8_t *u = (const uint8_t *)d; - - for(int c = 0; c < fmt.numComps; c++) - result.f32v[c] = float(u[c]) / float(0xff); - } - else if(fmt.compType == CompType::SNorm) - { - const int8_t *in = (const int8_t *)d; - - for(int c = 0; c < fmt.numComps; c++) - { - // -128 is mapped to -1, then -127 to -127 are mapped to -1 to 1 - if(in[c] == -128) - result.f32v[c] = -1.0f; - else - result.f32v[c] = float(in[c]) / 127.0f; - } - } - else - { - RDCERR("Unexpected format type on buffer resource"); - } - } - - // fill in alpha with 1.0 or 1 as appropriate - if(fmt.numComps < 4) - { - if(fmt.compType == CompType::UNorm || fmt.compType == CompType::UNormSRGB || - fmt.compType == CompType::SNorm || fmt.compType == CompType::Float) - result.f32v[3] = 1.0f; - else - result.u32v[3] = 1; - } - } - - return result; -} - void ConvertTypeToViewFormat(const DXIL::Type *type, DXILDebug::ViewFmt &fmt) { // variable should be a pointer to the underlying type @@ -1945,10 +1654,8 @@ void ThreadState::EnterEntryPoint(const Function *function, bool hasDebugState) UpdateCurrentInstruction(); } -// Must be called from the replay manager thread (the debugger thread) void ThreadState::FillCallstack(ShaderDebugState &state) { - THREADSTATE_CHECK_DEBUGGER_THREAD(); if(m_FunctionInfo->callstacks.size() == 1) { state.callstack = m_FunctionInfo->callstacks.begin()->second; @@ -2376,7 +2083,6 @@ bool ThreadState::ExecuteInstruction(const rdcarray &workgroup) } break; } - MarkResourceAccess(handleVar); const bool load = (dxOpCode == DXOp::TextureLoad) || (dxOpCode == DXOp::BufferLoad) || (dxOpCode == DXOp::RawBufferLoad); @@ -2434,8 +2140,6 @@ bool ThreadState::ExecuteInstruction(const rdcarray &workgroup) } uint32_t structOffset = 0; - const byte *data = NULL; - size_t dataSize = 0; bool texData = false; uint32_t rowPitch = 0; uint32_t depthPitch = 0; @@ -2449,31 +2153,43 @@ bool ThreadState::ExecuteInstruction(const rdcarray &workgroup) RDCASSERT((resClass == ResourceClass::SRV || resClass == ResourceClass::UAV), resClass); ResourceInfo resInfo; + DeviceOpResult opResult = DeviceOpResult::Unknown; + const BindingSlot &slot = resRefInfo.binding; switch(resClass) { case ResourceClass::UAV: { - const UAVData &uav = m_Debugger.GetUAVData(resRefInfo.binding); - resInfo = uav.resInfo; - data = uav.data.data(); - dataSize = uav.data.size(); - texData = uav.tex; - rowPitch = uav.rowPitch; - depthPitch = uav.depthPitch; + UAVInfo uav; + opResult = m_Debugger.GetUAV(slot, uav); + if(opResult == DeviceOpResult::Succeeded) + { + resInfo = uav.resInfo; + texData = uav.tex; + rowPitch = uav.rowPitch; + depthPitch = uav.depthPitch; + } break; } case ResourceClass::SRV: { - const SRVData &srv = m_Debugger.GetSRVData(resRefInfo.binding); - resInfo = srv.resInfo; - data = srv.data.data(); - dataSize = srv.data.size(); + SRVInfo srv; + opResult = m_Debugger.GetSRV(slot, srv); + if(opResult == DeviceOpResult::Succeeded) + { + resInfo = srv.resInfo; + } break; } default: RDCERR("Unexpected ResourceClass %s", ToStr(resClass).c_str()); break; } + if(opResult == DeviceOpResult::NeedsDevice) + { + SetStepNeedsDeviceThread(); + break; + } + MarkResourceAccess(handleVar); // Unbound resource - if(data == NULL) + if(!resInfo.hasData) { if(load) { @@ -2577,6 +2293,7 @@ bool ThreadState::ExecuteInstruction(const rdcarray &workgroup) dataOffset += structOffset; } + const uint64_t dataSize = resInfo.dataSize; // NULL resource or out of bounds if((!texData && elemIdx >= numElems) || (texData && dataOffset >= dataSize)) { @@ -2590,7 +2307,6 @@ bool ThreadState::ExecuteInstruction(const rdcarray &workgroup) } else { - data += dataOffset; int numComps = fmt.numComps; int maxNumComps = fmt.numComps; // Clamp the number of components to read based on the amount of data in the buffer @@ -2606,7 +2322,7 @@ bool ThreadState::ExecuteInstruction(const rdcarray &workgroup) // For stores load the whole data, update the component, save the whole data back // This is to support per component writes to packed formats - result.value = TypedUAVLoad(fmt, data); + result.value = m_Debugger.TypedResourceLoad(resClass, slot, fmt, dataOffset); // Zero out any out of bounds components if(fmt.numComps < numComps) @@ -2632,7 +2348,7 @@ bool ThreadState::ExecuteInstruction(const rdcarray &workgroup) } } fmt.numComps = RDCMIN(numComps, maxNumComps); - TypedUAVStore(fmt, (byte *)data, result.value); + m_Debugger.TypedResourceStore(resClass, slot, fmt, dataOffset, result.value); } } break; @@ -2990,15 +2706,11 @@ bool ThreadState::ExecuteInstruction(const rdcarray &workgroup) { const uint32_t dataOffset = regIndex * 16; const uint32_t byteWidth = 4; - const byte *data = cbufferData.data() + dataOffset; + const byte *base = cbufferData.data() + dataOffset; + const uint32_t *data = (const uint32_t *)base; const uint32_t numComps = RDCMIN(4U, (bufferSize - dataOffset) / byteWidth); - ViewFmt cbufferFmt; - cbufferFmt.byteWidth = byteWidth; - cbufferFmt.numComps = numComps; - cbufferFmt.compType = CompType::Float; - cbufferFmt.stride = 16; - - result.value = TypedUAVLoad(cbufferFmt, data); + for(uint32_t c = 0; c < numComps; c++) + result.value.u32v[c] = data[c]; } } else @@ -3596,7 +3308,6 @@ bool ThreadState::ExecuteInstruction(const rdcarray &workgroup) ResourceReferenceInfo resRefInfo = GetResource(handleId, annotatedHandle, handleVar); if(!resRefInfo.Valid()) break; - MarkResourceAccess(handleVar); ResourceClass resClass = resRefInfo.resClass; // handle must be a UAV @@ -3610,8 +3321,6 @@ bool ThreadState::ExecuteInstruction(const rdcarray &workgroup) ShaderVariable a; uint32_t structOffset = 0; - const byte *data = NULL; - size_t dataSize = 0; bool texData = false; uint32_t rowPitch = 0; uint32_t depthPitch = 0; @@ -3619,16 +3328,22 @@ bool ThreadState::ExecuteInstruction(const rdcarray &workgroup) uint32_t numElems = 0; ViewFmt fmt; - const UAVData &uav = m_Debugger.GetUAVData(resRefInfo.binding); - const ResourceInfo resInfo = uav.resInfo; - data = uav.data.data(); - dataSize = uav.data.size(); - texData = uav.tex; - rowPitch = uav.rowPitch; - depthPitch = uav.depthPitch; + const BindingSlot &slot = resRefInfo.binding; + UAVInfo uavInfo; + if(m_Debugger.GetUAV(slot, uavInfo) == DeviceOpResult::NeedsDevice) + { + SetStepNeedsDeviceThread(); + break; + } + MarkResourceAccess(handleVar); + + const ResourceInfo resInfo = uavInfo.resInfo; + texData = uavInfo.tex; + rowPitch = uavInfo.rowPitch; + depthPitch = uavInfo.depthPitch; // Unbound resource - if(data == NULL) + if(!resInfo.hasData) { RDCERR("Unbound resource %s", GetArgumentName(1).c_str()); a.value.u32v[0] = 0; @@ -3722,6 +3437,7 @@ bool ThreadState::ExecuteInstruction(const rdcarray &workgroup) dataOffset += (firstElem + elemIdx) * stride; } + const uint64_t dataSize = resInfo.dataSize; // NULL resource or out of bounds if((!texData && elemIdx >= numElems) || (texData && dataOffset >= dataSize)) { @@ -3732,7 +3448,6 @@ bool ThreadState::ExecuteInstruction(const rdcarray &workgroup) } else { - data += dataOffset; // Clamp the number of components to read based on the amount of data in the buffer if(!texData) { @@ -3743,7 +3458,7 @@ bool ThreadState::ExecuteInstruction(const rdcarray &workgroup) maxNumComps = (int)((maxOffset - dataOffset) / fmt.byteWidth); fmt.numComps = RDCMIN(fmt.numComps, maxNumComps); } - a.value = TypedUAVLoad(fmt, data); + a.value = m_Debugger.TypedResourceLoad(resClass, slot, fmt, dataOffset); } ShaderVariable b; @@ -3864,7 +3579,7 @@ bool ThreadState::ExecuteInstruction(const rdcarray &workgroup) } else { - TypedUAVStore(fmt, (byte *)data, res.value); + m_Debugger.TypedResourceStore(resClass, slot, fmt, dataOffset, res.value); } } @@ -10373,18 +10088,63 @@ const FunctionInfo *Debugger::GetFunctionInfo(const DXIL::Function *function) co return &m_FunctionInfos.at(function); } -// Must be called from the replay manager thread (the debugger thread) -const UAVData &Debugger::GetUAVData(const BindingSlot &slot) const +// Called from any thread +// Resource must be cached +ShaderValue Debugger::TypedResourceLoad(DXIL::ResourceClass resClass, const BindingSlot &slot, + const DXILDebug::ViewFmt &fmt, uint64_t dataOffset) { - CHECK_DEBUGGER_THREAD(); - return m_ApiWrapper->GetUAVData(slot); + if(resClass == DXIL::ResourceClass::UAV) + { + DXIL_DEBUG_RDCASSERT(m_ApiWrapper->IsUAVCached(slot)); + return m_ApiWrapper->TypedUAVLoad(slot, fmt, dataOffset); + } + else if(resClass == DXIL::ResourceClass::SRV) + { + DXIL_DEBUG_RDCASSERT(m_ApiWrapper->IsSRVCached(slot)); + return m_ApiWrapper->TypedSRVLoad(slot, fmt, dataOffset); + } + RDCERR("Unexpected resource class %s", ToStr(resClass).c_str()); + return ShaderValue(); } -// Must be called from the replay manager thread (the debugger thread) -const SRVData &Debugger::GetSRVData(const BindingSlot &slot) const +// Called from any thread +// Resource must be cached +bool Debugger::TypedResourceStore(DXIL::ResourceClass resClass, const BindingSlot &slot, + const DXILDebug::ViewFmt &fmt, uint64_t dataOffset, + ShaderValue &value) { - CHECK_DEBUGGER_THREAD(); - return m_ApiWrapper->GetSRVData(slot); + if(resClass == DXIL::ResourceClass::UAV) + { + DXIL_DEBUG_RDCASSERT(m_ApiWrapper->IsUAVCached(slot)); + return m_ApiWrapper->TypedUAVStore(slot, fmt, dataOffset, value); + } + else if(resClass == DXIL::ResourceClass::SRV) + { + DXIL_DEBUG_RDCASSERT(m_ApiWrapper->IsSRVCached(slot)); + return m_ApiWrapper->TypedSRVStore(slot, fmt, dataOffset, value); + } + RDCERR("Unexpected resource class %s", ToStr(resClass).c_str()); + return false; +} + +// Called from any thread +DeviceOpResult Debugger::GetUAV(const BindingSlot &slot, UAVInfo &uavInfo) const +{ + if(!IsDeviceThread() && !m_ApiWrapper->IsUAVCached(slot)) + return DeviceOpResult::NeedsDevice; + + uavInfo = m_ApiWrapper->GetUAV(slot); + return DeviceOpResult::Succeeded; +} + +// Called from any thread +DeviceOpResult Debugger::GetSRV(const BindingSlot &slot, SRVInfo &srvInfo) const +{ + if(!IsDeviceThread() && !m_ApiWrapper->IsSRVCached(slot)) + return DeviceOpResult::NeedsDevice; + + srvInfo = m_ApiWrapper->GetSRV(slot); + return DeviceOpResult::Succeeded; } // Called from any thread @@ -10392,10 +10152,9 @@ DeviceOpResult Debugger::GetResourceInfo(DXIL::ResourceClass resClass, const DXDebug::BindingSlot &slot, uint32_t mipLevel, ShaderVariable &result) const { - if(!IsDeviceThread()) + if(!IsDeviceThread() && !m_ApiWrapper->IsResourceInfoCached(slot, mipLevel)) return DeviceOpResult::NeedsDevice; - CHECK_DEBUGGER_THREAD(); result = m_ApiWrapper->GetResourceInfo(resClass, slot, mipLevel); return DeviceOpResult::Succeeded; } @@ -10404,10 +10163,9 @@ DeviceOpResult Debugger::GetResourceInfo(DXIL::ResourceClass resClass, DeviceOpResult Debugger::GetSampleInfo(DXIL::ResourceClass resClass, const DXDebug::BindingSlot &slot, const char *opString, ShaderVariable &result) const { - if(!IsDeviceThread()) + if(!IsDeviceThread() && !m_ApiWrapper->IsSampleInfoCached(slot)) return DeviceOpResult::NeedsDevice; - CHECK_DEBUGGER_THREAD(); result = m_ApiWrapper->GetSampleInfo(resClass, slot, opString); return DeviceOpResult::Succeeded; } @@ -10415,10 +10173,9 @@ DeviceOpResult Debugger::GetSampleInfo(DXIL::ResourceClass resClass, const DXDeb // Called from any thread DeviceOpResult Debugger::GetRenderTargetSampleInfo(const char *opString, ShaderVariable &result) const { - if(!IsDeviceThread()) + if(!IsDeviceThread() && !m_ApiWrapper->IsRenderTargetSampleInfoCached()) return DeviceOpResult::NeedsDevice; - CHECK_DEBUGGER_THREAD(); result = m_ApiWrapper->GetRenderTargetSampleInfo(opString); return DeviceOpResult::Succeeded; } @@ -10427,10 +10184,9 @@ DeviceOpResult Debugger::GetRenderTargetSampleInfo(const char *opString, ShaderV DeviceOpResult Debugger::GetResourceReferenceInfo(const DXDebug::BindingSlot &slot, ResourceReferenceInfo &result) const { - if(!IsDeviceThread()) + if(!IsDeviceThread() && !m_ApiWrapper->IsResourceReferenceInfoCached(slot)) return DeviceOpResult::NeedsDevice; - CHECK_DEBUGGER_THREAD(); result = m_ApiWrapper->GetResourceReferenceInfo(slot); return DeviceOpResult::Succeeded; } @@ -10439,10 +10195,9 @@ DeviceOpResult Debugger::GetResourceReferenceInfo(const DXDebug::BindingSlot &sl DeviceOpResult Debugger::GetShaderDirectAccess(DescriptorType type, const DXDebug::BindingSlot &slot, ShaderDirectAccess &result) const { - if(!IsDeviceThread()) + if(!IsDeviceThread() && !m_ApiWrapper->IsShaderDirectAccessCached(slot)) return DeviceOpResult::NeedsDevice; - CHECK_DEBUGGER_THREAD(); result = m_ApiWrapper->GetShaderDirectAccess(type, slot); return DeviceOpResult::Succeeded; } diff --git a/renderdoc/driver/shaders/dxil/dxil_debug.h b/renderdoc/driver/shaders/dxil/dxil_debug.h index 1bb99e3a6..79c1bef5c 100644 --- a/renderdoc/driver/shaders/dxil/dxil_debug.h +++ b/renderdoc/driver/shaders/dxil/dxil_debug.h @@ -228,21 +228,22 @@ struct ResourceInfo { ResourceInfo() : firstElement(0), numElements(0), isByteBuffer(false), isRootDescriptor(false) {} + size_t dataSize = 0; uint32_t firstElement; uint32_t numElements; + bool hasData = false; bool isByteBuffer; bool isRootDescriptor; // Buffer stride is stored in format.stride ViewFmt format; }; -struct UAVData +struct UAVInfo { - UAVData() = default; + UAVInfo() = default; ResourceInfo resInfo; - bytebuf data; uint32_t rowPitch = 0; uint32_t depthPitch = 0; @@ -250,12 +251,11 @@ struct UAVData bool tex = false; }; -struct SRVData +struct SRVInfo { - SRVData() = default; + SRVInfo() = default; ResourceInfo resInfo; - bytebuf data; }; enum class ThreadProperty : uint32_t @@ -294,9 +294,18 @@ class DebugAPIWrapper public: virtual ~DebugAPIWrapper() {} + virtual ShaderValue TypedUAVLoad(const BindingSlot &slot, const DXILDebug::ViewFmt &fmt, + uint64_t dataOffset) const = 0; + virtual ShaderValue TypedSRVLoad(const BindingSlot &slot, const DXILDebug::ViewFmt &fmt, + uint64_t dataOffset) const = 0; + virtual bool TypedUAVStore(const BindingSlot &slot, const DXILDebug::ViewFmt &fmt, + uint64_t dataOffset, const ShaderValue &value) = 0; + virtual bool TypedSRVStore(const BindingSlot &slot, const DXILDebug::ViewFmt &fmt, + uint64_t dataOffset, const ShaderValue &value) = 0; + // These will fetch the data on demand. - virtual const UAVData &GetUAVData(const BindingSlot &slot) = 0; - virtual const SRVData &GetSRVData(const BindingSlot &slot) = 0; + virtual UAVInfo GetUAV(const BindingSlot &slot) = 0; + virtual SRVInfo GetSRV(const BindingSlot &slot) = 0; virtual bool CalculateMathIntrinsic(DXIL::DXOp dxOp, const ShaderVariable &input, ShaderVariable &output) = 0; @@ -307,17 +316,21 @@ public: float lodValue, float compareValue, GatherChannel gatherChannel, uint32_t instructionIdx, ShaderVariable &output) = 0; virtual ShaderVariable GetResourceInfo(DXIL::ResourceClass resClass, - const DXDebug::BindingSlot &slot, - uint32_t mipLevel) const = 0; - virtual ShaderVariable GetSampleInfo(DXIL::ResourceClass resClass, const DXDebug::BindingSlot &slot, - const char *opString) const = 0; - virtual ShaderVariable GetRenderTargetSampleInfo(const char *opString) const = 0; - virtual ResourceReferenceInfo GetResourceReferenceInfo(const DXDebug::BindingSlot &slot) const = 0; + const DXDebug::BindingSlot &slot, uint32_t mipLevel) = 0; + virtual ShaderVariable GetSampleInfo(DXIL::ResourceClass resClass, + const DXDebug::BindingSlot &slot, const char *opString) = 0; + virtual ShaderVariable GetRenderTargetSampleInfo(const char *opString) = 0; + virtual ResourceReferenceInfo GetResourceReferenceInfo(const DXDebug::BindingSlot &slot) = 0; virtual ShaderDirectAccess GetShaderDirectAccess(DescriptorType type, - const DXDebug::BindingSlot &slot) const = 0; + const DXDebug::BindingSlot &slot) = 0; - virtual bool IsSRVCached(const DXDebug::BindingSlot &slot) = 0; - virtual bool IsUAVCached(const DXDebug::BindingSlot &slot) = 0; + virtual bool IsSRVCached(const DXDebug::BindingSlot &slot) const = 0; + virtual bool IsUAVCached(const DXDebug::BindingSlot &slot) const = 0; + virtual bool IsResourceInfoCached(const DXDebug::BindingSlot &slot, uint32_t mipLevel) = 0; + virtual bool IsSampleInfoCached(const DXDebug::BindingSlot &slot) = 0; + virtual bool IsRenderTargetSampleInfoCached() = 0; + virtual bool IsResourceReferenceInfoCached(const DXDebug::BindingSlot &slot) = 0; + virtual bool IsShaderDirectAccessCached(const DXDebug::BindingSlot &slot) = 0; virtual const ShaderVariable &GetInputPlaceholder() const = 0; virtual const rdcarray &GetWorkgroupProperties() const = 0; @@ -887,8 +900,13 @@ public: static rdcstr GetResourceReferenceName(const DXIL::Program *program, DXIL::ResourceClass resClass, const BindingSlot &slot); - const UAVData &GetUAVData(const BindingSlot &slot) const; - const SRVData &GetSRVData(const BindingSlot &slot) const; + ShaderValue TypedResourceLoad(DXIL::ResourceClass resClass, const BindingSlot &slot, + const DXILDebug::ViewFmt &fmt, uint64_t dataOffset); + bool TypedResourceStore(DXIL::ResourceClass resClass, const BindingSlot &slot, + const DXILDebug::ViewFmt &fmt, uint64_t dataOffset, ShaderValue &value); + + DeviceOpResult GetUAV(const BindingSlot &slot, UAVInfo &uavInfo) const; + DeviceOpResult GetSRV(const BindingSlot &slot, SRVInfo &srvInfo) const; DeviceOpResult GetResourceInfo(DXIL::ResourceClass resClass, const DXDebug::BindingSlot &slot, uint32_t mipLevel, ShaderVariable &result) const;