diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs index c55a758b..ad717755 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs @@ -118,6 +118,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL if (IsDualVp) { + ShaderDumper.Dump(Memory, Position + 0x50, Type, "a"); + ShaderDumper.Dump(Memory, PositionB + 0x50, Type, "b"); + Program = Decompiler.Decompile( Memory, Position + 0x50, @@ -126,6 +129,8 @@ namespace Ryujinx.Graphics.Gal.OpenGL } else { + ShaderDumper.Dump(Memory, Position + 0x50, Type); + Program = Decompiler.Decompile(Memory, Position + 0x50, Type); } diff --git a/Ryujinx.Graphics/Gal/ShaderDumper.cs b/Ryujinx.Graphics/Gal/ShaderDumper.cs new file mode 100644 index 00000000..7cd56b21 --- /dev/null +++ b/Ryujinx.Graphics/Gal/ShaderDumper.cs @@ -0,0 +1,96 @@ +using System; +using System.IO; + +namespace Ryujinx.Graphics.Gal +{ + static class ShaderDumper + { + private static string RuntimeDir; + + private static int DumpIndex = 1; + + public static void Dump(IGalMemory Memory, long Position, GalShaderType Type, string ExtSuffix = "") + { + if (string.IsNullOrWhiteSpace(GraphicsConfig.ShadersDumpPath)) + { + return; + } + + string FileName = "Shader" + DumpIndex.ToString("d4") + "." + ShaderExtension(Type) + ExtSuffix + ".bin"; + + string FilePath = Path.Combine(DumpDir(), FileName); + + DumpIndex++; + + using (FileStream Output = File.Create(FilePath)) + using (BinaryWriter Writer = new BinaryWriter(Output)) + { + long Offset = 0; + + ulong Instruction = 0; + + //Dump until a NOP instruction is found + while ((Instruction >> 52 & 0xfff8) != 0x50b0) + { + uint Word0 = (uint)Memory.ReadInt32(Position + Offset + 0); + uint Word1 = (uint)Memory.ReadInt32(Position + Offset + 4); + + Instruction = Word0 | (ulong)Word1 << 32; + + //Zero instructions (other kind of NOP) stop immediatly, + //this is to avoid two rows of zeroes + if (Instruction == 0) + { + break; + } + + Writer.Write(Instruction); + + Offset += 8; + } + + //Align to meet nvdisasm requeriments + while (Offset % 0x20 != 0) + { + Writer.Write(0); + + Offset += 4; + } + } + } + + private static string DumpDir() + { + if (string.IsNullOrEmpty(RuntimeDir)) + { + int Index = 1; + + do + { + RuntimeDir = Path.Combine(GraphicsConfig.ShadersDumpPath, "Dumps" + Index.ToString("d2")); + + Index++; + } + while (Directory.Exists(RuntimeDir)); + + Directory.CreateDirectory(RuntimeDir); + } + + return RuntimeDir; + } + + private static string ShaderExtension(GalShaderType Type) + { + switch (Type) + { + case GalShaderType.Vertex: return "vert"; + case GalShaderType.TessControl: return "tesc"; + case GalShaderType.TessEvaluation: return "tese"; + case GalShaderType.Geometry: return "geom"; + case GalShaderType.Fragment: return "frag"; + + default: throw new ArgumentException(nameof(Type)); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/GraphicsConfig.cs b/Ryujinx.Graphics/GraphicsConfig.cs new file mode 100644 index 00000000..3e3ef4ff --- /dev/null +++ b/Ryujinx.Graphics/GraphicsConfig.cs @@ -0,0 +1,4 @@ +public static class GraphicsConfig +{ + public static string ShadersDumpPath; +} diff --git a/Ryujinx/Config.cs b/Ryujinx/Config.cs index 940753ba..0f346122 100644 --- a/Ryujinx/Config.cs +++ b/Ryujinx/Config.cs @@ -29,6 +29,8 @@ namespace Ryujinx AOptimizations.DisableMemoryChecks = !Convert.ToBoolean(Parser.Value("Enable_Memory_Checks")); + GraphicsConfig.ShadersDumpPath = Parser.Value("Graphics_Shaders_Dump_Path"); + Log.SetEnable(LogLevel.Debug, Convert.ToBoolean(Parser.Value("Logging_Enable_Debug"))); Log.SetEnable(LogLevel.Stub, Convert.ToBoolean(Parser.Value("Logging_Enable_Stub"))); Log.SetEnable(LogLevel.Info, Convert.ToBoolean(Parser.Value("Logging_Enable_Info"))); diff --git a/Ryujinx/Ryujinx.conf b/Ryujinx/Ryujinx.conf index 59f7f859..063bb2de 100644 --- a/Ryujinx/Ryujinx.conf +++ b/Ryujinx/Ryujinx.conf @@ -1,6 +1,9 @@ #Enable cpu memory checks (slow) Enable_Memory_Checks = false +#Dump shaders in local directory (e.g. `C:\ShaderDumps`) +Graphics_Shaders_Dump_Path = + #Enable print debug logs Logging_Enable_Debug = false