From ec4cd57ccfada247d720b41c1913299abc733c74 Mon Sep 17 00:00:00 2001 From: gdkchan Date: Fri, 16 Dec 2022 12:06:38 -0300 Subject: [PATCH] Implement another non-indexed draw method on GPU (#4123) --- .../Engine/Threed/DrawManager.cs | 141 ++++++++++++++---- .../Engine/Threed/StateUpdater.cs | 2 - .../Engine/Threed/ThreedClass.cs | 74 +++++++-- .../Engine/Threed/ThreedClassState.cs | 17 ++- 4 files changed, 177 insertions(+), 57 deletions(-) diff --git a/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs b/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs index 5a659f555..cd14259a6 100644 --- a/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs +++ b/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs @@ -98,7 +98,12 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed /// Method call argument public void DrawEnd(ThreedClass engine, int argument) { - DrawEnd(engine, _state.State.IndexBufferState.First, (int)_state.State.IndexBufferCount); + DrawEnd( + engine, + _state.State.IndexBufferState.First, + (int)_state.State.IndexBufferCount, + _state.State.VertexBufferDrawState.First, + _state.State.VertexBufferDrawState.Count); } /// @@ -108,7 +113,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed /// 3D engine where this method is being called /// Index of the first index buffer element used on the draw /// Number of index buffer elements used on the draw - private void DrawEnd(ThreedClass engine, int firstIndex, int indexCount) + /// Index of the first vertex used on the draw + /// Number of vertices used on the draw + private void DrawEnd(ThreedClass engine, int firstIndex, int indexCount, int drawFirstVertex, int drawVertexCount) { ConditionalRenderEnabled renderEnable = ConditionalRendering.GetRenderEnable( _context, @@ -195,7 +202,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed { var drawState = _state.State.VertexBufferDrawState; - _context.Renderer.Pipeline.Draw(drawState.Count, 1, drawState.First, firstInstance); + _context.Renderer.Pipeline.Draw(drawVertexCount, 1, drawFirstVertex, firstInstance); } _drawState.DrawIndexed = false; @@ -216,16 +223,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed bool incrementInstance = (argument & (1 << 26)) != 0; bool resetInstance = (argument & (1 << 27)) == 0; - if (_state.State.PrimitiveTypeOverrideEnable) - { - PrimitiveTypeOverride typeOverride = _state.State.PrimitiveTypeOverride; - DrawBegin(incrementInstance, resetInstance, typeOverride.Convert()); - } - else - { - PrimitiveType type = (PrimitiveType)(argument & 0xffff); - DrawBegin(incrementInstance, resetInstance, type.Convert()); - } + PrimitiveType type = (PrimitiveType)(argument & 0xffff); + DrawBegin(incrementInstance, resetInstance, type); } /// @@ -234,8 +233,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed /// /// 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) + /// Primitive type + private void DrawBegin(bool incrementInstance, bool resetInstance, PrimitiveType primitiveType) { if (incrementInstance) { @@ -248,6 +247,18 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed _instanceIndex = 0; } + PrimitiveTopology topology; + + if (_state.State.PrimitiveTypeOverrideEnable) + { + PrimitiveTypeOverride typeOverride = _state.State.PrimitiveTypeOverride; + topology = typeOverride.Convert(); + } + else + { + topology = primitiveType.Convert(); + } + UpdateTopology(topology); } @@ -276,46 +287,70 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed _drawState.DrawIndexed = true; } + // TODO: Verify if the index type is implied from the method that is called, + // or if it uses the state index type on hardware. + /// - /// Performs a indexed draw with a low number of index buffer elements. + /// Performs a indexed draw with 8-bit index buffer elements. /// /// 3D engine where this method is being called /// Method call argument - public void DrawIndexedSmall(ThreedClass engine, int argument) + public void DrawIndexBuffer8BeginEndInstanceFirst(ThreedClass engine, int argument) { - DrawIndexedSmall(engine, argument, false); + DrawIndexBufferBeginEndInstance(engine, argument, false); } /// - /// Performs a indexed draw with a low number of index buffer elements. + /// Performs a indexed draw with 16-bit index buffer elements. /// /// 3D engine where this method is being called /// Method call argument - public void DrawIndexedSmall2(ThreedClass engine, int argument) + public void DrawIndexBuffer16BeginEndInstanceFirst(ThreedClass engine, int argument) { - DrawIndexedSmall(engine, argument); + DrawIndexBufferBeginEndInstance(engine, argument, false); } /// - /// Performs a indexed draw with a low number of index buffer elements, + /// Performs a indexed draw with 32-bit index buffer elements. + /// + /// 3D engine where this method is being called + /// Method call argument + public void DrawIndexBuffer32BeginEndInstanceFirst(ThreedClass engine, int argument) + { + DrawIndexBufferBeginEndInstance(engine, argument, false); + } + + /// + /// Performs a indexed draw with 8-bit index buffer elements, /// while also pre-incrementing the current instance value. /// /// 3D engine where this method is being called /// Method call argument - public void DrawIndexedSmallIncInstance(ThreedClass engine, int argument) + public void DrawIndexBuffer8BeginEndInstanceSubsequent(ThreedClass engine, int argument) { - DrawIndexedSmall(engine, argument, true); + DrawIndexBufferBeginEndInstance(engine, argument, true); } /// - /// Performs a indexed draw with a low number of index buffer elements, + /// Performs a indexed draw with 16-bit index buffer elements, /// while also pre-incrementing the current instance value. /// /// 3D engine where this method is being called /// Method call argument - public void DrawIndexedSmallIncInstance2(ThreedClass engine, int argument) + public void DrawIndexBuffer16BeginEndInstanceSubsequent(ThreedClass engine, int argument) { - DrawIndexedSmallIncInstance(engine, argument); + DrawIndexBufferBeginEndInstance(engine, argument, true); + } + + /// + /// Performs a indexed draw with 32-bit index buffer elements, + /// while also pre-incrementing the current instance value. + /// + /// 3D engine where this method is being called + /// Method call argument + public void DrawIndexBuffer32BeginEndInstanceSubsequent(ThreedClass engine, int argument) + { + DrawIndexBufferBeginEndInstance(engine, argument, true); } /// @@ -325,11 +360,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed /// 3D engine where this method is being called /// Method call argument /// True to increment the current instance value, false otherwise - private void DrawIndexedSmall(ThreedClass engine, int argument, bool instanced) + private void DrawIndexBufferBeginEndInstance(ThreedClass engine, int argument, bool instanced) { - PrimitiveTypeOverride typeOverride = _state.State.PrimitiveTypeOverride; - - DrawBegin(instanced, !instanced, typeOverride.Convert()); + DrawBegin(instanced, !instanced, (PrimitiveType)((argument >> 28) & 0xf)); int firstIndex = argument & 0xffff; int indexCount = (argument >> 16) & 0xfff; @@ -339,7 +372,51 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed _drawState.DrawIndexed = true; engine.ForceStateDirty(IndexBufferCountMethodOffset * 4); - DrawEnd(engine, firstIndex, indexCount); + DrawEnd(engine, firstIndex, indexCount, 0, 0); + + _drawState.DrawIndexed = oldDrawIndexed; + } + + /// + /// Performs a non-indexed draw with the specified topology, index and count. + /// + /// 3D engine where this method is being called + /// Method call argument + public void DrawVertexArrayBeginEndInstanceFirst(ThreedClass engine, int argument) + { + DrawVertexArrayBeginEndInstance(engine, argument, false); + } + + /// + /// Performs a non-indexed draw with the specified topology, index and count, + /// while incrementing the current instance. + /// + /// 3D engine where this method is being called + /// Method call argument + public void DrawVertexArrayBeginEndInstanceSubsequent(ThreedClass engine, int argument) + { + DrawVertexArrayBeginEndInstance(engine, argument, true); + } + + /// + /// Performs a indexed draw with a low number of index buffer elements, + /// while optionally also pre-incrementing the current instance value. + /// + /// 3D engine where this method is being called + /// Method call argument + /// True to increment the current instance value, false otherwise + private void DrawVertexArrayBeginEndInstance(ThreedClass engine, int argument, bool instanced) + { + DrawBegin(instanced, !instanced, (PrimitiveType)((argument >> 28) & 0xf)); + + int firstVertex = argument & 0xffff; + int vertexCount = (argument >> 16) & 0xfff; + + bool oldDrawIndexed = _drawState.DrawIndexed; + + _drawState.DrawIndexed = false; + + DrawEnd(engine, 0, 0, firstVertex, vertexCount); _drawState.DrawIndexed = oldDrawIndexed; } diff --git a/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs b/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs index e6b473450..014a17398 100644 --- a/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs +++ b/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs @@ -1,7 +1,5 @@ using Ryujinx.Common.Logging; -using Ryujinx.Common.Memory; using Ryujinx.Graphics.GAL; -using Ryujinx.Graphics.Gpu.Engine.GPFifo; using Ryujinx.Graphics.Gpu.Engine.Types; using Ryujinx.Graphics.Gpu.Image; using Ryujinx.Graphics.Gpu.Shader; diff --git a/Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClass.cs b/Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClass.cs index b254e95e0..87dd1d8ee 100644 --- a/Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClass.cs +++ b/Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClass.cs @@ -42,6 +42,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed { nameof(ThreedClassState.TextureBarrier), new RwCallback(TextureBarrier, null) }, { nameof(ThreedClassState.TextureBarrierTiled), new RwCallback(TextureBarrierTiled, null) }, { nameof(ThreedClassState.DrawTextureSrcY), new RwCallback(DrawTexture, null) }, + { nameof(ThreedClassState.DrawVertexArrayBeginEndInstanceFirst), new RwCallback(DrawVertexArrayBeginEndInstanceFirst, null) }, + { nameof(ThreedClassState.DrawVertexArrayBeginEndInstanceSubsequent), new RwCallback(DrawVertexArrayBeginEndInstanceSubsequent, null) }, { nameof(ThreedClassState.VbElementU8), new RwCallback(VbElementU8, null) }, { nameof(ThreedClassState.VbElementU16), new RwCallback(VbElementU16, null) }, { nameof(ThreedClassState.VbElementU32), new RwCallback(VbElementU32, null) }, @@ -49,10 +51,12 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed { nameof(ThreedClassState.RenderEnableCondition), new RwCallback(null, Zero) }, { nameof(ThreedClassState.DrawEnd), new RwCallback(DrawEnd, null) }, { nameof(ThreedClassState.DrawBegin), new RwCallback(DrawBegin, null) }, - { nameof(ThreedClassState.DrawIndexedSmall), new RwCallback(DrawIndexedSmall, null) }, - { nameof(ThreedClassState.DrawIndexedSmall2), new RwCallback(DrawIndexedSmall2, null) }, - { nameof(ThreedClassState.DrawIndexedSmallIncInstance), new RwCallback(DrawIndexedSmallIncInstance, null) }, - { nameof(ThreedClassState.DrawIndexedSmallIncInstance2), new RwCallback(DrawIndexedSmallIncInstance2, null) }, + { nameof(ThreedClassState.DrawIndexBuffer32BeginEndInstanceFirst), new RwCallback(DrawIndexBuffer32BeginEndInstanceFirst, null) }, + { nameof(ThreedClassState.DrawIndexBuffer16BeginEndInstanceFirst), new RwCallback(DrawIndexBuffer16BeginEndInstanceFirst, null) }, + { nameof(ThreedClassState.DrawIndexBuffer8BeginEndInstanceFirst), new RwCallback(DrawIndexBuffer8BeginEndInstanceFirst, null) }, + { nameof(ThreedClassState.DrawIndexBuffer32BeginEndInstanceSubsequent), new RwCallback(DrawIndexBuffer32BeginEndInstanceSubsequent, null) }, + { nameof(ThreedClassState.DrawIndexBuffer16BeginEndInstanceSubsequent), new RwCallback(DrawIndexBuffer16BeginEndInstanceSubsequent, null) }, + { nameof(ThreedClassState.DrawIndexBuffer8BeginEndInstanceSubsequent), new RwCallback(DrawIndexBuffer8BeginEndInstanceSubsequent, null) }, { nameof(ThreedClassState.IndexBufferCount), new RwCallback(SetIndexBufferCount, null) }, { nameof(ThreedClassState.Clear), new RwCallback(Clear, null) }, { nameof(ThreedClassState.SemaphoreControl), new RwCallback(Report, null) }, @@ -303,6 +307,25 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed _drawManager.DrawTexture(this, argument); } + /// + /// Performs a non-indexed draw with the specified topology, index and count. + /// + /// Method call argument + private void DrawVertexArrayBeginEndInstanceFirst(int argument) + { + _drawManager.DrawVertexArrayBeginEndInstanceFirst(this, argument); + } + + /// + /// Performs a non-indexed draw with the specified topology, index and count, + /// while incrementing the current instance. + /// + /// Method call argument + private void DrawVertexArrayBeginEndInstanceSubsequent(int argument) + { + _drawManager.DrawVertexArrayBeginEndInstanceSubsequent(this, argument); + } + /// /// Pushes four 8-bit index buffer elements. /// @@ -370,41 +393,60 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed } /// - /// Performs a indexed draw with a low number of index buffer elements. + /// Performs a indexed draw with 8-bit index buffer elements. /// /// Method call argument - private void DrawIndexedSmall(int argument) + private void DrawIndexBuffer8BeginEndInstanceFirst(int argument) { - _drawManager.DrawIndexedSmall(this, argument); + _drawManager.DrawIndexBuffer8BeginEndInstanceFirst(this, argument); } /// - /// Performs a indexed draw with a low number of index buffer elements. + /// Performs a indexed draw with 16-bit index buffer elements. /// /// Method call argument - private void DrawIndexedSmall2(int argument) + private void DrawIndexBuffer16BeginEndInstanceFirst(int argument) { - _drawManager.DrawIndexedSmall2(this, argument); + _drawManager.DrawIndexBuffer16BeginEndInstanceFirst(this, argument); } /// - /// Performs a indexed draw with a low number of index buffer elements, + /// Performs a indexed draw with 32-bit index buffer elements. + /// + /// Method call argument + private void DrawIndexBuffer32BeginEndInstanceFirst(int argument) + { + _drawManager.DrawIndexBuffer32BeginEndInstanceFirst(this, argument); + } + + /// + /// Performs a indexed draw with 8-bit index buffer elements, /// while also pre-incrementing the current instance value. /// /// Method call argument - private void DrawIndexedSmallIncInstance(int argument) + private void DrawIndexBuffer8BeginEndInstanceSubsequent(int argument) { - _drawManager.DrawIndexedSmallIncInstance(this, argument); + _drawManager.DrawIndexBuffer8BeginEndInstanceSubsequent(this, argument); } /// - /// Performs a indexed draw with a low number of index buffer elements, + /// Performs a indexed draw with 16-bit index buffer elements, /// while also pre-incrementing the current instance value. /// /// Method call argument - private void DrawIndexedSmallIncInstance2(int argument) + private void DrawIndexBuffer16BeginEndInstanceSubsequent(int argument) { - _drawManager.DrawIndexedSmallIncInstance2(this, argument); + _drawManager.DrawIndexBuffer16BeginEndInstanceSubsequent(this, argument); + } + + /// + /// Performs a indexed draw with 32-bit index buffer elements, + /// while also pre-incrementing the current instance value. + /// + /// Method call argument + private void DrawIndexBuffer32BeginEndInstanceSubsequent(int argument) + { + _drawManager.DrawIndexBuffer32BeginEndInstanceSubsequent(this, argument); } /// diff --git a/Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClassState.cs b/Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClassState.cs index e416cd583..1498e27ba 100644 --- a/Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClassState.cs +++ b/Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClassState.cs @@ -813,7 +813,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed public uint ClearFlags; public fixed uint Reserved10FC[25]; public Array32 VertexAttribState; - public fixed uint Reserved11E0[15]; + public fixed uint Reserved11E0[13]; + public uint DrawVertexArrayBeginEndInstanceFirst; + public uint DrawVertexArrayBeginEndInstanceSubsequent; public RtControl RtControl; public fixed uint Reserved1220[2]; public Size3D RtDepthStencilSize; @@ -888,12 +890,13 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed public fixed uint Reserved164C[95]; public IndexBufferState IndexBufferState; public uint IndexBufferCount; - public uint DrawIndexedSmall; - public uint DrawIndexedSmall2; - public uint Reserved17EC; - public uint DrawIndexedSmallIncInstance; - public uint DrawIndexedSmallIncInstance2; - public fixed uint Reserved17F8[33]; + public uint DrawIndexBuffer32BeginEndInstanceFirst; + public uint DrawIndexBuffer16BeginEndInstanceFirst; + public uint DrawIndexBuffer8BeginEndInstanceFirst; + public uint DrawIndexBuffer32BeginEndInstanceSubsequent; + public uint DrawIndexBuffer16BeginEndInstanceSubsequent; + public uint DrawIndexBuffer8BeginEndInstanceSubsequent; + public fixed uint Reserved17FC[32]; public float DepthBiasClamp; public Array16 VertexBufferInstanced; public fixed uint Reserved18C0[20];