From 7f2e06b0b5f4efd35d561663d983ef724fcb199e Mon Sep 17 00:00:00 2001 From: nattthebear Date: Sun, 28 May 2017 13:46:08 -0400 Subject: [PATCH] clean things up and make gpgx fully (?) multi-instance correct --- .../tools/Genesis/VDPViewer.cs | 19 ++- .../Base Implementations/MemoryDomainImpls.cs | 52 +++++- .../Sega/gpgx64/GPGX.IMemoryDomains.cs | 151 +++++++++--------- .../Consoles/Sega/gpgx64/GPGX.ISaveRam.cs | 4 +- .../Sega/gpgx64/GPGX.ISoundProvider.cs | 4 +- .../Consoles/Sega/gpgx64/GPGX.IStatable.cs | 4 - .../Sega/gpgx64/GPGX.IVideoProvider.cs | 62 +++---- .../Consoles/Sega/gpgx64/GPGX.cs | 61 ++++--- BizHawk.Emulation.Cores/Waterbox/Swappable.cs | 16 +- 9 files changed, 226 insertions(+), 147 deletions(-) diff --git a/BizHawk.Client.EmuHawk/tools/Genesis/VDPViewer.cs b/BizHawk.Client.EmuHawk/tools/Genesis/VDPViewer.cs index 1f7c619657..8c39dc5cc8 100644 --- a/BizHawk.Client.EmuHawk/tools/Genesis/VDPViewer.cs +++ b/BizHawk.Client.EmuHawk/tools/Genesis/VDPViewer.cs @@ -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; } } diff --git a/BizHawk.Emulation.Common/Base Implementations/MemoryDomainImpls.cs b/BizHawk.Emulation.Common/Base Implementations/MemoryDomainImpls.cs index ede698f122..6a80b62c62 100644 --- a/BizHawk.Emulation.Common/Base Implementations/MemoryDomainImpls.cs +++ b/BizHawk.Emulation.Common/Base Implementations/MemoryDomainImpls.cs @@ -10,7 +10,8 @@ namespace BizHawk.Emulation.Common public Func Peek { - get { return _peek; } set { _peek = value; } + get { return _peek; } + set { _peek = value; } } public Action 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; + } + } } diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.IMemoryDomains.cs b/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.IMemoryDomains.cs index 948aff16af..e8375ccc50 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.IMemoryDomains.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.IMemoryDomains.cs @@ -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(); - 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(); + 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(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(MemoryDomains); } } } diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.ISaveRam.cs b/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.ISaveRam.cs index 2f84bf6039..7578261d9c 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.ISaveRam.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.ISaveRam.cs @@ -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; } diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.ISoundProvider.cs b/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.ISoundProvider.cs index f979cd11bf..a85fc9ac06 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.ISoundProvider.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.ISoundProvider.cs @@ -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); } } } diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.IStatable.cs b/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.IStatable.cs index 812a540ebc..41337dfd89 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.IStatable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.IStatable.cs @@ -62,9 +62,5 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx64 ms.Close(); return ms.ToArray(); } - - private void InitStateBuffers() - { - } } } diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.IVideoProvider.cs b/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.IVideoProvider.cs index b432d9b65f..0432d4d4f5 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.IVideoProvider.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.IVideoProvider.cs @@ -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; + } } } } diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.cs b/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.cs index 74b0ad6190..6abca8fa24 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.cs @@ -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(_elf, _elf); - else - Core = BizInvoker.GetInvoker(_elf); - + Core = BizInvoker.GetInvoker(_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(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; } diff --git a/BizHawk.Emulation.Cores/Waterbox/Swappable.cs b/BizHawk.Emulation.Cores/Waterbox/Swappable.cs index dfa5e484b8..cff108ada9 100644 --- a/BizHawk.Emulation.Cores/Waterbox/Swappable.cs +++ b/BizHawk.Emulation.Cores/Waterbox/Swappable.cs @@ -15,9 +15,9 @@ namespace BizHawk.Emulation.Cores.Waterbox public abstract class Swappable : IMonitor, IDisposable { /// - /// start address, or 0 if we don't need to be swapped + /// start address /// - private ulong _lockkey = 0; + private ulong _lockkey; /// /// 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() }); } - /// - /// true if the IMonitor should be used for native calls - /// - 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!