initial commit

This commit is contained in:
lif 2019-11-04 00:14:16 -08:00
commit 6448c0a040
7 changed files with 5854 additions and 0 deletions

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
/target
**/*.rs.bk
/.idea
/Cargo.lock

12
Cargo.toml Normal file
View File

@ -0,0 +1,12 @@
[package]
name = "rustro"
version = "0.1.0"
authors = ["lifning <lifning+git@pm.me>"]
edition = "2018"
[dependencies]
failure = "^0.1"
libloading = "^0.5"
[build-dependencies]
bindgen = "^0.51" # keep an eye on https://github.com/rust-lang/rust-bindgen/issues/1541

29
build.rs Normal file
View File

@ -0,0 +1,29 @@
extern crate bindgen;
use std::env;
use std::path::PathBuf;
fn main() {
// Tell cargo to invalidate the built crate whenever the wrapper changes
println!("cargo:rerun-if-changed=libretro.h");
// The bindgen::Builder is the main entry point
// to bindgen, and lets you build up options for
// the resulting bindings.
let bindings = bindgen::Builder::default()
// The input header we would like to generate
// bindings for.
.header("libretro.h")
// We use libloading to dlopen() and dlsym() the cores at runtime.
.ignore_functions()
// Finish the builder and generate the bindings.
.generate()
// Unwrap the Result and panic on failure.
.expect("Unable to generate bindings");
// Write the bindings to the $OUT_DIR/bindings.rs file.
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
bindings
.write_to_file(out_path.join("libretro_types.rs"))
.expect("Couldn't write bindings!");
}

2473
libretro.h Normal file

File diff suppressed because it is too large Load Diff

103
src/libretro_loading.rs Normal file
View File

@ -0,0 +1,103 @@
use std::os::raw::{c_char, c_uint, c_void};
use failure::Fallible;
use libloading;
use crate::libretro_types::*;
pub struct LibretroApi<'a> {
pub retro_set_environment: libloading::Symbol<'a, unsafe extern "C" fn(arg1: retro_environment_t)>,
pub retro_set_video_refresh: libloading::Symbol<'a, unsafe extern "C" fn(arg1: retro_video_refresh_t)>,
pub retro_set_audio_sample: libloading::Symbol<'a, unsafe extern "C" fn(arg1: retro_audio_sample_t)>,
pub retro_set_audio_sample_batch: libloading::Symbol<'a, unsafe extern "C" fn(arg1: retro_audio_sample_batch_t)>,
pub retro_set_input_poll: libloading::Symbol<'a, unsafe extern "C" fn(arg1: retro_input_poll_t)>,
pub retro_set_input_state: libloading::Symbol<'a, unsafe extern "C" fn(arg1: retro_input_state_t)>,
pub retro_init: libloading::Symbol<'a, unsafe extern "C" fn()>,
pub retro_deinit: libloading::Symbol<'a, unsafe extern "C" fn()>,
pub retro_api_version: libloading::Symbol<'a, unsafe extern "C" fn() -> c_uint>,
pub retro_get_system_info: libloading::Symbol<'a, unsafe extern "C" fn(info: *mut retro_system_info)>,
pub retro_get_system_av_info: libloading::Symbol<'a, unsafe extern "C" fn(info: *mut retro_system_av_info)>,
pub retro_set_controller_port_device: libloading::Symbol<'a, unsafe extern "C" fn(port: c_uint, device: c_uint)>,
pub retro_reset: libloading::Symbol<'a, unsafe extern "C" fn()>,
pub retro_run: libloading::Symbol<'a, unsafe extern "C" fn()>,
pub retro_serialize_size: libloading::Symbol<'a, unsafe extern "C" fn() -> usize>,
pub retro_serialize: libloading::Symbol<'a, unsafe extern "C" fn(data: *mut c_void, size: usize) -> bool>,
pub retro_unserialize: libloading::Symbol<'a, unsafe extern "C" fn(data: *const c_void, size: usize) -> bool>,
pub retro_cheat_reset: libloading::Symbol<'a, unsafe extern "C" fn()>,
pub retro_cheat_set: libloading::Symbol<'a, unsafe extern "C" fn(index: c_uint, enabled: bool, code: *const c_char)>,
pub retro_load_game: libloading::Symbol<'a, unsafe extern "C" fn(game: *const retro_game_info) -> bool>,
pub retro_load_game_special: libloading::Symbol<'a, unsafe extern "C" fn(game_type: c_uint, info: *const retro_game_info, num_info: usize) -> bool>,
pub retro_unload_game: libloading::Symbol<'a, unsafe extern "C" fn()>,
pub retro_get_region: libloading::Symbol<'a, unsafe extern "C" fn() -> c_uint>,
pub retro_get_memory_data: libloading::Symbol<'a, unsafe extern "C" fn(id: c_uint) -> *mut c_void>,
pub retro_get_memory_size: libloading::Symbol<'a, unsafe extern "C" fn(id: c_uint) -> usize>,
}
impl<'a> LibretroApi<'a> {
pub fn from_library(lib: &'a libloading::Library) -> Fallible<Self> {
unsafe {
Ok(LibretroApi {
retro_set_environment: lib.get(b"retro_set_environment")?,
retro_set_video_refresh: lib.get(b"retro_set_video_refresh")?,
retro_set_audio_sample: lib.get(b"retro_set_audio_sample")?,
retro_set_audio_sample_batch: lib.get(b"retro_set_audio_sample_batch")?,
retro_set_input_poll: lib.get(b"retro_set_input_poll")?,
retro_set_input_state: lib.get(b"retro_set_input_state")?,
retro_init: lib.get(b"retro_init")?,
retro_deinit: lib.get(b"retro_deinit")?,
retro_api_version: lib.get(b"retro_api_version")?,
retro_get_system_info: lib.get(b"retro_get_system_info")?,
retro_get_system_av_info: lib.get(b"retro_get_system_av_info")?,
retro_set_controller_port_device: lib.get(b"retro_set_controller_port_device")?,
retro_reset: lib.get(b"retro_reset")?,
retro_run: lib.get(b"retro_run")?,
retro_serialize_size: lib.get(b"retro_serialize_size")?,
retro_serialize: lib.get(b"retro_serialize")?,
retro_unserialize: lib.get(b"retro_unserialize")?,
retro_cheat_reset: lib.get(b"retro_cheat_reset")?,
retro_cheat_set: lib.get(b"retro_cheat_set")?,
retro_load_game: lib.get(b"retro_load_game")?,
retro_load_game_special: lib.get(b"retro_load_game_special")?,
retro_unload_game: lib.get(b"retro_unload_game")?,
retro_get_region: lib.get(b"retro_get_region")?,
retro_get_memory_data: lib.get(b"retro_get_memory_data")?,
retro_get_memory_size: lib.get(b"retro_get_memory_size")?,
})
}
}
/// retro_set_environment() must be called before retro_init().
pub fn init(&self) {
unsafe {
// TODO assert!(called retro_set_environment);
(&self.retro_init)();
}
}
/// retro_set_environment() must be called before retro_init().
pub fn retro_set_environment(&self, env: retro_environment_t) {
unsafe {
(&self.retro_set_environment)(env);
}
}
/** Gets statically known system info.
* Can be called at any time, even before retro_init(). */
pub fn get_system_info(&self) -> retro_system_info {
unsafe {
let mut info = ::std::mem::zeroed::<retro_system_info>();
(&self.retro_get_system_info)(&mut info);
info
}
}
/** Gets information about system audio/video timings and geometry.
* Can be called only after retro_load_game() has successfully completed.
* NOTE: The implementation of this function might not initialize every
* variable if needed.
* E.g. geom.aspect_ratio might not be initialized if core doesn't
* desire a particular aspect ratio. */
pub fn get_system_av_info(&self) -> retro_system_av_info {
unsafe {
let mut av_info = ::std::mem::zeroed::<retro_system_av_info>();
(&self.retro_get_system_av_info)(&mut av_info);
av_info
}
}
}

3215
src/libretro_types.rs Normal file

File diff suppressed because it is too large Load Diff

18
src/main.rs Normal file
View File

@ -0,0 +1,18 @@
extern crate failure;
extern crate libloading;
use std::ffi::CStr;
#[allow(non_camel_case_types, non_upper_case_globals, non_snake_case, dead_code)]
mod libretro_types;
mod libretro_loading;
fn main() -> failure::Fallible<()> {
let lib = libloading::Library::new("/home/lifning/.config/retroarch/cores/gambatte_libretro.so")?;
let retro = libretro_loading::LibretroApi::from_library(&lib)?;
unsafe {
println!("api version: {}", (&retro.retro_api_version)());
println!("name: {}", CStr::from_ptr(retro.get_system_info().library_name).to_string_lossy());
}
Ok(())
}