clean things up and make gpgx fully (?) multi-instance correct
This commit is contained in:
parent
7d0330bb9e
commit
7f2e06b0b5
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,9 +62,5 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx64
|
|||
ms.Close();
|
||||
return ms.ToArray();
|
||||
}
|
||||
|
||||
private void InitStateBuffers()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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!
|
||||
|
||||
|
|
Loading…
Reference in New Issue