TASEmulators / BizHawk

BizHawk is a multi-system emulator written in C#. BizHawk provides nice features for casual gamers such as full screen, and joypad support in addition to full rerecording and debugging tools for all system cores.
http://tasvideos.org/BizHawk.html
Other
2.06k stars 375 forks source link

3DS Encore save state failed with Bizhawk API #3875

Closed jlefebure closed 2 months ago

jlefebure commented 2 months ago

Summary

Exception when saving state via SaveState API with a c# external tool

Repro

  1. Calling EmuClient.SaveState while loading a 3DS game
  2. Bizhawk crash. Exception is logged in IDE
    public ApiContainer? _maybeAPIContainer { get; set; }

    private ApiContainer APIs
        => _maybeAPIContainer!;
        //...

     APIs.EmuClient.Pause();
        APIs.EmuClient.SaveState(SAVE_PATH + @"\"+ SAVE_PREFIX + "-" + DateTime.Now.ToString("yyyyMMddHHmm"));
        APIs.EmuClient.SaveRam();
        APIs.EmuClient.Unpause();

Output

System.Exception: Failed to set context to current! SDL error: wglMakeCurrent(): La ressource demandée est en cours d’utilisation.
   à BizHawk.Bizware.Graphics.SDL2OpenGLContext.MakeContextCurrent() dans /src/BizHawk.Bizware.Graphics/OpenGL/SDL2OpenGLContext.cs:ligne 174
   à BizHawk.Client.EmuHawk.OpenGLProvider.ActivateGLContext(Object context) dans /src/BizHawk.Client.EmuHawk/GraphicsImplementations/OpenGLProvider.cs:ligne 23
   à BizHawk.Emulation.Cores.Consoles.Nintendo.N3DS.Encore.ActivateGLContextCallback(IntPtr context) dans /src/BizHawk.Emulation.Cores/Consoles/Nintendo/3DS/Encore.cs:ligne 190
   à Bizhawk.BizInvokeProxyLibEncore.Encore_StartSaveState(IntPtr )
   à BizHawk.Emulation.Cores.Consoles.Nintendo.N3DS.Encore.SaveStateBinary(BinaryWriter writer) dans /src/BizHawk.Emulation.Cores/Consoles/Nintendo/3DS/Encore.IStatable.cs:ligne 16
   à BizHawk.Client.Common.SavestateFile.<Create>b__6_4(BinaryWriter bw) dans /src/BizHawk.Client.Common/savestates/SavestateFile.cs:ligne 58
   à BizHawk.Client.Common.ZipStateSaver.<>c__DisplayClass6_0.<PutLump>b__0(Stream s) dans /src/BizHawk.Client.Common/savestates/ZipStateSaver.cs:ligne 46
   à BizHawk.Client.Common.FrameworkZipWriter.WriteItem(String name, Action`1 callback, Boolean zstdCompress) dans /src/BizHawk.Client.Common/FrameworkZipWriter.cs:ligne 40
   à BizHawk.Client.Common.ZipStateSaver.PutLump(BinaryStateLump lump, Action`1 callback, Boolean zstdCompress) dans /src/BizHawk.Client.Common/savestates/ZipStateSaver.cs:ligne 38
   à BizHawk.Client.Common.ZipStateSaver.PutLump(BinaryStateLump lump, Action`1 callback) dans /src/BizHawk.Client.Common/savestates/ZipStateSaver.cs:ligne 48
   à BizHawk.Client.Common.SavestateFile.Create(String filename, SaveStateConfig config) dans /src/BizHawk.Client.Common/savestates/SavestateFile.cs:ligne 60
   à BizHawk.Client.EmuHawk.MainForm.SaveState(String path, String userFriendlyStateName, Boolean fromLua, Boolean suppressOSD) dans /src/BizHawk.Client.EmuHawk/MainForm.cs:ligne 4327
   à BizHawk.Client.Common.EmuClientApi.SaveState(String name) dans /src/BizHawk.Client.Common/Api/Classes/EmuClientApi.cs:ligne 151
   à BizHawkTpp.SaveService.Save()

Host env.

YoshiRulz commented 2 months ago

Does this happen consistently?

Please copy the version from Help > About..., obviously you didn't mean to write 2.5.2.

jlefebure commented 2 months ago

Yup, always. Save states made using the UI works.

You're right, i'm on 2.9.2, last version from master branch (rev a803407cdd80b3bad10096edf6b1e63f303b5973)

CasualPokePlayer commented 2 months ago

Is this savestate possibly occurring in a separate thread? The error seems to indicate you are in a separate thread and it's when the main thread has the Encore OpenGL context active (and therefore other threads cannot make it active). You should not be calling SaveState outside of the main thread (this is more an OpenGL limitation if anything; even then savestates APIs (along with any other API touching emulator state) should not be considered safe outside of the main thread).

jlefebure commented 2 months ago

Hi, Yep, i'm on a separate thread. I'm actually calling the SaveState method every 10 minutes to make an autosave. I did not encounter any issue with NDS or GBA emulation, but I assume that it does not use OpenGL

Just to be sure, there is no workaround ?

CasualPokePlayer commented 2 months ago

Doing savestates with other cores have very high risks of causing crashes (especially any waterbox cores like NDS due to non-thread safe code in its handling) and whatever savestates produced would very likely be garbage / not load correctly. Your code is fundamentally wrong here.

YoshiRulz commented 2 months ago

Can't we make the call on the correct thread regardless of where the API was called from?

CasualPokePlayer commented 2 months ago

The API user could do that with the WinForms BeginInvoke/Invoke API.

jlefebure commented 2 months ago

Good to know. Thanks a lot @CasualPokePlayer, @YoshiRulz !

If API methods are not threadsafe, I close the issue and will work with BeginInvoke and Invoke methods