diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 0faaecdedc..80945bb992 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp @@ -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 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 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(); diff --git a/src/video_core/renderer_opengl/gl_shader_dumper.cpp b/src/video_core/renderer_opengl/gl_shader_dumper.cpp index 5b89972380..7738604498 100644 --- a/src/video_core/renderer_opengl/gl_shader_dumper.cpp +++ b/src/video_core/renderer_opengl/gl_shader_dumper.cpp @@ -1,9 +1,28 @@ +#include + #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 values; +}; + +auto dump_set = DumpSet{}; + +bool ShaderDumper::IsProgramMarked(u64 hash) { + return dump_set.IsMarked(hash); +} + template 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(); +} diff --git a/src/video_core/renderer_opengl/gl_shader_dumper.h b/src/video_core/renderer_opengl/gl_shader_dumper.h index c942e66643..1bd77fc9f1 100644 --- a/src/video_core/renderer_opengl/gl_shader_dumper.h +++ b/src/video_core/renderer_opengl/gl_shader_dumper.h @@ -5,17 +5,29 @@ #include #include "common/common_types.h" +#include "common/hash.h" class ShaderDumper { public: ShaderDumper(const std::vector& 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& program) { + return Common::ComputeHash64(program.data(), sizeof(u64) * program.size()); + } private: std::string hashName(); + + + u64 hash; std::string prefix; const std::vector& program; }; diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp index 0f1dbd8ed7..10bec2b6fa 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.cpp +++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp @@ -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}; }