ShaderDumper.cs 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. using System;
  2. using System.IO;
  3. namespace Ryujinx.Graphics.Gal
  4. {
  5. static class ShaderDumper
  6. {
  7. private static string _runtimeDir;
  8. public static int DumpIndex { get; private set; } = 1;
  9. public static void Dump(IGalMemory memory, long position, GalShaderType type, string extSuffix = "")
  10. {
  11. if (!IsDumpEnabled())
  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. {
  22. BinaryWriter fullWriter = new BinaryWriter(fullFile);
  23. BinaryWriter codeWriter = new BinaryWriter(codeFile);
  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 >> 48 & 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. public static bool IsDumpEnabled()
  56. {
  57. return !string.IsNullOrWhiteSpace(GraphicsConfig.ShadersDumpPath);
  58. }
  59. private static string FullDir()
  60. {
  61. return CreateAndReturn(Path.Combine(DumpDir(), "Full"));
  62. }
  63. private static string CodeDir()
  64. {
  65. return CreateAndReturn(Path.Combine(DumpDir(), "Code"));
  66. }
  67. private static string DumpDir()
  68. {
  69. if (string.IsNullOrEmpty(_runtimeDir))
  70. {
  71. int index = 1;
  72. do
  73. {
  74. _runtimeDir = Path.Combine(GraphicsConfig.ShadersDumpPath, "Dumps" + index.ToString("d2"));
  75. index++;
  76. }
  77. while (Directory.Exists(_runtimeDir));
  78. Directory.CreateDirectory(_runtimeDir);
  79. }
  80. return _runtimeDir;
  81. }
  82. private static string CreateAndReturn(string dir)
  83. {
  84. if (!Directory.Exists(dir))
  85. {
  86. Directory.CreateDirectory(dir);
  87. }
  88. return dir;
  89. }
  90. private static string ShaderExtension(GalShaderType type)
  91. {
  92. switch (type)
  93. {
  94. case GalShaderType.Vertex: return "vert";
  95. case GalShaderType.TessControl: return "tesc";
  96. case GalShaderType.TessEvaluation: return "tese";
  97. case GalShaderType.Geometry: return "geom";
  98. case GalShaderType.Fragment: return "frag";
  99. default: throw new ArgumentException(nameof(type));
  100. }
  101. }
  102. }
  103. }