pcsx2/tools/GSDumpGUI/Library/GSDXWrapper.cs

472 lines
22 KiB
C#

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.IO;
using TCPLibrary.MessageBased.Core;
using System.Threading;
namespace GSDumpGUI
{
public delegate void GSgifTransfer(IntPtr data, int size);
public delegate void GSgifTransfer1(IntPtr data, int size);
public delegate void GSgifTransfer2(IntPtr data, int size);
public delegate void GSgifTransfer3(IntPtr data, int size);
public delegate void GSVSync(byte field);
public delegate void GSreset();
public delegate void GSreadFIFO2(IntPtr data, int size);
public delegate void GSsetGameCRC(int crc, int options);
public delegate int GSfreeze(int mode, IntPtr data);
public delegate void GSopen(IntPtr hwnd, String Title, int renderer);
public delegate void GSclose();
public delegate void GSshutdown();
public delegate void GSConfigure();
public delegate void GSsetBaseMem(IntPtr data);
public delegate IntPtr PSEgetLibName();
public delegate void GSinit();
public class GSDXWrapper
{
static public bool DumpTooOld = false;
private GSConfigure gsConfigure;
private PSEgetLibName PsegetLibName;
private GSgifTransfer GSgifTransfer;
private GSgifTransfer1 GSgifTransfer1;
private GSgifTransfer2 GSgifTransfer2;
private GSgifTransfer3 GSgifTransfer3;
private GSVSync GSVSync;
private GSreadFIFO2 GSreadFIFO2;
private GSsetGameCRC GSsetGameCRC;
private GSfreeze GSfreeze;
private GSopen GSopen;
private GSclose GSclose;
private GSshutdown GSshutdown;
private GSsetBaseMem GSsetBaseMem;
private GSinit GSinit;
private GSreset GSreset;
private Boolean Loaded;
private String DLL;
private IntPtr DLLAddr;
private Boolean Running;
public Queue<TCPMessage> QueueMessage;
public Boolean DebugMode;
public GSData CurrentGIFPacket;
public bool ThereIsWork;
public AutoResetEvent ExternalEvent;
public int RunTo;
static public Boolean IsValidGSDX(String DLL)
{
NativeMethods.SetErrorMode(0x8007);
Boolean Ris = true;
Directory.SetCurrentDirectory(Path.GetDirectoryName(DLL));
IntPtr hmod = NativeMethods.LoadLibrary(DLL);
if (hmod.ToInt64() > 0)
{
IntPtr funcaddrLibName = NativeMethods.GetProcAddress(hmod, "PS2EgetLibName");
IntPtr funcaddrConfig = NativeMethods.GetProcAddress(hmod, "GSconfigure");
IntPtr funcaddrGIF = NativeMethods.GetProcAddress(hmod, "GSgifTransfer");
IntPtr funcaddrVSync = NativeMethods.GetProcAddress(hmod, "GSvsync");
IntPtr funcaddrSetBaseMem = NativeMethods.GetProcAddress(hmod, "GSsetBaseMem");
IntPtr funcaddrOpen = NativeMethods.GetProcAddress(hmod, "GSopen");
IntPtr funcaddrSetCRC = NativeMethods.GetProcAddress(hmod, "GSsetGameCRC");
IntPtr funcaddrClose = NativeMethods.GetProcAddress(hmod, "GSclose");
IntPtr funcaddrShutdown = NativeMethods.GetProcAddress(hmod, "GSshutdown");
IntPtr funcaddrFreeze = NativeMethods.GetProcAddress(hmod, "GSfreeze");
IntPtr funcaddrGSreadFIFO2 = NativeMethods.GetProcAddress(hmod, "GSreadFIFO2");
IntPtr funcaddrinit = NativeMethods.GetProcAddress(hmod, "GSinit");
NativeMethods.FreeLibrary(hmod);
if (!((funcaddrConfig.ToInt64() > 0) && (funcaddrLibName.ToInt64() > 0) && (funcaddrGIF.ToInt64() > 0)))
{
Int32 id = NativeMethods.GetLastError();
System.IO.File.AppendAllText(AppDomain.CurrentDomain.BaseDirectory + "log.txt", DLL + " failed to load. Error " + id + Environment.NewLine);
Ris = false;
}
}
else
{
Int32 id = NativeMethods.GetLastError();
System.IO.File.AppendAllText(AppDomain.CurrentDomain.BaseDirectory + "log.txt", DLL + " failed to load. Error " + id + Environment.NewLine);
Ris = false;
}
NativeMethods.SetErrorMode(0x0000);
return Ris;
}
public void Load(String DLL)
{
this.DLL = DLL;
NativeMethods.SetErrorMode(0x8007);
if (!IsValidGSDX(DLL))
throw new Exception("Invalid GSDX DLL");
if (Loaded)
Unload();
Loaded = true;
Directory.SetCurrentDirectory(Path.GetDirectoryName(DLL));
IntPtr hmod = NativeMethods.LoadLibrary(DLL);
if (hmod.ToInt64() > 0)
{
IntPtr funcaddrLibName = NativeMethods.GetProcAddress(hmod, "PS2EgetLibName");
IntPtr funcaddrConfig = NativeMethods.GetProcAddress(hmod, "GSconfigure");
IntPtr funcaddrGIF = NativeMethods.GetProcAddress(hmod, "GSgifTransfer");
IntPtr funcaddrGIF1 = NativeMethods.GetProcAddress(hmod, "GSgifTransfer1");
IntPtr funcaddrGIF2 = NativeMethods.GetProcAddress(hmod, "GSgifTransfer2");
IntPtr funcaddrGIF3 = NativeMethods.GetProcAddress(hmod, "GSgifTransfer3");
IntPtr funcaddrVSync = NativeMethods.GetProcAddress(hmod, "GSvsync");
IntPtr funcaddrSetBaseMem = NativeMethods.GetProcAddress(hmod, "GSsetBaseMem");
IntPtr funcaddrGSReset = NativeMethods.GetProcAddress(hmod, "GSreset");
IntPtr funcaddrOpen = NativeMethods.GetProcAddress(hmod, "GSopen");
IntPtr funcaddrSetCRC = NativeMethods.GetProcAddress(hmod, "GSsetGameCRC");
IntPtr funcaddrClose = NativeMethods.GetProcAddress(hmod, "GSclose");
IntPtr funcaddrShutdown = NativeMethods.GetProcAddress(hmod, "GSshutdown");
IntPtr funcaddrFreeze = NativeMethods.GetProcAddress(hmod, "GSfreeze");
IntPtr funcaddrGSreadFIFO2 = NativeMethods.GetProcAddress(hmod, "GSreadFIFO2");
IntPtr funcaddrinit = NativeMethods.GetProcAddress(hmod, "GSinit");
gsConfigure = (GSConfigure)Marshal.GetDelegateForFunctionPointer(funcaddrConfig, typeof(GSConfigure));
PsegetLibName = (PSEgetLibName)Marshal.GetDelegateForFunctionPointer(funcaddrLibName, typeof(PSEgetLibName));
this.GSgifTransfer = (GSgifTransfer)Marshal.GetDelegateForFunctionPointer(funcaddrGIF, typeof(GSgifTransfer));
this.GSgifTransfer1 = (GSgifTransfer1)Marshal.GetDelegateForFunctionPointer(funcaddrGIF1, typeof(GSgifTransfer1));
this.GSgifTransfer2 = (GSgifTransfer2)Marshal.GetDelegateForFunctionPointer(funcaddrGIF2, typeof(GSgifTransfer2));
this.GSgifTransfer3 = (GSgifTransfer3)Marshal.GetDelegateForFunctionPointer(funcaddrGIF3, typeof(GSgifTransfer3));
this.GSVSync = (GSVSync)Marshal.GetDelegateForFunctionPointer(funcaddrVSync, typeof(GSVSync));
this.GSsetBaseMem = (GSsetBaseMem)Marshal.GetDelegateForFunctionPointer(funcaddrSetBaseMem, typeof(GSsetBaseMem));
this.GSopen = (GSopen)Marshal.GetDelegateForFunctionPointer(funcaddrOpen, typeof(GSopen));
this.GSsetGameCRC = (GSsetGameCRC)Marshal.GetDelegateForFunctionPointer(funcaddrSetCRC, typeof(GSsetGameCRC));
this.GSclose = (GSclose)Marshal.GetDelegateForFunctionPointer(funcaddrClose, typeof(GSclose));
this.GSshutdown = (GSshutdown)Marshal.GetDelegateForFunctionPointer(funcaddrShutdown, typeof(GSshutdown));
this.GSfreeze = (GSfreeze)Marshal.GetDelegateForFunctionPointer(funcaddrFreeze, typeof(GSfreeze));
this.GSreset = (GSreset)Marshal.GetDelegateForFunctionPointer(funcaddrGSReset, typeof(GSreset));
this.GSreadFIFO2 = (GSreadFIFO2)Marshal.GetDelegateForFunctionPointer(funcaddrGSreadFIFO2, typeof(GSreadFIFO2));
this.GSinit = (GSinit)Marshal.GetDelegateForFunctionPointer(funcaddrinit, typeof(GSinit));
DLLAddr = hmod;
}
NativeMethods.SetErrorMode(0x0000);
}
public void Unload()
{
NativeMethods.FreeLibrary(DLLAddr);
Loaded = false;
}
public void GSConfig()
{
if (!Loaded)
throw new Exception("GSDX is not loaded");
gsConfigure.Invoke();
}
public String PSEGetLibName()
{
if (!Loaded)
throw new Exception("GSDX is not loaded");
return Marshal.PtrToStringAnsi(PsegetLibName.Invoke());
}
public unsafe void Run(GSDump dump, int rendererOverride)
{
QueueMessage = new Queue<TCPMessage>();
Running = true;
ExternalEvent = new AutoResetEvent(true);
GSinit();
byte[] tempregisters = new byte[8192];
Array.Copy(dump.Registers, tempregisters, 8192);
fixed (byte* pointer = tempregisters)
{
GSsetBaseMem(new IntPtr(pointer));
Int32 HWND = 0;
GSopen(new IntPtr(&HWND), "", rendererOverride);
GSsetGameCRC(dump.CRC, 0);
fixed (byte* freeze = dump.StateData)
{
byte[] GSFreez = new byte[8];
Array.Copy(BitConverter.GetBytes(dump.StateData.Length), 0, GSFreez, 0, 4);
Array.Copy(BitConverter.GetBytes(new IntPtr(freeze).ToInt32()), 0, GSFreez, 4, 4);
fixed (byte* fr = GSFreez)
{
int ris = GSfreeze(0, new IntPtr(fr));
if (ris == -1)
{
DumpTooOld = true;
return;
}
GSVSync(1);
while (Running)
{
if (!NativeMethods.IsWindowVisible(new IntPtr(HWND)))
{
Running = false;
break;
}
GSreset();
Marshal.Copy(dump.Registers, 0, new IntPtr(pointer), 8192);
GSsetBaseMem(new IntPtr(pointer));
GSfreeze(0, new IntPtr(fr));
for (int i = 0; i < dump.Data.Count; i++)
{
GSData itm = dump.Data[i];
CurrentGIFPacket = itm;
if (DebugMode)
{
if (RunTo != -1)
{
if (i == RunTo)
{
RunTo = -1;
int idxnextReg = dump.Data.FindIndex(i, a => a.id == GSType.Registers);
if (idxnextReg != -1)
{
Step(dump.Data[idxnextReg], pointer);
}
GSData g = new GSData();
g.id = GSType.VSync;
Step(g, pointer);
TCPMessage Msg = new TCPMessage();
Msg.MessageType = MessageType.RunToCursor;
Msg.Parameters.Add(i);
Program.Client.Send(Msg);
ExternalEvent.Set();
}
else
{
Step(itm, pointer);
}
}
else
{
while (!ThereIsWork && Running)
{
NativeMessage message;
while (NativeMethods.PeekMessage(out message, IntPtr.Zero, 0, 0, 1))
{
if (!NativeMethods.IsWindowVisible(new IntPtr(HWND)))
{
Running = false;
}
NativeMethods.TranslateMessage(ref message);
NativeMethods.DispatchMessage(ref message);
}
}
ThereIsWork = false;
if (QueueMessage.Count > 0)
{
TCPMessage Mess = QueueMessage.Dequeue();
switch (Mess.MessageType)
{
case MessageType.Step:
RunTo = i;
break;
case MessageType.RunToCursor:
RunTo = (int)Mess.Parameters[0];
break;
case MessageType.RunToNextVSync:
RunTo = dump.Data.FindIndex(i, a => a.id == GSType.VSync);
break;
default:
break;
}
break;
}
}
}
else
{
Step(itm, pointer);
}
}
}
GSclose();
GSshutdown();
}
}
}
}
private unsafe void Step(GSData itm, byte* registers)
{
/*"C:\Users\Alessio\Desktop\Plugins\Dll\GSdx-SSE4.dll" "C:\Users\Alessio\Desktop\Plugins\Dumps\gsdx_20101222215004.gs" "GSReplay" 0*/
switch (itm.id)
{
case GSType.Transfer:
switch (((GSTransfer)itm).Path)
{
case GSTransferPath.Path1Old:
byte[] data = new byte[16384];
int addr = 16384 - itm.data.Length;
Array.Copy(itm.data, 0, data, addr, itm.data.Length);
fixed (byte* gifdata = data)
{
GSgifTransfer1(new IntPtr(gifdata), addr);
}
break;
case GSTransferPath.Path2:
fixed (byte* gifdata = itm.data)
{
GSgifTransfer2(new IntPtr(gifdata), (itm.data.Length) / 16);
}
break;
case GSTransferPath.Path3:
fixed (byte* gifdata = itm.data)
{
GSgifTransfer3(new IntPtr(gifdata), (itm.data.Length) / 16);
}
break;
case GSTransferPath.Path1New:
fixed (byte* gifdata = itm.data)
{
GSgifTransfer(new IntPtr(gifdata), (itm.data.Length) / 16);
}
break;
}
break;
case GSType.VSync:
GSVSync((*((int*)(registers + 4096)) & 0x2000) > 0 ? (byte)1 : (byte)0);
break;
case GSType.ReadFIFO2:
fixed (byte* FIFO = itm.data)
{
byte[] arrnew = new byte[*((int*)FIFO)];
fixed (byte* arrn = arrnew)
{
GSreadFIFO2(new IntPtr(arrn), *((int*)FIFO));
}
}
break;
case GSType.Registers:
Marshal.Copy(itm.data, 0, new IntPtr(registers), 8192);
break;
default:
break;
}
}
public void Stop()
{
Running = false;
}
internal List<Object> GetGifPackets(GSDump dump)
{
List<Object> Data = new List<Object>();
for (int i = 0; i < dump.Data.Count; i++)
{
String act = i.ToString() + "|";
act += dump.Data[i].id.ToString() + "|";
if (dump.Data[i].GetType().IsSubclassOf(typeof(GSData)))
{
act += ((GSTransfer)dump.Data[i]).Path.ToString() + "|";
act += ((GSTransfer)dump.Data[i]).data.Length;
}
else
{
act += ((GSData)dump.Data[i]).data.Length;
}
Data.Add(act);
}
return Data;
}
internal String GetGifPacketInfo(GSDump dump, int i)
{
string val = dump.Data[i].data.Length.ToString() + "|";
switch (dump.Data[i].id)
{
case GSType.Transfer:
GIFTag tag = ExtractGifTag(dump.Data[i].data);
val += "Transfer Path " + ((GSTransfer)dump.Data[i]).Path.ToString() + "|";
val += "NLoop = " + tag.nloop + "|";
//val += "Pad1 = " + tag._pad1 + "|";
//val += "Pad2 = " + tag._pad2 + "|";
val += "eop = " + tag.eop + "|";
val += "flg = " + ((GIFFLG)tag.flg).ToString() + "|";
val += "pre = " + tag.pre + "|";
val += "prim~Prim Class = " + ((GS_PRIM)tag.prim.Prim).ToString() + "~IIP = " + tag.prim.IIP + "~TME = "+ tag.prim.TME + "~FGE = "+ tag.prim.FGE + "~ABE = "+
tag.prim.ABE + "~AA1 = "+ tag.prim.AA1 + "~FST = "+ tag.prim.FST + "~CTXT = " + tag.prim.CTXT + "~FIX = " + tag.prim.FIX + "|";
val += "nreg = " + tag.nreg + "|";
val += "regs = " + (tag.regs == 0 ? 16 : tag.regs);
break;
case GSType.VSync:
val += "Field = " + dump.Data[i].data[0].ToString();
break;
case GSType.ReadFIFO2:
val += "ReadFIFO2 : Size = " + BitConverter.ToInt32(dump.Data[i].data, 0).ToString() + " byte";
break;
case GSType.Registers:
val += "Registers";
break;
default:
break;
}
return val;
}
internal GIFTag ExtractGifTag(byte[] data)
{
Int16 nloopEOP = 0;
Int16 pad1 = 0;
Int32 pad2PrePrimFlgNReg = 0;
Int64 regs = 0;
nloopEOP = BitConverter.ToInt16(data, 0);
pad1 = BitConverter.ToInt16(data, 2);
pad2PrePrimFlgNReg = BitConverter.ToInt32(data, 4);
regs = BitConverter.ToInt64(data, 8);
GIFTag t = new GIFTag();
t.nloop = (nloopEOP & 0x7FFF);
t.eop = (nloopEOP & 0x8000) >> 15;
t._pad1 = pad1;
t._pad2 = (pad2PrePrimFlgNReg & 0x00003FFF);
t.pre = (pad2PrePrimFlgNReg & 0x00004000) >> 14;
int prim = (pad2PrePrimFlgNReg & 0x03FF8000) >> 15;
GIFPrim pri = new GIFPrim();
pri.Prim = (prim & 0x007);
pri.IIP = (prim & 0x008) >> 3;
pri.TME = (prim & 0x010) >> 4;
pri.FGE = (prim & 0x020) >> 5;
pri.ABE = (prim & 0x040) >> 6;
pri.AA1 = (prim & 0x080) >> 7;
pri.FST = (prim & 0x100) >> 8;
pri.CTXT = (prim & 0x200) >> 9;
pri.FIX = (prim & 0x400) >> 10;
t.prim = pri;
t.flg = (pad2PrePrimFlgNReg & 0xC000000) >> 26;
t.nreg = (int)(pad2PrePrimFlgNReg & 0xF0000000) >> 28;
t.regs = regs;
return t;
}
}
}