diff options
-rw-r--r-- | Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs | 4 | ||||
-rw-r--r-- | Ryujinx.Graphics.Gpu/Engine/Threed/IbStreamer.cs | 93 |
2 files changed, 72 insertions, 25 deletions
diff --git a/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs b/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs index 61f227d9..7438ba03 100644 --- a/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs +++ b/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs @@ -180,7 +180,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed int firstInstance = (int)_state.State.FirstInstance; - int inlineIndexCount = _drawState.IbStreamer.GetAndResetInlineIndexCount(); + int inlineIndexCount = _drawState.IbStreamer.GetAndResetInlineIndexCount(_context.Renderer); if (inlineIndexCount != 0) { @@ -670,7 +670,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed { if (indexedInline) { - int inlineIndexCount = _drawState.IbStreamer.GetAndResetInlineIndexCount(); + int inlineIndexCount = _drawState.IbStreamer.GetAndResetInlineIndexCount(_context.Renderer); BufferRange br = new BufferRange(_drawState.IbStreamer.GetInlineIndexBuffer(), 0, inlineIndexCount * 4); _channel.BufferManager.SetIndexBuffer(br, IndexType.UInt); diff --git a/Ryujinx.Graphics.Gpu/Engine/Threed/IbStreamer.cs b/Ryujinx.Graphics.Gpu/Engine/Threed/IbStreamer.cs index 4862bca1..80d8c00b 100644 --- a/Ryujinx.Graphics.Gpu/Engine/Threed/IbStreamer.cs +++ b/Ryujinx.Graphics.Gpu/Engine/Threed/IbStreamer.cs @@ -11,9 +11,13 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed /// </summary> struct IbStreamer { + private const int BufferCapacity = 256; // Must be a power of 2. + private BufferHandle _inlineIndexBuffer; private int _inlineIndexBufferSize; private int _inlineIndexCount; + private uint[] _buffer; + private int _bufferOffset; /// <summary> /// Indicates if any index buffer data has been pushed. @@ -38,9 +42,11 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed /// Gets the number of elements on the current inline index buffer, /// while also reseting it to zero for the next draw. /// </summary> + /// <param name="renderer">Host renderer</param> /// <returns>Inline index bufffer count</returns> - public int GetAndResetInlineIndexCount() + public int GetAndResetInlineIndexCount(IRenderer renderer) { + UpdateRemaining(renderer); int temp = _inlineIndexCount; _inlineIndexCount = 0; return temp; @@ -58,16 +64,12 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed 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; + int offset = _inlineIndexCount; - renderer.SetBufferData(GetInlineIndexBuffer(renderer, offset), offset, MemoryMarshal.Cast<uint, byte>(data)); + PushData(renderer, offset, i0); + PushData(renderer, offset + 1, i1); + PushData(renderer, offset + 2, i2); + PushData(renderer, offset + 3, i3); _inlineIndexCount += 4; } @@ -82,14 +84,10 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed ushort i0 = (ushort)argument; ushort i1 = (ushort)(argument >> 16); - Span<uint> data = stackalloc uint[2]; + int offset = _inlineIndexCount; - data[0] = i0; - data[1] = i1; - - int offset = _inlineIndexCount * 4; - - renderer.SetBufferData(GetInlineIndexBuffer(renderer, offset), offset, MemoryMarshal.Cast<uint, byte>(data)); + PushData(renderer, offset, i0); + PushData(renderer, offset + 1, i1); _inlineIndexCount += 2; } @@ -103,13 +101,61 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed { uint i0 = (uint)argument; - Span<uint> data = stackalloc uint[1]; + int offset = _inlineIndexCount++; + + PushData(renderer, offset, i0); + } + + /// <summary> + /// Pushes a 32-bit value to the index buffer. + /// </summary> + /// <param name="renderer">Host renderer</param> + /// <param name="offset">Offset where the data should be written, in 32-bit words</param> + /// <param name="value">Index value to be written</param> + private void PushData(IRenderer renderer, int offset, uint value) + { + if (_buffer == null) + { + _buffer = new uint[BufferCapacity]; + } - data[0] = i0; + // We upload data in chunks. + // If we are at the start of a chunk, then the buffer might be full, + // in that case we need to submit any existing data before overwriting the buffer. + int subOffset = offset & (BufferCapacity - 1); - int offset = _inlineIndexCount++ * 4; + if (subOffset == 0 && offset != 0) + { + int baseOffset = (offset - BufferCapacity) * sizeof(uint); + BufferHandle buffer = GetInlineIndexBuffer(renderer, baseOffset, BufferCapacity * sizeof(uint)); + renderer.SetBufferData(buffer, baseOffset, MemoryMarshal.Cast<uint, byte>(_buffer)); + } + + _buffer[subOffset] = value; + } + + /// <summary> + /// Makes sure that any pending data is submitted to the GPU before the index buffer is used. + /// </summary> + /// <param name="renderer">Host renderer</param> + private void UpdateRemaining(IRenderer renderer) + { + int offset = _inlineIndexCount; + if (offset == 0) + { + return; + } + + int count = offset & (BufferCapacity - 1); + if (count == 0) + { + count = BufferCapacity; + } - renderer.SetBufferData(GetInlineIndexBuffer(renderer, offset), offset, MemoryMarshal.Cast<uint, byte>(data)); + int baseOffset = (offset - count) * sizeof(uint); + int length = count * sizeof(uint); + BufferHandle buffer = GetInlineIndexBuffer(renderer, baseOffset, length); + renderer.SetBufferData(buffer, baseOffset, MemoryMarshal.Cast<uint, byte>(_buffer).Slice(0, length)); } /// <summary> @@ -117,12 +163,13 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed /// </summary> /// <param name="renderer">Host renderer</param> /// <param name="offset">Offset where the data will be written</param> + /// <param name="length">Number of bytes that will be written</param> /// <returns>Buffer handle</returns> - private BufferHandle GetInlineIndexBuffer(IRenderer renderer, int offset) + private BufferHandle GetInlineIndexBuffer(IRenderer renderer, int offset, int length) { // 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); + int size = BitUtils.AlignUp(offset + length + 0x10, 0x200); if (_inlineIndexBuffer == BufferHandle.Null) { |