Process cbuffer/structure types with type annotations

This commit is contained in:
baldurk
2020-06-18 17:22:43 +01:00
parent c112b3d2c0
commit be65ec48d7
7 changed files with 330 additions and 83 deletions
@@ -615,7 +615,7 @@ bool D3D11Replay::RenderTextureInternal(TextureDisplay cfg, TexDisplayFlags flag
if(var.name == "RENDERDOC_TexDim")
{
if(var.type.descriptor.rows == 1 && var.type.descriptor.cols == 4 &&
var.type.descriptor.type == DXBC::VARTYPE_UINT)
var.type.descriptor.varType == VarType::UInt)
{
uint32_t *d = (uint32_t *)(byteData + var.offset);
@@ -645,7 +645,7 @@ bool D3D11Replay::RenderTextureInternal(TextureDisplay cfg, TexDisplayFlags flag
else if(var.name == "RENDERDOC_SelectedMip")
{
if(var.type.descriptor.rows == 1 && var.type.descriptor.cols == 1 &&
var.type.descriptor.type == DXBC::VARTYPE_UINT)
var.type.descriptor.varType == VarType::UInt)
{
uint32_t *d = (uint32_t *)(byteData + var.offset);
@@ -660,7 +660,7 @@ bool D3D11Replay::RenderTextureInternal(TextureDisplay cfg, TexDisplayFlags flag
else if(var.name == "RENDERDOC_SelectedSliceFace")
{
if(var.type.descriptor.rows == 1 && var.type.descriptor.cols == 1 &&
var.type.descriptor.type == DXBC::VARTYPE_UINT)
var.type.descriptor.varType == VarType::UInt)
{
uint32_t *d = (uint32_t *)(byteData + var.offset);
@@ -675,7 +675,7 @@ bool D3D11Replay::RenderTextureInternal(TextureDisplay cfg, TexDisplayFlags flag
else if(var.name == "RENDERDOC_SelectedSample")
{
if(var.type.descriptor.rows == 1 && var.type.descriptor.cols == 1 &&
var.type.descriptor.type == DXBC::VARTYPE_INT)
var.type.descriptor.varType == VarType::SInt)
{
int32_t *d = (int32_t *)(byteData + var.offset);
@@ -690,7 +690,7 @@ bool D3D11Replay::RenderTextureInternal(TextureDisplay cfg, TexDisplayFlags flag
else if(var.name == "RENDERDOC_TextureType")
{
if(var.type.descriptor.rows == 1 && var.type.descriptor.cols == 1 &&
var.type.descriptor.type == DXBC::VARTYPE_UINT)
var.type.descriptor.varType == VarType::UInt)
{
uint32_t *d = (uint32_t *)(byteData + var.offset);
@@ -542,7 +542,7 @@ bool D3D12Replay::RenderTextureInternal(D3D12_CPU_DESCRIPTOR_HANDLE rtv, Texture
if(var.name == "RENDERDOC_TexDim")
{
if(var.type.descriptor.rows == 1 && var.type.descriptor.cols == 4 &&
var.type.descriptor.type == DXBC::VARTYPE_UINT)
var.type.descriptor.varType == VarType::UInt)
{
uint32_t *d = (uint32_t *)(byteData + var.offset);
@@ -576,7 +576,7 @@ bool D3D12Replay::RenderTextureInternal(D3D12_CPU_DESCRIPTOR_HANDLE rtv, Texture
else if(var.name == "RENDERDOC_SelectedMip")
{
if(var.type.descriptor.rows == 1 && var.type.descriptor.cols == 1 &&
var.type.descriptor.type == DXBC::VARTYPE_UINT)
var.type.descriptor.varType == VarType::UInt)
{
uint32_t *d = (uint32_t *)(byteData + var.offset);
@@ -591,7 +591,7 @@ bool D3D12Replay::RenderTextureInternal(D3D12_CPU_DESCRIPTOR_HANDLE rtv, Texture
else if(var.name == "RENDERDOC_SelectedSliceFace")
{
if(var.type.descriptor.rows == 1 && var.type.descriptor.cols == 1 &&
var.type.descriptor.type == DXBC::VARTYPE_UINT)
var.type.descriptor.varType == VarType::UInt)
{
uint32_t *d = (uint32_t *)(byteData + var.offset);
@@ -606,7 +606,7 @@ bool D3D12Replay::RenderTextureInternal(D3D12_CPU_DESCRIPTOR_HANDLE rtv, Texture
else if(var.name == "RENDERDOC_SelectedSample")
{
if(var.type.descriptor.rows == 1 && var.type.descriptor.cols == 1 &&
var.type.descriptor.type == DXBC::VARTYPE_INT)
var.type.descriptor.varType == VarType::SInt)
{
int32_t *d = (int32_t *)(byteData + var.offset);
@@ -621,7 +621,7 @@ bool D3D12Replay::RenderTextureInternal(D3D12_CPU_DESCRIPTOR_HANDLE rtv, Texture
else if(var.name == "RENDERDOC_TextureType")
{
if(var.type.descriptor.rows == 1 && var.type.descriptor.cols == 1 &&
var.type.descriptor.type == DXBC::VARTYPE_UINT)
var.type.descriptor.varType == VarType::UInt)
{
uint32_t *d = (uint32_t *)(byteData + var.offset);
@@ -358,7 +358,7 @@ DXBC::Reflection *Program::GuessReflection()
var.name = cb.name;
var.offset = 0;
var.type.descriptor.varClass = DXBC::VariableClass::CLASS_STRUCT;
var.type.descriptor.type = DXBC::VariableType::VARTYPE_VOID;
var.type.descriptor.varType = VarType::Unknown;
var.type.descriptor.rows = 1;
var.type.descriptor.cols = 4;
var.type.descriptor.elements = 1;
@@ -382,7 +382,7 @@ DXBC::Reflection *Program::GuessReflection()
var.type.descriptor.rows = 1;
var.type.descriptor.cols = 4;
var.type.descriptor.elements = 0;
var.type.descriptor.type = DXBC::VARTYPE_FLOAT;
var.type.descriptor.varType = VarType::Float;
var.type.descriptor.varClass = DXBC::CLASS_VECTOR;
var.type.descriptor.name = TypeName(var.type.descriptor);
+1 -1
View File
@@ -279,7 +279,7 @@ struct CBufferVariableType
struct Descriptor
{
VariableClass varClass;
VariableType type;
VarType varType;
uint32_t rows;
uint32_t cols;
uint32_t elements;
@@ -265,32 +265,6 @@ static const uint32_t FOURCC_HASH = MAKE_FOURCC('H', 'A', 'S', 'H');
static const uint32_t FOURCC_SFI0 = MAKE_FOURCC('S', 'F', 'I', '0');
static const uint32_t FOURCC_PSV0 = MAKE_FOURCC('P', 'S', 'V', '0');
int TypeByteSize(VariableType t)
{
switch(t)
{
case VARTYPE_UINT8: return 1;
case VARTYPE_BOOL:
case VARTYPE_INT:
case VARTYPE_FLOAT:
case VARTYPE_UINT:
return 4;
// we pretend for our purposes that the 'min' formats round up to 4 bytes. For any external
// interfaces they are treated as regular types, only using lower precision internally.
case VARTYPE_MIN8FLOAT:
case VARTYPE_MIN10FLOAT:
case VARTYPE_MIN16FLOAT:
case VARTYPE_MIN12INT:
case VARTYPE_MIN16INT:
case VARTYPE_MIN16UINT: return 4;
case VARTYPE_DOUBLE:
return 8;
// 'virtual' type. Just return 1
case VARTYPE_INTERFACE_POINTER: return 1;
default: RDCERR("Trying to take size of undefined type %d", t); return 1;
}
}
ShaderBuiltin GetSystemValue(SVSemantic systemValue)
{
switch(systemValue)
@@ -333,22 +307,15 @@ rdcstr TypeName(CBufferVariableType::Descriptor desc)
rdcstr ret;
char *type = "";
switch(desc.type)
switch(desc.varType)
{
case VARTYPE_BOOL: type = "bool"; break;
case VARTYPE_INT: type = "int"; break;
case VARTYPE_FLOAT: type = "float"; break;
case VARTYPE_DOUBLE: type = "double"; break;
case VARTYPE_UINT: type = "uint"; break;
case VARTYPE_UINT8: type = "ubyte"; break;
case VARTYPE_VOID: type = "void"; break;
case VARTYPE_INTERFACE_POINTER: type = "interface"; break;
case VARTYPE_MIN8FLOAT: type = "min8float"; break;
case VARTYPE_MIN10FLOAT: type = "min10float"; break;
case VARTYPE_MIN16FLOAT: type = "min16float"; break;
case VARTYPE_MIN12INT: type = "min12int"; break;
case VARTYPE_MIN16INT: type = "min16int"; break;
case VARTYPE_MIN16UINT: type = "min16uint"; break;
case VarType::Bool: type = "bool"; break;
case VarType::SInt: type = "int"; break;
case VarType::Float: type = "float"; break;
case VarType::Double: type = "double"; break;
case VarType::UInt: type = "uint"; break;
case VarType::UByte: type = "ubyte"; break;
case VarType::Unknown: type = "void"; break;
default: RDCERR("Unexpected type in RDEF variable type %d", type);
}
@@ -398,7 +365,23 @@ CBufferVariableType DXBCContainer::ParseRDEFType(const RDEFHeader *h, const byte
ret.descriptor.cols = type->cols;
ret.descriptor.elements = type->numElems;
ret.descriptor.rows = type->rows;
ret.descriptor.type = (VariableType)type->varType;
switch((VariableType)type->varType)
{
// DXBC treats all cbuffer variables as 32-bit regardless of declaration
case DXBC::VARTYPE_MIN12INT:
case DXBC::VARTYPE_MIN16INT:
case DXBC::VARTYPE_INT: ret.descriptor.varType = VarType::SInt; break;
case DXBC::VARTYPE_BOOL: ret.descriptor.varType = VarType::Bool; break;
case DXBC::VARTYPE_MIN16UINT:
case DXBC::VARTYPE_UINT: ret.descriptor.varType = VarType::UInt; break;
case DXBC::VARTYPE_DOUBLE: ret.descriptor.varType = VarType::Double; break;
case DXBC::VARTYPE_FLOAT:
case DXBC::VARTYPE_MIN8FLOAT:
case DXBC::VARTYPE_MIN10FLOAT:
case DXBC::VARTYPE_MIN16FLOAT:
default: ret.descriptor.varType = VarType::Float; break;
}
ret.descriptor.name = TypeName(ret.descriptor);
@@ -457,12 +440,12 @@ CBufferVariableType DXBCContainer::ParseRDEFType(const RDEFHeader *h, const byte
// the other dimension
if(ret.descriptor.varClass == CLASS_MATRIX_COLUMNS)
{
ret.descriptor.bytesize = TypeByteSize(ret.descriptor.type) * ret.descriptor.cols * 4 *
ret.descriptor.bytesize = VarTypeByteSize(ret.descriptor.varType) * ret.descriptor.cols * 4 *
RDCMAX(1U, ret.descriptor.elements);
}
else if(ret.descriptor.varClass == CLASS_MATRIX_ROWS)
{
ret.descriptor.bytesize = TypeByteSize(ret.descriptor.type) * ret.descriptor.rows * 4 *
ret.descriptor.bytesize = VarTypeByteSize(ret.descriptor.varType) * ret.descriptor.rows * 4 *
RDCMAX(1U, ret.descriptor.elements);
}
else
@@ -470,10 +453,10 @@ CBufferVariableType DXBCContainer::ParseRDEFType(const RDEFHeader *h, const byte
// arrays also take up a full vector for each element
if(ret.descriptor.elements > 1)
ret.descriptor.bytesize =
TypeByteSize(ret.descriptor.type) * 4 * RDCMAX(1U, ret.descriptor.elements);
VarTypeByteSize(ret.descriptor.varType) * 4 * RDCMAX(1U, ret.descriptor.elements);
else
ret.descriptor.bytesize =
TypeByteSize(ret.descriptor.type) * ret.descriptor.rows * ret.descriptor.cols;
VarTypeByteSize(ret.descriptor.varType) * ret.descriptor.rows * ret.descriptor.cols;
}
}
+1 -16
View File
@@ -33,22 +33,7 @@ static ShaderVariableType MakeShaderVariableType(DXBC::CBufferVariableType type)
{
ShaderVariableType ret;
switch(type.descriptor.type)
{
// D3D treats all cbuffer variables as 32-bit regardless of declaration
case DXBC::VARTYPE_MIN12INT:
case DXBC::VARTYPE_MIN16INT:
case DXBC::VARTYPE_INT: ret.descriptor.type = VarType::SInt; break;
case DXBC::VARTYPE_BOOL: ret.descriptor.type = VarType::Bool; break;
case DXBC::VARTYPE_MIN16UINT:
case DXBC::VARTYPE_UINT: ret.descriptor.type = VarType::UInt; break;
case DXBC::VARTYPE_DOUBLE: ret.descriptor.type = VarType::Double; break;
case DXBC::VARTYPE_FLOAT:
case DXBC::VARTYPE_MIN8FLOAT:
case DXBC::VARTYPE_MIN10FLOAT:
case DXBC::VARTYPE_MIN16FLOAT:
default: ret.descriptor.type = VarType::Float; break;
}
ret.descriptor.type = type.descriptor.varType;
ret.descriptor.rows = (uint8_t)type.descriptor.rows;
ret.descriptor.columns = (uint8_t)type.descriptor.cols;
ret.descriptor.elements = type.descriptor.elements;
+287 -8
View File
@@ -118,6 +118,18 @@ enum class SRVUAVTag
StructStride = 1,
};
enum class StructMemberAnnotation
{
SNorm = 0,
UNorm = 1,
Matrix = 2,
CBufferOffset = 3,
SemanticString = 4,
InterpolationMode = 5,
FieldName = 6,
CompType = 7,
};
template <typename T>
T getival(const Metadata *m)
{
@@ -283,7 +295,261 @@ struct DXMeta
}
};
static DXBC::ShaderInputBind MakeResourceBind(const Metadata *r, const bool srv)
struct TypeInfo
{
struct MemberData
{
enum Flags : uint8_t
{
None = 0,
UNorm = 0x1,
SNorm = 0x2,
RowMajor = 0x4,
Matrix = 0x8,
} flags = None;
uint8_t rows = 0, cols = 0;
uint32_t offset;
rdcstr name;
ComponentType type;
};
struct StructData
{
uint32_t byteSize;
rdcarray<MemberData> members;
};
std::map<const Type *, StructData> structData;
TypeInfo(const Metadata *typeAnnotations)
{
RDCASSERT(typeAnnotations->children.size() >= 2, typeAnnotations->children.size());
const Metadata *structAnnotations = typeAnnotations->children[0];
RDCASSERTEQUAL(getival<uint32_t>(structAnnotations->children[0]), 0);
for(size_t c = 1; c < structAnnotations->children.size(); c += 2)
{
const Type *type = structAnnotations->children[c]->type;
const Metadata *structMembers = structAnnotations->children[c + 1];
RDCASSERT(structMembers->children.size() - 1 >= type->members.size(),
structMembers->children.size(), type->members.size());
StructData &data = structData[type];
data.byteSize = getival<uint32_t>(structMembers->children[0]);
data.members.resize(type->members.size());
for(size_t m = 0; m < type->members.size(); m++)
{
const Metadata *memberIn = structMembers->children[m + 1];
MemberData &memberOut = data.members[m];
for(size_t tag = 0; tag < memberIn->children.size(); tag += 2)
{
StructMemberAnnotation fieldTag = getival<StructMemberAnnotation>(memberIn->children[tag]);
switch(fieldTag)
{
case StructMemberAnnotation::SNorm:
{
if(getival<uint32_t>(memberIn->children[tag + 1]) != 0)
memberOut.flags = MemberData::Flags(memberOut.flags | MemberData::SNorm);
break;
}
case StructMemberAnnotation::UNorm:
{
if(getival<uint32_t>(memberIn->children[tag + 1]) != 0)
memberOut.flags = MemberData::Flags(memberOut.flags | MemberData::UNorm);
break;
}
case StructMemberAnnotation::Matrix:
{
const Metadata *matrixData = memberIn->children[tag + 1];
memberOut.rows = getival<uint8_t>(matrixData->children[0]);
memberOut.cols = getival<uint8_t>(matrixData->children[1]);
bool rowmajor = (getival<uint32_t>(matrixData->children[2]) == 1);
if(rowmajor)
memberOut.flags =
MemberData::Flags(memberOut.flags | MemberData::RowMajor | MemberData::Matrix);
else
memberOut.flags = MemberData::Flags(memberOut.flags | MemberData::Matrix);
break;
}
case StructMemberAnnotation::CBufferOffset:
memberOut.offset = getival<uint32_t>(memberIn->children[tag + 1]);
break;
case StructMemberAnnotation::SemanticString: break;
case StructMemberAnnotation::InterpolationMode: break;
case StructMemberAnnotation::FieldName:
memberOut.name = memberIn->children[tag + 1]->str;
break;
case StructMemberAnnotation::CompType:
memberOut.type = getival<ComponentType>(memberIn->children[tag + 1]);
break;
default: RDCWARN("Unexpected field tag %u", fieldTag); break;
}
}
}
}
}
};
static DXBC::CBufferVariableType MakeCBufferVariableType(const TypeInfo &typeInfo, const Type *t)
{
using namespace DXBC;
CBufferVariableType ret = {};
if(t->type == Type::Scalar || t->type == Type::Vector)
{
ret.descriptor.rows = ret.descriptor.cols = 1;
if(t->type == Type::Vector)
ret.descriptor.cols = t->elemCount;
ret.descriptor.bytesize = (t->bitWidth / 8) * ret.descriptor.cols;
ret.descriptor.varClass = CLASS_SCALAR;
if(t->scalarType == Type::Float)
{
if(t->bitWidth > 32)
ret.descriptor.varType = VarType::Double;
else if(t->bitWidth == 16)
ret.descriptor.varType = VarType::Half;
else
ret.descriptor.varType = VarType::Float;
}
else
{
// can't distinguish int/uint here, default to signed
if(t->bitWidth > 32)
ret.descriptor.varType = VarType::SLong;
else if(t->bitWidth == 32)
ret.descriptor.varType = VarType::SInt;
else if(t->bitWidth == 16)
ret.descriptor.varType = VarType::SShort;
else if(t->bitWidth == 8)
ret.descriptor.varType = VarType::SByte;
else if(t->bitWidth == 1)
ret.descriptor.varType = VarType::Bool;
}
return ret;
}
else if(t->type == Type::Array)
{
ret = MakeCBufferVariableType(typeInfo, t->inner);
ret.descriptor.elements = t->elemCount;
// assume normal D3D array packing with each element on float4 boundary
ret.descriptor.bytesize += (t->elemCount - 1) * 16;
return ret;
}
else if(t->type == Type::Struct)
{
// processing below
}
else
{
RDCERR("Unexpected type %u iterating cbuffer variable type %s", t->type, t->name.c_str());
return ret;
}
// if there are no members, return straight away
if(t->members.empty())
return ret;
auto it = typeInfo.structData.find(t);
if(it != typeInfo.structData.end())
{
ret.descriptor.bytesize = it->second.byteSize;
ret.descriptor.name = t->name;
if(ret.descriptor.name.beginsWith("struct."))
ret.descriptor.name.erase(0, 7);
if(ret.descriptor.name.beginsWith("class."))
ret.descriptor.name.erase(0, 6);
ret.descriptor.varType = VarType::Unknown;
ret.descriptor.varClass = CLASS_STRUCT;
}
else
{
RDCERR("Don't have struct type annotations for %s", t->name.c_str());
}
for(size_t i = 0; i < t->members.size(); i++)
{
CBufferVariable var;
var.type = MakeCBufferVariableType(typeInfo, t->members[i]);
if(it != typeInfo.structData.end())
{
var.name = it->second.members[i].name;
var.offset = it->second.members[i].offset;
if(it->second.members[i].flags & TypeInfo::MemberData::Matrix)
{
var.type.descriptor.rows = it->second.members[i].rows;
var.type.descriptor.cols = it->second.members[i].cols;
var.type.descriptor.varClass = (it->second.members[i].flags & TypeInfo::MemberData::RowMajor)
? CLASS_MATRIX_ROWS
: CLASS_MATRIX_COLUMNS;
}
if(var.type.members.empty() && t->members[i]->type != Type::Struct)
{
switch(it->second.members[i].type)
{
case ComponentType::Invalid:
var.type.descriptor.varType = VarType::Unknown;
RDCERR("Unexpected type in cbuffer annotations");
break;
case ComponentType::I1: var.type.descriptor.varType = VarType::Bool; break;
case ComponentType::I16: var.type.descriptor.varType = VarType::SShort; break;
case ComponentType::U16: var.type.descriptor.varType = VarType::UShort; break;
case ComponentType::I32: var.type.descriptor.varType = VarType::SInt; break;
case ComponentType::U32: var.type.descriptor.varType = VarType::UInt; break;
case ComponentType::I64: var.type.descriptor.varType = VarType::SLong; break;
case ComponentType::U64: var.type.descriptor.varType = VarType::ULong; break;
case ComponentType::F16: var.type.descriptor.varType = VarType::Half; break;
case ComponentType::F32: var.type.descriptor.varType = VarType::Float; break;
case ComponentType::F64: var.type.descriptor.varType = VarType::Double; break;
case ComponentType::SNormF16:
var.type.descriptor.varType = VarType::Half;
RDCERR("Unexpected type in cbuffer annotations");
break;
case ComponentType::UNormF16:
var.type.descriptor.varType = VarType::Half;
RDCERR("Unexpected type in cbuffer annotations");
break;
case ComponentType::SNormF32:
var.type.descriptor.varType = VarType::Float;
RDCERR("Unexpected type in cbuffer annotations");
break;
case ComponentType::UNormF32:
var.type.descriptor.varType = VarType::Float;
RDCERR("Unexpected type in cbuffer annotations");
break;
case ComponentType::SNormF64:
var.type.descriptor.varType = VarType::Double;
RDCERR("Unexpected type in cbuffer annotations");
break;
case ComponentType::UNormF64:
var.type.descriptor.varType = VarType::Double;
RDCERR("Unexpected type in cbuffer annotations");
break;
}
}
}
else
{
// TODO if we have to handle this case, we should try to calculate the offset
var.name = StringFormat::Fmt("_child%zu", i);
var.offset = 0;
}
ret.members.push_back(var);
}
return ret;
}
static void AddResourceBind(DXBC::Reflection *refl, const TypeInfo &typeInfo, const Metadata *r,
const bool srv)
{
using namespace DXBC;
@@ -300,6 +566,7 @@ static DXBC::ShaderInputBind MakeResourceBind(const Metadata *r, const bool srv)
bind.numComps = 1;
const Type *resType = r->children[(size_t)ResField::VarDecl]->type;
const Type *baseType = resType;
// variable should be a pointer to the underlying type
RDCASSERT(resType->type == Type::Pointer);
@@ -441,7 +708,18 @@ static DXBC::ShaderInputBind MakeResourceBind(const Metadata *r, const bool srv)
bind.type = ShaderInputBind::TYPE_UAV_RWSTRUCTURED_WITH_COUNTER;
}
return bind;
switch(shape)
{
case ResShape::StructuredBuffer:
case ResShape::StructuredBufferWithCounter:
refl->ResourceBinds[bind.name] = MakeCBufferVariableType(typeInfo, baseType->inner);
default: break;
}
if(srv)
refl->SRVs.push_back(bind);
else
refl->UAVs.push_back(bind);
}
DXBC::Reflection *Program::GetReflection()
@@ -452,6 +730,8 @@ DXBC::Reflection *Program::GetReflection()
DXMeta dx(m_NamedMeta);
TypeInfo typeInfo(dx.typeAnnotations);
if(dx.resources)
{
RDCASSERTEQUAL(dx.resources->children.size(), 1);
@@ -464,7 +744,7 @@ DXBC::Reflection *Program::GetReflection()
{
for(const Metadata *r : SRVs->children)
{
refl->SRVs.push_back(MakeResourceBind(r, true));
AddResourceBind(refl, typeInfo, r, true);
}
}
@@ -473,7 +753,7 @@ DXBC::Reflection *Program::GetReflection()
{
for(const Metadata *r : UAVs->children)
{
refl->UAVs.push_back(MakeResourceBind(r, false));
AddResourceBind(refl, typeInfo, r, false);
}
}
@@ -498,10 +778,9 @@ DXBC::Reflection *Program::GetReflection()
RDCASSERT(cbufType->type == Type::Pointer);
cbufType = cbufType->inner;
for(const Type *member : cbufType->members)
{
(void)member;
}
CBufferVariableType rootType = MakeCBufferVariableType(typeInfo, cbufType);
bind.variables.swap(rootType.members);
refl->CBuffers.push_back(bind);
}