Libsnescore - Break off IEmulator implementation into a separate file

This commit is contained in:
adelikat 2017-04-19 10:36:08 -05:00
parent 8e3c3dab5d
commit bc42af0fa6
4 changed files with 157 additions and 136 deletions

View File

@ -10,14 +10,15 @@ namespace BizHawk.Emulation.Common
public interface IEmulator : IEmulatorService, IDisposable
{
/// <summary>
/// The intended mechanism to get services from a core
/// Gets the service provider.
/// This is the intended mechanism to get services from a core
/// Retrieves an IEmulatorService from the core,
/// if the core does not have the type specified, it will return null
/// </summary>
IEmulatorServiceProvider ServiceProvider { get; }
/// <summary>
/// Defines all the possible inputs and types that the core can receive
/// Gets the definition that defines all the possible inputs and types that the core can receive
/// By design this should not change during the lifetime of the instance of the core
/// To change the definition, a new instance should be created
/// </summary>
@ -39,17 +40,18 @@ namespace BizHawk.Emulation.Common
void FrameAdvance(bool render, bool rendersound = true);
/// <summary>
/// The frame count
/// Gets the current frame count
/// </summary>
int Frame { get; }
/// <summary>
/// The unique Id of the platform currently being emulated, for instance "NES"
/// Gets the unique Id of the platform currently being emulated, for instance "NES"
/// </summary>
string SystemId { get; }
/// <summary>
/// This flag is a contract with the client.
/// Gets a value indicating whether the core is in deterministic mode.
/// This flag is a contract with the client.
/// If true, the core agrees to behave in a completely deterministic manner,
/// Features like movie recording depend on this.
/// It is the client's responsibility to manage this flag.
@ -59,7 +61,7 @@ namespace BizHawk.Emulation.Common
bool DeterministicEmulation { get; }
/// <summary>
/// identifying information about a "mapper" or similar capability. null if no such useful distinction can be drawn
/// Gets the identifying information about a "mapper" or similar capability. null if no such useful distinction can be drawn
/// </summary>
string BoardName { get; }
@ -69,7 +71,7 @@ namespace BizHawk.Emulation.Common
void ResetCounters();
/// <summary>
/// the corecomm module in use by this core.
/// Gets the core communications module in use by this core.
/// </summary>
/// <seealso cref="BizHawk.Emulation.Common.CoreComm" />
CoreComm CoreComm { get; }

View File

@ -905,6 +905,9 @@
<DependentUpon>LibsnesCore.cs</DependentUpon>
</Compile>
<Compile Include="Consoles\Nintendo\SNES\LibsnesCore.IDebuggable.cs">
<DependentUpon>LibsnesCore.cs</DependentUpon>
</Compile>
<Compile Include="Consoles\Nintendo\SNES\LibsnesCore.IEmulator.cs">
<DependentUpon>LibsnesCore.cs</DependentUpon>
</Compile>
<Compile Include="Consoles\Nintendo\SNES\LibsnesCore.IInputPollable.cs">

View File

@ -0,0 +1,140 @@
using System.IO;
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores.Nintendo.SNES
{
public partial class LibsnesCore : IEmulator
{
public IEmulatorServiceProvider ServiceProvider { get; }
public ControllerDefinition ControllerDefinition => _controllerDeck.Definition;
public IController Controller { get; set; }
public void FrameAdvance(bool render, bool rendersound)
{
/* if the input poll callback is called, it will set this to false
* this has to be done before we save the per-frame state in deterministic
* mode, because in there, the core actually advances, and might advance
* through the point in time where IsLagFrame gets set to false. makes sense?
*/
IsLagFrame = true;
if (!nocallbacks && Tracer.Enabled)
{
api.QUERY_set_trace_callback(tracecb);
}
else
{
api.QUERY_set_trace_callback(null);
}
// for deterministic emulation, save the state we're going to use before frame advance
// don't do this during nocallbacks though, since it's already been done
if (!nocallbacks && DeterministicEmulation)
{
var ms = new MemoryStream();
var bw = new BinaryWriter(ms);
bw.Write(CoreSaveState());
bw.Write(false); // not framezero
var ssc = new SnesSaveController();
ssc.CopyFrom(Controller);
ssc.Serialize(bw);
bw.Close();
_savestatebuff = ms.ToArray();
}
// speedup when sound rendering is not needed
api.QUERY_set_audio_sample(rendersound ? soundcb : null);
bool resetSignal = Controller.IsPressed("Reset");
if (resetSignal)
{
api.CMD_reset();
}
bool powerSignal = Controller.IsPressed("Power");
if (powerSignal)
{
api.CMD_power();
}
var enables = new LibsnesApi.LayerEnables
{
BG1_Prio0 = _settings.ShowBG1_0,
BG1_Prio1 = _settings.ShowBG1_1,
BG2_Prio0 = _settings.ShowBG2_0,
BG2_Prio1 = _settings.ShowBG2_1,
BG3_Prio0 = _settings.ShowBG3_0,
BG3_Prio1 = _settings.ShowBG3_1,
BG4_Prio0 = _settings.ShowBG4_0,
BG4_Prio1 = _settings.ShowBG4_1,
Obj_Prio0 = _settings.ShowOBJ_0,
Obj_Prio1 = _settings.ShowOBJ_1,
Obj_Prio2 = _settings.ShowOBJ_2,
Obj_Prio3 = _settings.ShowOBJ_3
};
api.SetLayerEnables(ref enables);
RefreshMemoryCallbacks(false);
// apparently this is one frame?
_timeFrameCounter++;
api.CMD_run();
// once upon a time we forwarded messages frmo bsnes here, by checking for queued text messages, but I don't think it's needed any longer
if (IsLagFrame)
{
LagCount++;
}
}
public int Frame
{
get { return _timeFrameCounter; }
private set { _timeFrameCounter = value; }
}
public string SystemId { get; }
// adelikat: Nasty hack to force new business logic. Compatibility (and Accuracy when fully supported) will ALWAYS be in deterministic mode,
// a consequence is a permanent performance hit to the compatibility core
// Perormance will NEVER be in deterministic mode (and the client side logic will prohibit movie recording on it)
// feos: Nasty hack to a nasty hack. Allow user disable it with a strong warning.
public bool DeterministicEmulation =>
_settings.ForceDeterminism
&& (CurrentProfile == "Compatibility" || CurrentProfile == "Accuracy");
public string BoardName { get; }
public void ResetCounters()
{
_timeFrameCounter = 0;
LagCount = 0;
IsLagFrame = false;
}
public CoreComm CoreComm { get; }
public void Dispose()
{
if (_disposed)
{
return;
}
_disposed = true;
api.CMD_unload_cartridge();
api.CMD_term();
resampler.Dispose();
api.Dispose();
_currCdl?.Unpin();
}
}
}

View File

@ -160,7 +160,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES
SetupMemoryDomains(romData, sgbRomData);
DeterministicEmulation = deterministicEmulation;
// DeterministicEmulation = deterministicEmulation; // Note we don't respect the value coming in and force it instead
if (DeterministicEmulation) // save frame-0 savestate now
{
MemoryStream ms = new MemoryStream();
@ -174,8 +174,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES
}
}
public IEmulatorServiceProvider ServiceProvider { get; private set; }
private GameInfo _game;
public string CurrentProfile
@ -199,21 +197,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES
/// <summary>disable all external callbacks. the front end should not even know the core is frame advancing</summary>
bool nocallbacks = false;
bool disposed = false;
public void Dispose()
{
if (disposed) return;
disposed = true;
api.CMD_unload_cartridge();
api.CMD_term();
resampler.Dispose();
api.Dispose();
if (_currCdl != null) _currCdl.Unpin();
}
public ITraceable Tracer { get; private set; }
public class MyScanlineHookManager : ScanlineHookManager
@ -230,10 +213,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES
}
}
bool _disposed = false;
public MyScanlineHookManager ScanlineHookManager;
void OnScanlineHooksChanged()
{
if (disposed) return;
if (_disposed) return;
if (ScanlineHookManager.HookCount == 0) api.QUERY_set_scanlineStart(null);
else api.QUERY_set_scanlineStart(scanlineStart_cb);
}
@ -507,75 +492,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES
}
}
public void FrameAdvance(bool render, bool rendersound)
{
/* if the input poll callback is called, it will set this to false
* this has to be done before we save the per-frame state in deterministic
* mode, because in there, the core actually advances, and might advance
* through the point in time where IsLagFrame gets set to false. makes sense?
*/
IsLagFrame = true;
if (!nocallbacks && Tracer.Enabled)
api.QUERY_set_trace_callback(tracecb);
else
api.QUERY_set_trace_callback(null);
// for deterministic emulation, save the state we're going to use before frame advance
// don't do this during nocallbacks though, since it's already been done
if (!nocallbacks && DeterministicEmulation)
{
MemoryStream ms = new MemoryStream();
BinaryWriter bw = new BinaryWriter(ms);
bw.Write(CoreSaveState());
bw.Write(false); // not framezero
SnesSaveController ssc = new SnesSaveController();
ssc.CopyFrom(Controller);
ssc.Serialize(bw);
bw.Close();
_savestatebuff = ms.ToArray();
}
// speedup when sound rendering is not needed
if (!rendersound)
api.QUERY_set_audio_sample(null);
else
api.QUERY_set_audio_sample(soundcb);
bool resetSignal = Controller.IsPressed("Reset");
if (resetSignal) api.CMD_reset();
bool powerSignal = Controller.IsPressed("Power");
if (powerSignal) api.CMD_power();
var enables = new LibsnesApi.LayerEnables();
enables.BG1_Prio0 = _settings.ShowBG1_0;
enables.BG1_Prio1 = _settings.ShowBG1_1;
enables.BG2_Prio0 = _settings.ShowBG2_0;
enables.BG2_Prio1 = _settings.ShowBG2_1;
enables.BG3_Prio0 = _settings.ShowBG3_0;
enables.BG3_Prio1 = _settings.ShowBG3_1;
enables.BG4_Prio0 = _settings.ShowBG4_0;
enables.BG4_Prio1 = _settings.ShowBG4_1;
enables.Obj_Prio0 = _settings.ShowOBJ_0;
enables.Obj_Prio1 = _settings.ShowOBJ_1;
enables.Obj_Prio2 = _settings.ShowOBJ_2;
enables.Obj_Prio3 = _settings.ShowOBJ_3;
api.SetLayerEnables(ref enables);
RefreshMemoryCallbacks(false);
//apparently this is one frame?
timeFrameCounter++;
api.CMD_run();
//once upon a time we forwarded messages frmo bsnes here, by checking for queued text messages, but I don't think it's needed any longer
if (IsLagFrame)
LagCount++;
}
void RefreshMemoryCallbacks(bool suppress)
{
var mcs = MemoryCallbacks;
@ -584,34 +500,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES
api.QUERY_set_state_hook_write(!suppress && mcs.HasWrites);
}
public ControllerDefinition ControllerDefinition { get { return _controllerDeck.Definition; } }
IController controller;
public IController Controller
{
get { return controller; }
set { controller = value; }
}
int timeFrameCounter;
public int Frame { get { return timeFrameCounter; } set { timeFrameCounter = value; } }
public string SystemId { get; private set; }
public string BoardName { get; private set; }
// adelikat: Nasty hack to force new business logic. Compatibility (and Accuracy when fully supported) will ALWAYS be in deterministic mode,
// a consequence is a permanent performance hit to the compatibility core
// Perormance will NEVER be in deterministic mode (and the client side logic will prohibit movie recording on it)
// feos: Nasty hack to a nasty hack. Allow user disable it with a strong warning.
public bool DeterministicEmulation
{
get
{
return _settings.ForceDeterminism &&
(CurrentProfile == "Compatibility" || CurrentProfile == "Accuracy");
}
private set { /* Do nothing */ }
}
private int _timeFrameCounter;
//public byte[] snes_get_memory_data_read(LibsnesApi.SNES_MEMORY id)
//{
@ -621,13 +510,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES
// return ret;
//}
public void ResetCounters()
{
timeFrameCounter = 0;
LagCount = 0;
IsLagFrame = false;
}
#region savestates
/// <summary>
@ -729,14 +611,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES
}
}
#endregion
public CoreComm CoreComm { get; private set; }
// works for WRAM, garbage for anything else
static int? FakeBusMap(int addr)
{