GpuState.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396
  1. using System;
  2. using System.Runtime.InteropServices;
  3. namespace Ryujinx.Graphics.Gpu.State
  4. {
  5. /// <summary>
  6. /// GPU state.
  7. /// </summary>
  8. class GpuState
  9. {
  10. private const int RegistersCount = 0xe00;
  11. public delegate void MethodCallback(GpuState state, int argument);
  12. private readonly int[] _memory;
  13. private readonly int[] _shadow;
  14. /// <summary>
  15. /// GPU register information.
  16. /// </summary>
  17. private struct Register
  18. {
  19. public MethodCallback Callback;
  20. public MethodOffset BaseOffset;
  21. public int Stride;
  22. public int Count;
  23. public bool Modified;
  24. }
  25. private readonly Register[] _registers;
  26. /// <summary>
  27. /// Creates a new instance of the GPU state.
  28. /// </summary>
  29. public GpuState()
  30. {
  31. _memory = new int[RegistersCount];
  32. _shadow = new int[RegistersCount];
  33. _registers = new Register[RegistersCount];
  34. for (int index = 0; index < _registers.Length; index++)
  35. {
  36. _registers[index].BaseOffset = (MethodOffset)index;
  37. _registers[index].Stride = 1;
  38. _registers[index].Count = 1;
  39. _registers[index].Modified = true;
  40. }
  41. foreach (var item in GpuStateTable.Table)
  42. {
  43. int totalRegs = item.Size * item.Count;
  44. for (int regOffset = 0; regOffset < totalRegs; regOffset++)
  45. {
  46. int index = (int)item.Offset + regOffset;
  47. _registers[index].BaseOffset = item.Offset;
  48. _registers[index].Stride = item.Size;
  49. _registers[index].Count = item.Count;
  50. }
  51. }
  52. InitializeDefaultState(_memory);
  53. InitializeDefaultState(_shadow);
  54. }
  55. /// <summary>
  56. /// Calls a GPU method, using this state.
  57. /// </summary>
  58. /// <param name="meth">The GPU method to be called</param>
  59. /// <param name="shadowCtrl">Shadow RAM control register value</param>
  60. public void CallMethod(MethodParams meth, ShadowRamControl shadowCtrl)
  61. {
  62. int value = meth.Argument;
  63. // TODO: Figure out what TrackWithFilter does, compared to Track.
  64. if (shadowCtrl == ShadowRamControl.Track ||
  65. shadowCtrl == ShadowRamControl.TrackWithFilter)
  66. {
  67. _shadow[meth.Method] = value;
  68. }
  69. else if (shadowCtrl == ShadowRamControl.Replay)
  70. {
  71. value = _shadow[meth.Method];
  72. }
  73. Register register = _registers[meth.Method];
  74. if (_memory[meth.Method] != value)
  75. {
  76. _registers[(int)register.BaseOffset].Modified = true;
  77. }
  78. _memory[meth.Method] = value;
  79. register.Callback?.Invoke(this, value);
  80. }
  81. /// <summary>
  82. /// Reads data from a GPU register at the given offset.
  83. /// </summary>
  84. /// <param name="offset">Offset to be read</param>
  85. /// <returns>Data at the register</returns>
  86. public int Read(int offset)
  87. {
  88. return _memory[offset];
  89. }
  90. /// <summary>
  91. /// Writes data to the GPU register at the given offset.
  92. /// </summary>
  93. /// <param name="offset">Offset to be written</param>
  94. /// <param name="value">Value to be written</param>
  95. public void Write(int offset, int value)
  96. {
  97. _memory[offset] = value;
  98. }
  99. /// <summary>
  100. /// Writes an offset value at the uniform buffer offset register.
  101. /// </summary>
  102. /// <param name="offset">The offset to be written</param>
  103. public void SetUniformBufferOffset(int offset)
  104. {
  105. _memory[(int)MethodOffset.UniformBufferState + 3] = offset;
  106. }
  107. /// <summary>
  108. /// Initializes registers with the default state.
  109. /// </summary>
  110. private void InitializeDefaultState(int[] memory)
  111. {
  112. // Enable Rasterizer
  113. memory[(int)MethodOffset.RasterizeEnable] = 1;
  114. // Depth ranges.
  115. for (int index = 0; index < Constants.TotalViewports; index++)
  116. {
  117. memory[(int)MethodOffset.ViewportExtents + index * 4 + 2] = 0;
  118. memory[(int)MethodOffset.ViewportExtents + index * 4 + 3] = 0x3F800000;
  119. }
  120. // Viewport transform enable.
  121. memory[(int)MethodOffset.ViewportTransformEnable] = 1;
  122. // Default front stencil mask.
  123. memory[0x4e7] = 0xff;
  124. // Conditional rendering condition.
  125. memory[0x556] = (int)Condition.Always;
  126. // Default color mask.
  127. for (int index = 0; index < Constants.TotalRenderTargets; index++)
  128. {
  129. memory[(int)MethodOffset.RtColorMask + index] = 0x1111;
  130. }
  131. // Default blend states
  132. Set(MethodOffset.BlendStateCommon, BlendStateCommon.Default);
  133. for (int index = 0; index < Constants.TotalRenderTargets; index++)
  134. {
  135. Set(MethodOffset.BlendState, index, BlendState.Default);
  136. }
  137. }
  138. /// <summary>
  139. /// Registers a callback that is called every time a GPU method, or methods are called.
  140. /// </summary>
  141. /// <param name="offset">Offset of the method</param>
  142. /// <param name="count">Word count of the methods region</param>
  143. /// <param name="callback">Calllback to be called</param>
  144. public void RegisterCallback(MethodOffset offset, int count, MethodCallback callback)
  145. {
  146. for (int index = 0; index < count; index++)
  147. {
  148. _registers[(int)offset + index].Callback = callback;
  149. }
  150. }
  151. /// <summary>
  152. /// Registers a callback that is called every time a GPU method is called.
  153. /// </summary>
  154. /// <param name="offset">Offset of the method</param>
  155. /// <param name="callback">Calllback to be called</param>
  156. public void RegisterCallback(MethodOffset offset, MethodCallback callback)
  157. {
  158. _registers[(int)offset].Callback = callback;
  159. }
  160. /// <summary>
  161. /// Checks if a given register has been modified since the last call to this method.
  162. /// </summary>
  163. /// <param name="offset">Register offset</param>
  164. /// <returns>True if modified, false otherwise</returns>
  165. public bool QueryModified(MethodOffset offset)
  166. {
  167. bool modified = _registers[(int)offset].Modified;
  168. _registers[(int)offset].Modified = false;
  169. return modified;
  170. }
  171. /// <summary>
  172. /// Checks if two registers have been modified since the last call to this method.
  173. /// </summary>
  174. /// <param name="m1">First register offset</param>
  175. /// <param name="m2">Second register offset</param>
  176. /// <returns>True if any register was modified, false otherwise</returns>
  177. public bool QueryModified(MethodOffset m1, MethodOffset m2)
  178. {
  179. bool modified = _registers[(int)m1].Modified ||
  180. _registers[(int)m2].Modified;
  181. _registers[(int)m1].Modified = false;
  182. _registers[(int)m2].Modified = false;
  183. return modified;
  184. }
  185. /// <summary>
  186. /// Checks if three registers have been modified since the last call to this method.
  187. /// </summary>
  188. /// <param name="m1">First register offset</param>
  189. /// <param name="m2">Second register offset</param>
  190. /// <param name="m3">Third register offset</param>
  191. /// <returns>True if any register was modified, false otherwise</returns>
  192. public bool QueryModified(MethodOffset m1, MethodOffset m2, MethodOffset m3)
  193. {
  194. bool modified = _registers[(int)m1].Modified ||
  195. _registers[(int)m2].Modified ||
  196. _registers[(int)m3].Modified;
  197. _registers[(int)m1].Modified = false;
  198. _registers[(int)m2].Modified = false;
  199. _registers[(int)m3].Modified = false;
  200. return modified;
  201. }
  202. /// <summary>
  203. /// Checks if four registers have been modified since the last call to this method.
  204. /// </summary>
  205. /// <param name="m1">First register offset</param>
  206. /// <param name="m2">Second register offset</param>
  207. /// <param name="m3">Third register offset</param>
  208. /// <param name="m4">Fourth register offset</param>
  209. /// <returns>True if any register was modified, false otherwise</returns>
  210. public bool QueryModified(MethodOffset m1, MethodOffset m2, MethodOffset m3, MethodOffset m4)
  211. {
  212. bool modified = _registers[(int)m1].Modified ||
  213. _registers[(int)m2].Modified ||
  214. _registers[(int)m3].Modified ||
  215. _registers[(int)m4].Modified;
  216. _registers[(int)m1].Modified = false;
  217. _registers[(int)m2].Modified = false;
  218. _registers[(int)m3].Modified = false;
  219. _registers[(int)m4].Modified = false;
  220. return modified;
  221. }
  222. /// <summary>
  223. /// Checks if five registers have been modified since the last call to this method.
  224. /// </summary>
  225. /// <param name="m1">First register offset</param>
  226. /// <param name="m2">Second register offset</param>
  227. /// <param name="m3">Third register offset</param>
  228. /// <param name="m4">Fourth register offset</param>
  229. /// <param name="m5">Fifth register offset</param>
  230. /// <returns>True if any register was modified, false otherwise</returns>
  231. public bool QueryModified(
  232. MethodOffset m1,
  233. MethodOffset m2,
  234. MethodOffset m3,
  235. MethodOffset m4,
  236. MethodOffset m5)
  237. {
  238. bool modified = _registers[(int)m1].Modified ||
  239. _registers[(int)m2].Modified ||
  240. _registers[(int)m3].Modified ||
  241. _registers[(int)m4].Modified ||
  242. _registers[(int)m5].Modified;
  243. _registers[(int)m1].Modified = false;
  244. _registers[(int)m2].Modified = false;
  245. _registers[(int)m3].Modified = false;
  246. _registers[(int)m4].Modified = false;
  247. _registers[(int)m5].Modified = false;
  248. return modified;
  249. }
  250. /// <summary>
  251. /// Checks if six registers have been modified since the last call to this method.
  252. /// </summary>
  253. /// <param name="m1">First register offset</param>
  254. /// <param name="m2">Second register offset</param>
  255. /// <param name="m3">Third register offset</param>
  256. /// <param name="m4">Fourth register offset</param>
  257. /// <param name="m5">Fifth register offset</param>
  258. /// <param name="m6">Sixth register offset</param>
  259. /// <returns>True if any register was modified, false otherwise</returns>
  260. public bool QueryModified(
  261. MethodOffset m1,
  262. MethodOffset m2,
  263. MethodOffset m3,
  264. MethodOffset m4,
  265. MethodOffset m5,
  266. MethodOffset m6)
  267. {
  268. bool modified = _registers[(int)m1].Modified ||
  269. _registers[(int)m2].Modified ||
  270. _registers[(int)m3].Modified ||
  271. _registers[(int)m4].Modified ||
  272. _registers[(int)m5].Modified ||
  273. _registers[(int)m6].Modified;
  274. _registers[(int)m1].Modified = false;
  275. _registers[(int)m2].Modified = false;
  276. _registers[(int)m3].Modified = false;
  277. _registers[(int)m4].Modified = false;
  278. _registers[(int)m5].Modified = false;
  279. _registers[(int)m6].Modified = false;
  280. return modified;
  281. }
  282. /// <summary>
  283. /// Gets indexed data from a given register offset.
  284. /// </summary>
  285. /// <typeparam name="T">Type of the data</typeparam>
  286. /// <param name="offset">Register offset</param>
  287. /// <param name="index">Index for indexed data</param>
  288. /// <returns>The data at the specified location</returns>
  289. public T Get<T>(MethodOffset offset, int index) where T : struct
  290. {
  291. Register register = _registers[(int)offset];
  292. if ((uint)index >= register.Count)
  293. {
  294. throw new ArgumentOutOfRangeException(nameof(index));
  295. }
  296. return Get<T>(offset + index * register.Stride);
  297. }
  298. /// <summary>
  299. /// Gets data from a given register offset.
  300. /// </summary>
  301. /// <typeparam name="T">Type of the data</typeparam>
  302. /// <param name="offset">Register offset</param>
  303. /// <returns>The data at the specified location</returns>
  304. public T Get<T>(MethodOffset offset) where T : struct
  305. {
  306. return MemoryMarshal.Cast<int, T>(_memory.AsSpan().Slice((int)offset))[0];
  307. }
  308. /// <summary>
  309. /// Sets indexed data to a given register offset.
  310. /// </summary>
  311. /// <typeparam name="T">Type of the data</typeparam>
  312. /// <param name="offset">Register offset</param>
  313. /// <param name="index">Index for indexed data</param>
  314. /// <param name="data">The data to set</param>
  315. public void Set<T>(MethodOffset offset, int index, T data) where T : struct
  316. {
  317. Register register = _registers[(int)offset];
  318. if ((uint)index >= register.Count)
  319. {
  320. throw new ArgumentOutOfRangeException(nameof(index));
  321. }
  322. Set(offset + index * register.Stride, data);
  323. }
  324. /// <summary>
  325. /// Sets data to a given register offset.
  326. /// </summary>
  327. /// <typeparam name="T">Type of the data</typeparam>
  328. /// <param name="offset">Register offset</param>
  329. /// <param name="data">The data to set</param>
  330. public void Set<T>(MethodOffset offset, T data) where T : struct
  331. {
  332. ReadOnlySpan<int> intSpan = MemoryMarshal.Cast<T, int>(MemoryMarshal.CreateReadOnlySpan(ref data, 1));
  333. intSpan.CopyTo(_memory.AsSpan().Slice((int)offset, intSpan.Length));
  334. }
  335. }
  336. }