MethodDraw.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. using Ryujinx.Graphics.GAL;
  2. using Ryujinx.Graphics.Gpu.Image;
  3. using Ryujinx.Graphics.Gpu.State;
  4. namespace Ryujinx.Graphics.Gpu.Engine
  5. {
  6. partial class Methods
  7. {
  8. private bool _drawIndexed;
  9. private bool _instancedDrawPending;
  10. private bool _instancedIndexed;
  11. private int _instancedFirstIndex;
  12. private int _instancedFirstVertex;
  13. private int _instancedFirstInstance;
  14. private int _instancedIndexCount;
  15. private int _instancedDrawStateFirst;
  16. private int _instancedDrawStateCount;
  17. private int _instanceIndex;
  18. private IbStreamer _ibStreamer;
  19. /// <summary>
  20. /// Primitive topology of the current draw.
  21. /// </summary>
  22. public PrimitiveTopology Topology { get; private set; }
  23. /// <summary>
  24. /// Finishes the draw call.
  25. /// This draws geometry on the bound buffers based on the current GPU state.
  26. /// </summary>
  27. /// <param name="state">Current GPU state</param>
  28. /// <param name="argument">Method call argument</param>
  29. private void DrawEnd(GpuState state, int argument)
  30. {
  31. var indexBuffer = state.Get<IndexBufferState>(MethodOffset.IndexBufferState);
  32. DrawEnd(state, indexBuffer.First, indexBuffer.Count);
  33. }
  34. /// <summary>
  35. /// Finishes the draw call.
  36. /// This draws geometry on the bound buffers based on the current GPU state.
  37. /// </summary>
  38. /// <param name="state">Current GPU state</param>
  39. /// <param name="firstIndex">Index of the first index buffer element used on the draw</param>
  40. /// <param name="indexCount">Number of index buffer elements used on the draw</param>
  41. private void DrawEnd(GpuState state, int firstIndex, int indexCount)
  42. {
  43. ConditionalRenderEnabled renderEnable = GetRenderEnable(state);
  44. if (renderEnable == ConditionalRenderEnabled.False || _instancedDrawPending)
  45. {
  46. if (renderEnable == ConditionalRenderEnabled.False)
  47. {
  48. PerformDeferredDraws();
  49. }
  50. _drawIndexed = false;
  51. if (renderEnable == ConditionalRenderEnabled.Host)
  52. {
  53. _context.Renderer.Pipeline.EndHostConditionalRendering();
  54. }
  55. return;
  56. }
  57. UpdateState(state, firstIndex, indexCount);
  58. bool instanced = _vsUsesInstanceId || _isAnyVbInstanced;
  59. if (instanced)
  60. {
  61. _instancedDrawPending = true;
  62. _instancedIndexed = _drawIndexed;
  63. _instancedFirstIndex = firstIndex;
  64. _instancedFirstVertex = state.Get<int>(MethodOffset.FirstVertex);
  65. _instancedFirstInstance = state.Get<int>(MethodOffset.FirstInstance);
  66. _instancedIndexCount = indexCount;
  67. var drawState = state.Get<VertexBufferDrawState>(MethodOffset.VertexBufferDrawState);
  68. _instancedDrawStateFirst = drawState.First;
  69. _instancedDrawStateCount = drawState.Count;
  70. _drawIndexed = false;
  71. if (renderEnable == ConditionalRenderEnabled.Host)
  72. {
  73. _context.Renderer.Pipeline.EndHostConditionalRendering();
  74. }
  75. return;
  76. }
  77. int firstInstance = state.Get<int>(MethodOffset.FirstInstance);
  78. int inlineIndexCount = _ibStreamer.GetAndResetInlineIndexCount();
  79. if (inlineIndexCount != 0)
  80. {
  81. int firstVertex = state.Get<int>(MethodOffset.FirstVertex);
  82. BufferRange br = new BufferRange(_ibStreamer.GetInlineIndexBuffer(), 0, inlineIndexCount * 4);
  83. state.Channel.BufferManager.SetIndexBuffer(br, IndexType.UInt);
  84. _context.Renderer.Pipeline.DrawIndexed(
  85. inlineIndexCount,
  86. 1,
  87. firstIndex,
  88. firstVertex,
  89. firstInstance);
  90. }
  91. else if (_drawIndexed)
  92. {
  93. int firstVertex = state.Get<int>(MethodOffset.FirstVertex);
  94. _context.Renderer.Pipeline.DrawIndexed(
  95. indexCount,
  96. 1,
  97. firstIndex,
  98. firstVertex,
  99. firstInstance);
  100. }
  101. else
  102. {
  103. var drawState = state.Get<VertexBufferDrawState>(MethodOffset.VertexBufferDrawState);
  104. _context.Renderer.Pipeline.Draw(
  105. drawState.Count,
  106. 1,
  107. drawState.First,
  108. firstInstance);
  109. }
  110. _drawIndexed = false;
  111. if (renderEnable == ConditionalRenderEnabled.Host)
  112. {
  113. _context.Renderer.Pipeline.EndHostConditionalRendering();
  114. }
  115. }
  116. /// <summary>
  117. /// Starts draw.
  118. /// This sets primitive type and instanced draw parameters.
  119. /// </summary>
  120. /// <param name="state">Current GPU state</param>
  121. /// <param name="argument">Method call argument</param>
  122. private void DrawBegin(GpuState state, int argument)
  123. {
  124. bool incrementInstance = (argument & (1 << 26)) != 0;
  125. bool resetInstance = (argument & (1 << 27)) == 0;
  126. PrimitiveType type = (PrimitiveType)(argument & 0xffff);
  127. PrimitiveTypeOverride typeOverride = state.Get<PrimitiveTypeOverride>(MethodOffset.PrimitiveTypeOverride);
  128. if (typeOverride != PrimitiveTypeOverride.Invalid)
  129. {
  130. DrawBegin(incrementInstance, resetInstance, typeOverride.Convert());
  131. }
  132. else
  133. {
  134. DrawBegin(incrementInstance, resetInstance, type.Convert());
  135. }
  136. }
  137. /// <summary>
  138. /// Starts draw.
  139. /// This sets primitive type and instanced draw parameters.
  140. /// </summary>
  141. /// <param name="incrementInstance">Indicates if the current instance should be incremented</param>
  142. /// <param name="resetInstance">Indicates if the current instance should be set to zero</param>
  143. /// <param name="topology">Primitive topology</param>
  144. private void DrawBegin(bool incrementInstance, bool resetInstance, PrimitiveTopology topology)
  145. {
  146. if (incrementInstance)
  147. {
  148. _instanceIndex++;
  149. }
  150. else if (resetInstance)
  151. {
  152. PerformDeferredDraws();
  153. _instanceIndex = 0;
  154. }
  155. _context.Renderer.Pipeline.SetPrimitiveTopology(topology);
  156. Topology = topology;
  157. }
  158. /// <summary>
  159. /// Sets the index buffer count.
  160. /// This also sets internal state that indicates that the next draw is an indexed draw.
  161. /// </summary>
  162. /// <param name="state">Current GPU state</param>
  163. /// <param name="argument">Method call argument</param>
  164. private void SetIndexBufferCount(GpuState state, int argument)
  165. {
  166. _drawIndexed = true;
  167. }
  168. /// <summary>
  169. /// Performs a indexed draw with a low number of index buffer elements.
  170. /// </summary>
  171. /// <param name="state">Current GPU state</param>
  172. /// <param name="argument">Method call argument</param>
  173. private void DrawIndexedSmall(GpuState state, int argument)
  174. {
  175. DrawIndexedSmall(state, argument, false);
  176. }
  177. /// <summary>
  178. /// Performs a indexed draw with a low number of index buffer elements.
  179. /// </summary>
  180. /// <param name="state">Current GPU state</param>
  181. /// <param name="argument">Method call argument</param>
  182. private void DrawIndexedSmall2(GpuState state, int argument)
  183. {
  184. DrawIndexedSmall(state, argument);
  185. }
  186. /// <summary>
  187. /// Performs a indexed draw with a low number of index buffer elements,
  188. /// while also pre-incrementing the current instance value.
  189. /// </summary>
  190. /// <param name="state">Current GPU state</param>
  191. /// <param name="argument">Method call argument</param>
  192. private void DrawIndexedSmallIncInstance(GpuState state, int argument)
  193. {
  194. DrawIndexedSmall(state, argument, true);
  195. }
  196. /// <summary>
  197. /// Performs a indexed draw with a low number of index buffer elements,
  198. /// while also pre-incrementing the current instance value.
  199. /// </summary>
  200. /// <param name="state">Current GPU state</param>
  201. /// <param name="argument">Method call argument</param>
  202. private void DrawIndexedSmallIncInstance2(GpuState state, int argument)
  203. {
  204. DrawIndexedSmallIncInstance(state, argument);
  205. }
  206. /// <summary>
  207. /// Performs a indexed draw with a low number of index buffer elements,
  208. /// while optionally also pre-incrementing the current instance value.
  209. /// </summary>
  210. /// <param name="state">Current GPU state</param>
  211. /// <param name="argument">Method call argument</param>
  212. /// <param name="instanced">True to increment the current instance value, false otherwise</param>
  213. private void DrawIndexedSmall(GpuState state, int argument, bool instanced)
  214. {
  215. PrimitiveTypeOverride typeOverride = state.Get<PrimitiveTypeOverride>(MethodOffset.PrimitiveTypeOverride);
  216. DrawBegin(instanced, !instanced, typeOverride.Convert());
  217. int firstIndex = argument & 0xffff;
  218. int indexCount = (argument >> 16) & 0xfff;
  219. bool oldDrawIndexed = _drawIndexed;
  220. _drawIndexed = true;
  221. DrawEnd(state, firstIndex, indexCount);
  222. _drawIndexed = oldDrawIndexed;
  223. }
  224. /// <summary>
  225. /// Pushes four 8-bit index buffer elements.
  226. /// </summary>
  227. /// <param name="state">Current GPU state</param>
  228. /// <param name="argument">Method call argument</param>
  229. private void VbElementU8(GpuState state, int argument)
  230. {
  231. _ibStreamer.VbElementU8(_context.Renderer, argument);
  232. }
  233. /// <summary>
  234. /// Pushes two 16-bit index buffer elements.
  235. /// </summary>
  236. /// <param name="state">Current GPU state</param>
  237. /// <param name="argument">Method call argument</param>
  238. private void VbElementU16(GpuState state, int argument)
  239. {
  240. _ibStreamer.VbElementU16(_context.Renderer, argument);
  241. }
  242. /// <summary>
  243. /// Pushes one 32-bit index buffer element.
  244. /// </summary>
  245. /// <param name="state">Current GPU state</param>
  246. /// <param name="argument">Method call argument</param>
  247. private void VbElementU32(GpuState state, int argument)
  248. {
  249. _ibStreamer.VbElementU32(_context.Renderer, argument);
  250. }
  251. /// <summary>
  252. /// Perform any deferred draws.
  253. /// This is used for instanced draws.
  254. /// Since each instance is a separate draw, we defer the draw and accumulate the instance count.
  255. /// Once we detect the last instanced draw, then we perform the host instanced draw,
  256. /// with the accumulated instance count.
  257. /// </summary>
  258. public void PerformDeferredDraws()
  259. {
  260. // Perform any pending instanced draw.
  261. if (_instancedDrawPending)
  262. {
  263. _instancedDrawPending = false;
  264. if (_instancedIndexed)
  265. {
  266. _context.Renderer.Pipeline.DrawIndexed(
  267. _instancedIndexCount,
  268. _instanceIndex + 1,
  269. _instancedFirstIndex,
  270. _instancedFirstVertex,
  271. _instancedFirstInstance);
  272. }
  273. else
  274. {
  275. _context.Renderer.Pipeline.Draw(
  276. _instancedDrawStateCount,
  277. _instanceIndex + 1,
  278. _instancedDrawStateFirst,
  279. _instancedFirstInstance);
  280. }
  281. }
  282. }
  283. }
  284. }