Store shader profile in ShaderCompileFlags for D3D

This commit is contained in:
baldurk
2020-06-18 16:28:54 +01:00
parent d4ddb565d0
commit ad10f9ac01
12 changed files with 202 additions and 93 deletions
@@ -997,7 +997,7 @@ void PipelineStateViewer::SetupShaderEditButton(QToolButton *button, ResourceId
files.push_back(rdcpair<rdcstr, rdcstr>("pseudocode", editeddisasm));
EditShader(shaderId, shaderDetails->stage, shaderDetails->entryPoint,
ShaderCompileFlags(), ShaderEncoding::Unknown, files);
shaderDetails->debugInfo.compileFlags, ShaderEncoding::Unknown, files);
});
});
}
@@ -1009,7 +1009,7 @@ void PipelineStateViewer::SetupShaderEditButton(QToolButton *button, ResourceId
files.push_back(rdcpair<rdcstr, rdcstr>(
"decompiled_stub.hlsl", GenerateHLSLStub(bindpointMapping, shaderDetails, entry)));
EditShader(shaderId, shaderDetails->stage, entry, ShaderCompileFlags(),
EditShader(shaderId, shaderDetails->stage, entry, shaderDetails->debugInfo.compileFlags,
ShaderEncoding::HLSL, files);
}
+19 -17
View File
@@ -2533,21 +2533,23 @@ void D3D11Replay::BuildShader(ShaderEncoding sourceEncoding, const bytebuf &sour
if(sourceEncoding == ShaderEncoding::HLSL)
{
uint32_t flags = DXBC::DecodeFlags(compileFlags);
rdcstr profile = DXBC::GetProfile(compileFlags);
char *profile = NULL;
switch(type)
if(profile.empty())
{
case ShaderStage::Vertex: profile = "vs_5_0"; break;
case ShaderStage::Hull: profile = "hs_5_0"; break;
case ShaderStage::Domain: profile = "ds_5_0"; break;
case ShaderStage::Geometry: profile = "gs_5_0"; break;
case ShaderStage::Pixel: profile = "ps_5_0"; break;
case ShaderStage::Compute: profile = "cs_5_0"; break;
default:
RDCERR("Unexpected type in BuildShader!");
id = ResourceId();
return;
switch(type)
{
case ShaderStage::Vertex: profile = "vs_5_0"; break;
case ShaderStage::Hull: profile = "hs_5_0"; break;
case ShaderStage::Domain: profile = "ds_5_0"; break;
case ShaderStage::Geometry: profile = "gs_5_0"; break;
case ShaderStage::Pixel: profile = "ps_5_0"; break;
case ShaderStage::Compute: profile = "cs_5_0"; break;
default:
RDCERR("Unexpected type in BuildShader!");
id = ResourceId();
return;
}
}
rdcstr hlsl;
@@ -2555,8 +2557,8 @@ void D3D11Replay::BuildShader(ShaderEncoding sourceEncoding, const bytebuf &sour
ID3DBlob *blob = NULL;
errors = m_pDevice->GetShaderCache()->GetShaderBlob(hlsl.c_str(), entry.c_str(), flags, profile,
&blob);
errors = m_pDevice->GetShaderCache()->GetShaderBlob(hlsl.c_str(), entry.c_str(), flags,
profile.c_str(), &blob);
if(blob == NULL)
{
@@ -2681,8 +2683,8 @@ void D3D11Replay::BuildTargetShader(ShaderEncoding sourceEncoding, const bytebuf
const rdcstr &entry, const ShaderCompileFlags &compileFlags,
ShaderStage type, ResourceId &id, rdcstr &errors)
{
ShaderCompileFlags debugCompileFlags =
DXBC::EncodeFlags(DXBC::DecodeFlags(compileFlags) | D3DCOMPILE_DEBUG);
ShaderCompileFlags debugCompileFlags = DXBC::EncodeFlags(
DXBC::DecodeFlags(compileFlags) | D3DCOMPILE_DEBUG, DXBC::GetProfile(compileFlags));
BuildShader(sourceEncoding, source, entry, debugCompileFlags, type, id, errors);
}
+17 -14
View File
@@ -2801,20 +2801,23 @@ void D3D12Replay::BuildShader(ShaderEncoding sourceEncoding, const bytebuf &sour
if(sourceEncoding == ShaderEncoding::HLSL)
{
rdcstr profile;
rdcstr profile = DXBC::GetProfile(compileFlags);
switch(type)
if(profile.empty())
{
case ShaderStage::Vertex: profile = "vs_5_1"; break;
case ShaderStage::Hull: profile = "hs_5_1"; break;
case ShaderStage::Domain: profile = "ds_5_1"; break;
case ShaderStage::Geometry: profile = "gs_5_1"; break;
case ShaderStage::Pixel: profile = "ps_5_1"; break;
case ShaderStage::Compute: profile = "cs_5_1"; break;
default:
RDCERR("Unexpected type in BuildShader!");
id = ResourceId();
return;
switch(type)
{
case ShaderStage::Vertex: profile = "vs_5_1"; break;
case ShaderStage::Hull: profile = "hs_5_1"; break;
case ShaderStage::Domain: profile = "ds_5_1"; break;
case ShaderStage::Geometry: profile = "gs_5_1"; break;
case ShaderStage::Pixel: profile = "ps_5_1"; break;
case ShaderStage::Compute: profile = "cs_5_1"; break;
default:
RDCERR("Unexpected type in BuildShader!");
id = ResourceId();
return;
}
}
rdcstr hlsl;
@@ -2858,8 +2861,8 @@ void D3D12Replay::BuildTargetShader(ShaderEncoding sourceEncoding, const bytebuf
const rdcstr &entry, const ShaderCompileFlags &compileFlags,
ShaderStage type, ResourceId &id, rdcstr &errors)
{
ShaderCompileFlags debugCompileFlags =
DXBC::EncodeFlags(DXBC::DecodeFlags(compileFlags) | D3DCOMPILE_DEBUG);
ShaderCompileFlags debugCompileFlags = DXBC::EncodeFlags(
DXBC::DecodeFlags(compileFlags) | D3DCOMPILE_DEBUG, DXBC::GetProfile(compileFlags));
BuildShader(sourceEncoding, source, entry, debugCompileFlags, type, id, errors);
}
@@ -514,7 +514,7 @@ rdcstr D3D12ShaderCache::GetShaderBlob(const char *source, const char *entry,
rdcstr D3D12ShaderCache::GetShaderBlob(const char *source, const char *entry, uint32_t compileFlags,
const char *profile, ID3DBlob **srcblob)
{
return GetShaderBlob(source, entry, DXBC::EncodeFlags(compileFlags), profile, srcblob);
return GetShaderBlob(source, entry, DXBC::EncodeFlags(compileFlags, profile), profile, srcblob);
}
D3D12RootSignature D3D12ShaderCache::GetRootSig(const void *data, size_t dataSize)
@@ -29,6 +29,16 @@
#include "api/replay/rdcstr.h"
#include "api/replay/shader_types.h"
namespace DXBCBytecode
{
class Program;
};
namespace DXIL
{
class Program;
};
namespace DXBC
{
struct CountOffset
@@ -346,4 +356,27 @@ struct Reflection
uint32_t DispatchThreadsDimension[3];
};
class DXBCContainer;
class IDebugInfo
{
public:
virtual ~IDebugInfo() {}
virtual rdcstr GetCompilerSig() const = 0;
virtual rdcstr GetEntryFunction() const = 0;
virtual rdcstr GetShaderProfile() const = 0;
virtual ShaderCompileFlags GetShaderCompileFlags() const = 0;
rdcarray<rdcpair<rdcstr, rdcstr>> Files; // <filename, source>
virtual void GetLineInfo(size_t instruction, uintptr_t offset, LineColumnInfo &lineInfo) const = 0;
virtual void GetCallstack(size_t instruction, uintptr_t offset,
rdcarray<rdcstr> &callstack) const = 0;
virtual bool HasSourceMapping() const = 0;
virtual void GetLocals(const DXBC::DXBCContainer *dxbc, size_t instruction, uintptr_t offset,
rdcarray<SourceVariableMapping> &locals) const = 0;
};
};
+100 -17
View File
@@ -619,7 +619,7 @@ void DXBCContainer::FillStateInstructionInfo(ShaderDebugState &state) const
offset = m_DXBCByteCode->GetInstruction(instruction).offset;
if(m_DebugInfo)
m_DebugInfo->GetLocals(m_DXBCByteCode, instruction, offset, state.sourceVars);
m_DebugInfo->GetLocals(this, instruction, offset, state.sourceVars);
}
if(m_DebugInfo)
@@ -1702,7 +1702,39 @@ uint32_t DecodeFlags(const ShaderCompileFlags &compileFlags)
return ret;
}
ShaderCompileFlags EncodeFlags(const uint32_t flags)
rdcstr GetProfile(const ShaderCompileFlags &compileFlags)
{
for(const ShaderCompileFlag flag : compileFlags.flags)
{
if(flag.name == "@cmdline")
{
rdcstr cmdline = flag.value;
// ensure cmdline is surrounded by spaces and all whitespace is spaces. This means we can
// search for our flags surrounded by space and ensure we get exact matches.
for(char &c : cmdline)
if(isspace(c))
c = ' ';
cmdline = " " + cmdline + " ";
const char *prof = strstr(cmdline.c_str(), " /T ");
if(!prof)
prof = strstr(cmdline.c_str(), " -T ");
if(!prof)
return "";
prof += 4;
return rdcstr(prof, strstr(prof, " ") - prof);
}
}
return "";
}
ShaderCompileFlags EncodeFlags(const uint32_t flags, const rdcstr &profile)
{
ShaderCompileFlags ret;
@@ -1731,7 +1763,10 @@ ShaderCompileFlags EncodeFlags(const uint32_t flags)
else if(opt == D3DCOMPILE_OPTIMIZATION_LEVEL3)
cmdline += " /O3";
ret.flags = {{"@cmdline", cmdline}};
if(!profile.empty())
cmdline += " /T " + profile;
ret.flags = {{"@cmdline", cmdline.trimmed()}};
// If D3DCOMPILE_SKIP_OPTIMIZATION is set, then prefer source-level debugging as it should be
// accurate enough to work with.
@@ -1741,11 +1776,6 @@ ShaderCompileFlags EncodeFlags(const uint32_t flags)
return ret;
}
ShaderCompileFlags EncodeFlags(const IDebugInfo *dbg)
{
return EncodeFlags(dbg ? dbg->GetShaderCompileFlags() : 0);
}
}; // namespace DXBC
#if ENABLED(ENABLE_UNIT_TESTS)
@@ -1799,17 +1829,17 @@ TEST_CASE("Check DXBC flag encoding/decoding", "[dxbc]")
{
uint32_t flags = D3DCOMPILE_PARTIAL_PRECISION | D3DCOMPILE_SKIP_OPTIMIZATION |
D3DCOMPILE_ALL_RESOURCES_BOUND | D3DCOMPILE_OPTIMIZATION_LEVEL2;
uint32_t flags2 = DXBC::DecodeFlags(DXBC::EncodeFlags(flags));
uint32_t flags2 = DXBC::DecodeFlags(DXBC::EncodeFlags(flags, ""));
CHECK(flags == flags2);
flags = 0;
flags2 = DXBC::DecodeFlags(DXBC::EncodeFlags(flags));
flags2 = DXBC::DecodeFlags(DXBC::EncodeFlags(flags, ""));
CHECK(flags == flags2);
flags = D3DCOMPILE_OPTIMIZATION_LEVEL3 | D3DCOMPILE_DEBUG;
flags2 = DXBC::DecodeFlags(DXBC::EncodeFlags(flags));
flags2 = DXBC::DecodeFlags(DXBC::EncodeFlags(flags, ""));
CHECK(flags == flags2);
};
@@ -1817,7 +1847,7 @@ TEST_CASE("Check DXBC flag encoding/decoding", "[dxbc]")
SECTION("encode/decode discards unrecognised parameters")
{
uint32_t flags = D3DCOMPILE_PARTIAL_PRECISION | (1 << 30);
uint32_t flags2 = DXBC::DecodeFlags(DXBC::EncodeFlags(flags));
uint32_t flags2 = DXBC::DecodeFlags(DXBC::EncodeFlags(flags, ""));
CHECK(flags2 == D3DCOMPILE_PARTIAL_PRECISION);
@@ -1831,7 +1861,7 @@ TEST_CASE("Check DXBC flag encoding/decoding", "[dxbc]")
CHECK(flags2 == (D3DCOMPILE_DEBUG | D3DCOMPILE_WARNINGS_ARE_ERRORS));
flags = ~0U;
flags2 = DXBC::DecodeFlags(DXBC::EncodeFlags(flags));
flags2 = DXBC::DecodeFlags(DXBC::EncodeFlags(flags, ""));
uint32_t allflags = 0;
for(const DXBC::FxcArg &a : DXBC::fxc_flags)
@@ -1845,22 +1875,75 @@ TEST_CASE("Check DXBC flag encoding/decoding", "[dxbc]")
SECTION("optimisation flags are properly decoded and encoded")
{
uint32_t flags = D3DCOMPILE_DEBUG | D3DCOMPILE_OPTIMIZATION_LEVEL0;
uint32_t flags2 = DXBC::DecodeFlags(DXBC::EncodeFlags(flags));
uint32_t flags2 = DXBC::DecodeFlags(DXBC::EncodeFlags(flags, ""));
CHECK(flags == flags2);
flags = D3DCOMPILE_DEBUG | D3DCOMPILE_OPTIMIZATION_LEVEL1;
flags2 = DXBC::DecodeFlags(DXBC::EncodeFlags(flags));
flags2 = DXBC::DecodeFlags(DXBC::EncodeFlags(flags, ""));
CHECK(flags == flags2);
flags = D3DCOMPILE_DEBUG | D3DCOMPILE_OPTIMIZATION_LEVEL2;
flags2 = DXBC::DecodeFlags(DXBC::EncodeFlags(flags));
flags2 = DXBC::DecodeFlags(DXBC::EncodeFlags(flags, ""));
CHECK(flags == flags2);
flags = D3DCOMPILE_DEBUG | D3DCOMPILE_OPTIMIZATION_LEVEL3;
flags2 = DXBC::DecodeFlags(DXBC::EncodeFlags(flags));
flags2 = DXBC::DecodeFlags(DXBC::EncodeFlags(flags, ""));
CHECK(flags == flags2);
};
SECTION("Profile is correctly encoded and decoded")
{
const uint32_t flags = D3DCOMPILE_DEBUG | D3DCOMPILE_WARNINGS_ARE_ERRORS;
rdcstr profile = "ps_5_0";
rdcstr profile2 = DXBC::GetProfile(DXBC::EncodeFlags(flags, profile));
CHECK(profile == profile2);
profile = "ps_4_0";
profile2 = DXBC::GetProfile(DXBC::EncodeFlags(flags, profile));
CHECK(profile == profile2);
profile = "";
profile2 = DXBC::GetProfile(DXBC::EncodeFlags(flags, profile));
CHECK(profile == profile2);
profile = "cs_5_0";
profile2 = DXBC::GetProfile(DXBC::EncodeFlags(flags, profile));
CHECK(profile == profile2);
profile = "??_9_9";
profile2 = DXBC::GetProfile(DXBC::EncodeFlags(flags, profile));
CHECK(profile == profile2);
};
SECTION("Profile does not affect flag encoding")
{
uint32_t flags = D3DCOMPILE_DEBUG | D3DCOMPILE_WARNINGS_ARE_ERRORS;
uint32_t flags2 = DXBC::DecodeFlags(DXBC::EncodeFlags(flags, ""));
CHECK(flags == flags2);
flags = D3DCOMPILE_DEBUG | D3DCOMPILE_WARNINGS_ARE_ERRORS;
flags2 = DXBC::DecodeFlags(DXBC::EncodeFlags(flags, "ps_5_0"));
CHECK(flags == flags2);
flags = D3DCOMPILE_DEBUG | D3DCOMPILE_WARNINGS_ARE_ERRORS;
flags2 = DXBC::DecodeFlags(DXBC::EncodeFlags(flags, "ps_4_0"));
CHECK(flags == flags2);
flags = D3DCOMPILE_DEBUG | D3DCOMPILE_WARNINGS_ARE_ERRORS;
flags2 = DXBC::DecodeFlags(DXBC::EncodeFlags(flags, "??_9_9"));
CHECK(flags == flags2);
};
+2 -33
View File
@@ -34,16 +34,6 @@
#include "driver/dx/official/d3dcommon.h"
#include "dxbc_common.h"
namespace DXBCBytecode
{
class Program;
};
namespace DXIL
{
class Program;
};
namespace DXBC
{
class IDebugInfo;
@@ -141,30 +131,9 @@ rdcstr TypeName(CBufferVariableType::Descriptor desc);
struct RDEFHeader;
class IDebugInfo
{
public:
virtual ~IDebugInfo() {}
virtual rdcstr GetCompilerSig() const = 0;
virtual rdcstr GetEntryFunction() const = 0;
virtual rdcstr GetShaderProfile() const = 0;
virtual uint32_t GetShaderCompileFlags() const = 0;
rdcarray<rdcpair<rdcstr, rdcstr>> Files; // <filename, source>
virtual void GetLineInfo(size_t instruction, uintptr_t offset, LineColumnInfo &lineInfo) const = 0;
virtual void GetCallstack(size_t instruction, uintptr_t offset,
rdcarray<rdcstr> &callstack) const = 0;
virtual bool HasSourceMapping() const = 0;
virtual void GetLocals(DXBCBytecode::Program *program, size_t instruction, uintptr_t offset,
rdcarray<SourceVariableMapping> &locals) const = 0;
};
uint32_t DecodeFlags(const ShaderCompileFlags &compileFlags);
ShaderCompileFlags EncodeFlags(const IDebugInfo *dbg);
ShaderCompileFlags EncodeFlags(const uint32_t flags);
rdcstr GetProfile(const ShaderCompileFlags &compileFlags);
ShaderCompileFlags EncodeFlags(const uint32_t flags, const rdcstr &profile);
// declare one of these and pass in your shader bytecode, then inspect
// the members that are populated with the shader information.
+19 -1
View File
@@ -213,7 +213,7 @@ void MakeShaderReflection(DXBC::DXBCContainer *dxbc, ShaderReflection *refl,
refl->debugInfo.encoding = ShaderEncoding::HLSL;
refl->debugInfo.compileFlags = DXBC::EncodeFlags(dxbc->GetDebugInfo());
refl->debugInfo.compileFlags = dxbc->GetDebugInfo()->GetShaderCompileFlags();
refl->debugInfo.files.resize(dxbc->GetDebugInfo()->Files.size());
for(size_t i = 0; i < dxbc->GetDebugInfo()->Files.size(); i++)
@@ -229,6 +229,24 @@ void MakeShaderReflection(DXBC::DXBCContainer *dxbc, ShaderReflection *refl,
// 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.
}
else
{
// ensure we at least have shader compiler flags to indicate the right profile
rdcstr profile;
switch(dxbc->m_Type)
{
case DXBC::ShaderType::Pixel: profile = "ps"; break;
case DXBC::ShaderType::Vertex: profile = "vs"; break;
case DXBC::ShaderType::Geometry: profile = "gs"; break;
case DXBC::ShaderType::Hull: profile = "hs"; break;
case DXBC::ShaderType::Domain: profile = "ds"; break;
case DXBC::ShaderType::Compute: profile = "cs"; break;
default: profile = "xx"; break;
}
profile += StringFormat::Fmt("_%u_%u", dxbc->m_Version.Major, dxbc->m_Version.Minor);
refl->debugInfo.compileFlags = DXBC::EncodeFlags(0, profile);
}
if(dxbc->GetDXBCByteCode())
{
+1 -1
View File
@@ -127,7 +127,7 @@ bool SDBGChunk::HasSourceMapping() const
return false;
}
void SDBGChunk::GetLocals(DXBCBytecode::Program *program, size_t instruction, uintptr_t offset,
void SDBGChunk::GetLocals(const DXBC::DXBCContainer *dxbc, size_t instruction, uintptr_t offset,
rdcarray<SourceVariableMapping> &locals) const
{
}
+2 -2
View File
@@ -247,12 +247,12 @@ public:
rdcstr GetCompilerSig() const { return m_CompilerSig; }
rdcstr GetEntryFunction() const { return m_Entry; }
rdcstr GetShaderProfile() const { return m_Profile; }
uint32_t GetShaderCompileFlags() const { return m_ShaderFlags; }
ShaderCompileFlags GetShaderCompileFlags() const { return EncodeFlags(m_ShaderFlags, m_Profile); }
void GetLineInfo(size_t instruction, uintptr_t offset, LineColumnInfo &lineInfo) const;
void GetCallstack(size_t instruction, uintptr_t offset, rdcarray<rdcstr> &callstack) const;
bool HasSourceMapping() const;
void GetLocals(DXBCBytecode::Program *program, size_t instruction, uintptr_t offset,
void GetLocals(const DXBC::DXBCContainer *dxbc, size_t instruction, uintptr_t offset,
rdcarray<SourceVariableMapping> &locals) const;
private:
+4 -3
View File
@@ -1699,7 +1699,7 @@ bool SPDBChunk::HasSourceMapping() const
return true;
}
void SPDBChunk::GetLocals(DXBCBytecode::Program *program, size_t instruction, uintptr_t offset,
void SPDBChunk::GetLocals(const DXBC::DXBCContainer *dxbc, size_t instruction, uintptr_t offset,
rdcarray<SourceVariableMapping> &locals) const
{
locals.clear();
@@ -1734,10 +1734,11 @@ void SPDBChunk::GetLocals(DXBCBytecode::Program *program, size_t instruction, ui
// it's possible to declare coverage input but then not use it. We then get a local that
// doesn't map to any register because the register declaration is stripped.
// this doesn't happen on output because outputs don't get stripped in the same way.
if(it->regType == DXBCBytecode::TYPE_INPUT_COVERAGE_MASK && !program->HasCoverageInput())
if(it->regType == DXBCBytecode::TYPE_INPUT_COVERAGE_MASK &&
!dxbc->GetDXBCByteCode()->HasCoverageInput())
continue;
range.name = program->GetRegisterName(it->regType, it->regIndex);
range.name = dxbc->GetDXBCByteCode()->GetRegisterName(it->regType, it->regIndex);
range.component = it->regFirstComp;
if(IsInput(it->regType))
+2 -2
View File
@@ -271,12 +271,12 @@ public:
rdcstr GetCompilerSig() const { return m_CompilerSig; }
rdcstr GetEntryFunction() const { return m_Entry; }
rdcstr GetShaderProfile() const { return m_Profile; }
uint32_t GetShaderCompileFlags() const { return m_ShaderFlags; }
ShaderCompileFlags GetShaderCompileFlags() const { return EncodeFlags(m_ShaderFlags, m_Profile); }
void GetLineInfo(size_t instruction, uintptr_t offset, LineColumnInfo &lineInfo) const;
void GetCallstack(size_t instruction, uintptr_t offset, rdcarray<rdcstr> &callstack) const;
bool HasSourceMapping() const;
void GetLocals(DXBCBytecode::Program *program, size_t instruction, uintptr_t offset,
void GetLocals(const DXBC::DXBCContainer *dxbc, size_t instruction, uintptr_t offset,
rdcarray<SourceVariableMapping> &locals) const;
private: