[D3D12] DXILConv disassembly dumping option

This commit is contained in:
Triang3l
2020-08-22 23:15:50 +03:00
parent 92e445f01a
commit 0c13b239fd
9 changed files with 254 additions and 38 deletions

View File

@@ -62,21 +62,73 @@ void D3D12Shader::SetTexturesAndSamplers(
}
}
bool D3D12Shader::DisassembleDxbc(const ui::d3d12::D3D12Provider* provider) {
if (!host_disassembly_.empty()) {
return true;
void D3D12Shader::DisassembleDxbc(const ui::d3d12::D3D12Provider& provider,
bool disassemble_dxbc,
IDxbcConverter* dxbc_converter,
IDxcUtils* dxc_utils,
IDxcCompiler* dxc_compiler) {
bool is_first_disassembly = true;
if (disassemble_dxbc) {
ID3DBlob* dxbc_disassembly;
if (SUCCEEDED(provider.Disassemble(translated_binary().data(),
translated_binary().size(),
D3D_DISASM_ENABLE_INSTRUCTION_NUMBERING |
D3D_DISASM_ENABLE_INSTRUCTION_OFFSET,
nullptr, &dxbc_disassembly))) {
assert_true(is_first_disassembly);
is_first_disassembly = false;
host_disassembly_.append(
reinterpret_cast<const char*>(dxbc_disassembly->GetBufferPointer()));
dxbc_disassembly->Release();
} else {
XELOGE("Failed to disassemble DXBC shader {:016X}", ucode_data_hash());
}
}
ID3DBlob* blob;
if (FAILED(provider->Disassemble(translated_binary().data(),
translated_binary().size(),
D3D_DISASM_ENABLE_INSTRUCTION_NUMBERING |
D3D_DISASM_ENABLE_INSTRUCTION_OFFSET,
nullptr, &blob))) {
return false;
if (dxbc_converter && dxc_utils && dxc_compiler) {
void* dxil;
UINT32 dxil_size;
if (SUCCEEDED(dxbc_converter->Convert(
translated_binary().data(), UINT32(translated_binary().size()),
nullptr, &dxil, &dxil_size, nullptr)) &&
dxil != nullptr) {
IDxcBlobEncoding* dxil_blob;
if (SUCCEEDED(dxc_utils->CreateBlobFromPinned(dxil, dxil_size, DXC_CP_ACP,
&dxil_blob))) {
IDxcBlobEncoding* dxil_disassembly;
bool dxil_disassembled =
SUCCEEDED(dxc_compiler->Disassemble(dxil_blob, &dxil_disassembly));
dxil_blob->Release();
CoTaskMemFree(dxil);
if (dxil_disassembled) {
IDxcBlobUtf8* dxil_disassembly_utf8;
bool dxil_disassembly_got_utf8 = SUCCEEDED(dxc_utils->GetBlobAsUtf8(
dxil_disassembly, &dxil_disassembly_utf8));
dxil_disassembly->Release();
if (dxil_disassembly_got_utf8) {
if (!is_first_disassembly) {
host_disassembly_.append("\n\n");
}
is_first_disassembly = false;
host_disassembly_.append(reinterpret_cast<const char*>(
dxil_disassembly_utf8->GetStringPointer()));
dxil_disassembly_utf8->Release();
} else {
XELOGE("Failed to get DXIL shader {:016X} disassembly as UTF-8",
ucode_data_hash());
}
} else {
XELOGE("Failed to disassemble DXIL shader {:016X}",
ucode_data_hash());
}
} else {
XELOGE("Failed to create a blob with DXIL shader {:016X}",
ucode_data_hash());
CoTaskMemFree(dxil);
}
} else {
XELOGE("Failed to convert shader {:016X} to DXIL", ucode_data_hash());
}
}
host_disassembly_ = reinterpret_cast<const char*>(blob->GetBufferPointer());
blob->Release();
return true;
}
} // namespace d3d12

View File

@@ -43,7 +43,11 @@ class D3D12Shader : public Shader {
return forced_early_z_shader_;
}
bool DisassembleDxbc(const ui::d3d12::D3D12Provider* provider);
void DisassembleDxbc(const ui::d3d12::D3D12Provider& provider,
bool disassemble_dxbc,
IDxbcConverter* dxbc_converter = nullptr,
IDxcUtils* dxc_utils = nullptr,
IDxcCompiler* dxc_compiler = nullptr);
static constexpr uint32_t kMaxTextureBindingIndexBits =
DxbcShaderTranslator::kMaxTextureBindingIndexBits;

View File

@@ -31,9 +31,16 @@
#include "xenia/base/string.h"
#include "xenia/gpu/d3d12/d3d12_command_processor.h"
#include "xenia/gpu/gpu_flags.h"
#include "xenia/ui/d3d12/d3d12_util.h"
DEFINE_bool(d3d12_dxbc_disasm, false,
"Disassemble DXBC shaders after generation.", "D3D12");
DEFINE_bool(
d3d12_dxbc_disasm_dxilconv, false,
"Disassemble DXBC shaders after conversion to DXIL, if DXIL shaders are "
"supported by the OS, and DirectX Shader Compiler DLLs available at "
"https://github.com/microsoft/DirectXShaderCompiler/releases are present.",
"D3D12");
DEFINE_int32(
d3d12_pipeline_creation_threads, -1,
"Number of threads used for graphics pipeline state object creation. -1 to "
@@ -85,6 +92,30 @@ PipelineCache::PipelineCache(D3D12CommandProcessor* command_processor,
PipelineCache::~PipelineCache() { Shutdown(); }
bool PipelineCache::Initialize() {
auto provider = command_processor_->GetD3D12Context()->GetD3D12Provider();
// Initialize the command processor thread DXIL objects.
if (cvars::d3d12_dxbc_disasm_dxilconv) {
if (FAILED(provider->DxbcConverterCreateInstance(
CLSID_DxbcConverter, IID_PPV_ARGS(&dxbc_converter_)))) {
XELOGE(
"Failed to create DxbcConverter, converted DXIL disassembly for "
"debugging will be unavailable");
}
if (FAILED(provider->DxcCreateInstance(CLSID_DxcUtils,
IID_PPV_ARGS(&dxc_utils_)))) {
XELOGE(
"Failed to create DxcUtils, converted DXIL disassembly for debugging "
"will be unavailable");
}
if (FAILED(provider->DxcCreateInstance(CLSID_DxcCompiler,
IID_PPV_ARGS(&dxc_compiler_)))) {
XELOGE(
"Failed to create DxcCompiler, converted DXIL disassembly for "
"debugging will be unavailable");
}
}
uint32_t logical_processor_count = xe::threading::logical_processor_count();
if (!logical_processor_count) {
// Pick some reasonable amount if couldn't determine the number of cores.
@@ -134,6 +165,10 @@ void PipelineCache::Shutdown() {
creation_threads_.clear();
}
creation_completion_event_.reset();
ui::d3d12::util::ReleaseAndNull(dxc_compiler_);
ui::d3d12::util::ReleaseAndNull(dxc_utils_);
ui::d3d12::util::ReleaseAndNull(dxbc_converter_);
}
void PipelineCache::ClearCache(bool shutting_down) {
@@ -273,6 +308,19 @@ void PipelineCache::InitializeShaderStorage(
DxbcShaderTranslator translator(
provider->GetAdapterVendorID(), bindless_resources_used_,
edram_rov_used_, provider->GetGraphicsAnalysis() != nullptr);
// If needed and possible, create objects needed for DXIL conversion and
// disassembly on this thread.
IDxbcConverter* dxbc_converter = nullptr;
IDxcUtils* dxc_utils = nullptr;
IDxcCompiler* dxc_compiler = nullptr;
if (cvars::d3d12_dxbc_disasm_dxilconv && dxbc_converter_ && dxc_utils_ &&
dxc_compiler_) {
provider->DxbcConverterCreateInstance(CLSID_DxbcConverter,
IID_PPV_ARGS(&dxbc_converter));
provider->DxcCreateInstance(CLSID_DxcUtils, IID_PPV_ARGS(&dxc_utils));
provider->DxcCreateInstance(CLSID_DxcCompiler,
IID_PPV_ARGS(&dxc_compiler));
}
for (;;) {
std::pair<ShaderStoredHeader, D3D12Shader*> shader_to_translate;
for (;;) {
@@ -292,7 +340,8 @@ void PipelineCache::InitializeShaderStorage(
assert_not_null(shader_to_translate.second);
if (!TranslateShader(
translator, shader_to_translate.second,
shader_to_translate.first.sq_program_cntl,
shader_to_translate.first.sq_program_cntl, dxbc_converter,
dxc_utils, dxc_compiler,
shader_to_translate.first.host_vertex_shader_type)) {
std::lock_guard<std::mutex> lock(shaders_failed_to_translate_mutex);
shaders_failed_to_translate.push_back(shader_to_translate.second);
@@ -302,6 +351,15 @@ void PipelineCache::InitializeShaderStorage(
--shader_translation_threads_busy;
}
}
if (dxc_compiler) {
dxc_compiler->Release();
}
if (dxc_utils) {
dxc_utils->Release();
}
if (dxbc_converter) {
dxbc_converter->Release();
}
};
std::vector<std::unique_ptr<xe::threading::Thread>>
shader_translation_threads;
@@ -825,6 +883,7 @@ bool PipelineCache::EnsureShadersTranslated(
if (!vertex_shader->is_translated()) {
if (!TranslateShader(*shader_translator_, vertex_shader, sq_program_cntl,
dxbc_converter_, dxc_utils_, dxc_compiler_,
host_vertex_shader_type)) {
XELOGE("Failed to translate the vertex shader!");
return false;
@@ -842,7 +901,8 @@ bool PipelineCache::EnsureShadersTranslated(
}
if (pixel_shader != nullptr && !pixel_shader->is_translated()) {
if (!TranslateShader(*shader_translator_, pixel_shader, sq_program_cntl)) {
if (!TranslateShader(*shader_translator_, pixel_shader, sq_program_cntl,
dxbc_converter_, dxc_utils_, dxc_compiler_)) {
XELOGE("Failed to translate the pixel shader!");
return false;
}
@@ -953,7 +1013,8 @@ bool PipelineCache::ConfigurePipeline(
bool PipelineCache::TranslateShader(
DxbcShaderTranslator& translator, D3D12Shader* shader,
reg::SQ_PROGRAM_CNTL cntl,
reg::SQ_PROGRAM_CNTL cntl, IDxbcConverter* dxbc_converter,
IDxcUtils* dxc_utils, IDxcCompiler* dxc_compiler,
Shader::HostVertexShaderType host_vertex_shader_type) {
// Perform translation.
// If this fails the shader will be marked as invalid and ignored later.
@@ -1134,12 +1195,12 @@ bool PipelineCache::TranslateShader(
}
// Disassemble the shader for dumping.
if (cvars::d3d12_dxbc_disasm) {
auto provider = command_processor_->GetD3D12Context()->GetD3D12Provider();
if (!shader->DisassembleDxbc(provider)) {
XELOGE("Failed to disassemble DXBC shader {:016X}",
shader->ucode_data_hash());
}
auto provider = command_processor_->GetD3D12Context()->GetD3D12Provider();
if (cvars::d3d12_dxbc_disasm_dxilconv) {
shader->DisassembleDxbc(*provider, cvars::d3d12_dxbc_disasm, dxbc_converter,
dxc_utils, dxc_compiler);
} else {
shader->DisassembleDxbc(*provider, cvars::d3d12_dxbc_disasm);
}
// Dump shader files if desired.

View File

@@ -224,6 +224,9 @@ class PipelineCache {
// Can be called from multiple threads.
bool TranslateShader(DxbcShaderTranslator& translator, D3D12Shader* shader,
reg::SQ_PROGRAM_CNTL cntl,
IDxbcConverter* dxbc_converter = nullptr,
IDxcUtils* dxc_utils = nullptr,
IDxcCompiler* dxc_compiler = nullptr,
Shader::HostVertexShaderType host_vertex_shader_type =
Shader::HostVertexShaderType::kVertex);
@@ -245,6 +248,13 @@ class PipelineCache {
// Reusable shader translator.
std::unique_ptr<DxbcShaderTranslator> shader_translator_ = nullptr;
// Command processor thread DXIL conversion/disassembly interfaces, if DXIL
// disassembly is enabled.
IDxbcConverter* dxbc_converter_ = nullptr;
IDxcUtils* dxc_utils_ = nullptr;
IDxcCompiler* dxc_compiler_ = nullptr;
// All loaded shaders mapped by their guest hash key.
std::unordered_map<uint64_t, D3D12Shader*, xe::hash::IdentityHasher<uint64_t>>
shader_map_;