static Sameboy() { var resolver = new DynamicLibraryImportResolver( OSTailoredCode.IsUnixHost ? "libsameboy.so" : "libsameboy.dll", hasLimitedLifetime: false); LibSameboy = BizInvoker.GetInvoker <LibSameboy>(resolver, CallingConventionAdapters.Native); }
static SpeexResampler() { var resolver = new DynamicLibraryImportResolver( OSTailoredCode.IsUnixHost ? "libspeexdsp.so.1" : "libspeexdsp.dll", hasLimitedLifetime: false); NativeDSP = BizInvoker.GetInvoker <LibSpeexDSP>(resolver, CallingConventionAdapters.Native); }
static Lynx() { var resolver = new DynamicLibraryImportResolver( OSTailoredCode.IsUnixHost ? "libbizlynx.dll.so" : "bizlynx.dll", hasLimitedLifetime: false); LibLynx = BizInvoker.GetInvoker <LibLynx>(resolver, CallingConventionAdapters.Native); }
static MGBAHawk() { var resolver = new DynamicLibraryImportResolver( OSTailoredCode.IsUnixHost ? "libmgba.dll.so" : "mgba.dll", hasLimitedLifetime: false); LibmGBA = BizInvoker.GetInvoker <LibmGBA>(resolver, CallingConventionAdapters.Native); }
static QuickNES() { var resolver = new DynamicLibraryImportResolver( $"libquicknes{(OSTailoredCode.IsUnixHost ? ".dll.so.0.7.0" : ".dll")}", hasLimitedLifetime: false); QN = BizInvoker.GetInvoker <LibQuickNES>(resolver, CallingConventionAdapters.Native); QN.qn_setup_mappers(); }
public LibretroEmulator(CoreComm comm, IGameInfo game, string corePath, bool analysis = false) { try { cbHandler = bridge.LibretroBridge_CreateCallbackHandler(); if (cbHandler == IntPtr.Zero) { throw new Exception("Failed to create callback handler!"); } UpdateCallbackHandler(); api = BizInvoker.GetInvoker <LibretroApi>( new DynamicLibraryImportResolver(corePath, hasLimitedLifetime: false), CallingConventionAdapters.Native); _serviceProvider = new(this); Comm = comm; if (api.retro_api_version() != 1) { throw new InvalidOperationException("Unsupported Libretro API version (or major error in interop)"); } var SystemDirectory = RetroString(Comm.CoreFileProvider.GetRetroSystemPath(game)); var SaveDirectory = RetroString(Comm.CoreFileProvider.GetRetroSaveRAMDirectory(game)); var CoreDirectory = RetroString(Path.GetDirectoryName(corePath)); var CoreAssetsDirectory = RetroString(Path.GetDirectoryName(corePath)); bridge.LibretroBridge_SetDirectories(cbHandler, SystemDirectory, SaveDirectory, CoreDirectory, CoreAssetsDirectory); ControllerDefinition = CreateControllerDefinition(); // check if we're just analysing the core and the core path matches the loaded core path anyways if (analysis && corePath == LoadedCorePath) { Description = CalculateDescription(); Description.SupportsNoGame = LoadedCoreSupportsNoGame; // don't set init, we don't want the core deinit later } else { api.retro_set_environment(cb_procs.retro_environment_proc); Description = CalculateDescription(); } if (!analysis) { LoadedCorePath = corePath; LoadedCoreSupportsNoGame = Description.SupportsNoGame; } } catch { Dispose(); throw; } }
static WaterboxHost() { NativeImpl = BizInvoker.GetInvoker <WaterboxHostNative>( new DynamicLibraryImportResolver(OSTailoredCode.IsUnixHost ? "libwaterboxhost.so" : "waterboxhost.dll", eternal: true), CallingConventionAdapters.Native); #if !DEBUG NativeImpl.wbx_set_always_evict_blocks(false); #endif }
static LibretroEmulator() { var resolver = new DynamicLibraryImportResolver( OSTailoredCode.IsUnixHost ? "libLibretroBridge.so" : "libLibretroBridge.dll", hasLimitedLifetime: false); bridge = BizInvoker.GetInvoker <LibretroBridge>(resolver, CallingConventionAdapters.Native); cb_procs = new(); bridge.LibretroBridge_GetRetroProcs(ref cb_procs); }
protected T PreInit <T>(WaterboxOptions options) where T : LibWaterboxCore { options.Path ??= CoreComm.CoreFileProvider.DllPath(); _exe = new WaterboxHost(options); using (_exe.EnterExit()) { var ret = BizInvoker.GetInvoker <T>(_exe, _exe, CallingConventionAdapters.Waterbox); _core = ret; return(ret); } }
protected T PreInit <T>(PeRunnerOptions options) where T : LibWaterboxCore { if (options.Path == null) { options.Path = CoreComm.CoreFileProvider.DllPath(); } _exe = new PeRunner(options); using (_exe.EnterExit()) { var ret = BizInvoker.GetInvoker <T>(_exe, _exe, CallingConventionAdapters.Waterbox); _core = ret; return(ret); } }
protected T PreInit <T>(WaterboxOptions options, IEnumerable <Delegate> allExtraDelegates = null) where T : LibWaterboxCore { options.Path ??= CoreComm.CoreFileProvider.DllPath(); _exe = new WaterboxHost(options); var delegates = new Delegate[] { _inputCallback }.AsEnumerable(); if (allExtraDelegates != null) { delegates = delegates.Concat(allExtraDelegates); } using (_exe.EnterExit()) { var ret = BizInvoker.GetInvoker <T>(_exe, _exe, CallingConventionAdapters.MakeWaterbox(delegates, _exe)); _core = ret; return(ret); } }
public LibsnesApi(string dllPath) { _exe = new PeRunner(new PeRunnerOptions { Filename = "libsnes.wbx", Path = dllPath, SbrkHeapSizeKB = 4 * 1024, InvisibleHeapSizeKB = 8 * 1024, MmapHeapSizeKB = 32 * 1024, // TODO: see if we can safely make libco stacks smaller PlainHeapSizeKB = 2 * 1024, // TODO: wasn't there more in here? SealedHeapSizeKB = 128 * 1024 }); using (_exe.EnterExit()) { // Marshal checks that function pointers passed to GetDelegateForFunctionPointer are // _currently_ valid when created, even though they don't need to be valid until // the delegate is later invoked. so GetInvoker needs to be acquired within a lock. _core = BizInvoker.GetInvoker <CoreImpl>(_exe, _exe, CallingConventionAdapters.Waterbox); _comm = (CommStruct *)_core.DllInit().ToPointer(); } }
public LibsnesApi(string dllPath, CoreComm comm, IEnumerable <Delegate> allCallbacks) { _exe = new WaterboxHost(new WaterboxOptions { Filename = "libsnes.wbx", Path = dllPath, SbrkHeapSizeKB = 4 * 1024, InvisibleHeapSizeKB = 8 * 1024, MmapHeapSizeKB = 32 * 1024, // TODO: see if we can safely make libco stacks smaller PlainHeapSizeKB = 2 * 1024, // TODO: wasn't there more in here? SealedHeapSizeKB = 128 * 1024, SkipCoreConsistencyCheck = comm.CorePreferences.HasFlag(CoreComm.CorePreferencesFlags.WaterboxCoreConsistencyCheck), SkipMemoryConsistencyCheck = comm.CorePreferences.HasFlag(CoreComm.CorePreferencesFlags.WaterboxMemoryConsistencyCheck), }); using (_exe.EnterExit()) { // Marshal checks that function pointers passed to GetDelegateForFunctionPointer are // _currently_ valid when created, even though they don't need to be valid until // the delegate is later invoked. so GetInvoker needs to be acquired within a lock. _core = BizInvoker.GetInvoker <CoreImpl>(_exe, _exe, CallingConventionAdapters.MakeWaterbox(allCallbacks, _exe)); _comm = (CommStruct *)_core.DllInit().ToPointer(); } }
public GPGX(CoreComm comm, byte[] rom, IEnumerable <Disc> cds, object settings, object syncSettings) { ServiceProvider = new BasicServiceProvider(this); // this can influence some things internally (autodetect romtype, etc) string romextension = "GEN"; // three or six button? // http://www.sega-16.com/forum/showthread.php?4398-Forgotten-Worlds-giving-you-GAME-OVER-immediately-Fix-inside&highlight=forgotten%20worlds //hack, don't use if (rom != null && rom.Length > 32 * 1024 * 1024) { throw new InvalidOperationException("ROM too big! Did you try to load a CD as a ROM?"); } _elf = new PeRunner(new PeRunnerOptions { Path = comm.CoreFileProvider.DllPath(), Filename = "gpgx.wbx", SbrkHeapSizeKB = 512, SealedHeapSizeKB = 36 * 1024, InvisibleHeapSizeKB = 4 * 1024, PlainHeapSizeKB = 64, MmapHeapSizeKB = 1 * 1024 }); using (_elf.EnterExit()) { Core = BizInvoker.GetInvoker <LibGPGX>(_elf, _elf, CallingConventionAdapters.Waterbox); _syncSettings = (GPGXSyncSettings)syncSettings ?? new GPGXSyncSettings(); _settings = (GPGXSettings)settings ?? new GPGXSettings(); CoreComm = comm; LoadCallback = new LibGPGX.load_archive_cb(load_archive); _romfile = rom; if (cds != null) { _cds = cds.ToArray(); _cdReaders = cds.Select(c => new DiscSectorReader(c)).ToArray(); cd_callback_handle = new LibGPGX.cd_read_cb(CDRead); Core.gpgx_set_cdd_callback(cd_callback_handle); DriveLightEnabled = true; } LibGPGX.INPUT_SYSTEM system_a = LibGPGX.INPUT_SYSTEM.SYSTEM_NONE; LibGPGX.INPUT_SYSTEM system_b = LibGPGX.INPUT_SYSTEM.SYSTEM_NONE; switch (_syncSettings.ControlType) { case ControlType.None: default: break; case ControlType.Activator: system_a = LibGPGX.INPUT_SYSTEM.SYSTEM_ACTIVATOR; system_b = LibGPGX.INPUT_SYSTEM.SYSTEM_ACTIVATOR; break; case ControlType.Normal: system_a = LibGPGX.INPUT_SYSTEM.SYSTEM_MD_GAMEPAD; system_b = LibGPGX.INPUT_SYSTEM.SYSTEM_MD_GAMEPAD; break; case ControlType.OnePlayer: system_a = LibGPGX.INPUT_SYSTEM.SYSTEM_MD_GAMEPAD; break; case ControlType.Xea1p: system_a = LibGPGX.INPUT_SYSTEM.SYSTEM_XE_A1P; break; case ControlType.Teamplayer: system_a = LibGPGX.INPUT_SYSTEM.SYSTEM_TEAMPLAYER; system_b = LibGPGX.INPUT_SYSTEM.SYSTEM_TEAMPLAYER; break; case ControlType.Wayplay: system_a = LibGPGX.INPUT_SYSTEM.SYSTEM_WAYPLAY; system_b = LibGPGX.INPUT_SYSTEM.SYSTEM_WAYPLAY; break; case ControlType.Mouse: system_a = LibGPGX.INPUT_SYSTEM.SYSTEM_MD_GAMEPAD; // seems like mouse in port 1 would be supported, but not both at the same time system_b = LibGPGX.INPUT_SYSTEM.SYSTEM_MOUSE; break; } if (!Core.gpgx_init(romextension, LoadCallback, _syncSettings.UseSixButton, system_a, system_b, _syncSettings.Region, _syncSettings.GetNativeSettings())) { throw new Exception($"{nameof(Core.gpgx_init)}() failed"); } { int fpsnum = 60; int fpsden = 1; Core.gpgx_get_fps(ref fpsnum, ref fpsden); VsyncNumerator = fpsnum; VsyncDenominator = fpsden; Region = VsyncNumerator / VsyncDenominator > 55 ? DisplayType.NTSC : DisplayType.PAL; } // when we call Seal, ANY pointer passed from managed code must be 0. // this is so the initial state is clean // the only two pointers set so far are LoadCallback, which the core zeroed itself, // and CdCallback Core.gpgx_set_cdd_callback(null); _elf.Seal(); Core.gpgx_set_cdd_callback(cd_callback_handle); SetControllerDefinition(); // pull the default video size from the core UpdateVideo(); SetMemoryDomains(); InputCallback = new LibGPGX.input_cb(input_callback); Core.gpgx_set_input_callback(InputCallback); // process the non-init settings now PutSettings(_settings); //TODO - this hits performance, we need to make it controllable CDCallback = new LibGPGX.CDCallback(CDCallbackProc); InitMemCallbacks(); KillMemCallbacks(); _tracer = new GPGXTraceBuffer(this, MemoryDomains, this); (ServiceProvider as BasicServiceProvider).Register <ITraceable>(_tracer); } _romfile = null; }
static QuickNES() { Resolver = new DynamicLibraryImportResolver(LibQuickNES.dllname); QN = BizInvoker.GetInvoker <LibQuickNES>(Resolver); }
public static MemoryDomainAccessStub Create(IntPtr p, IMonitor monitor) { return(BizInvoker.GetInvoker <MemoryDomainAccessStub>(new StubResolver(p), monitor, CallingConventionAdapters.Waterbox)); }
public GPGX(CoreLoadParameters <GPGXSettings, GPGXSyncSettings> lp) { LoadCallback = new LibGPGX.load_archive_cb(load_archive); _inputCallback = new LibGPGX.input_cb(input_callback); InitMemCallbacks(); // ExecCallback, ReadCallback, WriteCallback CDCallback = new LibGPGX.CDCallback(CDCallbackProc); cd_callback_handle = new LibGPGX.cd_read_cb(CDRead); ServiceProvider = new BasicServiceProvider(this); // this can influence some things internally (autodetect romtype, etc) string romextension = "GEN"; // three or six button? // http://www.sega-16.com/forum/showthread.php?4398-Forgotten-Worlds-giving-you-GAME-OVER-immediately-Fix-inside&highlight=forgotten%20worlds //hack, don't use if (lp.Roms.FirstOrDefault()?.RomData.Length > 32 * 1024 * 1024) { throw new InvalidOperationException("ROM too big! Did you try to load a CD as a ROM?"); } _elf = new WaterboxHost(new WaterboxOptions { Path = lp.Comm.CoreFileProvider.DllPath(), Filename = "gpgx.wbx", SbrkHeapSizeKB = 512, SealedHeapSizeKB = 4 * 1024, InvisibleHeapSizeKB = 4 * 1024, PlainHeapSizeKB = 34 * 1024, MmapHeapSizeKB = 1 * 1024, SkipCoreConsistencyCheck = lp.Comm.CorePreferences.HasFlag(CoreComm.CorePreferencesFlags.WaterboxCoreConsistencyCheck), SkipMemoryConsistencyCheck = lp.Comm.CorePreferences.HasFlag(CoreComm.CorePreferencesFlags.WaterboxMemoryConsistencyCheck), }); var callingConventionAdapter = CallingConventionAdapters.MakeWaterbox(new Delegate[] { LoadCallback, _inputCallback, ExecCallback, ReadCallback, WriteCallback, CDCallback, cd_callback_handle, }, _elf); using (_elf.EnterExit()) { Core = BizInvoker.GetInvoker <LibGPGX>(_elf, _elf, callingConventionAdapter); _syncSettings = lp.SyncSettings ?? new GPGXSyncSettings(); _settings = lp.Settings ?? new GPGXSettings(); CoreComm = lp.Comm; _romfile = lp.Roms.FirstOrDefault()?.RomData; if (lp.Discs.Count > 0) { _cds = lp.Discs.Select(d => d.DiscData).ToArray(); _cdReaders = _cds.Select(c => new DiscSectorReader(c)).ToArray(); Core.gpgx_set_cdd_callback(cd_callback_handle); DriveLightEnabled = true; } LibGPGX.INPUT_SYSTEM system_a = SystemForSystem(_syncSettings.ControlTypeLeft); LibGPGX.INPUT_SYSTEM system_b = SystemForSystem(_syncSettings.ControlTypeRight); var initResult = Core.gpgx_init(romextension, LoadCallback, _syncSettings.GetNativeSettings(lp.Game)); if (!initResult) { throw new Exception($"{nameof(Core.gpgx_init)}() failed"); } { int fpsnum = 60; int fpsden = 1; Core.gpgx_get_fps(ref fpsnum, ref fpsden); VsyncNumerator = fpsnum; VsyncDenominator = fpsden; Region = VsyncNumerator / VsyncDenominator > 55 ? DisplayType.NTSC : DisplayType.PAL; } // when we call Seal, ANY pointer passed from managed code must be 0. // this is so the initial state is clean // the only two pointers set so far are LoadCallback, which the core zeroed itself, // and CdCallback Core.gpgx_set_cdd_callback(null); _elf.Seal(); Core.gpgx_set_cdd_callback(cd_callback_handle); SetControllerDefinition(); // pull the default video size from the core UpdateVideo(); SetMemoryDomains(); Core.gpgx_set_input_callback(_inputCallback); // process the non-init settings now PutSettings(_settings); KillMemCallbacks(); _tracer = new GPGXTraceBuffer(this, _memoryDomains, this); (ServiceProvider as BasicServiceProvider).Register <ITraceable>(_tracer); } _romfile = null; }
public static MemoryDomainAccessStub Create(IntPtr p, WaterboxHost host) { return(BizInvoker.GetInvoker <MemoryDomainAccessStub>( new StubResolver(p), host, CallingConventionAdapters.MakeWaterboxDepartureOnly(host))); }
public GPGX(CoreComm comm, byte[] rom, DiscSystem.Disc CD, object Settings, object SyncSettings) { ServiceProvider = new BasicServiceProvider(this); // this can influence some things internally (autodetect romtype, etc) string romextension = "GEN"; // three or six button? // http://www.sega-16.com/forum/showthread.php?4398-Forgotten-Worlds-giving-you-GAME-OVER-immediately-Fix-inside&highlight=forgotten%20worlds //hack, don't use if (rom != null && rom.Length > 32 * 1024 * 1024) { throw new InvalidOperationException("ROM too big! Did you try to load a CD as a ROM?"); } try { Elf = new ElfRunner(Path.Combine(comm.CoreFileProvider.DllPath(), "gpgx.elf"), 8 * 1024 * 1024, 36 * 1024 * 1024, 4 * 1024 * 1024); if (Elf.ShouldMonitor) { Core = BizInvoker.GetInvoker <LibGPGX>(Elf, Elf); } else { Core = BizInvoker.GetInvoker <LibGPGX>(Elf); } _syncSettings = (GPGXSyncSettings)SyncSettings ?? new GPGXSyncSettings(); _settings = (GPGXSettings)Settings ?? new GPGXSettings(); CoreComm = comm; LoadCallback = new LibGPGX.load_archive_cb(load_archive); this.romfile = rom; this.CD = CD; if (CD != null) { this.DiscSectorReader = new DiscSystem.DiscSectorReader(CD); cd_callback_handle = new LibGPGX.cd_read_cb(CDRead); Core.gpgx_set_cdd_callback(cd_callback_handle); } LibGPGX.INPUT_SYSTEM system_a = LibGPGX.INPUT_SYSTEM.SYSTEM_NONE; LibGPGX.INPUT_SYSTEM system_b = LibGPGX.INPUT_SYSTEM.SYSTEM_NONE; switch (_syncSettings.ControlType) { case ControlType.None: default: break; case ControlType.Activator: system_a = LibGPGX.INPUT_SYSTEM.SYSTEM_ACTIVATOR; system_b = LibGPGX.INPUT_SYSTEM.SYSTEM_ACTIVATOR; break; case ControlType.Normal: system_a = LibGPGX.INPUT_SYSTEM.SYSTEM_MD_GAMEPAD; system_b = LibGPGX.INPUT_SYSTEM.SYSTEM_MD_GAMEPAD; break; case ControlType.OnePlayer: system_a = LibGPGX.INPUT_SYSTEM.SYSTEM_MD_GAMEPAD; break; case ControlType.Xea1p: system_a = LibGPGX.INPUT_SYSTEM.SYSTEM_XE_A1P; break; case ControlType.Teamplayer: system_a = LibGPGX.INPUT_SYSTEM.SYSTEM_TEAMPLAYER; system_b = LibGPGX.INPUT_SYSTEM.SYSTEM_TEAMPLAYER; break; case ControlType.Wayplay: system_a = LibGPGX.INPUT_SYSTEM.SYSTEM_WAYPLAY; system_b = LibGPGX.INPUT_SYSTEM.SYSTEM_WAYPLAY; break; case ControlType.Mouse: system_a = LibGPGX.INPUT_SYSTEM.SYSTEM_MD_GAMEPAD; // seems like mouse in port 1 would be supported, but not both at the same time system_b = LibGPGX.INPUT_SYSTEM.SYSTEM_MOUSE; break; } if (!Core.gpgx_init(romextension, LoadCallback, _syncSettings.UseSixButton, system_a, system_b, _syncSettings.Region, _settings.GetNativeSettings())) { throw new Exception("gpgx_init() failed"); } { int fpsnum = 60; int fpsden = 1; Core.gpgx_get_fps(ref fpsnum, ref fpsden); CoreComm.VsyncNum = fpsnum; CoreComm.VsyncDen = fpsden; Region = CoreComm.VsyncRate > 55 ? DisplayType.NTSC : DisplayType.PAL; } // compute state size InitStateBuffers(); SetControllerDefinition(); // pull the default video size from the core UpdateVideoInitial(); SetMemoryDomains(); InputCallback = new LibGPGX.input_cb(input_callback); Core.gpgx_set_input_callback(InputCallback); if (CD != null) { DriveLightEnabled = true; } // process the non-init settings now PutSettings(_settings); //TODO - this hits performance, we need to make it controllable CDCallback = new LibGPGX.CDCallback(CDCallbackProc); InitMemCallbacks(); KillMemCallbacks(); Tracer = new GPGXTraceBuffer(this, MemoryDomains, this); (ServiceProvider as BasicServiceProvider).Register <ITraceable>(Tracer); Elf.Seal(); } catch { Dispose(); throw; } }
static QuickNES() { Resolver = new DynamicLibraryImportResolver($"libquicknes{(OSTailoredCode.CurrentOS == OSTailoredCode.DistinctOS.Windows ? ".dll" : ".dll.so.0.7.0")}"); QN = BizInvoker.GetInvoker <LibQuickNES>(Resolver, CallingConventionAdapters.Native); QN.qn_setup_mappers(); }
static QuickNES() { Resolver = new DynamicLibraryImportResolver(LibQuickNES.dllname); QN = BizInvoker.GetInvoker <LibQuickNES>(Resolver, CallingConventionAdapters.Native); }
static QuickNES() { Resolver = new DynamicLibraryImportResolver("libquicknes.dll" + (PlatformLinkedLibSingleton.RunningOnUnix ? ".so" : String.Empty)); QN = BizInvoker.GetInvoker <LibQuickNES>(Resolver, CallingConventionAdapters.Native); QN.qn_setup_mappers(); }