ShaderDumper.cs 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. using System;
  2. using System.IO;
  3. namespace Ryujinx.Graphics.Gal
  4. {
  5. static class ShaderDumper
  6. {
  7. private static string RuntimeDir;
  8. private static int DumpIndex = 1;
  9. public static void Dump(IGalMemory Memory, long Position, GalShaderType Type, string ExtSuffix = "")
  10. {
  11. if (string.IsNullOrWhiteSpace(GraphicsConfig.ShadersDumpPath))
  12. {
  13. return;
  14. }
  15. string FileName = "Shader" + DumpIndex.ToString("d4") + "." + ShaderExtension(Type) + ExtSuffix + ".bin";
  16. string FullPath = Path.Combine(FullDir(), FileName);
  17. string CodePath = Path.Combine(CodeDir(), FileName);
  18. DumpIndex++;
  19. using (FileStream FullFile = File.Create(FullPath))
  20. using (FileStream CodeFile = File.Create(CodePath))
  21. using (BinaryWriter FullWriter = new BinaryWriter(FullFile))
  22. using (BinaryWriter CodeWriter = new BinaryWriter(CodeFile))
  23. {
  24. for (long i = 0; i < 0x50; i += 4)
  25. {
  26. FullWriter.Write(Memory.ReadInt32(Position + i));
  27. }
  28. long Offset = 0;
  29. ulong Instruction = 0;
  30. //Dump until a NOP instruction is found
  31. while ((Instruction >> 52 & 0xfff8) != 0x50b0)
  32. {
  33. uint Word0 = (uint)Memory.ReadInt32(Position + 0x50 + Offset + 0);
  34. uint Word1 = (uint)Memory.ReadInt32(Position + 0x50 + Offset + 4);
  35. Instruction = Word0 | (ulong)Word1 << 32;
  36. //Zero instructions (other kind of NOP) stop immediatly,
  37. //this is to avoid two rows of zeroes
  38. if (Instruction == 0)
  39. {
  40. break;
  41. }
  42. FullWriter.Write(Instruction);
  43. CodeWriter.Write(Instruction);
  44. Offset += 8;
  45. }
  46. //Align to meet nvdisasm requeriments
  47. while (Offset % 0x20 != 0)
  48. {
  49. FullWriter.Write(0);
  50. CodeWriter.Write(0);
  51. Offset += 4;
  52. }
  53. }
  54. }
  55. private static string FullDir()
  56. {
  57. return CreateAndReturn(Path.Combine(DumpDir(), "Full"));
  58. }
  59. private static string CodeDir()
  60. {
  61. return CreateAndReturn(Path.Combine(DumpDir(), "Code"));
  62. }
  63. private static string DumpDir()
  64. {
  65. if (string.IsNullOrEmpty(RuntimeDir))
  66. {
  67. int Index = 1;
  68. do
  69. {
  70. RuntimeDir = Path.Combine(GraphicsConfig.ShadersDumpPath, "Dumps" + Index.ToString("d2"));
  71. Index++;
  72. }
  73. while (Directory.Exists(RuntimeDir));
  74. Directory.CreateDirectory(RuntimeDir);
  75. }
  76. return RuntimeDir;
  77. }
  78. private static string CreateAndReturn(string Dir)
  79. {
  80. if (!Directory.Exists(Dir))
  81. {
  82. Directory.CreateDirectory(Dir);
  83. }
  84. return Dir;
  85. }
  86. private static string ShaderExtension(GalShaderType Type)
  87. {
  88. switch (Type)
  89. {
  90. case GalShaderType.Vertex: return "vert";
  91. case GalShaderType.TessControl: return "tesc";
  92. case GalShaderType.TessEvaluation: return "tese";
  93. case GalShaderType.Geometry: return "geom";
  94. case GalShaderType.Fragment: return "frag";
  95. default: throw new ArgumentException(nameof(Type));
  96. }
  97. }
  98. }
  99. }