ShaderCache.cs 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  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(gpuVa, compute : true);
  87. return program;
  88. }
  89. private ShaderProgram TranslateGraphicsShader(ulong gpuVa, ulong gpuVaA = 0)
  90. {
  91. if (gpuVa == 0)
  92. {
  93. return null;
  94. }
  95. ShaderProgram program;
  96. const TranslationFlags flags =
  97. TranslationFlags.DebugMode |
  98. TranslationFlags.Unspecialized;
  99. TranslationConfig translationConfig = new TranslationConfig(0x10000, _dumper.CurrentDumpIndex, flags);
  100. if (gpuVaA != 0)
  101. {
  102. Span<byte> codeA = _context.MemoryAccessor.Read(gpuVaA, MaxProgramSize);
  103. Span<byte> codeB = _context.MemoryAccessor.Read(gpuVa, MaxProgramSize);
  104. program = Translator.Translate(codeA, codeB, translationConfig);
  105. _dumper.Dump(gpuVaA, compute: false);
  106. _dumper.Dump(gpuVa, compute: false);
  107. }
  108. else
  109. {
  110. Span<byte> code = _context.MemoryAccessor.Read(gpuVa, MaxProgramSize);
  111. program = Translator.Translate(code, translationConfig);
  112. _dumper.Dump(gpuVa, compute: false);
  113. }
  114. if (program.Stage == ShaderStage.Geometry)
  115. {
  116. PrimitiveType primitiveType = _context.Methods.PrimitiveType;
  117. string inPrimitive = "points";
  118. switch (primitiveType)
  119. {
  120. case PrimitiveType.Points:
  121. inPrimitive = "points";
  122. break;
  123. case PrimitiveType.Lines:
  124. case PrimitiveType.LineLoop:
  125. case PrimitiveType.LineStrip:
  126. inPrimitive = "lines";
  127. break;
  128. case PrimitiveType.LinesAdjacency:
  129. case PrimitiveType.LineStripAdjacency:
  130. inPrimitive = "lines_adjacency";
  131. break;
  132. case PrimitiveType.Triangles:
  133. case PrimitiveType.TriangleStrip:
  134. case PrimitiveType.TriangleFan:
  135. inPrimitive = "triangles";
  136. break;
  137. case PrimitiveType.TrianglesAdjacency:
  138. case PrimitiveType.TriangleStripAdjacency:
  139. inPrimitive = "triangles_adjacency";
  140. break;
  141. }
  142. program.Replace(DefineNames.InputTopologyName, inPrimitive);
  143. }
  144. return program;
  145. }
  146. private void BackpropQualifiers(GraphicsShader program)
  147. {
  148. ShaderProgram fragmentShader = program.Shader[4];
  149. bool isFirst = true;
  150. for (int stage = 3; stage >= 0; stage--)
  151. {
  152. if (program.Shader[stage] == null)
  153. {
  154. continue;
  155. }
  156. // We need to iterate backwards, since we do name replacement,
  157. // and it would otherwise replace a subset of the longer names.
  158. for (int attr = 31; attr >= 0; attr--)
  159. {
  160. string iq = fragmentShader?.Info.InterpolationQualifiers[attr].ToGlslQualifier() ?? string.Empty;
  161. if (isFirst && iq != string.Empty)
  162. {
  163. program.Shader[stage].Replace($"{DefineNames.OutQualifierPrefixName}{attr}", iq);
  164. }
  165. else
  166. {
  167. program.Shader[stage].Replace($"{DefineNames.OutQualifierPrefixName}{attr} ", string.Empty);
  168. }
  169. }
  170. isFirst = false;
  171. }
  172. }
  173. }
  174. }