EmitterContext.cs 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. using Ryujinx.Graphics.Shader.Decoders;
  2. using Ryujinx.Graphics.Shader.IntermediateRepresentation;
  3. using System.Collections.Generic;
  4. using System.Diagnostics;
  5. using System.Runtime.CompilerServices;
  6. using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper;
  7. namespace Ryujinx.Graphics.Shader.Translation
  8. {
  9. class EmitterContext
  10. {
  11. public Block CurrBlock { get; set; }
  12. public InstOp CurrOp { get; set; }
  13. public ShaderConfig Config { get; }
  14. public bool IsNonMain { get; }
  15. public int OperationsCount => _operations.Count;
  16. private readonly IReadOnlyDictionary<ulong, int> _funcs;
  17. private readonly List<Operation> _operations;
  18. private readonly Dictionary<ulong, Operand> _labels;
  19. public EmitterContext(ShaderConfig config, bool isNonMain, IReadOnlyDictionary<ulong, int> funcs)
  20. {
  21. Config = config;
  22. IsNonMain = isNonMain;
  23. _funcs = funcs;
  24. _operations = new List<Operation>();
  25. _labels = new Dictionary<ulong, Operand>();
  26. }
  27. public T GetOp<T>() where T : unmanaged
  28. {
  29. Debug.Assert(Unsafe.SizeOf<T>() == sizeof(ulong));
  30. ulong op = CurrOp.RawOpCode;
  31. return Unsafe.As<ulong, T>(ref op);
  32. }
  33. public Operand Add(Instruction inst, Operand dest = null, params Operand[] sources)
  34. {
  35. Operation operation = new Operation(inst, dest, sources);
  36. Add(operation);
  37. return dest;
  38. }
  39. public (Operand, Operand) Add(Instruction inst, (Operand, Operand) dest, params Operand[] sources)
  40. {
  41. Operand[] dests = new[] { dest.Item1, dest.Item2 };
  42. Operation operation = new Operation(inst, 0, dests, sources);
  43. Add(operation);
  44. return dest;
  45. }
  46. public void Add(Operation operation)
  47. {
  48. _operations.Add(operation);
  49. }
  50. public TextureOperation CreateTextureOperation(
  51. Instruction inst,
  52. SamplerType type,
  53. TextureFlags flags,
  54. int handle,
  55. int compIndex,
  56. Operand dest,
  57. params Operand[] sources)
  58. {
  59. return CreateTextureOperation(inst, type, TextureFormat.Unknown, flags, handle, compIndex, dest, sources);
  60. }
  61. public TextureOperation CreateTextureOperation(
  62. Instruction inst,
  63. SamplerType type,
  64. TextureFormat format,
  65. TextureFlags flags,
  66. int handle,
  67. int compIndex,
  68. Operand dest,
  69. params Operand[] sources)
  70. {
  71. if (!flags.HasFlag(TextureFlags.Bindless))
  72. {
  73. Config.SetUsedTexture(inst, type, format, flags, TextureOperation.DefaultCbufSlot, handle);
  74. }
  75. return new TextureOperation(inst, type, format, flags, handle, compIndex, dest, sources);
  76. }
  77. public void FlagAttributeRead(int attribute)
  78. {
  79. if (Config.Stage == ShaderStage.Vertex && attribute == AttributeConsts.InstanceId)
  80. {
  81. Config.SetUsedFeature(FeatureFlags.InstanceId);
  82. }
  83. else if (Config.Stage == ShaderStage.Fragment)
  84. {
  85. switch (attribute)
  86. {
  87. case AttributeConsts.PositionX:
  88. case AttributeConsts.PositionY:
  89. Config.SetUsedFeature(FeatureFlags.FragCoordXY);
  90. break;
  91. }
  92. }
  93. }
  94. public void FlagAttributeWritten(int attribute)
  95. {
  96. if (Config.Stage == ShaderStage.Vertex)
  97. {
  98. switch (attribute)
  99. {
  100. case AttributeConsts.ClipDistance0:
  101. case AttributeConsts.ClipDistance1:
  102. case AttributeConsts.ClipDistance2:
  103. case AttributeConsts.ClipDistance3:
  104. case AttributeConsts.ClipDistance4:
  105. case AttributeConsts.ClipDistance5:
  106. case AttributeConsts.ClipDistance6:
  107. case AttributeConsts.ClipDistance7:
  108. Config.SetClipDistanceWritten((attribute - AttributeConsts.ClipDistance0) / 4);
  109. break;
  110. }
  111. }
  112. if (Config.Stage != ShaderStage.Fragment && attribute == AttributeConsts.Layer)
  113. {
  114. Config.SetUsedFeature(FeatureFlags.RtLayer);
  115. }
  116. }
  117. public void MarkLabel(Operand label)
  118. {
  119. Add(Instruction.MarkLabel, label);
  120. }
  121. public Operand GetLabel(ulong address)
  122. {
  123. if (!_labels.TryGetValue(address, out Operand label))
  124. {
  125. label = Label();
  126. _labels.Add(address, label);
  127. }
  128. return label;
  129. }
  130. public int GetFunctionId(ulong address)
  131. {
  132. return _funcs[address];
  133. }
  134. public void PrepareForReturn()
  135. {
  136. if (!IsNonMain && Config.Stage == ShaderStage.Fragment)
  137. {
  138. if (Config.OmapDepth)
  139. {
  140. Operand dest = Attribute(AttributeConsts.FragmentOutputDepth);
  141. Operand src = Register(Config.GetDepthRegister(), RegisterType.Gpr);
  142. this.Copy(dest, src);
  143. }
  144. int regIndexBase = 0;
  145. for (int rtIndex = 0; rtIndex < 8; rtIndex++)
  146. {
  147. OmapTarget target = Config.OmapTargets[rtIndex];
  148. for (int component = 0; component < 4; component++)
  149. {
  150. if (!target.ComponentEnabled(component))
  151. {
  152. continue;
  153. }
  154. int fragmentOutputColorAttr = AttributeConsts.FragmentOutputColorBase + rtIndex * 16;
  155. Operand src = Register(regIndexBase + component, RegisterType.Gpr);
  156. // Perform B <-> R swap if needed, for BGRA formats (not supported on OpenGL).
  157. if (component == 0 || component == 2)
  158. {
  159. Operand isBgra = Attribute(AttributeConsts.FragmentOutputIsBgraBase + rtIndex * 4);
  160. Operand lblIsBgra = Label();
  161. Operand lblEnd = Label();
  162. this.BranchIfTrue(lblIsBgra, isBgra);
  163. this.Copy(Attribute(fragmentOutputColorAttr + component * 4), src);
  164. this.Branch(lblEnd);
  165. MarkLabel(lblIsBgra);
  166. this.Copy(Attribute(fragmentOutputColorAttr + (2 - component) * 4), src);
  167. MarkLabel(lblEnd);
  168. }
  169. else
  170. {
  171. this.Copy(Attribute(fragmentOutputColorAttr + component * 4), src);
  172. }
  173. }
  174. if (target.Enabled)
  175. {
  176. Config.SetOutputUserAttribute(rtIndex, perPatch: false);
  177. regIndexBase += 4;
  178. }
  179. }
  180. }
  181. }
  182. public Operation[] GetOperations()
  183. {
  184. return _operations.ToArray();
  185. }
  186. }
  187. }