MethodDraw.cs 5.3 KB

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