diff options
Diffstat (limited to 'Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs')
-rw-r--r-- | Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs | 165 |
1 files changed, 146 insertions, 19 deletions
diff --git a/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs b/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs index e02c8cdc..a7acb469 100644 --- a/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs +++ b/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs @@ -1,5 +1,6 @@ using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.Gpu.Engine.Types; +using Ryujinx.Graphics.Gpu.Memory; using System; namespace Ryujinx.Graphics.Gpu.Engine.Threed @@ -9,6 +10,11 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed /// </summary> class DrawManager { + // 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. + private const int MinIndirectIndexCount = 0x10000; + private const int MaxIndirectIndexCount = 0x4000000; + private readonly GpuContext _context; private readonly GpuChannel _channel; private readonly DeviceStateWithShadow<ThreedClassState> _state; @@ -28,6 +34,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed private int _instanceIndex; + private const int VertexBufferFirstMethodOffset = 0x35d; private const int IndexBufferCountMethodOffset = 0x5f8; /// <summary> @@ -237,6 +244,15 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed _instanceIndex = 0; } + UpdateTopology(topology); + } + + /// <summary> + /// Updates the current primitive topology if needed. + /// </summary> + /// <param name="topology">New primitive topology</param> + private void UpdateTopology(PrimitiveTopology topology) + { if (_drawState.Topology != topology || !_topologySet) { _context.Renderer.Pipeline.SetPrimitiveTopology(topology); @@ -383,28 +399,104 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed } /// <summary> - /// Performs a indirect multi-draw, with parameters from a GPU buffer. + /// Performs a indexed or non-indexed draw. + /// </summary> + /// <param name="engine">3D engine where this method is being called</param> + /// <param name="topology">Primitive topology</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> + public void Draw( + ThreedClass engine, + PrimitiveTopology topology, + int count, + int instanceCount, + int firstIndex, + int firstVertex, + int firstInstance, + bool indexed) + { + UpdateTopology(topology); + + ConditionalRenderEnabled renderEnable = ConditionalRendering.GetRenderEnable( + _context, + _channel.MemoryManager, + _state.State.RenderEnableAddress, + _state.State.RenderEnableCondition); + + if (renderEnable == ConditionalRenderEnabled.False) + { + _drawState.DrawIndexed = false; + return; + } + + if (indexed) + { + _drawState.FirstIndex = firstIndex; + _drawState.IndexCount = count; + _state.State.FirstVertex = (uint)firstVertex; + engine.ForceStateDirty(IndexBufferCountMethodOffset * 4); + } + else + { + _state.State.VertexBufferDrawState.First = firstVertex; + _state.State.VertexBufferDrawState.Count = count; + engine.ForceStateDirty(VertexBufferFirstMethodOffset * 4); + } + + _state.State.FirstInstance = (uint)firstInstance; + + _drawState.DrawIndexed = indexed; + _drawState.HasConstantBufferDrawParameters = true; + + engine.UpdateState(); + + 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; + + _drawState.DrawIndexed = false; + _drawState.HasConstantBufferDrawParameters = false; + + if (renderEnable == ConditionalRenderEnabled.Host) + { + _context.Renderer.Pipeline.EndHostConditionalRendering(); + } + } + + /// <summary> + /// Performs a indirect draw, with parameters from a GPU buffer. /// </summary> /// <param name="engine">3D engine where this method is being called</param> /// <param name="topology">Primitive topology</param> - /// <param name="indirectBuffer">GPU buffer with the draw parameters, such as count, first index, etc</param> - /// <param name="parameterBuffer">GPU buffer with the draw count</param> + /// <param name="indirectBufferAddress">Address of the buffer with the draw parameters, such as count, first index, etc</param> + /// <param name="parameterBufferAddress">Address of the buffer with the draw count</param> /// <param name="maxDrawCount">Maximum number of draws that can be made</param> - /// <param name="stride">Distance in bytes between each element on the <paramref name="indirectBuffer"/> array</param> - public void MultiDrawIndirectCount( + /// <param name="stride">Distance in bytes between each entry on the data pointed to by <paramref name="indirectBufferAddress"/></param> + /// <param name="indexCount">Maximum number of indices that the draw can consume</param> + /// <param name="drawType">Type of the indirect draw, which can be indexed or non-indexed, with or without a draw count</param> + public void DrawIndirect( ThreedClass engine, - int indexCount, PrimitiveTopology topology, - BufferRange indirectBuffer, - BufferRange parameterBuffer, + ulong indirectBufferAddress, + ulong parameterBufferAddress, int maxDrawCount, - int stride) + int stride, + int indexCount, + IndirectDrawType drawType) { - engine.Write(IndexBufferCountMethodOffset * 4, indexCount); - - _context.Renderer.Pipeline.SetPrimitiveTopology(topology); - _drawState.Topology = topology; - _topologySet = true; + UpdateTopology(topology); ConditionalRenderEnabled renderEnable = ConditionalRendering.GetRenderEnable( _context, @@ -418,21 +510,56 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed return; } - _drawState.FirstIndex = _state.State.IndexBufferState.First; - _drawState.IndexCount = indexCount; + PhysicalMemory memory = _channel.MemoryManager.Physical; + + bool hasCount = (drawType & IndirectDrawType.Count) != 0; + bool indexed = (drawType & IndirectDrawType.Indexed) != 0; + + if (indexed) + { + indexCount = Math.Clamp(indexCount, MinIndirectIndexCount, MaxIndirectIndexCount); + _drawState.FirstIndex = 0; + _drawState.IndexCount = indexCount; + engine.ForceStateDirty(IndexBufferCountMethodOffset * 4); + } + + _drawState.DrawIndexed = indexed; + _drawState.DrawIndirect = true; + _drawState.HasConstantBufferDrawParameters = true; engine.UpdateState(); - if (_drawState.DrawIndexed) + if (hasCount) { - _context.Renderer.Pipeline.MultiDrawIndexedIndirectCount(indirectBuffer, parameterBuffer, maxDrawCount, stride); + var indirectBuffer = memory.BufferCache.GetBufferRange(indirectBufferAddress, (ulong)maxDrawCount * (ulong)stride); + var parameterBuffer = memory.BufferCache.GetBufferRange(parameterBufferAddress, 4); + + if (indexed) + { + _context.Renderer.Pipeline.DrawIndexedIndirectCount(indirectBuffer, parameterBuffer, maxDrawCount, stride); + } + else + { + _context.Renderer.Pipeline.DrawIndirectCount(indirectBuffer, parameterBuffer, maxDrawCount, stride); + } } else { - _context.Renderer.Pipeline.MultiDrawIndirectCount(indirectBuffer, parameterBuffer, maxDrawCount, stride); + var indirectBuffer = memory.BufferCache.GetBufferRange(indirectBufferAddress, (ulong)stride); + + if (indexed) + { + _context.Renderer.Pipeline.DrawIndexedIndirect(indirectBuffer); + } + else + { + _context.Renderer.Pipeline.DrawIndirect(indirectBuffer); + } } _drawState.DrawIndexed = false; + _drawState.DrawIndirect = false; + _drawState.HasConstantBufferDrawParameters = false; if (renderEnable == ConditionalRenderEnabled.Host) { |