Post-process DXBC to remove vendor extension UAV and format instructions

This commit is contained in:
baldurk
2020-10-09 15:44:28 +01:00
parent 584746e406
commit 05b59b8ef3
10 changed files with 1972 additions and 21 deletions
+2 -1
View File
@@ -994,7 +994,8 @@ public:
{
if(m_DXBCFile == NULL && !m_Bytecode.empty())
{
m_DXBCFile = new DXBC::DXBCContainer(m_Bytecode, m_DebugInfoPath, m_ShaderExtSlot, ~0U);
m_DXBCFile = new DXBC::DXBCContainer(m_Bytecode, m_DebugInfoPath, GraphicsAPI::D3D11,
m_ShaderExtSlot, ~0U);
m_Bytecode.clear();
}
return m_DXBCFile;
+2 -1
View File
@@ -762,7 +762,8 @@ public:
{
if(m_DXBCFile == NULL && !m_Bytecode.empty())
{
m_DXBCFile = new DXBC::DXBCContainer(m_Bytecode, rdcstr(), m_ShaderExtSlot, m_ShaderExtSpace);
m_DXBCFile = new DXBC::DXBCContainer(m_Bytecode, rdcstr(), GraphicsAPI::D3D12,
m_ShaderExtSlot, m_ShaderExtSpace);
}
return m_DXBCFile;
}
+1 -1
View File
@@ -153,7 +153,7 @@ bool SupportedOpcode(NvShaderOpcode opcode)
{
if(NV_nvapi_AllowUnknownShaderOpcodes())
return true;
return opcode == NvShaderOpcode::UINT64Atomic;
return opcode == NvShaderOpcode::U64Atomic;
}
// try to initialise nvapi for replay
+30 -2
View File
@@ -29,11 +29,39 @@
enum class NvShaderOpcode : uint32_t
{
UINT64Atomic = 20,
Unknown = 0,
Shuffle = 1,
ShuffleUp = 2,
ShuffleDown = 3,
ShuffleXor = 4,
VoteAll = 5,
VoteAny = 6,
VoteBallot = 7,
GetLaneId = 8,
FP16Atomic = 12,
FP32Atomic = 13,
GetSpecial = 19,
U64Atomic = 20,
MatchAny = 21,
Footprint = 28,
FootprintBias = 29,
GetShadingRate = 30,
FootprintLevel = 31,
FootprintGrad = 32,
ShuffleGeneric = 33,
VPRSEvalAttribAtSample = 51,
VPRSEvalAttribSnapped = 52,
};
enum class NvShaderAtomic : uint32_t
enum class NvShaderSpecial
{
ThreadLtMask = 4,
FootprintSingleLOD = 5,
};
enum class NvShaderAtomic
{
Unknown = -1,
And = 0,
Or = 1,
Xor = 2,
@@ -400,6 +400,33 @@ DXBC::Reflection *Program::GuessReflection()
return ret;
}
rdcstr Program::GetDebugStatus()
{
// if there are no vendor extensions this is always debuggable
if(m_ShaderExt.second == ~0U)
return rdcstr();
// otherwise we need to check that no unsupported vendor extensions are used
DisassembleHexDump();
for(const Operation &op : m_Instructions)
{
if(op.operation >= OPCODE_VENDOR_FIRST)
{
bool supported = false;
// whitelist supported instructions here
if(!supported)
return StringFormat::Fmt("Unsupported shader extension '%s' used",
ToStr(op.operation).c_str());
}
}
// no unsupported instructions used
return rdcstr();
}
D3D_PRIMITIVE_TOPOLOGY Program::GetOutputTopology()
{
DisassembleHexDump();
+148 -8
View File
@@ -316,7 +316,59 @@ enum OpcodeType
OPCODE_CHECK_ACCESS_FULLY_MAPPED,
NUM_OPCODES,
NUM_REAL_OPCODES,
OPCODE_VENDOR_REMOVED,
OPCODE_VENDOR_FIRST,
OPCODE_AMD_READFIRSTLANE,
OPCODE_AMD_READLANE,
OPCODE_AMD_LANEID,
OPCODE_AMD_SWIZZLE,
OPCODE_AMD_BALLOT,
OPCODE_AMD_MBCNT,
OPCODE_AMD_MIN3U,
OPCODE_AMD_MIN3F,
OPCODE_AMD_MED3U,
OPCODE_AMD_MED3F,
OPCODE_AMD_MAX3U,
OPCODE_AMD_MAX3F,
OPCODE_AMD_BARYCOORD,
OPCODE_AMD_VTXPARAM,
OPCODE_AMD_GET_VIEWPORTINDEX,
OPCODE_AMD_GET_RTARRAYSLICE,
OPCODE_AMD_WAVE_REDUCE,
OPCODE_AMD_WAVE_SCAN,
OPCODE_AMD_LOADDWATADDR,
OPCODE_AMD_GET_DRAWINDEX,
OPCODE_AMD_U64_ATOMIC,
OPCODE_AMD_GET_WAVESIZE,
OPCODE_AMD_GET_BASEINSTANCE,
OPCODE_AMD_GET_BASEVERTEX,
OPCODE_NV_SHUFFLE,
OPCODE_NV_SHUFFLE_UP,
OPCODE_NV_SHUFFLE_DOWN,
OPCODE_NV_SHUFFLE_XOR,
OPCODE_NV_VOTE_ALL,
OPCODE_NV_VOTE_ANY,
OPCODE_NV_VOTE_BALLOT,
OPCODE_NV_GET_LANEID,
OPCODE_NV_FP16_ATOMIC,
OPCODE_NV_FP32_ATOMIC,
OPCODE_NV_GET_THREADLTMASK,
OPCODE_NV_GET_FOOTPRINT_SINGLELOD,
OPCODE_NV_U64_ATOMIC,
OPCODE_NV_MATCH_ANY,
OPCODE_NV_FOOTPRINT,
OPCODE_NV_FOOTPRINT_BIAS,
OPCODE_NV_GET_SHADING_RATE,
OPCODE_NV_FOOTPRINT_LEVEL,
OPCODE_NV_FOOTPRINT_GRAD,
OPCODE_NV_SHUFFLE_GENERIC,
OPCODE_NV_VPRS_EVAL_ATTRIB_SAMPLE,
OPCODE_NV_VPRS_EVAL_ATTRIB_SNAPPED,
};
size_t NumOperands(OpcodeType op);
@@ -622,6 +674,39 @@ enum ResourceDimension
NUM_DIMENSIONS,
};
enum VendorAtomicOp
{
ATOMIC_OP_NONE = 0,
ATOMIC_OP_AND,
ATOMIC_OP_OR,
ATOMIC_OP_XOR,
ATOMIC_OP_ADD,
ATOMIC_OP_MAX,
ATOMIC_OP_MIN,
ATOMIC_OP_SWAP,
ATOMIC_OP_CAS,
};
enum VendorWaveOp
{
WAVE_OP_NONE = 0,
WAVE_OP_ADD_FLOAT,
WAVE_OP_ADD_SINT,
WAVE_OP_ADD_UINT,
WAVE_OP_MUL_FLOAT,
WAVE_OP_MUL_SINT,
WAVE_OP_MUL_UINT,
WAVE_OP_MIN_FLOAT,
WAVE_OP_MIN_SINT,
WAVE_OP_MIN_UINT,
WAVE_OP_MAX_FLOAT,
WAVE_OP_MAX_SINT,
WAVE_OP_MAX_UINT,
WAVE_OP_AND,
WAVE_OP_OR,
WAVE_OP_XOR,
};
/////////////////////////////////////////////////////////////////////////
// Main structures
/////////////////////////////////////////////////////////////////////////
@@ -671,9 +756,13 @@ struct Operand
///////////////////////////////////////
OperandType
type; // temp register, constant buffer, input, output, other more specialised types
NumOperandComponents numComponents; // scalar, 4-vector or N-vector (currently unused)
// operands can be given names to make the assembly easier to read.
// mostly used on vendor extensions where the syntax is non-standard/undocumented
rdcstr name;
// temp register, constant buffer, input, output, other more specialised types
OperandType type;
// scalar, 4-vector or N-vector (currently unused)
NumOperandComponents numComponents;
uint8_t comps[4]; // the components. each is 0,1,2,3 for x,y,z,w or 0xff if unused.
// e.g. .x = { 0, -1, -1, -1 }
@@ -683,12 +772,50 @@ struct Operand
// .xyzw = { 0, 1, 2, 3 }
// .wzyx = { 3, 2, 1, 0 }
rdcarray<RegIndex> indices; // indices for this register.
// 0 means this is a special register, specified by type alone.
Operand swizzle(uint8_t c)
{
Operand ret = *this;
ret.numComponents = NUMCOMPS_1;
ret.comps[0] = comps[c];
ret.comps[1] = 0xff;
ret.comps[2] = 0xff;
ret.comps[3] = 0xff;
ret.values[0] = values[c];
ret.values[1] = 0;
ret.values[2] = 0;
ret.values[3] = 0;
return ret;
}
Operand swizzle(uint8_t x, uint8_t y, uint8_t z, uint8_t w)
{
Operand ret = *this;
ret.comps[0] = comps[x];
ret.comps[1] = comps[y];
ret.comps[2] = z < 4 ? comps[z] : 0xff;
ret.comps[3] = w < 4 ? comps[w] : 0xff;
ret.values[0] = values[x];
ret.values[1] = values[y];
ret.values[2] = z < 4 ? values[z] : 0;
ret.values[3] = w < 4 ? values[w] : 0;
return ret;
}
void setComps(uint8_t x, uint8_t y, uint8_t z, uint8_t w)
{
comps[0] = x;
comps[1] = y;
comps[2] = z;
comps[3] = w;
}
// indices for this register.
// 0 means this is a special register, specified by type alone.
// 1 is probably most common. Indicates RegIndex specifies the register
// 2 is for constant buffers, array inputs etc. [0] indicates the cbuffer, [1] indicates the
// cbuffer member
// 3 is rare but follows the above pattern
rdcarray<RegIndex> indices;
// the declaration of the resource in this operand (not always present)
Declaration *declaration;
@@ -748,7 +875,7 @@ struct Declaration
offset = 0;
length = 0;
instruction = 0;
declaration = NUM_OPCODES;
declaration = NUM_REAL_OPCODES;
refactoringAllowed = doublePrecisionFloats = forceEarlyDepthStencil =
enableRawAndStructuredBuffers = skipOptimisation = enableMinPrecision =
enableD3D11_1DoubleExtensions = enableD3D11_1ShaderExtensions =
@@ -907,7 +1034,7 @@ struct Operation
line = 0;
length = 0;
stride = 0;
operation = NUM_OPCODES;
operation = NUM_REAL_OPCODES;
nonzero = false;
saturate = false;
preciseValues = 0;
@@ -946,9 +1073,16 @@ class Program
public:
Program(const byte *bytes, size_t length);
void SetShaderEXTUAV(GraphicsAPI api, uint32_t space, uint32_t reg)
{
m_API = api;
m_ShaderExt = {space, reg};
}
void FetchComputeProperties(DXBC::Reflection *reflection);
DXBC::Reflection *GuessReflection();
rdcstr GetDebugStatus();
void SetReflection(const DXBC::Reflection *refl) { m_Reflection = refl; }
void SetDebugInfo(const DXBC::IDebugInfo *debug) { m_DebugInfo = debug; }
DXBC::ShaderType GetShaderType() const { return m_Type; }
@@ -978,6 +1112,9 @@ public:
private:
void FetchTypeVersion();
void DisassembleHexDump();
void PostprocessVendorExtensions();
void MakeDisassemblyString();
const DXBC::Reflection *m_Reflection = NULL;
@@ -1003,6 +1140,9 @@ private:
bool m_Disassembled = false;
GraphicsAPI m_API = GraphicsAPI::D3D11;
rdcpair<uint32_t, uint32_t> m_ShaderExt = {~0U, ~0U};
rdcstr m_Disassembly;
// declarations of inputs, outputs, constant buffers, temp registers etc.
@@ -556,6 +556,9 @@ const rdcstr &DXBCContainer::GetDisassembly()
if(!m_DebugFileName.empty())
m_Disassembly += StringFormat::Fmt("// Debug name: %s\n", m_DebugFileName.c_str());
if(m_ShaderExt.second != ~0U)
m_Disassembly += "// Vendor shader extensions in use\n";
m_Disassembly += m_DXBCByteCode->GetDisassembly();
}
else if(m_DXILByteCode)
@@ -568,6 +571,9 @@ const rdcstr &DXBCContainer::GetDisassembly()
if(!m_DebugFileName.empty())
m_Disassembly += StringFormat::Fmt("; shader debug name: %s\n", m_DebugFileName.c_str());
if(m_ShaderExt.second != ~0U)
m_Disassembly += "; Vendor shader extensions in use\n";
m_Disassembly += "; shader hash: ";
byte *hashBytes = (byte *)m_Hash;
for(size_t i = 0; i < sizeof(m_Hash); i++)
@@ -600,6 +606,8 @@ void DXBCContainer::FillTraceLineInfo(ShaderDebugTrace &trace) const
uint32_t extraLines = 2;
if(!m_DebugFileName.empty())
extraLines++;
if(m_ShaderExt.second != ~0U)
extraLines++;
if(m_GlobalFlags != GlobalShaderFlags::None)
extraLines += (uint32_t)Bits::CountOnes((uint32_t)m_GlobalFlags) + 2;
@@ -951,8 +959,8 @@ void DXBCContainer::TryFetchSeparateDebugInfo(bytebuf &byteCode, const rdcstr &d
}
}
DXBCContainer::DXBCContainer(bytebuf &ByteCode, const rdcstr &debugInfoPath, uint32_t shaderExtReg,
uint32_t shaderExtSpace)
DXBCContainer::DXBCContainer(bytebuf &ByteCode, const rdcstr &debugInfoPath, GraphicsAPI api,
uint32_t shaderExtReg, uint32_t shaderExtSpace)
{
RDCEraseEl(m_ShaderStats);
@@ -1838,6 +1846,26 @@ DXBCContainer::DXBCContainer(bytebuf &ByteCode, const rdcstr &debugInfoPath, uin
if(m_DXBCByteCode || m_DXILByteCode)
{
RDCASSERT(m_Reflection);
if(shaderExtReg != ~0U)
{
bool found = false;
const bool sm51 = (m_Version.Major == 5 && m_Version.Minor == 1);
// see if we can find the magic UAV. If so remove it from the reflection
for(size_t i = 0; i < m_Reflection->UAVs.size(); i++)
{
const ShaderInputBind &uav = m_Reflection->UAVs[i];
if(uav.reg == shaderExtReg && (!sm51 || shaderExtSpace == ~0U || shaderExtSpace == uav.space))
{
found = true;
m_Reflection->UAVs.erase(i);
m_DXBCByteCode->SetShaderEXTUAV(api, shaderExtSpace, shaderExtReg);
m_ShaderExt = {shaderExtSpace, shaderExtReg};
break;
}
}
}
}
}
@@ -2014,7 +2042,7 @@ TEST_CASE("DO NOT COMMIT - convenience test", "[dxbc]")
bytebuf buf;
FileIO::ReadAll("/path/to/container_file.dxbc", buf);
DXBC::DXBCContainer container(buf, rdcstr());
DXBC::DXBCContainer container(buf, rdcstr(), GraphicsAPI::D3D11, ~0U, ~0U);
// the only thing fetched lazily is the disassembly, so grab that here
@@ -142,8 +142,8 @@ ShaderCompileFlags EncodeFlags(const uint32_t flags, const rdcstr &profile);
class DXBCContainer
{
public:
DXBCContainer(bytebuf &ByteCode, const rdcstr &debugInfoPath, uint32_t shaderExtReg,
uint32_t shaderExtSpace);
DXBCContainer(bytebuf &ByteCode, const rdcstr &debugInfoPath, GraphicsAPI api,
uint32_t shaderExtReg, uint32_t shaderExtSpace);
~DXBCContainer();
DXBC::ShaderType m_Type = DXBC::ShaderType::Max;
struct
@@ -190,6 +190,8 @@ private:
uint32_t m_Hash[4];
rdcpair<uint32_t, uint32_t> m_ShaderExt = {~0U, ~0U};
rdcstr m_DebugFileName;
GlobalShaderFlags m_GlobalFlags = GlobalShaderFlags::None;
File diff suppressed because it is too large Load Diff
@@ -25,6 +25,7 @@
#include "dxbc_reflect.h"
#include "common/formatting.h"
#include "core/core.h"
#include "dxbc_bytecode.h"
#include "dxbc_container.h"
static ShaderConstant MakeConstantBufferVariable(const DXBC::CBufferVariable &var);
@@ -276,7 +277,9 @@ void MakeShaderReflection(DXBC::DXBCContainer *dxbc, ShaderReflection *refl,
if(dxbc->GetDXBCByteCode())
{
refl->debugInfo.debuggable = true;
refl->debugInfo.debugStatus = dxbc->GetDXBCByteCode()->GetDebugStatus();
refl->debugInfo.debuggable = refl->debugInfo.debugStatus.empty();
}
else
{