Some improvements to macro stuff
This commit is contained in:
parent
2c59418406
commit
d237bca9a8
5 changed files with 183 additions and 76 deletions
|
@ -77,16 +77,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
|
||||||
public void SetConstBuffer(int Cbuf, byte[] Data)
|
public void SetConstBuffer(int Cbuf, byte[] Data)
|
||||||
{
|
{
|
||||||
if (Cbuf != 3) return;
|
|
||||||
|
|
||||||
Console.WriteLine("cb: " + Cbuf);
|
|
||||||
|
|
||||||
foreach (byte b in Data)
|
|
||||||
{
|
|
||||||
Console.Write(b.ToString("x2") + " ");
|
|
||||||
}
|
|
||||||
|
|
||||||
Console.WriteLine();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Bind(long Tag)
|
public void Bind(long Tag)
|
||||||
|
|
|
@ -6,6 +6,7 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
{
|
{
|
||||||
class MacroInterpreter
|
class MacroInterpreter
|
||||||
{
|
{
|
||||||
|
private NvGpuFifo PFifo;
|
||||||
private INvGpuEngine Engine;
|
private INvGpuEngine Engine;
|
||||||
|
|
||||||
public Queue<int> Fifo { get; private set; }
|
public Queue<int> Fifo { get; private set; }
|
||||||
|
@ -19,8 +20,9 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
|
|
||||||
private long Pc;
|
private long Pc;
|
||||||
|
|
||||||
public MacroInterpreter(INvGpuEngine Engine)
|
public MacroInterpreter(NvGpuFifo PFifo, INvGpuEngine Engine)
|
||||||
{
|
{
|
||||||
|
this.PFifo = PFifo;
|
||||||
this.Engine = Engine;
|
this.Engine = Engine;
|
||||||
|
|
||||||
Fifo = new Queue<int>();
|
Fifo = new Queue<int>();
|
||||||
|
@ -60,7 +62,7 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
|
|
||||||
Pc += 4;
|
Pc += 4;
|
||||||
|
|
||||||
int Op = (OpCode >> 0) & 7;
|
int Op = OpCode & 7;
|
||||||
|
|
||||||
if (Op < 7)
|
if (Op < 7)
|
||||||
{
|
{
|
||||||
|
@ -106,9 +108,15 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
: GetGprA(OpCode) == 0;
|
: GetGprA(OpCode) == 0;
|
||||||
|
|
||||||
if (Taken)
|
if (Taken)
|
||||||
|
{
|
||||||
|
bool KeepExecuting = true;
|
||||||
|
|
||||||
|
//When bit 5 is set, branches executes as if delay slots didn't exist.
|
||||||
|
if ((OpCode & 0x20) == 0)
|
||||||
{
|
{
|
||||||
//Execute one more instruction due to delay slot.
|
//Execute one more instruction due to delay slot.
|
||||||
bool KeepExecuting = Step(Memory);
|
KeepExecuting = Step(Memory);
|
||||||
|
}
|
||||||
|
|
||||||
Pc = BaseAddr + (GetImm(OpCode) << 2);
|
Pc = BaseAddr + (GetImm(OpCode) << 2);
|
||||||
|
|
||||||
|
@ -166,7 +174,7 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
//Bitfield move.
|
//Bitfield move.
|
||||||
case 2:
|
case 2:
|
||||||
{
|
{
|
||||||
Src = (Src >> BfSrcBit) & BfMask;
|
Src = (int)((uint)Src >> BfSrcBit) & BfMask;
|
||||||
|
|
||||||
Dst &= ~(BfMask << BfDstBit);
|
Dst &= ~(BfMask << BfDstBit);
|
||||||
|
|
||||||
|
@ -178,7 +186,7 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
//Bitfield extract with left shift by immediate.
|
//Bitfield extract with left shift by immediate.
|
||||||
case 3:
|
case 3:
|
||||||
{
|
{
|
||||||
Src = (Src >> Dst) & BfMask;
|
Src = (int)((uint)Src >> Dst) & BfMask;
|
||||||
|
|
||||||
return Src << BfDstBit;
|
return Src << BfDstBit;
|
||||||
}
|
}
|
||||||
|
@ -186,7 +194,7 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
//Bitfield extract with left shift by register.
|
//Bitfield extract with left shift by register.
|
||||||
case 4:
|
case 4:
|
||||||
{
|
{
|
||||||
Src = (Src >> BfSrcBit) & BfMask;
|
Src = (int)((uint)Src >> BfSrcBit) & BfMask;
|
||||||
|
|
||||||
return Src << Dst;
|
return Src << Dst;
|
||||||
}
|
}
|
||||||
|
@ -204,9 +212,9 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
throw new ArgumentException(nameof(OpCode));
|
throw new ArgumentException(nameof(OpCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
private int GetAluResult(int SubOp, int A, int B)
|
private int GetAluResult(int AluOp, int A, int B)
|
||||||
{
|
{
|
||||||
switch (SubOp)
|
switch (AluOp)
|
||||||
{
|
{
|
||||||
//Add.
|
//Add.
|
||||||
case 0: return A + B;
|
case 0: return A + B;
|
||||||
|
@ -254,7 +262,7 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
case 12: return ~(A & B);
|
case 12: return ~(A & B);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ArgumentOutOfRangeException(nameof(SubOp));
|
throw new ArgumentOutOfRangeException(nameof(AluOp));
|
||||||
}
|
}
|
||||||
|
|
||||||
private int GetImm(int OpCode)
|
private int GetImm(int OpCode)
|
||||||
|
@ -291,7 +299,17 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
|
|
||||||
private int FetchParam()
|
private int FetchParam()
|
||||||
{
|
{
|
||||||
Fifo.TryDequeue(out int Value);
|
int Value;
|
||||||
|
|
||||||
|
//If we don't have any parameters in the FIFO,
|
||||||
|
//keep running the PFIFO engine until it writes the parameters.
|
||||||
|
while (!Fifo.TryDequeue(out Value))
|
||||||
|
{
|
||||||
|
if (!PFifo.Step())
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return Value;
|
return Value;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,35 +11,64 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
|
|
||||||
private Dictionary<int, NvGpuMethod> Methods;
|
private Dictionary<int, NvGpuMethod> Methods;
|
||||||
|
|
||||||
|
private struct ConstBuffer
|
||||||
|
{
|
||||||
|
public bool Enabled;
|
||||||
|
public long Position;
|
||||||
|
public int Size;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ConstBuffer[] Cbs;
|
||||||
|
|
||||||
public NvGpuEngine3d(NsGpu Gpu)
|
public NvGpuEngine3d(NsGpu Gpu)
|
||||||
{
|
{
|
||||||
this.Gpu = Gpu;
|
this.Gpu = Gpu;
|
||||||
|
|
||||||
Registers = new int[0xe00];
|
Registers = new int[0xe00];
|
||||||
|
|
||||||
Methods = new Dictionary<int, NvGpuMethod>()
|
Methods = new Dictionary<int, NvGpuMethod>();
|
||||||
|
|
||||||
|
void AddMethod(int Meth, int Count, int Stride, NvGpuMethod Method)
|
||||||
{
|
{
|
||||||
{ 0x6c3, QueryControl }
|
while (Count-- > 0)
|
||||||
};
|
{
|
||||||
|
Methods.Add(Meth, Method);
|
||||||
|
|
||||||
|
Meth += Stride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AddMethod(0x585, 1, 1, VertexEndGl);
|
||||||
|
AddMethod(0x6c3, 1, 1, QueryControl);
|
||||||
|
AddMethod(0x8e4, 16, 1, CbData);
|
||||||
|
AddMethod(0x904, 1, 1, CbBind);
|
||||||
|
|
||||||
|
Cbs = new ConstBuffer[18];
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CallMethod(AMemory Memory, NsGpuPBEntry PBEntry)
|
public void CallMethod(AMemory Memory, NsGpuPBEntry PBEntry)
|
||||||
{
|
{
|
||||||
if (Methods.TryGetValue(PBEntry.Method, out NvGpuMethod Methd))
|
if (Methods.TryGetValue(PBEntry.Method, out NvGpuMethod Method))
|
||||||
{
|
{
|
||||||
Methd(Memory, PBEntry);
|
Method(Memory, PBEntry);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WriteRegister(PBEntry);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PBEntry.Arguments.Count == 1)
|
private void VertexEndGl(AMemory Memory, NsGpuPBEntry PBEntry)
|
||||||
{
|
{
|
||||||
Registers[PBEntry.Method] = PBEntry.Arguments[0];
|
int TexCbuf = ReadRegister(NvGpuEngine3dReg.TextureCbIndex);
|
||||||
}
|
|
||||||
|
int TexHandle = ReadCb(Memory, TexCbuf, 0x20);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void QueryControl(AMemory Memory, NsGpuPBEntry PBEntry)
|
private void QueryControl(AMemory Memory, NsGpuPBEntry PBEntry)
|
||||||
{
|
{
|
||||||
long Position = MakeAddress(NvGpuEngine3dReg.QueryAddr);
|
if (TryGetCpuAddr(NvGpuEngine3dReg.QueryAddr, out long Position))
|
||||||
|
{
|
||||||
int Seq = Registers[(int)NvGpuEngine3dReg.QuerySequence];
|
int Seq = Registers[(int)NvGpuEngine3dReg.QuerySequence];
|
||||||
int Ctrl = Registers[(int)NvGpuEngine3dReg.QueryControl];
|
int Ctrl = Registers[(int)NvGpuEngine3dReg.QueryControl];
|
||||||
|
|
||||||
|
@ -48,20 +77,90 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
if (Mode == 0)
|
if (Mode == 0)
|
||||||
{
|
{
|
||||||
//Write.
|
//Write.
|
||||||
Position = Gpu.MemoryMgr.GetCpuAddr(Position);
|
|
||||||
|
|
||||||
if (Position != -1)
|
|
||||||
{
|
|
||||||
Memory.WriteInt32(Position, Seq);
|
Memory.WriteInt32(Position, Seq);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WriteRegister(PBEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
private long MakeAddress(NvGpuEngine3dReg Reg)
|
private void CbData(AMemory Memory, NsGpuPBEntry PBEntry)
|
||||||
|
{
|
||||||
|
if (TryGetCpuAddr(NvGpuEngine3dReg.CbAddress, out long Position))
|
||||||
|
{
|
||||||
|
int Offset = ReadRegister(NvGpuEngine3dReg.CbOffset);
|
||||||
|
|
||||||
|
foreach (int Arg in PBEntry.Arguments)
|
||||||
|
{
|
||||||
|
Memory.WriteInt32(Position + Offset, Arg);
|
||||||
|
|
||||||
|
Offset += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
WriteRegister(NvGpuEngine3dReg.CbOffset, Offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CbBind(AMemory Memory, NsGpuPBEntry PBEntry)
|
||||||
|
{
|
||||||
|
int Index = PBEntry.Arguments[0];
|
||||||
|
|
||||||
|
bool Enabled = (Index & 1) != 0;
|
||||||
|
|
||||||
|
Index = (Index >> 4) & 0x1f;
|
||||||
|
|
||||||
|
if (TryGetCpuAddr(NvGpuEngine3dReg.CbAddress, out long Position))
|
||||||
|
{
|
||||||
|
Cbs[Index].Position = Position;
|
||||||
|
}
|
||||||
|
|
||||||
|
Cbs[Index].Enabled = Enabled;
|
||||||
|
Cbs[Index].Size = ReadRegister(NvGpuEngine3dReg.CbSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int ReadCb(AMemory Memory, int Cbuf, int Offset)
|
||||||
|
{
|
||||||
|
long Position = Cbs[Cbuf].Position;
|
||||||
|
|
||||||
|
int Value = Memory.ReadInt32(Position + Offset);
|
||||||
|
|
||||||
|
return Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool TryGetCpuAddr(NvGpuEngine3dReg Reg, out long Position)
|
||||||
|
{
|
||||||
|
Position = MakeInt64From2xInt32(Reg);
|
||||||
|
|
||||||
|
Position = Gpu.GetCpuAddr(Position);
|
||||||
|
|
||||||
|
return Position != -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private long MakeInt64From2xInt32(NvGpuEngine3dReg Reg)
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
(long)Registers[(int)Reg + 0] << 32 |
|
(long)Registers[(int)Reg + 0] << 32 |
|
||||||
(uint)Registers[(int)Reg + 1];
|
(uint)Registers[(int)Reg + 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void WriteRegister(NsGpuPBEntry PBEntry)
|
||||||
|
{
|
||||||
|
int ArgsCount = PBEntry.Arguments.Count;
|
||||||
|
|
||||||
|
if (ArgsCount > 0)
|
||||||
|
{
|
||||||
|
Registers[PBEntry.Method] = PBEntry.Arguments[ArgsCount - 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int ReadRegister(NvGpuEngine3dReg Reg)
|
||||||
|
{
|
||||||
|
return Registers[(int)Reg];
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WriteRegister(NvGpuEngine3dReg Reg, int Value)
|
||||||
|
{
|
||||||
|
Registers[(int)Reg] = Value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -4,6 +4,10 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
{
|
{
|
||||||
QueryAddr = 0x6c0,
|
QueryAddr = 0x6c0,
|
||||||
QuerySequence = 0x6c2,
|
QuerySequence = 0x6c2,
|
||||||
QueryControl = 0x6c3
|
QueryControl = 0x6c3,
|
||||||
|
CbSize = 0x8e0,
|
||||||
|
CbAddress = 0x8e1,
|
||||||
|
CbOffset = 0x8e3,
|
||||||
|
TextureCbIndex = 0x982
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -11,7 +11,7 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
|
|
||||||
private NsGpu Gpu;
|
private NsGpu Gpu;
|
||||||
|
|
||||||
private ConcurrentQueue<(AMemory, NsGpuPBEntry[])> BufferQueue;
|
private ConcurrentQueue<(AMemory, NsGpuPBEntry)> BufferQueue;
|
||||||
|
|
||||||
private NvGpuEngine[] SubChannels;
|
private NvGpuEngine[] SubChannels;
|
||||||
|
|
||||||
|
@ -21,11 +21,11 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
|
|
||||||
private MacroInterpreter Interpreter;
|
private MacroInterpreter Interpreter;
|
||||||
|
|
||||||
public CachedMacro(INvGpuEngine Engine, long Position)
|
public CachedMacro(NvGpuFifo PFifo, INvGpuEngine Engine, long Position)
|
||||||
{
|
{
|
||||||
this.Position = Position;
|
this.Position = Position;
|
||||||
|
|
||||||
Interpreter = new MacroInterpreter(Engine);
|
Interpreter = new MacroInterpreter(PFifo, Engine);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void PushParam(int Param)
|
public void PushParam(int Param)
|
||||||
|
@ -39,50 +39,45 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private long CurrentMacroPosition;
|
private long CurrMacroPosition;
|
||||||
private int CurrentMacroBindIndex;
|
private int CurrMacroBindIndex;
|
||||||
|
|
||||||
private CachedMacro[] Macros;
|
private CachedMacro[] Macros;
|
||||||
|
|
||||||
private Queue<(int, int)> MacroQueue;
|
|
||||||
|
|
||||||
public NvGpuFifo(NsGpu Gpu)
|
public NvGpuFifo(NsGpu Gpu)
|
||||||
{
|
{
|
||||||
this.Gpu = Gpu;
|
this.Gpu = Gpu;
|
||||||
|
|
||||||
BufferQueue = new ConcurrentQueue<(AMemory, NsGpuPBEntry[])>();
|
BufferQueue = new ConcurrentQueue<(AMemory, NsGpuPBEntry)>();
|
||||||
|
|
||||||
SubChannels = new NvGpuEngine[8];
|
SubChannels = new NvGpuEngine[8];
|
||||||
|
|
||||||
Macros = new CachedMacro[MacrosCount];
|
Macros = new CachedMacro[MacrosCount];
|
||||||
|
|
||||||
MacroQueue = new Queue<(int, int)>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void PushBuffer(AMemory Memory, NsGpuPBEntry[] Buffer)
|
public void PushBuffer(AMemory Memory, NsGpuPBEntry[] Buffer)
|
||||||
{
|
{
|
||||||
BufferQueue.Enqueue((Memory, Buffer));
|
foreach (NsGpuPBEntry PBEntry in Buffer)
|
||||||
|
{
|
||||||
|
BufferQueue.Enqueue((Memory, PBEntry));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DispatchCalls()
|
public void DispatchCalls()
|
||||||
{
|
{
|
||||||
while (BufferQueue.TryDequeue(out (AMemory Memory, NsGpuPBEntry[] Buffer) Tuple))
|
while (Step());
|
||||||
{
|
|
||||||
foreach (NsGpuPBEntry PBEntry in Tuple.Buffer)
|
|
||||||
{
|
|
||||||
CallMethod(Tuple.Memory, PBEntry);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ExecuteMacros(Tuple.Memory);
|
public bool Step()
|
||||||
}
|
{
|
||||||
|
if (BufferQueue.TryDequeue(out (AMemory Memory, NsGpuPBEntry PBEntry) Tuple))
|
||||||
|
{
|
||||||
|
CallMethod(Tuple.Memory, Tuple.PBEntry);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ExecuteMacros(AMemory Memory)
|
return false;
|
||||||
{
|
|
||||||
while (MacroQueue.TryDequeue(out (int Index, int Param) Tuple))
|
|
||||||
{
|
|
||||||
Macros[Tuple.Index].Execute(Memory, Tuple.Param);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CallMethod(AMemory Memory, NsGpuPBEntry PBEntry)
|
private void CallMethod(AMemory Memory, NsGpuPBEntry PBEntry)
|
||||||
|
@ -102,20 +97,20 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
|
|
||||||
case NvGpuFifoMeth.SetMacroUploadAddress:
|
case NvGpuFifoMeth.SetMacroUploadAddress:
|
||||||
{
|
{
|
||||||
CurrentMacroPosition = (long)((ulong)PBEntry.Arguments[0] << 2);
|
CurrMacroPosition = (long)((ulong)PBEntry.Arguments[0] << 2);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case NvGpuFifoMeth.SendMacroCodeData:
|
case NvGpuFifoMeth.SendMacroCodeData:
|
||||||
{
|
{
|
||||||
long Position = Gpu.GetCpuAddr(CurrentMacroPosition);
|
long Position = Gpu.GetCpuAddr(CurrMacroPosition);
|
||||||
|
|
||||||
foreach (int Arg in PBEntry.Arguments)
|
foreach (int Arg in PBEntry.Arguments)
|
||||||
{
|
{
|
||||||
Memory.WriteInt32(Position, Arg);
|
Memory.WriteInt32(Position, Arg);
|
||||||
|
|
||||||
CurrentMacroPosition += 4;
|
CurrMacroPosition += 4;
|
||||||
|
|
||||||
Position += 4;
|
Position += 4;
|
||||||
}
|
}
|
||||||
|
@ -124,7 +119,7 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
|
|
||||||
case NvGpuFifoMeth.SetMacroBindingIndex:
|
case NvGpuFifoMeth.SetMacroBindingIndex:
|
||||||
{
|
{
|
||||||
CurrentMacroBindIndex = PBEntry.Arguments[0];
|
CurrMacroBindIndex = PBEntry.Arguments[0];
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -135,7 +130,7 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
|
|
||||||
Position = Gpu.GetCpuAddr(Position);
|
Position = Gpu.GetCpuAddr(Position);
|
||||||
|
|
||||||
Macros[CurrentMacroBindIndex] = new CachedMacro(Gpu.Engine3d, Position);
|
Macros[CurrMacroBindIndex] = new CachedMacro(this, Gpu.Engine3d, Position);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -169,7 +164,7 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MacroQueue.Enqueue((MacroIndex, PBEntry.Arguments[0]));
|
Macros[MacroIndex].Execute(Memory, PBEntry.Arguments[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue