From dbeb50684d24bf43c2bdbc087f6b1f52f385acf2 Mon Sep 17 00:00:00 2001 From: gdkchan Date: Fri, 3 Jul 2020 19:41:27 -0300 Subject: Support inline index buffer data (#1351) * Support inline index buffer data * Sort usings --- Ryujinx.Graphics.Gpu/Engine/MethodDraw.cs | 128 +++++++++++++++++++++++++++++- 1 file changed, 125 insertions(+), 3 deletions(-) (limited to 'Ryujinx.Graphics.Gpu/Engine/MethodDraw.cs') diff --git a/Ryujinx.Graphics.Gpu/Engine/MethodDraw.cs b/Ryujinx.Graphics.Gpu/Engine/MethodDraw.cs index d70402e9..5d41dafd 100644 --- a/Ryujinx.Graphics.Gpu/Engine/MethodDraw.cs +++ b/Ryujinx.Graphics.Gpu/Engine/MethodDraw.cs @@ -1,5 +1,9 @@ -using Ryujinx.Graphics.Gpu.State; +using Ryujinx.Common; +using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.Gpu.Image; +using Ryujinx.Graphics.Gpu.State; +using System; +using System.Runtime.InteropServices; namespace Ryujinx.Graphics.Gpu.Engine { @@ -22,6 +26,10 @@ namespace Ryujinx.Graphics.Gpu.Engine private int _instanceIndex; + private BufferHandle _inlineIndexBuffer = BufferHandle.Null; + private int _inlineIndexBufferSize; + private int _inlineIndexCount; + /// /// Primitive type of the current draw. /// @@ -87,10 +95,25 @@ namespace Ryujinx.Graphics.Gpu.Engine int firstInstance = state.Get(MethodOffset.FirstInstance); - if (_drawIndexed) + if (_inlineIndexCount != 0) { - _drawIndexed = false; + int firstVertex = state.Get(MethodOffset.FirstVertex); + + BufferRange br = new BufferRange(_inlineIndexBuffer, 0, _inlineIndexCount * 4); + + _context.Methods.BufferManager.SetIndexBuffer(br, IndexType.UInt); + + _context.Renderer.Pipeline.DrawIndexed( + _inlineIndexCount, + 1, + _firstIndex, + firstVertex, + firstInstance); + _inlineIndexCount = 0; + } + else if (_drawIndexed) + { int firstVertex = state.Get(MethodOffset.FirstVertex); _context.Renderer.Pipeline.DrawIndexed( @@ -111,6 +134,8 @@ namespace Ryujinx.Graphics.Gpu.Engine firstInstance); } + _drawIndexed = false; + if (renderEnable == ConditionalRenderEnabled.Host) { _context.Renderer.Pipeline.EndHostConditionalRendering(); @@ -154,6 +179,103 @@ namespace Ryujinx.Graphics.Gpu.Engine _drawIndexed = true; } + /// + /// Pushes four 8-bit index buffer elements. + /// + /// Current GPU state + /// Method call argument + private void VbElementU8(GpuState state, int argument) + { + byte i0 = (byte)argument; + byte i1 = (byte)(argument >> 8); + byte i2 = (byte)(argument >> 16); + byte i3 = (byte)(argument >> 24); + + Span data = stackalloc uint[4]; + + data[0] = i0; + data[1] = i1; + data[2] = i2; + data[3] = i3; + + int offset = _inlineIndexCount * 4; + + _context.Renderer.SetBufferData(GetInlineIndexBuffer(offset), offset, MemoryMarshal.Cast(data)); + + _inlineIndexCount += 4; + } + + /// + /// Pushes two 16-bit index buffer elements. + /// + /// Current GPU state + /// Method call argument + private void VbElementU16(GpuState state, int argument) + { + ushort i0 = (ushort)argument; + ushort i1 = (ushort)(argument >> 16); + + Span data = stackalloc uint[2]; + + data[0] = i0; + data[1] = i1; + + int offset = _inlineIndexCount * 4; + + _context.Renderer.SetBufferData(GetInlineIndexBuffer(offset), offset, MemoryMarshal.Cast(data)); + + _inlineIndexCount += 2; + } + + /// + /// Pushes one 32-bit index buffer element. + /// + /// Current GPU state + /// Method call argument + private void VbElementU32(GpuState state, int argument) + { + uint i0 = (uint)argument; + + Span data = stackalloc uint[1]; + + data[0] = i0; + + int offset = _inlineIndexCount++ * 4; + + _context.Renderer.SetBufferData(GetInlineIndexBuffer(offset), offset, MemoryMarshal.Cast(data)); + } + + /// + /// Gets the handle of a buffer large enough to hold the data that will be written to . + /// + /// Offset where the data will be written + /// Buffer handle + private BufferHandle GetInlineIndexBuffer(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 = _context.Renderer.CreateBuffer(size); + _inlineIndexBufferSize = size; + } + else if (_inlineIndexBufferSize < size) + { + BufferHandle oldBuffer = _inlineIndexBuffer; + int oldSize = _inlineIndexBufferSize; + + _inlineIndexBuffer = _context.Renderer.CreateBuffer(size); + _inlineIndexBufferSize = size; + + _context.Renderer.Pipeline.CopyBuffer(oldBuffer, _inlineIndexBuffer, 0, 0, oldSize); + _context.Renderer.DeleteBuffer(oldBuffer); + } + + return _inlineIndexBuffer; + } + /// /// Perform any deferred draws. /// This is used for instanced draws. -- cgit v1.2.3