From 8e1adb95cf7f67b976f105f4cac26d3ff2986057 Mon Sep 17 00:00:00 2001 From: mpnico Date: Thu, 26 Aug 2021 23:50:28 +0200 Subject: Add support for HLE macros and accelerate MultiDrawElementsIndirectCount #2 (#2557) * Add support for HLE macros and accelerate MultiDrawElementsIndirectCount * Add missing barrier * Fix index buffer count * Add support check for each macro hle before use * Add missing xml doc Co-authored-by: gdkchan --- Ryujinx.Graphics.Gpu/Engine/MME/MacroHLE.cs | 142 ++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 Ryujinx.Graphics.Gpu/Engine/MME/MacroHLE.cs (limited to 'Ryujinx.Graphics.Gpu/Engine/MME/MacroHLE.cs') diff --git a/Ryujinx.Graphics.Gpu/Engine/MME/MacroHLE.cs b/Ryujinx.Graphics.Gpu/Engine/MME/MacroHLE.cs new file mode 100644 index 00000000..77b44e81 --- /dev/null +++ b/Ryujinx.Graphics.Gpu/Engine/MME/MacroHLE.cs @@ -0,0 +1,142 @@ +using Ryujinx.Common.Logging; +using Ryujinx.Graphics.Device; +using Ryujinx.Graphics.GAL; +using Ryujinx.Graphics.Gpu.Engine.GPFifo; +using Ryujinx.Graphics.Gpu.Engine.Threed; +using Ryujinx.Graphics.Gpu.Memory; +using System; +using System.Collections.Generic; + +namespace Ryujinx.Graphics.Gpu.Engine.MME +{ + /// + /// Macro High-level emulation. + /// + class MacroHLE : IMacroEE + { + private readonly GPFifoProcessor _processor; + private readonly MacroHLEFunctionName _functionName; + + /// + /// Arguments FIFO. + /// + public Queue Fifo { get; } + + /// + /// Creates a new instance of the HLE macro handler. + /// + /// GPU context the macro is being executed on + /// GPU memory manager + /// 3D engine where this macro is being called + /// Name of the HLE macro function to be called + public MacroHLE(GPFifoProcessor processor, MacroHLEFunctionName functionName) + { + _processor = processor; + _functionName = functionName; + + Fifo = new Queue(); + } + + /// + /// Executes a macro program until it exits. + /// + /// Code of the program to execute + /// GPU state at the time of the call + /// Optional argument passed to the program, 0 if not used + public void Execute(ReadOnlySpan code, IDeviceState state, int arg0) + { + switch (_functionName) + { + case MacroHLEFunctionName.MultiDrawElementsIndirectCount: + MultiDrawElementsIndirectCount(state, arg0); + break; + default: + throw new NotImplementedException(_functionName.ToString()); + } + } + + /// + /// Performs a indirect multi-draw, with parameters from a GPU buffer. + /// + /// GPU state at the time of the call + /// First argument of the call + private void MultiDrawElementsIndirectCount(IDeviceState state, int arg0) + { + int arg1 = FetchParam().Word; + int arg2 = FetchParam().Word; + int arg3 = FetchParam().Word; + + int startOffset = arg0; + int endOffset = arg1; + var topology = (PrimitiveTopology)arg2; + int paddingWords = arg3; + int maxDrawCount = endOffset - startOffset; + int stride = paddingWords * 4 + 0x14; + int indirectBufferSize = maxDrawCount * stride; + + ulong parameterBufferGpuVa = FetchParam().GpuVa; + ulong indirectBufferGpuVa = 0; + + int indexCount = 0; + + for (int i = 0; i < maxDrawCount; i++) + { + var count = FetchParam(); + var instanceCount = FetchParam(); + var firstIndex = FetchParam(); + var baseVertex = FetchParam(); + var baseInstance = FetchParam(); + + if (i == 0) + { + indirectBufferGpuVa = count.GpuVa; + } + + indexCount = Math.Max(indexCount, count.Word + firstIndex.Word); + + if (i != maxDrawCount - 1) + { + for (int j = 0; j < paddingWords; j++) + { + FetchParam(); + } + } + } + + // It should be empty at this point, but clear it just to be safe. + Fifo.Clear(); + + var parameterBuffer = _processor.MemoryManager.Physical.BufferCache.GetGpuBufferRange(_processor.MemoryManager, parameterBufferGpuVa, 4); + var indirectBuffer = _processor.MemoryManager.Physical.BufferCache.GetGpuBufferRange(_processor.MemoryManager, indirectBufferGpuVa, (ulong)indirectBufferSize); + + _processor.ThreedClass.MultiDrawIndirectCount(indexCount, topology, indirectBuffer, parameterBuffer, maxDrawCount, stride); + } + + /// + /// Fetches a arguments from the arguments FIFO. + /// + /// The call argument, or a 0 value with null address if the FIFO is empty + private FifoWord FetchParam() + { + if (!Fifo.TryDequeue(out var value)) + { + Logger.Warning?.Print(LogClass.Gpu, "Macro attempted to fetch an inexistent argument."); + + return new FifoWord(0UL, 0); + } + + return value; + } + + /// + /// Performs a GPU method call. + /// + /// Current GPU state + /// Address, in words, of the method + /// Call argument + private static void Send(IDeviceState state, int methAddr, int value) + { + state.Write(methAddr * 4, value); + } + } +} -- cgit v1.2.3