MethodDraw.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. using Ryujinx.Common;
  2. using Ryujinx.Graphics.GAL;
  3. using Ryujinx.Graphics.Gpu.Image;
  4. using Ryujinx.Graphics.Gpu.State;
  5. using System;
  6. using System.Runtime.InteropServices;
  7. namespace Ryujinx.Graphics.Gpu.Engine
  8. {
  9. partial class Methods
  10. {
  11. private bool _drawIndexed;
  12. private int _firstIndex;
  13. private int _indexCount;
  14. private bool _instancedDrawPending;
  15. private bool _instancedIndexed;
  16. private int _instancedFirstIndex;
  17. private int _instancedFirstVertex;
  18. private int _instancedFirstInstance;
  19. private int _instancedIndexCount;
  20. private int _instancedDrawStateFirst;
  21. private int _instancedDrawStateCount;
  22. private int _instanceIndex;
  23. private BufferHandle _inlineIndexBuffer = BufferHandle.Null;
  24. private int _inlineIndexBufferSize;
  25. private int _inlineIndexCount;
  26. /// <summary>
  27. /// Primitive type of the current draw.
  28. /// </summary>
  29. public PrimitiveType PrimitiveType { get; private set; }
  30. /// <summary>
  31. /// Finishes draw call.
  32. /// This draws geometry on the bound buffers based on the current GPU state.
  33. /// </summary>
  34. /// <param name="state">Current GPU state</param>
  35. /// <param name="argument">Method call argument</param>
  36. private void DrawEnd(GpuState state, int argument)
  37. {
  38. ConditionalRenderEnabled renderEnable = GetRenderEnable(state);
  39. if (renderEnable == ConditionalRenderEnabled.False || _instancedDrawPending)
  40. {
  41. if (renderEnable == ConditionalRenderEnabled.False)
  42. {
  43. PerformDeferredDraws();
  44. }
  45. _drawIndexed = false;
  46. if (renderEnable == ConditionalRenderEnabled.Host)
  47. {
  48. _context.Renderer.Pipeline.EndHostConditionalRendering();
  49. }
  50. return;
  51. }
  52. UpdateState(state);
  53. bool instanced = _vsUsesInstanceId || _isAnyVbInstanced;
  54. if (instanced)
  55. {
  56. _instancedDrawPending = true;
  57. _instancedIndexed = _drawIndexed;
  58. _instancedFirstIndex = _firstIndex;
  59. _instancedFirstVertex = state.Get<int>(MethodOffset.FirstVertex);
  60. _instancedFirstInstance = state.Get<int>(MethodOffset.FirstInstance);
  61. _instancedIndexCount = _indexCount;
  62. var drawState = state.Get<VertexBufferDrawState>(MethodOffset.VertexBufferDrawState);
  63. _instancedDrawStateFirst = drawState.First;
  64. _instancedDrawStateCount = drawState.Count;
  65. _drawIndexed = false;
  66. if (renderEnable == ConditionalRenderEnabled.Host)
  67. {
  68. _context.Renderer.Pipeline.EndHostConditionalRendering();
  69. }
  70. return;
  71. }
  72. int firstInstance = state.Get<int>(MethodOffset.FirstInstance);
  73. if (_inlineIndexCount != 0)
  74. {
  75. int firstVertex = state.Get<int>(MethodOffset.FirstVertex);
  76. BufferRange br = new BufferRange(_inlineIndexBuffer, 0, _inlineIndexCount * 4);
  77. _context.Methods.BufferManager.SetIndexBuffer(br, IndexType.UInt);
  78. _context.Renderer.Pipeline.DrawIndexed(
  79. _inlineIndexCount,
  80. 1,
  81. _firstIndex,
  82. firstVertex,
  83. firstInstance);
  84. _inlineIndexCount = 0;
  85. }
  86. else if (_drawIndexed)
  87. {
  88. int firstVertex = state.Get<int>(MethodOffset.FirstVertex);
  89. _context.Renderer.Pipeline.DrawIndexed(
  90. _indexCount,
  91. 1,
  92. _firstIndex,
  93. firstVertex,
  94. firstInstance);
  95. }
  96. else
  97. {
  98. var drawState = state.Get<VertexBufferDrawState>(MethodOffset.VertexBufferDrawState);
  99. _context.Renderer.Pipeline.Draw(
  100. drawState.Count,
  101. 1,
  102. drawState.First,
  103. firstInstance);
  104. }
  105. _drawIndexed = false;
  106. if (renderEnable == ConditionalRenderEnabled.Host)
  107. {
  108. _context.Renderer.Pipeline.EndHostConditionalRendering();
  109. }
  110. }
  111. /// <summary>
  112. /// Starts draw.
  113. /// This sets primitive type and instanced draw parameters.
  114. /// </summary>
  115. /// <param name="state">Current GPU state</param>
  116. /// <param name="argument">Method call argument</param>
  117. private void DrawBegin(GpuState state, int argument)
  118. {
  119. if ((argument & (1 << 26)) != 0)
  120. {
  121. _instanceIndex++;
  122. }
  123. else if ((argument & (1 << 27)) == 0)
  124. {
  125. PerformDeferredDraws();
  126. _instanceIndex = 0;
  127. }
  128. PrimitiveType type = (PrimitiveType)(argument & 0xffff);
  129. _context.Renderer.Pipeline.SetPrimitiveTopology(type.Convert());
  130. PrimitiveType = type;
  131. }
  132. /// <summary>
  133. /// Sets the index buffer count.
  134. /// This also sets internal state that indicates that the next draw is an indexed draw.
  135. /// </summary>
  136. /// <param name="state">Current GPU state</param>
  137. /// <param name="argument">Method call argument</param>
  138. private void SetIndexBufferCount(GpuState state, int argument)
  139. {
  140. _drawIndexed = true;
  141. }
  142. /// <summary>
  143. /// Pushes four 8-bit index buffer elements.
  144. /// </summary>
  145. /// <param name="state">Current GPU state</param>
  146. /// <param name="argument">Method call argument</param>
  147. private void VbElementU8(GpuState state, int argument)
  148. {
  149. byte i0 = (byte)argument;
  150. byte i1 = (byte)(argument >> 8);
  151. byte i2 = (byte)(argument >> 16);
  152. byte i3 = (byte)(argument >> 24);
  153. Span<uint> data = stackalloc uint[4];
  154. data[0] = i0;
  155. data[1] = i1;
  156. data[2] = i2;
  157. data[3] = i3;
  158. int offset = _inlineIndexCount * 4;
  159. _context.Renderer.SetBufferData(GetInlineIndexBuffer(offset), offset, MemoryMarshal.Cast<uint, byte>(data));
  160. _inlineIndexCount += 4;
  161. }
  162. /// <summary>
  163. /// Pushes two 16-bit index buffer elements.
  164. /// </summary>
  165. /// <param name="state">Current GPU state</param>
  166. /// <param name="argument">Method call argument</param>
  167. private void VbElementU16(GpuState state, int argument)
  168. {
  169. ushort i0 = (ushort)argument;
  170. ushort i1 = (ushort)(argument >> 16);
  171. Span<uint> data = stackalloc uint[2];
  172. data[0] = i0;
  173. data[1] = i1;
  174. int offset = _inlineIndexCount * 4;
  175. _context.Renderer.SetBufferData(GetInlineIndexBuffer(offset), offset, MemoryMarshal.Cast<uint, byte>(data));
  176. _inlineIndexCount += 2;
  177. }
  178. /// <summary>
  179. /// Pushes one 32-bit index buffer element.
  180. /// </summary>
  181. /// <param name="state">Current GPU state</param>
  182. /// <param name="argument">Method call argument</param>
  183. private void VbElementU32(GpuState state, int argument)
  184. {
  185. uint i0 = (uint)argument;
  186. Span<uint> data = stackalloc uint[1];
  187. data[0] = i0;
  188. int offset = _inlineIndexCount++ * 4;
  189. _context.Renderer.SetBufferData(GetInlineIndexBuffer(offset), offset, MemoryMarshal.Cast<uint, byte>(data));
  190. }
  191. /// <summary>
  192. /// Gets the handle of a buffer large enough to hold the data that will be written to <paramref name="offset"/>.
  193. /// </summary>
  194. /// <param name="offset">Offset where the data will be written</param>
  195. /// <returns>Buffer handle</returns>
  196. private BufferHandle GetInlineIndexBuffer(int offset)
  197. {
  198. // Calculate a reasonable size for the buffer that can fit all the data,
  199. // and that also won't require frequent resizes if we need to push more data.
  200. int size = BitUtils.AlignUp(offset + 0x10, 0x200);
  201. if (_inlineIndexBuffer == BufferHandle.Null)
  202. {
  203. _inlineIndexBuffer = _context.Renderer.CreateBuffer(size);
  204. _inlineIndexBufferSize = size;
  205. }
  206. else if (_inlineIndexBufferSize < size)
  207. {
  208. BufferHandle oldBuffer = _inlineIndexBuffer;
  209. int oldSize = _inlineIndexBufferSize;
  210. _inlineIndexBuffer = _context.Renderer.CreateBuffer(size);
  211. _inlineIndexBufferSize = size;
  212. _context.Renderer.Pipeline.CopyBuffer(oldBuffer, _inlineIndexBuffer, 0, 0, oldSize);
  213. _context.Renderer.DeleteBuffer(oldBuffer);
  214. }
  215. return _inlineIndexBuffer;
  216. }
  217. /// <summary>
  218. /// Perform any deferred draws.
  219. /// This is used for instanced draws.
  220. /// Since each instance is a separate draw, we defer the draw and accumulate the instance count.
  221. /// Once we detect the last instanced draw, then we perform the host instanced draw,
  222. /// with the accumulated instance count.
  223. /// </summary>
  224. public void PerformDeferredDraws()
  225. {
  226. // Perform any pending instanced draw.
  227. if (_instancedDrawPending)
  228. {
  229. _instancedDrawPending = false;
  230. if (_instancedIndexed)
  231. {
  232. _context.Renderer.Pipeline.DrawIndexed(
  233. _instancedIndexCount,
  234. _instanceIndex + 1,
  235. _instancedFirstIndex,
  236. _instancedFirstVertex,
  237. _instancedFirstInstance);
  238. }
  239. else
  240. {
  241. _context.Renderer.Pipeline.Draw(
  242. _instancedDrawStateCount,
  243. _instanceIndex + 1,
  244. _instancedDrawStateFirst,
  245. _instancedFirstInstance);
  246. }
  247. }
  248. }
  249. }
  250. }