diff --git a/BizHawk.Client.EmuHawk/MainForm.cs b/BizHawk.Client.EmuHawk/MainForm.cs index f9ee25dd1e..5f425f7a1c 100644 --- a/BizHawk.Client.EmuHawk/MainForm.cs +++ b/BizHawk.Client.EmuHawk/MainForm.cs @@ -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); diff --git a/BizHawk.Common/Win32Hacks.cs b/BizHawk.Common/Win32Hacks.cs index 5405076205..88313cb295 100644 --- a/BizHawk.Common/Win32Hacks.cs +++ b/BizHawk.Common/Win32Hacks.cs @@ -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 + { + /// + /// On a Pentium, a floating-point precision error can occur in rare circumstances + /// + FloatingPointPrecisionErrata = 0, + /// + /// 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. + /// + FloatingPointEmulated = 1, + /// + /// The atomic compare and exchange operation (cmpxchg) is available + /// + CompareExchangeDouble = 2, + /// + /// The MMX instruction set is available + /// + InstructionsMMXAvailable = 3, + /// + /// The SSE instruction set is available + /// + InstructionsXMMIAvailable = 6, + /// + /// The 3D-Now instruction set is available. + /// + Instruction3DNowAvailable = 7, + /// + /// The RDTSC instruction is available + /// + InstructionRDTSCAvailable = 8, + /// + /// The processor is PAE-enabled + /// + PAEEnabled = 9, + /// + /// The SSE2 instruction set is available + /// + InstructionsXMMI64Available = 10, + /// + /// Data execution prevention is enabled. (This feature is not supported until Windows XP SP2 and Windows Server 2003 SP1) + /// + NXEnabled = 12, + /// + /// The SSE3 instruction set is available. (This feature is not supported until Windows Vista) + /// + InstructionsSSE3Available = 13, + /// + /// The atomic compare and exchange 128-bit operation (cmpxchg16b) is available. (This feature is not supported until Windows Vista) + /// + CompareExchange128 = 14, + /// + /// The atomic compare 64 and exchange 128-bit operation (cmp8xchg16) is available (This feature is not supported until Windows Vista.) + /// + Compare64Exchange128 = 15, + /// + /// TBD + /// + ChannelsEnabled = 16, + } + + } + //largely from https://raw.githubusercontent.com/noserati/tpl/master/ThreadAffinityTaskScheduler.cs (MIT license) public static class Win32ThreadHacks { diff --git a/BizHawk.Emulation.Cores/LibRetro.cs b/BizHawk.Emulation.Cores/LibRetro.cs index 124dc3cc5e..392a5d482a 100644 --- a/BizHawk.Emulation.Cores/LibRetro.cs +++ b/BizHawk.Emulation.Cores/LibRetro.cs @@ -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)] diff --git a/BizHawk.Emulation.Cores/LibRetroEmulator.cs b/BizHawk.Emulation.Cores/LibRetroEmulator.cs index 5e4e181787..c93e37827b 100644 --- a/BizHawk.Emulation.Cores/LibRetroEmulator.cs +++ b/BizHawk.Emulation.Cores/LibRetroEmulator.cs @@ -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 {