// inits only to get settings info // should only ever be called if no SettingsInfo cache exists statically within the core protected void InitForSettingsInfo(string wbxFilename) { _nyma = PreInit <LibNymaCore>(NymaWaterboxOptions(wbxFilename)); using (_exe.EnterExit()) { _nyma.PreInit(); var portData = GetInputPortsData(); InitAllSettingsInfo(portData); } }
protected T DoInit <T>(GameInfo game, byte[] rom, Disc[] discs, string wbxFilename, string extension, bool deterministic, IDictionary <string, FirmwareID> firmwares = null) where T : LibNymaCore { _settingsQueryDelegate = SettingsQuery; _cdTocCallback = CDTOCCallback; _cdSectorCallback = CDSectorCallback; var filesToRemove = new List <string>(); var firmwareDelegate = new LibNymaCore.FrontendFirmwareNotify((name) => { if (firmwares != null && firmwares.TryGetValue(name, out var id)) { var data = CoreComm.CoreFileProvider.GetFirmwareOrThrow(id, "Firmware files are usually required and may stop your game from loading"); _exe.AddReadonlyFile(data, name); filesToRemove.Add(name); } else { throw new InvalidOperationException($"Core asked for firmware `{name}`, but that was not understood by the system"); } }); var t = PreInit <T>(new WaterboxOptions { Filename = wbxFilename, // WaterboxHost only saves parts of memory that have changed, so not much to be gained by making these precisely sized SbrkHeapSizeKB = 1024 * 16, SealedHeapSizeKB = 1024 * 48, InvisibleHeapSizeKB = 1024 * 48, PlainHeapSizeKB = 1024 * 48, MmapHeapSizeKB = 1024 * 48, SkipCoreConsistencyCheck = CoreComm.CorePreferences.HasFlag(CoreComm.CorePreferencesFlags.WaterboxCoreConsistencyCheck), SkipMemoryConsistencyCheck = CoreComm.CorePreferences.HasFlag(CoreComm.CorePreferencesFlags.WaterboxMemoryConsistencyCheck), }, new Delegate[] { _settingsQueryDelegate, _cdTocCallback, _cdSectorCallback, firmwareDelegate }); _nyma = t; using (_exe.EnterExit()) { _nyma.PreInit(); _nyma.SetFrontendFirmwareNotify(firmwareDelegate); var portData = GetInputPortsData(); InitAllSettingsInfo(portData); _nyma.SetFrontendSettingQuery(_settingsQueryDelegate); if (discs?.Length > 0) { _disks = discs; _diskReaders = _disks.Select(d => new DiscSectorReader(d) { Policy = _diskPolicy }).ToArray(); _nyma.SetCDCallbacks(_cdTocCallback, _cdSectorCallback); var didInit = _nyma.InitCd(_disks.Length); if (!didInit) { throw new InvalidOperationException("Core rejected the CDs!"); } } else { var fn = game.FilesystemSafeName(); _exe.AddReadonlyFile(rom, fn); var didInit = _nyma.InitRom(new LibNymaCore.InitData { // TODO: Set these as some cores need them FileNameBase = "", FileNameExt = extension.Trim('.').ToLowerInvariant(), FileNameFull = fn }); if (!didInit) { throw new InvalidOperationException("Core rejected the rom!"); } _exe.RemoveReadonlyFile(fn); } foreach (var s in filesToRemove) { _exe.RemoveReadonlyFile(s); } // any later attempts to request a firmware will crash _nyma.SetFrontendFirmwareNotify(null); var info = *_nyma.GetSystemInfo(); _videoBuffer = new int[Math.Max(info.MaxWidth * info.MaxHeight, info.LcmWidth * info.LcmHeight)]; BufferWidth = info.NominalWidth; BufferHeight = info.NominalHeight; _mdfnNominalWidth = info.NominalWidth; _mdfnNominalHeight = info.NominalHeight; switch (info.VideoSystem) { // TODO: There seriously isn't any region besides these? case LibNymaCore.VideoSystem.PAL: case LibNymaCore.VideoSystem.SECAM: Region = DisplayType.PAL; break; case LibNymaCore.VideoSystem.PAL_M: Region = DisplayType.Dendy; // sort of... break; default: Region = DisplayType.NTSC; break; } VsyncNumerator = info.FpsFixed; VsyncDenominator = 1 << 24; _soundBuffer = new short[22050 * 2]; InitControls(portData, discs?.Length > 0, ref info); PostInit(); SettingsInfo.LayerNames = GetLayerData(); _settings.Normalize(SettingsInfo); _syncSettings.Normalize(SettingsInfo); _nyma.SetFrontendSettingQuery(_settingsQueryDelegate); if (_disks != null) { _nyma.SetCDCallbacks(_cdTocCallback, _cdSectorCallback); } PutSettings(_settings); DateTime RtcStart = DateTime.Parse("2010-01-01"); try { RtcStart = DateTime.Parse(SettingsQuery("nyma.rtcinitialtime")); } catch { Console.Error.WriteLine($"Couldn't parse DateTime \"{SettingsQuery("nyma.rtcinitialtime")}\""); } // Don't optimistically set deterministic, as some cores like faust can change this DeterministicEmulation = deterministic; // || SettingsQuery("nyma.rtcrealtime") == "0"; InitializeRtc(RtcStart); _frameThreadPtr = _nyma.GetFrameThreadProc(); if (_frameThreadPtr != IntPtr.Zero) { // This will probably be fine, right? TODO: Revisit // if (deterministic) // throw new InvalidOperationException("Internal error: Core set a frame thread proc in deterministic mode"); Console.WriteLine($"Setting up waterbox thread for {_frameThreadPtr}"); _frameThreadStart = CallingConventionAdapters.GetWaterboxUnsafeUnwrapped().GetDelegateForFunctionPointer <Action>(_frameThreadPtr); } } return(t); }
public ControllerAdapter(LibNymaCore core, IList <string> config) { var ret = new ControllerDefinition { Name = "Mednafen Controller" }; var finalDevices = new List <string>(); var numPorts = core.GetNumPorts(); if (numPorts > MAX_PORTS) { throw new InvalidOperationException($"Too many input ports"); } for (uint port = 0, devByteStart = 0; port < numPorts; port++, devByteStart += MAX_PORT_DATA) { var portInfo = *core.GetPort(port); var deviceName = port < config.Count ? config[(int)port] : portInfo.DefaultDeviceShortName; finalDevices.Add(deviceName); var devices = Enumerable.Range(0, (int)portInfo.NumDevices) .Select(i => new { Index = (uint)i, Device = *core.GetDevice(port, (uint)i) }) .ToList(); var device = devices.FirstOrDefault(a => a.Device.ShortName == deviceName); if (device == null) { Console.WriteLine($"Warn: unknown controller device {deviceName}"); device = devices.FirstOrDefault(a => a.Device.ShortName == portInfo.DefaultDeviceShortName); if (device == null) { throw new InvalidOperationException($"Fail: unknown controller device {portInfo.DefaultDeviceShortName}"); } } var deviceInfo = device.Device; if (deviceInfo.ByteLength > MAX_PORT_DATA) { throw new InvalidOperationException($"Input device {deviceInfo.ShortName} uses more than {MAX_PORT_DATA} bytes"); } var category = portInfo.FullName + " - " + deviceInfo.FullName; var inputs = Enumerable.Range(0, (int)deviceInfo.NumInputs) .Select(i => new { Index = i, Data = *core.GetInput(port, device.Index, (uint)i) }) .OrderBy(a => a.Data.ConfigOrder); foreach (var input in inputs) { var inputInfo = input.Data; var bitSize = (int)inputInfo.BitSize; var bitOffset = (int)inputInfo.BitOffset; var byteStart = devByteStart + bitOffset / 8; bitOffset %= 8; var name = $"P{port + 1} {inputInfo.Name}"; switch (inputInfo.Type) { case LibNymaCore.InputType.PADDING: { break; } case LibNymaCore.InputType.BUTTON: case LibNymaCore.InputType.BUTTON_CAN_RAPID: { // var data = *core.GetButton(port, device.Index, (uint)input.Index); // TODO: Wire up data.ExcludeName ret.BoolButtons.Add(name); _thunks.Add((c, b) => { if (c.IsPressed(name)) { b[byteStart] |= (byte)(1 << bitOffset); } }); break; } case LibNymaCore.InputType.SWITCH: { var data = *core.GetSwitch(port, device.Index, (uint)input.Index); var zzhacky = (int)data.DefaultPosition; // TODO: Possibly bulebutton for 2 states? ret.AxisControls.Add(name); ret.AxisRanges.Add(new ControllerDefinition.AxisRange( 0, (int)data.DefaultPosition, (int)data.NumPositions - 1)); _thunks.Add((c, b) => { // HACK: Silently discard this until bizhawk fixes its shit // var val = (int)Math.Round(c.AxisValue(name)); var val = zzhacky; b[byteStart] |= (byte)(val << bitOffset); }); break; } case LibNymaCore.InputType.AXIS: { // var data = core.GetAxis(port, device.Index, (uint)input.Index); ret.AxisControls.Add(name); ret.AxisRanges.Add(new ControllerDefinition.AxisRange( 0, 0x8000, 0xffff, (inputInfo.Flags & LibNymaCore.AxisFlags.INVERT_CO) != 0 )); _thunks.Add((c, b) => { var val = (ushort)Math.Round(c.AxisValue(name)); b[byteStart] = (byte)val; b[byteStart + 1] = (byte)(val >> 8); }); break; } case LibNymaCore.InputType.AXIS_REL: { // var data = core.GetAxis(port, device.Index, (uint)input.Index); ret.AxisControls.Add(name); ret.AxisRanges.Add(new ControllerDefinition.AxisRange( -0x8000, 0, 0x7fff, (inputInfo.Flags & LibNymaCore.AxisFlags.INVERT_CO) != 0 )); _thunks.Add((c, b) => { var val = (short)Math.Round(c.AxisValue(name)); b[byteStart] = (byte)val; b[byteStart + 1] = (byte)(val >> 8); }); break; } case LibNymaCore.InputType.POINTER_X: { throw new Exception("TODO: Axis ranges are ints????"); // ret.AxisControls.Add(name); // ret.AxisRanges.Add(new ControllerDefinition.AxisRange(0, 0.5, 1)); // break; } case LibNymaCore.InputType.POINTER_Y: { throw new Exception("TODO: Axis ranges are ints????"); // ret.AxisControls.Add(name); // ret.AxisRanges.Add(new ControllerDefinition.AxisRange(0, 0.5, 1, true)); // break; } // TODO: wire up statuses to something (not controller, of course) default: throw new NotImplementedException($"Unimplemented button type {inputInfo.Type}"); } ret.CategoryLabels[name] = category; } } Definition = ret; finalDevices.Add(null); Devices = finalDevices.ToArray(); }
protected T DoInit <T>(GameInfo game, byte[] rom, Disc[] discs, string wbxFilename, string extension, bool deterministic, ICollection <KeyValuePair <string, byte[]> > firmwares = null) where T : LibNymaCore { var t = PreInit <T>(new WaterboxOptions { Filename = wbxFilename, // MemoryBlock understands reserve vs commit semantics, so nothing to be gained by making these precisely sized SbrkHeapSizeKB = 1024 * 16, SealedHeapSizeKB = 1024 * 48, InvisibleHeapSizeKB = 1024 * 48, PlainHeapSizeKB = 1024 * 48, MmapHeapSizeKB = 1024 * 48, SkipCoreConsistencyCheck = CoreComm.CorePreferences.HasFlag(CoreComm.CorePreferencesFlags.WaterboxCoreConsistencyCheck), SkipMemoryConsistencyCheck = CoreComm.CorePreferences.HasFlag(CoreComm.CorePreferencesFlags.WaterboxMemoryConsistencyCheck), }); _nyma = t; _settingsQueryDelegate = new LibNymaCore.FrontendSettingQuery(SettingsQuery); using (_exe.EnterExit()) { _nyma.PreInit(); var portData = GetInputPortsData(); InitSyncSettingsInfo(portData); _nyma.SetFrontendSettingQuery(_settingsQueryDelegate); if (firmwares != null) { foreach (var kvp in firmwares) { _exe.AddReadonlyFile(kvp.Value, kvp.Key); } } if (discs?.Length > 0) { _disks = discs; _diskReaders = _disks.Select(d => new DiscSectorReader(d) { Policy = _diskPolicy }).ToArray(); _cdTocCallback = CDTOCCallback; _cdSectorCallback = CDSectorCallback; _nyma.SetCDCallbacks(_cdTocCallback, _cdSectorCallback); var didInit = _nyma.InitCd(_disks.Length); if (!didInit) { throw new InvalidOperationException("Core rejected the CDs!"); } } else { var fn = game.FilesystemSafeName(); _exe.AddReadonlyFile(rom, fn); var didInit = _nyma.InitRom(new LibNymaCore.InitData { // TODO: Set these as some cores need them FileNameBase = "", FileNameExt = extension.Trim('.').ToLowerInvariant(), FileNameFull = fn }); if (!didInit) { throw new InvalidOperationException("Core rejected the rom!"); } _exe.RemoveReadonlyFile(fn); } if (firmwares != null) { foreach (var kvp in firmwares) { _exe.RemoveReadonlyFile(kvp.Key); } } var info = *_nyma.GetSystemInfo(); _videoBuffer = new int[info.MaxWidth * info.MaxHeight]; BufferWidth = info.NominalWidth; BufferHeight = info.NominalHeight; switch (info.VideoSystem) { // TODO: There seriously isn't any region besides these? case LibNymaCore.VideoSystem.PAL: case LibNymaCore.VideoSystem.SECAM: Region = DisplayType.PAL; break; case LibNymaCore.VideoSystem.PAL_M: Region = DisplayType.Dendy; // sort of... break; default: Region = DisplayType.NTSC; break; } VsyncNumerator = info.FpsFixed; VsyncDenominator = 1 << 24; _soundBuffer = new short[22050 * 2]; InitControls(portData); _nyma.SetFrontendSettingQuery(null); if (_disks != null) { _nyma.SetCDCallbacks(null, null); } PostInit(); SettingsInfo.LayerNames = GetLayerData(); _nyma.SetFrontendSettingQuery(_settingsQueryDelegate); if (_disks != null) { _nyma.SetCDCallbacks(_cdTocCallback, _cdSectorCallback); } PutSettings(_settings); DateTime RtcStart = DateTime.Parse("2010-01-01"); try { RtcStart = DateTime.Parse(SettingsQuery("nyma.rtcinitialtime")); } catch { Console.Error.WriteLine($"Couldn't parse DateTime \"{SettingsQuery("nyma.rtcinitialtime")}\""); } // Don't optimistically set deterministic, as some cores like faust can change this DeterministicEmulation = deterministic; // || SettingsQuery("nyma.rtcrealtime") == "0"; InitializeRtc(RtcStart); _frameThreadPtr = _nyma.GetFrameThreadProc(); if (_frameThreadPtr != IntPtr.Zero) { if (deterministic) { throw new InvalidOperationException("Internal error: Core set a frame thread proc in deterministic mode"); } Console.WriteLine($"Setting up waterbox thread for {_frameThreadPtr}"); _frameThreadStart = CallingConventionAdapters.Waterbox.GetDelegateForFunctionPointer <Action>(_frameThreadPtr); } } return(t); }
protected T DoInit <T>(GameInfo game, byte[] rom, Disc[] discs, string wbxFilename, string extension, ICollection <KeyValuePair <string, byte[]> > firmwares = null) where T : LibNymaCore { var t = PreInit <T>(new WaterboxOptions { // TODO fix these up Filename = wbxFilename, SbrkHeapSizeKB = 1024 * 16, SealedHeapSizeKB = 1024 * 16, InvisibleHeapSizeKB = 1024 * 16, PlainHeapSizeKB = 1024 * 16, MmapHeapSizeKB = 1024 * 16, SkipCoreConsistencyCheck = CoreComm.CorePreferences.HasFlag(CoreComm.CorePreferencesFlags.WaterboxCoreConsistencyCheck), SkipMemoryConsistencyCheck = CoreComm.CorePreferences.HasFlag(CoreComm.CorePreferencesFlags.WaterboxMemoryConsistencyCheck), }); _nyma = t; _settingsQueryDelegate = new LibNymaCore.FrontendSettingQuery(SettingsQuery); using (_exe.EnterExit()) { _nyma.PreInit(); InitSyncSettingsInfo(); _nyma.SetFrontendSettingQuery(_settingsQueryDelegate); if (firmwares != null) { foreach (var kvp in firmwares) { _exe.AddReadonlyFile(kvp.Value, kvp.Key); } } if (discs?.Length > 0) { _disks = discs; _diskReaders = _disks.Select(d => new DiscSectorReader(d) { Policy = _diskPolicy }).ToArray(); _cdTocCallback = CDTOCCallback; _cdSectorCallback = CDSectorCallback; _nyma.SetCDCallbacks(_cdTocCallback, _cdSectorCallback); var didInit = _nyma.InitCd(_disks.Length); if (!didInit) { throw new InvalidOperationException("Core rejected the CDs!"); } } else { var fn = game.FilesystemSafeName(); _exe.AddReadonlyFile(rom, fn); var didInit = _nyma.InitRom(new LibNymaCore.InitData { // TODO: Set these as some cores need them FileNameBase = "", FileNameExt = extension.Trim('.').ToLowerInvariant(), FileNameFull = fn }); if (!didInit) { throw new InvalidOperationException("Core rejected the rom!"); } _exe.RemoveReadonlyFile(fn); } if (firmwares != null) { foreach (var kvp in firmwares) { _exe.RemoveReadonlyFile(kvp.Key); } } var info = *_nyma.GetSystemInfo(); _videoBuffer = new int[info.MaxWidth * info.MaxHeight]; BufferWidth = info.NominalWidth; BufferHeight = info.NominalHeight; switch (info.VideoSystem) { // TODO: There seriously isn't any region besides these? case LibNymaCore.VideoSystem.PAL: case LibNymaCore.VideoSystem.SECAM: Region = DisplayType.PAL; break; case LibNymaCore.VideoSystem.PAL_M: Region = DisplayType.Dendy; // sort of... break; default: Region = DisplayType.NTSC; break; } VsyncNumerator = info.FpsFixed; VsyncDenominator = 1 << 24; _soundBuffer = new short[22050 * 2]; InitControls(); _nyma.SetFrontendSettingQuery(null); _nyma.SetCDCallbacks(null, null); PostInit(); SettingsInfo.LayerNames = GetLayerData(); _nyma.SetFrontendSettingQuery(_settingsQueryDelegate); _nyma.SetCDCallbacks(_cdTocCallback, _cdSectorCallback); PutSettings(_settings); } return(t); }