aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics.Gpu/Engine/ShaderDumper.cs
diff options
context:
space:
mode:
authorgdk <gab.dark.100@gmail.com>2019-10-13 03:02:07 -0300
committerThog <thog@protonmail.com>2020-01-09 02:13:00 +0100
commit1876b346fea647e8284a66bb6d62c38801035cff (patch)
tree6eeff094298cda84d1613dc5ec0691e51d7b35f1 /Ryujinx.Graphics.Gpu/Engine/ShaderDumper.cs
parentf617fb542a0e3d36012d77a4b5acbde7b08902f2 (diff)
Initial work
Diffstat (limited to 'Ryujinx.Graphics.Gpu/Engine/ShaderDumper.cs')
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/ShaderDumper.cs126
1 files changed, 126 insertions, 0 deletions
diff --git a/Ryujinx.Graphics.Gpu/Engine/ShaderDumper.cs b/Ryujinx.Graphics.Gpu/Engine/ShaderDumper.cs
new file mode 100644
index 00000000..fdcf0612
--- /dev/null
+++ b/Ryujinx.Graphics.Gpu/Engine/ShaderDumper.cs
@@ -0,0 +1,126 @@
+using System.IO;
+
+namespace Ryujinx.Graphics.Gpu.Engine
+{
+ class ShaderDumper
+ {
+ private const int ShaderHeaderSize = 0x50;
+
+ private GpuContext _context;
+
+ private string _runtimeDir;
+ private string _dumpPath;
+ private int _dumpIndex;
+
+ public int CurrentDumpIndex => _dumpIndex;
+
+ public ShaderDumper(GpuContext context)
+ {
+ _context = context;
+
+ _dumpIndex = 1;
+ }
+
+ public void Dump(ulong gpuVa, bool compute)
+ {
+ _dumpPath = GraphicsConfig.ShadersDumpPath;
+
+ if (string.IsNullOrWhiteSpace(_dumpPath))
+ {
+ return;
+ }
+
+ string fileName = "Shader" + _dumpIndex.ToString("d4") + ".bin";
+
+ string fullPath = Path.Combine(FullDir(), fileName);
+ string codePath = Path.Combine(CodeDir(), fileName);
+
+ _dumpIndex++;
+
+ ulong headerSize = compute ? 0UL : ShaderHeaderSize;
+
+ using (FileStream fullFile = File.Create(fullPath))
+ using (FileStream codeFile = File.Create(codePath))
+ {
+ BinaryWriter fullWriter = new BinaryWriter(fullFile);
+ BinaryWriter codeWriter = new BinaryWriter(codeFile);
+
+ for (ulong i = 0; i < headerSize; i += 4)
+ {
+ fullWriter.Write(_context.MemoryAccessor.ReadInt32(gpuVa + i));
+ }
+
+ ulong offset = 0;
+
+ ulong instruction = 0;
+
+ // Dump until a NOP instruction is found.
+ while ((instruction >> 48 & 0xfff8) != 0x50b0)
+ {
+ uint word0 = (uint)_context.MemoryAccessor.ReadInt32(gpuVa + headerSize + offset + 0);
+ uint word1 = (uint)_context.MemoryAccessor.ReadInt32(gpuVa + headerSize + offset + 4);
+
+ instruction = word0 | (ulong)word1 << 32;
+
+ // Zero instructions (other kind of NOP) stop immediately,
+ // this is to avoid two rows of zeroes.
+ if (instruction == 0)
+ {
+ break;
+ }
+
+ fullWriter.Write(instruction);
+ codeWriter.Write(instruction);
+
+ offset += 8;
+ }
+
+ // Align to meet nvdisasm requirements.
+ while (offset % 0x20 != 0)
+ {
+ fullWriter.Write(0);
+ codeWriter.Write(0);
+
+ offset += 4;
+ }
+ }
+ }
+
+ private string FullDir()
+ {
+ return CreateAndReturn(Path.Combine(DumpDir(), "Full"));
+ }
+
+ private string CodeDir()
+ {
+ return CreateAndReturn(Path.Combine(DumpDir(), "Code"));
+ }
+
+ private string DumpDir()
+ {
+ if (string.IsNullOrEmpty(_runtimeDir))
+ {
+ int index = 1;
+
+ do
+ {
+ _runtimeDir = Path.Combine(_dumpPath, "Dumps" + index.ToString("d2"));
+
+ index++;
+ }
+ while (Directory.Exists(_runtimeDir));
+
+ Directory.CreateDirectory(_runtimeDir);
+ }
+
+ return _runtimeDir;
+ }
+
+ private static string CreateAndReturn(string dir)
+ {
+ Directory.CreateDirectory(dir);
+
+ return dir;
+ }
+ }
+} \ No newline at end of file