ShaderCache.cs 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. using Ryujinx.Graphics.GAL;
  2. using Ryujinx.Graphics.Gpu.State;
  3. using Ryujinx.Graphics.Shader;
  4. using Ryujinx.Graphics.Shader.Translation;
  5. using System;
  6. using System.Collections.Generic;
  7. using System.Globalization;
  8. namespace Ryujinx.Graphics.Gpu.Engine
  9. {
  10. class ShaderCache
  11. {
  12. private const int MaxProgramSize = 0x100000;
  13. private GpuContext _context;
  14. private ShaderDumper _dumper;
  15. private Dictionary<ulong, ComputeShader> _cpPrograms;
  16. private Dictionary<ShaderAddresses, GraphicsShader> _gpPrograms;
  17. public ShaderCache(GpuContext context)
  18. {
  19. _context = context;
  20. _dumper = new ShaderDumper(context);
  21. _cpPrograms = new Dictionary<ulong, ComputeShader>();
  22. _gpPrograms = new Dictionary<ShaderAddresses, GraphicsShader>();
  23. }
  24. public ComputeShader GetComputeShader(ulong gpuVa, int localSizeX, int localSizeY, int localSizeZ)
  25. {
  26. if (!_cpPrograms.TryGetValue(gpuVa, out ComputeShader cpShader))
  27. {
  28. ShaderProgram shader = TranslateComputeShader(gpuVa);
  29. shader.Replace(DefineNames.LocalSizeX, localSizeX.ToString(CultureInfo.InvariantCulture));
  30. shader.Replace(DefineNames.LocalSizeY, localSizeY.ToString(CultureInfo.InvariantCulture));
  31. shader.Replace(DefineNames.LocalSizeZ, localSizeZ.ToString(CultureInfo.InvariantCulture));
  32. IShader hostShader = _context.Renderer.CompileShader(shader);
  33. IProgram program = _context.Renderer.CreateProgram(new IShader[] { hostShader });
  34. cpShader = new ComputeShader(program, shader);
  35. _cpPrograms.Add(gpuVa, cpShader);
  36. }
  37. return cpShader;
  38. }
  39. public GraphicsShader GetGraphicsShader(ShaderAddresses addresses)
  40. {
  41. if (!_gpPrograms.TryGetValue(addresses, out GraphicsShader gpShader))
  42. {
  43. gpShader = new GraphicsShader();
  44. if (addresses.VertexA != 0)
  45. {
  46. gpShader.Shader[0] = TranslateGraphicsShader(addresses.Vertex, addresses.VertexA);
  47. }
  48. else
  49. {
  50. gpShader.Shader[0] = TranslateGraphicsShader(addresses.Vertex);
  51. }
  52. gpShader.Shader[1] = TranslateGraphicsShader(addresses.TessControl);
  53. gpShader.Shader[2] = TranslateGraphicsShader(addresses.TessEvaluation);
  54. gpShader.Shader[3] = TranslateGraphicsShader(addresses.Geometry);
  55. gpShader.Shader[4] = TranslateGraphicsShader(addresses.Fragment);
  56. BackpropQualifiers(gpShader);
  57. List<IShader> shaders = new List<IShader>();
  58. for (int stage = 0; stage < gpShader.Shader.Length; stage++)
  59. {
  60. if (gpShader.Shader[stage] == null)
  61. {
  62. continue;
  63. }
  64. IShader shader = _context.Renderer.CompileShader(gpShader.Shader[stage]);
  65. shaders.Add(shader);
  66. }
  67. gpShader.Interface = _context.Renderer.CreateProgram(shaders.ToArray());
  68. _gpPrograms.Add(addresses, gpShader);
  69. }
  70. return gpShader;
  71. }
  72. private ShaderProgram TranslateComputeShader(ulong gpuVa)
  73. {
  74. if (gpuVa == 0)
  75. {
  76. return null;
  77. }
  78. ShaderProgram program;
  79. const TranslationFlags flags =
  80. TranslationFlags.Compute |
  81. TranslationFlags.DebugMode |
  82. TranslationFlags.Unspecialized;
  83. TranslationConfig translationConfig = new TranslationConfig(0x10000, _dumper.CurrentDumpIndex, flags);
  84. Span<byte> code = _context.MemoryAccessor.Read(gpuVa, MaxProgramSize);
  85. program = Translator.Translate(code, translationConfig);
  86. _dumper.Dump(code, compute : true, out string fullPath, out string codePath);
  87. if (fullPath != null && codePath != null)
  88. {
  89. program.Prepend("// " + codePath);
  90. program.Prepend("// " + fullPath);
  91. }
  92. return program;
  93. }
  94. private ShaderProgram TranslateGraphicsShader(ulong gpuVa, ulong gpuVaA = 0)
  95. {
  96. if (gpuVa == 0)
  97. {
  98. return null;
  99. }
  100. ShaderProgram program;
  101. const TranslationFlags flags =
  102. TranslationFlags.DebugMode |
  103. TranslationFlags.Unspecialized;
  104. TranslationConfig translationConfig = new TranslationConfig(0x10000, _dumper.CurrentDumpIndex, flags);
  105. if (gpuVaA != 0)
  106. {
  107. Span<byte> codeA = _context.MemoryAccessor.Read(gpuVaA, MaxProgramSize);
  108. Span<byte> codeB = _context.MemoryAccessor.Read(gpuVa, MaxProgramSize);
  109. program = Translator.Translate(codeA, codeB, translationConfig);
  110. _dumper.Dump(codeA, compute: false, out string fullPathA, out string codePathA);
  111. _dumper.Dump(codeB, compute: false, out string fullPathB, out string codePathB);
  112. if (fullPathA != null && fullPathB != null && codePathA != null && codePathB != null)
  113. {
  114. program.Prepend("// " + codePathB);
  115. program.Prepend("// " + fullPathB);
  116. program.Prepend("// " + codePathA);
  117. program.Prepend("// " + fullPathA);
  118. }
  119. }
  120. else
  121. {
  122. Span<byte> code = _context.MemoryAccessor.Read(gpuVa, MaxProgramSize);
  123. program = Translator.Translate(code, translationConfig);
  124. _dumper.Dump(code, compute: false, out string fullPath, out string codePath);
  125. if (fullPath != null && codePath != null)
  126. {
  127. program.Prepend("// " + codePath);
  128. program.Prepend("// " + fullPath);
  129. }
  130. }
  131. if (program.Stage == ShaderStage.Geometry)
  132. {
  133. PrimitiveType primitiveType = _context.Methods.PrimitiveType;
  134. string inPrimitive = "points";
  135. switch (primitiveType)
  136. {
  137. case PrimitiveType.Points:
  138. inPrimitive = "points";
  139. break;
  140. case PrimitiveType.Lines:
  141. case PrimitiveType.LineLoop:
  142. case PrimitiveType.LineStrip:
  143. inPrimitive = "lines";
  144. break;
  145. case PrimitiveType.LinesAdjacency:
  146. case PrimitiveType.LineStripAdjacency:
  147. inPrimitive = "lines_adjacency";
  148. break;
  149. case PrimitiveType.Triangles:
  150. case PrimitiveType.TriangleStrip:
  151. case PrimitiveType.TriangleFan:
  152. inPrimitive = "triangles";
  153. break;
  154. case PrimitiveType.TrianglesAdjacency:
  155. case PrimitiveType.TriangleStripAdjacency:
  156. inPrimitive = "triangles_adjacency";
  157. break;
  158. }
  159. program.Replace(DefineNames.InputTopologyName, inPrimitive);
  160. }
  161. return program;
  162. }
  163. private void BackpropQualifiers(GraphicsShader program)
  164. {
  165. ShaderProgram fragmentShader = program.Shader[4];
  166. bool isFirst = true;
  167. for (int stage = 3; stage >= 0; stage--)
  168. {
  169. if (program.Shader[stage] == null)
  170. {
  171. continue;
  172. }
  173. // We need to iterate backwards, since we do name replacement,
  174. // and it would otherwise replace a subset of the longer names.
  175. for (int attr = 31; attr >= 0; attr--)
  176. {
  177. string iq = fragmentShader?.Info.InterpolationQualifiers[attr].ToGlslQualifier() ?? string.Empty;
  178. if (isFirst && iq != string.Empty)
  179. {
  180. program.Shader[stage].Replace($"{DefineNames.OutQualifierPrefixName}{attr}", iq);
  181. }
  182. else
  183. {
  184. program.Shader[stage].Replace($"{DefineNames.OutQualifierPrefixName}{attr} ", string.Empty);
  185. }
  186. }
  187. isFirst = false;
  188. }
  189. }
  190. }
  191. }