ShaderDumper.cs 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. using System.IO;
  2. namespace Ryujinx.Graphics.Gpu.Engine
  3. {
  4. class ShaderDumper
  5. {
  6. private const int ShaderHeaderSize = 0x50;
  7. private GpuContext _context;
  8. private string _runtimeDir;
  9. private string _dumpPath;
  10. private int _dumpIndex;
  11. public int CurrentDumpIndex => _dumpIndex;
  12. public ShaderDumper(GpuContext context)
  13. {
  14. _context = context;
  15. _dumpIndex = 1;
  16. }
  17. public void Dump(ulong gpuVa, bool compute)
  18. {
  19. _dumpPath = GraphicsConfig.ShadersDumpPath;
  20. if (string.IsNullOrWhiteSpace(_dumpPath))
  21. {
  22. return;
  23. }
  24. string fileName = "Shader" + _dumpIndex.ToString("d4") + ".bin";
  25. string fullPath = Path.Combine(FullDir(), fileName);
  26. string codePath = Path.Combine(CodeDir(), fileName);
  27. _dumpIndex++;
  28. ulong headerSize = compute ? 0UL : ShaderHeaderSize;
  29. using (FileStream fullFile = File.Create(fullPath))
  30. using (FileStream codeFile = File.Create(codePath))
  31. {
  32. BinaryWriter fullWriter = new BinaryWriter(fullFile);
  33. BinaryWriter codeWriter = new BinaryWriter(codeFile);
  34. for (ulong i = 0; i < headerSize; i += 4)
  35. {
  36. fullWriter.Write(_context.MemoryAccessor.ReadInt32(gpuVa + i));
  37. }
  38. ulong offset = 0;
  39. ulong instruction = 0;
  40. // Dump until a NOP instruction is found.
  41. while ((instruction >> 48 & 0xfff8) != 0x50b0)
  42. {
  43. uint word0 = (uint)_context.MemoryAccessor.ReadInt32(gpuVa + headerSize + offset + 0);
  44. uint word1 = (uint)_context.MemoryAccessor.ReadInt32(gpuVa + headerSize + offset + 4);
  45. instruction = word0 | (ulong)word1 << 32;
  46. // Zero instructions (other kind of NOP) stop immediately,
  47. // this is to avoid two rows of zeroes.
  48. if (instruction == 0)
  49. {
  50. break;
  51. }
  52. fullWriter.Write(instruction);
  53. codeWriter.Write(instruction);
  54. offset += 8;
  55. }
  56. // Align to meet nvdisasm requirements.
  57. while (offset % 0x20 != 0)
  58. {
  59. fullWriter.Write(0);
  60. codeWriter.Write(0);
  61. offset += 4;
  62. }
  63. }
  64. }
  65. private string FullDir()
  66. {
  67. return CreateAndReturn(Path.Combine(DumpDir(), "Full"));
  68. }
  69. private string CodeDir()
  70. {
  71. return CreateAndReturn(Path.Combine(DumpDir(), "Code"));
  72. }
  73. private string DumpDir()
  74. {
  75. if (string.IsNullOrEmpty(_runtimeDir))
  76. {
  77. int index = 1;
  78. do
  79. {
  80. _runtimeDir = Path.Combine(_dumpPath, "Dumps" + index.ToString("d2"));
  81. index++;
  82. }
  83. while (Directory.Exists(_runtimeDir));
  84. Directory.CreateDirectory(_runtimeDir);
  85. }
  86. return _runtimeDir;
  87. }
  88. private static string CreateAndReturn(string dir)
  89. {
  90. Directory.CreateDirectory(dir);
  91. return dir;
  92. }
  93. }
  94. }