EmitterContext.cs 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  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 DecodedProgram Program { get; }
  12. public ShaderConfig Config { get; }
  13. public bool IsNonMain { get; }
  14. public Block CurrBlock { get; set; }
  15. public InstOp CurrOp { get; set; }
  16. public int OperationsCount => _operations.Count;
  17. private readonly List<Operation> _operations;
  18. private readonly Dictionary<ulong, Operand> _labels;
  19. public EmitterContext(DecodedProgram program, ShaderConfig config, bool isNonMain)
  20. {
  21. Program = program;
  22. Config = config;
  23. IsNonMain = isNonMain;
  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 void PrepareForReturn()
  131. {
  132. if (!IsNonMain && Config.Stage == ShaderStage.Fragment)
  133. {
  134. if (Config.OmapDepth)
  135. {
  136. Operand dest = Attribute(AttributeConsts.FragmentOutputDepth);
  137. Operand src = Register(Config.GetDepthRegister(), RegisterType.Gpr);
  138. this.Copy(dest, src);
  139. }
  140. int regIndexBase = 0;
  141. for (int rtIndex = 0; rtIndex < 8; rtIndex++)
  142. {
  143. OmapTarget target = Config.OmapTargets[rtIndex];
  144. for (int component = 0; component < 4; component++)
  145. {
  146. if (!target.ComponentEnabled(component))
  147. {
  148. continue;
  149. }
  150. int fragmentOutputColorAttr = AttributeConsts.FragmentOutputColorBase + rtIndex * 16;
  151. Operand src = Register(regIndexBase + component, RegisterType.Gpr);
  152. // Perform B <-> R swap if needed, for BGRA formats (not supported on OpenGL).
  153. if (component == 0 || component == 2)
  154. {
  155. Operand isBgra = Attribute(AttributeConsts.FragmentOutputIsBgraBase + rtIndex * 4);
  156. Operand lblIsBgra = Label();
  157. Operand lblEnd = Label();
  158. this.BranchIfTrue(lblIsBgra, isBgra);
  159. this.Copy(Attribute(fragmentOutputColorAttr + component * 4), src);
  160. this.Branch(lblEnd);
  161. MarkLabel(lblIsBgra);
  162. this.Copy(Attribute(fragmentOutputColorAttr + (2 - component) * 4), src);
  163. MarkLabel(lblEnd);
  164. }
  165. else
  166. {
  167. this.Copy(Attribute(fragmentOutputColorAttr + component * 4), src);
  168. }
  169. }
  170. if (target.Enabled)
  171. {
  172. Config.SetOutputUserAttribute(rtIndex, perPatch: false);
  173. regIndexBase += 4;
  174. }
  175. }
  176. }
  177. }
  178. public Operation[] GetOperations()
  179. {
  180. return _operations.ToArray();
  181. }
  182. }
  183. }