static-linked libretro core support
This commit is contained in:
parent
464e670be4
commit
f5b86f9f8e
|
@ -12,3 +12,6 @@ libretro-sys = "0.1"
|
||||||
libloading = "0.5"
|
libloading = "0.5"
|
||||||
num_enum = "0.4"
|
num_enum = "0.4"
|
||||||
once_cell = "1"
|
once_cell = "1"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
static = []
|
||||||
|
|
|
@ -3,4 +3,9 @@ fn main() {
|
||||||
cc::Build::new()
|
cc::Build::new()
|
||||||
.file("src/retro/c_ext/log_wrapper.c")
|
.file("src/retro/c_ext/log_wrapper.c")
|
||||||
.compile("log_wrapper");
|
.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");
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -10,7 +10,7 @@ use super::ffi::*;
|
||||||
pub type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;
|
pub type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;
|
||||||
|
|
||||||
pub struct LibretroApi {
|
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,
|
pub core_api: CoreAPI,
|
||||||
loaded_game: bool,
|
loaded_game: bool,
|
||||||
environment_set: bool,
|
environment_set: bool,
|
||||||
|
@ -46,9 +46,68 @@ impl LibretroApi {
|
||||||
retro_get_memory_data: *lib.get(b"retro_get_memory_data")?,
|
retro_get_memory_data: *lib.get(b"retro_get_memory_data")?,
|
||||||
retro_get_memory_size: *lib.get(b"retro_get_memory_size")?,
|
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().
|
/// set_environment() must be called before init().
|
||||||
pub fn set_environment(&mut self, cb: EnvironmentFn) {
|
pub fn set_environment(&mut self, cb: EnvironmentFn) {
|
||||||
self.environment_set = true;
|
self.environment_set = true;
|
||||||
|
|
|
@ -8,7 +8,7 @@ edition = "2021"
|
||||||
cc = "^1"
|
cc = "^1"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
ferretro_base = { path = "../ferretro_base"}
|
ferretro_base = { path = "../ferretro_base" }
|
||||||
libloading = "0.5"
|
libloading = "0.5"
|
||||||
num_enum = "0.4"
|
num_enum = "0.4"
|
||||||
ffmpeg-next = { version = "4.3.8", optional = true }
|
ffmpeg-next = { version = "4.3.8", optional = true }
|
||||||
|
@ -22,6 +22,7 @@ crossbeam-channel = "0.4"
|
||||||
structopt = "0.3"
|
structopt = "0.3"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
static = ["ferretro_base/static"]
|
||||||
ffmpeg_comp = ["ffmpeg-next"]
|
ffmpeg_comp = ["ffmpeg-next"]
|
||||||
sdl2_comp = ["sdl2", "gl", "crossbeam-channel"]
|
sdl2_comp = ["sdl2", "gl", "crossbeam-channel"]
|
||||||
|
|
||||||
|
|
|
@ -4,16 +4,18 @@
|
||||||
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use ferretro_base::retro::ffi::*;
|
use ferretro_base::retro::ffi::*;
|
||||||
|
use ferretro_base::retro::loading::LibretroApi;
|
||||||
use ferretro_base::prelude::{LibretroWrapperAccess, RetroHandlerId};
|
use ferretro_base::prelude::{LibretroWrapperAccess, RetroHandlerId};
|
||||||
|
|
||||||
use core::any::{Any, TypeId};
|
use core::any::{Any, TypeId};
|
||||||
use core::pin::Pin;
|
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::collections::HashMap;
|
||||||
use std::ffi::c_void;
|
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 {
|
pub struct RetroComponentBase {
|
||||||
retro: LibretroWrapper,
|
retro: LibretroWrapper,
|
||||||
|
@ -37,7 +39,7 @@ pub struct RetroComponentBase {
|
||||||
cached_geometry: Option<GameGeometry>,
|
cached_geometry: Option<GameGeometry>,
|
||||||
|
|
||||||
handler_id: Option<RetroHandlerId>,
|
handler_id: Option<RetroHandlerId>,
|
||||||
_temp_dir: tempfile::TempDir,
|
_temp_dir: Option<tempfile::TempDir>,
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl Send for RetroComponentBase {}
|
unsafe impl Send for RetroComponentBase {}
|
||||||
|
@ -62,7 +64,6 @@ pub trait RetroComponent: RetroCallbacks + Any {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RetroComponentBase {
|
impl RetroComponentBase {
|
||||||
// TODO: constructor & wrapper that uses a statically linked libretro?
|
|
||||||
pub fn new(core_path: impl AsRef<Path>) -> Pin<Box<Self>> {
|
pub fn new(core_path: impl AsRef<Path>) -> Pin<Box<Self>> {
|
||||||
// allow multiple copies of same lib, possibly?
|
// allow multiple copies of same lib, possibly?
|
||||||
let temp_dir = tempfile::tempdir().unwrap();
|
let temp_dir = tempfile::tempdir().unwrap();
|
||||||
|
@ -70,7 +71,16 @@ impl RetroComponentBase {
|
||||||
std::fs::copy(core_path.as_ref(), &libretro_path).unwrap();
|
std::fs::copy(core_path.as_ref(), &libretro_path).unwrap();
|
||||||
|
|
||||||
let lib = libloading::Library::new(&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 retro = LibretroWrapper::from(raw_retro);
|
||||||
|
|
||||||
let emu = RetroComponentBase {
|
let emu = RetroComponentBase {
|
||||||
|
@ -90,7 +100,7 @@ impl RetroComponentBase {
|
||||||
cached_memory_map: None,
|
cached_memory_map: None,
|
||||||
cached_geometry: None,
|
cached_geometry: None,
|
||||||
handler_id: None,
|
handler_id: None,
|
||||||
_temp_dir: temp_dir,
|
_temp_dir,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut pin_emu = Box::pin(emu);
|
let mut pin_emu = Box::pin(emu);
|
||||||
|
|
Loading…
Reference in New Issue