From 6783f6a8512db95d0bb2eb62f7b0e1032f61619c Mon Sep 17 00:00:00 2001 From: baldurk Date: Wed, 17 Jun 2020 13:16:32 +0100 Subject: [PATCH] Improve handling if reflection information is stripped --- .../driver/shaders/dxil/dxil_reflect.cpp | 107 ++++++++++++++++-- 1 file changed, 98 insertions(+), 9 deletions(-) diff --git a/renderdoc/driver/shaders/dxil/dxil_reflect.cpp b/renderdoc/driver/shaders/dxil/dxil_reflect.cpp index ec04bdb25..ee230af8e 100644 --- a/renderdoc/driver/shaders/dxil/dxil_reflect.cpp +++ b/renderdoc/driver/shaders/dxil/dxil_reflect.cpp @@ -278,6 +278,9 @@ struct TypeInfo TypeInfo(const Metadata *typeAnnotations) { + if(!typeAnnotations) + return; + RDCASSERT(typeAnnotations->children.size() >= 2, typeAnnotations->children.size()); const Metadata *structAnnotations = typeAnnotations->children[0]; @@ -412,20 +415,23 @@ static DXBC::CBufferVariableType MakeCBufferVariableType(const TypeInfo &typeInf auto it = typeInfo.structData.find(t); + ret.descriptor.name = t->name; + ret.descriptor.varType = VarType::Unknown; + ret.descriptor.varClass = CLASS_STRUCT; + 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()); + // shouldn't get here if we don't have type information at all + RDCERR("Couldn't find type information for struct '%s'!", t->name.c_str()); + return ret; } for(size_t i = 0; i < t->members.size(); i++) @@ -493,7 +499,6 @@ static DXBC::CBufferVariableType MakeCBufferVariableType(const TypeInfo &typeInf } 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; } @@ -550,10 +555,15 @@ static void AddResourceBind(DXBC::Reflection *refl, const TypeInfo &typeInfo, co const Metadata *tags = srv ? r->children[(size_t)ResField::SRVTags] : r->children[(size_t)ResField::UAVTags]; + uint32_t structStride = 0; for(size_t t = 0; tags && t < tags->children.size(); t += 2) { RDCASSERT(tags->children[t]->value); - if(getival(tags->children[t]) == SRVUAVTag::ElementType) + if(getival(tags->children[t]) == SRVUAVTag::StructStride) + { + structStride = getival(tags->children[t + 1]); + } + else if(getival(tags->children[t]) == SRVUAVTag::ElementType) { switch(getival(tags->children[t + 1])) { @@ -582,6 +592,8 @@ static void AddResourceBind(DXBC::Reflection *refl, const TypeInfo &typeInfo, co ResourceKind shape = srv ? getival(r->children[(size_t)ResField::SRVShape]) : getival(r->children[(size_t)ResField::UAVShape]); + rdcstr defName; + switch(shape) { case ResourceKind::Unknown: @@ -592,66 +604,81 @@ static void AddResourceBind(DXBC::Reflection *refl, const TypeInfo &typeInfo, co case ResourceKind::FeedbackTexture2D: case ResourceKind::FeedbackTexture2DArray: RDCERR("Unexpected %s shape %u", srv ? "SRV" : "UAV", shape); + defName = srv ? "SRV" : "UAV"; break; case ResourceKind::Texture1D: bind.type = srv ? ShaderInputBind::TYPE_TEXTURE : ShaderInputBind::TYPE_UAV_RWTYPED; + defName = srv ? "Texture1D" : "RWTexture1D"; bind.dimension = ShaderInputBind::DIM_TEXTURE1D; break; case ResourceKind::Texture2D: bind.type = srv ? ShaderInputBind::TYPE_TEXTURE : ShaderInputBind::TYPE_UAV_RWTYPED; + defName = srv ? "Texture2D" : "RWTexture2D"; bind.dimension = ShaderInputBind::DIM_TEXTURE2D; break; case ResourceKind::Texture2DMS: bind.type = srv ? ShaderInputBind::TYPE_TEXTURE : ShaderInputBind::TYPE_UAV_RWTYPED; + defName = srv ? "Texture2DMS" : "RWTexture2DMS"; bind.dimension = ShaderInputBind::DIM_TEXTURE2DMS; break; case ResourceKind::Texture3D: bind.type = srv ? ShaderInputBind::TYPE_TEXTURE : ShaderInputBind::TYPE_UAV_RWTYPED; + defName = srv ? "Texture3D" : "RWTexture3D"; bind.dimension = ShaderInputBind::DIM_TEXTURE3D; break; case ResourceKind::TextureCube: bind.type = srv ? ShaderInputBind::TYPE_TEXTURE : ShaderInputBind::TYPE_UAV_RWTYPED; + defName = srv ? "TextureCube" : "RWTextureCube"; bind.dimension = ShaderInputBind::DIM_TEXTURECUBE; break; case ResourceKind::Texture1DArray: bind.type = srv ? ShaderInputBind::TYPE_TEXTURE : ShaderInputBind::TYPE_UAV_RWTYPED; + defName = srv ? "Texture1DArray" : "RWTexture1DArray"; bind.dimension = ShaderInputBind::DIM_TEXTURE1DARRAY; break; case ResourceKind::Texture2DArray: bind.type = srv ? ShaderInputBind::TYPE_TEXTURE : ShaderInputBind::TYPE_UAV_RWTYPED; + defName = srv ? "Texture2DArray" : "RWTexture2DArray"; bind.dimension = ShaderInputBind::DIM_TEXTURE2DARRAY; break; case ResourceKind::Texture2DMSArray: bind.type = srv ? ShaderInputBind::TYPE_TEXTURE : ShaderInputBind::TYPE_UAV_RWTYPED; + defName = srv ? "Texture2DMSArray" : "RWTexture2DMSArray"; bind.dimension = ShaderInputBind::DIM_TEXTURE2DMSARRAY; break; case ResourceKind::TextureCubeArray: bind.type = srv ? ShaderInputBind::TYPE_TEXTURE : ShaderInputBind::TYPE_UAV_RWTYPED; + defName = srv ? "TextureCubeArray" : "RWTextureCubeArray"; bind.dimension = ShaderInputBind::DIM_TEXTURECUBEARRAY; break; case ResourceKind::TypedBuffer: bind.type = srv ? ShaderInputBind::TYPE_TEXTURE : ShaderInputBind::TYPE_UAV_RWTYPED; + defName = srv ? "Buffer" : "RWBuffer"; bind.dimension = ShaderInputBind::DIM_BUFFER; break; case ResourceKind::TBuffer: bind.type = ShaderInputBind::TYPE_TBUFFER; + defName = "TBuffer"; bind.dimension = ShaderInputBind::DIM_UNKNOWN; bind.retType = RETURN_TYPE_UNKNOWN; break; case ResourceKind::RawBuffer: bind.type = ShaderInputBind::TYPE_BYTEADDRESS; bind.type = srv ? ShaderInputBind::TYPE_BYTEADDRESS : ShaderInputBind::TYPE_UAV_RWBYTEADDRESS; + defName = srv ? "ByteAddressBuffer" : "RWByteAddressBuffer"; bind.dimension = ShaderInputBind::DIM_BUFFER; bind.retType = RETURN_TYPE_MIXED; break; case ResourceKind::StructuredBuffer: bind.type = srv ? ShaderInputBind::TYPE_STRUCTURED : ShaderInputBind::TYPE_UAV_RWSTRUCTURED; + defName = srv ? "StructuredBuffer" : "RWStructuredBuffer"; bind.dimension = ShaderInputBind::DIM_BUFFER; bind.retType = RETURN_TYPE_MIXED; break; case ResourceKind::StructuredBufferWithCounter: bind.type = srv ? ShaderInputBind::TYPE_STRUCTURED : ShaderInputBind::TYPE_UAV_RWSTRUCTURED_WITH_COUNTER; + defName = srv ? "StructuredBufferWithCounter" : "RWStructuredBufferWithCounter"; bind.dimension = ShaderInputBind::DIM_BUFFER; bind.retType = RETURN_TYPE_MIXED; break; @@ -663,11 +690,30 @@ static void AddResourceBind(DXBC::Reflection *refl, const TypeInfo &typeInfo, co bind.type = ShaderInputBind::TYPE_UAV_RWSTRUCTURED_WITH_COUNTER; } + if(bind.name.empty()) + bind.name = StringFormat::Fmt("%s%u", defName.c_str(), + getival(r->children[(size_t)ResField::ID])); + switch(shape) { case ResourceKind::StructuredBuffer: case ResourceKind::StructuredBufferWithCounter: - refl->ResourceBinds[bind.name] = MakeCBufferVariableType(typeInfo, baseType->inner); + { + if(!typeInfo.structData.empty()) + { + refl->ResourceBinds[bind.name] = MakeCBufferVariableType(typeInfo, baseType->inner); + } + else + { + // if we don't have type annotations, create a dummy byte-array struct member + refl->ResourceBinds[bind.name].descriptor.bytesize = structStride; + refl->ResourceBinds[bind.name].descriptor.cols = 1; + refl->ResourceBinds[bind.name].descriptor.rows = 1; + refl->ResourceBinds[bind.name].descriptor.elements = structStride; + refl->ResourceBinds[bind.name].descriptor.varClass = DXBC::CLASS_SCALAR; + refl->ResourceBinds[bind.name].descriptor.varType = VarType::UByte; + } + } default: break; } @@ -727,15 +773,49 @@ DXBC::Reflection *Program::GetReflection() bind.descriptor.type = CBuffer::Descriptor::TYPE_CBUFFER; bind.descriptor.byteSize = getival(r->children[(size_t)ResField::CBufferByteSize]); + if(bind.name.empty()) + bind.name = StringFormat::Fmt("cbuffer%u", bind.identifier); + const Type *cbufType = r->children[(size_t)ResField::VarDecl]->type; // variable should be a pointer to the cbuffer type RDCASSERT(cbufType->type == Type::Pointer); cbufType = cbufType->inner; - CBufferVariableType rootType = MakeCBufferVariableType(typeInfo, cbufType); + if(!typeInfo.structData.empty()) + { + CBufferVariableType rootType = MakeCBufferVariableType(typeInfo, cbufType); - bind.variables.swap(rootType.members); + bind.variables.swap(rootType.members); + } + else + { + CBufferVariable var; + + var.name = "unknown"; + var.offset = 0; + + // if we don't have type annotations, create a dummy struct member + var.type.descriptor.bytesize = bind.descriptor.byteSize / 16; + var.type.descriptor.cols = 4; + var.type.descriptor.rows = 1; + var.type.descriptor.elements = bind.descriptor.byteSize / 16; + var.type.descriptor.varClass = DXBC::CLASS_SCALAR; + var.type.descriptor.varType = VarType::UInt; + + bind.variables.push_back(var); + + // add any remaining bytes if the struct isn't a multiple of float4 size + var.type.descriptor.cols = 1; + var.type.descriptor.bytesize = var.type.descriptor.elements = 1; + var.type.descriptor.varType = VarType::UByte; + + for(uint32_t remainingBytes = var.type.descriptor.bytesize * 16; + remainingBytes < bind.descriptor.byteSize; remainingBytes++) + { + bind.variables.push_back(var); + } + } refl->CBuffers.push_back(bind); } @@ -754,11 +834,20 @@ DXBC::Reflection *Program::GetReflection() bind.type = ShaderInputBind::TYPE_SAMPLER; bind.dimension = ShaderInputBind::DIM_UNKNOWN; bind.numComps = 0; + bind.retType = RETURN_TYPE_UNKNOWN; + + if(bind.name.empty()) + bind.name = + StringFormat::Fmt("sampler%u", getival(r->children[(size_t)ResField::ID])); + refl->Samplers.push_back(bind); } } } + RDCEraseEl(refl->Interfaces); + RDCEraseEl(refl->DispatchThreadsDimension); + return refl; }