From f5b86f9f8e6aa6cb2fa9af7c2030027de7fb80e3 Mon Sep 17 00:00:00 2001 From: lifning <> Date: Thu, 11 Nov 2021 16:09:14 -0800 Subject: [PATCH] static-linked libretro core support --- ferretro_base/Cargo.toml | 3 ++ ferretro_base/build.rs | 7 +++- ferretro_base/src/retro/loading.rs | 63 ++++++++++++++++++++++++++++- ferretro_components/Cargo.toml | 3 +- ferretro_components/src/base/mod.rs | 24 +++++++---- 5 files changed, 89 insertions(+), 11 deletions(-) diff --git a/ferretro_base/Cargo.toml b/ferretro_base/Cargo.toml index ec16a4f..cbf9f42 100644 --- a/ferretro_base/Cargo.toml +++ b/ferretro_base/Cargo.toml @@ -12,3 +12,6 @@ libretro-sys = "0.1" libloading = "0.5" num_enum = "0.4" once_cell = "1" + +[features] +static = [] diff --git a/ferretro_base/build.rs b/ferretro_base/build.rs index b79d098..202a36a 100644 --- a/ferretro_base/build.rs +++ b/ferretro_base/build.rs @@ -3,4 +3,9 @@ fn main() { cc::Build::new() .file("src/retro/c_ext/log_wrapper.c") .compile("log_wrapper"); -} \ No newline at end of file + if cfg!(feature = "static") { + println!("cargo:rustc-link-search=./lib"); + println!("cargo:rustc-link-lib=retro"); + println!("cargo:rustc-link-lib=m"); + } +} diff --git a/ferretro_base/src/retro/loading.rs b/ferretro_base/src/retro/loading.rs index ddd283f..2c49de1 100644 --- a/ferretro_base/src/retro/loading.rs +++ b/ferretro_base/src/retro/loading.rs @@ -10,7 +10,7 @@ use super::ffi::*; pub type Result = std::result::Result>; pub struct LibretroApi { - _lib: libloading::Library, // for tying our lifetime to its own + _lib: Option, // for tying our lifetime to its own pub core_api: CoreAPI, loaded_game: bool, environment_set: bool, @@ -46,9 +46,68 @@ impl LibretroApi { retro_get_memory_data: *lib.get(b"retro_get_memory_data")?, retro_get_memory_size: *lib.get(b"retro_get_memory_size")?, }; - Ok(LibretroApi { _lib: lib, core_api, loaded_game: false, environment_set: false }) + Ok(LibretroApi { _lib: Some(lib), core_api, loaded_game: false, environment_set: false }) } } + #[cfg(feature = "static")] + pub fn from_static() -> Self { + use std::os::raw::c_uint; + extern "C" { + fn retro_set_environment(callback: EnvironmentFn); + fn retro_set_video_refresh(callback: VideoRefreshFn); + fn retro_set_audio_sample(callback: AudioSampleFn); + fn retro_set_audio_sample_batch(callback: AudioSampleBatchFn); + fn retro_set_input_poll(callback: InputPollFn); + fn retro_set_input_state(callback: InputStateFn); + fn retro_init(); + fn retro_deinit(); + fn retro_api_version() -> c_uint; + fn retro_get_system_info(info: *mut SystemInfo); + fn retro_get_system_av_info(info: *mut SystemAvInfo); + fn retro_set_controller_port_device(port: c_uint, device: c_uint); + fn retro_reset(); + fn retro_run(); + fn retro_serialize_size() -> usize; + fn retro_serialize(data: *mut c_void, size: usize); + fn retro_unserialize(data: *const c_void, size: usize) -> bool; + fn retro_cheat_reset(); + fn retro_cheat_set(index: c_uint, enabled: bool, code: *const c_char); + fn retro_load_game(game: *const GameInfo) -> bool; + fn retro_load_game_special(game_type: c_uint, info: *const GameInfo, num_info: usize) -> bool; + fn retro_unload_game(); + fn retro_get_region() -> c_uint; + fn retro_get_memory_data(id: c_uint) -> *mut c_void; + fn retro_get_memory_size(id: c_uint) -> usize; + } + let core_api = CoreAPI { + retro_set_environment, + retro_set_video_refresh, + retro_set_audio_sample, + retro_set_audio_sample_batch, + retro_set_input_poll, + retro_set_input_state, + retro_init, + retro_deinit, + retro_api_version, + retro_get_system_info, + retro_get_system_av_info, + retro_set_controller_port_device, + retro_reset, + retro_run, + retro_serialize_size, + retro_serialize, + retro_unserialize, + retro_cheat_reset, + retro_cheat_set, + retro_load_game, + retro_load_game_special, + retro_unload_game, + retro_get_region, + retro_get_memory_data, + retro_get_memory_size, + }; + LibretroApi { _lib: None, core_api, loaded_game: false, environment_set: false } + } /// set_environment() must be called before init(). pub fn set_environment(&mut self, cb: EnvironmentFn) { self.environment_set = true; diff --git a/ferretro_components/Cargo.toml b/ferretro_components/Cargo.toml index 22b46ec..dd8bc64 100644 --- a/ferretro_components/Cargo.toml +++ b/ferretro_components/Cargo.toml @@ -8,7 +8,7 @@ edition = "2021" cc = "^1" [dependencies] -ferretro_base = { path = "../ferretro_base"} +ferretro_base = { path = "../ferretro_base" } libloading = "0.5" num_enum = "0.4" ffmpeg-next = { version = "4.3.8", optional = true } @@ -22,6 +22,7 @@ crossbeam-channel = "0.4" structopt = "0.3" [features] +static = ["ferretro_base/static"] ffmpeg_comp = ["ffmpeg-next"] sdl2_comp = ["sdl2", "gl", "crossbeam-channel"] diff --git a/ferretro_components/src/base/mod.rs b/ferretro_components/src/base/mod.rs index a66b18d..4ca1320 100644 --- a/ferretro_components/src/base/mod.rs +++ b/ferretro_components/src/base/mod.rs @@ -4,16 +4,18 @@ use crate::prelude::*; use ferretro_base::retro::ffi::*; +use ferretro_base::retro::loading::LibretroApi; use ferretro_base::prelude::{LibretroWrapperAccess, RetroHandlerId}; use core::any::{Any, TypeId}; use core::pin::Pin; -use std::os::raw::c_uint; -use std::path::{PathBuf, Path}; -use std::io::Read; use std::collections::HashMap; use std::ffi::c_void; +use std::io::Read; +use std::os::raw::c_uint; +use std::path::{PathBuf, Path}; +use tempfile::TempDir; pub struct RetroComponentBase { retro: LibretroWrapper, @@ -37,7 +39,7 @@ pub struct RetroComponentBase { cached_geometry: Option, handler_id: Option, - _temp_dir: tempfile::TempDir, + _temp_dir: Option, } unsafe impl Send for RetroComponentBase {} @@ -62,7 +64,6 @@ pub trait RetroComponent: RetroCallbacks + Any { } impl RetroComponentBase { - // TODO: constructor & wrapper that uses a statically linked libretro? pub fn new(core_path: impl AsRef) -> Pin> { // allow multiple copies of same lib, possibly? let temp_dir = tempfile::tempdir().unwrap(); @@ -70,7 +71,16 @@ impl RetroComponentBase { std::fs::copy(core_path.as_ref(), &libretro_path).unwrap(); let lib = libloading::Library::new(&libretro_path).unwrap(); - let raw_retro = ferretro_base::retro::loading::LibretroApi::from_library(lib).unwrap(); + let raw_retro = LibretroApi::from_library(lib).unwrap(); + Self::new_inner(raw_retro, libretro_path, Some(temp_dir)) + } + + #[cfg(feature = "static")] + pub fn new_static() -> Pin> { + Self::new_inner(LibretroApi::from_static(), PathBuf::new(), None) + } + + fn new_inner(raw_retro: LibretroApi, libretro_path: PathBuf, _temp_dir: Option) -> Pin> { let retro = LibretroWrapper::from(raw_retro); let emu = RetroComponentBase { @@ -90,7 +100,7 @@ impl RetroComponentBase { cached_memory_map: None, cached_geometry: None, handler_id: None, - _temp_dir: temp_dir, + _temp_dir, }; let mut pin_emu = Box::pin(emu);