UcodeAssembler.cs 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. using System;
  2. using System.Collections.Generic;
  3. namespace Ryujinx.Graphics.Gpu.Engine.Threed.Blender
  4. {
  5. /// <summary>
  6. /// Blend microcode instruction.
  7. /// </summary>
  8. enum Instruction
  9. {
  10. Mmadd = 0,
  11. Mmsub = 1,
  12. Min = 2,
  13. Max = 3,
  14. Rcp = 4,
  15. Add = 5,
  16. Sub = 6
  17. }
  18. /// <summary>
  19. /// Blend microcode condition code.
  20. /// </summary>
  21. enum CC
  22. {
  23. F = 0,
  24. T = 1,
  25. EQ = 2,
  26. NE = 3,
  27. LT = 4,
  28. LE = 5,
  29. GT = 6,
  30. GE = 7
  31. }
  32. /// <summary>
  33. /// Blend microcode opend B or D value.
  34. /// </summary>
  35. enum OpBD
  36. {
  37. ConstantZero = 0x0,
  38. ConstantOne = 0x1,
  39. SrcRGB = 0x2,
  40. SrcAAA = 0x3,
  41. OneMinusSrcAAA = 0x4,
  42. DstRGB = 0x5,
  43. DstAAA = 0x6,
  44. OneMinusDstAAA = 0x7,
  45. Temp0 = 0x9,
  46. Temp1 = 0xa,
  47. Temp2 = 0xb,
  48. PBR = 0xc,
  49. ConstantRGB = 0xd
  50. }
  51. /// <summary>
  52. /// Blend microcode operand A or C value.
  53. /// </summary>
  54. enum OpAC
  55. {
  56. SrcRGB = 0,
  57. DstRGB = 1,
  58. SrcAAA = 2,
  59. DstAAA = 3,
  60. Temp0 = 4,
  61. Temp1 = 5,
  62. Temp2 = 6,
  63. PBR = 7
  64. }
  65. /// <summary>
  66. /// Blend microcode destination operand.
  67. /// </summary>
  68. enum OpDst
  69. {
  70. Temp0 = 0,
  71. Temp1 = 1,
  72. Temp2 = 2,
  73. PBR = 3
  74. }
  75. /// <summary>
  76. /// Blend microcode input swizzle.
  77. /// </summary>
  78. enum Swizzle
  79. {
  80. RGB = 0,
  81. GBR = 1,
  82. RRR = 2,
  83. GGG = 3,
  84. BBB = 4,
  85. RToA = 5
  86. }
  87. /// <summary>
  88. /// Blend microcode output components.
  89. /// </summary>
  90. enum WriteMask
  91. {
  92. RGB = 0,
  93. R = 1,
  94. G = 2,
  95. B = 3
  96. }
  97. /// <summary>
  98. /// Floating-point RGB color values.
  99. /// </summary>
  100. struct RgbFloat
  101. {
  102. /// <summary>
  103. /// Red component value.
  104. /// </summary>
  105. public float R { get; }
  106. /// <summary>
  107. /// Green component value.
  108. /// </summary>
  109. public float G { get; }
  110. /// <summary>
  111. /// Blue component value.
  112. /// </summary>
  113. public float B { get; }
  114. /// <summary>
  115. /// Creates a new floating-point RGB value.
  116. /// </summary>
  117. /// <param name="r">Red component value</param>
  118. /// <param name="g">Green component value</param>
  119. /// <param name="b">Blue component value</param>
  120. public RgbFloat(float r, float g, float b)
  121. {
  122. R = r;
  123. G = g;
  124. B = b;
  125. }
  126. }
  127. /// <summary>
  128. /// Blend microcode destination operand, including swizzle, write mask and condition code update flag.
  129. /// </summary>
  130. struct Dest
  131. {
  132. public static Dest Temp0 => new Dest(OpDst.Temp0, Swizzle.RGB, WriteMask.RGB, false);
  133. public static Dest Temp1 => new Dest(OpDst.Temp1, Swizzle.RGB, WriteMask.RGB, false);
  134. public static Dest Temp2 => new Dest(OpDst.Temp2, Swizzle.RGB, WriteMask.RGB, false);
  135. public static Dest PBR => new Dest(OpDst.PBR, Swizzle.RGB, WriteMask.RGB, false);
  136. public Dest GBR => new Dest(Dst, Swizzle.GBR, WriteMask, WriteCC);
  137. public Dest RRR => new Dest(Dst, Swizzle.RRR, WriteMask, WriteCC);
  138. public Dest GGG => new Dest(Dst, Swizzle.GGG, WriteMask, WriteCC);
  139. public Dest BBB => new Dest(Dst, Swizzle.BBB, WriteMask, WriteCC);
  140. public Dest RToA => new Dest(Dst, Swizzle.RToA, WriteMask, WriteCC);
  141. public Dest R => new Dest(Dst, Swizzle, WriteMask.R, WriteCC);
  142. public Dest G => new Dest(Dst, Swizzle, WriteMask.G, WriteCC);
  143. public Dest B => new Dest(Dst, Swizzle, WriteMask.B, WriteCC);
  144. public Dest CC => new Dest(Dst, Swizzle, WriteMask, true);
  145. public OpDst Dst { get; }
  146. public Swizzle Swizzle { get; }
  147. public WriteMask WriteMask { get; }
  148. public bool WriteCC { get; }
  149. /// <summary>
  150. /// Creates a new blend microcode destination operand.
  151. /// </summary>
  152. /// <param name="dst">Operand</param>
  153. /// <param name="swizzle">Swizzle</param>
  154. /// <param name="writeMask">Write maks</param>
  155. /// <param name="writeCC">Indicates if condition codes should be updated</param>
  156. public Dest(OpDst dst, Swizzle swizzle, WriteMask writeMask, bool writeCC)
  157. {
  158. Dst = dst;
  159. Swizzle = swizzle;
  160. WriteMask = writeMask;
  161. WriteCC = writeCC;
  162. }
  163. }
  164. /// <summary>
  165. /// Blend microcode operaiton.
  166. /// </summary>
  167. struct UcodeOp
  168. {
  169. public readonly uint Word;
  170. /// <summary>
  171. /// Creates a new blend microcode operation.
  172. /// </summary>
  173. /// <param name="cc">Condition code that controls whenever the operation is executed or not</param>
  174. /// <param name="inst">Instruction</param>
  175. /// <param name="constIndex">Index on the constant table of the constant used by any constant operand</param>
  176. /// <param name="dest">Destination operand</param>
  177. /// <param name="srcA">First input operand</param>
  178. /// <param name="srcB">Second input operand</param>
  179. /// <param name="srcC">Third input operand</param>
  180. /// <param name="srcD">Fourth input operand</param>
  181. public UcodeOp(CC cc, Instruction inst, int constIndex, Dest dest, OpAC srcA, OpBD srcB, OpAC srcC, OpBD srcD)
  182. {
  183. Word = (uint)cc |
  184. ((uint)inst << 3) |
  185. ((uint)constIndex << 6) |
  186. ((uint)srcA << 9) |
  187. ((uint)srcB << 12) |
  188. ((uint)srcC << 16) |
  189. ((uint)srcD << 19) |
  190. ((uint)dest.Swizzle << 23) |
  191. ((uint)dest.WriteMask << 26) |
  192. ((uint)dest.Dst << 28) |
  193. (dest.WriteCC ? (1u << 31) : 0);
  194. }
  195. }
  196. /// <summary>
  197. /// Blend microcode assembler.
  198. /// </summary>
  199. struct UcodeAssembler
  200. {
  201. private List<uint> _code;
  202. private RgbFloat[] _constants;
  203. private int _constantIndex;
  204. public void Mul(CC cc, Dest dest, OpAC srcA, OpBD srcB)
  205. {
  206. Assemble(cc, Instruction.Mmadd, dest, srcA, srcB, OpAC.SrcRGB, OpBD.ConstantZero);
  207. }
  208. public void Madd(CC cc, Dest dest, OpAC srcA, OpBD srcB, OpAC srcC)
  209. {
  210. Assemble(cc, Instruction.Mmadd, dest, srcA, srcB, srcC, OpBD.ConstantOne);
  211. }
  212. public void Mmadd(CC cc, Dest dest, OpAC srcA, OpBD srcB, OpAC srcC, OpBD srcD)
  213. {
  214. Assemble(cc, Instruction.Mmadd, dest, srcA, srcB, srcC, srcD);
  215. }
  216. public void Mmsub(CC cc, Dest dest, OpAC srcA, OpBD srcB, OpAC srcC, OpBD srcD)
  217. {
  218. Assemble(cc, Instruction.Mmsub, dest, srcA, srcB, srcC, srcD);
  219. }
  220. public void Min(CC cc, Dest dest, OpAC srcA, OpBD srcB)
  221. {
  222. Assemble(cc, Instruction.Min, dest, srcA, srcB, OpAC.SrcRGB, OpBD.ConstantZero);
  223. }
  224. public void Max(CC cc, Dest dest, OpAC srcA, OpBD srcB)
  225. {
  226. Assemble(cc, Instruction.Max, dest, srcA, srcB, OpAC.SrcRGB, OpBD.ConstantZero);
  227. }
  228. public void Rcp(CC cc, Dest dest, OpAC srcA)
  229. {
  230. Assemble(cc, Instruction.Rcp, dest, srcA, OpBD.ConstantZero, OpAC.SrcRGB, OpBD.ConstantZero);
  231. }
  232. public void Mov(CC cc, Dest dest, OpBD srcB)
  233. {
  234. Assemble(cc, Instruction.Add, dest, OpAC.SrcRGB, srcB, OpAC.SrcRGB, OpBD.ConstantZero);
  235. }
  236. public void Add(CC cc, Dest dest, OpBD srcB, OpBD srcD)
  237. {
  238. Assemble(cc, Instruction.Add, dest, OpAC.SrcRGB, srcB, OpAC.SrcRGB, srcD);
  239. }
  240. public void Sub(CC cc, Dest dest, OpBD srcB, OpBD srcD)
  241. {
  242. Assemble(cc, Instruction.Sub, dest, OpAC.SrcRGB, srcB, OpAC.SrcRGB, srcD);
  243. }
  244. private void Assemble(CC cc, Instruction inst, Dest dest, OpAC srcA, OpBD srcB, OpAC srcC, OpBD srcD)
  245. {
  246. (_code ??= new List<uint>()).Add(new UcodeOp(cc, inst, _constantIndex, dest, srcA, srcB, srcC, srcD).Word);
  247. }
  248. public void SetConstant(int index, float r, float g, float b)
  249. {
  250. if (_constants == null)
  251. {
  252. _constants = new RgbFloat[index + 1];
  253. }
  254. else if (_constants.Length <= index)
  255. {
  256. Array.Resize(ref _constants, index + 1);
  257. }
  258. _constants[index] = new RgbFloat(r, g, b);
  259. _constantIndex = index;
  260. }
  261. public uint[] GetCode()
  262. {
  263. return _code?.ToArray();
  264. }
  265. public RgbFloat[] GetConstants()
  266. {
  267. return _constants;
  268. }
  269. }
  270. }