diff options
| author | gdkchan <gab.dark.100@gmail.com> | 2020-09-23 20:48:34 -0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-09-24 09:48:34 +1000 |
| commit | bd28ce90e6df04b5b15a5c1149523f3742af38cc (patch) | |
| tree | 4d30eaf20b8549e292896e3a7f9fc2aecacfbc2c /Ryujinx.Graphics.Gpu/Engine/IbStreamer.cs | |
| parent | e00ca92063b9dda7b3272f6461610743cfa83ad5 (diff) | |
Implement small indexed draws and other fixes to make guest Vulkan work (#1558)
Diffstat (limited to 'Ryujinx.Graphics.Gpu/Engine/IbStreamer.cs')
| -rw-r--r-- | Ryujinx.Graphics.Gpu/Engine/IbStreamer.cs | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/Ryujinx.Graphics.Gpu/Engine/IbStreamer.cs b/Ryujinx.Graphics.Gpu/Engine/IbStreamer.cs new file mode 100644 index 00000000..b407c941 --- /dev/null +++ b/Ryujinx.Graphics.Gpu/Engine/IbStreamer.cs @@ -0,0 +1,139 @@ +using Ryujinx.Common; +using Ryujinx.Graphics.GAL; +using System; +using System.Runtime.InteropServices; + +namespace Ryujinx.Graphics.Gpu.Engine +{ + /// <summary> + /// Holds inline index buffer state. + /// The inline index buffer data is sent to the GPU through the command buffer. + /// </summary> + struct IbStreamer + { + private BufferHandle _inlineIndexBuffer; + private int _inlineIndexBufferSize; + private int _inlineIndexCount; + + public bool HasInlineIndexData => _inlineIndexCount != 0; + + /// <summary> + /// Gets the handle for the host buffer currently holding the inline index buffer data. + /// </summary> + /// <returns>Host buffer handle</returns> + public BufferHandle GetInlineIndexBuffer() + { + return _inlineIndexBuffer; + } + + /// <summary> + /// Gets the number of elements on the current inline index buffer, + /// while also reseting it to zero for the next draw. + /// </summary> + /// <returns>Inline index bufffer count</returns> + public int GetAndResetInlineIndexCount() + { + int temp = _inlineIndexCount; + _inlineIndexCount = 0; + return temp; + } + + /// <summary> + /// Pushes four 8-bit index buffer elements. + /// </summary> + /// <param name="renderer">Host renderer</param> + /// <param name="argument">Method call argument</param> + public void VbElementU8(IRenderer renderer, int argument) + { + byte i0 = (byte)argument; + byte i1 = (byte)(argument >> 8); + byte i2 = (byte)(argument >> 16); + byte i3 = (byte)(argument >> 24); + + Span<uint> data = stackalloc uint[4]; + + data[0] = i0; + data[1] = i1; + data[2] = i2; + data[3] = i3; + + int offset = _inlineIndexCount * 4; + + renderer.SetBufferData(GetInlineIndexBuffer(renderer, offset), offset, MemoryMarshal.Cast<uint, byte>(data)); + + _inlineIndexCount += 4; + } + + /// <summary> + /// Pushes two 16-bit index buffer elements. + /// </summary> + /// <param name="renderer">Host renderer</param> + /// <param name="argument">Method call argument</param> + public void VbElementU16(IRenderer renderer, int argument) + { + ushort i0 = (ushort)argument; + ushort i1 = (ushort)(argument >> 16); + + Span<uint> data = stackalloc uint[2]; + + data[0] = i0; + data[1] = i1; + + int offset = _inlineIndexCount * 4; + + renderer.SetBufferData(GetInlineIndexBuffer(renderer, offset), offset, MemoryMarshal.Cast<uint, byte>(data)); + + _inlineIndexCount += 2; + } + + /// <summary> + /// Pushes one 32-bit index buffer element. + /// </summary> + /// <param name="renderer">Host renderer</param> + /// <param name="argument">Method call argument</param> + public void VbElementU32(IRenderer renderer, int argument) + { + uint i0 = (uint)argument; + + Span<uint> data = stackalloc uint[1]; + + data[0] = i0; + + int offset = _inlineIndexCount++ * 4; + + renderer.SetBufferData(GetInlineIndexBuffer(renderer, offset), offset, MemoryMarshal.Cast<uint, byte>(data)); + } + + /// <summary> + /// Gets the handle of a buffer large enough to hold the data that will be written to <paramref name="offset"/>. + /// </summary> + /// <param name="renderer">Host renderer</param> + /// <param name="offset">Offset where the data will be written</param> + /// <returns>Buffer handle</returns> + private BufferHandle GetInlineIndexBuffer(IRenderer renderer, int offset) + { + // Calculate a reasonable size for the buffer that can fit all the data, + // and that also won't require frequent resizes if we need to push more data. + int size = BitUtils.AlignUp(offset + 0x10, 0x200); + + if (_inlineIndexBuffer == BufferHandle.Null) + { + _inlineIndexBuffer = renderer.CreateBuffer(size); + _inlineIndexBufferSize = size; + } + else if (_inlineIndexBufferSize < size) + { + BufferHandle oldBuffer = _inlineIndexBuffer; + int oldSize = _inlineIndexBufferSize; + + _inlineIndexBuffer = renderer.CreateBuffer(size); + _inlineIndexBufferSize = size; + + renderer.Pipeline.CopyBuffer(oldBuffer, _inlineIndexBuffer, 0, 0, oldSize); + renderer.DeleteBuffer(oldBuffer); + } + + return _inlineIndexBuffer; + } + } +} |
