clean things up and make gpgx fully (?) multi-instance correct

This commit is contained in:
nattthebear 2017-05-28 13:46:08 -04:00
parent 7d0330bb9e
commit 7f2e06b0b5
9 changed files with 226 additions and 147 deletions

View File

@ -7,9 +7,10 @@ using System.Linq;
using System.Text;
using System.Windows.Forms;
using BizHawk.Client.Common;
using BizHawk.Emulation.Cores.Consoles.Sega.gpgx;
using System.Drawing.Imaging;
using BizHawk.Emulation.Common;
using BizHawk.Emulation.Cores.Consoles.Sega.gpgx64;
using BizHawk.Common;
namespace BizHawk.Client.EmuHawk
{
@ -18,7 +19,8 @@ namespace BizHawk.Client.EmuHawk
[RequiredService]
private GPGX Emu { get; set; }
private LibGPGX.VDPView View = new LibGPGX.VDPView();
private GPGX.VDPView View;
int palindex = 0;
protected override System.Drawing.Point ScrollToControl(System.Windows.Forms.Control activeControl)
@ -81,7 +83,7 @@ namespace BizHawk.Client.EmuHawk
bv.Refresh();
}
unsafe void DrawPalettes(int *pal)
unsafe void DrawPalettes(int* pal)
{
var lockdata = bmpViewPal.bmp.LockBits(new Rectangle(0, 0, 16, 4), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
int pitch = lockdata.Stride / sizeof(int);
@ -121,23 +123,24 @@ namespace BizHawk.Client.EmuHawk
public void NewUpdate(ToolFormUpdateType type) { }
public void UpdateValues()
public unsafe void UpdateValues()
{
if (Emu == null)
return;
Emu.UpdateVDPViewContext(View);
unsafe
using ((View = Emu.UpdateVDPViewContext()).EnterExit())
{
int* pal = (int*)View.ColorCache;
//for (int i = 0; i < 0x40; i++)
// pal[i] |= unchecked((int)0xff000000);
DrawPalettes(pal);
DrawTiles();
ushort *VRAMNT = (ushort*)View.VRAM;
byte *tiles = (byte*)View.PatternCache;
ushort* VRAMNT = (ushort*)View.VRAM;
byte* tiles = (byte*)View.PatternCache;
DrawNameTable(View.NTA, VRAMNT, tiles, pal, bmpViewNTA);
DrawNameTable(View.NTB, VRAMNT, tiles, pal, bmpViewNTB);
DrawNameTable(View.NTW, VRAMNT, tiles, pal, bmpViewNTW);
View = null;
}
}

View File

@ -10,7 +10,8 @@ namespace BizHawk.Emulation.Common
public Func<long, byte> Peek
{
get { return _peek; } set { _peek = value; }
get { return _peek; }
set { _peek = value; }
}
public Action<long, byte> Poke
@ -228,4 +229,53 @@ namespace BizHawk.Emulation.Common
WordSize = 2;
}
}
public unsafe class MemoryDomainIntPtrSwap16Monitor : MemoryDomain
{
public IntPtr Data { get; set; }
private readonly IMonitor _monitor;
public override byte PeekByte(long addr)
{
if ((ulong)addr < (ulong)Size)
{
using (_monitor.EnterExit())
{
return ((byte*)Data)[addr ^ 1];
}
}
throw new ArgumentOutOfRangeException(nameof(addr));
}
public override void PokeByte(long addr, byte val)
{
if (Writable)
{
if ((ulong)addr < (ulong)Size)
{
using (_monitor.EnterExit())
{
((byte*)Data)[addr ^ 1] = val;
}
}
else
{
throw new ArgumentOutOfRangeException(nameof(addr));
}
}
}
public MemoryDomainIntPtrSwap16Monitor(string name, Endian endian, IntPtr data, long size, bool writable,
IMonitor monitor)
{
Name = name;
EndianType = endian;
Data = data;
Size = size;
Writable = writable;
WordSize = 2;
_monitor = monitor;
}
}
}

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Runtime.InteropServices;
using BizHawk.Emulation.Common;
using BizHawk.Common;
namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx64
{
@ -12,84 +13,88 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx64
private unsafe void SetMemoryDomains()
{
var mm = new List<MemoryDomain>();
for (int i = LibGPGX.MIN_MEM_DOMAIN; i <= LibGPGX.MAX_MEM_DOMAIN; i++)
using (_elf.EnterExit())
{
IntPtr area = IntPtr.Zero;
int size = 0;
IntPtr pname = Core.gpgx_get_memdom(i, ref area, ref size);
if (area == IntPtr.Zero || pname == IntPtr.Zero || size == 0)
continue;
string name = Marshal.PtrToStringAnsi(pname);
if (name == "VRAM")
var mm = new List<MemoryDomain>();
for (int i = LibGPGX.MIN_MEM_DOMAIN; i <= LibGPGX.MAX_MEM_DOMAIN; i++)
{
// vram pokes need to go through hook which invalidates cached tiles
byte* p = (byte*)area;
mm.Add(new MemoryDomainDelegate(name, size, MemoryDomain.Endian.Unknown,
delegate(long addr)
{
if (addr < 0 || addr >= 65536)
throw new ArgumentOutOfRangeException();
return p[addr ^ 1];
},
delegate(long addr, byte val)
{
if (addr < 0 || addr >= 65536)
throw new ArgumentOutOfRangeException();
Core.gpgx_poke_vram(((int)addr) ^ 1, val);
},
wordSize: 2));
IntPtr area = IntPtr.Zero;
int size = 0;
IntPtr pname = Core.gpgx_get_memdom(i, ref area, ref size);
if (area == IntPtr.Zero || pname == IntPtr.Zero || size == 0)
continue;
string name = Marshal.PtrToStringAnsi(pname);
if (name == "VRAM")
{
// vram pokes need to go through hook which invalidates cached tiles
byte* p = (byte*)area;
mm.Add(new MemoryDomainDelegate(name, size, MemoryDomain.Endian.Unknown,
delegate (long addr)
{
if (addr < 0 || addr >= 65536)
throw new ArgumentOutOfRangeException();
using (_elf.EnterExit())
return p[addr ^ 1];
},
delegate (long addr, byte val)
{
if (addr < 0 || addr >= 65536)
throw new ArgumentOutOfRangeException();
Core.gpgx_poke_vram(((int)addr) ^ 1, val);
},
wordSize: 2));
}
else
{
// TODO: are the Z80 domains really Swap16 in the core? Check this
mm.Add(new MemoryDomainIntPtrSwap16Monitor(name, MemoryDomain.Endian.Big, area, size, name != "MD CART" && name != "CD BOOT ROM", _elf));
}
}
var m68Bus = new MemoryDomainDelegate("M68K BUS", 0x1000000, MemoryDomain.Endian.Big,
delegate (long addr)
{
var a = (uint)addr;
if (a >= 0x1000000)
throw new ArgumentOutOfRangeException();
return Core.gpgx_peek_m68k_bus(a);
},
delegate (long addr, byte val)
{
var a = (uint)addr;
if (a >= 0x1000000)
throw new ArgumentOutOfRangeException();
Core.gpgx_write_m68k_bus(a, val);
}, 2);
mm.Add(m68Bus);
if (IsMegaCD)
{
var s68Bus = new MemoryDomainDelegate("S68K BUS", 0x1000000, MemoryDomain.Endian.Big,
delegate (long addr)
{
var a = (uint)addr;
if (a >= 0x1000000)
throw new ArgumentOutOfRangeException();
return Core.gpgx_peek_s68k_bus(a);
},
delegate (long addr, byte val)
{
var a = (uint)addr;
if (a >= 0x1000000)
throw new ArgumentOutOfRangeException();
Core.gpgx_write_s68k_bus(a, val);
}, 2);
mm.Add(s68Bus);
}
else
{
// TODO: are the Z80 domains really Swap16 in the core? Check this
mm.Add(new MemoryDomainIntPtrSwap16(name, MemoryDomain.Endian.Big, area, size, name != "MD CART" && name != "CD BOOT ROM"));
}
MemoryDomains = new MemoryDomainList(mm);
MemoryDomains.SystemBus = m68Bus;
(ServiceProvider as BasicServiceProvider).Register<IMemoryDomains>(MemoryDomains);
}
var m68Bus = new MemoryDomainDelegate("M68K BUS", 0x1000000, MemoryDomain.Endian.Big,
delegate (long addr)
{
var a = (uint)addr;
if (a >= 0x1000000)
throw new ArgumentOutOfRangeException();
return Core.gpgx_peek_m68k_bus(a);
},
delegate (long addr, byte val)
{
var a = (uint)addr;
if (a >= 0x1000000)
throw new ArgumentOutOfRangeException();
Core.gpgx_write_m68k_bus(a, val);
}, 2);
mm.Add(m68Bus);
var s68Bus = new MemoryDomainDelegate("S68K BUS", 0x1000000, MemoryDomain.Endian.Big,
delegate (long addr)
{
var a = (uint)addr;
if (a >= 0x1000000)
throw new ArgumentOutOfRangeException();
return Core.gpgx_peek_s68k_bus(a);
},
delegate (long addr, byte val)
{
var a = (uint)addr;
if (a >= 0x1000000)
throw new ArgumentOutOfRangeException();
Core.gpgx_write_s68k_bus(a, val);
}, 2);
if (IsMegaCD)
{
mm.Add(s68Bus);
}
MemoryDomains = new MemoryDomainList(mm);
MemoryDomains.SystemBus = m68Bus;
(ServiceProvider as BasicServiceProvider).Register<IMemoryDomains>(MemoryDomains);
}
}
}

