EmitterContext.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  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 PrepareForVertexReturn()
  131. {
  132. if (Config.GpuAccessor.QueryViewportTransformDisable())
  133. {
  134. Operand x = Attribute(AttributeConsts.PositionX | AttributeConsts.LoadOutputMask);
  135. Operand y = Attribute(AttributeConsts.PositionY | AttributeConsts.LoadOutputMask);
  136. Operand xScale = Attribute(AttributeConsts.SupportBlockViewInverseX);
  137. Operand yScale = Attribute(AttributeConsts.SupportBlockViewInverseY);
  138. Operand negativeOne = ConstF(-1.0f);
  139. this.Copy(Attribute(AttributeConsts.PositionX), this.FPFusedMultiplyAdd(x, xScale, negativeOne));
  140. this.Copy(Attribute(AttributeConsts.PositionY), this.FPFusedMultiplyAdd(y, yScale, negativeOne));
  141. }
  142. }
  143. public void PrepareForVertexReturn(out Operand oldXLocal, out Operand oldYLocal, out Operand oldZLocal)
  144. {
  145. if (Config.GpuAccessor.QueryViewportTransformDisable())
  146. {
  147. oldXLocal = Local();
  148. this.Copy(oldXLocal, Attribute(AttributeConsts.PositionX | AttributeConsts.LoadOutputMask));
  149. oldYLocal = Local();
  150. this.Copy(oldYLocal, Attribute(AttributeConsts.PositionY | AttributeConsts.LoadOutputMask));
  151. }
  152. else
  153. {
  154. oldXLocal = null;
  155. oldYLocal = null;
  156. }
  157. // Will be used by Vulkan backend for depth mode emulation.
  158. oldZLocal = null;
  159. PrepareForVertexReturn();
  160. }
  161. public void PrepareForReturn()
  162. {
  163. if (IsNonMain)
  164. {
  165. return;
  166. }
  167. if (Config.LastInVertexPipeline &&
  168. (Config.Stage == ShaderStage.Vertex || Config.Stage == ShaderStage.TessellationEvaluation) &&
  169. (Config.Options.Flags & TranslationFlags.VertexA) == 0)
  170. {
  171. PrepareForVertexReturn();
  172. }
  173. else if (Config.Stage == ShaderStage.Fragment)
  174. {
  175. GenerateAlphaToCoverageDitherDiscard();
  176. if (Config.OmapDepth)
  177. {
  178. Operand dest = Attribute(AttributeConsts.FragmentOutputDepth);
  179. Operand src = Register(Config.GetDepthRegister(), RegisterType.Gpr);
  180. this.Copy(dest, src);
  181. }
  182. bool supportsBgra = Config.GpuAccessor.QueryHostSupportsBgraFormat();
  183. int regIndexBase = 0;
  184. for (int rtIndex = 0; rtIndex < 8; rtIndex++)
  185. {
  186. for (int component = 0; component < 4; component++)
  187. {
  188. bool componentEnabled = (Config.OmapTargets & (1 << (rtIndex * 4 + component))) != 0;
  189. if (!componentEnabled)
  190. {
  191. continue;
  192. }
  193. int fragmentOutputColorAttr = AttributeConsts.FragmentOutputColorBase + rtIndex * 16;
  194. Operand src = Register(regIndexBase + component, RegisterType.Gpr);
  195. // Perform B <-> R swap if needed, for BGRA formats (not supported on OpenGL).
  196. if (!supportsBgra && (component == 0 || component == 2))
  197. {
  198. Operand isBgra = Attribute(AttributeConsts.FragmentOutputIsBgraBase + rtIndex * 4);
  199. Operand lblIsBgra = Label();
  200. Operand lblEnd = Label();
  201. this.BranchIfTrue(lblIsBgra, isBgra);
  202. this.Copy(Attribute(fragmentOutputColorAttr + component * 4), src);
  203. this.Branch(lblEnd);
  204. MarkLabel(lblIsBgra);
  205. this.Copy(Attribute(fragmentOutputColorAttr + (2 - component) * 4), src);
  206. MarkLabel(lblEnd);
  207. }
  208. else
  209. {
  210. this.Copy(Attribute(fragmentOutputColorAttr + component * 4), src);
  211. }
  212. }
  213. bool targetEnabled = (Config.OmapTargets & (0xf << (rtIndex * 4))) != 0;
  214. if (targetEnabled)
  215. {
  216. Config.SetOutputUserAttribute(rtIndex, perPatch: false);
  217. regIndexBase += 4;
  218. }
  219. }
  220. }
  221. }
  222. private void GenerateAlphaToCoverageDitherDiscard()
  223. {
  224. // If the feature is disabled, or alpha is not written, then we're done.
  225. if (!Config.GpuAccessor.QueryAlphaToCoverageDitherEnable() || (Config.OmapTargets & 8) == 0)
  226. {
  227. return;
  228. }
  229. // 11 11 11 10 10 10 10 00
  230. // 11 01 01 01 01 00 00 00
  231. Operand ditherMask = Const(unchecked((int)0xfbb99110u));
  232. Operand x = this.BitwiseAnd(this.FP32ConvertToU32(Attribute(AttributeConsts.PositionX)), Const(1));
  233. Operand y = this.BitwiseAnd(this.FP32ConvertToU32(Attribute(AttributeConsts.PositionY)), Const(1));
  234. Operand xy = this.BitwiseOr(x, this.ShiftLeft(y, Const(1)));
  235. Operand alpha = Register(3, RegisterType.Gpr);
  236. Operand scaledAlpha = this.FPMultiply(this.FPSaturate(alpha), ConstF(8));
  237. Operand quantizedAlpha = this.IMinimumU32(this.FP32ConvertToU32(scaledAlpha), Const(7));
  238. Operand shift = this.BitwiseOr(this.ShiftLeft(quantizedAlpha, Const(2)), xy);
  239. Operand opaque = this.BitwiseAnd(this.ShiftRightU32(ditherMask, shift), Const(1));
  240. Operand a2cDitherEndLabel = Label();
  241. this.BranchIfTrue(a2cDitherEndLabel, opaque);
  242. this.Discard();
  243. this.MarkLabel(a2cDitherEndLabel);
  244. }
  245. public Operation[] GetOperations()
  246. {
  247. return _operations.ToArray();
  248. }
  249. }
  250. }