Added caching to DXIL APIWrapper and Debugger

Added TypedUAV Load/Store to APIWrapper
This commit is contained in:
Jake Turner
2025-10-25 14:17:40 +01:00
parent f72c1a3769
commit 0e20fbf9fb
4 changed files with 824 additions and 464 deletions
+611 -77
View File
@@ -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<ID3D12Resource>(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<ID3D12Resource>(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;
+70 -17
View File
@@ -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<ShaderVariable> &invars, rdcarray<ShaderVariable> &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<DXILDebug::ThreadProperties> m_WorkgroupProperties;
@@ -135,10 +155,43 @@ private:
ShaderVariable m_InputPlaceholder;
uint32_t m_SubgroupSize = 1;
Threading::RWLock m_UAVsLock;
std::map<BindingSlot, UAVData> m_UAVs;
Threading::RWLock m_SRVsLock;
std::map<BindingSlot, SRVData> 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<BindingSlot, UAVInfo> m_UAVInfos;
std::map<BindingSlot, bytebuf> m_UAVBuffers;
mutable Threading::RWLock m_SRVsLock;
std::map<BindingSlot, SRVInfo> m_SRVInfos;
std::map<BindingSlot, bytebuf> m_SRVBuffers;
Threading::RWLock m_ResourceInfosLock;
std::map<ResourceInfoMiplevel, ShaderVariable> m_ResourceInfos;
Threading::RWLock m_SampleInfosLock;
std::map<BindingSlot, ShaderVariable> m_SampleInfos;
Threading::RWLock m_ResourceReferenceInfosLock;
std::map<BindingSlot, ResourceReferenceInfo> m_ResourceReferenceInfos;
Threading::RWLock m_RenderTargetSampleInfoLock;
ShaderVariable m_RenderTargetSampleInfo;
bool m_RenderTargetSampleInfoValid = false;
Threading::RWLock m_ShaderDirectAccessesLock;
std::map<BindingSlot, ShaderDirectAccess> m_ShaderDirectAccesses;
const ShaderReflection &m_Reflection;
WrappedID3D12Device *m_Device = NULL;
+106 -351
View File
@@ -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<ThreadState> &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<ThreadState> &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<ThreadState> &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<ThreadState> &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<ThreadState> &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<ThreadState> &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<ThreadState> &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<ThreadState> &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<ThreadState> &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<ThreadState> &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<ThreadState> &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<ThreadState> &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<ThreadState> &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<ThreadState> &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<ThreadState> &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;
}
+37 -19
View File
@@ -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<DXILDebug::ThreadProperties> &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;