mame cleanup

This commit is contained in:
feos 2019-12-23 20:18:42 +03:00
parent a0dd2e1314
commit 1dc33e074f
1 changed files with 133 additions and 130 deletions

View File

@ -26,9 +26,9 @@ namespace BizHawk.Emulation.Cores.Arcades.MAME
ServiceProvider = new BasicServiceProvider(this); ServiceProvider = new BasicServiceProvider(this);
CoreComm = comm; CoreComm = comm;
gameDirectory = dir; _gameDirectory = dir;
gameFilename = file; _gameFilename = file;
MAMEThread = new Thread(ExecuteMAMEThread); _mameThread = new Thread(ExecuteMAMEThread);
AsyncLaunchMAME(); AsyncLaunchMAME();
@ -45,13 +45,48 @@ namespace BizHawk.Emulation.Cores.Arcades.MAME
} }
} }
/* strings and MAME
*
* MAME's luaengine uses lua strings to return C strings as well as
* binary buffers. You're meant to know which you're going to get and
* handle that accordingly.
*
* When we want to get a C string, we Marshal.PtrToStringAnsi().
* With buffers, we Marshal.Copy() to our new buffer.
* MameGetString() only covers the former because it's the same steps
* every time, while buffers use to need aditional logic.
*
* In both cases MAME wants us to manually free the string buffer. It's
* made that way to make the buffer persist actoss C API calls.
*
*/
private static string MameGetString(string command)
{
IntPtr ptr = LibMAME.mame_lua_get_string(command, out var lengthInBytes);
if (ptr == IntPtr.Zero)
{
Console.WriteLine("LibMAME ERROR: string buffer pointer is null");
return "";
}
var ret = Marshal.PtrToStringAnsi(ptr, lengthInBytes);
if (!LibMAME.mame_lua_free_string(ptr))
{
Console.WriteLine("LibMAME ERROR: string buffer wasn't freed");
}
return ret;
}
#region Properties #region Properties
public CoreComm CoreComm { get; private set; } public CoreComm CoreComm { get; private set; }
public IEmulatorServiceProvider ServiceProvider { get; private set; } public IEmulatorServiceProvider ServiceProvider { get; private set; }
public ControllerDefinition ControllerDefinition => MAMEController; public ControllerDefinition ControllerDefinition => MAMEController;
public string SystemId => "MAME"; public string SystemId => "MAME";
public int[] GetVideoBuffer() => frameBuffer; public int[] GetVideoBuffer() => _frameBuffer;
public bool DeterministicEmulation => true; public bool DeterministicEmulation => true;
public bool CanProvideAsync => false; public bool CanProvideAsync => false;
public SyncSoundMode SyncMode => SyncSoundMode.Sync; public SyncSoundMode SyncMode => SyncSoundMode.Sync;
@ -69,32 +104,32 @@ namespace BizHawk.Emulation.Cores.Arcades.MAME
#region Fields #region Fields
private SyncSettings _syncSettings; private SyncSettings _syncSettings;
private Thread MAMEThread; private Thread _mameThread;
private ManualResetEvent MAMEStartupComplete = new ManualResetEvent(false); private ManualResetEvent _mameStartupComplete = new ManualResetEvent(false);
private ManualResetEvent MAMEFrameComplete = new ManualResetEvent(false); private ManualResetEvent _mameFrameComplete = new ManualResetEvent(false);
private AutoResetEvent MAMEPeriodicComplete = new AutoResetEvent(false); private AutoResetEvent _mamePeriodicComplete = new AutoResetEvent(false);
private AutoResetEvent MemoryAccessComplete = new AutoResetEvent(false); private AutoResetEvent _memoryAccessComplete = new AutoResetEvent(false);
private SortedDictionary<string, string> fieldsPorts = new SortedDictionary<string, string>(); private SortedDictionary<string, string> _fieldsPorts = new SortedDictionary<string, string>();
private IController Controller = NullController.Instance; private IController _controller = NullController.Instance;
private IMemoryDomains _memoryDomains; private IMemoryDomains _memoryDomains;
private int systemBusAddressShift = 0; private int _systemBusAddressShift = 0;
private bool memAccess = false; private bool _memAccess = false;
private int[] frameBuffer = new int[0]; private int[] _frameBuffer = new int[0];
private Queue<short> audioSamples = new Queue<short>(); private Queue<short> _audioSamples = new Queue<short>();
private decimal dAudioSamples = 0; private decimal _dAudioSamples = 0;
private int sampleRate = 44100; private int _sampleRate = 44100;
private int numSamples = 0; private int _numSamples = 0;
private bool paused = true; private bool _paused = true;
private bool exiting = false; private bool _exiting = false;
private bool frameDone = true; private bool _frameDone = true;
private string gameDirectory; private string _gameDirectory;
private string gameFilename; private string _gameFilename;
private string _gameName = "Arcade"; private string _gameName = "Arcade";
private string _loadFailure = ""; private string _loadFailure = "";
private LibMAME.PeriodicCallbackDelegate periodicCallback; private LibMAME.PeriodicCallbackDelegate _periodicCallback;
private LibMAME.SoundCallbackDelegate soundCallback; private LibMAME.SoundCallbackDelegate _soundCallback;
private LibMAME.BootCallbackDelegate bootCallback; private LibMAME.BootCallbackDelegate _bootCallback;
private LibMAME.LogCallbackDelegate logCallback; private LibMAME.LogCallbackDelegate _logCallback;
#endregion #endregion
@ -102,18 +137,18 @@ namespace BizHawk.Emulation.Cores.Arcades.MAME
public bool FrameAdvance(IController controller, bool render, bool renderSound = true) public bool FrameAdvance(IController controller, bool render, bool renderSound = true)
{ {
if (exiting) if (_exiting)
{ {
return false; return false;
} }
Controller = controller; _controller = controller;
paused = false; _paused = false;
frameDone = false; _frameDone = false;
for (; frameDone == false;) for (; _frameDone == false;)
{ {
MAMEFrameComplete.WaitOne(); _mameFrameComplete.WaitOne();
} }
Frame++; Frame++;
@ -128,8 +163,8 @@ namespace BizHawk.Emulation.Cores.Arcades.MAME
public void Dispose() public void Dispose()
{ {
exiting = true; _exiting = true;
MAMEThread.Join(); _mameThread.Join();
} }
#endregion #endregion
@ -201,12 +236,12 @@ namespace BizHawk.Emulation.Cores.Arcades.MAME
*/ */
public void GetSamplesSync(out short[] samples, out int nsamp) public void GetSamplesSync(out short[] samples, out int nsamp)
{ {
decimal dSamplesPerFrame = (decimal)sampleRate * VsyncDenominator / VsyncNumerator; decimal dSamplesPerFrame = (decimal)_sampleRate * VsyncDenominator / VsyncNumerator;
if (audioSamples.Any()) if (_audioSamples.Any())
{ {
dAudioSamples -= dSamplesPerFrame; _dAudioSamples -= dSamplesPerFrame;
int remainder = (int)Math.Round(dAudioSamples - Math.Truncate(dAudioSamples)) ^ 1; int remainder = (int)Math.Round(_dAudioSamples - Math.Truncate(_dAudioSamples)) ^ 1;
nsamp = (int)Math.Round(dSamplesPerFrame) + remainder; nsamp = (int)Math.Round(dSamplesPerFrame) + remainder;
} }
else else
@ -218,9 +253,9 @@ namespace BizHawk.Emulation.Cores.Arcades.MAME
for (int i = 0; i < nsamp * 2; i++) for (int i = 0; i < nsamp * 2; i++)
{ {
if (audioSamples.Any()) if (_audioSamples.Any())
{ {
samples[i] = audioSamples.Dequeue(); samples[i] = _audioSamples.Dequeue();
} }
else else
{ {
@ -236,7 +271,7 @@ namespace BizHawk.Emulation.Cores.Arcades.MAME
public void DiscardSamples() public void DiscardSamples()
{ {
audioSamples.Clear(); _audioSamples.Clear();
} }
#endregion #endregion
@ -247,16 +282,10 @@ namespace BizHawk.Emulation.Cores.Arcades.MAME
{ {
var domains = new List<MemoryDomain>(); var domains = new List<MemoryDomain>();
systemBusAddressShift = LibMAME.mame_lua_get_int(MAMELuaCommand.GetSpaceAddressShift); _systemBusAddressShift = LibMAME.mame_lua_get_int(MAMELuaCommand.GetSpaceAddressShift);
var size = (long)LibMAME.mame_lua_get_double(MAMELuaCommand.GetSpaceAddressMask) + 1; var size = (long)LibMAME.mame_lua_get_double(MAMELuaCommand.GetSpaceAddressMask) + 1;
var dataWidth = LibMAME.mame_lua_get_int(MAMELuaCommand.GetSpaceDataWidth) >> 3; var dataWidth = LibMAME.mame_lua_get_int(MAMELuaCommand.GetSpaceDataWidth) >> 3; // mame returns in bits
IntPtr ptr = LibMAME.mame_lua_get_string(MAMELuaCommand.GetSpaceEndianness, out var lengthInBytes); var endianString = MameGetString(MAMELuaCommand.GetSpaceEndianness);
string endianString = Marshal.PtrToStringAnsi(ptr, lengthInBytes);
if (!LibMAME.mame_lua_free_string(ptr))
{
Console.WriteLine("LibMAME ERROR: string buffer wasn't freed");
}
MemoryDomain.Endian endian = MemoryDomain.Endian.Unknown; MemoryDomain.Endian endian = MemoryDomain.Endian.Unknown;
@ -277,11 +306,11 @@ namespace BizHawk.Emulation.Cores.Arcades.MAME
throw new ArgumentOutOfRangeException(); throw new ArgumentOutOfRangeException();
} }
memAccess = true; _memAccess = true;
MAMEPeriodicComplete.WaitOne(); _mamePeriodicComplete.WaitOne();
var val = (byte)LibMAME.mame_lua_get_int(MAMELuaCommand.GetSpace + $":read_u8({ addr << systemBusAddressShift })"); var val = (byte)LibMAME.mame_lua_get_int(MAMELuaCommand.GetSpace + $":read_u8({ addr << _systemBusAddressShift })");
MemoryAccessComplete.Set(); _memoryAccessComplete.Set();
memAccess = false; _memAccess = false;
return val; return val;
}, },
delegate (long addr, byte val) delegate (long addr, byte val)
@ -291,11 +320,11 @@ namespace BizHawk.Emulation.Cores.Arcades.MAME
throw new ArgumentOutOfRangeException(); throw new ArgumentOutOfRangeException();
} }
memAccess = true; _memAccess = true;
MAMEPeriodicComplete.WaitOne(); _mamePeriodicComplete.WaitOne();
LibMAME.mame_lua_execute(MAMELuaCommand.GetSpace + $":write_u8({ addr << systemBusAddressShift }, { val })"); LibMAME.mame_lua_execute(MAMELuaCommand.GetSpace + $":write_u8({ addr << _systemBusAddressShift }, { val })");
MemoryAccessComplete.Set(); _memoryAccessComplete.Set();
memAccess = false; _memAccess = false;
}, dataWidth)); }, dataWidth));
_memoryDomains = new MemoryDomainList(domains); _memoryDomains = new MemoryDomainList(domains);
@ -308,37 +337,37 @@ namespace BizHawk.Emulation.Cores.Arcades.MAME
private void AsyncLaunchMAME() private void AsyncLaunchMAME()
{ {
MAMEThread.Start(); _mameThread.Start();
MAMEStartupComplete.WaitOne(); _mameStartupComplete.WaitOne();
} }
private void ExecuteMAMEThread() private void ExecuteMAMEThread()
{ {
// dodge GC // dodge GC
periodicCallback = MAMEPeriodicCallback; _periodicCallback = MAMEPeriodicCallback;
soundCallback = MAMESoundCallback; _soundCallback = MAMESoundCallback;
bootCallback = MAMEBootCallback; _bootCallback = MAMEBootCallback;
logCallback = MAMELogCallback; _logCallback = MAMELogCallback;
LibMAME.mame_set_periodic_callback(periodicCallback); LibMAME.mame_set_periodic_callback(_periodicCallback);
LibMAME.mame_set_sound_callback(soundCallback); LibMAME.mame_set_sound_callback(_soundCallback);
LibMAME.mame_set_boot_callback(bootCallback); LibMAME.mame_set_boot_callback(_bootCallback);
LibMAME.mame_set_log_callback(logCallback); LibMAME.mame_set_log_callback(_logCallback);
// https://docs.mamedev.org/commandline/commandline-index.html // https://docs.mamedev.org/commandline/commandline-index.html
string[] args = string[] args =
{ {
"mame" // dummy, internally discarded by index, so has to go first "mame" // dummy, internally discarded by index, so has to go first
, gameFilename // no dash for rom names , _gameFilename // no dash for rom names
, "-noreadconfig" // forbid reading any config files , "-noreadconfig" // forbid reading any config files
, "-norewind" // forbid rewind savestates (captured upon frame advance) , "-norewind" // forbid rewind savestates (captured upon frame advance)
, "-skip_gameinfo" // forbid this blocking screen that requires user input , "-skip_gameinfo" // forbid this blocking screen that requires user input
, "-nothrottle" // forbid throttling to "real" speed of the device , "-nothrottle" // forbid throttling to "real" speed of the device
, "-update_in_pause" // ^ including frame-advancing , "-update_in_pause" // ^ including frame-advancing
, "-rompath", gameDirectory // mame doesn't load roms from full paths, only from dirs to scan , "-rompath", _gameDirectory // mame doesn't load roms from full paths, only from dirs to scan
, "-volume", "-32" // lowest attenuation means mame osd remains silent , "-volume", "-32" // lowest attenuation means mame osd remains silent
, "-output", "console" // print everything to hawk console , "-output", "console" // print everything to hawk console
, "-samplerate", sampleRate.ToString() // match hawk samplerate , "-samplerate", _sampleRate.ToString() // match hawk samplerate
, "-video", "none" // forbid mame window altogether , "-video", "none" // forbid mame window altogether
, "-keyboardprovider", "none" , "-keyboardprovider", "none"
, "-mouseprovider", "none" , "-mouseprovider", "none"
@ -395,8 +424,8 @@ namespace BizHawk.Emulation.Cores.Arcades.MAME
return; return;
} }
frameBuffer = new int[expectedSize]; _frameBuffer = new int[expectedSize];
Marshal.Copy(ptr, frameBuffer, 0, expectedSize); Marshal.Copy(ptr, _frameBuffer, 0, expectedSize);
if (!LibMAME.mame_lua_free_string(ptr)) if (!LibMAME.mame_lua_free_string(ptr))
{ {
@ -406,13 +435,13 @@ namespace BizHawk.Emulation.Cores.Arcades.MAME
private void UpdateInput() private void UpdateInput()
{ {
foreach (var fieldPort in fieldsPorts) foreach (var fieldPort in _fieldsPorts)
{ {
LibMAME.mame_lua_execute( LibMAME.mame_lua_execute(
"manager:machine():ioport()" + "manager:machine():ioport()" +
$".ports [\"{ fieldPort.Value }\"]" + $".ports [\"{ fieldPort.Value }\"]" +
$".fields [\"{ fieldPort.Key }\"]" + $".fields [\"{ fieldPort.Key }\"]" +
$":set_value({ (Controller.IsPressed(fieldPort.Key) ? 1 : 0) })"); $":set_value({ (_controller.IsPressed(fieldPort.Key) ? 1 : 0) })");
} }
} }
@ -424,34 +453,21 @@ namespace BizHawk.Emulation.Cores.Arcades.MAME
UpdateInput(); UpdateInput();
} }
private void CheckVersions() private void UpdateGameName()
{ {
IntPtr ptr = LibMAME.mame_lua_get_string(MAMELuaCommand.GetVersion, out var lengthInBytes); _gameName = MameGetString(MAMELuaCommand.GetGameName);
string mameVersion = Marshal.PtrToStringAnsi(ptr, lengthInBytes);
if (!LibMAME.mame_lua_free_string(ptr))
{
Console.WriteLine("LibMAME ERROR: string buffer wasn't freed");
} }
string version = this.Attributes().PortedVersion; private void CheckVersions()
{
var mameVersion = MameGetString(MAMELuaCommand.GetVersion);
var version = this.Attributes().PortedVersion;
Debug.Assert(version == mameVersion, Debug.Assert(version == mameVersion,
"MAME versions desync!\n\n" + "MAME versions desync!\n\n" +
$"MAME is { mameVersion }\n" + $"MAME is { mameVersion }\n" +
$"MAMEHawk is { version }"); $"MAMEHawk is { version }");
} }
private void UpdateGameName()
{
IntPtr ptr = LibMAME.mame_lua_get_string(MAMELuaCommand.GetGameName, out var lengthInBytes);
_gameName = Marshal.PtrToStringAnsi(ptr, lengthInBytes);
if (!LibMAME.mame_lua_free_string(ptr))
{
Console.WriteLine("LibMAME ERROR: string buffer wasn't freed");
}
}
#endregion #endregion
#region Callbacks #region Callbacks
@ -488,32 +504,32 @@ namespace BizHawk.Emulation.Cores.Arcades.MAME
*/ */
private void MAMEPeriodicCallback() private void MAMEPeriodicCallback()
{ {
if (exiting) if (_exiting)
{ {
LibMAME.mame_lua_execute(MAMELuaCommand.Exit); LibMAME.mame_lua_execute(MAMELuaCommand.Exit);
exiting = false; _exiting = false;
} }
if (memAccess) if (_memAccess)
{ {
MAMEPeriodicComplete.Set(); _mamePeriodicComplete.Set();
MemoryAccessComplete.WaitOne(); _memoryAccessComplete.WaitOne();
return; return;
} }
//int MAMEFrame = LibMAME.mame_lua_get_int(MAMELuaCommand.GetFrameNumber); //int MAMEFrame = LibMAME.mame_lua_get_int(MAMELuaCommand.GetFrameNumber);
if (!paused) if (!_paused)
{ {
LibMAME.mame_lua_execute(MAMELuaCommand.Step); LibMAME.mame_lua_execute(MAMELuaCommand.Step);
frameDone = false; _frameDone = false;
paused = true; _paused = true;
} }
else if (!frameDone) else if (!_frameDone)
{ {
Update(); Update();
frameDone = true; _frameDone = true;
MAMEFrameComplete.Set(); _mameFrameComplete.Set();
} }
} }
@ -528,15 +544,15 @@ namespace BizHawk.Emulation.Cores.Arcades.MAME
return; return;
} }
numSamples = lengthInBytes / bytesPerSample; _numSamples = lengthInBytes / bytesPerSample;
unsafe unsafe
{ {
short* pSample = (short*)ptr.ToPointer(); short* pSample = (short*)ptr.ToPointer();
for (int i = 0; i < numSamples; i++) for (int i = 0; i < _numSamples; i++)
{ {
audioSamples.Enqueue(*(pSample + i)); _audioSamples.Enqueue(*(pSample + i));
dAudioSamples++; _dAudioSamples++;
} }
} }
@ -556,7 +572,7 @@ namespace BizHawk.Emulation.Cores.Arcades.MAME
UpdateGameName(); UpdateGameName();
InitMemoryDomains(); InitMemoryDomains();
MAMEStartupComplete.Set(); _mameStartupComplete.Set();
} }
private void MAMELogCallback(LibMAME.OutputChannel channel, int size, string data) private void MAMELogCallback(LibMAME.OutputChannel channel, int size, string data)
@ -568,7 +584,7 @@ namespace BizHawk.Emulation.Cores.Arcades.MAME
if (data.Contains("Fatal error")) if (data.Contains("Fatal error"))
{ {
MAMEStartupComplete.Set(); _mameStartupComplete.Set();
_loadFailure += data; _loadFailure += data;
} }
@ -593,15 +609,7 @@ namespace BizHawk.Emulation.Cores.Arcades.MAME
private void GetInputFields() private void GetInputFields()
{ {
IntPtr ptr = LibMAME.mame_lua_get_string(MAMELuaCommand.GetInputFields, out var lengthInBytes); string inputFields = MameGetString(MAMELuaCommand.GetInputFields);
if (ptr == IntPtr.Zero)
{
Console.WriteLine("LibMAME ERROR: string buffer pointer is null");
return;
}
string inputFields = Marshal.PtrToStringAnsi(ptr, lengthInBytes);
string[] portFields = inputFields.Split(';'); string[] portFields = inputFields.Split(';');
MAMEController.BoolButtons.Clear(); MAMEController.BoolButtons.Clear();
@ -613,15 +621,10 @@ namespace BizHawk.Emulation.Cores.Arcades.MAME
string tag = substrings.First(); string tag = substrings.First();
string field = substrings.Last(); string field = substrings.Last();
fieldsPorts.Add(field, tag); _fieldsPorts.Add(field, tag);
MAMEController.BoolButtons.Add(field); MAMEController.BoolButtons.Add(field);
} }
} }
if (!LibMAME.mame_lua_free_string(ptr))
{
Console.WriteLine("LibMAME ERROR: string buffer wasn't freed");
}
} }
#endregion #endregion