aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics/NvGpuFifo.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx.Graphics/NvGpuFifo.cs')
-rw-r--r--Ryujinx.Graphics/NvGpuFifo.cs198
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