static-linked libretro core support

This commit is contained in:
lifning 2021-11-11 16:09:14 -08:00
parent 464e670be4
commit f5b86f9f8e
5 changed files with 89 additions and 11 deletions

View File

@ -12,3 +12,6 @@ libretro-sys = "0.1"
libloading = "0.5"
num_enum = "0.4"
once_cell = "1"
[features]
static = []

View File

@ -3,4 +3,9 @@ fn main() {
cc::Build::new()
.file("src/retro/c_ext/log_wrapper.c")
.compile("log_wrapper");
}
if cfg!(feature = "static") {
println!("cargo:rustc-link-search=./lib");
println!("cargo:rustc-link-lib=retro");
println!("cargo:rustc-link-lib=m");
}
}

View File

@ -10,7 +10,7 @@ use super::ffi::*;
pub type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;
pub struct LibretroApi {
_lib: libloading::Library, // for tying our lifetime to its own
_lib: Option<libloading::Library>, // 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;

View File

@ -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"]

View File

@ -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<GameGeometry>,
handler_id: Option<RetroHandlerId>,
_temp_dir: tempfile::TempDir,
_temp_dir: Option<tempfile::TempDir>,
}
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<Path>) -> Pin<Box<Self>> {
// 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<Box<Self>> {
Self::new_inner(LibretroApi::from_static(), PathBuf::new(), None)
}
fn new_inner(raw_retro: LibretroApi, libretro_path: PathBuf, _temp_dir: Option<TempDir>) -> Pin<Box<Self>> {
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);