TranslatorContext.cs 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. using Ryujinx.Graphics.Shader.CodeGen.Glsl;
  2. using Ryujinx.Graphics.Shader.CodeGen.Spirv;
  3. using Ryujinx.Graphics.Shader.Decoders;
  4. using Ryujinx.Graphics.Shader.IntermediateRepresentation;
  5. using Ryujinx.Graphics.Shader.StructuredIr;
  6. using System;
  7. using System.Collections.Generic;
  8. using System.Linq;
  9. using System.Numerics;
  10. using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper;
  11. using static Ryujinx.Graphics.Shader.Translation.Translator;
  12. namespace Ryujinx.Graphics.Shader.Translation
  13. {
  14. public class TranslatorContext
  15. {
  16. private readonly DecodedProgram _program;
  17. private ShaderConfig _config;
  18. public ulong Address { get; }
  19. public ShaderStage Stage => _config.Stage;
  20. public int Size => _config.Size;
  21. public int Cb1DataSize => _config.Cb1DataSize;
  22. public bool LayerOutputWritten => _config.LayerOutputWritten;
  23. public IGpuAccessor GpuAccessor => _config.GpuAccessor;
  24. internal TranslatorContext(ulong address, DecodedProgram program, ShaderConfig config)
  25. {
  26. Address = address;
  27. _program = program;
  28. _config = config;
  29. }
  30. private static bool IsLoadUserDefined(Operation operation)
  31. {
  32. // TODO: Check if sources count match and all sources are constant.
  33. return operation.Inst == Instruction.Load && (IoVariable)operation.GetSource(0).Value == IoVariable.UserDefined;
  34. }
  35. private static bool IsStoreUserDefined(Operation operation)
  36. {
  37. // TODO: Check if sources count match and all sources are constant.
  38. return operation.Inst == Instruction.Store && (IoVariable)operation.GetSource(0).Value == IoVariable.UserDefined;
  39. }
  40. private static FunctionCode[] Combine(FunctionCode[] a, FunctionCode[] b, int aStart)
  41. {
  42. // Here we combine two shaders.
  43. // For shader A:
  44. // - All user attribute stores on shader A are turned into copies to a
  45. // temporary variable. It's assumed that shader B will consume them.
  46. // - All return instructions are turned into branch instructions, the
  47. // branch target being the start of the shader B code.
  48. // For shader B:
  49. // - All user attribute loads on shader B are turned into copies from a
  50. // temporary variable, as long that attribute is written by shader A.
  51. FunctionCode[] output = new FunctionCode[a.Length + b.Length - 1];
  52. List<Operation> ops = new List<Operation>(a.Length + b.Length);
  53. Operand[] temps = new Operand[AttributeConsts.UserAttributesCount * 4];
  54. Operand lblB = Label();
  55. for (int index = aStart; index < a[0].Code.Length; index++)
  56. {
  57. Operation operation = a[0].Code[index];
  58. if (IsStoreUserDefined(operation))
  59. {
  60. int tIndex = operation.GetSource(1).Value * 4 + operation.GetSource(2).Value;
  61. Operand temp = temps[tIndex];
  62. if (temp == null)
  63. {
  64. temp = Local();
  65. temps[tIndex] = temp;
  66. }
  67. operation.Dest = temp;
  68. operation.TurnIntoCopy(operation.GetSource(operation.SourcesCount - 1));
  69. }
  70. if (operation.Inst == Instruction.Return)
  71. {
  72. ops.Add(new Operation(Instruction.Branch, lblB));
  73. }
  74. else
  75. {
  76. ops.Add(operation);
  77. }
  78. }
  79. ops.Add(new Operation(Instruction.MarkLabel, lblB));
  80. for (int index = 0; index < b[0].Code.Length; index++)
  81. {
  82. Operation operation = b[0].Code[index];
  83. if (IsLoadUserDefined(operation))
  84. {
  85. int tIndex = operation.GetSource(1).Value * 4 + operation.GetSource(2).Value;
  86. Operand temp = temps[tIndex];
  87. if (temp != null)
  88. {
  89. operation.TurnIntoCopy(temp);
  90. }
  91. }
  92. ops.Add(operation);
  93. }
  94. output[0] = new FunctionCode(ops.ToArray());
  95. for (int i = 1; i < a.Length; i++)
  96. {
  97. output[i] = a[i];
  98. }
  99. for (int i = 1; i < b.Length; i++)
  100. {
  101. output[a.Length + i - 1] = b[i];
  102. }
  103. return output;
  104. }
  105. public void SetNextStage(TranslatorContext nextStage)
  106. {
  107. _config.MergeFromtNextStage(nextStage._config);
  108. }
  109. public void SetGeometryShaderLayerInputAttribute(int attr)
  110. {
  111. _config.SetGeometryShaderLayerInputAttribute(attr);
  112. }
  113. public void SetLastInVertexPipeline()
  114. {
  115. _config.SetLastInVertexPipeline();
  116. }
  117. public ShaderProgram Translate(TranslatorContext other = null)
  118. {
  119. FunctionCode[] code = EmitShader(_program, _config, initializeOutputs: other == null, out _);
  120. if (other != null)
  121. {
  122. other._config.MergeOutputUserAttributes(_config.UsedOutputAttributes, Enumerable.Empty<int>());
  123. FunctionCode[] otherCode = EmitShader(other._program, other._config, initializeOutputs: true, out int aStart);
  124. code = Combine(otherCode, code, aStart);
  125. _config.InheritFrom(other._config);
  126. }
  127. return Translator.Translate(code, _config);
  128. }
  129. public ShaderProgram GenerateGeometryPassthrough()
  130. {
  131. int outputAttributesMask = _config.UsedOutputAttributes;
  132. int layerOutputAttr = _config.LayerOutputAttribute;
  133. OutputTopology outputTopology;
  134. int maxOutputVertices;
  135. switch (GpuAccessor.QueryPrimitiveTopology())
  136. {
  137. case InputTopology.Points:
  138. outputTopology = OutputTopology.PointList;
  139. maxOutputVertices = 1;
  140. break;
  141. case InputTopology.Lines:
  142. case InputTopology.LinesAdjacency:
  143. outputTopology = OutputTopology.LineStrip;
  144. maxOutputVertices = 2;
  145. break;
  146. default:
  147. outputTopology = OutputTopology.TriangleStrip;
  148. maxOutputVertices = 3;
  149. break;
  150. }
  151. ShaderConfig config = new ShaderConfig(ShaderStage.Geometry, outputTopology, maxOutputVertices, GpuAccessor, _config.Options);
  152. EmitterContext context = new EmitterContext(default, config, false);
  153. for (int v = 0; v < maxOutputVertices; v++)
  154. {
  155. int outAttrsMask = outputAttributesMask;
  156. while (outAttrsMask != 0)
  157. {
  158. int attrIndex = BitOperations.TrailingZeroCount(outAttrsMask);
  159. outAttrsMask &= ~(1 << attrIndex);
  160. for (int c = 0; c < 4; c++)
  161. {
  162. int attr = AttributeConsts.UserAttributeBase + attrIndex * 16 + c * 4;
  163. Operand value = context.Load(StorageKind.Input, IoVariable.UserDefined, Const(attrIndex), Const(v), Const(c));
  164. if (attr == layerOutputAttr)
  165. {
  166. context.Store(StorageKind.Output, IoVariable.Layer, null, value);
  167. }
  168. else
  169. {
  170. context.Store(StorageKind.Output, IoVariable.UserDefined, null, Const(attrIndex), Const(c), value);
  171. config.SetOutputUserAttribute(attrIndex);
  172. }
  173. config.SetInputUserAttribute(attrIndex, c);
  174. }
  175. }
  176. for (int c = 0; c < 4; c++)
  177. {
  178. Operand value = context.Load(StorageKind.Input, IoVariable.Position, Const(v), Const(c));
  179. context.Store(StorageKind.Output, IoVariable.Position, null, Const(c), value);
  180. }
  181. context.EmitVertex();
  182. }
  183. context.EndPrimitive();
  184. var operations = context.GetOperations();
  185. var cfg = ControlFlowGraph.Create(operations);
  186. var function = new Function(cfg.Blocks, "main", false, 0, 0);
  187. var sInfo = StructuredProgram.MakeStructuredProgram(new[] { function }, config);
  188. var info = config.CreateProgramInfo();
  189. return config.Options.TargetLanguage switch
  190. {
  191. TargetLanguage.Glsl => new ShaderProgram(info, TargetLanguage.Glsl, GlslGenerator.Generate(sInfo, config)),
  192. TargetLanguage.Spirv => new ShaderProgram(info, TargetLanguage.Spirv, SpirvGenerator.Generate(sInfo, config)),
  193. _ => throw new NotImplementedException(config.Options.TargetLanguage.ToString())
  194. };
  195. }
  196. }
  197. }