MethodDraw.cs 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. using Ryujinx.Graphics.Gpu.State;
  2. using Ryujinx.Graphics.Gpu.Image;
  3. namespace Ryujinx.Graphics.Gpu.Engine
  4. {
  5. partial class Methods
  6. {
  7. private bool _drawIndexed;
  8. private int _firstIndex;
  9. private int _indexCount;
  10. private bool _instancedDrawPending;
  11. private bool _instancedIndexed;
  12. private int _instancedFirstIndex;
  13. private int _instancedFirstVertex;
  14. private int _instancedFirstInstance;
  15. private int _instancedIndexCount;
  16. private int _instancedDrawStateFirst;
  17. private int _instancedDrawStateCount;
  18. private int _instanceIndex;
  19. /// <summary>
  20. /// Primitive type of the current draw.
  21. /// </summary>
  22. public PrimitiveType PrimitiveType { get; private set; }
  23. /// <summary>
  24. /// Finishes 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. bool renderEnable = GetRenderEnable(state);
  32. if (!renderEnable || _instancedDrawPending)
  33. {
  34. if (!renderEnable)
  35. {
  36. PerformDeferredDraws();
  37. }
  38. _drawIndexed = false;
  39. return;
  40. }
  41. UpdateState(state);
  42. bool instanced = _vsUsesInstanceId || _isAnyVbInstanced;
  43. if (instanced)
  44. {
  45. _instancedDrawPending = true;
  46. _instancedIndexed = _drawIndexed;
  47. _instancedFirstIndex = _firstIndex;
  48. _instancedFirstVertex = state.Get<int>(MethodOffset.FirstVertex);
  49. _instancedFirstInstance = state.Get<int>(MethodOffset.FirstInstance);
  50. _instancedIndexCount = _indexCount;
  51. var drawState = state.Get<VertexBufferDrawState>(MethodOffset.VertexBufferDrawState);
  52. _instancedDrawStateFirst = drawState.First;
  53. _instancedDrawStateCount = drawState.Count;
  54. _drawIndexed = false;
  55. return;
  56. }
  57. int firstInstance = state.Get<int>(MethodOffset.FirstInstance);
  58. if (_drawIndexed)
  59. {
  60. _drawIndexed = false;
  61. int firstVertex = state.Get<int>(MethodOffset.FirstVertex);
  62. _context.Renderer.Pipeline.DrawIndexed(
  63. _indexCount,
  64. 1,
  65. _firstIndex,
  66. firstVertex,
  67. firstInstance);
  68. }
  69. else
  70. {
  71. var drawState = state.Get<VertexBufferDrawState>(MethodOffset.VertexBufferDrawState);
  72. _context.Renderer.Pipeline.Draw(
  73. drawState.Count,
  74. 1,
  75. drawState.First,
  76. firstInstance);
  77. }
  78. }
  79. /// <summary>
  80. /// Starts draw.
  81. /// This sets primitive type and instanced draw parameters.
  82. /// </summary>
  83. /// <param name="state">Current GPU state</param>
  84. /// <param name="argument">Method call argument</param>
  85. private void DrawBegin(GpuState state, int argument)
  86. {
  87. if ((argument & (1 << 26)) != 0)
  88. {
  89. _instanceIndex++;
  90. }
  91. else if ((argument & (1 << 27)) == 0)
  92. {
  93. PerformDeferredDraws();
  94. _instanceIndex = 0;
  95. }
  96. PrimitiveType type = (PrimitiveType)(argument & 0xffff);
  97. _context.Renderer.Pipeline.SetPrimitiveTopology(type.Convert());
  98. PrimitiveType = type;
  99. }
  100. /// <summary>
  101. /// Sets the index buffer count.
  102. /// This also sets internal state that indicates that the next draw is an indexed draw.
  103. /// </summary>
  104. /// <param name="state">Current GPU state</param>
  105. /// <param name="argument">Method call argument</param>
  106. private void SetIndexBufferCount(GpuState state, int argument)
  107. {
  108. _drawIndexed = true;
  109. }
  110. /// <summary>
  111. /// Perform any deferred draws.
  112. /// This is used for instanced draws.
  113. /// Since each instance is a separate draw, we defer the draw and accumulate the instance count.
  114. /// Once we detect the last instanced draw, then we perform the host instanced draw,
  115. /// with the accumulated instance count.
  116. /// </summary>
  117. public void PerformDeferredDraws()
  118. {
  119. // Perform any pending instanced draw.
  120. if (_instancedDrawPending)
  121. {
  122. _instancedDrawPending = false;
  123. if (_instancedIndexed)
  124. {
  125. _context.Renderer.Pipeline.DrawIndexed(
  126. _instancedIndexCount,
  127. _instanceIndex + 1,
  128. _instancedFirstIndex,
  129. _instancedFirstVertex,
  130. _instancedFirstInstance);
  131. }
  132. else
  133. {
  134. _context.Renderer.Pipeline.Draw(
  135. _instancedDrawStateCount,
  136. _instanceIndex + 1,
  137. _instancedDrawStateFirst,
  138. _instancedFirstInstance);
  139. }
  140. }
  141. }
  142. }
  143. }