Reflect multiple entry points & ray properties from DXIL shaders

This commit is contained in:
baldurk
2024-04-26 13:55:19 +01:00
parent 476fed06d6
commit 7e7bbf58a8
13 changed files with 268 additions and 20 deletions
@@ -27,6 +27,7 @@
#include <map>
#include "api/replay/rdcarray.h"
#include "api/replay/rdcflatmap.h"
#include "api/replay/rdcpair.h"
#include "api/replay/rdcstr.h"
#include "common/common.h"
@@ -184,6 +185,19 @@ public:
const Reflection *GetReflection() const { return m_Reflection; }
D3D_PRIMITIVE_TOPOLOGY GetOutputTopology();
CBufferVariableType GetRayPayload(const ShaderEntryPoint &entry)
{
if(m_RayPayloads.empty())
return {};
return m_RayPayloads[entry].first;
}
CBufferVariableType GetRayAttributes(const ShaderEntryPoint &entry)
{
if(m_RayPayloads.empty())
return {};
return m_RayPayloads[entry].second;
}
rdcarray<ShaderEntryPoint> GetEntryPoints() const { return m_EntryPoints; }
const rdcstr &GetDisassembly(bool dxcStyle);
@@ -246,6 +260,8 @@ private:
size_t m_NonDebugDXILByteCodeOffset = 0;
size_t m_NonDebugDXILByteCodeSize = 0;
rdcflatmap<ShaderEntryPoint, rdcpair<CBufferVariableType, CBufferVariableType>> m_RayPayloads;
ShaderStatistics m_ShaderStats;
DXBCBytecode::Program *m_DXBCByteCode = NULL;
DXIL::Program *m_DXILByteCode = NULL;
+40 -6
View File
@@ -293,7 +293,8 @@ static void MakeResourceList(bool srv, DXBC::DXBCContainer *dxbc,
}
}
void MakeShaderReflection(DXBC::DXBCContainer *dxbc, ShaderReflection *refl)
void MakeShaderReflection(DXBC::DXBCContainer *dxbc, const ShaderEntryPoint &entry,
ShaderReflection *refl)
{
if(dxbc == NULL || !RenderDoc::Inst().IsReplayApp())
return;
@@ -308,6 +309,7 @@ void MakeShaderReflection(DXBC::DXBCContainer *dxbc, ShaderReflection *refl)
case DXBC::ShaderType::Compute: refl->stage = ShaderStage::Compute; break;
case DXBC::ShaderType::Amplification: refl->stage = ShaderStage::Amplification; break;
case DXBC::ShaderType::Mesh: refl->stage = ShaderStage::Mesh; break;
case DXBC::ShaderType::Library: refl->stage = entry.stage; break;
default:
RDCERR("Unexpected DXBC shader type %u", dxbc->m_Type);
refl->stage = ShaderStage::Vertex;
@@ -318,8 +320,6 @@ void MakeShaderReflection(DXBC::DXBCContainer *dxbc, ShaderReflection *refl)
if(dxbc->GetDebugInfo())
{
refl->debugInfo.entrySourceName = refl->entryPoint = dxbc->GetDebugInfo()->GetEntryFunction();
refl->debugInfo.encoding = ShaderEncoding::HLSL;
refl->debugInfo.sourceDebugInformation = true;
@@ -330,9 +330,22 @@ void MakeShaderReflection(DXBC::DXBCContainer *dxbc, ShaderReflection *refl)
dxbc->GetDebugInfo()->GetLineInfo(~0U, ~0U, refl->debugInfo.entryLocation);
rdcstr entry = dxbc->GetDebugInfo()->GetEntryFunction();
if(entry.empty())
entry = "main";
rdcstr entryFunc = entry.name;
if(entryFunc.empty())
entryFunc = dxbc->GetDebugInfo()->GetEntryFunction();
if(entryFunc.empty())
entryFunc = "main";
refl->debugInfo.entrySourceName = refl->entryPoint = entryFunc;
// demangle DXIL source names for display
if(refl->debugInfo.entrySourceName.size() > 2 && refl->debugInfo.entrySourceName[0] == '\x1' &&
refl->debugInfo.entrySourceName[1] == '?')
{
int idx = refl->debugInfo.entrySourceName.indexOf('@');
if(idx > 2)
refl->debugInfo.entrySourceName = refl->debugInfo.entrySourceName.substr(2, idx - 2);
}
// assume the debug info put the file with the entry point at the start. SDBG seems to do this
// by default, and SPDB has an extra sorting step that probably maybe possibly does this.
@@ -349,6 +362,7 @@ void MakeShaderReflection(DXBC::DXBCContainer *dxbc, ShaderReflection *refl)
case DXBC::ShaderType::Hull: profile = "hs"; break;
case DXBC::ShaderType::Domain: profile = "ds"; break;
case DXBC::ShaderType::Compute: profile = "cs"; break;
case DXBC::ShaderType::Library: profile = "lib"; break;
default: profile = "xx"; break;
}
profile += StringFormat::Fmt("_%u_%u", dxbc->m_Version.Major, dxbc->m_Version.Minor);
@@ -469,4 +483,24 @@ void MakeShaderReflection(DXBC::DXBCContainer *dxbc, ShaderReflection *refl)
refl->taskPayload.variables.push_back(
MakeConstantBufferVariable(false, dxbcRefl->TaskPayload.members[v]));
}
DXBC::CBufferVariableType RayPayload = dxbc->GetRayPayload(entry);
DXBC::CBufferVariableType RayAttributes = dxbc->GetRayAttributes(entry);
refl->rayPayload.bufferBacked = false;
refl->rayPayload.name = RayPayload.name;
refl->rayPayload.variables.reserve(RayPayload.members.size());
for(size_t v = 0; v < RayPayload.members.size(); v++)
{
refl->rayPayload.variables.push_back(MakeConstantBufferVariable(false, RayPayload.members[v]));
}
refl->rayAttributes.bufferBacked = false;
refl->rayAttributes.name = RayAttributes.name;
refl->rayAttributes.variables.reserve(RayAttributes.members.size());
for(size_t v = 0; v < RayAttributes.members.size(); v++)
{
refl->rayAttributes.variables.push_back(
MakeConstantBufferVariable(false, RayAttributes.members[v]));
}
}
+3 -1
View File
@@ -30,7 +30,9 @@ class DXBCContainer;
}
struct ShaderReflection;
struct ShaderEntryPoint;
#define D3Dx_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT 32
void MakeShaderReflection(DXBC::DXBCContainer *dxbc, ShaderReflection *refl);
void MakeShaderReflection(DXBC::DXBCContainer *dxbc, const ShaderEntryPoint &entry,
ShaderReflection *refl);
@@ -27,6 +27,7 @@
#include <stdint.h>
#include "api/replay/apidefs.h"
#include "api/replay/rdcflatmap.h"
#include "api/replay/rdcstr.h"
#include "common/common.h"
#include "driver/dx/official/d3dcommon.h"
@@ -1230,6 +1231,10 @@ public:
void FetchComputeProperties(DXBC::Reflection *reflection);
DXBC::Reflection *GetReflection();
rdcarray<ShaderEntryPoint> GetEntryPoints();
void FillRayPayloads(
Program *executable,
rdcflatmap<ShaderEntryPoint, rdcpair<DXBC::CBufferVariableType, DXBC::CBufferVariableType>>
&rayPayloads);
DXBC::ShaderType GetShaderType() const { return m_Type; }
uint32_t GetMajorVersion() const { return m_Major; }
@@ -703,6 +703,175 @@ void Program::FetchComputeProperties(DXBC::Reflection *reflection)
reflection->DispatchThreadsDimension[2] = 1;
}
void Program::FillRayPayloads(
Program *executable,
rdcflatmap<ShaderEntryPoint, rdcpair<DXBC::CBufferVariableType, DXBC::CBufferVariableType>> &rayPayloads)
{
if(m_Type != DXBC::ShaderType::Library)
return;
DXMeta dx(m_NamedMeta);
TypeInfo typeInfo(dx.typeAnnotations);
if(dx.entryPoints)
{
for(Metadata *entry : dx.entryPoints->children)
{
if(entry->children.size() > 2 && entry->children[0] != NULL)
{
ShaderEntryPoint entryPoint;
entryPoint.name = entry->children[1]->str;
Metadata *tags = entry->children[4];
for(size_t i = 0; i < tags->children.size(); i += 2)
{
// 8 is the type tag
if(getival<uint32_t>(tags->children[i]) == 8U)
{
entryPoint.stage =
GetShaderStage((DXBC::ShaderType)getival<uint32_t>(tags->children[i + 1]));
break;
}
}
Function *ownFunc = cast<Function>(entry->children[0]->value);
Function *executableFunc = NULL;
// locate the function in the executable program so we can iterate instructions.
for(Function *f : executable->m_Functions)
{
// assume names will match
if(f->name == ownFunc->name)
{
executableFunc = f;
break;
}
}
// intersection shaders only report attributes, they do not access the ray payload
if(entryPoint.stage == ShaderStage::Intersection)
{
// find the reportHit and grab the type from that
for(const Instruction *in : executableFunc->instructions)
{
const Instruction &inst = *in;
if(inst.op == Operation::Call && inst.getFuncCall()->name.beginsWith("dx.op.reportHit"))
{
if(inst.args.size() != 4)
{
RDCERR("Unexpected number of arguments to reportHit");
continue;
}
const Type *executableAttrType = inst.args[3]->type;
if(!executableAttrType)
{
RDCERR("Unexpected untyped payload argument to reportHit");
continue;
}
RDCASSERT(executableAttrType->type == Type::Pointer);
executableAttrType = (Type *)executableAttrType->inner;
Type *ownAttrType = NULL;
// we have the executable type but we can't use that to look up our type info. Try to
// go back by name
for(Type *t : m_Types)
{
if(t->type == executableAttrType->type && t->name == executableAttrType->name)
{
ownAttrType = t;
break;
}
}
if(ownAttrType)
rayPayloads[entryPoint].second = MakePayloadType(typeInfo, ownAttrType);
else
RDCERR("Couldn't find matching attribute type for '%s' by name",
executableAttrType->name);
break;
}
}
}
// raygen shaders only use the ray payload, not attributes
else if(entryPoint.stage == ShaderStage::RayGen)
{
// find the reportHit and grab the type from that
for(const Instruction *in : executableFunc->instructions)
{
const Instruction &inst = *in;
if(inst.op == Operation::Call && inst.getFuncCall()->name.beginsWith("dx.op.traceRay"))
{
if(inst.args.size() != 16)
{
RDCERR("Unexpected number of arguments to traceRay");
continue;
}
const Type *executablePayloadType = inst.args[15]->type;
if(!executablePayloadType)
{
RDCERR("Unexpected untyped payload argument to traceRay");
continue;
}
RDCASSERT(executablePayloadType->type == Type::Pointer);
executablePayloadType = (Type *)executablePayloadType->inner;
Type *ownPayloadType = NULL;
// we have the executable type but we can't use that to look up our type info. Try to
// go back by name
for(Type *t : m_Types)
{
if(t->type == executablePayloadType->type && t->name == executablePayloadType->name)
{
ownPayloadType = t;
break;
}
}
if(ownPayloadType)
rayPayloads[entryPoint].first = MakePayloadType(typeInfo, ownPayloadType);
else
RDCERR("Couldn't find matching payload type for '%s' by name",
executablePayloadType->name);
break;
}
}
}
else if(entryPoint.stage == ShaderStage::Miss || entryPoint.stage == ShaderStage::AnyHit ||
entryPoint.stage == ShaderStage::ClosestHit)
{
const Type *payloadType = ownFunc->type->members[0];
RDCASSERT(payloadType->type == Type::Pointer);
payloadType = (Type *)payloadType->inner;
rdcpair<DXBC::CBufferVariableType, DXBC::CBufferVariableType> &dst =
rayPayloads[entryPoint];
// miss shaders only use the payload, any-hit and closest-hit use both. The first
// parameter is the payload, the second is the attributes
dst.first = MakePayloadType(typeInfo, payloadType);
if(entryPoint.stage != ShaderStage::Miss)
{
const Type *attrType = ownFunc->type->members[1];
RDCASSERT(attrType->type == Type::Pointer);
attrType = (Type *)attrType->inner;
dst.second = MakePayloadType(typeInfo, attrType);
}
}
}
}
}
}
D3D_PRIMITIVE_TOPOLOGY Program::GetOutputTopology()
{
if(m_Type != DXBC::ShaderType::Geometry && m_Type != DXBC::ShaderType::Domain &&