Migrate lowest-level stuff to existing libretro-sys crate

This commit is contained in:
lif 2019-11-11 23:46:53 -08:00
parent 498c874bc7
commit 2a8b3f350a
6 changed files with 250 additions and 3504 deletions

View File

@ -5,10 +5,8 @@ authors = ["lifning <lifning+git@pm.me>"]
edition = "2018"
[dependencies]
libretro-sys = "^0.1"
failure = "^0.1"
libloading = "^0.5"
num_enum = "^0.4"
structopt = "^0.3"
[build-dependencies]
bindgen = "^0.51" # keep an eye on https://github.com/rust-lang/rust-bindgen/issues/1541

View File

@ -1,29 +0,0 @@
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_ffi.rs"))
.expect("Couldn't write bindings!");
}

View File

@ -5,106 +5,104 @@ use std::path::PathBuf;
use num_enum::{TryFromPrimitive, IntoPrimitive};
use crate::libretro_ffi::*;
/*
#[derive(TryFromPrimitive, IntoPrimitive)]
#[repr(u32)]
pub enum Region {
NTSC = RETRO_REGION_NTSC,
PAL = RETRO_REGION_PAL,
}
*/
#[derive(TryFromPrimitive, IntoPrimitive)]
#[repr(u32)]
pub enum DeviceType {
None = RETRO_DEVICE_NONE,
Joypad = RETRO_DEVICE_JOYPAD,
Mouse = RETRO_DEVICE_MOUSE,
Keyboard = RETRO_DEVICE_KEYBOARD,
LightGun = RETRO_DEVICE_LIGHTGUN,
Analog = RETRO_DEVICE_ANALOG,
Pointer = RETRO_DEVICE_POINTER,
None = DEVICE_NONE,
Joypad = DEVICE_JOYPAD,
Mouse = DEVICE_MOUSE,
Keyboard = DEVICE_KEYBOARD,
LightGun = DEVICE_LIGHTGUN,
Analog = DEVICE_ANALOG,
Pointer = DEVICE_POINTER,
}
#[derive(TryFromPrimitive, IntoPrimitive)]
#[repr(u32)]
pub enum DeviceIndex {
Left = RETRO_DEVICE_INDEX_ANALOG_LEFT,
Right = RETRO_DEVICE_INDEX_ANALOG_RIGHT,
Button = RETRO_DEVICE_INDEX_ANALOG_BUTTON,
Left = DEVICE_INDEX_ANALOG_LEFT,
Right = DEVICE_INDEX_ANALOG_RIGHT,
// Button = DEVICE_INDEX_ANALOG_BUTTON,
}
#[derive(TryFromPrimitive, IntoPrimitive)]
#[repr(u32)]
pub enum JoypadButton {
B = RETRO_DEVICE_ID_JOYPAD_B,
Y = RETRO_DEVICE_ID_JOYPAD_Y,
Select = RETRO_DEVICE_ID_JOYPAD_SELECT,
Start = RETRO_DEVICE_ID_JOYPAD_START,
Up = RETRO_DEVICE_ID_JOYPAD_UP,
Down = RETRO_DEVICE_ID_JOYPAD_DOWN,
Left = RETRO_DEVICE_ID_JOYPAD_LEFT,
Right = RETRO_DEVICE_ID_JOYPAD_RIGHT,
A = RETRO_DEVICE_ID_JOYPAD_A,
X = RETRO_DEVICE_ID_JOYPAD_X,
L = RETRO_DEVICE_ID_JOYPAD_L,
R = RETRO_DEVICE_ID_JOYPAD_R,
L2 = RETRO_DEVICE_ID_JOYPAD_L2,
R2 = RETRO_DEVICE_ID_JOYPAD_R2,
L3 = RETRO_DEVICE_ID_JOYPAD_L3,
R3 = RETRO_DEVICE_ID_JOYPAD_R3,
B = DEVICE_ID_JOYPAD_B,
Y = DEVICE_ID_JOYPAD_Y,
Select = DEVICE_ID_JOYPAD_SELECT,
Start = DEVICE_ID_JOYPAD_START,
Up = DEVICE_ID_JOYPAD_UP,
Down = DEVICE_ID_JOYPAD_DOWN,
Left = DEVICE_ID_JOYPAD_LEFT,
Right = DEVICE_ID_JOYPAD_RIGHT,
A = DEVICE_ID_JOYPAD_A,
X = DEVICE_ID_JOYPAD_X,
L = DEVICE_ID_JOYPAD_L,
R = DEVICE_ID_JOYPAD_R,
L2 = DEVICE_ID_JOYPAD_L2,
R2 = DEVICE_ID_JOYPAD_R2,
L3 = DEVICE_ID_JOYPAD_L3,
R3 = DEVICE_ID_JOYPAD_R3,
}
#[derive(TryFromPrimitive, IntoPrimitive)]
#[repr(u32)]
pub enum AnalogAxis {
X = RETRO_DEVICE_ID_ANALOG_X,
Y = RETRO_DEVICE_ID_ANALOG_Y,
X = DEVICE_ID_ANALOG_X,
Y = DEVICE_ID_ANALOG_Y,
}
#[derive(TryFromPrimitive, IntoPrimitive)]
#[repr(u32)]
pub enum MouseButton {
X = RETRO_DEVICE_ID_MOUSE_X,
Y = RETRO_DEVICE_ID_MOUSE_Y,
Left = RETRO_DEVICE_ID_MOUSE_LEFT,
Right = RETRO_DEVICE_ID_MOUSE_RIGHT,
WheelUp = RETRO_DEVICE_ID_MOUSE_WHEELUP,
WheelDown = RETRO_DEVICE_ID_MOUSE_WHEELDOWN,
Middle = RETRO_DEVICE_ID_MOUSE_MIDDLE,
HorizWheelUp = RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELUP,
HorizWheelDown = RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELDOWN,
Button4 = RETRO_DEVICE_ID_MOUSE_BUTTON_4,
Button5 = RETRO_DEVICE_ID_MOUSE_BUTTON_5,
X = DEVICE_ID_MOUSE_X,
Y = DEVICE_ID_MOUSE_Y,
Left = DEVICE_ID_MOUSE_LEFT,
Right = DEVICE_ID_MOUSE_RIGHT,
WheelUp = DEVICE_ID_MOUSE_WHEELUP,
WheelDown = DEVICE_ID_MOUSE_WHEELDOWN,
Middle = DEVICE_ID_MOUSE_MIDDLE,
HorizWheelUp = DEVICE_ID_MOUSE_HORIZ_WHEELUP,
HorizWheelDown = DEVICE_ID_MOUSE_HORIZ_WHEELDOWN,
}
#[derive(TryFromPrimitive, IntoPrimitive)]
#[repr(u32)]
pub enum LightGunButton {
ScreenX = RETRO_DEVICE_ID_LIGHTGUN_SCREEN_X,
ScreenY = RETRO_DEVICE_ID_LIGHTGUN_SCREEN_Y,
IsOffscreen = RETRO_DEVICE_ID_LIGHTGUN_IS_OFFSCREEN,
Trigger = RETRO_DEVICE_ID_LIGHTGUN_TRIGGER,
Reload = RETRO_DEVICE_ID_LIGHTGUN_RELOAD,
Start = RETRO_DEVICE_ID_LIGHTGUN_START,
Select = RETRO_DEVICE_ID_LIGHTGUN_SELECT,
AuxC = RETRO_DEVICE_ID_LIGHTGUN_AUX_C,
DpadUp = RETRO_DEVICE_ID_LIGHTGUN_DPAD_UP,
DpadDown = RETRO_DEVICE_ID_LIGHTGUN_DPAD_DOWN,
DpadLeft = RETRO_DEVICE_ID_LIGHTGUN_DPAD_LEFT,
DpadRight = RETRO_DEVICE_ID_LIGHTGUN_DPAD_RIGHT,
X = RETRO_DEVICE_ID_LIGHTGUN_X,
Y = RETRO_DEVICE_ID_LIGHTGUN_Y,
Cursor = RETRO_DEVICE_ID_LIGHTGUN_CURSOR,
Turbo = RETRO_DEVICE_ID_LIGHTGUN_TURBO,
Pause = RETRO_DEVICE_ID_LIGHTGUN_PAUSE,
// ScreenX = DEVICE_ID_LIGHTGUN_SCREEN_X,
// ScreenY = DEVICE_ID_LIGHTGUN_SCREEN_Y,
// IsOffscreen = DEVICE_ID_LIGHTGUN_IS_OFFSCREEN,
Trigger = DEVICE_ID_LIGHTGUN_TRIGGER,
// Reload = DEVICE_ID_LIGHTGUN_RELOAD,
Start = DEVICE_ID_LIGHTGUN_START,
// Select = DEVICE_ID_LIGHTGUN_SELECT,
// AuxC = DEVICE_ID_LIGHTGUN_AUX_C,
// DpadUp = DEVICE_ID_LIGHTGUN_DPAD_UP,
// DpadDown = DEVICE_ID_LIGHTGUN_DPAD_DOWN,
// DpadLeft = DEVICE_ID_LIGHTGUN_DPAD_LEFT,
// DpadRight = DEVICE_ID_LIGHTGUN_DPAD_RIGHT,
X = DEVICE_ID_LIGHTGUN_X,
Y = DEVICE_ID_LIGHTGUN_Y,
Cursor = DEVICE_ID_LIGHTGUN_CURSOR,
Turbo = DEVICE_ID_LIGHTGUN_TURBO,
Pause = DEVICE_ID_LIGHTGUN_PAUSE,
}
#[derive(TryFromPrimitive, IntoPrimitive)]
#[repr(u32)]
pub enum PointerStat {
X = RETRO_DEVICE_ID_POINTER_X,
Y = RETRO_DEVICE_ID_POINTER_Y,
Pressed = RETRO_DEVICE_ID_POINTER_PRESSED,
X = DEVICE_ID_POINTER_X,
Y = DEVICE_ID_POINTER_Y,
Pressed = DEVICE_ID_POINTER_PRESSED,
}
pub enum Input {
@ -145,7 +143,7 @@ pub enum EnvRotation {
CounterClockwise180 = 2,
CounterClockwise270 = 3,
}
/*
#[derive(TryFromPrimitive, IntoPrimitive)]
#[repr(u32)]
pub enum EnvPixelFormat {
@ -154,14 +152,14 @@ pub enum EnvPixelFormat {
XRGB8888 = retro_pixel_format_RETRO_PIXEL_FORMAT_XRGB8888,
Unknown = retro_pixel_format_RETRO_PIXEL_FORMAT_UNKNOWN,
}
*/
pub struct EnvVariable {
key: &'static str,
description: &'static str,
expected_values: Vec<&'static str>,
value: Option<String>,
}
/*
#[derive(TryFromPrimitive, IntoPrimitive)]
#[repr(u32)]
pub enum EnvLanguage {
@ -185,87 +183,87 @@ pub enum EnvLanguage {
Greek = retro_language_RETRO_LANGUAGE_GREEK,
Last = retro_language_RETRO_LANGUAGE_LAST,
}
*/
// TODO: experimental calls
#[derive(TryFromPrimitive, IntoPrimitive)]
#[repr(u32)]
pub enum EnvironmentCmdData {
SetRotation = RETRO_ENVIRONMENT_SET_ROTATION,
GetOverscan = RETRO_ENVIRONMENT_GET_OVERSCAN,
GetCanDupe = RETRO_ENVIRONMENT_GET_CAN_DUPE,
SetMessage = RETRO_ENVIRONMENT_SET_MESSAGE,
Shutdown = RETRO_ENVIRONMENT_SHUTDOWN,
SetPerformanceLevel = RETRO_ENVIRONMENT_SET_PERFORMANCE_LEVEL,
GetSystemDirectory = RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY,
SetPixelFormat = RETRO_ENVIRONMENT_SET_PIXEL_FORMAT,
SetInputDescriptors = RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS,
SetKeyboardCallback = RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK,
SetDiskControlInterface = RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE,
SetHwRender = RETRO_ENVIRONMENT_SET_HW_RENDER,
GetVariable = RETRO_ENVIRONMENT_GET_VARIABLE,
SetVariables = RETRO_ENVIRONMENT_SET_VARIABLES,
GetVariableUpdate = RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE,
SetSupportNoGame = RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME,
GetLibretroPath = RETRO_ENVIRONMENT_GET_LIBRETRO_PATH,
SetFrameTimeCallback = RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK,
SetAudioCallback = RETRO_ENVIRONMENT_SET_AUDIO_CALLBACK,
GetRumbleInterface = RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE,
GetInputDeviceCapabilities = RETRO_ENVIRONMENT_GET_INPUT_DEVICE_CAPABILITIES,
GetSensorInterface = RETRO_ENVIRONMENT_GET_SENSOR_INTERFACE,
GetCameraInterface = RETRO_ENVIRONMENT_GET_CAMERA_INTERFACE,
GetLogInterface = RETRO_ENVIRONMENT_GET_LOG_INTERFACE,
GetPerfInterface = RETRO_ENVIRONMENT_GET_PERF_INTERFACE,
GetLocationInterface = RETRO_ENVIRONMENT_GET_LOCATION_INTERFACE,
GetCoreAssetsDirectory = RETRO_ENVIRONMENT_GET_CORE_ASSETS_DIRECTORY,
GetSaveDirectory = RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY,
SetSystemAvInfo = RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO,
SetProcAddressCallback = RETRO_ENVIRONMENT_SET_PROC_ADDRESS_CALLBACK,
SetSubsystemInfo = RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO,
SetControllerInfo = RETRO_ENVIRONMENT_SET_CONTROLLER_INFO,
SetMemoryMaps = RETRO_ENVIRONMENT_SET_MEMORY_MAPS,
SetGeometry = RETRO_ENVIRONMENT_SET_GEOMETRY,
GetUsername = RETRO_ENVIRONMENT_GET_USERNAME,
GetLanguage = RETRO_ENVIRONMENT_GET_LANGUAGE,
SetSerializationQuirks = RETRO_ENVIRONMENT_SET_SERIALIZATION_QUIRKS,
pub enum EnvCmd {
SetRotation = ENVIRONMENT_SET_ROTATION,
GetOverscan = ENVIRONMENT_GET_OVERSCAN,
GetCanDupe = ENVIRONMENT_GET_CAN_DUPE,
SetMessage = ENVIRONMENT_SET_MESSAGE,
Shutdown = ENVIRONMENT_SHUTDOWN,
SetPerformanceLevel = ENVIRONMENT_SET_PERFORMANCE_LEVEL,
GetSystemDirectory = ENVIRONMENT_GET_SYSTEM_DIRECTORY,
SetPixelFormat = ENVIRONMENT_SET_PIXEL_FORMAT,
SetInputDescriptors = ENVIRONMENT_SET_INPUT_DESCRIPTORS,
SetKeyboardCallback = ENVIRONMENT_SET_KEYBOARD_CALLBACK,
SetDiskControlInterface = ENVIRONMENT_SET_DISK_CONTROL_INTERFACE,
SetHwRender = ENVIRONMENT_SET_HW_RENDER,
GetVariable = ENVIRONMENT_GET_VARIABLE,
SetVariables = ENVIRONMENT_SET_VARIABLES,
GetVariableUpdate = ENVIRONMENT_GET_VARIABLE_UPDATE,
SetSupportNoGame = ENVIRONMENT_SET_SUPPORT_NO_GAME,
GetLibretroPath = ENVIRONMENT_GET_LIBRETRO_PATH,
SetFrameTimeCallback = ENVIRONMENT_SET_FRAME_TIME_CALLBACK,
SetAudioCallback = ENVIRONMENT_SET_AUDIO_CALLBACK,
GetRumbleInterface = ENVIRONMENT_GET_RUMBLE_INTERFACE,
GetInputDeviceCapabilities = ENVIRONMENT_GET_INPUT_DEVICE_CAPABILITIES,
GetSensorInterface = ENVIRONMENT_GET_SENSOR_INTERFACE,
GetCameraInterface = ENVIRONMENT_GET_CAMERA_INTERFACE,
GetLogInterface = ENVIRONMENT_GET_LOG_INTERFACE,
GetPerfInterface = ENVIRONMENT_GET_PERF_INTERFACE,
GetLocationInterface = ENVIRONMENT_GET_LOCATION_INTERFACE,
GetCoreAssetsDirectory = ENVIRONMENT_GET_CORE_ASSETS_DIRECTORY,
GetSaveDirectory = ENVIRONMENT_GET_SAVE_DIRECTORY,
SetSystemAvInfo = ENVIRONMENT_SET_SYSTEM_AV_INFO,
SetProcAddressCallback = ENVIRONMENT_SET_PROC_ADDRESS_CALLBACK,
SetSubsystemInfo = ENVIRONMENT_SET_SUBSYSTEM_INFO,
SetControllerInfo = ENVIRONMENT_SET_CONTROLLER_INFO,
SetMemoryMaps = ENVIRONMENT_SET_MEMORY_MAPS,
SetGeometry = ENVIRONMENT_SET_GEOMETRY,
GetUsername = ENVIRONMENT_GET_USERNAME,
GetLanguage = ENVIRONMENT_GET_LANGUAGE,
// SetSerializationQuirks = ENVIRONMENT_SET_SERIALIZATION_QUIRKS,
}
pub trait HandlesEnvironment: Send + Sync + 'static {
fn set_rotation(&mut self, rotation: EnvRotation) -> bool { false }
fn get_overscan(&mut self) -> Option<bool> { None }
fn get_can_dupe(&mut self) -> Option<bool> { None }
fn set_message(&mut self, message: retro_message) -> bool { false }
fn set_message(&mut self, message: Message) -> bool { false }
fn shutdown(&mut self) -> bool { false }
fn set_performance_level(&mut self, level: c_uint) -> bool { false }
fn get_system_directory(&mut self) -> Option<PathBuf> { None }
fn set_pixel_format(&mut self, format: EnvPixelFormat) -> bool { false }
fn set_input_descriptors(&mut self, input_descriptors: &[retro_input_descriptor]) -> bool { false }
fn set_keyboard_callback(&mut self, cb: retro_keyboard_callback) -> bool { false }
fn set_disk_control_interface(&mut self, cb: retro_disk_control_callback) -> bool { false }
fn set_hw_render(&mut self, hw_render_callback: retro_hw_render_callback) -> bool { false }
fn set_pixel_format(&mut self, format: PixelFormat) -> bool { false }
fn set_input_descriptors(&mut self, input_descriptors: &[InputDescriptor]) -> bool { false }
fn set_keyboard_callback(&mut self, cb: KeyboardCallback) -> bool { false }
fn set_disk_control_interface(&mut self, cb: DiskControlCallback) -> bool { false }
fn set_hw_render(&mut self, hw_render_callback: HwRenderCallback) -> bool { false }
fn get_variable(&mut self) -> Option<EnvVariable> { None }
fn set_variables(&mut self, variables: &[EnvVariable]) -> bool { false }
fn get_variable_update(&mut self) -> Option<bool> { None }
fn set_support_no_game(&mut self, supports_no_game: bool) -> bool { false }
fn get_libretro_path(&mut self) -> Option<PathBuf> { None }
fn set_frame_time_callback(&mut self, cb: retro_frame_time_callback) -> bool { false }
fn set_audio_callback(&mut self, audio_callback: retro_audio_callback) -> bool { false }
fn get_rumble_interface(&mut self) -> Option<retro_rumble_interface> { None }
fn set_frame_time_callback(&mut self, cb: FrameTimeCallback) -> bool { false }
fn set_audio_callback(&mut self, audio_callback: AudioCallback) -> bool { false }
fn get_rumble_interface(&mut self) -> Option<RumbleInterface> { None }
fn get_input_device_capabilities(&mut self) -> Option<u64> { None }
fn get_sensor_interface(&mut self) -> Option<retro_sensor_interface> { None }
fn get_camera_interface(&mut self) -> Option<retro_camera_callback> { None }
fn get_log_interface(&mut self) -> Option<retro_log_callback> { None }
fn get_perf_interface(&mut self) -> Option<retro_perf_callback> { None }
fn get_location_interface(&mut self) -> Option<retro_location_callback> { None }
fn get_sensor_interface(&mut self) -> Option<SensorInterface> { None }
fn get_camera_interface(&mut self) -> Option<CameraCallback> { None }
fn get_log_interface(&mut self) -> Option<LogCallback> { None }
fn get_perf_interface(&mut self) -> Option<PerfCallback> { None }
fn get_location_interface(&mut self) -> Option<LocationCallback> { None }
fn get_core_assets_directory(&mut self) -> Option<PathBuf> { None }
fn get_save_directory(&mut self) -> Option<PathBuf> { None }
fn set_system_av_info(&mut self, system_av_info: retro_system_av_info) -> bool { false }
fn set_proc_address_callback(&mut self, cb: retro_get_proc_address_interface) -> bool { false }
fn set_subsystem_info(&mut self, subsystem_info: retro_subsystem_info) -> bool { false }
fn set_controller_info(&mut self, controller_info: retro_controller_info) -> bool { false }
fn set_memory_maps(&mut self, memory_map: retro_memory_map) -> bool { false }
fn set_geometry(&mut self, game_geometry: retro_game_geometry) -> bool { false }
fn set_system_av_info(&mut self, system_av_info: SystemAvInfo) -> bool { false }
fn set_proc_address_callback(&mut self, cb: GetProcAddressInterface) -> bool { false }
fn set_subsystem_info(&mut self, subsystem_info: SubsystemInfo) -> bool { false }
fn set_controller_info(&mut self, controller_info: ControllerInfo) -> bool { false }
fn set_memory_maps(&mut self, memory_map: MemoryMap) -> bool { false }
fn set_geometry(&mut self, game_geometry: GameGeometry) -> bool { false }
fn get_username(&mut self) -> Option<String> { None }
fn get_language(&mut self) -> Option<EnvLanguage> { None }
fn get_language(&mut self) -> Option<Language> { None }
fn set_serialization_quirks(&mut self, quirks: &mut u64) -> bool { false }
}

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
use std::convert::TryInto;
use std::os::raw::{c_char, c_uint, c_void};
use std::os::raw::{c_char, c_void};
use std::path::Path;
use failure::Fallible;
@ -9,125 +9,82 @@ use crate::libretro_ffi::*;
use crate::libretro_convert::*;
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>,
lib: &'a libloading::Library, // for tying our lifetime to its own
pub core_api: CoreAPI,
}
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")?,
lib,
core_api: CoreAPI {
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")?,
}
})
}
}
/// set_environment() must be called before init().
pub fn set_environment(&self, cb: retro_environment_t) {
unsafe { (&self.retro_set_environment)(cb) }
pub fn set_environment(&self, cb: EnvironmentFn) {
unsafe { (&self.core_api.retro_set_environment)(cb) }
}
/// video_refresh() must be called before run().
pub fn set_video_refresh(&self, cb: retro_video_refresh_t) {
unsafe { (&self.retro_set_video_refresh)(cb) }
pub fn set_video_refresh(&self, cb: VideoRefreshFn) {
unsafe { (&self.core_api.retro_set_video_refresh)(cb) }
}
pub fn set_audio_sample(&self, cb: retro_audio_sample_t) {
unsafe { (&self.retro_set_audio_sample)(cb) }
pub fn set_audio_sample(&self, cb: AudioSampleFn) {
unsafe { (&self.core_api.retro_set_audio_sample)(cb) }
}
pub fn set_audio_sample_batch(&self, cb: retro_audio_sample_batch_t) {
unsafe { (&self.retro_set_audio_sample_batch)(cb) }
pub fn set_audio_sample_batch(&self, cb: AudioSampleBatchFn) {
unsafe { (&self.core_api.retro_set_audio_sample_batch)(cb) }
}
pub fn set_input_poll(&self, cb: retro_input_poll_t) {
unsafe { (&self.retro_set_input_poll)(cb) }
pub fn set_input_poll(&self, cb: InputPollFn) {
unsafe { (&self.core_api.retro_set_input_poll)(cb) }
}
pub fn set_input_state(&self, cb: retro_input_state_t) {
unsafe { (&self.retro_set_input_state)(cb) }
pub fn set_input_state(&self, cb: InputStateFn) {
unsafe { (&self.core_api.retro_set_input_state)(cb) }
}
/// set_environment() must be called before init().
pub fn init(&self) {
// TODO assert!(called retro_set_environment);
unsafe { (&self.retro_init)() }
unsafe { (&self.core_api.retro_init)() }
}
pub fn deinit(&self) {
unsafe { (&self.retro_deinit)() }
unsafe { (&self.core_api.retro_deinit)() }
}
/// Must return RETRO_API_VERSION. Used to validate ABI compatibility when the API is revised.
pub fn api_version(&self) -> u32 {
unsafe { (&self.retro_api_version)() as u32 }
unsafe { (&self.core_api.retro_api_version)() as u32 }
}
/// Gets statically known system info. Can be called at any time, even before retro_init().
pub fn get_system_info(&self) -> retro_system_info {
pub fn get_system_info(&self) -> SystemInfo {
unsafe {
let mut info = ::std::mem::zeroed::<retro_system_info>();
(&self.retro_get_system_info)(&mut info);
let mut info = ::std::mem::zeroed::<SystemInfo>();
(&self.core_api.retro_get_system_info)(&mut info);
info
}
}
@ -136,10 +93,10 @@ impl<'a> LibretroApi<'a> {
* 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 {
pub fn get_system_av_info(&self) -> SystemAvInfo {
unsafe {
let mut av_info = ::std::mem::zeroed::<retro_system_av_info>();
(&self.retro_get_system_av_info)(&mut av_info);
let mut av_info = ::std::mem::zeroed::<SystemAvInfo>();
(&self.core_api.retro_get_system_av_info)(&mut av_info);
av_info
}
}
@ -158,11 +115,11 @@ impl<'a> LibretroApi<'a> {
* result of changing the device type.
*/
pub fn set_controller_port_device(&self, port: u32, device: u32) {
unsafe { (&self.retro_set_controller_port_device)(port, device) }
unsafe { (&self.core_api.retro_set_controller_port_device)(port, device) }
}
/// Resets the current game.
pub fn reset(&self) {
unsafe { (&self.retro_reset)() }
unsafe { (&self.core_api.retro_reset)() }
}
/** Runs the game for one video frame.
* During retro_run(), input_poll callback must be called at least once.
@ -173,31 +130,32 @@ impl<'a> LibretroApi<'a> {
* In this case, the video callback can take a NULL argument for data.
*/
pub fn run(&self) {
unsafe { (&self.retro_run)() }
unsafe { (&self.core_api.retro_run)() }
}
/// Serializes internal state.
pub fn serialize(&self) -> Fallible<Vec<u8>> {
let size = unsafe { (&self.retro_serialize_size)() };
let size = unsafe { (&self.core_api.retro_serialize_size)() };
let mut vec = Vec::with_capacity(size);
vec.resize(size, 0);
if unsafe { (&self.retro_serialize)(vec.as_mut_ptr() as *mut c_void, size) } {
// FIXME: libretro-sys incorrectly says retro_serialize is a void(), not a bool()
if unsafe { (&self.core_api.retro_serialize)(vec.as_mut_ptr() as *mut c_void, size); true } {
Ok(vec)
} else {
Err(failure::err_msg("Serialize failed"))
}
}
pub fn unserialize(&self, data: &[u8]) -> Fallible<()> {
if unsafe { (&self.retro_unserialize)(data.as_ptr() as *const c_void, data.len()) } {
if unsafe { (&self.core_api.retro_unserialize)(data.as_ptr() as *const c_void, data.len()) } {
Ok(())
} else {
Err(failure::err_msg("Unserialize failed"))
}
}
pub fn cheat_reset(&self) {
unsafe { (&self.retro_cheat_reset)() }
unsafe { (&self.core_api.retro_cheat_reset)() }
}
pub fn cheat_set(&self, index: u32, enabled: bool, code: &str) {
unsafe { (&self.retro_cheat_set)(index, enabled, code.as_bytes().as_ptr() as *const c_char) }
unsafe { (&self.core_api.retro_cheat_set)(index, enabled, code.as_bytes().as_ptr() as *const c_char) }
}
/// Loads a game.
pub fn load_game(
@ -206,7 +164,7 @@ impl<'a> LibretroApi<'a> {
data: Option<&[u8]>,
meta: Option<&str>,
) -> Fallible<()> {
let mut game = retro_game_info {
let mut game = GameInfo {
path: std::ptr::null(),
data: std::ptr::null(),
size: 0,
@ -223,7 +181,7 @@ impl<'a> LibretroApi<'a> {
game.meta = m.as_bytes().as_ptr() as *const c_char;
}
if unsafe { (&self.retro_load_game)(&game) } {
if unsafe { (&self.core_api.retro_load_game)(&game) } {
Ok(())
} else {
Err(failure::err_msg("Failed to load game"))
@ -231,16 +189,16 @@ impl<'a> LibretroApi<'a> {
}
/// Unloads the currently loaded game. Called before deinit().
pub fn unload_game(&self) {
unsafe { (&self.retro_unload_game)() }
unsafe { (&self.core_api.retro_unload_game)() }
}
pub fn get_region(&self) -> Region {
unsafe { (&self.retro_get_region)().try_into().expect("Invalid region") }
unsafe { std::mem::transmute((&self.core_api.retro_get_region)()) }
}
/// Gets (read/write access to) a region of memory
pub fn get_memory(&self, id: u32) -> &mut [u8] {
unsafe {
let data = (&self.retro_get_memory_data)(id);
let size = (&self.retro_get_memory_size)(id);
let data = (&self.core_api.retro_get_memory_data)(id);
let size = (&self.core_api.retro_get_memory_size)(id);
std::slice::from_raw_parts_mut(data as *mut u8, size)
}
}

View File

@ -5,6 +5,8 @@ use core::slice::from_raw_parts;
use std::ffi::CString;
use std::os::raw::{c_uint, c_char};
use libretro_sys::{Message, PixelFormat, SystemAvInfo, GameGeometry};
use crate::libretro_convert::*;
use crate::libretro_loading::*;
use std::path::Path;
@ -56,43 +58,43 @@ impl StaticCallbacks {
fn environment_cb_inner(cmd: u32, data: *mut c_void) -> Option<bool> {
let mut handler = unsafe { CB_SINGLETON.environment.as_mut() }?;
match cmd.try_into().ok()? {
EnvironmentCmdData::SetRotation => handler.set_rotation(Self::enum_from_void(data)?),
EnvironmentCmdData::GetOverscan => Self::clone_into_void(data, &handler.get_overscan()?)?,
EnvironmentCmdData::GetCanDupe => Self::clone_into_void(data, &handler.get_can_dupe()?)?,
EnvironmentCmdData::SetMessage => handler.set_message(*Self::from_void(data)?),
EnvironmentCmdData::Shutdown => handler.shutdown(),
EnvironmentCmdData::SetPerformanceLevel => handler.set_performance_level(*Self::from_void(data)?),
EnvironmentCmdData::GetSystemDirectory => Self::path_into_void(data, handler.get_system_directory()?)?,
EnvironmentCmdData::SetPixelFormat => handler.set_pixel_format(Self::enum_from_void(data)?),
EnvCmd::SetRotation => handler.set_rotation(Self::enum_from_void(data)?),
EnvCmd::GetOverscan => Self::clone_into_void(data, &handler.get_overscan()?)?,
EnvCmd::GetCanDupe => Self::clone_into_void(data, &handler.get_can_dupe()?)?,
EnvCmd::SetMessage => handler.set_message(Self::from_void::<Message>(data)?.clone()),
EnvCmd::Shutdown => handler.shutdown(),
EnvCmd::SetPerformanceLevel => handler.set_performance_level(*Self::from_void(data)?),
EnvCmd::GetSystemDirectory => Self::path_into_void(data, handler.get_system_directory()?)?,
EnvCmd::SetPixelFormat => handler.set_pixel_format(PixelFormat::from_uint(*Self::from_void(data)?)?),
// TODO EnvironmentCmdData::SetInputDescriptors => {},
// TODO EnvironmentCmdData::SetKeyboardCallback => {},
// TODO EnvironmentCmdData::SetDiskControlInterface => {},
// TODO EnvironmentCmdData::SetHwRender => {},
// TODO EnvironmentCmdData::GetVariable => {}, -- also change to mut parameter?
// TODO EnvironmentCmdData::SetVariables => {},
EnvironmentCmdData::GetVariableUpdate => Self::clone_into_void(data, &handler.get_variable_update()?)?,
EnvironmentCmdData::SetSupportNoGame => handler.set_support_no_game(*Self::from_void(data)?),
EnvironmentCmdData::GetLibretroPath => Self::path_into_void(data, handler.get_libretro_path()?)?,
EnvCmd::GetVariableUpdate => Self::clone_into_void(data, &handler.get_variable_update()?)?,
EnvCmd::SetSupportNoGame => handler.set_support_no_game(*Self::from_void(data)?),
EnvCmd::GetLibretroPath => Self::path_into_void(data, handler.get_libretro_path()?)?,
// TODO EnvironmentCmdData::SetFrameTimeCallback => {},
// TODO EnvironmentCmdData::SetAudioCallback => {},
// TODO EnvironmentCmdData::GetRumbleInterface => {},
EnvironmentCmdData::GetInputDeviceCapabilities => Self::clone_into_void(data, &handler.get_input_device_capabilities()?)?,
EnvCmd::GetInputDeviceCapabilities => Self::clone_into_void(data, &handler.get_input_device_capabilities()?)?,
// TODO EnvironmentCmdData::GetSensorInterface => {},
// TODO EnvironmentCmdData::GetCameraInterface => {},
// TODO EnvironmentCmdData::GetLogInterface => {},
// TODO EnvironmentCmdData::GetPerfInterface => {},
// TODO EnvironmentCmdData::GetLocationInterface => {},
EnvironmentCmdData::GetCoreAssetsDirectory => Self::path_into_void(data, handler.get_core_assets_directory()?)?,
EnvironmentCmdData::GetSaveDirectory => Self::path_into_void(data, handler.get_save_directory()?)?,
EnvironmentCmdData::SetSystemAvInfo => handler.set_system_av_info(*Self::from_void(data)?),
EnvCmd::GetCoreAssetsDirectory => Self::path_into_void(data, handler.get_core_assets_directory()?)?,
EnvCmd::GetSaveDirectory => Self::path_into_void(data, handler.get_save_directory()?)?,
EnvCmd::SetSystemAvInfo => handler.set_system_av_info(Self::from_void::<SystemAvInfo>(data)?.clone()),
// TODO EnvironmentCmdData::SetProcAddressCallback => {},
// TODO EnvironmentCmdData::SetSubsystemInfo => {},
// TODO EnvironmentCmdData::SetControllerInfo => {},
// TODO EnvironmentCmdData::SetMemoryMaps => {},
EnvironmentCmdData::SetGeometry => handler.set_geometry(*Self::from_void(data)?),
EnvironmentCmdData::GetUsername => Self::string_into_void(data, handler.get_username()?)?,
EnvironmentCmdData::GetLanguage => Self::clone_into_void(data, &c_uint::from(handler.get_language()?))?,
EnvironmentCmdData::SetSerializationQuirks => handler.set_serialization_quirks(Self::from_void(data)?),
EnvCmd::SetGeometry => handler.set_geometry(Self::from_void::<GameGeometry>(data)?.clone()),
EnvCmd::GetUsername => Self::string_into_void(data, handler.get_username()?)?,
EnvCmd::GetLanguage => Self::clone_into_void(data, &handler.get_language()?)?,
// EnvironmentCmdData::SetSerializationQuirks => handler.set_serialization_quirks(Self::from_void(data)?),
_ => false,
}.into()
}
@ -191,12 +193,12 @@ pub struct LibretroWrapper<'a> {
impl<'a> From<LibretroApi<'a>> for LibretroWrapper<'a> {
fn from(api: LibretroApi<'a>) -> Self {
api.set_environment(Some(StaticCallbacks::environment_cb));
api.set_video_refresh(Some(StaticCallbacks::video_refresh_cb));
api.set_audio_sample(Some(StaticCallbacks::audio_sample_cb));
api.set_audio_sample_batch(Some(StaticCallbacks::audio_sample_batch_cb));
api.set_input_poll(Some(StaticCallbacks::input_poll_cb));
api.set_input_state(Some(StaticCallbacks::input_state_cb));
api.set_environment(StaticCallbacks::environment_cb);
api.set_video_refresh(StaticCallbacks::video_refresh_cb);
api.set_audio_sample(StaticCallbacks::audio_sample_cb);
api.set_audio_sample_batch(StaticCallbacks::audio_sample_batch_cb);
api.set_input_poll(StaticCallbacks::input_poll_cb);
api.set_input_state(StaticCallbacks::input_state_cb);
LibretroWrapper { api }
}
}