Repository navigation
FFI sound and saves; update to Rust 1.99 and current deps - #7
Merged
Merged
Conversation
Expose sound and battery-backed saves to C hosts, and stop the FFI build from forcing every cartridge onto MBC3. - get_mbc no longer special-cases a missing path as MBC3; every mapper takes an optional save path, so FFI and wasm loads get the right MBC. - MemoryBankController::save() writes cartridge RAM on demand (Drop still saves too). Writes go through a temp file and a rename. - Gameboy::try_new / Cpu::try_new return errors instead of panicking, which matters with panic = "abort" in release. - New FFI: load_with_save, save, enable_audio, audio_queued, last_error. audio_queued lets hosts pace frame() to the audio clock. - Bump cpal to 0.17: 0.16's CoreAudio supported_configs passes a pointer to an immutable local as an out-parameter, so optimized builds reserve a zero-sized buffer and crash at 0x1 when querying the device.
CI's desktop example step resolves dependencies fresh (examples have no lockfile), and current crates need Rust 1.85+ and edition 2024, so the pinned 1.83 toolchain could no longer build it. - rust-toolchain: 1.83.0 -> 1.99.1 - cpal 0.18, ratatui 0.30, ratatui-image 11, icy_sixel 0.5, base64 0.23, blip_buf 0.2, image 0.25.10, wasm-bindgen/js-sys/web-sys latest - glutin 0.28 -> 0.32: windowing moved out of glutin, so the desktop screen now runs on winit 0.30 + glutin-winit (ApplicationHandler). Same window, keys, focus pause and ~60 FPS pacing; it now also updates the GL viewport on resize. - blip_buf 0.2 returns Err where 0.1 asserted; those calls now drop the sample instead of aborting. - Fixes for new clippy lints (repeat_n, is_multiple_of, format width).
ratatui-image 11 enables chafa-dyn by default, which needs the system libchafa via pkg-config. Keep just the crossterm backend so the terminal frontend has no new system dependency.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Makes the C FFI usable for a real native host (built for a SwiftUI macOS frontend): sound, persistent battery saves, and errors instead of aborts.
get_mbctreated a missing file path as "use MBC3 without saves", so every FFI/wasm game ran on MBC3. Each mapper now takesOption<PathBuf>and saves are simply disabled without one.MemoryBankController::save()writes cartridge RAM (MBC3 keeps its RTC prefix).Dropstill saves. Writes go to a.gbsave.tmpand are renamed, so a crash never leaves a truncated save. This matters for FFI because the globalGAMEBOYstatic is never dropped.Gameboy::try_new/Cpu::try_newreturnResult;newkeeps its old behaviour. Withpanic = "abort"a bad ROM used to kill the host process.gameboy.h):load_with_save(bytes, len, rom_path): likeload, with.gbsavenext torom_path; returns a status codesave(): flush cartridge RAM nowenable_audio(): start cpal output, returns the sample rateaudio_queued(): queued stereo frames, so hosts can paceframe()to the audio clock (displays run at 60 Hz, the Game Boy at 59.73 Hz)last_error(): message for the last failuresupported_configspasses&data_sizeof an immutable local as an out-parameter. In optimized builds the compiler assumes it stays0, reserves a zero-sized buffer, and CoreAudio writes to0x1(EXC_BAD_ACCESS). Reproduced on macOS 26.5 in release builds; fixed upstream in 0.17.Toolchain and dependency update
CI's
Make desktop buildstep was failing (onmaintoo): the examples have no lockfile, so they resolve dependencies fresh, and current crates need Rust 1.85+ and edition 2024.rust-toolchain: 1.83.0 → 1.99.1screen/desktop.rsnow runs on winit 0.30 + glutin-winit with anApplicationHandler. Same window, key mapping, pause-when-unfocused and ~60 FPS pacing; it also updates the GL viewport on resize now.chafa-dynfeature, which requires the system libchafa via pkg-config.Errwhere 0.1 asserted; those calls now drop the sample instead of aborting.repeat_n,is_multiple_of, format width).Testing
CI passes (lint, tests, desktop build). Locally on macOS 26.5 with Rust 1.99.1:
make lint(clippy-D warnings),cargo test --release: passcargo build --release --target wasm32-unknown-unknown: buildsexamples/desktopandexamples/terminal: buildcargo build --release --no-default-features --features ffi: builds; tested from a Swift host with Pokémon Silver (MBC3 + RTC + battery): audio callback runs,.gbsaveis written (8-byte RTC + 32 KiB RAM)