View File

@ -4,6 +4,7 @@ using System.IO;
using BizHawk.Common.BufferExtensions;
using BizHawk.Emulation.Common;
using System.Runtime.InteropServices;
using BizHawk.Common;
namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx64
{
@ -17,7 +18,8 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx64
return new byte[0];
byte[] ret = new byte[size];
Marshal.Copy(area, ret, 0, size);
using (_elf.EnterExit())
Marshal.Copy(area, ret, 0, size);
return ret;
}

View File

@ -1,6 +1,7 @@
using System;
using BizHawk.Emulation.Common;
using System.Runtime.InteropServices;
using BizHawk.Common;
namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx64
{
@ -50,7 +51,8 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx64
Core.gpgx_get_audio(ref nsamp, ref src);
if (src != IntPtr.Zero)
{
Marshal.Copy(src, samples, 0, nsamp * 2);
using (_elf.EnterExit())
Marshal.Copy(src, samples, 0, nsamp * 2);
}
}
}

View File

@ -62,9 +62,5 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx64
ms.Close();
return ms.ToArray();
}
private void InitStateBuffers()
{
}
}
}

View File

@ -1,5 +1,6 @@
using System;
using BizHawk.Emulation.Common;
using BizHawk.Common;
namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx64
{
@ -47,38 +48,41 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx64
return;
}
int gppitch, gpwidth, gpheight;
IntPtr src = IntPtr.Zero;
Core.gpgx_get_video(out gpwidth, out gpheight, out gppitch, ref src);
vwidth = gpwidth;
vheight = gpheight;
if (_settings.PadScreen320 && vwidth == 256)
vwidth = 320;
int xpad = (vwidth - gpwidth) / 2;
int xpad2 = vwidth - gpwidth - xpad;
if (vidbuff.Length < vwidth * vheight)
vidbuff = new int[vwidth * vheight];
int rinc = (gppitch / 4) - gpwidth;
fixed (int* pdst_ = vidbuff)
using (_elf.EnterExit())
{
int* pdst = pdst_;
int* psrc = (int*)src;
int gppitch, gpwidth, gpheight;
IntPtr src = IntPtr.Zero;
for (int j = 0; j < gpheight; j++)
Core.gpgx_get_video(out gpwidth, out gpheight, out gppitch, ref src);
vwidth = gpwidth;
vheight = gpheight;
if (_settings.PadScreen320 && vwidth == 256)
vwidth = 320;
int xpad = (vwidth - gpwidth) / 2;
int xpad2 = vwidth - gpwidth - xpad;
if (vidbuff.Length < vwidth * vheight)
vidbuff = new int[vwidth * vheight];
int rinc = (gppitch / 4) - gpwidth;
fixed (int* pdst_ = vidbuff)
{
for (int i = 0; i < xpad; i++)
*pdst++ = unchecked((int)0xff000000);
for (int i = 0; i < gpwidth; i++)
*pdst++ = *psrc++;;
for (int i = 0; i < xpad2; i++)
*pdst++ = unchecked((int)0xff000000);
psrc += rinc;
int* pdst = pdst_;
int* psrc = (int*)src;
for (int j = 0; j < gpheight; j++)
{
for (int i = 0; i < xpad; i++)
*pdst++ = unchecked((int)0xff000000);
for (int i = 0; i < gpwidth; i++)
*pdst++ = *psrc++; ;
for (int i = 0; i < xpad2; i++)
*pdst++ = unchecked((int)0xff000000);
psrc += rinc;
}
}
}
}

