BizHawk icon indicating copy to clipboard operation
BizHawk copied to clipboard

[Core Port Req.] NanoBoyAdvance for GBA

Open RetroEdit opened this issue 2 years ago • 8 comments

Upstream info

  • Website/source repo: https://github.com/nba-emu/NanoBoyAdvance
  • Author: @fleroviux
  • Target platforms: Linux, Windows, macOS
  • Language(s): C++
  • License: GPL-3.0

Merits

BizHawk already has a much-appreciated and generally accurate GBA core: mGBA. However, NanoBoyAdvance was designed from the ground up to be cycle-accurate and also has notable general accuracy improvements as a result. It's essentially the cutting-edge of GBA emulation that's been able to benefit from the knowledge of its predecessors and fleriouviux has also been able to do her own research to advance GBA emulation accuracy.

To point out a specific case with which I'm intimately familiar, a version of my Shrek 2 TAS in mGBA had a ~17.9 second deviation from real console, while in NanoBoyAdvance it's a mere ~81 frames. Both emulators will probably improve in accuracy over time, but NanoBoyAdvance may have an inherent architectural advantage in certain accuracy-related matters.

I have noticed mGBA has similar deviations from real-console in other GBA games with lag, although I've only rigorously tested Shrek 2 (and I'm still doing ongoing testing there).

NanoBoyAdvance also has its own accuracy datasheet.

Other GBA emulators

NanoBoyAdvance is not the only newer accuracy focused GBA emulator. Alyosha recently released their own GBA TAS emulator GBAHawk. For the Shrek 2 TAS test, GBAHawk was ~4.034 seconds away from real console. SkyEmu is also more recent, and was ~31 frames away in the Shrek 2 TAS test, with some caveats related to testing with and without prefetch. SkyEmu was also previously rejected as a BizHawk core a year ago (#3311), although SkyEmu accuracy has advanced since then.

Technical details

I'm quoting this information directly from fleroviux.

  • Able to build .dll/.so for P/Invoke? -- "should be easy to do with CMake (just add another library that sits on top of libnba)"
  • Frontend/backend separation -- "The backend is completely separated from the frontend."
  • can force single-threaded? -- "NBA is completely single-threaded."
  • Has I/O abstraction accepting byte array -- "This is not completely there yet. ROMs can be loaded from memory, however saves need to be read from and written to disk. If necessary this could be extended I think."
  • Savestate quality -- "Savestate quality should be pretty high I think, at least on a frame to level. However savestate compatibility between releases is practically nonexistent."
    • my note: BizHawk generally doesn't guarantee core savestates will be ~~stable~~ compatible between versions anyway

Additional notes

I may have some interest in working on a draft pull request for this. fleroviux also said she was interested in having TAS support for the emulator and interested in potentially helping bring about a BizHawk core.

RetroEdit avatar Aug 14 '23 15:08 RetroEdit

The core API surface seems to be defined in these files:

https://github.com/nba-emu/NanoBoyAdvance/blob/master/src/nba/src/core.hpp https://github.com/nba-emu/NanoBoyAdvance/blob/master/src/nba/include/nba/config.hpp https://github.com/nba-emu/NanoBoyAdvance/blob/master/src/nba/include/nba/device/audio_device.hpp https://github.com/nba-emu/NanoBoyAdvance/blob/master/src/nba/include/nba/device/input_device.hpp https://github.com/nba-emu/NanoBoyAdvance/blob/master/src/nba/include/nba/device/video_device.hpp

On first review, it seems like a reasonable API. I haven't checked off every last method but it could probably do most of what Bizhawk wants off of what exists already in the src/nba folder. As you point out, loading roms from a byte array/byte stream, and loading and saving saveram from a byte array/byte stream, are desirable.

Could be waterboxed if we want to; you never know about savestates, even the best of the best are pretty rough.

nattthebear avatar Aug 14 '23 19:08 nattthebear

I generally would prefer using core-provided savestates if they're reliable, but that's just my personal thought. I would wonder if using waterbox would have a notable impact on speed or savestate size, since I would personally prefer those to be optimized. But I can also appreciate how important reliable savestates are for a good user experience, so there is a fair argument for waterbox.

RetroEdit avatar Aug 14 '23 20:08 RetroEdit

Waterboxing can often be better for performance compared to a native build, as the waterboxing layer is ultimately extremely thin and the cores get to have the benefit of everything is compiled under Linux's ABI (which often is better for e.g. context switching), and would reduce the size of the core builds (1 build for both Windows and Linux that is zstd compressed would be much smaller than 2 native builds), and can even reduce state size and increase state performance (due to dirty detection + savestating is just a ton of memcpy's)

CasualPokePlayer avatar Aug 14 '23 20:08 CasualPokePlayer

Would someone be willing to give me a quick rundown of what waterboxing exactly is? I'm not familar with the term, thanks.

Could be waterboxed if we want to; you never know about savestates, even the best of the best are pretty rough.

It should be noted that if there are issues with my save state implementation, I'd definitely be interested in fixing those issues in the core. The current save state implementation should already be very accurate and I think there's only one case where I know it's not completely correct yet (that is when taking save-states in the middle of a scanline). But that has been more due to "lazyness" (there is a lot of internal PPU state) and could be fixed at some point.

fleroviux avatar Aug 14 '23 20:08 fleroviux

/waterbox in this repo. It's a userspace not-an-emulator which runs ELF binaries compiled against its fork of musl.

YoshiRulz avatar Aug 14 '23 21:08 YoshiRulz

In terms of what it means for building cores: it's effectively no different than a cross compiling setup targeting a unique "Linux" version with all the needed goodies in a sysroot folder.

To be clear, the standard for savestates in BizHawk is much, much higher than a casual user needs: any small thing, any small mistake, can mean a desync and hours on hours of lost work and hours trying to recover work (assuming the demotivation doesn't cause the TASer to abandon their project). Whereas a casual player won't care if there's some minutte difference as long the game/emulator doesn't crash.

Savestates under waterbox are effectively "perfect." The core's entire memory is initially Read-Only. This is so an exception/signal handler is able to catch writes, and thus know what pages of memory has been written to ("dirtied," i.e. dirty detection). This trick allows us to make savestates that are guaranteed to be perfect, while also keeping size down (and sometimes be smaller than upstream's own state, not to mention it's often faster than an upstream implementation assuming upstream isn't just a ton of memcpys).

CasualPokePlayer avatar Aug 14 '23 23:08 CasualPokePlayer

We don't need to make a strong commitment one way or the other. Most of the adapter code on the Bizhawk side can be used with either a traditional native core or a waterbox core.

nattthebear avatar Aug 15 '23 10:08 nattthebear

From Discord

ive considered doing an NBA port, although since its development is planned to cease and Mesen2 appears to have surpassed it i would probably instead consider porting over that

Probably not too much point overall in pursuing an NBA port as an "accuracy core" just because its development is planned to sunset with other emulators surpassing it with accuracy and continuing development.

CasualPokePlayer avatar Oct 21 '25 05:10 CasualPokePlayer