IbStreamer.cs 4.7 KB

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