View File

@ -5,6 +5,7 @@ using System.Runtime.InteropServices;
using BizHawk.Common.BizInvoke;
using BizHawk.Emulation.Common;
using BizHawk.Emulation.Cores.Waterbox;
using BizHawk.Common;
namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx64
{
@ -40,8 +41,6 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx64
throw new InvalidOperationException("ROM too big! Did you try to load a CD as a ROM?");
}
try
{
_elf = new PeRunner(new PeRunnerOptions
{
Path = comm.CoreFileProvider.DllPath(),
@ -52,11 +51,9 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx64
SpecialHeapSizeKB = 64
});
if (_elf.ShouldMonitor)
Core = BizInvoker.GetInvoker<LibGPGX>(_elf, _elf);
else
Core = BizInvoker.GetInvoker<LibGPGX>(_elf);
Core = BizInvoker.GetInvoker<LibGPGX>(_elf, _elf);
using (_elf.EnterExit())
{
_syncSettings = (GPGXSyncSettings)syncSettings ?? new GPGXSyncSettings();
_settings = (GPGXSettings)settings ?? new GPGXSettings();
@ -110,7 +107,6 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx64
break;
}
if (!Core.gpgx_init(romextension, LoadCallback, _syncSettings.UseSixButton, system_a, system_b, _syncSettings.Region, _settings.GetNativeSettings()))
throw new Exception("gpgx_init() failed");
@ -131,10 +127,6 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx64
_elf.Seal();
Core.gpgx_set_cdd_callback(cd_callback_handle);
// compute state size
InitStateBuffers();
SetControllerDefinition();
// pull the default video size from the core
@ -160,11 +152,6 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx64
Tracer = new GPGXTraceBuffer(this, MemoryDomains, this);
(ServiceProvider as BasicServiceProvider).Register<ITraceable>(Tracer);
}
catch
{
Dispose();
throw;
}
}
private LibGPGX Core;
@ -382,10 +369,46 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx64
public bool IsMegaCD { get { return CD != null; } }
public void UpdateVDPViewContext(LibGPGX.VDPView view)
public class VDPView : IMonitor
{
Core.gpgx_get_vdp_view(view);
private readonly IMonitor _m;
public VDPView(LibGPGX.VDPView v, IMonitor m)
{
_m = m;
VRAM = v.VRAM;
PatternCache = v.PatternCache;
ColorCache = v.ColorCache;
NTA = v.NTA;
NTB = v.NTB;
NTW = v.NTW;
}
public IntPtr VRAM;
public IntPtr PatternCache;
public IntPtr ColorCache;
public LibGPGX.VDPNameTable NTA;
public LibGPGX.VDPNameTable NTB;
public LibGPGX.VDPNameTable NTW;
public void Enter()
{
_m.Enter();
}
public void Exit()
{
_m.Exit();
}
}
public VDPView UpdateVDPViewContext()
{
var v = new LibGPGX.VDPView();
Core.gpgx_get_vdp_view(v);
Core.gpgx_flush_vram(); // fully regenerate internal caches as needed
return new VDPView(v, _elf);
}
public DisplayType Region { get; private set; }

View File

@ -15,9 +15,9 @@ namespace BizHawk.Emulation.Cores.Waterbox
public abstract class Swappable : IMonitor, IDisposable
{
/// <summary>
/// start address, or 0 if we don't need to be swapped
/// start address
/// </summary>
private ulong _lockkey = 0;
private ulong _lockkey;
/// <summary>
/// the the relevant lockinfo for this core
@ -42,17 +42,11 @@ namespace BizHawk.Emulation.Cores.Waterbox
protected void Initialize(ulong lockkey)
{
_lockkey = lockkey;
if (lockkey != 0)
{
_currentLockInfo = LockInfos.GetOrAdd(_lockkey, new LockInfo { Sync = new object() });
}
if (lockkey == 0)
throw new NullReferenceException();
_currentLockInfo = LockInfos.GetOrAdd(_lockkey, new LockInfo { Sync = new object() });
}
/// <summary>
/// true if the IMonitor should be used for native calls
/// </summary>
public bool ShouldMonitor { get { return _lockkey != 0; } }
// any Swappable is assumed to conflict with any other Swappable at the same base address,
// but not any other starting address. so don't put them too close together!