update snes9x to use WaterboxCore
This commit is contained in:
parent
3e731ae0b3
commit
c04beea4d0
|
@ -4,30 +4,12 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using BizHawk.Common.BizInvoke;
|
using BizHawk.Common.BizInvoke;
|
||||||
|
using BizHawk.Emulation.Cores.Waterbox;
|
||||||
|
|
||||||
namespace BizHawk.Emulation.Cores.Nintendo.SNES9X
|
namespace BizHawk.Emulation.Cores.Nintendo.SNES9X
|
||||||
{
|
{
|
||||||
public abstract class LibSnes9x
|
public abstract class LibSnes9x : LibWaterboxCore
|
||||||
{
|
{
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
|
||||||
public class memory_area
|
|
||||||
{
|
|
||||||
public IntPtr ptr;
|
|
||||||
public int size;
|
|
||||||
};
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
|
||||||
public class frame_info
|
|
||||||
{
|
|
||||||
public IntPtr vptr;
|
|
||||||
public int vpitch;
|
|
||||||
public int vwidth;
|
|
||||||
public int vheight;
|
|
||||||
public IntPtr sptr;
|
|
||||||
public int slen;
|
|
||||||
public int padread;
|
|
||||||
};
|
|
||||||
|
|
||||||
public enum LeftPortDevice : uint
|
public enum LeftPortDevice : uint
|
||||||
{
|
{
|
||||||
//None = 0, // something in the libretro spaghetti input goes wonky with None
|
//None = 0, // something in the libretro spaghetti input goes wonky with None
|
||||||
|
@ -44,11 +26,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES9X
|
||||||
Justifier = 5
|
Justifier = 5
|
||||||
}
|
}
|
||||||
|
|
||||||
[UnmanagedFunctionPointer(CC)]
|
[BizImport(CC)]
|
||||||
public delegate void InputCallback();
|
public abstract void SetButtons(short[] buttons);
|
||||||
|
|
||||||
const CallingConvention CC = CallingConvention.Cdecl;
|
|
||||||
|
|
||||||
[BizImport(CC)]
|
[BizImport(CC)]
|
||||||
public abstract void biz_set_sound_channels(int channels);
|
public abstract void biz_set_sound_channels(int channels);
|
||||||
[BizImport(CC)]
|
[BizImport(CC)]
|
||||||
|
@ -64,14 +43,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES9X
|
||||||
[BizImport(CC)]
|
[BizImport(CC)]
|
||||||
public abstract bool biz_init();
|
public abstract bool biz_init();
|
||||||
[BizImport(CC)]
|
[BizImport(CC)]
|
||||||
public abstract void biz_run([In, Out] frame_info frame, [In]short[] input);
|
|
||||||
[BizImport(CC)]
|
|
||||||
public abstract bool biz_is_ntsc();
|
public abstract bool biz_is_ntsc();
|
||||||
[BizImport(CC)]
|
[BizImport(CC)]
|
||||||
public abstract void biz_get_memory_area(int which, [In, Out] memory_area mem);
|
|
||||||
[BizImport(CC)]
|
|
||||||
public abstract void biz_post_load_state();
|
public abstract void biz_post_load_state();
|
||||||
[BizImport(CC)]
|
|
||||||
public abstract void biz_set_input_callback(InputCallback callback);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,26 +12,31 @@ using System.Linq;
|
||||||
|
|
||||||
namespace BizHawk.Emulation.Cores.Nintendo.SNES9X
|
namespace BizHawk.Emulation.Cores.Nintendo.SNES9X
|
||||||
{
|
{
|
||||||
[CoreAttributes("Snes9x", "", true, true, "5e0319ab3ef9611250efb18255186d0dc0d7e125", "https://github.com/snes9xgit/snes9x", false)]
|
[CoreAttributes("Snes9x", "", true, true,
|
||||||
|
"5e0319ab3ef9611250efb18255186d0dc0d7e125", "https://github.com/snes9xgit/snes9x", false)]
|
||||||
[ServiceNotApplicable(typeof(IDriveLight))]
|
[ServiceNotApplicable(typeof(IDriveLight))]
|
||||||
public class Snes9x : IEmulator, IVideoProvider, ISoundProvider, IStatable,
|
public class Snes9x : WaterboxCore,
|
||||||
ISettable<Snes9x.Settings, Snes9x.SyncSettings>,
|
ISettable<Snes9x.Settings, Snes9x.SyncSettings>, IRegionable
|
||||||
ISaveRam, IInputPollable, IRegionable
|
|
||||||
{
|
{
|
||||||
private LibSnes9x _core;
|
private LibSnes9x _core;
|
||||||
private PeRunner _exe;
|
|
||||||
|
|
||||||
[CoreConstructor("SNES")]
|
[CoreConstructor("SNES")]
|
||||||
public Snes9x(CoreComm comm, byte[] rom, Settings settings, SyncSettings syncSettings)
|
public Snes9x(CoreComm comm, byte[] rom, Settings settings, SyncSettings syncSettings)
|
||||||
|
:base(comm, new Configuration
|
||||||
|
{
|
||||||
|
DefaultWidth = 256,
|
||||||
|
DefaultHeight = 224,
|
||||||
|
MaxWidth = 512,
|
||||||
|
MaxHeight = 480,
|
||||||
|
MaxSamples = 8192,
|
||||||
|
SystemId = "SNES"
|
||||||
|
})
|
||||||
{
|
{
|
||||||
ServiceProvider = new BasicServiceProvider(this);
|
|
||||||
CoreComm = comm;
|
|
||||||
settings = settings ?? new Settings();
|
settings = settings ?? new Settings();
|
||||||
syncSettings = syncSettings ?? new SyncSettings();
|
syncSettings = syncSettings ?? new SyncSettings();
|
||||||
|
|
||||||
_exe = new PeRunner(new PeRunnerOptions
|
_core = PreInit<LibSnes9x>(new PeRunnerOptions
|
||||||
{
|
{
|
||||||
Path = comm.CoreFileProvider.DllPath(),
|
|
||||||
Filename = "snes9x.wbx",
|
Filename = "snes9x.wbx",
|
||||||
SbrkHeapSizeKB = 1024,
|
SbrkHeapSizeKB = 1024,
|
||||||
SealedHeapSizeKB = 12 * 1024,
|
SealedHeapSizeKB = 12 * 1024,
|
||||||
|
@ -39,16 +44,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES9X
|
||||||
PlainHeapSizeKB = 64
|
PlainHeapSizeKB = 64
|
||||||
});
|
});
|
||||||
|
|
||||||
_core = BizInvoker.GetInvoker<LibSnes9x>(_exe, _exe);
|
|
||||||
if (!_core.biz_init())
|
if (!_core.biz_init())
|
||||||
{
|
|
||||||
throw new InvalidOperationException("Init() failed");
|
throw new InvalidOperationException("Init() failed");
|
||||||
}
|
|
||||||
if (!_core.biz_load_rom(rom, rom.Length))
|
if (!_core.biz_load_rom(rom, rom.Length))
|
||||||
{
|
|
||||||
throw new InvalidOperationException("LoadRom() failed");
|
throw new InvalidOperationException("LoadRom() failed");
|
||||||
}
|
|
||||||
_exe.Seal();
|
PostInit();
|
||||||
|
|
||||||
if (_core.biz_is_ntsc())
|
if (_core.biz_is_ntsc())
|
||||||
{
|
{
|
||||||
|
@ -65,16 +66,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES9X
|
||||||
Region = DisplayType.PAL;
|
Region = DisplayType.PAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
_nsampTarget = (int)Math.Round(44100.0 * VsyncDenominator / VsyncNumerator);
|
|
||||||
_nsampWarn = (int)Math.Round(1.05 * 44100.0 * VsyncDenominator / VsyncNumerator);
|
|
||||||
|
|
||||||
_syncSettings = syncSettings;
|
_syncSettings = syncSettings;
|
||||||
InitControllers();
|
InitControllers();
|
||||||
PutSettings(settings);
|
PutSettings(settings);
|
||||||
InitMemoryDomains();
|
|
||||||
InitSaveram();
|
|
||||||
|
|
||||||
_inputCallback = InputCallbacks.Call;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#region controller
|
#region controller
|
||||||
|
@ -115,13 +109,13 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES9X
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ControllerDefinition = ControllerDefinitionMerger.GetMerged(
|
_controllerDefinition = ControllerDefinitionMerger.GetMerged(
|
||||||
_controllers.Select(c => c.Definition), out _cdums);
|
_controllers.Select(c => c.Definition), out _cdums);
|
||||||
|
|
||||||
// add buttons that the core itself will handle
|
// add buttons that the core itself will handle
|
||||||
ControllerDefinition.BoolButtons.Add("Reset");
|
_controllerDefinition.BoolButtons.Add("Reset");
|
||||||
ControllerDefinition.BoolButtons.Add("Power");
|
_controllerDefinition.BoolButtons.Add("Power");
|
||||||
ControllerDefinition.Name = "SNES Controller";
|
_controllerDefinition.Name = "SNES Controller";
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateControls(IController c)
|
private void UpdateControls(IController c)
|
||||||
|
@ -285,238 +279,47 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES9X
|
||||||
public override ControllerDefinition Definition => _definition;
|
public override ControllerDefinition Definition => _definition;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ControllerDefinition ControllerDefinition { get; private set; }
|
private ControllerDefinition _controllerDefinition;
|
||||||
|
public override ControllerDefinition ControllerDefinition => _controllerDefinition;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
private bool _disposed = false;
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
if (!_disposed)
|
|
||||||
{
|
|
||||||
_exe.Dispose();
|
|
||||||
_exe = null;
|
|
||||||
_disposed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public DisplayType Region { get; }
|
public DisplayType Region { get; }
|
||||||
|
|
||||||
public IEmulatorServiceProvider ServiceProvider { get; }
|
protected override LibWaterboxCore.FrameInfo FrameAdvancePrep(IController controller, bool render, bool rendersound)
|
||||||
|
|
||||||
public void FrameAdvance(IController controller, bool render, bool rendersound = true)
|
|
||||||
{
|
{
|
||||||
_core.biz_set_input_callback(InputCallbacks.Count > 0 ? _inputCallback : null);
|
|
||||||
|
|
||||||
if (controller.IsPressed("Power"))
|
if (controller.IsPressed("Power"))
|
||||||
_core.biz_hard_reset();
|
_core.biz_hard_reset();
|
||||||
else if (controller.IsPressed("Reset"))
|
else if (controller.IsPressed("Reset"))
|
||||||
_core.biz_soft_reset();
|
_core.biz_soft_reset();
|
||||||
|
|
||||||
UpdateControls(controller);
|
UpdateControls(controller);
|
||||||
Frame++;
|
_core.SetButtons(_inputState);
|
||||||
LibSnes9x.frame_info frame = new LibSnes9x.frame_info();
|
|
||||||
|
|
||||||
_core.biz_run(frame, _inputState);
|
return new LibWaterboxCore.FrameInfo();
|
||||||
IsLagFrame = frame.padread == 0;
|
|
||||||
if (IsLagFrame)
|
|
||||||
LagCount++;
|
|
||||||
using (_exe.EnterExit())
|
|
||||||
{
|
|
||||||
Blit(frame);
|
|
||||||
Sblit(frame);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
protected override void FrameAdvancePost()
|
||||||
public int Frame { get; private set; }
|
|
||||||
|
|
||||||
public void ResetCounters()
|
|
||||||
{
|
{
|
||||||
Frame = 0;
|
_virtualHeight = BufferHeight;
|
||||||
|
_virtualWidth = BufferWidth;
|
||||||
|
if (_virtualHeight * 2 < _virtualWidth)
|
||||||
|
_virtualHeight *= 2;
|
||||||
|
if (_virtualHeight > 240)
|
||||||
|
_virtualWidth = 512;
|
||||||
|
_virtualWidth = (int)Math.Round(_virtualWidth * 1.146);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string SystemId { get { return "SNES"; } }
|
private int _virtualWidth;
|
||||||
public bool DeterministicEmulation { get { return true; } }
|
private int _virtualHeight;
|
||||||
public CoreComm CoreComm { get; private set; }
|
public override int VirtualWidth => _virtualWidth;
|
||||||
|
public override int VirtualHeight => _virtualHeight;
|
||||||
#region IVideoProvider
|
|
||||||
|
|
||||||
private static readonly int[] VirtualWidths = new[] { 293, 587, 587, 587 }; // 256 512 256 512
|
|
||||||
private static readonly int[] VirtualHeights = new[] { 224, 448, 448, 448 }; // 224 224 448 448
|
|
||||||
|
|
||||||
private unsafe void Blit(LibSnes9x.frame_info frame)
|
|
||||||
{
|
|
||||||
BufferWidth = frame.vwidth;
|
|
||||||
BufferHeight = frame.vheight;
|
|
||||||
|
|
||||||
int vinc = frame.vpitch / sizeof(ushort) - frame.vwidth;
|
|
||||||
|
|
||||||
ushort* src = (ushort*)frame.vptr;
|
|
||||||
fixed (int* _dst = _vbuff)
|
|
||||||
{
|
|
||||||
byte* dst = (byte*)_dst;
|
|
||||||
|
|
||||||
for (int j = 0; j < frame.vheight; j++)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < frame.vwidth; i++)
|
|
||||||
{
|
|
||||||
var c = *src++;
|
|
||||||
|
|
||||||
*dst++ = (byte)(c << 3 & 0xf8 | c >> 2 & 7);
|
|
||||||
*dst++ = (byte)(c >> 3 & 0xfa | c >> 9 & 3);
|
|
||||||
*dst++ = (byte)(c >> 8 & 0xf8 | c >> 13 & 7);
|
|
||||||
*dst++ = 0xff;
|
|
||||||
}
|
|
||||||
src += vinc;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VirtualHeight = BufferHeight;
|
|
||||||
VirtualWidth = BufferWidth;
|
|
||||||
if (VirtualHeight * 2 < VirtualWidth)
|
|
||||||
VirtualHeight *= 2;
|
|
||||||
if (VirtualHeight > 240)
|
|
||||||
VirtualWidth = 512;
|
|
||||||
VirtualWidth = (int)Math.Round(VirtualWidth * 1.146);
|
|
||||||
}
|
|
||||||
|
|
||||||
private int[] _vbuff = new int[512 * 480];
|
|
||||||
public int[] GetVideoBuffer() { return _vbuff; }
|
|
||||||
public int VirtualWidth { get; private set; } = 293;
|
|
||||||
public int VirtualHeight { get; private set; } = 224;
|
|
||||||
public int BufferWidth { get; private set; } = 256;
|
|
||||||
public int BufferHeight { get; private set; } = 224;
|
|
||||||
public int BackgroundColor { get { return unchecked((int)0xff000000); } }
|
|
||||||
|
|
||||||
public int VsyncNumerator
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int VsyncDenominator
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region ISoundProvider
|
|
||||||
|
|
||||||
private void Sblit(LibSnes9x.frame_info frame)
|
|
||||||
{
|
|
||||||
Marshal.Copy(frame.sptr, _sbuff, 0, frame.slen * 2);
|
|
||||||
_nsamp = frame.slen;
|
|
||||||
if (_nsamp > _nsampWarn)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"Warn: Long frame! {_nsamp} > {_nsampTarget}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly int _nsampWarn;
|
|
||||||
private readonly int _nsampTarget;
|
|
||||||
|
|
||||||
private int _nsamp;
|
|
||||||
private short[] _sbuff = new short[8192];
|
|
||||||
|
|
||||||
public void GetSamplesSync(out short[] samples, out int nsamp)
|
|
||||||
{
|
|
||||||
samples = _sbuff;
|
|
||||||
nsamp = _nsamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void DiscardSamples()
|
|
||||||
{
|
|
||||||
// Nothing to do
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetSyncMode(SyncSoundMode mode)
|
|
||||||
{
|
|
||||||
if (mode == SyncSoundMode.Async)
|
|
||||||
{
|
|
||||||
throw new NotSupportedException("Async mode is not supported.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool CanProvideAsync
|
|
||||||
{
|
|
||||||
get { return false; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public SyncSoundMode SyncMode
|
|
||||||
{
|
|
||||||
get { return SyncSoundMode.Sync; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public void GetSamplesAsync(short[] samples)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("Async mode is not supported.");
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
private LibSnes9x.InputCallback _inputCallback;
|
|
||||||
|
|
||||||
public int LagCount { get; set; }
|
|
||||||
public bool IsLagFrame { get; set; }
|
|
||||||
|
|
||||||
public IInputCallbackSystem InputCallbacks { get; } = new InputCallbackSystem();
|
|
||||||
|
|
||||||
#region IStatable
|
#region IStatable
|
||||||
|
|
||||||
public bool BinarySaveStatesPreferred
|
protected override void LoadStateBinaryInternal(BinaryReader reader)
|
||||||
{
|
{
|
||||||
get { return true; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SaveStateText(TextWriter writer)
|
|
||||||
{
|
|
||||||
var temp = SaveStateBinary();
|
|
||||||
temp.SaveAsHexFast(writer);
|
|
||||||
// write extra copy of stuff we don't use
|
|
||||||
writer.WriteLine("Frame {0}", Frame);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void LoadStateText(TextReader reader)
|
|
||||||
{
|
|
||||||
string hex = reader.ReadLine();
|
|
||||||
byte[] state = new byte[hex.Length / 2];
|
|
||||||
state.ReadFromHexFast(hex);
|
|
||||||
LoadStateBinary(new BinaryReader(new MemoryStream(state)));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void LoadStateBinary(BinaryReader reader)
|
|
||||||
{
|
|
||||||
_exe.LoadStateBinary(reader);
|
|
||||||
// other variables
|
|
||||||
Frame = reader.ReadInt32();
|
|
||||||
LagCount = reader.ReadInt32();
|
|
||||||
IsLagFrame = reader.ReadBoolean();
|
|
||||||
// any managed pointers that we sent to the core need to be resent now!
|
|
||||||
_core.biz_set_input_callback(null);
|
|
||||||
|
|
||||||
_core.biz_post_load_state();
|
_core.biz_post_load_state();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SaveStateBinary(BinaryWriter writer)
|
|
||||||
{
|
|
||||||
_exe.SaveStateBinary(writer);
|
|
||||||
// other variables
|
|
||||||
writer.Write(Frame);
|
|
||||||
writer.Write(LagCount);
|
|
||||||
writer.Write(IsLagFrame);
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] SaveStateBinary()
|
|
||||||
{
|
|
||||||
var ms = new MemoryStream();
|
|
||||||
var bw = new BinaryWriter(ms);
|
|
||||||
SaveStateBinary(bw);
|
|
||||||
bw.Flush();
|
|
||||||
ms.Close();
|
|
||||||
return ms.ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region settings
|
#region settings
|
||||||
|
@ -686,83 +489,5 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES9X
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Memory Domains
|
|
||||||
|
|
||||||
private unsafe void InitMemoryDomains()
|
|
||||||
{
|
|
||||||
var native = new LibSnes9x.memory_area();
|
|
||||||
var domains = new List<MemoryDomain>();
|
|
||||||
|
|
||||||
var names = new[] { "CARTRAM", "CARTRAM B", "RTC", "WRAM", "VRAM" };
|
|
||||||
int index = 0;
|
|
||||||
foreach (var s in names)
|
|
||||||
{
|
|
||||||
_core.biz_get_memory_area(index++, native);
|
|
||||||
if (native.ptr != IntPtr.Zero && native.size > 0)
|
|
||||||
{
|
|
||||||
domains.Add(new MemoryDomainIntPtrMonitor(s, MemoryDomain.Endian.Little,
|
|
||||||
native.ptr, native.size, true, 2, _exe));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(ServiceProvider as BasicServiceProvider).Register<IMemoryDomains>(new MemoryDomainList(domains)
|
|
||||||
{
|
|
||||||
MainMemory = domains.Single(d => d.Name == "WRAM")
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region ISaveRam
|
|
||||||
|
|
||||||
private void InitSaveram()
|
|
||||||
{
|
|
||||||
for (int i = 0; i < 2; i++) // SRAM A, SRAM B, RTC
|
|
||||||
{
|
|
||||||
var native = new LibSnes9x.memory_area();
|
|
||||||
_core.biz_get_memory_area(i, native);
|
|
||||||
if (native.ptr != IntPtr.Zero && native.size > 0)
|
|
||||||
_saveramMemoryAreas.Add(native);
|
|
||||||
}
|
|
||||||
_saveramSize = _saveramMemoryAreas.Sum(a => a.size);
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly List<LibSnes9x.memory_area> _saveramMemoryAreas = new List<LibSnes9x.memory_area>();
|
|
||||||
|
|
||||||
private int _saveramSize;
|
|
||||||
|
|
||||||
public bool SaveRamModified => _saveramSize > 0;
|
|
||||||
|
|
||||||
public byte[] CloneSaveRam()
|
|
||||||
{
|
|
||||||
using (_exe.EnterExit())
|
|
||||||
{
|
|
||||||
var ret = new byte[_saveramSize];
|
|
||||||
var offset = 0;
|
|
||||||
foreach (var area in _saveramMemoryAreas)
|
|
||||||
{
|
|
||||||
Marshal.Copy(area.ptr, ret, offset, area.size);
|
|
||||||
offset += area.size;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void StoreSaveRam(byte[] data)
|
|
||||||
{
|
|
||||||
using (_exe.EnterExit())
|
|
||||||
{
|
|
||||||
if (data.Length != _saveramSize)
|
|
||||||
throw new InvalidOperationException("Saveram size mismatch");
|
|
||||||
var offset = 0;
|
|
||||||
foreach (var area in _saveramMemoryAreas)
|
|
||||||
{
|
|
||||||
Marshal.Copy(data, offset, area.ptr, area.size);
|
|
||||||
offset += area.size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
||||||
public abstract class WaterboxCore : IEmulator, IVideoProvider, ISoundProvider, IStatable,
|
public abstract class WaterboxCore : IEmulator, IVideoProvider, ISoundProvider, IStatable,
|
||||||
IInputPollable, ISaveRam
|
IInputPollable, ISaveRam
|
||||||
{
|
{
|
||||||
protected LibWaterboxCore _core;
|
private LibWaterboxCore _core;
|
||||||
protected PeRunner _exe;
|
protected PeRunner _exe;
|
||||||
protected LibWaterboxCore.MemoryArea[] _memoryAreas;
|
protected LibWaterboxCore.MemoryArea[] _memoryAreas;
|
||||||
private LibWaterboxCore.EmptyCallback _inputCallback;
|
private LibWaterboxCore.EmptyCallback _inputCallback;
|
||||||
|
@ -153,6 +153,8 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
||||||
#region IEmulator
|
#region IEmulator
|
||||||
|
|
||||||
protected abstract LibWaterboxCore.FrameInfo FrameAdvancePrep(IController controller, bool render, bool rendersound);
|
protected abstract LibWaterboxCore.FrameInfo FrameAdvancePrep(IController controller, bool render, bool rendersound);
|
||||||
|
protected virtual void FrameAdvancePost()
|
||||||
|
{ }
|
||||||
|
|
||||||
public unsafe void FrameAdvance(IController controller, bool render, bool rendersound = true)
|
public unsafe void FrameAdvance(IController controller, bool render, bool rendersound = true)
|
||||||
{
|
{
|
||||||
|
@ -176,6 +178,8 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
||||||
BufferWidth = frame.Width;
|
BufferWidth = frame.Width;
|
||||||
BufferHeight = frame.Height;
|
BufferHeight = frame.Height;
|
||||||
_numSamples = frame.Samples;
|
_numSamples = frame.Samples;
|
||||||
|
|
||||||
|
FrameAdvancePost();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
|
@ -1,12 +1,13 @@
|
||||||
// Place your settings in this file to overwrite default and user settings.
|
// Place your settings in this file to overwrite default and user settings.
|
||||||
{
|
{
|
||||||
"editor.insertSpaces": false,
|
"editor.insertSpaces": false,
|
||||||
"editor.detectIndentation": false,
|
"editor.detectIndentation": false,
|
||||||
"files.associations": {
|
"files.associations": {
|
||||||
"algorithm": "cpp",
|
"algorithm": "cpp",
|
||||||
"vector": "cpp",
|
"vector": "cpp",
|
||||||
"xstring": "cpp",
|
"xstring": "cpp",
|
||||||
"xutility": "cpp",
|
"xutility": "cpp",
|
||||||
"xmemory0": "cpp"
|
"xmemory0": "cpp",
|
||||||
}
|
"iosfwd": "cpp"
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1 +1 @@
|
||||||
Subproject commit 33a7181fa05a01434f420db3ab826d41140aad9c
|
Subproject commit 06a2bc83c9288c5efd5872d5d2e4b94f03d6e4b7
|
Loading…
Reference in New Issue