diff --git a/src/BizHawk.Bizware.Graphics/OpenGL/SDL2OpenGLContext.cs b/src/BizHawk.Bizware.Graphics/OpenGL/SDL2OpenGLContext.cs index a81c39872b..8d62b41f22 100644 --- a/src/BizHawk.Bizware.Graphics/OpenGL/SDL2OpenGLContext.cs +++ b/src/BizHawk.Bizware.Graphics/OpenGL/SDL2OpenGLContext.cs @@ -1,5 +1,12 @@ +// #define DEBUG_OPENGL + using System; +#if DEBUG_OPENGL +using System.Runtime.InteropServices; +using Silk.NET.OpenGL.Legacy; +#endif + using static SDL2.SDL; namespace BizHawk.Bizware.Graphics @@ -42,6 +49,12 @@ namespace BizHawk.Bizware.Graphics SDL_SetHint(SDL_HINT_WINDOWS_ENABLE_MESSAGELOOP, "0"); } +#if DEBUG_OPENGL + private static readonly DebugProc _debugProc = DebugCallback; + private static void DebugCallback(GLEnum source, GLEnum type, int id, GLEnum severity, int length, IntPtr message, IntPtr userParam) + => Console.WriteLine($"{source} {type} {severity}: {Marshal.PtrToStringAnsi(message, length)}"); +#endif + private IntPtr _sdlWindow; private IntPtr _glContext; @@ -64,6 +77,13 @@ namespace BizHawk.Bizware.Graphics throw new($"Could not set GL Context Flags! SDL Error: {SDL_GetError()}"); } +#if DEBUG_OPENGL + if (SDL_GL_SetAttribute(SDL_GLattr.SDL_GL_CONTEXT_FLAGS, (int)SDL_GLcontext.SDL_GL_CONTEXT_DEBUG_FLAG) != 0) + { + throw new($"Could not set GL Debug Flag! SDL Error: {SDL_GetError()}"); + } +#endif + var profile = coreProfile ? SDL_GLprofile.SDL_GL_CONTEXT_PROFILE_CORE : SDL_GLprofile.SDL_GL_CONTEXT_PROFILE_COMPATIBILITY; @@ -78,6 +98,17 @@ namespace BizHawk.Bizware.Graphics { throw new($"Could not create GL Context! SDL Error: {SDL_GetError()}"); } + +#if DEBUG_OPENGL + if (GetGLProcAddress("glDebugMessageCallback") != IntPtr.Zero) + { + using var gl = GL.GetApi(GetGLProcAddress); + unsafe + { + gl.DebugMessageCallback(_debugProc, null); + } + } +#endif } public SDL2OpenGLContext(IntPtr nativeWindowhandle, int majorVersion, int minorVersion, bool coreProfile, bool forwardCompatible) diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/LibMelonDS.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/LibMelonDS.cs index a994df88b2..5d3e967769 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/LibMelonDS.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/LibMelonDS.cs @@ -58,6 +58,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS public bool DSi; public bool ClearNAND; public bool LoadDSiWare; + public bool IsWinApi; public NDS.NDSSyncSettings.ThreeDeeRendererType ThreeDeeRenderer; public RenderSettings RenderSettings; } @@ -168,21 +169,6 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS [UnmanagedFunctionPointer(CC)] public delegate IntPtr GetGLProcAddressCallback(string proc); - [StructLayout(LayoutKind.Sequential)] - public struct GLCallbackInterface - { - public RequestGLContextCallback RequestGLContext; - public ReleaseGLContextCallback ReleaseGLContext; - public ActivateGLContextCallback ActivateGLContext; - public GetGLProcAddressCallback GetGLProcAddress; - - public IntPtr[] AllCallbacksInArray(ICallingConventionAdapter adapter) - { - return new Delegate[] { RequestGLContext, ReleaseGLContext, ActivateGLContext, GetGLProcAddress } - .Select(adapter.GetFunctionPointerForDelegate).ToArray(); - } - } - public enum LogLevel : int { Debug, @@ -197,10 +183,10 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS [BizImport(CC)] public abstract IntPtr Init( ref InitConfig loadData, - /* ref ConfigCallbackInterface */ IntPtr[] configCallbackInterface, - /* ref FileCallbackInterface */ IntPtr[] fileCallbackInterface, - // /* ref GLCallbackInterface */ IntPtr[] glCallbackInterface, // TODO - LogCallback logCallback); + IntPtr[] configCallbackInterface, /* ref ConfigCallbackInterface */ + IntPtr[] fileCallbackInterface, /* ref FileCallbackInterface */ + LogCallback logCallback, + GetGLProcAddressCallback getGLProcAddressCallback); [BizImport(CC)] public abstract void PutSaveRam(byte[] data, uint len); @@ -271,5 +257,11 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS [BizImport(CC)] public abstract void GetNANDData(byte[] buf); + + [BizImport(CC)] + public abstract int GetGLTexture(); + + [BizImport(CC)] + public abstract void ReadFrameBuffer(int[] buffer); } } diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS.IDebuggable.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS.IDebuggable.cs index f186b20fbb..141b5640be 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS.IDebuggable.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS.IDebuggable.cs @@ -26,7 +26,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS public void SetCpuRegister(string register, int value) { - if (register.Length != 7 && register.Length != 8) + if (register.Length is not (7 or 8)) { throw new InvalidOperationException("Wrong String Length???"); } @@ -50,13 +50,13 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS public long TotalExecutedCycles => CycleCount + _core.GetCallbackCycleOffset(); - public IMemoryCallbackSystem MemoryCallbacks => _memorycallbacks; + public IMemoryCallbackSystem MemoryCallbacks => _memoryCallbacks; - private readonly MemoryCallbackSystem _memorycallbacks = new(new[] { "System Bus" }); + private readonly MemoryCallbackSystem _memoryCallbacks = new(new[] { "System Bus" }); - private LibMelonDS.MemoryCallback _readcb; - private LibMelonDS.MemoryCallback _writecb; - private LibMelonDS.MemoryCallback _execcb; + private LibMelonDS.MemoryCallback _readCallback; + private LibMelonDS.MemoryCallback _writeCallback; + private LibMelonDS.MemoryCallback _execCallback; private void InitMemoryCallbacks() { @@ -72,18 +72,18 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS }; } - _readcb = CreateCallback(MemoryCallbackFlags.AccessRead, () => MemoryCallbacks.HasReads); - _writecb = CreateCallback(MemoryCallbackFlags.AccessWrite, () => MemoryCallbacks.HasWrites); - _execcb = CreateCallback(MemoryCallbackFlags.AccessExecute, () => MemoryCallbacks.HasExecutes); + _readCallback = CreateCallback(MemoryCallbackFlags.AccessRead, () => MemoryCallbacks.HasReads); + _writeCallback = CreateCallback(MemoryCallbackFlags.AccessWrite, () => MemoryCallbacks.HasWrites); + _execCallback = CreateCallback(MemoryCallbackFlags.AccessExecute, () => MemoryCallbacks.HasExecutes); - _memorycallbacks.ActiveChanged += SetMemoryCallbacks; + _memoryCallbacks.ActiveChanged += SetMemoryCallbacks; } private void SetMemoryCallbacks() { - _core.SetMemoryCallback(0, MemoryCallbacks.HasReads ? _readcb : null); - _core.SetMemoryCallback(1, MemoryCallbacks.HasWrites ? _writecb : null); - _core.SetMemoryCallback(2, MemoryCallbacks.HasExecutes ? _execcb : null); + _core.SetMemoryCallback(0, MemoryCallbacks.HasReads ? _readCallback : null); + _core.SetMemoryCallback(1, MemoryCallbacks.HasWrites ? _writeCallback : null); + _core.SetMemoryCallback(2, MemoryCallbacks.HasExecutes ? _execCallback : null); } } } diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS.IGLTextureProvider.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS.IGLTextureProvider.cs new file mode 100644 index 0000000000..9a140b1bba --- /dev/null +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS.IGLTextureProvider.cs @@ -0,0 +1,46 @@ +using System; + +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS +{ + public class MelonDSGLTextureProvider : IGLTextureProvider + { + private readonly IVideoProvider _vp; + private readonly LibMelonDS _core; + private readonly Action _activateGLContextCallback; + private readonly int[] _vbuf = new int[256 * 16 * 384 * 16]; + + internal bool VideoDirty; + + internal MelonDSGLTextureProvider(IVideoProvider vp, LibMelonDS core, Action activateGLContextCallback) + { + _vp = vp; + _core = core; + _activateGLContextCallback = activateGLContextCallback; + } + + public int GetGLTexture() + => _core.GetGLTexture(); + + public int[] GetVideoBuffer() + { + if (VideoDirty) + { + _activateGLContextCallback(); + _core.ReadFrameBuffer(_vbuf); + VideoDirty = false; + } + + return _vbuf; + } + + public int VirtualWidth => 256; + public int VirtualHeight => 384; + public int BufferWidth => _vp.BufferWidth; + public int BufferHeight => _vp.BufferHeight; + public int VsyncNumerator => _vp.VsyncNumerator; + public int VsyncDenominator => _vp.VsyncDenominator; + public int BackgroundColor => _vp.BackgroundColor; + } +} diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS.ISaveRam.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS.ISaveRam.cs index 573a19a6c0..0a10664c5d 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS.ISaveRam.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS.ISaveRam.cs @@ -12,19 +12,24 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS if (IsDSiWare) { _core.DSiWareSavsLength(DSiTitleId.Lower, out var publicSavSize, out var privateSavSize, out var bannerSavSize); - if (publicSavSize + privateSavSize + bannerSavSize == 0) return null; + if (publicSavSize + privateSavSize + bannerSavSize == 0) + { + return null; + } + _exe.AddTransientFile(Array.Empty(), "public.sav"); _exe.AddTransientFile(Array.Empty(), "private.sav"); _exe.AddTransientFile(Array.Empty(), "banner.sav"); _core.ExportDSiWareSavs(DSiTitleId.Lower); + var publicSav = _exe.RemoveTransientFile("public.sav"); var privateSav = _exe.RemoveTransientFile("private.sav"); var bannerSav = _exe.RemoveTransientFile("banner.sav"); - if (publicSav.Length != publicSavSize || privateSav.Length != privateSavSize || - bannerSav.Length != bannerSavSize) + if (publicSav.Length != publicSavSize || privateSav.Length != privateSavSize || bannerSav.Length != bannerSavSize) { throw new InvalidOperationException("Unexpected size difference in DSiWare sav files!"); } + var ret = new byte[publicSavSize + privateSavSize + bannerSavSize]; publicSav.AsSpan().CopyTo(ret.AsSpan().Slice(0, publicSavSize)); privateSav.AsSpan().CopyTo(ret.AsSpan().Slice(publicSavSize, privateSavSize)); diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS.ISettable.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS.ISettable.cs index 021a4930cd..770be692fc 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS.ISettable.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS.ISettable.cs @@ -83,7 +83,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS Marshal.WriteByte(buffer, numToCopy, 0); } - private void GetArraySettingCallback(LibMelonDS.ConfigEntry configEntry, IntPtr buffer) + private static void GetArraySettingCallback(LibMelonDS.ConfigEntry configEntry, IntPtr buffer) { if (configEntry != LibMelonDS.ConfigEntry.Firm_MAC) { @@ -195,18 +195,20 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS return ret; } - public NDSSettings Clone() => MemberwiseClone() as NDSSettings; + public NDSSettings Clone() + => (NDSSettings)MemberwiseClone(); public static bool NeedsScreenResize(NDSSettings x, NDSSettings y) { - bool ret = false; + var ret = false; ret |= x.ScreenLayout != y.ScreenLayout; ret |= x.ScreenGap != y.ScreenGap; ret |= x.ScreenRotation != y.ScreenRotation; return ret; } - public NDSSettings() => SettingsUtil.SetDefaultValues(this); + public NDSSettings() + => SettingsUtil.SetDefaultValues(this); } private static readonly DateTime minDate = new(2000, 1, 1); @@ -217,20 +219,41 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS public enum ThreeDeeRendererType : int { Software, - //OpenGL_Classic, + [Display(Name = "OpenGL Classic")] + OpenGL_Classic, + // [Display(Name = "OpenGL Compute")] //OpenGL_Compute, } [DisplayName("3D Renderer")] - [Description("Renderer used for 3D. OpenGL Classic requires at least OpenGL 3.2, OpenGL Compute requires at least OpenGL 4.3. Forced to Software when recording a movie.")] + // [Description("Renderer used for 3D. OpenGL Classic requires at least OpenGL 3.2, OpenGL Compute requires at least OpenGL 4.3. Forced to Software when recording a movie.")] + [Description("Renderer used for 3D. OpenGL Classic requires at least OpenGL 3.2. Forced to Software when recording a movie.")] [DefaultValue(ThreeDeeRendererType.Software)] + [TypeConverter(typeof(DescribableEnumConverter))] public ThreeDeeRendererType ThreeDeeRenderer { get; set; } - [DisplayName("Threaded 3D Rendering")] - [Description("Offloads 3D rendering to a separate thread. Only used for the software 3D renderer.")] + [DisplayName("Threaded Software 3D Rendering")] + [Description("Offloads 3D rendering to a separate thread. Only used for the software renderer.")] [DefaultValue(true)] public bool ThreadedRendering { get; set; } + [JsonIgnore] + private int _glScaleFactor; + + [DisplayName("OpenGL Scale Factor")] + [Description("Factor at which OpenGL upscales the final image. Not used for the software renderer.")] + [DefaultValue(1)] + public int GLScaleFactor + { + get => _glScaleFactor; + set => _glScaleFactor = Math.Max(1, Math.Min(16, value)); + } + + [DisplayName("OpenGL Better Polygons")] + [Description("Enhances polygon quality with OpenGL. Not used for the software renderer.")] + [DefaultValue(false)] + public bool GLBetterPolygons { get; set; } + [JsonIgnore] private DateTime _initaltime; @@ -406,16 +429,21 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS set => _firmwaremessage = value.Substring(0, Math.Min(26, value.Length)); } - public NDSSyncSettings Clone() => MemberwiseClone() as NDSSyncSettings; + public NDSSyncSettings Clone() + => (NDSSyncSettings)MemberwiseClone(); - public static bool NeedsReboot(NDSSyncSettings x, NDSSyncSettings y) => !DeepEquality.DeepEquals(x, y); + public static bool NeedsReboot(NDSSyncSettings x, NDSSyncSettings y) + => !DeepEquality.DeepEquals(x, y); - public NDSSyncSettings() => SettingsUtil.SetDefaultValues(this); + public NDSSyncSettings() + => SettingsUtil.SetDefaultValues(this); } - public NDSSettings GetSettings() => _settings.Clone(); + public NDSSettings GetSettings() + => _settings.Clone(); - public NDSSyncSettings GetSyncSettings() => _syncSettings.Clone(); + public NDSSyncSettings GetSyncSettings() + => _syncSettings.Clone(); public PutSettingsDirtyBits PutSettings(NDSSettings o) { @@ -433,28 +461,12 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS private static int SanitizeBirthdayDay(int day, NDSSyncSettings.Month fwMonth) { - int maxdays; - switch (fwMonth) + var maxdays = fwMonth switch { - case NDSSyncSettings.Month.February: - { - maxdays = 29; - break; - } - case NDSSyncSettings.Month.April: - case NDSSyncSettings.Month.June: - case NDSSyncSettings.Month.September: - case NDSSyncSettings.Month.November: - { - maxdays = 30; - break; - } - default: - { - maxdays = 31; - break; - } - } + NDSSyncSettings.Month.February => 29, + NDSSyncSettings.Month.April or NDSSyncSettings.Month.June or NDSSyncSettings.Month.September or NDSSyncSettings.Month.November => 30, + _ => 31 + }; return Math.Max(1, Math.Min(day, maxdays)); } diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS.ITraceable.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS.ITraceable.cs index d0a0f1f40c..ff2220ef27 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS.ITraceable.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS.ITraceable.cs @@ -8,10 +8,11 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS public partial class NDS { private ITraceable Tracer { get; } - private readonly LibMelonDS.TraceCallback _tracecb; + private readonly LibMelonDS.TraceCallback _traceCallback; private unsafe void MakeTrace(LibMelonDS.TraceMask type, uint opcode, IntPtr r, IntPtr disasm, uint cyclesOff) { + // ReSharper disable once SwitchExpressionHandlesSomeKnownEnumValuesWithExceptionInDefault var cpu = type switch { LibMelonDS.TraceMask.ARM7_THUMB => "ARM7 (Thumb)", diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS.cs index a8596b09cc..bccfade539 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS.cs @@ -62,14 +62,22 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS private static void LogCallback(LibMelonDS.LogLevel level, string message) => Console.Write($"[{level}] {message}"); + private readonly MelonDSGLTextureProvider _glTextureProvider; + private readonly IOpenGLProvider _openGLProvider; + private readonly object _glContext; + private readonly LibMelonDS.GetGLProcAddressCallback _getGLProcAddressCallback; + + private IntPtr GetGLProcAddressCallback(string proc) + => _openGLProvider.GetGLProcAddress(proc); + [CoreConstructor(VSystemID.Raw.NDS)] public NDS(CoreLoadParameters lp) : base(lp.Comm, new() { DefaultWidth = 256, DefaultHeight = 384, - MaxWidth = 256, - MaxHeight = 384, + MaxWidth = 256 * 16, + MaxHeight = 384 * 16, MaxSamples = 1024, DefaultFpsNumerator = 33513982, DefaultFpsDenominator = 560190, @@ -93,12 +101,10 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS throw new InvalidOperationException("Wrong number of ROMs!"); } - var gbacartpresent = roms.Count == 2; - InitMemoryCallbacks(); - _tracecb = MakeTrace; - _threadstartcb = ThreadStartCallback; + _traceCallback = MakeTrace; + _threadStartCallback = ThreadStartCallback; _configCallbackInterface.GetBoolean = GetBooleanSettingCallback; _configCallbackInterface.GetInteger = GetIntegerSettingCallback; @@ -110,6 +116,35 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS _logCallback = LogCallback; + _openGLProvider = CoreComm.OpenGLProvider; + _getGLProcAddressCallback = GetGLProcAddressCallback; + + if (lp.DeterministicEmulationRequested) + { + _activeSyncSettings.ThreeDeeRenderer = NDSSyncSettings.ThreeDeeRendererType.Software; + } + + if (_activeSyncSettings.ThreeDeeRenderer != NDSSyncSettings.ThreeDeeRendererType.Software) + { + // ReSharper disable once SwitchExpressionHandlesSomeKnownEnumValuesWithExceptionInDefault + var (majorGlVersion, minorGlVersion) = _activeSyncSettings.ThreeDeeRenderer switch + { + NDSSyncSettings.ThreeDeeRendererType.OpenGL_Classic => (3, 2), + // NDSSyncSettings.ThreeDeeRendererType.OpenGL_Compute => (4, 3), + _ => throw new InvalidOperationException($"Invalid {nameof(NDSSyncSettings.ThreeDeeRenderer)}") + }; + + if (!_openGLProvider.SupportsGLVersion(majorGlVersion, minorGlVersion)) + { + lp.Comm.Notify($"OpenGL {majorGlVersion}.{minorGlVersion} is not supported on this machine, falling back to software renderer", null); + _activeSyncSettings.ThreeDeeRenderer = NDSSyncSettings.ThreeDeeRendererType.Software; + } + else + { + _glContext = _openGLProvider.RequestGLContext(majorGlVersion, minorGlVersion, true, false); + } + } + _core = PreInit(new() { Filename = "melonDS.wbx", @@ -122,11 +157,11 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS SkipMemoryConsistencyCheck = CoreComm.CorePreferences.HasFlag(CoreComm.CorePreferencesFlags.WaterboxMemoryConsistencyCheck), }, new Delegate[] { - _readcb, _writecb, _execcb, _tracecb, _threadstartcb, + _readCallback, _writeCallback, _execCallback, _traceCallback, _threadStartCallback, _configCallbackInterface.GetBoolean, _configCallbackInterface.GetInteger, _configCallbackInterface.GetString, _configCallbackInterface.GetArray, _fileCallbackInterface.GetLength, _fileCallbackInterface.GetData, - _logCallback + _logCallback, _getGLProcAddressCallback }); _activeSyncSettings.UseRealBIOS |= IsDSi; @@ -164,22 +199,23 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS else { AddCoreFile("nds.rom", roms[0]); - if (gbacartpresent) + if (roms.Count == 2) { AddCoreFile("gba.rom", roms[1]); } } LibMelonDS.InitConfig initConfig; - initConfig.SkipFW = _activeSyncSettings.SkipFirmware; - initConfig.HasGBACart = gbacartpresent; + initConfig.SkipFW = _activeSyncSettings.SkipFirmware && !IsDSi; + initConfig.HasGBACart = roms.Count == 2; initConfig.DSi = IsDSi; initConfig.ClearNAND = _activeSyncSettings.ClearNAND || lp.DeterministicEmulationRequested; initConfig.LoadDSiWare = IsDSiWare; + initConfig.IsWinApi = !OSTailoredCode.IsUnixHost; initConfig.ThreeDeeRenderer = _activeSyncSettings.ThreeDeeRenderer; initConfig.RenderSettings.SoftThreaded = _activeSyncSettings.ThreadedRendering; - initConfig.RenderSettings.GLScaleFactor = 1; // TODO - initConfig.RenderSettings.GLBetterPolygons = false; // TODO + initConfig.RenderSettings.GLScaleFactor = _activeSyncSettings.GLScaleFactor; + initConfig.RenderSettings.GLBetterPolygons = _activeSyncSettings.GLBetterPolygons; _activeSyncSettings.FirmwareOverride |= !_activeSyncSettings.UseRealBIOS || lp.DeterministicEmulationRequested; @@ -205,7 +241,8 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS ref initConfig, _configCallbackInterface.AllCallbacksInArray(_adapter), _fileCallbackInterface.AllCallbacksInArray(_adapter), - _logCallback); + _logCallback, + _getGLProcAddressCallback); if (error != IntPtr.Zero) { using (_exe.EnterExit()) @@ -233,7 +270,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS _frameThreadAction = CallingConventionAdapters .GetWaterboxUnsafeUnwrapped() .GetDelegateForFunctionPointer(_frameThreadPtr); - _core.SetThreadStartCallback(_threadstartcb); + _core.SetThreadStartCallback(_threadStartCallback); } _disassembler = new(_core); @@ -242,6 +279,12 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS const string TRACE_HEADER = "ARM9+ARM7: Opcode address, opcode, registers (r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, SP, LR, PC, Cy, CpuMode)"; Tracer = new TraceBuffer(TRACE_HEADER); _serviceProvider.Register(Tracer); + + if (_glContext != null) + { + _glTextureProvider = new(this, _core, () => _openGLProvider.ActivateGLContext(_glContext)); + _serviceProvider.Register(_glTextureProvider); + } } private static (ulong Full, uint Upper, uint Lower) GetDSiTitleId(IReadOnlyList file) @@ -361,7 +404,13 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS protected override LibWaterboxCore.FrameInfo FrameAdvancePrep(IController controller, bool render, bool rendersound) { - _core.SetTraceCallback(Tracer.IsEnabled() ? _tracecb : null, _settings.GetTraceMask()); + if (_glContext != null) + { + _openGLProvider.ActivateGLContext(_glContext); + } + + _core.SetTraceCallback(Tracer.IsEnabled() ? _traceCallback : null, _settings.GetTraceMask()); + return new LibMelonDS.FrameInfo { Time = GetRtcTime(!DeterministicEmulation), @@ -376,7 +425,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS private readonly IntPtr _frameThreadPtr; private readonly Action _frameThreadAction; - private readonly LibMelonDS.ThreadStartCallback _threadstartcb; + private readonly LibMelonDS.ThreadStartCallback _threadStartCallback; private readonly Thread _frameThread; private readonly SemaphoreSlim _frameThreadStartEvent = new(0, 1); @@ -391,6 +440,12 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS _frameThread?.Join(); _frameThreadStartEvent.Dispose(); _frameThreadEndEvent.Dispose(); + + if (_glContext != null) + { + _openGLProvider.ReleaseGLContext(_glContext); + } + base.Dispose(); } @@ -425,12 +480,17 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS _frameThreadEndEvent.Wait(); _renderThreadRanThisFrame = false; } + + if (_glTextureProvider != null) + { + _glTextureProvider.VideoDirty = true; + } } protected override void LoadStateBinaryInternal(BinaryReader reader) { SetMemoryCallbacks(); - _core.SetThreadStartCallback(_threadstartcb); + _core.SetThreadStartCallback(_threadStartCallback); if (_frameThreadPtr != _core.GetFrameThreadProc()) { throw new InvalidOperationException("_frameThreadPtr mismatch");