Improve Shader Dumper: now outputs decompiled shaders
This commit is contained in:
@@ -17,6 +17,7 @@
|
||||
#include "video_core/engines/shader_header.h"
|
||||
#include "video_core/renderer_opengl/gl_rasterizer.h"
|
||||
#include "video_core/renderer_opengl/gl_shader_decompiler.h"
|
||||
#include "video_core/renderer_opengl/gl_shader_dumper.h"
|
||||
|
||||
namespace OpenGL::GLShader::Decompiler {
|
||||
|
||||
@@ -278,7 +279,7 @@ public:
|
||||
const Maxwell3D::Regs::ShaderStage& stage, const std::string& suffix,
|
||||
const Tegra::Shader::Header& header)
|
||||
: shader{shader}, declarations{declarations}, stage{stage}, suffix{suffix}, header{header},
|
||||
fixed_pipeline_output_attributes_used{}, local_memory_size{0} {
|
||||
fixed_pipeline_output_attributes_used{}, local_memory_size{0}, faulty{false} {
|
||||
BuildRegisterList();
|
||||
BuildInputList();
|
||||
}
|
||||
@@ -603,6 +604,10 @@ public:
|
||||
local_memory_size = lmem;
|
||||
}
|
||||
|
||||
bool IsFaulty() {
|
||||
return faulty;
|
||||
}
|
||||
|
||||
private:
|
||||
/// Generates declarations for registers.
|
||||
void GenerateRegisters(const std::string& suffix) {
|
||||
@@ -942,6 +947,7 @@ private:
|
||||
const Tegra::Shader::Header& header;
|
||||
std::unordered_set<Attribute::Index> fixed_pipeline_output_attributes_used;
|
||||
u64 local_memory_size;
|
||||
bool faulty;
|
||||
};
|
||||
|
||||
class GLSLGenerator {
|
||||
@@ -3732,6 +3738,12 @@ private:
|
||||
}
|
||||
|
||||
void Generate(const std::string& suffix) {
|
||||
|
||||
u64 hash = ShaderDumper::GenerateHash(program_code);
|
||||
|
||||
shader.AddLine(fmt::format("// Program Hash Id: 0x{:x}UL", hash));
|
||||
faulty |= ShaderDumper::IsProgramMarked(hash);
|
||||
|
||||
// Add declarations for all subroutines
|
||||
for (const auto& subroutine : subroutines) {
|
||||
shader.AddLine("bool " + subroutine.GetName() + "();");
|
||||
@@ -3805,6 +3817,7 @@ private:
|
||||
}
|
||||
|
||||
GenerateDeclarations();
|
||||
faulty = faulty || regs.IsFaulty();
|
||||
}
|
||||
|
||||
/// Add declarations for registers
|
||||
@@ -3841,8 +3854,8 @@ std::string GetCommonDeclarations() {
|
||||
}
|
||||
|
||||
std::optional<ProgramResult> DecompileProgram(const ProgramCode& program_code, u32 main_offset,
|
||||
Maxwell3D::Regs::ShaderStage stage,
|
||||
const std::string& suffix, bool& faulty_shader) {
|
||||
Maxwell3D::Regs::ShaderStage stage,
|
||||
const std::string& suffix, bool& faulty_shader) {
|
||||
try {
|
||||
const auto subroutines =
|
||||
ControlFlowAnalyzer(program_code, main_offset, suffix).GetSubroutines();
|
||||
|
||||
@@ -1,9 +1,28 @@
|
||||
|
||||
#include <unordered_set>
|
||||
|
||||
#include "common/file_util.h"
|
||||
#include "common/hash.h"
|
||||
#include "video_core/engines/shader_bytecode.h"
|
||||
#include "video_core/renderer_opengl/gl_shader_dumper.h"
|
||||
|
||||
struct DumpSet {
|
||||
DumpSet() : values{} {
|
||||
// Insert Marked Shaders here.
|
||||
values.insert(0);
|
||||
}
|
||||
const bool IsMarked(u64 index) const {
|
||||
return values.count(index) != 0;
|
||||
}
|
||||
std::unordered_set<u64> values;
|
||||
};
|
||||
|
||||
auto dump_set = DumpSet{};
|
||||
|
||||
bool ShaderDumper::IsProgramMarked(u64 hash) {
|
||||
return dump_set.IsMarked(hash);
|
||||
}
|
||||
|
||||
template <typename I>
|
||||
std::string n2hexstr(I w, size_t hex_len = sizeof(I) << 1) {
|
||||
static const char* digits = "0123456789ABCDEF";
|
||||
@@ -14,7 +33,6 @@ std::string n2hexstr(I w, size_t hex_len = sizeof(I) << 1) {
|
||||
}
|
||||
|
||||
std::string ShaderDumper::hashName() {
|
||||
u64 hash = Common::ComputeHash64(program.data(), sizeof(u64) * program.size());
|
||||
return n2hexstr(hash);
|
||||
}
|
||||
|
||||
@@ -28,7 +46,7 @@ bool IsSchedInstruction(u32 offset, u32 main_offset) {
|
||||
|
||||
void ShaderDumper::dump() {
|
||||
FileUtil::IOFile sFile;
|
||||
std::string name = prefix + hashName();
|
||||
std::string name = prefix + hashName() + ".bin";
|
||||
sFile.Open(name, "wb");
|
||||
u32 start_offset = 10;
|
||||
u32 offset = start_offset;
|
||||
@@ -52,3 +70,11 @@ void ShaderDumper::dump() {
|
||||
}
|
||||
sFile.Close();
|
||||
}
|
||||
|
||||
void ShaderDumper::dumpText(const std::string out) {
|
||||
FileUtil::IOFile sFile;
|
||||
std::string name = prefix + hashName() + ".txt";
|
||||
sFile.Open(name, "w");
|
||||
sFile.WriteString(out);
|
||||
sFile.Close();
|
||||
}
|
||||
|
||||
@@ -5,17 +5,29 @@
|
||||
#include <vector>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/hash.h"
|
||||
|
||||
class ShaderDumper {
|
||||
public:
|
||||
ShaderDumper(const std::vector<u64>& prog, std::string prefix) : program(prog) {
|
||||
this->hash = GenerateHash(program);
|
||||
this->prefix = prefix;
|
||||
}
|
||||
void dump();
|
||||
void dumpText(const std::string out);
|
||||
|
||||
static bool IsProgramMarked(u64 hash);
|
||||
|
||||
static u64 GenerateHash(const std::vector<u64>& program) {
|
||||
return Common::ComputeHash64(program.data(), sizeof(u64) * program.size());
|
||||
}
|
||||
|
||||
private:
|
||||
std::string hashName();
|
||||
|
||||
|
||||
|
||||
u64 hash;
|
||||
std::string prefix;
|
||||
const std::vector<u64>& program;
|
||||
};
|
||||
|
||||
@@ -80,21 +80,16 @@ void main() {
|
||||
}
|
||||
|
||||
)";
|
||||
if (setup.IsDualProgram()) {
|
||||
ProgramResult program_b =
|
||||
Decompiler::DecompileProgram(setup.program.code_b, PROGRAM_OFFSET,
|
||||
Maxwell3D::Regs::ShaderStage::Vertex, "vertex_b", faultyB)
|
||||
.get_value_or({});
|
||||
out += program_b.first;
|
||||
}
|
||||
|
||||
if (faultyA) {
|
||||
ShaderDumper s(setup.program.code, "VS");
|
||||
s.dump();
|
||||
s.dumpText(out);
|
||||
}
|
||||
if (faultyB) {
|
||||
ShaderDumper s(setup.program.code_b, "VS");
|
||||
s.dump();
|
||||
s.dumpText(out);
|
||||
}
|
||||
return {out, program.second};
|
||||
}
|
||||
@@ -134,6 +129,7 @@ void main() {
|
||||
if (faulty) {
|
||||
ShaderDumper s(setup.program.code, "GS");
|
||||
s.dump();
|
||||
s.dumpText(out);
|
||||
}
|
||||
return {out, program.second};
|
||||
}
|
||||
@@ -201,6 +197,7 @@ void main() {
|
||||
if (faulty) {
|
||||
ShaderDumper s(setup.program.code, "FM");
|
||||
s.dump();
|
||||
s.dumpText(out);
|
||||
}
|
||||
return {out, program.second};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user