|
|
@@ -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));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|