diff --git a/src/BizHawk.Client.Common/DisplayManager/DisplayManagerBase.cs b/src/BizHawk.Client.Common/DisplayManager/DisplayManagerBase.cs index 70948564b0..362d43174e 100644 --- a/src/BizHawk.Client.Common/DisplayManager/DisplayManagerBase.cs +++ b/src/BizHawk.Client.Common/DisplayManager/DisplayManagerBase.cs @@ -593,18 +593,6 @@ namespace BizHawk.Client.Common videoProvider.BufferWidth, videoProvider.BufferHeight, out virtualWidth, out virtualHeight); } - // TODO: it is bad that this is happening outside the filter chain - // the filter chain has the ability to add padding... - // for now, we have to have some hacks. this could be improved by refactoring the filter setup hacks to be in one place only though - // could the PADDING be done as filters too? that would be nice. - var fCoreScreenControl = CreateCoreScreenControl(); - if (fCoreScreenControl != null) - { - var sz = fCoreScreenControl.PresizeInput("default", new(bufferWidth, bufferHeight)); - virtualWidth = bufferWidth = sz.Width; - virtualHeight = bufferHeight = sz.Height; - } - var padding = CalculateCompleteContentPaddingSum(true, false); virtualWidth += padding.Horizontal; virtualHeight += padding.Vertical; @@ -768,24 +756,10 @@ namespace BizHawk.Client.Common var bufferWidth = videoProvider.BufferWidth; var bufferHeight = videoProvider.BufferHeight; - var presenterTextureWidth = bufferWidth; - var presenterTextureHeight = bufferHeight; var vw = videoProvider.VirtualWidth; var vh = videoProvider.VirtualHeight; - // TODO: it is bad that this is happening outside the filter chain - // the filter chain has the ability to add padding... - // for now, we have to have some hacks. this could be improved by refactoring the filter setup hacks to be in one place only though - // could the PADDING be done as filters too? that would be nice. - var fCoreScreenControl = CreateCoreScreenControl(); - if(fCoreScreenControl != null) - { - var sz = fCoreScreenControl.PresizeInput("default", new(bufferWidth, bufferHeight)); - presenterTextureWidth = vw = sz.Width; - presenterTextureHeight = vh = sz.Height; - } - if (GlobalConfig.DispFixAspectRatio) { switch (GlobalConfig.DispManagerAR) @@ -862,7 +836,7 @@ namespace BizHawk.Client.Common if (fPresent != null) { fPresent.VirtualTextureSize = new(vw, vh); - fPresent.TextureSize = new(presenterTextureWidth, presenterTextureHeight); + fPresent.TextureSize = new(bufferWidth, bufferHeight); fPresent.BackgroundColor = videoProvider.BackgroundColor; fPresent.Config_FixAspectRatio = GlobalConfig.DispFixAspectRatio; fPresent.Config_FixScaleInteger = GlobalConfig.DispFixScaleInteger; diff --git a/src/BizHawk.Client.Common/DisplayManager/Filters/Gui.cs b/src/BizHawk.Client.Common/DisplayManager/Filters/Gui.cs index 060ed3a95d..7d47fe6149 100644 --- a/src/BizHawk.Client.Common/DisplayManager/Filters/Gui.cs +++ b/src/BizHawk.Client.Common/DisplayManager/Filters/Gui.cs @@ -182,268 +182,25 @@ namespace BizHawk.Client.Common.Filters { private readonly NDS _nds; - // TODO: actually use this -#if false - private bool Nop = false; -#endif - - // matrices used for transforming screens - private Matrix4x4 matTop, matBot; - private Matrix4x4 matTopInvert, matBotInvert; - - // final output area size - private Size outputSize; - - private static float Round(float f) - => (float)Math.Round(f); - public ScreenControlNDS(NDS nds) { _nds = nds; } - public override void Initialize() - { - //we're going to be blitting the source as pieces to a new render target, so we need our input to be a texture - DeclareInput(SurfaceDisposition.Texture); - } - - private void CrunchNumbers() - { - MatrixStack top = new(), bot = new(); - - // set up transforms for each screen based on screen control values - // this will be TRICKY depending on how many features we have, but once it's done, everything should be easy - - var settings = _nds.GetSettings(); - - switch (settings.ScreenLayout) - { - //gap only applies to vertical, I guess - case NDS.ScreenLayoutKind.Vertical: - bot.Translate(0, 192); - bot.Translate(0, settings.ScreenGap); - break; - case NDS.ScreenLayoutKind.Horizontal: - bot.Translate(256, 0); - break; - case NDS.ScreenLayoutKind.Top: - case NDS.ScreenLayoutKind.Bottom: - // do nothing here, we'll discard the other screen - break; - default: - throw new InvalidOperationException(); - } - - // this doesn't make any sense, it's likely to be too much for a monitor to gracefully handle too - if (settings.ScreenLayout != NDS.ScreenLayoutKind.Horizontal) - { - var rot = settings.ScreenRotation switch - { - NDS.ScreenRotationKind.Rotate90 => 90, - NDS.ScreenRotationKind.Rotate180 => 180, - NDS.ScreenRotationKind.Rotate270 => 270, - _ => 0 - }; - - top.RotateZ(rot); - bot.RotateZ(rot); - } - - // TODO: refactor some of the below into a class that doesn't require having top and bottom replica code - - matTop = top.Top; - matBot = bot.Top; - - // apply transforms from standard input screen positions to output screen positions - var top_TL = Vector2.Transform(new(0, 0), matTop); - var top_TR = Vector2.Transform(new(256, 0), matTop); - var top_BL = Vector2.Transform(new(0, 192), matTop); - var top_BR = Vector2.Transform(new(256, 192), matTop); - var bot_TL = Vector2.Transform(new(0, 0), matBot); - var bot_TR = Vector2.Transform(new(256, 0), matBot); - var bot_BL = Vector2.Transform(new(0, 192), matBot); - var bot_BR = Vector2.Transform(new(256, 192), matBot); - - // in case of math errors in the transforms, we'll round this stuff.. although... - // we're gonna use matrix transforms for drawing later, so it isn't extremely helpful - - // TODO - need more consideration of numerical precision here, because the typical case should be rock solid - top_TL.X = Round(top_TL.X); top_TL.Y = Round(top_TL.Y); - top_TR.X = Round(top_TR.X); top_TR.Y = Round(top_TR.Y); - top_BL.X = Round(top_BL.X); top_BL.Y = Round(top_BL.Y); - top_BR.X = Round(top_BR.X); top_BR.Y = Round(top_BR.Y); - bot_TL.X = Round(bot_TL.X); bot_TL.Y = Round(bot_TL.Y); - bot_TR.X = Round(bot_TR.X); bot_TR.Y = Round(bot_TR.Y); - bot_BL.X = Round(bot_BL.X); bot_BL.Y = Round(bot_BL.Y); - bot_BR.X = Round(bot_BR.X); bot_BR.Y = Round(bot_BR.Y); - -#if false - // precalculate some useful metrics - top_width = (int)(top_TR.X - top_TL.X); - top_height = (int)(top_BR.Y - top_TR.Y); - bot_width = (int)(bot_TR.X - bot_TL.X); - bot_height = (int)(bot_BR.Y - bot_TR.Y); -#endif - - // the size can now be determined in a kind of fluffily magical way by transforming edges and checking the bounds - float fxmin = 100000, fymin = 100000, fxmax = -100000, fymax = -100000; - if (settings.ScreenLayout != NDS.ScreenLayoutKind.Bottom) - { - fxmin = Math.Min(Math.Min(Math.Min(Math.Min(top_TL.X, top_TR.X), top_BL.X), top_BR.X), fxmin); - fymin = Math.Min(Math.Min(Math.Min(Math.Min(top_TL.Y, top_TR.Y), top_BL.Y), top_BR.Y), fymin); - fxmax = Math.Max(Math.Max(Math.Max(Math.Max(top_TL.X, top_TR.X), top_BL.X), top_BR.X), fxmax); - fymax = Math.Max(Math.Max(Math.Max(Math.Max(top_TL.Y, top_TR.Y), top_BL.Y), top_BR.Y), fymax); - } - if (settings.ScreenLayout != NDS.ScreenLayoutKind.Top) - { - fxmin = Math.Min(Math.Min(Math.Min(Math.Min(bot_TL.X, bot_TR.X), bot_BL.X), bot_BR.X), fxmin); - fymin = Math.Min(Math.Min(Math.Min(Math.Min(bot_TL.Y, bot_TR.Y), bot_BL.Y), bot_BR.Y), fymin); - fxmax = Math.Max(Math.Max(Math.Max(Math.Max(bot_TL.X, bot_TR.X), bot_BL.X), bot_BR.X), fxmax); - fymax = Math.Max(Math.Max(Math.Max(Math.Max(bot_TL.Y, bot_TR.Y), bot_BL.Y), bot_BR.Y), fymax); - } - - // relocate whatever we got back into the viewable area - top.Translate(-fxmin, -fymin); - bot.Translate(-fxmin, -fymin); - matTop = top.Top; - matBot = bot.Top; - - // do some more rounding - unsafe - { - fixed (Matrix4x4* matTopP = &matTop, matBotP = &matBot) - { - float* matTopF = (float*)matTopP, matBotF = (float*)matBotP; - for (var i = 0; i < 4 * 4; i++) - { - if (Math.Abs(matTopF[i]) < 0.0000001f) - { - matTopF[i] = 0; - } - - if (Math.Abs(matBotF[i]) < 0.0000001f) - { - matBotF[i] = 0; - } - } - } - } - - Matrix4x4.Invert(matTop, out matTopInvert); - Matrix4x4.Invert(matBot, out matBotInvert); - - outputSize = new((int)(fxmax - fxmin), (int)(fymax - fymin)); - } - - public override Size PresizeInput(string channel, Size size) - { - CrunchNumbers(); - return outputSize; - } - - public override Size PresizeOutput(string channel, Size size) - { - CrunchNumbers(); - return base.PresizeOutput(channel, outputSize); - } - - public override void SetInputFormat(string channel, SurfaceState state) - { - CrunchNumbers(); - var ss = new SurfaceState(new(outputSize), SurfaceDisposition.RenderTarget); - DeclareOutput(ss, channel); - } - public override Vector2 UntransformPoint(string channel, Vector2 point) { - var settings = _nds.GetSettings(); - var invert = settings.ScreenInvert - && settings.ScreenLayout != NDS.ScreenLayoutKind.Top - && settings.ScreenLayout != NDS.ScreenLayoutKind.Bottom; - - point = Vector2.Transform(point, invert ? matTopInvert : matBotInvert); - - // hack to accomodate input tracking system's float-point sense (based on the core's VideoBuffer height) - // actually, this is needed for a reason similar to the "TouchScreenStart" that I removed. - // So, something like that needs readding if we're to get rid of this hack. - // (should redo it as a mouse coordinate offset or something.. but the key is to pipe it to the point where this is needed.. that is where MainForm does DisplayManager.UntransformPoint() - point.Y *= 2; - - // in case we're in this layout, we get confused, so fix it - if (settings.ScreenLayout == NDS.ScreenLayoutKind.Top) point = new(0.0f, 0.0f); - - // TODO: we probably need more subtle logic here. - // some capability to return -1,-1 perhaps in case the cursor is nowhere. - // not sure about that - - return point; + var ret = _nds.GetTouchCoords((int)point.X, (int)point.Y); + var vp = _nds.AsVideoProvider(); + ret.X *= vp.BufferWidth / 255.0f; + ret.Y *= vp.BufferHeight / 191.0f; + return ret; } public override Vector2 TransformPoint(string channel, Vector2 point) { - return Vector2.Transform(point, matTop); - } - - public override void Run() - { -#if false - if (Nop) - { - return; - } -#endif - - // TODO: this could be more efficient (draw only in gap) - FilterProgram.GL.ClearColor(Color.Black); - - FilterProgram.GuiRenderer.Begin(outputSize); - FilterProgram.GuiRenderer.DisableBlending(); - - // TODO: may depend on input, or other factors, not sure yet - // watch out though... if we filter linear, then screens will bleed into each other. - // so we will have to break them into render targets first. - InputTexture.SetFilterNearest(); - - //draw screens - var renderTop = false; - var renderBottom = false; - var settings = _nds.GetSettings(); - switch (settings.ScreenLayout) - { - case NDS.ScreenLayoutKind.Bottom: - renderBottom = true; - break; - case NDS.ScreenLayoutKind.Top: - renderTop = true; - break; - case NDS.ScreenLayoutKind.Vertical: - case NDS.ScreenLayoutKind.Horizontal: - renderTop = renderBottom = true; - break; - default: - throw new InvalidOperationException(); - } - - var invert = settings.ScreenInvert && renderTop && renderBottom; - - if (renderTop) - { - FilterProgram.GuiRenderer.Modelview.Push(); - FilterProgram.GuiRenderer.Modelview.PreMultiplyMatrix(invert ? matBot : matTop); - FilterProgram.GuiRenderer.DrawSubrect(InputTexture, 0, 0, 256, 192, 0.0f, 0.0f, 1.0f, 0.5f); - FilterProgram.GuiRenderer.Modelview.Pop(); - } - - if (renderBottom) - { - FilterProgram.GuiRenderer.Modelview.Push(); - FilterProgram.GuiRenderer.Modelview.PreMultiplyMatrix(invert ? matTop : matBot); - FilterProgram.GuiRenderer.DrawSubrect(InputTexture, 0, 0, 256, 192, 0.0f, 0.5f, 1.0f, 1.0f); - FilterProgram.GuiRenderer.Modelview.Pop(); - } - - FilterProgram.GuiRenderer.End(); + // TODO + Console.WriteLine($"TODO ScreenControlNDS TransformPoint {point.X} / {point.Y}"); + return base.TransformPoint(channel, point); } } diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/LibMelonDS.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/LibMelonDS.cs index 5d3e967769..78d65550dc 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/LibMelonDS.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/LibMelonDS.cs @@ -157,15 +157,6 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS } } - [UnmanagedFunctionPointer(CC)] - public delegate IntPtr RequestGLContextCallback(); - - [UnmanagedFunctionPointer(CC)] - public delegate void ReleaseGLContextCallback(IntPtr context); - - [UnmanagedFunctionPointer(CC)] - public delegate void ActivateGLContextCallback(IntPtr context); - [UnmanagedFunctionPointer(CC)] public delegate IntPtr GetGLProcAddressCallback(string proc); @@ -263,5 +254,45 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS [BizImport(CC)] public abstract void ReadFrameBuffer(int[] buffer); + + public enum ScreenLayout : int + { + Natural, + Vertical, + Horizontal, + // TODO? do we want this? + // Hybrid, + } + + public enum ScreenRotation : int + { + Deg0, + Deg90, + Deg180, + Deg270, + } + + public enum ScreenSizing : int + { + Even = 0, + TopOnly = 4, + BotOnly = 5, + } + + [StructLayout(LayoutKind.Sequential)] + public struct ScreenSettings + { + public ScreenLayout ScreenLayout; + public ScreenRotation ScreenRotation; + public ScreenSizing ScreenSizing; + public int ScreenGap; + public bool ScreenSwap; + } + + [BizImport(CC)] + public abstract void SetScreenSettings(ref ScreenSettings screenSettings, out int width, out int height, out int vwidth, out int vheight); + + [BizImport(CC)] + public abstract void GetTouchCoords(ref int x, ref int y); } } diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS.IGLTextureProvider.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS.IGLTextureProvider.cs index 9a140b1bba..7efa2d4ad9 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS.IGLTextureProvider.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS.IGLTextureProvider.cs @@ -9,7 +9,6 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS 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; @@ -25,18 +24,19 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS public int[] GetVideoBuffer() { + var vb = _vp.GetVideoBuffer(); if (VideoDirty) { _activateGLContextCallback(); - _core.ReadFrameBuffer(_vbuf); + _core.ReadFrameBuffer(vb); VideoDirty = false; } - return _vbuf; + return vb; } - public int VirtualWidth => 256; - public int VirtualHeight => 384; + public int VirtualWidth { get; internal set; } + public int VirtualHeight { get; internal set; } public int BufferWidth => _vp.BufferWidth; public int BufferHeight => _vp.BufferHeight; public int VsyncNumerator => _vp.VsyncNumerator; 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 770be692fc..f314c6a8b6 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS.ISettable.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS.ISettable.cs @@ -101,25 +101,33 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS public enum ScreenLayoutKind { + Natural, Vertical, Horizontal, + [Display(Name = "Top Only")] Top, + [Display(Name = "Bottom Only")] Bottom, } public enum ScreenRotationKind { + [Display(Name = "0°")] Rotate0, + [Display(Name = "90°")] Rotate90, + [Display(Name = "180°")] Rotate180, + [Display(Name = "270°")] Rotate270, } public class NDSSettings { [DisplayName("Screen Layout")] - [Description("Adjusts the layout of the screens")] - [DefaultValue(ScreenLayoutKind.Vertical)] + [Description("Adjusts the layout of the screens. Natural will change between Vertical and Horizontal depending on Screen Rotation")] + [DefaultValue(ScreenLayoutKind.Natural)] + [TypeConverter(typeof(DescribableEnumConverter))] public ScreenLayoutKind ScreenLayout { get; set; } [DisplayName("Invert Screens")] @@ -130,6 +138,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS [DisplayName("Rotation")] [Description("Adjusts the orientation of the screens")] [DefaultValue(ScreenRotationKind.Rotate0)] + [TypeConverter(typeof(DescribableEnumConverter))] public ScreenRotationKind ScreenRotation { get; set; } [JsonIgnore] @@ -147,13 +156,16 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS public enum AudioBitDepthType : int { Auto, + [Display(Name = "10")] Ten, + [Display(Name = "16")] Sixteen, } [DisplayName("Audio Bit Depth")] [Description("Auto will set the audio bit depth most accurate to the console (10 for DS, 16 for DSi).")] [DefaultValue(AudioBitDepthType.Auto)] + [TypeConverter(typeof(DescribableEnumConverter))] public AudioBitDepthType AudioBitDepth { get; set; } [DisplayName("Alt Lag")] @@ -445,9 +457,56 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS public NDSSyncSettings GetSyncSettings() => _syncSettings.Clone(); + private void RefreshScreenSettings(NDSSettings settings) + { + var screenSettings = new LibMelonDS.ScreenSettings + { + ScreenLayout = settings.ScreenLayout switch + { + ScreenLayoutKind.Natural => LibMelonDS.ScreenLayout.Natural, + ScreenLayoutKind.Vertical => LibMelonDS.ScreenLayout.Vertical, + ScreenLayoutKind.Horizontal => LibMelonDS.ScreenLayout.Horizontal, + _ => LibMelonDS.ScreenLayout.Natural, + }, + ScreenRotation = settings.ScreenRotation switch + { + ScreenRotationKind.Rotate0 => LibMelonDS.ScreenRotation.Deg0, + ScreenRotationKind.Rotate90 => LibMelonDS.ScreenRotation.Deg90, + ScreenRotationKind.Rotate180 => LibMelonDS.ScreenRotation.Deg180, + ScreenRotationKind.Rotate270 => LibMelonDS.ScreenRotation.Deg270, + _ => LibMelonDS.ScreenRotation.Deg0, + }, + ScreenSizing = settings.ScreenLayout switch + { + ScreenLayoutKind.Top => LibMelonDS.ScreenSizing.TopOnly, + ScreenLayoutKind.Bottom => LibMelonDS.ScreenSizing.BotOnly, + _ => LibMelonDS.ScreenSizing.Even, + }, + ScreenGap = Math.Max(0, Math.Min(settings.ScreenGap, 128)), + ScreenSwap = settings.ScreenInvert + }; + + _openGLProvider.ActivateGLContext(_glContext); // SetScreenSettings will re-present the frame, so needs OpenGL context active + _core.SetScreenSettings(ref screenSettings, out var w , out var h, out var vw, out var vh); + + BufferWidth = w; + BufferHeight = h; + _glTextureProvider.VirtualWidth = vw; + _glTextureProvider.VirtualHeight = vh; + _glTextureProvider.VideoDirty = true; + } + public PutSettingsDirtyBits PutSettings(NDSSettings o) { var ret = NDSSettings.NeedsScreenResize(_settings, o); + + // ScreenInvert changing won't need a screen resize + // but it will change the underlying image + if (_glContext != null && (ret || _settings.ScreenInvert != o.ScreenInvert)) + { + RefreshScreenSettings(o); + } + _settings = o; return ret ? PutSettingsDirtyBits.ScreenLayoutChanged : PutSettingsDirtyBits.None; } diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS.cs index bccfade539..1dfab01590 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.IO; using System.IO.Compression; using System.Linq; +using System.Numerics; using System.Runtime.InteropServices; using System.Threading; @@ -64,12 +65,22 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS private readonly MelonDSGLTextureProvider _glTextureProvider; private readonly IOpenGLProvider _openGLProvider; - private readonly object _glContext; private readonly LibMelonDS.GetGLProcAddressCallback _getGLProcAddressCallback; + private object _glContext; private IntPtr GetGLProcAddressCallback(string proc) => _openGLProvider.GetGLProcAddress(proc); + public Vector2 GetTouchCoords(int x, int y) + { + if (_glContext != null) + { + _core.GetTouchCoords(ref x, ref y); + } + + return new(x, y); + } + [CoreConstructor(VSystemID.Raw.NDS)] public NDS(CoreLoadParameters lp) : base(lp.Comm, new() @@ -77,7 +88,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS DefaultWidth = 256, DefaultHeight = 384, MaxWidth = 256 * 16, - MaxHeight = 384 * 16, + MaxHeight = (384 + 128) * 16, MaxSamples = 1024, DefaultFpsNumerator = 33513982, DefaultFpsDenominator = 560190, @@ -145,6 +156,18 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS } } + if (_activeSyncSettings.ThreeDeeRenderer == NDSSyncSettings.ThreeDeeRendererType.Software) + { + if (!_openGLProvider.SupportsGLVersion(3, 1)) + { + lp.Comm.Notify("OpenGL 3.1 is not supported on this machine, screen control options will not work.", null); + } + else + { + _glContext = _openGLProvider.RequestGLContext(3, 1, true, false); + } + } + _core = PreInit(new() { Filename = "melonDS.wbx", @@ -242,7 +265,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS _configCallbackInterface.AllCallbacksInArray(_adapter), _fileCallbackInterface.AllCallbacksInArray(_adapter), _logCallback, - _getGLProcAddressCallback); + _glContext != null ? _getGLProcAddressCallback : null); if (error != IntPtr.Zero) { using (_exe.EnterExit()) @@ -284,6 +307,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS { _glTextureProvider = new(this, _core, () => _openGLProvider.ActivateGLContext(_glContext)); _serviceProvider.Register(_glTextureProvider); + RefreshScreenSettings(_settings); } } @@ -444,6 +468,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS if (_glContext != null) { _openGLProvider.ReleaseGLContext(_glContext); + _glContext = null; } base.Dispose();