diff options
Diffstat (limited to 'Ryujinx.Graphics/NvGpuFifo.cs')
| -rw-r--r-- | Ryujinx.Graphics/NvGpuFifo.cs | 198 |
1 files changed, 198 insertions, 0 deletions
diff --git a/Ryujinx.Graphics/NvGpuFifo.cs b/Ryujinx.Graphics/NvGpuFifo.cs new file mode 100644 index 00000000..3b79a055 --- /dev/null +++ b/Ryujinx.Graphics/NvGpuFifo.cs @@ -0,0 +1,198 @@ +using Ryujinx.Graphics.Memory; +using System.Collections.Concurrent; +using System.Threading; + +namespace Ryujinx.Graphics +{ + public class NvGpuFifo + { + private const int MacrosCount = 0x80; + private const int MacroIndexMask = MacrosCount - 1; + + //Note: The size of the macro memory is unknown, we just make + //a guess here and use 256kb as the size. Increase if needed. + private const int MmeWords = 256 * 256; + + private NvGpu Gpu; + + private ConcurrentQueue<(NvGpuVmm, NvGpuPBEntry[])> BufferQueue; + + private NvGpuEngine[] SubChannels; + + public AutoResetEvent Event { get; private set; } + + private struct CachedMacro + { + public int Position { get; private set; } + + private MacroInterpreter Interpreter; + + public CachedMacro(NvGpuFifo PFifo, INvGpuEngine Engine, int Position) + { + this.Position = Position; + + Interpreter = new MacroInterpreter(PFifo, Engine); + } + + public void PushParam(int Param) + { + Interpreter?.Fifo.Enqueue(Param); + } + + public void Execute(NvGpuVmm Vmm, int[] Mme, int Param) + { + Interpreter?.Execute(Vmm, Mme, Position, Param); + } + } + + private int CurrMacroPosition; + private int CurrMacroBindIndex; + + private CachedMacro[] Macros; + + private int[] Mme; + + public NvGpuFifo(NvGpu Gpu) + { + this.Gpu = Gpu; + + BufferQueue = new ConcurrentQueue<(NvGpuVmm, NvGpuPBEntry[])>(); + + SubChannels = new NvGpuEngine[8]; + + Macros = new CachedMacro[MacrosCount]; + + Mme = new int[MmeWords]; + + Event = new AutoResetEvent(false); + } + + public void PushBuffer(NvGpuVmm Vmm, NvGpuPBEntry[] Buffer) + { + BufferQueue.Enqueue((Vmm, Buffer)); + + Event.Set(); + } + + public void DispatchCalls() + { + while (Step()); + } + + private (NvGpuVmm Vmm, NvGpuPBEntry[] Pb) Curr; + + private int CurrPbEntryIndex; + + public bool Step() + { + while (Curr.Pb == null || Curr.Pb.Length <= CurrPbEntryIndex) + { + if (!BufferQueue.TryDequeue(out Curr)) + { + return false; + } + + Gpu.Engine3d.ResetCache(); + + CurrPbEntryIndex = 0; + } + + CallMethod(Curr.Vmm, Curr.Pb[CurrPbEntryIndex++]); + + return true; + } + + private void CallMethod(NvGpuVmm Vmm, NvGpuPBEntry PBEntry) + { + if (PBEntry.Method < 0x80) + { + switch ((NvGpuFifoMeth)PBEntry.Method) + { + case NvGpuFifoMeth.BindChannel: + { + NvGpuEngine Engine = (NvGpuEngine)PBEntry.Arguments[0]; + + SubChannels[PBEntry.SubChannel] = Engine; + + break; + } + + case NvGpuFifoMeth.SetMacroUploadAddress: + { + CurrMacroPosition = PBEntry.Arguments[0]; + + break; + } + + case NvGpuFifoMeth.SendMacroCodeData: + { + foreach (int Arg in PBEntry.Arguments) + { + Mme[CurrMacroPosition++] = Arg; + } + break; + } + + case NvGpuFifoMeth.SetMacroBindingIndex: + { + CurrMacroBindIndex = PBEntry.Arguments[0]; + + break; + } + + case NvGpuFifoMeth.BindMacro: + { + int Position = PBEntry.Arguments[0]; + + Macros[CurrMacroBindIndex] = new CachedMacro(this, Gpu.Engine3d, Position); + + break; + } + } + } + else + { + switch (SubChannels[PBEntry.SubChannel]) + { + case NvGpuEngine._2d: Call2dMethod (Vmm, PBEntry); break; + case NvGpuEngine._3d: Call3dMethod (Vmm, PBEntry); break; + case NvGpuEngine.Dma: CallDmaMethod(Vmm, PBEntry); break; + } + } + } + + private void Call2dMethod(NvGpuVmm Vmm, NvGpuPBEntry PBEntry) + { + Gpu.Engine2d.CallMethod(Vmm, PBEntry); + } + + private void Call3dMethod(NvGpuVmm Vmm, NvGpuPBEntry PBEntry) + { + if (PBEntry.Method < 0xe00) + { + Gpu.Engine3d.CallMethod(Vmm, PBEntry); + } + else + { + int MacroIndex = (PBEntry.Method >> 1) & MacroIndexMask; + + if ((PBEntry.Method & 1) != 0) + { + foreach (int Arg in PBEntry.Arguments) + { + Macros[MacroIndex].PushParam(Arg); + } + } + else + { + Macros[MacroIndex].Execute(Vmm, Mme, PBEntry.Arguments[0]); + } + } + } + + private void CallDmaMethod(NvGpuVmm Vmm, NvGpuPBEntry PBEntry) + { + Gpu.EngineDma.CallMethod(Vmm, PBEntry); + } + } +}
\ No newline at end of file |
