ShaderOptExprProp.cs 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. using System;
  2. using System.Collections.Generic;
  3. namespace Ryujinx.Graphics.Gal.Shader
  4. {
  5. static class ShaderOptExprProp
  6. {
  7. private struct UseSite
  8. {
  9. public object Parent;
  10. public int OperIndex;
  11. public UseSite(object Parent, int OperIndex)
  12. {
  13. this.Parent = Parent;
  14. this.OperIndex = OperIndex;
  15. }
  16. }
  17. private class RegUse
  18. {
  19. public ShaderIrAsg Asg { get; private set; }
  20. public int AsgIndex { get; private set; }
  21. private bool Propagate;
  22. private List<UseSite> Sites;
  23. public RegUse()
  24. {
  25. Sites = new List<UseSite>();
  26. }
  27. public void AddUseSite(UseSite Site)
  28. {
  29. Sites.Add(Site);
  30. }
  31. public bool TryPropagate()
  32. {
  33. //This happens when a untiliazied register is used,
  34. //this usually indicates a decoding error, but may also
  35. //be cased by bogus programs (?). In any case, we just
  36. //keep the unitialized access and avoid trying to propagate
  37. //the expression (since we can't propagate what doesn't yet exist).
  38. if (Asg == null || !Propagate)
  39. {
  40. return false;
  41. }
  42. if (Sites.Count > 0)
  43. {
  44. foreach (UseSite Site in Sites)
  45. {
  46. if (Site.Parent is ShaderIrCond Cond)
  47. {
  48. switch (Site.OperIndex)
  49. {
  50. case 0: Cond.Pred = Asg.Src; break;
  51. case 1: Cond.Child = Asg.Src; break;
  52. default: throw new InvalidOperationException();
  53. }
  54. }
  55. else if (Site.Parent is ShaderIrOp Op)
  56. {
  57. switch (Site.OperIndex)
  58. {
  59. case 0: Op.OperandA = Asg.Src; break;
  60. case 1: Op.OperandB = Asg.Src; break;
  61. case 2: Op.OperandC = Asg.Src; break;
  62. default: throw new InvalidOperationException();
  63. }
  64. }
  65. else if (Site.Parent is ShaderIrAsg SiteAsg)
  66. {
  67. SiteAsg.Src = Asg.Src;
  68. }
  69. else
  70. {
  71. throw new InvalidOperationException();
  72. }
  73. }
  74. }
  75. return true;
  76. }
  77. public void SetNewAsg(ShaderIrAsg Asg, int AsgIndex, bool Propagate)
  78. {
  79. this.Asg = Asg;
  80. this.AsgIndex = AsgIndex;
  81. this.Propagate = Propagate;
  82. Sites.Clear();
  83. }
  84. }
  85. public static void Optimize(List<ShaderIrNode> Nodes, GalShaderType ShaderType)
  86. {
  87. Dictionary<int, RegUse> Uses = new Dictionary<int, RegUse>();
  88. RegUse GetUse(int Key)
  89. {
  90. RegUse Use;
  91. if (!Uses.TryGetValue(Key, out Use))
  92. {
  93. Use = new RegUse();
  94. Uses.Add(Key, Use);
  95. }
  96. return Use;
  97. }
  98. int GetGprKey(int GprIndex)
  99. {
  100. return GprIndex;
  101. }
  102. int GetPredKey(int PredIndex)
  103. {
  104. return PredIndex | 0x10000000;
  105. }
  106. RegUse GetGprUse(int GprIndex)
  107. {
  108. return GetUse(GetGprKey(GprIndex));
  109. }
  110. RegUse GetPredUse(int PredIndex)
  111. {
  112. return GetUse(GetPredKey(PredIndex));
  113. }
  114. void FindRegUses(List<(int, UseSite)> UseList, object Parent, ShaderIrNode Node, int OperIndex = 0)
  115. {
  116. if (Node is ShaderIrAsg Asg)
  117. {
  118. FindRegUses(UseList, Asg, Asg.Src);
  119. }
  120. else if (Node is ShaderIrCond Cond)
  121. {
  122. FindRegUses(UseList, Cond, Cond.Pred, 0);
  123. FindRegUses(UseList, Cond, Cond.Child, 1);
  124. }
  125. else if (Node is ShaderIrOp Op)
  126. {
  127. FindRegUses(UseList, Op, Op.OperandA, 0);
  128. FindRegUses(UseList, Op, Op.OperandB, 1);
  129. FindRegUses(UseList, Op, Op.OperandC, 2);
  130. }
  131. else if (Node is ShaderIrOperGpr Gpr && Gpr.Index != ShaderIrOperGpr.ZRIndex)
  132. {
  133. UseList.Add((GetGprKey(Gpr.Index), new UseSite(Parent, OperIndex)));
  134. }
  135. else if (Node is ShaderIrOperPred Pred)
  136. {
  137. UseList.Add((GetPredKey(Pred.Index), new UseSite(Parent, OperIndex)));
  138. }
  139. }
  140. void TryAddRegUseSite(ShaderIrNode Node)
  141. {
  142. List<(int, UseSite)> UseList = new List<(int, UseSite)>();
  143. FindRegUses(UseList, null, Node);
  144. foreach ((int Key, UseSite Site) in UseList)
  145. {
  146. GetUse(Key).AddUseSite(Site);
  147. }
  148. }
  149. bool TryPropagate(RegUse Use)
  150. {
  151. //We can only propagate if the registers that the expression depends
  152. //on weren't assigned after the original expression assignment
  153. //to a register took place. We traverse the expression tree to find
  154. //all registers being used, if any of those registers was assigned
  155. //after the assignment to be propagated, then we can't propagate.
  156. if (Use?.Asg == null)
  157. {
  158. return false;
  159. }
  160. List<(int, UseSite)> UseList = new List<(int, UseSite)>();
  161. FindRegUses(UseList, Use.Asg, Use.Asg.Src);
  162. foreach ((int Key, UseSite Site) in UseList)
  163. {
  164. if (GetUse(Key).AsgIndex >= Use.AsgIndex)
  165. {
  166. return false;
  167. }
  168. }
  169. return Use.TryPropagate();
  170. }
  171. for (int Index = 0, AsgIndex = 0; Index < Nodes.Count; Index++, AsgIndex++)
  172. {
  173. ShaderIrNode Node = Nodes[Index];
  174. bool IsConditional = Node is ShaderIrCond;
  175. TryAddRegUseSite(Node);
  176. while (Node is ShaderIrCond Cond)
  177. {
  178. Node = Cond.Child;
  179. }
  180. if (!(Node is ShaderIrAsg Asg))
  181. {
  182. continue;
  183. }
  184. RegUse Use = null;
  185. if (Asg.Dst is ShaderIrOperGpr Gpr && Gpr.Index != ShaderIrOperGpr.ZRIndex)
  186. {
  187. Use = GetGprUse(Gpr.Index);
  188. }
  189. else if (Asg.Dst is ShaderIrOperPred Pred)
  190. {
  191. Use = GetPredUse(Pred.Index);
  192. }
  193. if (!IsConditional && TryPropagate(Use))
  194. {
  195. Nodes.Remove(Use.Asg);
  196. Index--;
  197. }
  198. //All nodes inside conditional nodes can't be propagated,
  199. //as we don't even know if they will be executed to begin with.
  200. Use?.SetNewAsg(Asg, AsgIndex, !IsConditional);
  201. }
  202. foreach (RegUse Use in Uses.Values)
  203. {
  204. //Gprs 0-3 are the color output on fragment shaders,
  205. //so we can't remove the last assignments to those registers.
  206. if (ShaderType == GalShaderType.Fragment)
  207. {
  208. if (Use.Asg?.Dst is ShaderIrOperGpr Gpr && Gpr.Index < 4)
  209. {
  210. continue;
  211. }
  212. }
  213. if (TryPropagate(Use))
  214. {
  215. Nodes.Remove(Use.Asg);
  216. }
  217. }
  218. }
  219. }
  220. }