Some improvements to macro stuff

This commit is contained in:
gdkchan 2018-03-28 16:40:51 -03:00
commit d237bca9a8
5 changed files with 183 additions and 76 deletions

View file

@ -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)

View file

@ -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;
} }

View file

@ -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;
}
} }
} }

View file

@ -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
} }
} }

View file

@ -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]);
} }
} }
} }