IbStreamer.cs 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. using Ryujinx.Common;
  2. using Ryujinx.Graphics.GAL;
  3. using System;
  4. using System.Runtime.InteropServices;
  5. namespace Ryujinx.Graphics.Gpu.Engine.Threed
  6. {
  7. /// <summary>
  8. /// Holds inline index buffer state.
  9. /// The inline index buffer data is sent to the GPU through the command buffer.
  10. /// </summary>
  11. struct IbStreamer
  12. {
  13. private BufferHandle _inlineIndexBuffer;
  14. private int _inlineIndexBufferSize;
  15. private int _inlineIndexCount;
  16. /// <summary>
  17. /// Indicates if any index buffer data has been pushed.
  18. /// </summary>
  19. public bool HasInlineIndexData => _inlineIndexCount != 0;
  20. /// <summary>
  21. /// Gets the handle for the host buffer currently holding the inline index buffer data.
  22. /// </summary>
  23. /// <returns>Host buffer handle</returns>
  24. public BufferHandle GetInlineIndexBuffer()
  25. {
  26. return _inlineIndexBuffer;
  27. }
  28. /// <summary>
  29. /// Gets the number of elements on the current inline index buffer,
  30. /// while also reseting it to zero for the next draw.
  31. /// </summary>
  32. /// <returns>Inline index bufffer count</returns>
  33. public int GetAndResetInlineIndexCount()
  34. {
  35. int temp = _inlineIndexCount;
  36. _inlineIndexCount = 0;
  37. return temp;
  38. }
  39. /// <summary>
  40. /// Pushes four 8-bit index buffer elements.
  41. /// </summary>
  42. /// <param name="renderer">Host renderer</param>
  43. /// <param name="argument">Method call argument</param>
  44. public void VbElementU8(IRenderer renderer, int argument)
  45. {
  46. byte i0 = (byte)argument;
  47. byte i1 = (byte)(argument >> 8);
  48. byte i2 = (byte)(argument >> 16);
  49. byte i3 = (byte)(argument >> 24);
  50. Span<uint> data = stackalloc uint[4];
  51. data[0] = i0;
  52. data[1] = i1;
  53. data[2] = i2;
  54. data[3] = i3;
  55. int offset = _inlineIndexCount * 4;
  56. renderer.SetBufferData(GetInlineIndexBuffer(renderer, offset), offset, MemoryMarshal.Cast<uint, byte>(data));
  57. _inlineIndexCount += 4;
  58. }
  59. /// <summary>
  60. /// Pushes two 16-bit index buffer elements.
  61. /// </summary>
  62. /// <param name="renderer">Host renderer</param>
  63. /// <param name="argument">Method call argument</param>
  64. public void VbElementU16(IRenderer renderer, int argument)
  65. {
  66. ushort i0 = (ushort)argument;
  67. ushort i1 = (ushort)(argument >> 16);
  68. Span<uint> data = stackalloc uint[2];
  69. data[0] = i0;
  70. data[1] = i1;
  71. int offset = _inlineIndexCount * 4;
  72. renderer.SetBufferData(GetInlineIndexBuffer(renderer, offset), offset, MemoryMarshal.Cast<uint, byte>(data));
  73. _inlineIndexCount += 2;
  74. }
  75. /// <summary>
  76. /// Pushes one 32-bit index buffer element.
  77. /// </summary>
  78. /// <param name="renderer">Host renderer</param>
  79. /// <param name="argument">Method call argument</param>
  80. public void VbElementU32(IRenderer renderer, int argument)
  81. {
  82. uint i0 = (uint)argument;
  83. Span<uint> data = stackalloc uint[1];
  84. data[0] = i0;
  85. int offset = _inlineIndexCount++ * 4;
  86. renderer.SetBufferData(GetInlineIndexBuffer(renderer, offset), offset, MemoryMarshal.Cast<uint, byte>(data));
  87. }
  88. /// <summary>
  89. /// Gets the handle of a buffer large enough to hold the data that will be written to <paramref name="offset"/>.
  90. /// </summary>
  91. /// <param name="renderer">Host renderer</param>
  92. /// <param name="offset">Offset where the data will be written</param>
  93. /// <returns>Buffer handle</returns>
  94. private BufferHandle GetInlineIndexBuffer(IRenderer renderer, int offset)
  95. {
  96. // Calculate a reasonable size for the buffer that can fit all the data,
  97. // and that also won't require frequent resizes if we need to push more data.
  98. int size = BitUtils.AlignUp(offset + 0x10, 0x200);
  99. if (_inlineIndexBuffer == BufferHandle.Null)
  100. {
  101. _inlineIndexBuffer = renderer.CreateBuffer(size);
  102. _inlineIndexBufferSize = size;
  103. }
  104. else if (_inlineIndexBufferSize < size)
  105. {
  106. BufferHandle oldBuffer = _inlineIndexBuffer;
  107. int oldSize = _inlineIndexBufferSize;
  108. _inlineIndexBuffer = renderer.CreateBuffer(size);
  109. _inlineIndexBufferSize = size;
  110. renderer.Pipeline.CopyBuffer(oldBuffer, _inlineIndexBuffer, 0, 0, oldSize);
  111. renderer.DeleteBuffer(oldBuffer);
  112. }
  113. return _inlineIndexBuffer;
  114. }
  115. }
  116. }