diff options
Diffstat (limited to 'Ryujinx.Graphics.Gpu/Engine/MethodDraw.cs')
-rw-r--r-- | Ryujinx.Graphics.Gpu/Engine/MethodDraw.cs | 214 |
1 files changed, 122 insertions, 92 deletions
diff --git a/Ryujinx.Graphics.Gpu/Engine/MethodDraw.cs b/Ryujinx.Graphics.Gpu/Engine/MethodDraw.cs index 5d41dafd..88f2e8fe 100644 --- a/Ryujinx.Graphics.Gpu/Engine/MethodDraw.cs +++ b/Ryujinx.Graphics.Gpu/Engine/MethodDraw.cs @@ -1,9 +1,6 @@ -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 { @@ -11,9 +8,6 @@ namespace Ryujinx.Graphics.Gpu.Engine { private bool _drawIndexed; - private int _firstIndex; - private int _indexCount; - private bool _instancedDrawPending; private bool _instancedIndexed; @@ -26,23 +20,35 @@ namespace Ryujinx.Graphics.Gpu.Engine private int _instanceIndex; - private BufferHandle _inlineIndexBuffer = BufferHandle.Null; - private int _inlineIndexBufferSize; - private int _inlineIndexCount; + private IbStreamer _ibStreamer; /// <summary> - /// Primitive type of the current draw. + /// Primitive topology of the current draw. /// </summary> - public PrimitiveType PrimitiveType { get; private set; } + public PrimitiveTopology Topology { get; private set; } /// <summary> - /// Finishes draw call. + /// Finishes the draw call. /// This draws geometry on the bound buffers based on the current GPU state. /// </summary> /// <param name="state">Current GPU state</param> /// <param name="argument">Method call argument</param> private void DrawEnd(GpuState state, int argument) { + var indexBuffer = state.Get<IndexBufferState>(MethodOffset.IndexBufferState); + + DrawEnd(state, indexBuffer.First, indexBuffer.Count); + } + + /// <summary> + /// Finishes the draw call. + /// This draws geometry on the bound buffers based on the current GPU state. + /// </summary> + /// <param name="state">Current GPU state</param> + /// <param name="firstIndex">Index of the first index buffer element used on the draw</param> + /// <param name="indexCount">Number of index buffer elements used on the draw</param> + private void DrawEnd(GpuState state, int firstIndex, int indexCount) + { ConditionalRenderEnabled renderEnable = GetRenderEnable(state); if (renderEnable == ConditionalRenderEnabled.False || _instancedDrawPending) @@ -62,7 +68,7 @@ namespace Ryujinx.Graphics.Gpu.Engine return; } - UpdateState(state); + UpdateState(state, firstIndex, indexCount); bool instanced = _vsUsesInstanceId || _isAnyVbInstanced; @@ -72,11 +78,11 @@ namespace Ryujinx.Graphics.Gpu.Engine _instancedIndexed = _drawIndexed; - _instancedFirstIndex = _firstIndex; - _instancedFirstVertex = state.Get<int>(MethodOffset.FirstVertex); + _instancedFirstIndex = firstIndex; + _instancedFirstVertex = state.Get<int>(MethodOffset.FirstVertex); _instancedFirstInstance = state.Get<int>(MethodOffset.FirstInstance); - _instancedIndexCount = _indexCount; + _instancedIndexCount = indexCount; var drawState = state.Get<VertexBufferDrawState>(MethodOffset.VertexBufferDrawState); @@ -95,31 +101,31 @@ namespace Ryujinx.Graphics.Gpu.Engine int firstInstance = state.Get<int>(MethodOffset.FirstInstance); - if (_inlineIndexCount != 0) + int inlineIndexCount = _ibStreamer.GetAndResetInlineIndexCount(); + + if (inlineIndexCount != 0) { int firstVertex = state.Get<int>(MethodOffset.FirstVertex); - BufferRange br = new BufferRange(_inlineIndexBuffer, 0, _inlineIndexCount * 4); + BufferRange br = new BufferRange(_ibStreamer.GetInlineIndexBuffer(), 0, inlineIndexCount * 4); _context.Methods.BufferManager.SetIndexBuffer(br, IndexType.UInt); _context.Renderer.Pipeline.DrawIndexed( - _inlineIndexCount, + inlineIndexCount, 1, - _firstIndex, + firstIndex, firstVertex, firstInstance); - - _inlineIndexCount = 0; } else if (_drawIndexed) { int firstVertex = state.Get<int>(MethodOffset.FirstVertex); _context.Renderer.Pipeline.DrawIndexed( - _indexCount, + indexCount, 1, - _firstIndex, + firstIndex, firstVertex, firstInstance); } @@ -150,22 +156,46 @@ namespace Ryujinx.Graphics.Gpu.Engine /// <param name="argument">Method call argument</param> private void DrawBegin(GpuState state, int argument) { - if ((argument & (1 << 26)) != 0) + bool incrementInstance = (argument & (1 << 26)) != 0; + bool resetInstance = (argument & (1 << 27)) == 0; + + PrimitiveType type = (PrimitiveType)(argument & 0xffff); + + PrimitiveTypeOverride typeOverride = state.Get<PrimitiveTypeOverride>(MethodOffset.PrimitiveTypeOverride); + + if (typeOverride != PrimitiveTypeOverride.Invalid) + { + DrawBegin(incrementInstance, resetInstance, typeOverride.Convert()); + } + else + { + DrawBegin(incrementInstance, resetInstance, type.Convert()); + } + } + + /// <summary> + /// Starts draw. + /// This sets primitive type and instanced draw parameters. + /// </summary> + /// <param name="incrementInstance">Indicates if the current instance should be incremented</param> + /// <param name="resetInstance">Indicates if the current instance should be set to zero</param> + /// <param name="topology">Primitive topology</param> + private void DrawBegin(bool incrementInstance, bool resetInstance, PrimitiveTopology topology) + { + if (incrementInstance) { _instanceIndex++; } - else if ((argument & (1 << 27)) == 0) + else if (resetInstance) { PerformDeferredDraws(); _instanceIndex = 0; } - PrimitiveType type = (PrimitiveType)(argument & 0xffff); - - _context.Renderer.Pipeline.SetPrimitiveTopology(type.Convert()); + _context.Renderer.Pipeline.SetPrimitiveTopology(topology); - PrimitiveType = type; + Topology = topology; } /// <summary> @@ -180,100 +210,100 @@ namespace Ryujinx.Graphics.Gpu.Engine } /// <summary> - /// Pushes four 8-bit index buffer elements. + /// Performs a indexed draw with a low number of index buffer elements. /// </summary> /// <param name="state">Current GPU state</param> /// <param name="argument">Method call argument</param> - private void VbElementU8(GpuState state, int argument) + private void DrawIndexedSmall(GpuState state, 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; + DrawIndexedSmall(state, argument, false); + } - int offset = _inlineIndexCount * 4; + /// <summary> + /// Performs a indexed draw with a low number of index buffer elements. + /// </summary> + /// <param name="state">Current GPU state</param> + /// <param name="argument">Method call argument</param> + private void DrawIndexedSmall2(GpuState state, int argument) + { + DrawIndexedSmall(state, argument); + } - _context.Renderer.SetBufferData(GetInlineIndexBuffer(offset), offset, MemoryMarshal.Cast<uint, byte>(data)); + /// <summary> + /// Performs a indexed draw with a low number of index buffer elements, + /// while also pre-incrementing the current instance value. + /// </summary> + /// <param name="state">Current GPU state</param> + /// <param name="argument">Method call argument</param> + private void DrawIndexedSmallIncInstance(GpuState state, int argument) + { + DrawIndexedSmall(state, argument, true); + } - _inlineIndexCount += 4; + /// <summary> + /// Performs a indexed draw with a low number of index buffer elements, + /// while also pre-incrementing the current instance value. + /// </summary> + /// <param name="state">Current GPU state</param> + /// <param name="argument">Method call argument</param> + private void DrawIndexedSmallIncInstance2(GpuState state, int argument) + { + DrawIndexedSmallIncInstance(state, argument); } /// <summary> - /// Pushes two 16-bit index buffer elements. + /// Performs a indexed draw with a low number of index buffer elements, + /// while optionally also pre-incrementing the current instance value. /// </summary> /// <param name="state">Current GPU state</param> /// <param name="argument">Method call argument</param> - private void VbElementU16(GpuState state, int argument) + /// <param name="instanced">True to increment the current instance value, false otherwise</param> + private void DrawIndexedSmall(GpuState state, int argument, bool instanced) { - ushort i0 = (ushort)argument; - ushort i1 = (ushort)(argument >> 16); + PrimitiveTypeOverride typeOverride = state.Get<PrimitiveTypeOverride>(MethodOffset.PrimitiveTypeOverride); + + DrawBegin(instanced, !instanced, typeOverride.Convert()); - Span<uint> data = stackalloc uint[2]; + int firstIndex = argument & 0xffff; + int indexCount = (argument >> 16) & 0xfff; - data[0] = i0; - data[1] = i1; + bool oldDrawIndexed = _drawIndexed; - int offset = _inlineIndexCount * 4; + _drawIndexed = true; - _context.Renderer.SetBufferData(GetInlineIndexBuffer(offset), offset, MemoryMarshal.Cast<uint, byte>(data)); + DrawEnd(state, firstIndex, indexCount); - _inlineIndexCount += 2; + _drawIndexed = oldDrawIndexed; } /// <summary> - /// Pushes one 32-bit index buffer element. + /// Pushes four 8-bit index buffer elements. /// </summary> /// <param name="state">Current GPU state</param> /// <param name="argument">Method call argument</param> - private void VbElementU32(GpuState state, int argument) + private void VbElementU8(GpuState state, int argument) { - uint i0 = (uint)argument; - - Span<uint> data = stackalloc uint[1]; - - data[0] = i0; - - int offset = _inlineIndexCount++ * 4; - - _context.Renderer.SetBufferData(GetInlineIndexBuffer(offset), offset, MemoryMarshal.Cast<uint, byte>(data)); + _ibStreamer.VbElementU8(_context.Renderer, argument); } /// <summary> - /// Gets the handle of a buffer large enough to hold the data that will be written to <paramref name="offset"/>. + /// Pushes two 16-bit index buffer elements. /// </summary> - /// <param name="offset">Offset where the data will be written</param> - /// <returns>Buffer handle</returns> - private BufferHandle GetInlineIndexBuffer(int offset) + /// <param name="state">Current GPU state</param> + /// <param name="argument">Method call argument</param> + private void VbElementU16(GpuState state, int argument) { - // 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); - } + _ibStreamer.VbElementU16(_context.Renderer, argument); + } - return _inlineIndexBuffer; + /// <summary> + /// Pushes one 32-bit index buffer element. + /// </summary> + /// <param name="state">Current GPU state</param> + /// <param name="argument">Method call argument</param> + private void VbElementU32(GpuState state, int argument) + { + _ibStreamer.VbElementU32(_context.Renderer, argument); } /// <summary> |