WIP nonfunctional SDL 2 thing

This commit is contained in:
lif 2019-11-14 21:21:58 -08:00
parent 6668c9c11f
commit 50b1649315
5 changed files with 148 additions and 69 deletions

View File

@ -10,4 +10,12 @@ failure = "^0.1"
libloading = "^0.5"
num_enum = "^0.4"
structopt = "^0.3"
sdl2 = { version = "*", optional = true }
[features]
with-sdl2 = ["sdl2"]
[[bin]]
name = "example"
path = "src/bin/example.rs"
required-features = ["with-sdl2"]

View File

@ -1,19 +1,108 @@
extern crate rustro;
extern crate sdl2;
use rustro::retro;
use rustro::retro::ffi::GameGeometry;
use std::ffi::CStr;
use std::path::PathBuf;
use std::path::{PathBuf, Path};
use std::time::Duration;
use structopt::StructOpt;
use rustro::retro;
use sdl2::render::{WindowCanvas, Texture};
use sdl2::rect::Rect;
struct Foo;
impl retro::convert::Handler for Foo {
fn video_refresh(&mut self, data: &[u8], width: u32, height: u32, pitch: u32) {
println!("video_refresh {}x{}", width, height);
struct MyEmulator {
retro: retro::wrapper::LibretroWrapper,
sdl_context: sdl2::Sdl,
video_subsystem: sdl2::VideoSubsystem,
canvas: WindowCanvas,
pixel_format: sdl2::pixels::PixelFormatEnum,
}
impl MyEmulator {
pub fn with_core(core: impl AsRef<Path>) -> Self {
let lib = libloading::Library::new(core.as_ref()).unwrap();
let raw_retro = retro::loading::LibretroApi::from_library(lib).unwrap();
let retro = retro::wrapper::LibretroWrapper::from(raw_retro);
println!("api version: {}", retro.as_ref().api_version());
println!("name: {}", unsafe { CStr::from_ptr(retro.as_ref().get_system_info().library_name) }.to_string_lossy());
let av = retro.as_ref().get_system_av_info();
let sdl_context = sdl2::init().unwrap();
let video_subsystem = sdl_context.video().unwrap();
let window = video_subsystem.window(
"rust libretro",
av.geometry.base_width,
av.geometry.base_height
).position_centered().build().unwrap();
let mut canvas = window.into_canvas().build().unwrap();
let pixel_format = sdl2::pixels::PixelFormatEnum::ABGR1555;
let mut result = MyEmulator { retro, sdl_context, video_subsystem, canvas, pixel_format };
retro::wrapper::register_handler(&mut result);
result.retro.as_ref().init();
result
}
pub fn run(&self) {
println!("run?");
self.retro.as_ref().run();
println!("run.");
}
pub fn load_game(&self, rom: impl AsRef<Path>) {
self.retro.as_ref().load_game(Some(rom.as_ref()), None, None);
}
}
impl retro::convert::Handler for MyEmulator {
fn video_refresh(&mut self, data: &[u8], width: u32, height: u32, pitch: u32) {
println!("video_refresh {}x{}", width, height);
let rect = Rect::new(0, 0, width, height);
println!("0");
let tex_creator = self.canvas.texture_creator();
println!("a");
let mut tex: Texture = tex_creator.create_texture_streaming(
self.pixel_format,
width,
height,
).unwrap();
println!("b");
tex.update(None, data, pitch as usize);
println!("c");
self.canvas.copy(&tex, rect, rect);
println!("d");
self.canvas.present();
println!("e");
}
fn set_pixel_format(&mut self, pix_fmt: retro::ffi::PixelFormat) -> bool {
self.pixel_format = match pix_fmt {
retro::ffi::PixelFormat::ARGB1555 => sdl2::pixels::PixelFormatEnum::RGB555,
retro::ffi::PixelFormat::ARGB8888 => sdl2::pixels::PixelFormatEnum::ARGB8888,
retro::ffi::PixelFormat::RGB565 => sdl2::pixels::PixelFormatEnum::RGB565,
};
true
}
}
pub fn main() {
let opt: Opt = Opt::from_args();
let mut emu = MyEmulator::with_core(&opt.core);
emu.load_game(&opt.rom);
loop {
emu.run();
::std::thread::sleep(Duration::new(0, 1_000_000_000u32 / 60));
}
}
#[derive(StructOpt)]
struct Opt {
@ -24,18 +113,3 @@ struct Opt {
#[structopt(short, long, parse(from_os_str))]
rom: PathBuf,
}
fn main() -> failure::Fallible<()> {
let opt: Opt = Opt::from_args();
let lib = libloading::Library::new(&opt.core)?;
let retro = retro::loading::LibretroApi::from_library(&lib)?;
let wrapper = retro::wrapper::LibretroWrapper::from(retro);
let mut foo = Foo{};
wrapper.register_handler(&mut foo);
println!("api version: {}", wrapper.as_ref().api_version());
println!("name: {}", unsafe { CStr::from_ptr(wrapper.as_ref().get_system_info().library_name) }.to_string_lossy());
wrapper.as_ref().init();
wrapper.as_ref().load_game(Some(&opt.rom), None, None);
wrapper.as_ref().run();
Ok(())
}

View File

@ -189,7 +189,7 @@ pub enum EnvCmd {
// SetSerializationQuirks = ENVIRONMENT_SET_SERIALIZATION_QUIRKS,
}
pub trait Handler: Send + Sync + 'static {
pub trait Handler: 'static {
fn video_refresh(&mut self, data: &[u8], width: c_uint, height: c_uint, pitch: c_uint) {}
fn audio_sample(&mut self, left: i16, right: i16) {}
fn audio_sample_batch(&mut self, stereo_pcm: &[i16]) -> usize { stereo_pcm.len() }

View File

@ -1,6 +1,7 @@
use std::convert::TryInto;
use std::os::raw::{c_char, c_void};
use std::path::Path;
use std::marker::PhantomData;
use failure::Fallible;
use libloading;
@ -8,44 +9,42 @@ use libloading;
use super::ffi::*;
use super::convert::*;
pub struct LibretroApi<'a> {
lib: &'a libloading::Library, // for tying our lifetime to its own
pub struct LibretroApi {
lib: 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> {
impl LibretroApi {
pub fn from_library(lib: libloading::Library) -> Fallible<Self> {
unsafe {
Ok(LibretroApi {
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")?,
}
})
let 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")?,
};
Ok(LibretroApi { lib, core_api })
}
}
/// set_environment() must be called before init().

View File

@ -135,7 +135,7 @@ impl StaticCallbacks {
None => 0,
}
}
pub(crate) fn set_environment(cb: &'static mut dyn Handler) {
pub(crate) fn register(cb: &'static mut dyn Handler) {
unsafe {
CB_SINGLETON.handler.replace(cb);
}
@ -147,12 +147,12 @@ impl StaticCallbacks {
}
}
pub struct LibretroWrapper<'a> {
api: LibretroApi<'a>,
pub struct LibretroWrapper {
api: LibretroApi,
}
impl<'a> From<LibretroApi<'a>> for LibretroWrapper<'a> {
fn from(api: LibretroApi<'a>) -> Self {
impl From<LibretroApi> for LibretroWrapper {
fn from(api: LibretroApi) -> Self {
api.set_environment(StaticCallbacks::environment_cb);
api.set_video_refresh(StaticCallbacks::video_refresh_cb);
api.set_audio_sample(StaticCallbacks::audio_sample_cb);
@ -163,13 +163,13 @@ impl<'a> From<LibretroApi<'a>> for LibretroWrapper<'a> {
}
}
impl<'a> AsRef<LibretroApi<'a>> for LibretroWrapper<'a> {
fn as_ref(&self) -> &LibretroApi<'a> {
impl AsRef<LibretroApi> for LibretroWrapper {
fn as_ref(&self) -> &LibretroApi {
&self.api
}
}
impl<'a> Drop for LibretroWrapper<'a> {
impl Drop for LibretroWrapper {
fn drop(&mut self) {
StaticCallbacks::reset();
}
@ -177,9 +177,7 @@ impl<'a> Drop for LibretroWrapper<'a> {
// a note on lifetimes: we explicitly lie about them here because as long as they live as long as
// the library wrapper itself we're good (we wipe our 'static references on drop() too)
impl<'a> LibretroWrapper<'a> {
pub fn register_handler(&self, handler: &'a mut dyn Handler) {
let ptr: *mut dyn Handler = handler;
StaticCallbacks::set_environment(unsafe { ptr.as_mut() }.unwrap());
}
pub fn register_handler(handler: &mut dyn Handler) {
let ptr: *mut dyn Handler = handler;
StaticCallbacks::register(unsafe { ptr.as_mut() }.unwrap());
}