ShaderDumper.cs 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. using System;
  2. using System.IO;
  3. namespace Ryujinx.Graphics.Gpu.Shader
  4. {
  5. /// <summary>
  6. /// Shader dumper, writes binary shader code to disk.
  7. /// </summary>
  8. class ShaderDumper
  9. {
  10. private string _runtimeDir;
  11. private string _dumpPath;
  12. /// <summary>
  13. /// Current index of the shader dump binary file.
  14. /// This is incremented after each save, in order to give unique names to the files.
  15. /// </summary>
  16. public int CurrentDumpIndex { get; private set; }
  17. /// <summary>
  18. /// Creates a new instance of the shader dumper.
  19. /// </summary>
  20. public ShaderDumper()
  21. {
  22. CurrentDumpIndex = 1;
  23. }
  24. /// <summary>
  25. /// Dumps shader code to disk.
  26. /// </summary>
  27. /// <param name="code">Code to be dumped</param>
  28. /// <param name="compute">True for compute shader code, false for graphics shader code</param>
  29. /// <param name="fullPath">Output path for the shader code with header included</param>
  30. /// <param name="codePath">Output path for the shader code without header</param>
  31. public void Dump(byte[] code, bool compute, out string fullPath, out string codePath)
  32. {
  33. _dumpPath = GraphicsConfig.ShadersDumpPath;
  34. if (string.IsNullOrWhiteSpace(_dumpPath))
  35. {
  36. fullPath = null;
  37. codePath = null;
  38. return;
  39. }
  40. string fileName = "Shader" + CurrentDumpIndex.ToString("d4") + ".bin";
  41. fullPath = Path.Combine(FullDir(), fileName);
  42. codePath = Path.Combine(CodeDir(), fileName);
  43. CurrentDumpIndex++;
  44. using MemoryStream stream = new MemoryStream(code);
  45. BinaryReader codeReader = new BinaryReader(stream);
  46. using FileStream fullFile = File.Create(fullPath);
  47. using FileStream codeFile = File.Create(codePath);
  48. BinaryWriter fullWriter = new BinaryWriter(fullFile);
  49. BinaryWriter codeWriter = new BinaryWriter(codeFile);
  50. int headerSize = compute ? 0 : 0x50;
  51. fullWriter.Write(codeReader.ReadBytes(headerSize));
  52. byte[] temp = codeReader.ReadBytes(code.Length - headerSize);
  53. fullWriter.Write(temp);
  54. codeWriter.Write(temp);
  55. // Align to meet nvdisasm requirements.
  56. while (codeFile.Length % 0x20 != 0)
  57. {
  58. codeWriter.Write(0);
  59. }
  60. }
  61. /// <summary>
  62. /// Returns the output directory for shader code with header.
  63. /// </summary>
  64. /// <returns>Directory path</returns>
  65. private string FullDir()
  66. {
  67. return CreateAndReturn(Path.Combine(DumpDir(), "Full"));
  68. }
  69. /// <summary>
  70. /// Returns the output directory for shader code without header.
  71. /// </summary>
  72. /// <returns>Directory path</returns>
  73. private string CodeDir()
  74. {
  75. return CreateAndReturn(Path.Combine(DumpDir(), "Code"));
  76. }
  77. /// <summary>
  78. /// Returns the full output directory for the current shader dump.
  79. /// </summary>
  80. /// <returns>Directory path</returns>
  81. private string DumpDir()
  82. {
  83. if (string.IsNullOrEmpty(_runtimeDir))
  84. {
  85. int index = 1;
  86. do
  87. {
  88. _runtimeDir = Path.Combine(_dumpPath, "Dumps" + index.ToString("d2"));
  89. index++;
  90. }
  91. while (Directory.Exists(_runtimeDir));
  92. Directory.CreateDirectory(_runtimeDir);
  93. }
  94. return _runtimeDir;
  95. }
  96. /// <summary>
  97. /// Creates a new specified directory if needed.
  98. /// </summary>
  99. /// <param name="dir">The directory to create</param>
  100. /// <returns>The same directory passed to the method</returns>
  101. private static string CreateAndReturn(string dir)
  102. {
  103. Directory.CreateDirectory(dir);
  104. return dir;
  105. }
  106. }
  107. }