mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-07-28 18:31:40 +00:00
Process root signature elements into pipeline state
This commit is contained in:
@@ -83,10 +83,16 @@ struct D3D12PipelineState
|
||||
ShaderStageType stage;
|
||||
} m_VS, m_HS, m_DS, m_GS, m_PS, m_CS;
|
||||
|
||||
// Immediate indicates either a root parameter (not in a table), or static samplers
|
||||
// RootElement is the index in the original root signature that this descriptor came from.
|
||||
|
||||
struct ResourceView
|
||||
{
|
||||
ResourceView()
|
||||
: Resource(),
|
||||
: VisibilityMask(),
|
||||
Immediate(0),
|
||||
RootElement(0),
|
||||
Resource(),
|
||||
Format(),
|
||||
BufferFlags(0),
|
||||
BufferStructCount(0),
|
||||
@@ -106,6 +112,12 @@ struct D3D12PipelineState
|
||||
swizzle[3] = eSwizzle_Alpha;
|
||||
}
|
||||
|
||||
// parameters from descriptor
|
||||
ShaderStageBits VisibilityMask;
|
||||
bool32 Immediate;
|
||||
uint32_t RootElement;
|
||||
|
||||
// parameters from resource/view
|
||||
ResourceId Resource;
|
||||
rdctype::str Type;
|
||||
ResourceFormat Format;
|
||||
@@ -134,7 +146,10 @@ struct D3D12PipelineState
|
||||
struct Sampler
|
||||
{
|
||||
Sampler()
|
||||
: UseBorder(false),
|
||||
: VisibilityMask(),
|
||||
Immediate(0),
|
||||
RootElement(0),
|
||||
UseBorder(false),
|
||||
UseComparison(false),
|
||||
MaxAniso(0),
|
||||
MaxLOD(0.0f),
|
||||
@@ -143,6 +158,13 @@ struct D3D12PipelineState
|
||||
{
|
||||
BorderColor[0] = BorderColor[1] = BorderColor[2] = BorderColor[3] = 0.0f;
|
||||
}
|
||||
|
||||
// parameters from descriptor
|
||||
ShaderStageBits VisibilityMask;
|
||||
bool32 Immediate;
|
||||
uint32_t RootElement;
|
||||
|
||||
// parameters from resource/view
|
||||
rdctype::str AddressU, AddressV, AddressW;
|
||||
float BorderColor[4];
|
||||
rdctype::str Comparison;
|
||||
@@ -157,52 +179,32 @@ struct D3D12PipelineState
|
||||
|
||||
struct CBuffer
|
||||
{
|
||||
CBuffer() : Buffer(), Offset(0), ByteSize(0) {}
|
||||
CBuffer() : VisibilityMask(), Immediate(0), RootElement(0), Buffer(), Offset(0), ByteSize(0) {}
|
||||
// parameters from descriptor
|
||||
ShaderStageBits VisibilityMask;
|
||||
bool32 Immediate;
|
||||
uint32_t RootElement;
|
||||
|
||||
// parameters from resource/view
|
||||
ResourceId Buffer;
|
||||
uint64_t Offset;
|
||||
uint32_t ByteSize;
|
||||
|
||||
rdctype::array<uint32_t> Immediate;
|
||||
rdctype::array<uint32_t> RootValues;
|
||||
};
|
||||
|
||||
struct RootSignature
|
||||
{
|
||||
ResourceId obj;
|
||||
|
||||
// Immediate indicates either a root parameter (not in a table), or static samplers
|
||||
// RootElement is the index in the original root signature that this descriptor came from.
|
||||
|
||||
struct CBufferDescriptor
|
||||
struct RegisterSpace
|
||||
{
|
||||
ShaderStageBits VisibilityMask;
|
||||
bool32 Immediate;
|
||||
uint32_t RootElement;
|
||||
|
||||
CBuffer obj;
|
||||
rdctype::array<CBuffer> ConstantBuffers;
|
||||
rdctype::array<Sampler> Samplers;
|
||||
rdctype::array<ResourceView> SRVs;
|
||||
rdctype::array<ResourceView> UAVs;
|
||||
};
|
||||
|
||||
struct ViewDescriptor
|
||||
{
|
||||
ShaderStageBits VisibilityMask;
|
||||
bool32 Immediate;
|
||||
uint32_t RootElement;
|
||||
|
||||
ResourceView obj;
|
||||
};
|
||||
|
||||
struct SamplerDescriptor
|
||||
{
|
||||
ShaderStageBits VisibilityMask;
|
||||
bool32 Immediate;
|
||||
uint32_t RootElement;
|
||||
|
||||
Sampler obj;
|
||||
};
|
||||
|
||||
rdctype::array<CBufferDescriptor> ConstantBuffers;
|
||||
rdctype::array<SamplerDescriptor> Samplers;
|
||||
rdctype::array<ViewDescriptor> SRVs;
|
||||
rdctype::array<ViewDescriptor> UAVs;
|
||||
rdctype::array<RegisterSpace> Spaces;
|
||||
} m_RootSig;
|
||||
|
||||
struct Streamout
|
||||
|
||||
@@ -320,6 +320,7 @@ enum ShaderStageType
|
||||
|
||||
enum ShaderStageBits
|
||||
{
|
||||
eStageBits_None = 0,
|
||||
eStageBits_Vertex = 1 << eShaderStage_Vertex,
|
||||
eStageBits_Hull = 1 << eShaderStage_Hull,
|
||||
eStageBits_Tess_Control = 1 << eShaderStage_Tess_Control,
|
||||
@@ -329,6 +330,9 @@ enum ShaderStageBits
|
||||
eStageBits_Pixel = 1 << eShaderStage_Pixel,
|
||||
eStageBits_Fragment = 1 << eShaderStage_Fragment,
|
||||
eStageBits_Compute = 1 << eShaderStage_Compute,
|
||||
eStageBits_All = eStageBits_Vertex | eStageBits_Hull | eStageBits_Domain | eStageBits_Geometry |
|
||||
eStageBits_Pixel |
|
||||
eStageBits_Compute,
|
||||
};
|
||||
|
||||
enum DebugMessageCategory
|
||||
|
||||
@@ -647,12 +647,15 @@ D3D11PipelineState D3D11Replay::MakePipelineState()
|
||||
samp.Filter = ToStr::Get(desc.Filter);
|
||||
samp.MaxAniso = 0;
|
||||
if(desc.Filter == D3D11_FILTER_ANISOTROPIC ||
|
||||
desc.Filter == D3D11_FILTER_COMPARISON_ANISOTROPIC)
|
||||
desc.Filter == D3D11_FILTER_COMPARISON_ANISOTROPIC ||
|
||||
desc.Filter == D3D11_FILTER_MINIMUM_ANISOTROPIC ||
|
||||
desc.Filter == D3D11_FILTER_MAXIMUM_ANISOTROPIC)
|
||||
samp.MaxAniso = desc.MaxAnisotropy;
|
||||
samp.MaxLOD = desc.MaxLOD;
|
||||
samp.MinLOD = desc.MinLOD;
|
||||
samp.MipLODBias = desc.MipLODBias;
|
||||
samp.UseComparison = (desc.Filter >= D3D11_FILTER_COMPARISON_MIN_MAG_MIP_POINT);
|
||||
samp.UseComparison = (desc.Filter >= D3D11_FILTER_COMPARISON_MIN_MAG_MIP_POINT &&
|
||||
desc.Filter <= D3D11_FILTER_COMPARISON_ANISOTROPIC);
|
||||
samp.UseBorder = (desc.AddressU == D3D11_TEXTURE_ADDRESS_BORDER ||
|
||||
desc.AddressV == D3D11_TEXTURE_ADDRESS_BORDER ||
|
||||
desc.AddressW == D3D11_TEXTURE_ADDRESS_BORDER);
|
||||
|
||||
@@ -28,9 +28,308 @@
|
||||
#include "d3d12_manager.h"
|
||||
#include "d3d12_resources.h"
|
||||
|
||||
static ShaderConstant MakeConstantBufferVariable(const DXBC::CBufferVariable &var, uint32_t &offset);
|
||||
|
||||
static ShaderVariableType MakeShaderVariableType(DXBC::CBufferVariableType type, uint32_t &offset)
|
||||
{
|
||||
ShaderVariableType ret;
|
||||
|
||||
switch(type.descriptor.type)
|
||||
{
|
||||
case DXBC::VARTYPE_INT: ret.descriptor.type = eVar_Int; break;
|
||||
case DXBC::VARTYPE_BOOL:
|
||||
case DXBC::VARTYPE_UINT: ret.descriptor.type = eVar_UInt; break;
|
||||
case DXBC::VARTYPE_DOUBLE: ret.descriptor.type = eVar_Double; break;
|
||||
case DXBC::VARTYPE_FLOAT:
|
||||
default: ret.descriptor.type = eVar_Float; break;
|
||||
}
|
||||
ret.descriptor.rows = type.descriptor.rows;
|
||||
ret.descriptor.cols = type.descriptor.cols;
|
||||
ret.descriptor.elements = type.descriptor.elements;
|
||||
ret.descriptor.name = type.descriptor.name;
|
||||
ret.descriptor.rowMajorStorage = (type.descriptor.varClass == DXBC::CLASS_MATRIX_ROWS);
|
||||
|
||||
uint32_t baseElemSize = (ret.descriptor.type == eVar_Double) ? 8 : 4;
|
||||
if(ret.descriptor.rowMajorStorage)
|
||||
{
|
||||
uint32_t primary = ret.descriptor.rows;
|
||||
if(primary == 3)
|
||||
primary = 4;
|
||||
ret.descriptor.arrayStride = baseElemSize * primary * ret.descriptor.cols;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t primary = ret.descriptor.cols;
|
||||
if(primary == 3)
|
||||
primary = 4;
|
||||
ret.descriptor.arrayStride = baseElemSize * primary * ret.descriptor.rows;
|
||||
}
|
||||
|
||||
uint32_t o = offset;
|
||||
|
||||
create_array_uninit(ret.members, type.members.size());
|
||||
for(size_t i = 0; i < type.members.size(); i++)
|
||||
{
|
||||
offset = o;
|
||||
ret.members[i] = MakeConstantBufferVariable(type.members[i], offset);
|
||||
}
|
||||
|
||||
if(ret.members.count > 0)
|
||||
{
|
||||
ret.descriptor.rows = 0;
|
||||
ret.descriptor.cols = 0;
|
||||
ret.descriptor.elements = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ShaderConstant MakeConstantBufferVariable(const DXBC::CBufferVariable &var, uint32_t &offset)
|
||||
{
|
||||
ShaderConstant ret;
|
||||
|
||||
ret.name = var.name;
|
||||
ret.reg.vec = offset + var.descriptor.offset / 16;
|
||||
ret.reg.comp = (var.descriptor.offset - (var.descriptor.offset & ~0xf)) / 4;
|
||||
ret.defaultValue = 0;
|
||||
|
||||
offset = ret.reg.vec;
|
||||
|
||||
ret.type = MakeShaderVariableType(var.type, offset);
|
||||
|
||||
offset = ret.reg.vec + RDCMAX(1U, var.type.descriptor.bytesize / 16);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void MakeShaderReflection(DXBC::DXBCFile *dxbc, ShaderReflection *refl,
|
||||
ShaderBindpointMapping *mapping)
|
||||
{
|
||||
if(dxbc == NULL || !RenderDoc::Inst().IsReplayApp())
|
||||
return;
|
||||
|
||||
if(dxbc->m_DebugInfo)
|
||||
{
|
||||
refl->DebugInfo.entryFunc = dxbc->m_DebugInfo->GetEntryFunction();
|
||||
refl->DebugInfo.compileFlags = dxbc->m_DebugInfo->GetShaderCompileFlags();
|
||||
|
||||
refl->DebugInfo.entryFile = -1;
|
||||
|
||||
create_array_uninit(refl->DebugInfo.files, dxbc->m_DebugInfo->Files.size());
|
||||
for(size_t i = 0; i < dxbc->m_DebugInfo->Files.size(); i++)
|
||||
{
|
||||
refl->DebugInfo.files[i].first = dxbc->m_DebugInfo->Files[i].first;
|
||||
refl->DebugInfo.files[i].second = dxbc->m_DebugInfo->Files[i].second;
|
||||
|
||||
if(refl->DebugInfo.entryFile == -1 &&
|
||||
strstr(refl->DebugInfo.files[i].second.elems, refl->DebugInfo.entryFunc.elems))
|
||||
{
|
||||
refl->DebugInfo.entryFile = (int32_t)i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
refl->Disassembly = dxbc->GetDisassembly();
|
||||
|
||||
if(dxbc->m_ShaderBlob.empty())
|
||||
create_array_uninit(refl->RawBytes, 0);
|
||||
else
|
||||
create_array_init(refl->RawBytes, dxbc->m_ShaderBlob.size(), &dxbc->m_ShaderBlob[0]);
|
||||
|
||||
refl->DispatchThreadsDimension[0] = dxbc->DispatchThreadsDimension[0];
|
||||
refl->DispatchThreadsDimension[1] = dxbc->DispatchThreadsDimension[1];
|
||||
refl->DispatchThreadsDimension[2] = dxbc->DispatchThreadsDimension[2];
|
||||
|
||||
refl->InputSig = dxbc->m_InputSig;
|
||||
refl->OutputSig = dxbc->m_OutputSig;
|
||||
|
||||
create_array_uninit(mapping->InputAttributes, D3D12_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT);
|
||||
for(int s = 0; s < D3D12_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT; s++)
|
||||
mapping->InputAttributes[s] = s;
|
||||
|
||||
int numCbuffers = 0;
|
||||
|
||||
// skip 'empty' cbuffers added for the benefit of D3D11
|
||||
for(size_t i = 0; i < dxbc->m_CBuffers.size(); i++)
|
||||
{
|
||||
if(dxbc->m_CBuffers[i].descriptor.type == DXBC::CBuffer::Descriptor::TYPE_CBUFFER)
|
||||
numCbuffers++;
|
||||
}
|
||||
|
||||
create_array_uninit(mapping->ConstantBlocks, numCbuffers);
|
||||
create_array_uninit(refl->ConstantBlocks, numCbuffers);
|
||||
for(size_t i = 0, c = 0; i < dxbc->m_CBuffers.size(); i++)
|
||||
{
|
||||
ConstantBlock &cb = refl->ConstantBlocks[c];
|
||||
|
||||
if(dxbc->m_CBuffers[i].descriptor.type != DXBC::CBuffer::Descriptor::TYPE_CBUFFER)
|
||||
continue;
|
||||
|
||||
cb.name = dxbc->m_CBuffers[i].name;
|
||||
cb.bufferBacked = true;
|
||||
cb.byteSize = dxbc->m_CBuffers[i].descriptor.byteSize;
|
||||
cb.bindPoint = (uint32_t)c;
|
||||
|
||||
BindpointMap map = {};
|
||||
map.arraySize = 1;
|
||||
map.bind = (int32_t)i;
|
||||
map.used = true;
|
||||
|
||||
mapping->ConstantBlocks[c] = map;
|
||||
|
||||
create_array_uninit(cb.variables, dxbc->m_CBuffers[i].variables.size());
|
||||
for(size_t v = 0; v < dxbc->m_CBuffers[i].variables.size(); v++)
|
||||
{
|
||||
uint32_t vecOffset = 0;
|
||||
cb.variables[v] = MakeConstantBufferVariable(dxbc->m_CBuffers[i].variables[v], vecOffset);
|
||||
}
|
||||
}
|
||||
|
||||
int numRWResources = 0;
|
||||
int numROResources = 0;
|
||||
|
||||
for(size_t i = 0; i < dxbc->m_Resources.size(); i++)
|
||||
{
|
||||
const auto &r = dxbc->m_Resources[i];
|
||||
|
||||
if(r.type != DXBC::ShaderInputBind::TYPE_CBUFFER)
|
||||
{
|
||||
bool IsReadWrite = (r.type == DXBC::ShaderInputBind::TYPE_UAV_RWTYPED ||
|
||||
r.type == DXBC::ShaderInputBind::TYPE_UAV_RWSTRUCTURED ||
|
||||
r.type == DXBC::ShaderInputBind::TYPE_UAV_RWBYTEADDRESS ||
|
||||
r.type == DXBC::ShaderInputBind::TYPE_UAV_APPEND_STRUCTURED ||
|
||||
r.type == DXBC::ShaderInputBind::TYPE_UAV_CONSUME_STRUCTURED ||
|
||||
r.type == DXBC::ShaderInputBind::TYPE_UAV_RWSTRUCTURED_WITH_COUNTER);
|
||||
|
||||
if(IsReadWrite)
|
||||
numRWResources++;
|
||||
else
|
||||
numROResources++;
|
||||
}
|
||||
}
|
||||
|
||||
create_array_uninit(mapping->ReadWriteResources, numRWResources);
|
||||
create_array_uninit(refl->ReadWriteResources, numRWResources);
|
||||
|
||||
create_array_uninit(mapping->ReadOnlyResources, numROResources);
|
||||
create_array_uninit(refl->ReadOnlyResources, numROResources);
|
||||
|
||||
int32_t rwidx = 0, roidx = 0;
|
||||
for(size_t i = 0; i < dxbc->m_Resources.size(); i++)
|
||||
{
|
||||
const auto &r = dxbc->m_Resources[i];
|
||||
|
||||
if(r.type == DXBC::ShaderInputBind::TYPE_CBUFFER)
|
||||
continue;
|
||||
|
||||
ShaderResource res;
|
||||
res.name = r.name;
|
||||
|
||||
res.IsSampler = (r.type == DXBC::ShaderInputBind::TYPE_SAMPLER);
|
||||
res.IsTexture = (r.type == DXBC::ShaderInputBind::TYPE_TEXTURE &&
|
||||
r.dimension != DXBC::ShaderInputBind::DIM_UNKNOWN &&
|
||||
r.dimension != DXBC::ShaderInputBind::DIM_BUFFER &&
|
||||
r.dimension != DXBC::ShaderInputBind::DIM_BUFFEREX);
|
||||
res.IsSRV = (r.type == DXBC::ShaderInputBind::TYPE_TBUFFER ||
|
||||
r.type == DXBC::ShaderInputBind::TYPE_TEXTURE ||
|
||||
r.type == DXBC::ShaderInputBind::TYPE_STRUCTURED ||
|
||||
r.type == DXBC::ShaderInputBind::TYPE_BYTEADDRESS);
|
||||
bool IsReadWrite = (r.type == DXBC::ShaderInputBind::TYPE_UAV_RWTYPED ||
|
||||
r.type == DXBC::ShaderInputBind::TYPE_UAV_RWSTRUCTURED ||
|
||||
r.type == DXBC::ShaderInputBind::TYPE_UAV_RWBYTEADDRESS ||
|
||||
r.type == DXBC::ShaderInputBind::TYPE_UAV_APPEND_STRUCTURED ||
|
||||
r.type == DXBC::ShaderInputBind::TYPE_UAV_CONSUME_STRUCTURED ||
|
||||
r.type == DXBC::ShaderInputBind::TYPE_UAV_RWSTRUCTURED_WITH_COUNTER);
|
||||
|
||||
switch(r.dimension)
|
||||
{
|
||||
default:
|
||||
case DXBC::ShaderInputBind::DIM_UNKNOWN: res.resType = eResType_None; break;
|
||||
case DXBC::ShaderInputBind::DIM_BUFFER:
|
||||
case DXBC::ShaderInputBind::DIM_BUFFEREX: res.resType = eResType_Buffer; break;
|
||||
case DXBC::ShaderInputBind::DIM_TEXTURE1D: res.resType = eResType_Texture1D; break;
|
||||
case DXBC::ShaderInputBind::DIM_TEXTURE1DARRAY: res.resType = eResType_Texture1DArray; break;
|
||||
case DXBC::ShaderInputBind::DIM_TEXTURE2D: res.resType = eResType_Texture2D; break;
|
||||
case DXBC::ShaderInputBind::DIM_TEXTURE2DARRAY: res.resType = eResType_Texture2DArray; break;
|
||||
case DXBC::ShaderInputBind::DIM_TEXTURE2DMS: res.resType = eResType_Texture2DMS; break;
|
||||
case DXBC::ShaderInputBind::DIM_TEXTURE2DMSARRAY:
|
||||
res.resType = eResType_Texture2DMSArray;
|
||||
break;
|
||||
case DXBC::ShaderInputBind::DIM_TEXTURE3D: res.resType = eResType_Texture3D; break;
|
||||
case DXBC::ShaderInputBind::DIM_TEXTURECUBE: res.resType = eResType_TextureCube; break;
|
||||
case DXBC::ShaderInputBind::DIM_TEXTURECUBEARRAY:
|
||||
res.resType = eResType_TextureCubeArray;
|
||||
break;
|
||||
}
|
||||
|
||||
if(r.retType != DXBC::ShaderInputBind::RETTYPE_UNKNOWN &&
|
||||
r.retType != DXBC::ShaderInputBind::RETTYPE_MIXED &&
|
||||
r.retType != DXBC::ShaderInputBind::RETTYPE_CONTINUED)
|
||||
{
|
||||
res.variableType.descriptor.rows = 1;
|
||||
res.variableType.descriptor.cols = r.numSamples;
|
||||
res.variableType.descriptor.elements = 1;
|
||||
|
||||
string name;
|
||||
|
||||
switch(r.retType)
|
||||
{
|
||||
case DXBC::ShaderInputBind::RETTYPE_UNORM: name = "unorm float"; break;
|
||||
case DXBC::ShaderInputBind::RETTYPE_SNORM: name = "snorm float"; break;
|
||||
case DXBC::ShaderInputBind::RETTYPE_SINT: name = "int"; break;
|
||||
case DXBC::ShaderInputBind::RETTYPE_UINT: name = "uint"; break;
|
||||
case DXBC::ShaderInputBind::RETTYPE_FLOAT: name = "float"; break;
|
||||
case DXBC::ShaderInputBind::RETTYPE_DOUBLE: name = "double"; break;
|
||||
default: name = "unknown"; break;
|
||||
}
|
||||
|
||||
name += ToStr::Get(r.numSamples);
|
||||
|
||||
res.variableType.descriptor.name = name;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(dxbc->m_ResourceBinds.find(r.name) != dxbc->m_ResourceBinds.end())
|
||||
{
|
||||
uint32_t vecOffset = 0;
|
||||
res.variableType = MakeShaderVariableType(dxbc->m_ResourceBinds[r.name], vecOffset);
|
||||
}
|
||||
else
|
||||
{
|
||||
res.variableType.descriptor.rows = 0;
|
||||
res.variableType.descriptor.cols = 0;
|
||||
res.variableType.descriptor.elements = 0;
|
||||
res.variableType.descriptor.name = "";
|
||||
}
|
||||
}
|
||||
|
||||
res.bindPoint = IsReadWrite ? rwidx : roidx;
|
||||
|
||||
BindpointMap map = {};
|
||||
map.arraySize = 1;
|
||||
map.bind = r.bindPoint;
|
||||
map.used = true;
|
||||
|
||||
if(IsReadWrite)
|
||||
{
|
||||
refl->ReadWriteResources[rwidx++] = res;
|
||||
mapping->ReadWriteResources[i] = map;
|
||||
}
|
||||
else
|
||||
{
|
||||
refl->ReadOnlyResources[roidx++] = res;
|
||||
mapping->ReadOnlyResources[i] = map;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t numInterfaces = 0;
|
||||
for(size_t i = 0; i < dxbc->m_Interfaces.variables.size(); i++)
|
||||
numInterfaces = RDCMAX(dxbc->m_Interfaces.variables[i].descriptor.offset + 1, numInterfaces);
|
||||
|
||||
create_array(refl->Interfaces, numInterfaces);
|
||||
for(size_t i = 0; i < dxbc->m_Interfaces.variables.size(); i++)
|
||||
refl->Interfaces[dxbc->m_Interfaces.variables[i].descriptor.offset] =
|
||||
dxbc->m_Interfaces.variables[i].name;
|
||||
}
|
||||
|
||||
enum D3D12ResourceBarrierSubresource
|
||||
@@ -127,6 +426,21 @@ UINT GetNumSubresources(const D3D12_RESOURCE_DESC *desc)
|
||||
return 1;
|
||||
}
|
||||
|
||||
ShaderStageBits ConvertVisibility(D3D12_SHADER_VISIBILITY ShaderVisibility)
|
||||
{
|
||||
switch(ShaderVisibility)
|
||||
{
|
||||
case D3D12_SHADER_VISIBILITY_ALL: return eStageBits_All;
|
||||
case D3D12_SHADER_VISIBILITY_VERTEX: return eStageBits_Vertex;
|
||||
case D3D12_SHADER_VISIBILITY_HULL: return eStageBits_Hull;
|
||||
case D3D12_SHADER_VISIBILITY_DOMAIN: return eStageBits_Domain;
|
||||
case D3D12_SHADER_VISIBILITY_GEOMETRY: return eStageBits_Geometry;
|
||||
case D3D12_SHADER_VISIBILITY_PIXEL: return eStageBits_Pixel;
|
||||
}
|
||||
|
||||
return eStageBits_Vertex;
|
||||
}
|
||||
|
||||
string ToStrHelper<false, D3D12ComponentMapping>::Get(const D3D12ComponentMapping &el)
|
||||
{
|
||||
string ret;
|
||||
|
||||
@@ -57,6 +57,7 @@ void MakeShaderReflection(DXBC::DXBCFile *dxbc, ShaderReflection *refl,
|
||||
// buffer replay is happening
|
||||
#define VERBOSE_PARTIAL_REPLAY
|
||||
|
||||
ShaderStageBits ConvertVisibility(D3D12_SHADER_VISIBILITY ShaderVisibility);
|
||||
UINT GetNumSubresources(const D3D12_RESOURCE_DESC *desc);
|
||||
|
||||
class WrappedID3D12Device;
|
||||
@@ -125,7 +126,7 @@ public:
|
||||
|
||||
struct D3D12RootSignatureParameter : D3D12_ROOT_PARAMETER
|
||||
{
|
||||
void MakeFrom(const D3D12_ROOT_PARAMETER ¶m)
|
||||
void MakeFrom(const D3D12_ROOT_PARAMETER ¶m, UINT &numSpaces)
|
||||
{
|
||||
ParameterType = param.ParameterType;
|
||||
ShaderVisibility = param.ShaderVisibility;
|
||||
@@ -138,11 +139,23 @@ struct D3D12RootSignatureParameter : D3D12_ROOT_PARAMETER
|
||||
{
|
||||
ranges.resize(param.DescriptorTable.NumDescriptorRanges);
|
||||
for(size_t i = 0; i < ranges.size(); i++)
|
||||
{
|
||||
ranges[i] = param.DescriptorTable.pDescriptorRanges[i];
|
||||
|
||||
numSpaces = RDCMAX(numSpaces, ranges[i].RegisterSpace + 1);
|
||||
}
|
||||
|
||||
DescriptorTable.NumDescriptorRanges = (UINT)ranges.size();
|
||||
DescriptorTable.pDescriptorRanges = &ranges[0];
|
||||
}
|
||||
else if(ParameterType == D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS)
|
||||
{
|
||||
numSpaces = RDCMAX(numSpaces, Constants.RegisterSpace + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
numSpaces = RDCMAX(numSpaces, Descriptor.RegisterSpace + 1);
|
||||
}
|
||||
}
|
||||
|
||||
vector<D3D12_DESCRIPTOR_RANGE> ranges;
|
||||
@@ -150,6 +163,8 @@ struct D3D12RootSignatureParameter : D3D12_ROOT_PARAMETER
|
||||
|
||||
struct D3D12RootSignature
|
||||
{
|
||||
D3D12RootSignature() : numSpaces(0) {}
|
||||
uint32_t numSpaces;
|
||||
vector<D3D12RootSignatureParameter> params;
|
||||
vector<D3D12_STATIC_SAMPLER_DESC> samplers;
|
||||
};
|
||||
|
||||
@@ -830,11 +830,16 @@ D3D12RootSignature D3D12DebugManager::GetRootSig(const void *data, size_t dataSi
|
||||
ret.params.resize(desc->NumParameters);
|
||||
|
||||
for(size_t i = 0; i < ret.params.size(); i++)
|
||||
ret.params[i].MakeFrom(desc->pParameters[i]);
|
||||
ret.params[i].MakeFrom(desc->pParameters[i], ret.numSpaces);
|
||||
|
||||
if(desc->NumStaticSamplers > 0)
|
||||
{
|
||||
ret.samplers.assign(desc->pStaticSamplers, desc->pStaticSamplers + desc->NumStaticSamplers);
|
||||
|
||||
for(size_t i = 0; i < ret.samplers.size(); i++)
|
||||
ret.numSpaces = RDCMAX(ret.numSpaces, ret.samplers[i].RegisterSpace + 1);
|
||||
}
|
||||
|
||||
SAFE_RELEASE(deser);
|
||||
|
||||
return ret;
|
||||
|
||||
@@ -28,6 +28,15 @@
|
||||
#include "d3d12_device.h"
|
||||
#include "d3d12_resources.h"
|
||||
|
||||
template <class T>
|
||||
T &resize_and_add(std::vector<T> &vec, size_t idx)
|
||||
{
|
||||
if(idx >= vec.size())
|
||||
vec.resize(idx + 1);
|
||||
|
||||
return vec[idx];
|
||||
}
|
||||
|
||||
D3D12Replay::D3D12Replay()
|
||||
{
|
||||
m_pDevice = NULL;
|
||||
@@ -244,20 +253,10 @@ vector<EventUsage> D3D12Replay::GetUsage(ResourceId id)
|
||||
return m_pDevice->GetQueue()->GetUsage(id);
|
||||
}
|
||||
|
||||
void D3D12Replay::FillResourceView(D3D12PipelineState::ResourceView &view,
|
||||
const PortableHandle &resHandle)
|
||||
void D3D12Replay::FillResourceView(D3D12PipelineState::ResourceView &view, D3D12Descriptor *desc)
|
||||
{
|
||||
D3D12ResourceManager *rm = m_pDevice->GetResourceManager();
|
||||
|
||||
if(resHandle.heap == ResourceId())
|
||||
return;
|
||||
|
||||
WrappedID3D12DescriptorHeap *heap = rm->GetLiveAs<WrappedID3D12DescriptorHeap>(resHandle.heap);
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE handle = heap->GetCPUDescriptorHandleForHeapStart();
|
||||
|
||||
D3D12Descriptor *desc = (D3D12Descriptor *)handle.ptr;
|
||||
desc += resHandle.index;
|
||||
|
||||
if(desc->GetType() == D3D12Descriptor::TypeSampler || desc->GetType() == D3D12Descriptor::TypeCBV)
|
||||
{
|
||||
RDCERR("Invalid descriptors - expected a resource view");
|
||||
@@ -561,7 +560,7 @@ void D3D12Replay::MakePipelineState()
|
||||
// Shaders
|
||||
/////////////////////////////////////////////////
|
||||
|
||||
ResourceId rootSig;
|
||||
const D3D12RenderState::RootSignature *rootSig = NULL;
|
||||
|
||||
if(pipe && pipe->IsCompute())
|
||||
{
|
||||
@@ -570,8 +569,9 @@ void D3D12Replay::MakePipelineState()
|
||||
|
||||
state.m_CS.Shader = sh->GetResourceID();
|
||||
state.m_CS.stage = eShaderStage_Compute;
|
||||
state.m_CS.BindpointMapping = sh->GetMapping();
|
||||
|
||||
rootSig = rs.compute.rootsig;
|
||||
rootSig = &rs.compute;
|
||||
}
|
||||
else if(pipe)
|
||||
{
|
||||
@@ -598,331 +598,281 @@ void D3D12Replay::MakePipelineState()
|
||||
}
|
||||
}
|
||||
|
||||
rootSig = rs.graphics.rootsig;
|
||||
rootSig = &rs.graphics;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if(rootSig)
|
||||
{
|
||||
D3D11PipelineState::ShaderStage &dst = *dstArr[stage];
|
||||
const D3D11RenderState::shader &src = *srcArr[stage];
|
||||
state.m_RootSig.obj = rm->GetOriginalID(rootSig->rootsig);
|
||||
|
||||
dst.stage = (ShaderStageType)stage;
|
||||
WrappedID3D12RootSignature *sig =
|
||||
m_pDevice->GetResourceManager()->GetCurrentAs<WrappedID3D12RootSignature>(rootSig->rootsig);
|
||||
|
||||
ResourceId id = GetIDForResource(src.Shader);
|
||||
|
||||
WrappedShader *shad = (WrappedShader *)(WrappedID3D11Shader<ID3D11VertexShader> *)src.Shader;
|
||||
|
||||
ShaderReflection *refl = NULL;
|
||||
|
||||
if(shad != NULL)
|
||||
refl = shad->GetDetails();
|
||||
|
||||
dst.Shader = rm->GetOriginalID(id);
|
||||
dst.ShaderDetails = NULL;
|
||||
|
||||
string str = GetDebugName(src.Shader);
|
||||
dst.customName = true;
|
||||
|
||||
if(str == "" && dst.Shader != ResourceId())
|
||||
struct Space
|
||||
{
|
||||
dst.customName = false;
|
||||
str = StringFormat::Fmt("%s Shader %llu", stageNames[stage], dst.Shader);
|
||||
}
|
||||
vector<D3D12PipelineState::CBuffer> cbuffers;
|
||||
vector<D3D12PipelineState::Sampler> samplers;
|
||||
vector<D3D12PipelineState::ResourceView> srvs;
|
||||
vector<D3D12PipelineState::ResourceView> uavs;
|
||||
};
|
||||
|
||||
dst.ShaderName = str;
|
||||
Space *spaces = new Space[sig->sig.numSpaces];
|
||||
create_array_uninit(state.m_RootSig.Spaces, sig->sig.numSpaces);
|
||||
|
||||
// create identity bindpoint mapping
|
||||
create_array_uninit(dst.BindpointMapping.InputAttributes,
|
||||
D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT);
|
||||
for(int s = 0; s < D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT; s++)
|
||||
for(size_t rootEl = 0; rootEl < RDCMIN(sig->sig.params.size(), rootSig->sigelems.size()); rootEl++)
|
||||
{
|
||||
// TODO: this should do any semantic rematching as defined by the bytecode
|
||||
// the input layout was built with (not necessarily the vertex shader's bytecode -
|
||||
// in the case of a mismatch). It's commonly, but not always the identity mapping
|
||||
dst.BindpointMapping.InputAttributes[s] = s;
|
||||
}
|
||||
const D3D12RenderState::SignatureElement &e = rootSig->sigelems[rootEl];
|
||||
const D3D12RootSignatureParameter &p = sig->sig.params[rootEl];
|
||||
|
||||
create_array_uninit(dst.BindpointMapping.ConstantBlocks,
|
||||
D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT);
|
||||
for(int s = 0; s < D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT; s++)
|
||||
{
|
||||
dst.BindpointMapping.ConstantBlocks[s].bindset = 0;
|
||||
dst.BindpointMapping.ConstantBlocks[s].bind = s;
|
||||
dst.BindpointMapping.ConstantBlocks[s].used = false;
|
||||
dst.BindpointMapping.ConstantBlocks[s].arraySize = 1;
|
||||
}
|
||||
|
||||
create_array_uninit(dst.BindpointMapping.ReadOnlyResources,
|
||||
D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT);
|
||||
for(int32_t s = 0; s < D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT; s++)
|
||||
{
|
||||
dst.BindpointMapping.ReadOnlyResources[s].bindset = 0;
|
||||
dst.BindpointMapping.ReadOnlyResources[s].bind = s;
|
||||
dst.BindpointMapping.ReadOnlyResources[s].used = false;
|
||||
dst.BindpointMapping.ReadOnlyResources[s].arraySize = 1;
|
||||
}
|
||||
|
||||
create_array_uninit(dst.BindpointMapping.ReadWriteResources, D3D11_1_UAV_SLOT_COUNT);
|
||||
for(int32_t s = 0; s < D3D11_1_UAV_SLOT_COUNT; s++)
|
||||
{
|
||||
dst.BindpointMapping.ReadWriteResources[s].bindset = 0;
|
||||
dst.BindpointMapping.ReadWriteResources[s].bind = s;
|
||||
dst.BindpointMapping.ReadWriteResources[s].used = false;
|
||||
dst.BindpointMapping.ReadWriteResources[s].arraySize = 1;
|
||||
}
|
||||
|
||||
// mark resources as used if they are referenced by the shader
|
||||
if(refl)
|
||||
{
|
||||
for(int32_t i = 0; i < refl->ConstantBlocks.count; i++)
|
||||
if(refl->ConstantBlocks[i].bufferBacked)
|
||||
dst.BindpointMapping.ConstantBlocks[refl->ConstantBlocks[i].bindPoint].used = true;
|
||||
|
||||
for(int32_t i = 0; i < refl->ReadOnlyResources.count; i++)
|
||||
if(!refl->ReadOnlyResources[i].IsSampler)
|
||||
dst.BindpointMapping.ReadOnlyResources[refl->ReadOnlyResources[i].bindPoint].used = true;
|
||||
|
||||
for(int32_t i = 0; i < refl->ReadWriteResources.count; i++)
|
||||
dst.BindpointMapping.ReadWriteResources[refl->ReadWriteResources[i].bindPoint].used = true;
|
||||
}
|
||||
|
||||
create_array_uninit(dst.ConstantBuffers, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT);
|
||||
for(size_t s = 0; s < D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT; s++)
|
||||
{
|
||||
dst.ConstantBuffers[s].Buffer = rm->GetOriginalID(GetIDForResource(src.ConstantBuffers[s]));
|
||||
dst.ConstantBuffers[s].VecOffset = src.CBOffsets[s];
|
||||
dst.ConstantBuffers[s].VecCount = src.CBCounts[s];
|
||||
}
|
||||
|
||||
create_array_uninit(dst.Samplers, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT);
|
||||
for(size_t s = 0; s < D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT; s++)
|
||||
{
|
||||
D3D11PipelineState::ShaderStage::Sampler &samp = dst.Samplers[s];
|
||||
|
||||
samp.Samp = rm->GetOriginalID(GetIDForResource(src.Samplers[s]));
|
||||
|
||||
if(samp.Samp != ResourceId())
|
||||
if(p.ParameterType == D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS && e.type == eRootConst)
|
||||
{
|
||||
samp.SamplerName = GetDebugName(src.Samplers[s]);
|
||||
samp.customSamplerName = true;
|
||||
D3D12PipelineState::CBuffer &cb =
|
||||
resize_and_add(spaces[p.Constants.RegisterSpace].cbuffers, p.Constants.ShaderRegister);
|
||||
cb.VisibilityMask = ConvertVisibility(p.ShaderVisibility);
|
||||
cb.Immediate = true;
|
||||
cb.RootElement = (uint32_t)rootEl;
|
||||
cb.ByteSize = uint32_t(sizeof(uint32_t) * p.Constants.Num32BitValues);
|
||||
|
||||
if(samp.SamplerName.count == 0)
|
||||
create_array_init(cb.RootValues, e.constants.size(), &e.constants[0]);
|
||||
}
|
||||
else if(p.ParameterType == D3D12_ROOT_PARAMETER_TYPE_CBV && e.type == eRootCBV)
|
||||
{
|
||||
D3D12PipelineState::CBuffer &cb =
|
||||
resize_and_add(spaces[p.Constants.RegisterSpace].cbuffers, p.Constants.ShaderRegister);
|
||||
cb.VisibilityMask = ConvertVisibility(p.ShaderVisibility);
|
||||
cb.Immediate = true;
|
||||
cb.RootElement = (uint32_t)rootEl;
|
||||
|
||||
ID3D12Resource *res = rm->GetCurrentAs<ID3D12Resource>(e.id);
|
||||
|
||||
cb.Buffer = rm->GetOriginalID(e.id);
|
||||
cb.Offset = e.offset;
|
||||
cb.ByteSize = uint32_t(res->GetDesc().Width - cb.Offset);
|
||||
}
|
||||
else if(p.ParameterType == D3D12_ROOT_PARAMETER_TYPE_SRV && e.type == eRootSRV)
|
||||
{
|
||||
D3D12PipelineState::ResourceView &view =
|
||||
resize_and_add(spaces[p.Constants.RegisterSpace].srvs, p.Constants.ShaderRegister);
|
||||
view.VisibilityMask = ConvertVisibility(p.ShaderVisibility);
|
||||
view.Immediate = true;
|
||||
view.RootElement = (uint32_t)rootEl;
|
||||
|
||||
ID3D12Resource *res = rm->GetCurrentAs<ID3D12Resource>(e.id);
|
||||
|
||||
// parameters from resource/view
|
||||
view.Resource = rm->GetOriginalID(e.id);
|
||||
view.Type = ToStr::Get(D3D12_SRV_DIMENSION_BUFFER);
|
||||
view.Format = MakeResourceFormat(DXGI_FORMAT_R32_UINT);
|
||||
|
||||
view.ElementSize = sizeof(uint32_t);
|
||||
view.FirstElement = e.offset / sizeof(uint32_t);
|
||||
view.NumElements = uint32_t((res->GetDesc().Width - e.offset) / sizeof(uint32_t));
|
||||
}
|
||||
else if(p.ParameterType == D3D12_ROOT_PARAMETER_TYPE_UAV && e.type == eRootUAV)
|
||||
{
|
||||
D3D12PipelineState::ResourceView &view =
|
||||
resize_and_add(spaces[p.Constants.RegisterSpace].uavs, p.Constants.ShaderRegister);
|
||||
view.VisibilityMask = ConvertVisibility(p.ShaderVisibility);
|
||||
view.Immediate = true;
|
||||
view.RootElement = (uint32_t)rootEl;
|
||||
|
||||
ID3D12Resource *res = rm->GetCurrentAs<ID3D12Resource>(e.id);
|
||||
|
||||
// parameters from resource/view
|
||||
view.Resource = rm->GetOriginalID(e.id);
|
||||
view.Type = ToStr::Get(D3D12_UAV_DIMENSION_BUFFER);
|
||||
view.Format = MakeResourceFormat(DXGI_FORMAT_R32_UINT);
|
||||
|
||||
view.ElementSize = sizeof(uint32_t);
|
||||
view.FirstElement = e.offset / sizeof(uint32_t);
|
||||
view.NumElements = uint32_t((res->GetDesc().Width - e.offset) / sizeof(uint32_t));
|
||||
}
|
||||
else if(p.ParameterType == D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE && e.type == eRootTable)
|
||||
{
|
||||
WrappedID3D12DescriptorHeap *heap = rm->GetCurrentAs<WrappedID3D12DescriptorHeap>(e.id);
|
||||
|
||||
UINT prevTableOffset = 0;
|
||||
|
||||
for(size_t r = 0; r < p.ranges.size(); r++)
|
||||
{
|
||||
samp.customSamplerName = false;
|
||||
samp.SamplerName = StringFormat::Fmt("Sampler %llu", samp.Samp);
|
||||
const D3D12_DESCRIPTOR_RANGE &range = p.ranges[r];
|
||||
|
||||
UINT shaderReg = range.BaseShaderRegister;
|
||||
UINT regSpace = range.RegisterSpace;
|
||||
|
||||
D3D12Descriptor *desc = (D3D12Descriptor *)heap->GetCPUDescriptorHandleForHeapStart().ptr;
|
||||
|
||||
UINT offset = range.OffsetInDescriptorsFromTableStart;
|
||||
|
||||
if(range.OffsetInDescriptorsFromTableStart == D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND)
|
||||
offset = prevTableOffset;
|
||||
|
||||
desc += offset;
|
||||
|
||||
prevTableOffset = offset + range.NumDescriptors;
|
||||
|
||||
if(range.RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER)
|
||||
{
|
||||
UINT maxReg = shaderReg + range.NumDescriptors - 1;
|
||||
if(maxReg >= spaces[regSpace].samplers.size())
|
||||
spaces[regSpace].samplers.resize(maxReg + 1);
|
||||
|
||||
for(UINT i = 0; i < range.NumDescriptors; i++, desc++, shaderReg++)
|
||||
{
|
||||
D3D12PipelineState::Sampler &samp = spaces[regSpace].samplers[shaderReg];
|
||||
samp.VisibilityMask = ConvertVisibility(p.ShaderVisibility);
|
||||
samp.Immediate = false;
|
||||
samp.RootElement = (uint32_t)rootEl;
|
||||
|
||||
D3D12_SAMPLER_DESC &sampDesc = desc->samp.desc;
|
||||
|
||||
samp.AddressU = ToStr::Get(sampDesc.AddressU);
|
||||
samp.AddressV = ToStr::Get(sampDesc.AddressV);
|
||||
samp.AddressW = ToStr::Get(sampDesc.AddressW);
|
||||
|
||||
memcpy(samp.BorderColor, sampDesc.BorderColor, sizeof(FLOAT) * 4);
|
||||
|
||||
samp.Comparison = ToStr::Get(sampDesc.ComparisonFunc);
|
||||
samp.Filter = ToStr::Get(sampDesc.Filter);
|
||||
samp.MaxAniso = 0;
|
||||
if(sampDesc.Filter == D3D12_FILTER_ANISOTROPIC ||
|
||||
sampDesc.Filter == D3D12_FILTER_COMPARISON_ANISOTROPIC ||
|
||||
sampDesc.Filter == D3D12_FILTER_MINIMUM_ANISOTROPIC ||
|
||||
sampDesc.Filter == D3D12_FILTER_MAXIMUM_ANISOTROPIC)
|
||||
samp.MaxAniso = sampDesc.MaxAnisotropy;
|
||||
samp.MaxLOD = sampDesc.MaxLOD;
|
||||
samp.MinLOD = sampDesc.MinLOD;
|
||||
samp.MipLODBias = sampDesc.MipLODBias;
|
||||
samp.UseComparison = (sampDesc.Filter >= D3D12_FILTER_COMPARISON_MIN_MAG_MIP_POINT &&
|
||||
sampDesc.Filter <= D3D12_FILTER_COMPARISON_ANISOTROPIC);
|
||||
samp.UseBorder = (sampDesc.AddressU == D3D12_TEXTURE_ADDRESS_MODE_BORDER ||
|
||||
sampDesc.AddressV == D3D12_TEXTURE_ADDRESS_MODE_BORDER ||
|
||||
sampDesc.AddressW == D3D12_TEXTURE_ADDRESS_MODE_BORDER);
|
||||
}
|
||||
}
|
||||
else if(range.RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_CBV)
|
||||
{
|
||||
UINT maxReg = shaderReg + range.NumDescriptors - 1;
|
||||
if(maxReg >= spaces[regSpace].cbuffers.size())
|
||||
spaces[regSpace].cbuffers.resize(maxReg + 1);
|
||||
|
||||
for(UINT i = 0; i < range.NumDescriptors; i++, desc++, shaderReg++)
|
||||
{
|
||||
D3D12PipelineState::CBuffer &cb = spaces[regSpace].cbuffers[shaderReg];
|
||||
cb.VisibilityMask = ConvertVisibility(p.ShaderVisibility);
|
||||
cb.Immediate = false;
|
||||
cb.RootElement = (uint32_t)rootEl;
|
||||
|
||||
WrappedID3D12Resource::GetResIDFromAddr(desc->nonsamp.cbv.BufferLocation, cb.Buffer,
|
||||
cb.Offset);
|
||||
cb.Buffer = rm->GetOriginalID(cb.Buffer);
|
||||
cb.ByteSize = desc->nonsamp.cbv.SizeInBytes;
|
||||
}
|
||||
}
|
||||
else if(range.RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_SRV)
|
||||
{
|
||||
UINT maxReg = shaderReg + range.NumDescriptors - 1;
|
||||
if(maxReg >= spaces[regSpace].srvs.size())
|
||||
spaces[regSpace].srvs.resize(maxReg + 1);
|
||||
|
||||
for(UINT i = 0; i < range.NumDescriptors; i++, desc++, shaderReg++)
|
||||
{
|
||||
D3D12PipelineState::ResourceView &view = spaces[regSpace].srvs[shaderReg];
|
||||
view.VisibilityMask = ConvertVisibility(p.ShaderVisibility);
|
||||
view.Immediate = false;
|
||||
view.RootElement = (uint32_t)rootEl;
|
||||
|
||||
FillResourceView(view, desc);
|
||||
}
|
||||
}
|
||||
else if(range.RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_UAV)
|
||||
{
|
||||
UINT maxReg = shaderReg + range.NumDescriptors - 1;
|
||||
if(maxReg >= spaces[regSpace].uavs.size())
|
||||
spaces[regSpace].uavs.resize(maxReg + 1);
|
||||
|
||||
for(UINT i = 0; i < range.NumDescriptors; i++, desc++, shaderReg++)
|
||||
{
|
||||
D3D12PipelineState::ResourceView &view = spaces[regSpace].uavs[shaderReg];
|
||||
view.VisibilityMask = ConvertVisibility(p.ShaderVisibility);
|
||||
view.Immediate = false;
|
||||
view.RootElement = (uint32_t)rootEl;
|
||||
|
||||
FillResourceView(view, desc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
D3D11_SAMPLER_DESC desc;
|
||||
src.Samplers[s]->GetDesc(&desc);
|
||||
|
||||
samp.AddressU = ToStr::Get(desc.AddressU);
|
||||
samp.AddressV = ToStr::Get(desc.AddressV);
|
||||
samp.AddressW = ToStr::Get(desc.AddressW);
|
||||
|
||||
memcpy(samp.BorderColor, desc.BorderColor, sizeof(FLOAT) * 4);
|
||||
|
||||
samp.Comparison = ToStr::Get(desc.ComparisonFunc);
|
||||
samp.Filter = ToStr::Get(desc.Filter);
|
||||
samp.MaxAniso = 0;
|
||||
if(desc.Filter == D3D11_FILTER_ANISOTROPIC ||
|
||||
desc.Filter == D3D11_FILTER_COMPARISON_ANISOTROPIC)
|
||||
samp.MaxAniso = desc.MaxAnisotropy;
|
||||
samp.MaxLOD = desc.MaxLOD;
|
||||
samp.MinLOD = desc.MinLOD;
|
||||
samp.MipLODBias = desc.MipLODBias;
|
||||
samp.UseComparison = (desc.Filter >= D3D11_FILTER_COMPARISON_MIN_MAG_MIP_POINT);
|
||||
samp.UseBorder = (desc.AddressU == D3D11_TEXTURE_ADDRESS_BORDER ||
|
||||
desc.AddressV == D3D11_TEXTURE_ADDRESS_BORDER ||
|
||||
desc.AddressW == D3D11_TEXTURE_ADDRESS_BORDER);
|
||||
}
|
||||
}
|
||||
|
||||
create_array_uninit(dst.SRVs, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT);
|
||||
for(size_t s = 0; s < D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT; s++)
|
||||
for(size_t i = 0; i < sig->sig.samplers.size(); i++)
|
||||
{
|
||||
D3D11PipelineState::ShaderStage::ResourceView &view = dst.SRVs[s];
|
||||
D3D12_STATIC_SAMPLER_DESC &sampDesc = sig->sig.samplers[i];
|
||||
|
||||
view.View = rm->GetOriginalID(GetIDForResource(src.SRVs[s]));
|
||||
D3D12PipelineState::Sampler &samp =
|
||||
resize_and_add(spaces[sampDesc.RegisterSpace].samplers, sampDesc.ShaderRegister);
|
||||
samp.VisibilityMask = ConvertVisibility(sampDesc.ShaderVisibility);
|
||||
samp.Immediate = true;
|
||||
samp.RootElement = (uint32_t)i;
|
||||
|
||||
if(view.View != ResourceId())
|
||||
samp.AddressU = ToStr::Get(sampDesc.AddressU);
|
||||
samp.AddressV = ToStr::Get(sampDesc.AddressV);
|
||||
samp.AddressW = ToStr::Get(sampDesc.AddressW);
|
||||
|
||||
if(sampDesc.BorderColor == D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK)
|
||||
{
|
||||
D3D11_SHADER_RESOURCE_VIEW_DESC desc;
|
||||
src.SRVs[s]->GetDesc(&desc);
|
||||
|
||||
view.Format = MakeResourceFormat(desc.Format);
|
||||
|
||||
ID3D11Resource *res = NULL;
|
||||
src.SRVs[s]->GetResource(&res);
|
||||
|
||||
view.Structured = false;
|
||||
view.BufferStructCount = 0;
|
||||
|
||||
view.ElementSize =
|
||||
desc.Format == DXGI_FORMAT_UNKNOWN ? 1 : GetByteSize(1, 1, 1, desc.Format, 0);
|
||||
|
||||
view.Resource = rm->GetOriginalID(GetIDForResource(res));
|
||||
|
||||
view.Type = ToStr::Get(desc.ViewDimension);
|
||||
|
||||
if(desc.ViewDimension == D3D11_SRV_DIMENSION_BUFFER)
|
||||
{
|
||||
view.FirstElement = desc.Buffer.FirstElement;
|
||||
view.NumElements = desc.Buffer.NumElements;
|
||||
view.ElementOffset = desc.Buffer.ElementOffset;
|
||||
view.ElementWidth = desc.Buffer.ElementWidth;
|
||||
|
||||
D3D11_BUFFER_DESC bufdesc;
|
||||
((ID3D11Buffer *)res)->GetDesc(&bufdesc);
|
||||
|
||||
view.Structured = bufdesc.StructureByteStride > 0 && desc.Format == DXGI_FORMAT_UNKNOWN;
|
||||
|
||||
if(view.Structured)
|
||||
view.ElementSize = bufdesc.StructureByteStride;
|
||||
}
|
||||
else if(desc.ViewDimension == D3D11_SRV_DIMENSION_BUFFEREX)
|
||||
{
|
||||
view.FirstElement = desc.BufferEx.FirstElement;
|
||||
view.NumElements = desc.BufferEx.NumElements;
|
||||
view.Flags = desc.BufferEx.Flags;
|
||||
}
|
||||
else if(desc.ViewDimension == D3D11_SRV_DIMENSION_TEXTURE1D)
|
||||
{
|
||||
view.HighestMip = desc.Texture1D.MostDetailedMip;
|
||||
view.NumMipLevels = desc.Texture1D.MipLevels;
|
||||
}
|
||||
else if(desc.ViewDimension == D3D11_SRV_DIMENSION_TEXTURE1DARRAY)
|
||||
{
|
||||
view.ArraySize = desc.Texture1DArray.ArraySize;
|
||||
view.FirstArraySlice = desc.Texture1DArray.FirstArraySlice;
|
||||
view.HighestMip = desc.Texture1DArray.MostDetailedMip;
|
||||
view.NumMipLevels = desc.Texture1DArray.MipLevels;
|
||||
}
|
||||
else if(desc.ViewDimension == D3D11_SRV_DIMENSION_TEXTURE2D)
|
||||
{
|
||||
view.HighestMip = desc.Texture2D.MostDetailedMip;
|
||||
view.NumMipLevels = desc.Texture2D.MipLevels;
|
||||
}
|
||||
else if(desc.ViewDimension == D3D11_SRV_DIMENSION_TEXTURE2DARRAY)
|
||||
{
|
||||
view.ArraySize = desc.Texture2DArray.ArraySize;
|
||||
view.FirstArraySlice = desc.Texture2DArray.FirstArraySlice;
|
||||
view.HighestMip = desc.Texture2DArray.MostDetailedMip;
|
||||
view.NumMipLevels = desc.Texture2DArray.MipLevels;
|
||||
}
|
||||
else if(desc.ViewDimension == D3D11_SRV_DIMENSION_TEXTURE2DMS)
|
||||
{
|
||||
}
|
||||
else if(desc.ViewDimension == D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY)
|
||||
{
|
||||
view.ArraySize = desc.Texture2DArray.ArraySize;
|
||||
view.FirstArraySlice = desc.Texture2DArray.FirstArraySlice;
|
||||
}
|
||||
else if(desc.ViewDimension == D3D11_SRV_DIMENSION_TEXTURE3D)
|
||||
{
|
||||
view.HighestMip = desc.Texture3D.MostDetailedMip;
|
||||
view.NumMipLevels = desc.Texture3D.MipLevels;
|
||||
}
|
||||
else if(desc.ViewDimension == D3D11_SRV_DIMENSION_TEXTURECUBE)
|
||||
{
|
||||
view.ArraySize = 6;
|
||||
view.HighestMip = desc.TextureCube.MostDetailedMip;
|
||||
view.NumMipLevels = desc.TextureCube.MipLevels;
|
||||
}
|
||||
else if(desc.ViewDimension == D3D11_SRV_DIMENSION_TEXTURECUBEARRAY)
|
||||
{
|
||||
view.ArraySize = desc.TextureCubeArray.NumCubes * 6;
|
||||
view.FirstArraySlice = desc.TextureCubeArray.First2DArrayFace;
|
||||
view.HighestMip = desc.TextureCubeArray.MostDetailedMip;
|
||||
view.NumMipLevels = desc.TextureCubeArray.MipLevels;
|
||||
}
|
||||
|
||||
SAFE_RELEASE(res);
|
||||
samp.BorderColor[0] = 0.0f;
|
||||
samp.BorderColor[1] = 0.0f;
|
||||
samp.BorderColor[2] = 0.0f;
|
||||
samp.BorderColor[3] = 0.0f;
|
||||
}
|
||||
else if(sampDesc.BorderColor == D3D12_STATIC_BORDER_COLOR_OPAQUE_BLACK)
|
||||
{
|
||||
samp.BorderColor[0] = 0.0f;
|
||||
samp.BorderColor[1] = 0.0f;
|
||||
samp.BorderColor[2] = 0.0f;
|
||||
samp.BorderColor[3] = 1.0f;
|
||||
}
|
||||
else if(sampDesc.BorderColor == D3D12_STATIC_BORDER_COLOR_OPAQUE_WHITE)
|
||||
{
|
||||
samp.BorderColor[0] = 1.0f;
|
||||
samp.BorderColor[1] = 1.0f;
|
||||
samp.BorderColor[2] = 1.0f;
|
||||
samp.BorderColor[3] = 1.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
RDCERR("Unexpected static border colour: %u", sampDesc.BorderColor);
|
||||
}
|
||||
|
||||
samp.Comparison = ToStr::Get(sampDesc.ComparisonFunc);
|
||||
samp.Filter = ToStr::Get(sampDesc.Filter);
|
||||
samp.MaxAniso = 0;
|
||||
if(sampDesc.Filter == D3D12_FILTER_ANISOTROPIC ||
|
||||
sampDesc.Filter == D3D12_FILTER_COMPARISON_ANISOTROPIC ||
|
||||
sampDesc.Filter == D3D12_FILTER_MINIMUM_ANISOTROPIC ||
|
||||
sampDesc.Filter == D3D12_FILTER_MAXIMUM_ANISOTROPIC)
|
||||
samp.MaxAniso = sampDesc.MaxAnisotropy;
|
||||
samp.MaxLOD = sampDesc.MaxLOD;
|
||||
samp.MinLOD = sampDesc.MinLOD;
|
||||
samp.MipLODBias = sampDesc.MipLODBias;
|
||||
samp.UseComparison = (sampDesc.Filter >= D3D12_FILTER_COMPARISON_MIN_MAG_MIP_POINT &&
|
||||
sampDesc.Filter <= D3D12_FILTER_COMPARISON_ANISOTROPIC);
|
||||
samp.UseBorder = (sampDesc.AddressU == D3D12_TEXTURE_ADDRESS_MODE_BORDER ||
|
||||
sampDesc.AddressV == D3D12_TEXTURE_ADDRESS_MODE_BORDER ||
|
||||
sampDesc.AddressW == D3D12_TEXTURE_ADDRESS_MODE_BORDER);
|
||||
}
|
||||
|
||||
create_array(dst.UAVs, D3D11_1_UAV_SLOT_COUNT);
|
||||
for(size_t s = 0; dst.stage == eShaderStage_Compute && s < D3D11_1_UAV_SLOT_COUNT; s++)
|
||||
for(uint32_t i = 0; i < sig->sig.numSpaces; i++)
|
||||
{
|
||||
D3D11PipelineState::ShaderStage::ResourceView &view = dst.UAVs[s];
|
||||
|
||||
view.View = rm->GetOriginalID(GetIDForResource(rs.CSUAVs[s]));
|
||||
|
||||
if(view.View != ResourceId())
|
||||
{
|
||||
D3D11_UNORDERED_ACCESS_VIEW_DESC desc;
|
||||
rs.CSUAVs[s]->GetDesc(&desc);
|
||||
|
||||
ID3D11Resource *res = NULL;
|
||||
rs.CSUAVs[s]->GetResource(&res);
|
||||
|
||||
view.Structured = false;
|
||||
view.BufferStructCount = 0;
|
||||
|
||||
view.ElementSize =
|
||||
desc.Format == DXGI_FORMAT_UNKNOWN ? 1 : GetByteSize(1, 1, 1, desc.Format, 0);
|
||||
|
||||
if(desc.ViewDimension == D3D11_UAV_DIMENSION_BUFFER &&
|
||||
(desc.Buffer.Flags & (D3D11_BUFFER_UAV_FLAG_APPEND | D3D11_BUFFER_UAV_FLAG_COUNTER)))
|
||||
{
|
||||
view.BufferStructCount = m_pDevice->GetDebugManager()->GetStructCount(rs.CSUAVs[s]);
|
||||
}
|
||||
|
||||
view.Resource = rm->GetOriginalID(GetIDForResource(res));
|
||||
|
||||
view.Format = MakeResourceFormat(desc.Format);
|
||||
view.Type = ToStr::Get(desc.ViewDimension);
|
||||
|
||||
if(desc.ViewDimension == D3D11_UAV_DIMENSION_BUFFER)
|
||||
{
|
||||
view.FirstElement = desc.Buffer.FirstElement;
|
||||
view.NumElements = desc.Buffer.NumElements;
|
||||
view.Flags = desc.Buffer.Flags;
|
||||
|
||||
D3D11_BUFFER_DESC bufdesc;
|
||||
((ID3D11Buffer *)res)->GetDesc(&bufdesc);
|
||||
|
||||
view.Structured = bufdesc.StructureByteStride > 0 && desc.Format == DXGI_FORMAT_UNKNOWN;
|
||||
|
||||
if(view.Structured)
|
||||
view.ElementSize = bufdesc.StructureByteStride;
|
||||
}
|
||||
else if(desc.ViewDimension == D3D11_UAV_DIMENSION_TEXTURE1D)
|
||||
{
|
||||
view.HighestMip = desc.Texture1D.MipSlice;
|
||||
view.NumMipLevels = 1;
|
||||
}
|
||||
else if(desc.ViewDimension == D3D11_UAV_DIMENSION_TEXTURE1DARRAY)
|
||||
{
|
||||
view.ArraySize = desc.Texture1DArray.ArraySize;
|
||||
view.FirstArraySlice = desc.Texture1DArray.FirstArraySlice;
|
||||
view.HighestMip = desc.Texture1DArray.MipSlice;
|
||||
view.NumMipLevels = 1;
|
||||
}
|
||||
else if(desc.ViewDimension == D3D11_UAV_DIMENSION_TEXTURE2D)
|
||||
{
|
||||
view.HighestMip = desc.Texture2D.MipSlice;
|
||||
view.NumMipLevels = 1;
|
||||
}
|
||||
else if(desc.ViewDimension == D3D11_UAV_DIMENSION_TEXTURE2DARRAY)
|
||||
{
|
||||
view.ArraySize = desc.Texture2DArray.ArraySize;
|
||||
view.FirstArraySlice = desc.Texture2DArray.FirstArraySlice;
|
||||
view.HighestMip = desc.Texture2DArray.MipSlice;
|
||||
view.NumMipLevels = 1;
|
||||
}
|
||||
else if(desc.ViewDimension == D3D11_UAV_DIMENSION_TEXTURE3D)
|
||||
{
|
||||
view.ArraySize = desc.Texture3D.WSize;
|
||||
view.FirstArraySlice = desc.Texture3D.FirstWSlice;
|
||||
view.HighestMip = desc.Texture3D.MipSlice;
|
||||
view.NumMipLevels = 1;
|
||||
}
|
||||
|
||||
SAFE_RELEASE(res);
|
||||
}
|
||||
state.m_RootSig.Spaces[i].ConstantBuffers = spaces[i].cbuffers;
|
||||
state.m_RootSig.Spaces[i].Samplers = spaces[i].samplers;
|
||||
state.m_RootSig.Spaces[i].SRVs = spaces[i].srvs;
|
||||
state.m_RootSig.Spaces[i].UAVs = spaces[i].uavs;
|
||||
}
|
||||
|
||||
SAFE_DELETE_ARRAY(spaces);
|
||||
}
|
||||
#endif
|
||||
|
||||
if(pipe && pipe->IsGraphics())
|
||||
{
|
||||
@@ -994,18 +944,32 @@ void D3D12Replay::MakePipelineState()
|
||||
{
|
||||
D3D12PipelineState::ResourceView &view = state.m_OM.RenderTargets[i];
|
||||
|
||||
PortableHandle h = rs.rtSingle ? rs.rts[i] : rs.rts[i];
|
||||
PortableHandle h = rs.rtSingle ? rs.rts[0] : rs.rts[i];
|
||||
|
||||
if(rs.rtSingle)
|
||||
h.index += (uint32_t)i;
|
||||
if(h.heap != ResourceId())
|
||||
{
|
||||
WrappedID3D12DescriptorHeap *heap = rm->GetLiveAs<WrappedID3D12DescriptorHeap>(h.heap);
|
||||
D3D12Descriptor *desc =
|
||||
(D3D12Descriptor *)heap->GetCPUDescriptorHandleForHeapStart().ptr + h.index;
|
||||
|
||||
FillResourceView(view, h);
|
||||
if(rs.rtSingle)
|
||||
desc += i;
|
||||
|
||||
FillResourceView(view, desc);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
D3D12PipelineState::ResourceView &view = state.m_OM.DepthTarget;
|
||||
|
||||
FillResourceView(view, rs.dsv);
|
||||
if(rs.dsv.heap != ResourceId())
|
||||
{
|
||||
WrappedID3D12DescriptorHeap *heap = rm->GetLiveAs<WrappedID3D12DescriptorHeap>(rs.dsv.heap);
|
||||
D3D12Descriptor *desc =
|
||||
(D3D12Descriptor *)heap->GetCPUDescriptorHandleForHeapStart().ptr + rs.dsv.index;
|
||||
|
||||
FillResourceView(view, desc);
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(state.m_OM.m_BlendState.BlendFactor, rs.blendFactor, sizeof(FLOAT) * 4);
|
||||
|
||||
@@ -165,7 +165,7 @@ public:
|
||||
private:
|
||||
void MakePipelineState();
|
||||
|
||||
void FillResourceView(D3D12PipelineState::ResourceView &view, const PortableHandle &resHandle);
|
||||
void FillResourceView(D3D12PipelineState::ResourceView &view, D3D12Descriptor *desc);
|
||||
|
||||
bool m_Proxy;
|
||||
|
||||
|
||||
@@ -168,7 +168,7 @@ struct D3D12RenderState
|
||||
};
|
||||
vector<StreamOut> streamouts;
|
||||
|
||||
struct Pipeline
|
||||
struct RootSignature
|
||||
{
|
||||
ResourceId rootsig;
|
||||
|
||||
|
||||
@@ -109,6 +109,10 @@ namespace renderdoc
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public class ResourceView
|
||||
{
|
||||
public ShaderStageBits VisibilityMask;
|
||||
public bool Immediate;
|
||||
public UInt32 RootElement;
|
||||
|
||||
public ResourceId Resource;
|
||||
[CustomMarshalAs(CustomUnmanagedType.UTF8TemplatedString)]
|
||||
public string Type;
|
||||
@@ -141,6 +145,10 @@ namespace renderdoc
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public class Sampler
|
||||
{
|
||||
public ShaderStageBits VisibilityMask;
|
||||
public bool Immediate;
|
||||
public UInt32 RootElement;
|
||||
|
||||
[CustomMarshalAs(CustomUnmanagedType.UTF8TemplatedString)]
|
||||
public string AddressU, AddressV, AddressW;
|
||||
[CustomMarshalAs(CustomUnmanagedType.FixedArray, FixedLength = 4)]
|
||||
@@ -160,12 +168,16 @@ namespace renderdoc
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public class CBuffer
|
||||
{
|
||||
public ShaderStageBits VisibilityMask;
|
||||
public bool Immediate;
|
||||
public UInt32 RootElement;
|
||||
|
||||
public ResourceId Buffer;
|
||||
public UInt64 Offset;
|
||||
public UInt32 ByteSize;
|
||||
|
||||
[CustomMarshalAs(CustomUnmanagedType.TemplatedArray)]
|
||||
public UInt32[] Immediate;
|
||||
public UInt32[] RootValues;
|
||||
};
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
@@ -174,46 +186,20 @@ namespace renderdoc
|
||||
public ResourceId Obj;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public class CBufferDescriptor
|
||||
public class RegisterSpace
|
||||
{
|
||||
public ShaderStageBits VisibilityMask;
|
||||
public bool Immediate;
|
||||
public UInt32 RootElement;
|
||||
|
||||
[CustomMarshalAs(CustomUnmanagedType.CustomClass)]
|
||||
CBuffer obj;
|
||||
};
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public class ViewDescriptor
|
||||
{
|
||||
public ShaderStageBits VisibilityMask;
|
||||
public bool Immediate;
|
||||
public UInt32 RootElement;
|
||||
|
||||
[CustomMarshalAs(CustomUnmanagedType.CustomClass)]
|
||||
ResourceView obj;
|
||||
};
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public class SamplerDescriptor
|
||||
{
|
||||
public ShaderStageBits VisibilityMask;
|
||||
public bool Immediate;
|
||||
public UInt32 RootElement;
|
||||
|
||||
[CustomMarshalAs(CustomUnmanagedType.CustomClass)]
|
||||
Sampler obj;
|
||||
[CustomMarshalAs(CustomUnmanagedType.TemplatedArray)]
|
||||
public CBuffer[] ConstantBuffers;
|
||||
[CustomMarshalAs(CustomUnmanagedType.TemplatedArray)]
|
||||
public Sampler[] Samplers;
|
||||
[CustomMarshalAs(CustomUnmanagedType.TemplatedArray)]
|
||||
public ResourceView[] SRVs;
|
||||
[CustomMarshalAs(CustomUnmanagedType.TemplatedArray)]
|
||||
public ResourceView[] UAVs;
|
||||
};
|
||||
|
||||
[CustomMarshalAs(CustomUnmanagedType.TemplatedArray)]
|
||||
public CBufferDescriptor[] ConstantBuffers;
|
||||
[CustomMarshalAs(CustomUnmanagedType.TemplatedArray)]
|
||||
public SamplerDescriptor[] Samplers;
|
||||
[CustomMarshalAs(CustomUnmanagedType.TemplatedArray)]
|
||||
public ViewDescriptor[] SRVs;
|
||||
[CustomMarshalAs(CustomUnmanagedType.TemplatedArray)]
|
||||
public ViewDescriptor[] UAVs;
|
||||
public RegisterSpace[] Spaces;
|
||||
};
|
||||
[CustomMarshalAs(CustomUnmanagedType.CustomClass)]
|
||||
public RootSignature m_RootSig;
|
||||
|
||||
Reference in New Issue
Block a user