diff --git a/Ryujinx.Graphics.Gpu/Engine/ConditionalRenderEnabled.cs b/Ryujinx.Graphics.Gpu/Engine/ConditionalRenderEnabled.cs new file mode 100644 index 000000000..451f49636 --- /dev/null +++ b/Ryujinx.Graphics.Gpu/Engine/ConditionalRenderEnabled.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.Graphics.Gpu.Engine +{ + enum ConditionalRenderEnabled + { + False, + True, + Host + } +} diff --git a/Ryujinx.Graphics.Gpu/Engine/IbStreamer.cs b/Ryujinx.Graphics.Gpu/Engine/IbStreamer.cs new file mode 100644 index 000000000..b407c941e --- /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 +{ + /// + /// Holds inline index buffer state. + /// The inline index buffer data is sent to the GPU through the command buffer. + /// + struct IbStreamer + { + private BufferHandle _inlineIndexBuffer; + private int _inlineIndexBufferSize; + private int _inlineIndexCount; + + public bool HasInlineIndexData => _inlineIndexCount != 0; + + /// + /// Gets the handle for the host buffer currently holding the inline index buffer data. + /// + /// Host buffer handle + public BufferHandle GetInlineIndexBuffer() + { + return _inlineIndexBuffer; + } + + /// + /// Gets the number of elements on the current inline index buffer, + /// while also reseting it to zero for the next draw. + /// + /// Inline index bufffer count + public int GetAndResetInlineIndexCount() + { + int temp = _inlineIndexCount; + _inlineIndexCount = 0; + return temp; + } + + /// + /// Pushes four 8-bit index buffer elements. + /// + /// Host renderer + /// Method call argument + 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 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(data)); + + _inlineIndexCount += 4; + } + + /// + /// Pushes two 16-bit index buffer elements. + /// + /// Host renderer + /// Method call argument + public void VbElementU16(IRenderer renderer, 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; + + renderer.SetBufferData(GetInlineIndexBuffer(renderer, offset), offset, MemoryMarshal.Cast(data)); + + _inlineIndexCount += 2; + } + + /// + /// Pushes one 32-bit index buffer element. + /// + /// Host renderer + /// Method call argument + public void VbElementU32(IRenderer renderer, int argument) + { + uint i0 = (uint)argument; + + Span data = stackalloc uint[1]; + + data[0] = i0; + + int offset = _inlineIndexCount++ * 4; + + renderer.SetBufferData(GetInlineIndexBuffer(renderer, offset), offset, MemoryMarshal.Cast(data)); + } + + /// + /// Gets the handle of a buffer large enough to hold the data that will be written to . + /// + /// Host renderer + /// Offset where the data will be written + /// Buffer handle + 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; + } + } +} diff --git a/Ryujinx.Graphics.Gpu/Engine/MethodClear.cs b/Ryujinx.Graphics.Gpu/Engine/MethodClear.cs index 5da87e6ca..82c4a9905 100644 --- a/Ryujinx.Graphics.Gpu/Engine/MethodClear.cs +++ b/Ryujinx.Graphics.Gpu/Engine/MethodClear.cs @@ -30,7 +30,7 @@ namespace Ryujinx.Graphics.Gpu.Engine UpdateRenderTargetState(state, useControl: false, singleUse: index); - TextureManager.CommitGraphicsBindings(); + TextureManager.UpdateRenderTargets(); bool clearDepth = (argument & 1) != 0; bool clearStencil = (argument & 2) != 0; diff --git a/Ryujinx.Graphics.Gpu/Engine/MethodConditionalRendering.cs b/Ryujinx.Graphics.Gpu/Engine/MethodConditionalRendering.cs index c508f3b69..7e7964c4b 100644 --- a/Ryujinx.Graphics.Gpu/Engine/MethodConditionalRendering.cs +++ b/Ryujinx.Graphics.Gpu/Engine/MethodConditionalRendering.cs @@ -6,13 +6,6 @@ namespace Ryujinx.Graphics.Gpu.Engine { partial class Methods { - enum ConditionalRenderEnabled - { - False, - True, - Host - } - /// /// Checks if draws and clears should be performed, according /// to currently set conditional rendering conditions. diff --git a/Ryujinx.Graphics.Gpu/Engine/MethodDraw.cs b/Ryujinx.Graphics.Gpu/Engine/MethodDraw.cs index 5d41dafd7..88f2e8fe9 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,22 +20,34 @@ namespace Ryujinx.Graphics.Gpu.Engine private int _instanceIndex; - private BufferHandle _inlineIndexBuffer = BufferHandle.Null; - private int _inlineIndexBufferSize; - private int _inlineIndexCount; + private IbStreamer _ibStreamer; /// - /// Primitive type of the current draw. + /// Primitive topology of the current draw. /// - public PrimitiveType PrimitiveType { get; private set; } + public PrimitiveTopology Topology { get; private set; } /// - /// Finishes draw call. + /// Finishes the draw call. /// This draws geometry on the bound buffers based on the current GPU state. /// /// Current GPU state /// Method call argument private void DrawEnd(GpuState state, int argument) + { + var indexBuffer = state.Get(MethodOffset.IndexBufferState); + + DrawEnd(state, indexBuffer.First, indexBuffer.Count); + } + + /// + /// Finishes the draw call. + /// This draws geometry on the bound buffers based on the current GPU state. + /// + /// Current GPU state + /// Index of the first index buffer element used on the draw + /// Number of index buffer elements used on the draw + private void DrawEnd(GpuState state, int firstIndex, int indexCount) { ConditionalRenderEnabled renderEnable = GetRenderEnable(state); @@ -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(MethodOffset.FirstVertex); + _instancedFirstIndex = firstIndex; + _instancedFirstVertex = state.Get(MethodOffset.FirstVertex); _instancedFirstInstance = state.Get(MethodOffset.FirstInstance); - _instancedIndexCount = _indexCount; + _instancedIndexCount = indexCount; var drawState = state.Get(MethodOffset.VertexBufferDrawState); @@ -95,31 +101,31 @@ namespace Ryujinx.Graphics.Gpu.Engine int firstInstance = state.Get(MethodOffset.FirstInstance); - if (_inlineIndexCount != 0) + int inlineIndexCount = _ibStreamer.GetAndResetInlineIndexCount(); + + if (inlineIndexCount != 0) { int firstVertex = state.Get(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(MethodOffset.FirstVertex); _context.Renderer.Pipeline.DrawIndexed( - _indexCount, + indexCount, 1, - _firstIndex, + firstIndex, firstVertex, firstInstance); } @@ -150,22 +156,46 @@ namespace Ryujinx.Graphics.Gpu.Engine /// Method call argument 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(MethodOffset.PrimitiveTypeOverride); + + if (typeOverride != PrimitiveTypeOverride.Invalid) + { + DrawBegin(incrementInstance, resetInstance, typeOverride.Convert()); + } + else + { + DrawBegin(incrementInstance, resetInstance, type.Convert()); + } + } + + /// + /// Starts draw. + /// This sets primitive type and instanced draw parameters. + /// + /// Indicates if the current instance should be incremented + /// Indicates if the current instance should be set to zero + /// Primitive topology + 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(topology); - _context.Renderer.Pipeline.SetPrimitiveTopology(type.Convert()); - - PrimitiveType = type; + Topology = topology; } /// @@ -179,6 +209,73 @@ namespace Ryujinx.Graphics.Gpu.Engine _drawIndexed = true; } + /// + /// Performs a indexed draw with a low number of index buffer elements. + /// + /// Current GPU state + /// Method call argument + private void DrawIndexedSmall(GpuState state, int argument) + { + DrawIndexedSmall(state, argument, false); + } + + /// + /// Performs a indexed draw with a low number of index buffer elements. + /// + /// Current GPU state + /// Method call argument + private void DrawIndexedSmall2(GpuState state, int argument) + { + DrawIndexedSmall(state, argument); + } + + /// + /// Performs a indexed draw with a low number of index buffer elements, + /// while also pre-incrementing the current instance value. + /// + /// Current GPU state + /// Method call argument + private void DrawIndexedSmallIncInstance(GpuState state, int argument) + { + DrawIndexedSmall(state, argument, true); + } + + /// + /// Performs a indexed draw with a low number of index buffer elements, + /// while also pre-incrementing the current instance value. + /// + /// Current GPU state + /// Method call argument + private void DrawIndexedSmallIncInstance2(GpuState state, int argument) + { + DrawIndexedSmallIncInstance(state, argument); + } + + /// + /// Performs a indexed draw with a low number of index buffer elements, + /// while optionally also pre-incrementing the current instance value. + /// + /// Current GPU state + /// Method call argument + /// True to increment the current instance value, false otherwise + private void DrawIndexedSmall(GpuState state, int argument, bool instanced) + { + PrimitiveTypeOverride typeOverride = state.Get(MethodOffset.PrimitiveTypeOverride); + + DrawBegin(instanced, !instanced, typeOverride.Convert()); + + int firstIndex = argument & 0xffff; + int indexCount = (argument >> 16) & 0xfff; + + bool oldDrawIndexed = _drawIndexed; + + _drawIndexed = true; + + DrawEnd(state, firstIndex, indexCount); + + _drawIndexed = oldDrawIndexed; + } + /// /// Pushes four 8-bit index buffer elements. /// @@ -186,23 +283,7 @@ namespace Ryujinx.Graphics.Gpu.Engine /// 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; + _ibStreamer.VbElementU8(_context.Renderer, argument); } /// @@ -212,19 +293,7 @@ namespace Ryujinx.Graphics.Gpu.Engine /// 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; + _ibStreamer.VbElementU16(_context.Renderer, argument); } /// @@ -234,46 +303,7 @@ namespace Ryujinx.Graphics.Gpu.Engine /// 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; + _ibStreamer.VbElementU32(_context.Renderer, argument); } /// diff --git a/Ryujinx.Graphics.Gpu/Engine/Methods.cs b/Ryujinx.Graphics.Gpu/Engine/Methods.cs index 618f64406..df40e19e7 100644 --- a/Ryujinx.Graphics.Gpu/Engine/Methods.cs +++ b/Ryujinx.Graphics.Gpu/Engine/Methods.cs @@ -87,8 +87,12 @@ namespace Ryujinx.Graphics.Gpu.Engine state.RegisterCallback(MethodOffset.ResetCounter, ResetCounter); - state.RegisterCallback(MethodOffset.DrawEnd, DrawEnd); - state.RegisterCallback(MethodOffset.DrawBegin, DrawBegin); + state.RegisterCallback(MethodOffset.DrawEnd, DrawEnd); + state.RegisterCallback(MethodOffset.DrawBegin, DrawBegin); + state.RegisterCallback(MethodOffset.DrawIndexedSmall, DrawIndexedSmall); + state.RegisterCallback(MethodOffset.DrawIndexedSmall2, DrawIndexedSmall2); + state.RegisterCallback(MethodOffset.DrawIndexedSmallIncInstance, DrawIndexedSmallIncInstance); + state.RegisterCallback(MethodOffset.DrawIndexedSmallIncInstance2, DrawIndexedSmallIncInstance2); state.RegisterCallback(MethodOffset.IndexBufferCount, SetIndexBufferCount); @@ -111,7 +115,9 @@ namespace Ryujinx.Graphics.Gpu.Engine /// Updates host state based on the current guest GPU state. /// /// Guest GPU state - private void UpdateState(GpuState state) + /// Index of the first index buffer element used on the draw + /// Number of index buffer elements used on the draw + private void UpdateState(GpuState state, int firstIndex, int indexCount) { bool tfEnable = state.Get(MethodOffset.TfEnable); @@ -233,7 +239,7 @@ namespace Ryujinx.Graphics.Gpu.Engine if (state.QueryModified(MethodOffset.IndexBufferState)) { - UpdateIndexBufferState(state); + UpdateIndexBufferState(state, firstIndex, indexCount); } if (state.QueryModified(MethodOffset.VertexBufferDrawState, @@ -273,7 +279,7 @@ namespace Ryujinx.Graphics.Gpu.Engine if (tfEnable && !_prevTfEnable) { - _context.Renderer.Pipeline.BeginTransformFeedback(PrimitiveType.Convert()); + _context.Renderer.Pipeline.BeginTransformFeedback(Topology); _prevTfEnable = true; } } @@ -742,14 +748,13 @@ namespace Ryujinx.Graphics.Gpu.Engine /// Updates host index buffer binding based on guest GPU state. /// /// Current GPU state - private void UpdateIndexBufferState(GpuState state) + /// Index of the first index buffer element used on the draw + /// Number of index buffer elements used on the draw + private void UpdateIndexBufferState(GpuState state, int firstIndex, int indexCount) { var indexBuffer = state.Get(MethodOffset.IndexBufferState); - _firstIndex = indexBuffer.First; - _indexCount = indexBuffer.Count; - - if (_indexCount == 0) + if (indexCount == 0) { return; } @@ -758,7 +763,7 @@ namespace Ryujinx.Graphics.Gpu.Engine // Do not use the end address to calculate the size, because // the result may be much larger than the real size of the index buffer. - ulong size = (ulong)(_firstIndex + _indexCount); + ulong size = (ulong)(firstIndex + indexCount); switch (indexBuffer.Type) { @@ -806,7 +811,7 @@ namespace Ryujinx.Graphics.Gpu.Engine ulong size; - if (_inlineIndexCount != 0 || _drawIndexed || stride == 0 || instanced) + if (_ibStreamer.HasInlineIndexData || _drawIndexed || stride == 0 || instanced) { // This size may be (much) larger than the real vertex buffer size. // Avoid calculating it this way, unless we don't have any other option. diff --git a/Ryujinx.Graphics.Gpu/Image/TextureManager.cs b/Ryujinx.Graphics.Gpu/Image/TextureManager.cs index f8720695d..ea321aae4 100644 --- a/Ryujinx.Graphics.Gpu/Image/TextureManager.cs +++ b/Ryujinx.Graphics.Gpu/Image/TextureManager.cs @@ -348,7 +348,7 @@ namespace Ryujinx.Graphics.Gpu.Image /// /// Update host framebuffer attachments based on currently bound render target buffers. /// - private void UpdateRenderTargets() + public void UpdateRenderTargets() { bool anyChanged = false; diff --git a/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs b/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs index fd0a6b0db..d726bcb8b 100644 --- a/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs +++ b/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs @@ -147,23 +147,23 @@ namespace Ryujinx.Graphics.Gpu.Shader /// Current primitive topology public InputTopology QueryPrimitiveTopology() { - switch (_context.Methods.PrimitiveType) + switch (_context.Methods.Topology) { - case PrimitiveType.Points: + case PrimitiveTopology.Points: return InputTopology.Points; - case PrimitiveType.Lines: - case PrimitiveType.LineLoop: - case PrimitiveType.LineStrip: + case PrimitiveTopology.Lines: + case PrimitiveTopology.LineLoop: + case PrimitiveTopology.LineStrip: return InputTopology.Lines; - case PrimitiveType.LinesAdjacency: - case PrimitiveType.LineStripAdjacency: + case PrimitiveTopology.LinesAdjacency: + case PrimitiveTopology.LineStripAdjacency: return InputTopology.LinesAdjacency; - case PrimitiveType.Triangles: - case PrimitiveType.TriangleStrip: - case PrimitiveType.TriangleFan: + case PrimitiveTopology.Triangles: + case PrimitiveTopology.TriangleStrip: + case PrimitiveTopology.TriangleFan: return InputTopology.Triangles; - case PrimitiveType.TrianglesAdjacency: - case PrimitiveType.TriangleStripAdjacency: + case PrimitiveTopology.TrianglesAdjacency: + case PrimitiveTopology.TriangleStripAdjacency: return InputTopology.TrianglesAdjacency; } diff --git a/Ryujinx.Graphics.Gpu/State/MethodOffset.cs b/Ryujinx.Graphics.Gpu/State/MethodOffset.cs index 13b699f3b..8d2df79a2 100644 --- a/Ryujinx.Graphics.Gpu/State/MethodOffset.cs +++ b/Ryujinx.Graphics.Gpu/State/MethodOffset.cs @@ -86,12 +86,17 @@ namespace Ryujinx.Graphics.Gpu.State PrimitiveRestartState = 0x591, IndexBufferState = 0x5f2, IndexBufferCount = 0x5f8, + DrawIndexedSmall = 0x5f9, + DrawIndexedSmall2 = 0x5fa, + DrawIndexedSmallIncInstance = 0x5fc, + DrawIndexedSmallIncInstance2 = 0x5fd, DepthBiasClamp = 0x61f, VertexBufferInstanced = 0x620, VertexProgramPointSize = 0x644, FaceState = 0x646, ViewportTransformEnable = 0x64b, ViewVolumeClipControl = 0x64f, + PrimitiveTypeOverride = 0x65c, LogicOpState = 0x671, Clear = 0x674, RtColorMask = 0x680, diff --git a/Ryujinx.Graphics.Gpu/State/PrimitiveTopology.cs b/Ryujinx.Graphics.Gpu/State/PrimitiveType.cs similarity index 53% rename from Ryujinx.Graphics.Gpu/State/PrimitiveTopology.cs rename to Ryujinx.Graphics.Gpu/State/PrimitiveType.cs index 340991c2e..b49088aac 100644 --- a/Ryujinx.Graphics.Gpu/State/PrimitiveTopology.cs +++ b/Ryujinx.Graphics.Gpu/State/PrimitiveType.cs @@ -24,6 +24,25 @@ namespace Ryujinx.Graphics.Gpu.State Patches } + /// + /// Alternative primitive type that might override . + /// + enum PrimitiveTypeOverride + { + Invalid = 0, + Points = 1, + Lines = 2, + LineStrip = 3, + Triangles = 4, + TriangleStrip = 5, + TriangleFan = 0x1015, + LinesAdjacency = 10, + LineStripAdjacency = 11, + TrianglesAdjacency = 12, + TriangleStripAdjacency = 13, + Patches = 14 + } + static class PrimitiveTypeConverter { /// @@ -53,5 +72,29 @@ namespace Ryujinx.Graphics.Gpu.State _ => PrimitiveTopology.Triangles }; } + + /// + /// Converts the primitive type into something that can be used with the host API. + /// + /// The primitive type to convert + /// A host compatible enum value + public static PrimitiveTopology Convert(this PrimitiveTypeOverride type) + { + return type switch + { + PrimitiveTypeOverride.Points => PrimitiveTopology.Points, + PrimitiveTypeOverride.Lines => PrimitiveTopology.Lines, + PrimitiveTypeOverride.LineStrip => PrimitiveTopology.LineStrip, + PrimitiveTypeOverride.Triangles => PrimitiveTopology.Triangles, + PrimitiveTypeOverride.TriangleStrip => PrimitiveTopology.TriangleStrip, + PrimitiveTypeOverride.TriangleFan => PrimitiveTopology.TriangleFan, + PrimitiveTypeOverride.LinesAdjacency => PrimitiveTopology.LinesAdjacency, + PrimitiveTypeOverride.LineStripAdjacency => PrimitiveTopology.LineStripAdjacency, + PrimitiveTypeOverride.TrianglesAdjacency => PrimitiveTopology.TrianglesAdjacency, + PrimitiveTypeOverride.TriangleStripAdjacency => PrimitiveTopology.TriangleStripAdjacency, + PrimitiveTypeOverride.Patches => PrimitiveTopology.Patches, + _ => PrimitiveTopology.Triangles + }; + } } } \ No newline at end of file