From 69d3dbc35f1faf011c97d16984cc477b8b21726e Mon Sep 17 00:00:00 2001 From: nattthebear Date: Sun, 24 May 2020 11:42:39 -0400 Subject: [PATCH] pce: basic rom loading and playing works --- src/BizHawk.Common/PtrToStringUtf8.cs | 20 ++ .../Waterbox/ElfLoader.cs | 2 + .../Waterbox/EmuLibc.cs | 4 +- .../Waterbox/LibNymaCore.cs | 51 +++-- .../Waterbox/LibWaterboxCore.cs | 2 +- .../Waterbox/NymaCore.Controller.cs | 185 ++++++++++++++++++ .../Waterbox/NymaCore.cs | 167 +--------------- .../Waterbox/WaterboxCore.cs | 18 +- waterbox/nyma/NymaCore.cpp | 59 ++++-- 9 files changed, 302 insertions(+), 206 deletions(-) create mode 100644 src/BizHawk.Common/PtrToStringUtf8.cs create mode 100644 src/BizHawk.Emulation.Cores/Waterbox/NymaCore.Controller.cs diff --git a/src/BizHawk.Common/PtrToStringUtf8.cs b/src/BizHawk.Common/PtrToStringUtf8.cs new file mode 100644 index 0000000000..1a234ab210 --- /dev/null +++ b/src/BizHawk.Common/PtrToStringUtf8.cs @@ -0,0 +1,20 @@ +using System; +using System.Text; + +namespace BizHawk.Common +{ + public static class Mershul + { + /// + /// TODO: Update to a version of .nyet that includes this + /// + public static unsafe string PtrToStringUtf8(IntPtr p) + { + byte* b = (byte*)p; + int len = 0; + while (*b++ != 0) + len++; + return Encoding.UTF8.GetString((byte*)p, len); + } + } +} diff --git a/src/BizHawk.Emulation.Cores/Waterbox/ElfLoader.cs b/src/BizHawk.Emulation.Cores/Waterbox/ElfLoader.cs index 9605630ed6..5251cc06b7 100644 --- a/src/BizHawk.Emulation.Cores/Waterbox/ElfLoader.cs +++ b/src/BizHawk.Emulation.Cores/Waterbox/ElfLoader.cs @@ -195,10 +195,12 @@ namespace BizHawk.Emulation.Cores.Waterbox /// private bool IsSpecialReadonlySection(Section sec) { + // TODO: I don't think there are any more relro sections, right? return sec.Name.Contains(".rel.ro") || sec.Name.StartsWith(".got") || sec.Name == ".init_array" || sec.Name == ".fini_array" + || sec.Name == ".tbss" || sec == _imports || sec == _sealed; } diff --git a/src/BizHawk.Emulation.Cores/Waterbox/EmuLibc.cs b/src/BizHawk.Emulation.Cores/Waterbox/EmuLibc.cs index 10853a6cc9..367609f5ef 100644 --- a/src/BizHawk.Emulation.Cores/Waterbox/EmuLibc.cs +++ b/src/BizHawk.Emulation.Cores/Waterbox/EmuLibc.cs @@ -1,6 +1,7 @@ using System; using System.Runtime.InteropServices; using BizHawk.BizInvoke; +using BizHawk.Common; namespace BizHawk.Emulation.Cores.Waterbox { @@ -36,8 +37,7 @@ namespace BizHawk.Emulation.Cores.Waterbox [BizExport(CallingConvention.Cdecl, EntryPoint = "__w_debug_puts")] public void DebugPuts(IntPtr s) { - // TODO: Should be PtrToStringUtf8 - Console.WriteLine(Marshal.PtrToStringAnsi(s)); + Console.WriteLine(Mershul.PtrToStringUtf8(s)); } } } diff --git a/src/BizHawk.Emulation.Cores/Waterbox/LibNymaCore.cs b/src/BizHawk.Emulation.Cores/Waterbox/LibNymaCore.cs index 3620a918fa..84d81fb6f0 100644 --- a/src/BizHawk.Emulation.Cores/Waterbox/LibNymaCore.cs +++ b/src/BizHawk.Emulation.Cores/Waterbox/LibNymaCore.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Runtime.InteropServices; using BizHawk.BizInvoke; +using BizHawk.Common; namespace BizHawk.Emulation.Cores.Waterbox { @@ -59,7 +60,11 @@ namespace BizHawk.Emulation.Cores.Waterbox /// /// true to skip video rendering /// - public int SkipRendering; + public short SkipRendering; + /// + /// true to skip audion rendering + /// + public short SkipSoundening; /// /// a single command to run at the start of this frame /// @@ -129,9 +134,9 @@ namespace BizHawk.Emulation.Cores.Waterbox public IntPtr _defaultDeviceShortName; public uint NumDevices; - public string ShortName => Marshal.PtrToStringAnsi(_shortName); - public string FullName => Marshal.PtrToStringAnsi(_fullName); - public string DefaultDeviceShortName => Marshal.PtrToStringAnsi(_defaultDeviceShortName); + public string ShortName => Mershul.PtrToStringUtf8(_shortName); + public string FullName => Mershul.PtrToStringUtf8(_fullName); + public string DefaultDeviceShortName => Mershul.PtrToStringUtf8(_defaultDeviceShortName); } [StructLayout(LayoutKind.Sequential)] public struct NDeviceInfo @@ -143,9 +148,9 @@ namespace BizHawk.Emulation.Cores.Waterbox public uint ByteLength; public uint NumInputs; - public string ShortName => Marshal.PtrToStringAnsi(_shortName); - public string FullName => Marshal.PtrToStringAnsi(_fullName); - public string Description => Marshal.PtrToStringAnsi(_description); + public string ShortName => Mershul.PtrToStringUtf8(_shortName); + public string FullName => Mershul.PtrToStringUtf8(_fullName); + public string Description => Mershul.PtrToStringUtf8(_description); } [StructLayout(LayoutKind.Sequential)] public struct NInputInfo @@ -158,15 +163,15 @@ namespace BizHawk.Emulation.Cores.Waterbox public AxisFlags Flags; public byte BitSize; - public string SettingName => Marshal.PtrToStringAnsi(_settingName); - public string Name => Marshal.PtrToStringAnsi(_name); + public string SettingName => Mershul.PtrToStringUtf8(_settingName); + public string Name => Mershul.PtrToStringUtf8(_name); } [StructLayout(LayoutKind.Sequential)] public struct NButtonInfo { public IntPtr _excludeName; - public string ExcludeName => Marshal.PtrToStringAnsi(_excludeName); + public string ExcludeName => Mershul.PtrToStringUtf8(_excludeName); } [StructLayout(LayoutKind.Sequential)] public struct NAxisInfo @@ -176,10 +181,10 @@ namespace BizHawk.Emulation.Cores.Waterbox public IntPtr _nameNeg; public IntPtr _namePos; - public string SettingsNameNeg => Marshal.PtrToStringAnsi(_settingsNameNeg); - public string SettingsNamePos => Marshal.PtrToStringAnsi(_settingsNamePos); - public string NameNeg => Marshal.PtrToStringAnsi(_nameNeg); - public string NamePos => Marshal.PtrToStringAnsi(_namePos); + public string SettingsNameNeg => Mershul.PtrToStringUtf8(_settingsNameNeg); + public string SettingsNamePos => Mershul.PtrToStringUtf8(_settingsNamePos); + public string NameNeg => Mershul.PtrToStringUtf8(_nameNeg); + public string NamePos => Mershul.PtrToStringUtf8(_namePos); } [StructLayout(LayoutKind.Sequential)] public struct NSwitchInfo @@ -193,9 +198,9 @@ namespace BizHawk.Emulation.Cores.Waterbox public IntPtr _name; public IntPtr _description; - public string SettingName => Marshal.PtrToStringAnsi(_settingName); - public string Name => Marshal.PtrToStringAnsi(_name); - public string Description => Marshal.PtrToStringAnsi(_description); + public string SettingName => Mershul.PtrToStringUtf8(_settingName); + public string Name => Mershul.PtrToStringUtf8(_name); + public string Description => Mershul.PtrToStringUtf8(_description); } } [StructLayout(LayoutKind.Sequential)] @@ -210,8 +215,8 @@ namespace BizHawk.Emulation.Cores.Waterbox public int Color; // (msb)0RGB(lsb), -1 for unused. public int _Padding; - public string ShortName => Marshal.PtrToStringAnsi(_shortName); - public string Name => Marshal.PtrToStringAnsi(_name); + public string ShortName => Mershul.PtrToStringUtf8(_shortName); + public string Name => Mershul.PtrToStringUtf8(_name); } } @@ -236,6 +241,10 @@ namespace BizHawk.Emulation.Cores.Waterbox [BizImport(CC, Compatibility = true)] public abstract NAxisInfo* GetAxis(uint port, uint dev, uint input); + /// + /// Set what input devices we're going to use + /// + /// MUST end with a null string [BizImport(CC, Compatibility = true)] public abstract void SetInputDevices(string[] devices); @@ -249,7 +258,7 @@ namespace BizHawk.Emulation.Cores.Waterbox } [StructLayout(LayoutKind.Sequential)] - public class SystemInfo + public struct SystemInfo { public int MaxWidth; public int MaxHeight; @@ -260,6 +269,6 @@ namespace BizHawk.Emulation.Cores.Waterbox } [BizImport(CC, Compatibility = true)] - public abstract SystemInfo GetSystemInfo(); + public abstract SystemInfo* GetSystemInfo(); } } diff --git a/src/BizHawk.Emulation.Cores/Waterbox/LibWaterboxCore.cs b/src/BizHawk.Emulation.Cores/Waterbox/LibWaterboxCore.cs index 6a6ada55a2..2b5f8c4744 100644 --- a/src/BizHawk.Emulation.Cores/Waterbox/LibWaterboxCore.cs +++ b/src/BizHawk.Emulation.Cores/Waterbox/LibWaterboxCore.cs @@ -176,7 +176,7 @@ namespace BizHawk.Emulation.Cores.Waterbox public WaterboxMemoryDomain(MemoryArea m, IMonitor monitor) { - Name = Marshal.PtrToStringAnsi(m.Name); + Name = Mershul.PtrToStringUtf8(m.Name); EndianType = (m.Flags & MemoryDomainFlags.YugeEndian) != 0 ? Endian.Big : Endian.Little; _data = m.Data; Size = m.Size; diff --git a/src/BizHawk.Emulation.Cores/Waterbox/NymaCore.Controller.cs b/src/BizHawk.Emulation.Cores/Waterbox/NymaCore.Controller.cs new file mode 100644 index 0000000000..d99d6fc6c0 --- /dev/null +++ b/src/BizHawk.Emulation.Cores/Waterbox/NymaCore.Controller.cs @@ -0,0 +1,185 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Waterbox +{ + unsafe partial class NymaCore + { + private ControllerAdapter _controllerAdapter; + private readonly byte[] _inputPortData = new byte[16 * 16]; + + private void InitControls() + { + _controllerAdapter = new ControllerAdapter(_nyma, new string[0]); + _nyma.SetInputDevices(_controllerAdapter.Devices); + ControllerDefinition = _controllerAdapter.Definition; + } + protected delegate void ControllerThunk(IController c, byte[] b); + + protected class ControllerAdapter + { + /// + /// allowed number of input ports. must match native + /// + private const int MAX_PORTS = 16; + /// + /// total maximum bytes on each input port. must match native + /// + private const int MAX_PORT_DATA = 16; + + /// + /// Device list suitable to pass back to the core + /// + public string[] Devices { get; } + public ControllerDefinition Definition { get; } + public ControllerAdapter(LibNymaCore core, string[] config) + { + var ret = new ControllerDefinition + { + Name = "TODO" + }; + + var finalDevices = new List(); + + 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.Length ? config[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); + // TODO: Possibly bulebutton for 2 states? + ret.AxisControls.Add(name); + ret.AxisRanges.Add(new ControllerDefinition.AxisRange( + 0, (int)data.DefaultPosition, (int)data.NumPositions - 1)); + // HACK: Silently discard this until bizhawk fixes its shit + // _thunks.Add((c, b) => + // { + // var val = (int)Math.Round(c.AxisValue(name)); + // b[byteStart] |= (byte)(1 << 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(); + } + + private readonly List> _thunks = new List>(); + + public void SetBits(IController src, byte[] dest) + { + Array.Clear(dest, 0, dest.Length); + foreach (var t in _thunks) + t(src, dest); + } + } + } +} diff --git a/src/BizHawk.Emulation.Cores/Waterbox/NymaCore.cs b/src/BizHawk.Emulation.Cores/Waterbox/NymaCore.cs index ead96696b5..7d7be2f53e 100644 --- a/src/BizHawk.Emulation.Cores/Waterbox/NymaCore.cs +++ b/src/BizHawk.Emulation.Cores/Waterbox/NymaCore.cs @@ -7,7 +7,7 @@ using BizHawk.Emulation.Common; namespace BizHawk.Emulation.Cores.Waterbox { - public unsafe abstract class NymaCore : WaterboxCore + public unsafe abstract partial class NymaCore : WaterboxCore { protected NymaCore(GameInfo game, byte[] rom, CoreComm comm, Configuration c) : base(comm, c) @@ -15,9 +15,6 @@ namespace BizHawk.Emulation.Cores.Waterbox } private LibNymaCore _nyma; - private ControllerAdapter _controllerAdapter; - private readonly byte[] _inputPortData = new byte[16 * 16]; - protected T DoInit(GameInfo game, byte[] rom, string filename, string extension) where T : LibNymaCore { @@ -55,7 +52,7 @@ namespace BizHawk.Emulation.Cores.Waterbox _exe.RemoveReadonlyFile(fn); - var info = _nyma.GetSystemInfo(); + var info = *_nyma.GetSystemInfo(); _videoBuffer = new int[info.MaxWidth * info.MaxHeight]; BufferWidth = info.NominalWidth; BufferHeight = info.NominalHeight; @@ -76,8 +73,9 @@ namespace BizHawk.Emulation.Cores.Waterbox VsyncNumerator = info.FpsFixed; VsyncDenominator = 1 << 24; - _controllerAdapter = new ControllerAdapter(_nyma, new string[0]); - _nyma.SetInputDevices(_controllerAdapter.Devices); + _soundBuffer = new short[22050 * 2]; + + InitControls(); PostInit(); } @@ -94,7 +92,8 @@ namespace BizHawk.Emulation.Cores.Waterbox _frameAdvanceInputLock = GCHandle.Alloc(_inputPortData, GCHandleType.Pinned); var ret = new LibNymaCore.FrameInfo { - SkipRendering = render ? 0 : 1, + SkipRendering = (short)(render ? 0 : 1), + SkipSoundening =(short)(rendersound ? 0 : 1), Command = LibNymaCore.CommandType.NONE, InputPortData = (byte*)_frameAdvanceInputLock.AddrOfPinnedObject() }; @@ -105,156 +104,6 @@ namespace BizHawk.Emulation.Cores.Waterbox _frameAdvanceInputLock.Free(); } - protected delegate void ControllerThunk(IController c, byte[] b); - - protected class ControllerAdapter - { - public string[] Devices { get; } - public ControllerDefinition Definition { get; } - public ControllerAdapter(LibNymaCore core, string[] config) - { - var ret = new ControllerDefinition - { - Name = "TODO" - }; - - var finalDevices = new List(); - - var numPorts = core.GetNumPorts(); - for (uint i = 0, devByteStart = 0; i < numPorts; i++) - { - var port = *core.GetPort(i); - var devName = i < config.Length ? config[i] : port.DefaultDeviceShortName; - finalDevices.Add(devName); - - var devices = Enumerable.Range(0, (int)port.NumDevices) - .Select(j => new { Index = (uint)j, Device = *core.GetDevice(i, (uint)j) }) - .ToList(); - - var device = devices.FirstOrDefault(a => a.Device.ShortName == devName); - if (device == null) - { - Console.WriteLine($"Warn: unknown controller device {devName}"); - device = devices.FirstOrDefault(a => a.Device.ShortName == port.DefaultDeviceShortName); - if (device == null) - throw new InvalidOperationException($"Fail: unknown controller device {port.DefaultDeviceShortName}"); - } - - var dev = device.Device; - var category = port.FullName + " - " + dev.FullName; - - var inputs = Enumerable.Range(0, (int)dev.NumInputs) - .Select(iix => new { Index = iix, Data = *core.GetInput(i, device.Index, (uint)iix) }) - .OrderBy(a => a.Data.ConfigOrder); - - foreach (var inputzz in inputs) - { - var input = inputzz.Data; - var bitSize = (int)input.BitSize; - var bitOffset = (int)input.BitOffset; - var byteStart = devByteStart + bitOffset / 8; - bitOffset %= 8; - var name = input.Name; - switch (input.Type) - { - case LibNymaCore.InputType.PADDING: - { - break; - } - case LibNymaCore.InputType.BUTTON: - case LibNymaCore.InputType.BUTTON_CAN_RAPID: - { - var data = *core.GetButton(i, device.Index, (uint)inputzz.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(i, device.Index, (uint)inputzz.Index); - // 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) => - { - var val = (int)Math.Round(c.AxisValue(name)); - b[byteStart] |= (byte)(1 << bitOffset); - }); - break; - } - case LibNymaCore.InputType.AXIS: - { - var data = core.GetAxis(i, device.Index, (uint)inputzz.Index); - ret.AxisControls.Add(name); - ret.AxisRanges.Add(new ControllerDefinition.AxisRange( - 0, 0x8000, 0xffff, (input.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(i, device.Index, (uint)inputzz.Index); - ret.AxisControls.Add(name); - ret.AxisRanges.Add(new ControllerDefinition.AxisRange( - -0x8000, 0, 0x7fff, (input.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 {input.Type}"); - } - ret.CategoryLabels[name] = category; - } - - devByteStart += dev.ByteLength; - } - Definition = ret; - Devices = finalDevices.ToArray(); - } - - private readonly List> _thunks = new List>(); - - public void SetBits(IController src, byte[] dest) - { - Array.Clear(dest, 0, dest.Length); - foreach (var t in _thunks) - t(src, dest); - } - } - public DisplayType Region { get; protected set; } /// @@ -274,7 +123,7 @@ namespace BizHawk.Emulation.Cores.Waterbox if (*q == 0) { if (q > p) - ret.Add(Marshal.PtrToStringAnsi((IntPtr)p)); + ret.Add(Mershul.PtrToStringUtf8((IntPtr)p)); else break; p = ++q; diff --git a/src/BizHawk.Emulation.Cores/Waterbox/WaterboxCore.cs b/src/BizHawk.Emulation.Cores/Waterbox/WaterboxCore.cs index 605e88f004..d4e3d885b2 100644 --- a/src/BizHawk.Emulation.Cores/Waterbox/WaterboxCore.cs +++ b/src/BizHawk.Emulation.Cores/Waterbox/WaterboxCore.cs @@ -197,9 +197,19 @@ namespace BizHawk.Emulation.Cores.Waterbox LagCount++; AdvanceRtc(); - BufferWidth = frame.Width; - BufferHeight = frame.Height; - _numSamples = frame.Samples; + if (render) + { + BufferWidth = frame.Width; + BufferHeight = frame.Height; + } + if (rendersound) + { + _numSamples = frame.Samples; + } + else + { + _numSamples = 0; + } FrameAdvancePost(); } @@ -319,7 +329,7 @@ namespace BizHawk.Emulation.Cores.Waterbox { } - protected readonly short[] _soundBuffer; + protected short[] _soundBuffer; protected int _numSamples; public bool CanProvideAsync => false; public SyncSoundMode SyncMode => SyncSoundMode.Sync; diff --git a/waterbox/nyma/NymaCore.cpp b/waterbox/nyma/NymaCore.cpp index e80aee4b77..c13af185dc 100644 --- a/waterbox/nyma/NymaCore.cpp +++ b/waterbox/nyma/NymaCore.cpp @@ -36,12 +36,13 @@ ECL_EXPORT bool Init(const InitData& data) samples = new int16_t[22050 * 2]; Surf = new MDFN_Surface( pixels, Game->fb_width, Game->fb_height, Game->fb_width, - MDFN_PixelFormat(MDFN_COLORSPACE_RGB, 0, 8, 16, 24) + MDFN_PixelFormat(MDFN_COLORSPACE_RGB, 16, 8, 0, 24) ); EES = new EmulateSpecStruct(); EES->surface = Surf; EES->VideoFormatChanged = true; EES->LineWidths = new int32_t[Game->fb_height]; + memset(EES->LineWidths, 0xff, Game->fb_height * sizeof(int32_t)); EES->SoundBuf = samples; EES->SoundBufMaxSize = 22050; EES->SoundFormatChanged = true; @@ -71,7 +72,8 @@ ECL_EXPORT bool Init(const InitData& data) struct MyFrameInfo: public FrameInfo { // true to skip video rendering - int32_t SkipRendering; + int16_t SkipRendering; + int16_t SkipSoundening; // a single MDFN_MSC_* command to run at the start of this frame; 0 if none int32_t Command; // raw data for each input port, assumed to be MAX_PORTS * MAX_PORT_DATA long @@ -92,24 +94,43 @@ ECL_EXPORT void FrameAdvance(MyFrameInfo& frame) EES->VideoFormatChanged = false; EES->SoundFormatChanged = false; - frame.Cycles = EES->MasterCycles; // TODO: Was this supposed to be total or delta? - memcpy(frame.SoundBuffer, EES->SoundBuf, EES->SoundBufSize * 4); - frame.Samples = EES->SoundBufSize; - - // TODO: Use linewidths - int w = EES->DisplayRect.w; - int h = EES->DisplayRect.h; - frame.Width = w; - frame.Height = h; - int srcp = Game->fb_width; - int dstp = Game->fb_height; - uint32_t* src = pixels + EES->DisplayRect.x + EES->DisplayRect.y * srcp; - uint32_t* dst = pixels; - for (int line = 0; line < h; line++) + frame.Cycles = EES->MasterCycles; + if (!frame.SkipSoundening) { - memcpy(dst, src, w * 4); - src += srcp; - dst += dstp; + memcpy(frame.SoundBuffer, EES->SoundBuf, EES->SoundBufSize * 4); + frame.Samples = EES->SoundBufSize; + } + if (!frame.SkipRendering) + { + int h = EES->DisplayRect.h; + int lineStart = EES->DisplayRect.y; + int lineEnd = lineStart + h; + + auto multiWidth = EES->LineWidths[0] != -1; + int w; + if (multiWidth) + { + w = 0; + for (int line = lineStart; line < lineEnd; line++) + w = std::max(w, EES->LineWidths[line]); + } + else + { + w = EES->DisplayRect.w; + } + + frame.Width = w; + frame.Height = h; + int srcp = Game->fb_width; + int dstp = w; + uint32_t* src = pixels + EES->DisplayRect.x + EES->DisplayRect.y * srcp; + uint32_t* dst = frame.VideoBuffer; + for (int line = lineStart; line < lineEnd; line++) + { + memcpy(dst, src, (multiWidth ? EES->LineWidths[line] : w) * sizeof(uint32_t)); + src += srcp; + dst += dstp; + } } }