[GPU] Refactor shader dumps - bin and txt files for both ucode and host
This commit is contained in:
parent
2bc0113dae
commit
9009cba90a
|
@ -844,17 +844,12 @@ D3D12Shader* PipelineCache::LoadShader(xenos::ShaderType shader_type,
|
||||||
// Shader has been previously loaded.
|
// Shader has been previously loaded.
|
||||||
return it->second;
|
return it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Always create the shader and stash it away.
|
// Always create the shader and stash it away.
|
||||||
// We need to track it even if it fails translation so we know not to try
|
// We need to track it even if it fails translation so we know not to try
|
||||||
// again.
|
// again.
|
||||||
D3D12Shader* shader =
|
D3D12Shader* shader =
|
||||||
new D3D12Shader(shader_type, data_hash, host_address, dword_count);
|
new D3D12Shader(shader_type, data_hash, host_address, dword_count);
|
||||||
shaders_.emplace(data_hash, shader);
|
shaders_.emplace(data_hash, shader);
|
||||||
if (!cvars::dump_shaders.empty()) {
|
|
||||||
shader->DumpUcodeBinary(cvars::dump_shaders);
|
|
||||||
}
|
|
||||||
|
|
||||||
return shader;
|
return shader;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
#include <cinttypes>
|
#include <cinttypes>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include "third_party/fmt/include/fmt/format.h"
|
#include "third_party/fmt/include/fmt/format.h"
|
||||||
#include "xenia/base/filesystem.h"
|
#include "xenia/base/filesystem.h"
|
||||||
|
@ -45,37 +46,50 @@ std::string Shader::Translation::GetTranslatedBinaryString() const {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::filesystem::path Shader::Translation::Dump(
|
std::pair<std::filesystem::path, std::filesystem::path>
|
||||||
const std::filesystem::path& base_path, const char* path_prefix) {
|
Shader::Translation::Dump(const std::filesystem::path& base_path,
|
||||||
|
const char* path_prefix) const {
|
||||||
|
if (!is_valid()) {
|
||||||
|
return std::make_pair(std::filesystem::path(), std::filesystem::path());
|
||||||
|
}
|
||||||
|
|
||||||
std::filesystem::path path = base_path;
|
std::filesystem::path path = base_path;
|
||||||
// Ensure target path exists.
|
// Ensure target path exists.
|
||||||
if (!path.empty()) {
|
std::filesystem::path target_path = base_path;
|
||||||
path = std::filesystem::absolute(path);
|
if (!target_path.empty()) {
|
||||||
std::filesystem::create_directories(path);
|
target_path = std::filesystem::absolute(target_path);
|
||||||
|
std::filesystem::create_directories(target_path);
|
||||||
}
|
}
|
||||||
path = path /
|
|
||||||
fmt::format(
|
const char* type_extension =
|
||||||
"shader_{:016X}_{:016X}.{}.{}", shader().ucode_data_hash(),
|
shader().type() == xenos::ShaderType::kVertex ? "vert" : "frag";
|
||||||
modification(), path_prefix,
|
|
||||||
shader().type() == xenos::ShaderType::kVertex ? "vert" : "frag");
|
std::filesystem::path binary_path =
|
||||||
FILE* f = filesystem::OpenFile(path, "wb");
|
target_path / fmt::format("shader_{:016X}_{:016X}.{}.bin.{}",
|
||||||
if (f) {
|
shader().ucode_data_hash(), modification(),
|
||||||
fwrite(translated_binary_.data(), 1, translated_binary_.size(), f);
|
path_prefix, type_extension);
|
||||||
fprintf(f, "\n\n");
|
FILE* binary_file = filesystem::OpenFile(binary_path, "wb");
|
||||||
auto ucode_disasm_ptr = shader().ucode_disassembly().c_str();
|
if (binary_file) {
|
||||||
while (*ucode_disasm_ptr) {
|
fwrite(translated_binary_.data(), sizeof(*translated_binary_.data()),
|
||||||
auto line_end = std::strchr(ucode_disasm_ptr, '\n');
|
translated_binary_.size(), binary_file);
|
||||||
fprintf(f, "// ");
|
fclose(binary_file);
|
||||||
fwrite(ucode_disasm_ptr, 1, line_end - ucode_disasm_ptr + 1, f);
|
|
||||||
ucode_disasm_ptr = line_end + 1;
|
|
||||||
}
|
}
|
||||||
fprintf(f, "\n\n");
|
|
||||||
|
std::filesystem::path disasm_path;
|
||||||
if (!host_disassembly_.empty()) {
|
if (!host_disassembly_.empty()) {
|
||||||
fprintf(f, "\n\n/*\n%s\n*/\n", host_disassembly_.c_str());
|
disasm_path =
|
||||||
|
target_path / fmt::format("shader_{:016X}_{:016X}.{}.{}",
|
||||||
|
shader().ucode_data_hash(), modification(),
|
||||||
|
path_prefix, type_extension);
|
||||||
|
FILE* disasm_file = filesystem::OpenFile(disasm_path, "w");
|
||||||
|
if (disasm_file) {
|
||||||
|
fwrite(host_disassembly_.data(), sizeof(*host_disassembly_.data()),
|
||||||
|
host_disassembly_.size(), disasm_file);
|
||||||
|
fclose(disasm_file);
|
||||||
}
|
}
|
||||||
fclose(f);
|
|
||||||
}
|
}
|
||||||
return std::move(path);
|
|
||||||
|
return std::make_pair(std::move(binary_path), std::move(disasm_path));
|
||||||
}
|
}
|
||||||
|
|
||||||
Shader::Translation* Shader::GetOrCreateTranslation(uint64_t modification,
|
Shader::Translation* Shader::GetOrCreateTranslation(uint64_t modification,
|
||||||
|
@ -104,24 +118,41 @@ void Shader::DestroyTranslation(uint64_t modification) {
|
||||||
translations_.erase(it);
|
translations_.erase(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::filesystem::path Shader::DumpUcodeBinary(
|
std::pair<std::filesystem::path, std::filesystem::path> Shader::DumpUcode(
|
||||||
const std::filesystem::path& base_path) {
|
const std::filesystem::path& base_path) const {
|
||||||
// Ensure target path exists.
|
// Ensure target path exists.
|
||||||
std::filesystem::path path = base_path;
|
std::filesystem::path target_path = base_path;
|
||||||
if (!path.empty()) {
|
if (!target_path.empty()) {
|
||||||
path = std::filesystem::absolute(path);
|
target_path = std::filesystem::absolute(target_path);
|
||||||
std::filesystem::create_directories(path);
|
std::filesystem::create_directories(target_path);
|
||||||
}
|
}
|
||||||
path = path /
|
|
||||||
fmt::format("shader_{:016X}.ucode.bin.{}", ucode_data_hash(),
|
|
||||||
type() == xenos::ShaderType::kVertex ? "vert" : "frag");
|
|
||||||
|
|
||||||
FILE* f = filesystem::OpenFile(path, "wb");
|
const char* type_extension =
|
||||||
if (f) {
|
type() == xenos::ShaderType::kVertex ? "vert" : "frag";
|
||||||
fwrite(ucode_data().data(), 4, ucode_data().size(), f);
|
|
||||||
fclose(f);
|
std::filesystem::path binary_path =
|
||||||
|
target_path / fmt::format("shader_{:016X}.ucode.bin.{}",
|
||||||
|
ucode_data_hash(), type_extension);
|
||||||
|
FILE* binary_file = filesystem::OpenFile(binary_path, "wb");
|
||||||
|
if (binary_file) {
|
||||||
|
fwrite(ucode_data().data(), sizeof(*ucode_data().data()),
|
||||||
|
ucode_data().size(), binary_file);
|
||||||
|
fclose(binary_file);
|
||||||
}
|
}
|
||||||
return std::move(path);
|
|
||||||
|
std::filesystem::path disasm_path;
|
||||||
|
if (is_ucode_analyzed()) {
|
||||||
|
disasm_path = target_path / fmt::format("shader_{:016X}.ucode.{}",
|
||||||
|
ucode_data_hash(), type_extension);
|
||||||
|
FILE* disasm_file = filesystem::OpenFile(disasm_path, "w");
|
||||||
|
if (disasm_file) {
|
||||||
|
fwrite(ucode_disassembly().data(), sizeof(*ucode_disassembly().data()),
|
||||||
|
ucode_disassembly().size(), disasm_file);
|
||||||
|
fclose(disasm_file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::make_pair(std::move(binary_path), std::move(disasm_path));
|
||||||
}
|
}
|
||||||
|
|
||||||
Shader::Translation* Shader::CreateTranslationInstance(uint64_t modification) {
|
Shader::Translation* Shader::CreateTranslationInstance(uint64_t modification) {
|
||||||
|
|
|
@ -763,11 +763,11 @@ class Shader {
|
||||||
host_disassembly_ = std::move(disassembly);
|
host_disassembly_ = std::move(disassembly);
|
||||||
}
|
}
|
||||||
|
|
||||||
// For dumping after translation. Dumps the shader's disassembled microcode,
|
// For dumping after translation. Dumps the shader's translated code, and,
|
||||||
// translated code, and, if available, translated disassembly, to a file in
|
// if available, translated disassembly, to files in the given directory
|
||||||
// the given path based on ucode hash. Returns the name of the written file.
|
// based on ucode hash. Returns {binary path, disassembly path if written}.
|
||||||
std::filesystem::path Dump(const std::filesystem::path& base_path,
|
std::pair<std::filesystem::path, std::filesystem::path> Dump(
|
||||||
const char* path_prefix);
|
const std::filesystem::path& base_path, const char* path_prefix) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Translation(Shader& shader, uint64_t modification)
|
Translation(Shader& shader, uint64_t modification)
|
||||||
|
@ -928,10 +928,12 @@ class Shader {
|
||||||
ucode_storage_index_ = storage_index;
|
ucode_storage_index_ = storage_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dumps the shader's microcode binary to a file in the given path based on
|
// Dumps the shader's microcode binary and, if analyzed, disassembly, to files
|
||||||
// ucode hash. Returns the name of the written file. Can be called at any
|
// in the given directory based on ucode hash. Returns the name of the written
|
||||||
// time, doesn't require the shader to be translated.
|
// file. Can be called at any time, doesn't require the shader to be
|
||||||
std::filesystem::path DumpUcodeBinary(const std::filesystem::path& base_path);
|
// translated. Returns {binary path, disassembly path if written}.
|
||||||
|
std::pair<std::filesystem::path, std::filesystem::path> DumpUcode(
|
||||||
|
const std::filesystem::path& base_path) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend class ShaderTranslator;
|
friend class ShaderTranslator;
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include "xenia/base/assert.h"
|
#include "xenia/base/assert.h"
|
||||||
#include "xenia/base/logging.h"
|
#include "xenia/base/logging.h"
|
||||||
#include "xenia/base/math.h"
|
#include "xenia/base/math.h"
|
||||||
|
#include "xenia/gpu/gpu_flags.h"
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace gpu {
|
namespace gpu {
|
||||||
|
@ -224,6 +225,12 @@ void Shader::AnalyzeUcode(StringBuffer& ucode_disasm_buffer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
is_ucode_analyzed_ = true;
|
is_ucode_analyzed_ = true;
|
||||||
|
|
||||||
|
// An empty shader can be created internally by shader translators as a dummy,
|
||||||
|
// don't dump it.
|
||||||
|
if (!cvars::dump_shaders.empty() && !ucode_data().empty()) {
|
||||||
|
DumpUcode(cvars::dump_shaders);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shader::GatherExecInformation(
|
void Shader::GatherExecInformation(
|
||||||
|
|
Loading…
Reference in New Issue