ShaderCache.cs 7.6 KB

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