fix rebooting of libretro cores, add CPU detection win32 hacks, add retro perf interface

This commit is contained in:
zeromus 2015-11-07 13:05:40 -06:00
parent cbdf6a2acc
commit 70b7098cb8
4 changed files with 158 additions and 4 deletions

View File

@ -836,7 +836,7 @@ namespace BizHawk.Client.EmuHawk
public void RebootCore()
{
var ioa = OpenAdvancedSerializer.ParseWithLegacy(CurrentlyOpenRom);
if (ioa is IOpenAdvancedLibretro)
if (ioa is OpenAdvanced_LibretroNoGame)
LoadRom("", CurrentlyOpenRomArgs);
else
LoadRom(ioa.SimplePath, CurrentlyOpenRomArgs);

View File

@ -4,6 +4,75 @@ using System.Runtime.InteropServices;
namespace BizHawk.Common
{
public static class Win32PInvokes
{
[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool IsProcessorFeaturePresent(ProcessorFeature processorFeature);
public enum ProcessorFeature : uint
{
/// <summary>
/// On a Pentium, a floating-point precision error can occur in rare circumstances
/// </summary>
FloatingPointPrecisionErrata = 0,
/// <summary>
/// Floating-point operations are emulated using a software emulator.
/// This function returns a nonzero value if floating-point operations are emulated; otherwise, it returns zero.
/// </summary>
FloatingPointEmulated = 1,
/// <summary>
/// The atomic compare and exchange operation (cmpxchg) is available
/// </summary>
CompareExchangeDouble = 2,
/// <summary>
/// The MMX instruction set is available
/// </summary>
InstructionsMMXAvailable = 3,
/// <summary>
/// The SSE instruction set is available
/// </summary>
InstructionsXMMIAvailable = 6,
/// <summary>
/// The 3D-Now instruction set is available.
/// </summary>
Instruction3DNowAvailable = 7,
/// <summary>
/// The RDTSC instruction is available
/// </summary>
InstructionRDTSCAvailable = 8,
/// <summary>
/// The processor is PAE-enabled
/// </summary>
PAEEnabled = 9,
/// <summary>
/// The SSE2 instruction set is available
/// </summary>
InstructionsXMMI64Available = 10,
/// <summary>
/// Data execution prevention is enabled. (This feature is not supported until Windows XP SP2 and Windows Server 2003 SP1)
/// </summary>
NXEnabled = 12,
/// <summary>
/// The SSE3 instruction set is available. (This feature is not supported until Windows Vista)
/// </summary>
InstructionsSSE3Available = 13,
/// <summary>
/// The atomic compare and exchange 128-bit operation (cmpxchg16b) is available. (This feature is not supported until Windows Vista)
/// </summary>
CompareExchange128 = 14,
/// <summary>
/// The atomic compare 64 and exchange 128-bit operation (cmp8xchg16) is available (This feature is not supported until Windows Vista.)
/// </summary>
Compare64Exchange128 = 15,
/// <summary>
/// TBD
/// </summary>
ChannelsEnabled = 16,
}
}
//largely from https://raw.githubusercontent.com/noserati/tpl/master/ThreadAffinityTaskScheduler.cs (MIT license)
public static class Win32ThreadHacks
{

View File

@ -263,6 +263,29 @@ namespace BizHawk.Emulation.Cores
SCROLLLOCK = 64
};
[Flags]
public enum RETRO_SIMD
{
SSE = (1 << 0),
SSE2 = (1 << 1),
VMX = (1 << 2),
VMX128 = (1 << 3),
AVX = (1 << 4),
NEON = (1 << 5),
SSE3 = (1 << 6),
SSSE3 = (1 << 7),
MMX = (1 << 8),
MMXEXT = (1 << 9),
SSE4 = (1 << 10),
SSE42 = (1 << 11),
AVX2 = (1 << 12),
VFPU = (1 << 13),
PS = (1 << 14),
AES = (1 << 15),
VFPV3 = (1 << 16),
VFPV4 = (1 << 17),
}
public enum RETRO_ENVIRONMENT
{
SET_ROTATION = 1,
@ -371,6 +394,46 @@ namespace BizHawk.Emulation.Cores
public string meta;
}
//untested
public struct retro_perf_counter
{
public string ident;
public ulong start;
public ulong total;
public ulong call_cnt;
[MarshalAs(UnmanagedType.U1)]
public bool registered;
};
//perf callbacks
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate long retro_perf_get_time_usec_t();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate long retro_perf_get_counter_t();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate ulong retro_get_cpu_features_t();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void retro_perf_log_t();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void retro_perf_register_t(ref retro_perf_counter counter);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void retro_perf_start_t(ref retro_perf_counter counter);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void retro_perf_stop_t(ref retro_perf_counter counter);
//for GET_PERF_INTERFACE
public struct retro_perf_callback
{
public retro_perf_get_time_usec_t get_time_usec;
public retro_get_cpu_features_t get_cpu_features;
public retro_perf_get_counter_t get_perf_counter;
public retro_perf_register_t perf_register;
public retro_perf_start_t perf_start;
public retro_perf_stop_t perf_stop;
public retro_perf_log_t perf_log;
}
#region callback prototypes
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
[return:MarshalAs(UnmanagedType.U1)]

View File

@ -114,6 +114,8 @@ namespace BizHawk.Emulation.Cores
case LibRetro.RETRO_ENVIRONMENT.SET_PERFORMANCE_LEVEL:
return false;
case LibRetro.RETRO_ENVIRONMENT.GET_SYSTEM_DIRECTORY:
//please write an example of a core that crashes without this (fmsx malfunctions..)
//"this is optional, but many cores will silently malfunction without it as they can't load their firmware files"
//an alternative (alongside where the saverams and such will go?)
//*((IntPtr*)data.ToPointer()) = unmanagedResources.StringToHGlobalAnsi(CoreComm.CoreFileProvider.GetGameBasePath());
*((IntPtr*)data.ToPointer()) = SystemDirectoryAtom;
@ -188,15 +190,18 @@ namespace BizHawk.Emulation.Cores
case LibRetro.RETRO_ENVIRONMENT.GET_LOG_INTERFACE:
return false;
case LibRetro.RETRO_ENVIRONMENT.GET_PERF_INTERFACE:
return false;
//some builds of fmsx core crash without this set
Marshal.StructureToPtr(retro_perf_callback, data, false);
return true;
case LibRetro.RETRO_ENVIRONMENT.GET_LOCATION_INTERFACE:
return false;
case LibRetro.RETRO_ENVIRONMENT.GET_CORE_ASSETS_DIRECTORY:
return false;
case LibRetro.RETRO_ENVIRONMENT.GET_SAVE_DIRECTORY:
//supposedly optional like everything else here, but without it ?? crashes (please write which case)
//this will suffice for now. if we find evidence later it's needed we can stash a string with
//unmanagedResources and CoreFileProvider
*((IntPtr*)data.ToPointer()) = IntPtr.Zero;
//*((IntPtr*)data.ToPointer()) = IntPtr.Zero;
return false;
case LibRetro.RETRO_ENVIRONMENT.SET_CONTROLLER_INFO:
return true;
@ -265,6 +270,8 @@ namespace BizHawk.Emulation.Cores
LibRetro.retro_input_poll_t retro_input_poll_cb;
LibRetro.retro_input_state_t retro_input_state_cb;
LibRetro.retro_perf_callback retro_perf_callback = new LibRetro.retro_perf_callback();
#endregion
private LibRetro retro;
@ -292,7 +299,7 @@ namespace BizHawk.Emulation.Cores
ServiceProvider = new BasicServiceProvider(this);
_SyncSettings = new SyncSettings();
retro_environment_cb = new LibRetro.retro_environment_t(retro_environment);
retro_video_refresh_cb = new LibRetro.retro_video_refresh_t(retro_video_refresh);
retro_audio_sample_cb = new LibRetro.retro_audio_sample_t(retro_audio_sample);
@ -300,6 +307,21 @@ namespace BizHawk.Emulation.Cores
retro_input_poll_cb = new LibRetro.retro_input_poll_t(retro_input_poll);
retro_input_state_cb = new LibRetro.retro_input_state_t(retro_input_state);
//no way (need new mechanism) to check for SSSE3, MMXEXT, SSE4, SSE42
retro_perf_callback.get_cpu_features = new LibRetro.retro_get_cpu_features_t(() => (ulong)(
(Win32PInvokes.IsProcessorFeaturePresent(Win32PInvokes.ProcessorFeature.InstructionsXMMIAvailable) ? LibRetro.RETRO_SIMD.SSE : 0) |
(Win32PInvokes.IsProcessorFeaturePresent(Win32PInvokes.ProcessorFeature.InstructionsXMMI64Available) ? LibRetro.RETRO_SIMD.SSE2 : 0) |
(Win32PInvokes.IsProcessorFeaturePresent(Win32PInvokes.ProcessorFeature.InstructionsSSE3Available) ? LibRetro.RETRO_SIMD.SSE3 : 0) |
(Win32PInvokes.IsProcessorFeaturePresent(Win32PInvokes.ProcessorFeature.InstructionsMMXAvailable) ? LibRetro.RETRO_SIMD.MMX : 0)
) );
retro_perf_callback.get_perf_counter = new LibRetro.retro_perf_get_counter_t(() => System.Diagnostics.Stopwatch.GetTimestamp());
retro_perf_callback.get_time_usec = new LibRetro.retro_perf_get_time_usec_t(() => DateTime.Now.Ticks / 10);
retro_perf_callback.perf_log = new LibRetro.retro_perf_log_t( () => {} );
retro_perf_callback.perf_register = new LibRetro.retro_perf_register_t((ref LibRetro.retro_perf_counter counter) => { });
retro_perf_callback.perf_start = new LibRetro.retro_perf_start_t((ref LibRetro.retro_perf_counter counter) => { });
retro_perf_callback.perf_stop = new LibRetro.retro_perf_stop_t((ref LibRetro.retro_perf_counter counter) => { });
retro = new LibRetro(modulename);
try
{