diff options
Diffstat (limited to 'src/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs')
-rw-r--r-- | src/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs | 142 |
1 files changed, 105 insertions, 37 deletions
diff --git a/src/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs b/src/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs index d7ee24b1..18e7ac00 100644 --- a/src/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs +++ b/src/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs @@ -1,4 +1,5 @@ using Ryujinx.Graphics.GAL; +using Ryujinx.Graphics.Gpu.Engine.Threed.ComputeDraw; using Ryujinx.Graphics.Gpu.Engine.Types; using Ryujinx.Graphics.Gpu.Memory; using System; @@ -8,7 +9,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed /// <summary> /// Draw manager. /// </summary> - class DrawManager + class DrawManager : IDisposable { // Since we don't know the index buffer size for indirect draws, // we must assume a minimum and maximum size and use that for buffer data update purposes. @@ -20,6 +21,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed private readonly DeviceStateWithShadow<ThreedClassState> _state; private readonly DrawState _drawState; private readonly SpecializationStateUpdater _currentSpecState; + private readonly VtgAsCompute _vtgAsCompute; private bool _topologySet; private bool _instancedDrawPending; @@ -53,6 +55,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed _state = state; _drawState = drawState; _currentSpecState = spec; + _vtgAsCompute = new(context, channel, state); } /// <summary> @@ -127,7 +130,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed { if (renderEnable == ConditionalRenderEnabled.False) { - PerformDeferredDraws(); + PerformDeferredDraws(engine); } _drawState.DrawIndexed = false; @@ -190,13 +193,13 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed _channel.BufferManager.SetIndexBuffer(br, IndexType.UInt); - _context.Renderer.Pipeline.DrawIndexed(inlineIndexCount, 1, firstIndex, firstVertex, firstInstance); + DrawImpl(engine, inlineIndexCount, 1, firstIndex, firstVertex, firstInstance, indexed: true); } else if (_drawState.DrawIndexed) { int firstVertex = (int)_state.State.FirstVertex; - _context.Renderer.Pipeline.DrawIndexed(indexCount, 1, firstIndex, firstVertex, firstInstance); + DrawImpl(engine, indexCount, 1, firstIndex, firstVertex, firstInstance, indexed: true); } else { @@ -204,7 +207,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed var drawState = _state.State.VertexBufferDrawState; #pragma warning restore IDE0059 - _context.Renderer.Pipeline.Draw(drawVertexCount, 1, drawFirstVertex, firstInstance); + DrawImpl(engine, drawVertexCount, 1, 0, drawFirstVertex, firstInstance, indexed: false); } _drawState.DrawIndexed = false; @@ -219,24 +222,26 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed /// Starts draw. /// This sets primitive type and instanced draw parameters. /// </summary> + /// <param name="engine">3D engine where this method is being called</param> /// <param name="argument">Method call argument</param> - public void DrawBegin(int argument) + public void DrawBegin(ThreedClass engine, int argument) { bool incrementInstance = (argument & (1 << 26)) != 0; bool resetInstance = (argument & (1 << 27)) == 0; PrimitiveType type = (PrimitiveType)(argument & 0xffff); - DrawBegin(incrementInstance, resetInstance, type); + DrawBegin(engine, incrementInstance, resetInstance, type); } /// <summary> /// Starts draw. /// This sets primitive type and instanced draw parameters. /// </summary> + /// <param name="engine">3D engine where this method is being called</param> /// <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="primitiveType">Primitive type</param> - private void DrawBegin(bool incrementInstance, bool resetInstance, PrimitiveType primitiveType) + private void DrawBegin(ThreedClass engine, bool incrementInstance, bool resetInstance, PrimitiveType primitiveType) { if (incrementInstance) { @@ -244,7 +249,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed } else if (resetInstance) { - PerformDeferredDraws(); + PerformDeferredDraws(engine); _instanceIndex = 0; } @@ -364,7 +369,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed /// <param name="instanced">True to increment the current instance value, false otherwise</param> private void DrawIndexBufferBeginEndInstance(ThreedClass engine, int argument, bool instanced) { - DrawBegin(instanced, !instanced, (PrimitiveType)((argument >> 28) & 0xf)); + DrawBegin(engine, instanced, !instanced, (PrimitiveType)((argument >> 28) & 0xf)); int firstIndex = argument & 0xffff; int indexCount = (argument >> 16) & 0xfff; @@ -409,7 +414,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed /// <param name="instanced">True to increment the current instance value, false otherwise</param> private void DrawVertexArrayBeginEndInstance(ThreedClass engine, int argument, bool instanced) { - DrawBegin(instanced, !instanced, (PrimitiveType)((argument >> 28) & 0xf)); + DrawBegin(engine, instanced, !instanced, (PrimitiveType)((argument >> 28) & 0xf)); int firstVertex = argument & 0xffff; int vertexCount = (argument >> 16) & 0xfff; @@ -541,23 +546,12 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed engine.UpdateState(); - if (instanceCount > 1) - { - // Must be called after UpdateState as it assumes the shader state - // has already been set, and that bindings have been updated already. - - _channel.BufferManager.SetInstancedDrawVertexCount(count); - } + DrawImpl(engine, count, instanceCount, firstIndex, firstVertex, firstInstance, indexed); if (indexed) { - _context.Renderer.Pipeline.DrawIndexed(count, instanceCount, firstIndex, firstVertex, firstInstance); _state.State.FirstVertex = 0; } - else - { - _context.Renderer.Pipeline.Draw(count, instanceCount, firstVertex, firstInstance); - } _state.State.FirstInstance = 0; @@ -570,6 +564,67 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed } /// <summary> + /// Performs a indexed or non-indexed draw. + /// </summary> + /// <param name="engine">3D engine where this method is being called</param> + /// <param name="count">Index count for indexed draws, vertex count for non-indexed draws</param> + /// <param name="instanceCount">Instance count</param> + /// <param name="firstIndex">First index on the index buffer for indexed draws, ignored for non-indexed draws</param> + /// <param name="firstVertex">First vertex on the vertex buffer</param> + /// <param name="firstInstance">First instance</param> + /// <param name="indexed">True if the draw is indexed, false otherwise</param> + private void DrawImpl( + ThreedClass engine, + int count, + int instanceCount, + int firstIndex, + int firstVertex, + int firstInstance, + bool indexed) + { + if (instanceCount > 1) + { + _channel.BufferManager.SetInstancedDrawVertexCount(count); + } + + if (_drawState.VertexAsCompute != null) + { + _vtgAsCompute.DrawAsCompute( + engine, + _drawState.VertexAsCompute, + _drawState.GeometryAsCompute, + _drawState.VertexPassthrough, + _drawState.Topology, + count, + instanceCount, + firstIndex, + firstVertex, + firstInstance, + indexed); + + if (_drawState.GeometryAsCompute != null) + { + // Geometry draws need to change the topology, so we need to set it here again + // if we are going to do a regular draw. + // Would have been better to do that on the callee, but doing it here + // avoids having to pass the draw manager instance. + ForceStateDirty(); + } + } + else + { + if (indexed) + { + _context.Renderer.Pipeline.DrawIndexed(count, instanceCount, firstIndex, firstVertex, firstInstance); + } + else + { + _context.Renderer.Pipeline.Draw(count, instanceCount, firstVertex, firstInstance); + } + } + } + + /// <summary> /// Performs a indirect draw, with parameters from a GPU buffer. /// </summary> /// <param name="engine">3D engine where this method is being called</param> @@ -667,43 +722,42 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed /// Once we detect the last instanced draw, then we perform the host instanced draw, /// with the accumulated instance count. /// </summary> - public void PerformDeferredDraws() + /// <param name="engine">3D engine where this method is being called</param> + public void PerformDeferredDraws(ThreedClass engine) { // Perform any pending instanced draw. if (_instancedDrawPending) { _instancedDrawPending = false; + int instanceCount = _instanceIndex + 1; + int firstInstance = _instancedFirstInstance; bool indexedInline = _instancedIndexedInline; if (_instancedIndexed || indexedInline) { + int indexCount = _instancedIndexCount; + if (indexedInline) { int inlineIndexCount = _drawState.IbStreamer.GetAndResetInlineIndexCount(_context.Renderer); BufferRange br = new(_drawState.IbStreamer.GetInlineIndexBuffer(), 0, inlineIndexCount * 4); _channel.BufferManager.SetIndexBuffer(br, IndexType.UInt); + indexCount = inlineIndexCount; } - _channel.BufferManager.SetInstancedDrawVertexCount(_instancedIndexCount); + int firstIndex = _instancedFirstIndex; + int firstVertex = _instancedFirstVertex; - _context.Renderer.Pipeline.DrawIndexed( - _instancedIndexCount, - _instanceIndex + 1, - _instancedFirstIndex, - _instancedFirstVertex, - _instancedFirstInstance); + DrawImpl(engine, indexCount, instanceCount, firstIndex, firstVertex, firstInstance, indexed: true); } else { - _channel.BufferManager.SetInstancedDrawVertexCount(_instancedDrawStateCount); + int vertexCount = _instancedDrawStateCount; + int firstVertex = _instancedDrawStateFirst; - _context.Renderer.Pipeline.Draw( - _instancedDrawStateCount, - _instanceIndex + 1, - _instancedDrawStateFirst, - _instancedFirstInstance); + DrawImpl(engine, vertexCount, instanceCount, 0, firstVertex, firstInstance, indexed: false); } } } @@ -866,5 +920,19 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed _context.Renderer.Pipeline.EndHostConditionalRendering(); } } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + _vtgAsCompute.Dispose(); + } + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } } } |