working sdl2 example, albeit messy

This commit is contained in:
lif 2019-11-15 20:59:08 -08:00
parent d3f83c48c1
commit e183627018
4 changed files with 38 additions and 46 deletions

View File

@ -6,8 +6,12 @@ use rustro::retro::ffi::GameGeometry;
use rustro::retro::ffi::SystemAvInfo;
use std::ffi::CStr;
use std::io::Write;
use std::ops::Deref;
use std::path::{PathBuf, Path};
use std::time::Duration;
use std::pin::Pin;
use std::thread::sleep;
use std::time::{Duration, Instant};
use structopt::StructOpt;
@ -16,7 +20,6 @@ use sdl2::rect::Rect;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::video::WindowContext;
use std::io::Write;
struct MyEmulator {
retro: retro::wrapper::LibretroWrapper,
@ -26,7 +29,7 @@ struct MyEmulator {
}
impl MyEmulator {
pub fn with_core(core: impl AsRef<Path>) -> Self {
pub fn with_core(core: impl AsRef<Path>) -> Pin<Box<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);
@ -36,11 +39,12 @@ impl MyEmulator {
let av_info = retro.as_ref().get_system_av_info();
let pixel_format = sdl2::pixels::PixelFormatEnum::ABGR1555;
let mut result = MyEmulator { retro, av_info, pixel_format, texture: None };
let mut emu = MyEmulator { retro, av_info, pixel_format, texture: None };
let mut pin_emu = Box::pin(emu);
retro::wrapper::register_handler(&mut result);
result.retro.as_ref().init();
result
retro::wrapper::register_handler(pin_emu.as_mut());
pin_emu.retro.as_ref().init();
pin_emu
}
pub fn run(&self) {
@ -58,20 +62,9 @@ impl MyEmulator {
impl retro::convert::Handler for MyEmulator {
fn video_refresh(&mut self, data: &[u8], width: u32, height: u32, pitch: u32) {
println!("self ref: {:?}", self as *mut Self);
//println!("video_refresh {}x{}", width, height);
//let rect = Rect::new(0, 0, width, height);
let rect = Rect::new(0, 0, width, height);
if let Some(tex) = self.texture.as_mut() {
tex.with_lock(None, |tex_buffer: &mut [u8], tex_pitch: usize| {
let src_pitch = pitch as usize;
let src_width = width as usize;
for y in 0..(height as usize) {
let src_slice = (y * src_pitch)..((y * src_pitch) + src_width);
let tex_slice = (y * tex_pitch)..((y * tex_pitch) + src_width);
tex_buffer[tex_slice].copy_from_slice(&data[src_slice]);
}
}).unwrap();
//tex.update(None, data, pitch as usize).unwrap();
tex.update(rect, data, pitch as usize).unwrap();
}
}
@ -85,6 +78,14 @@ impl retro::convert::Handler for MyEmulator {
}
}
impl Drop for MyEmulator {
fn drop(&mut self) {
if let Some(x) = self.texture.take() {
unsafe { x.destroy(); }
}
}
}
pub fn main() -> failure::Fallible<()> {
let opt: Opt = Opt::from_args();
let mut emu = MyEmulator::with_core(&opt.core);
@ -102,11 +103,12 @@ pub fn main() -> failure::Fallible<()> {
let texture_creator = canvas.texture_creator();
emu.texture = texture_creator.create_texture_streaming(emu.pixel_format, width, height).ok();
let mut x: u8 = 1;
println!("emu ref: {:?}", &emu as *const MyEmulator);
let target_frame_time = Duration::from_secs_f64(1.0 / emu.av_info.timing.fps);
let mut event_pump = sdl_context.event_pump().map_err(failure::err_msg)?;
'running: loop {
let frame_begin = Instant::now();
for event in event_pump.poll_iter() {
match event {
Event::Quit {..}
@ -116,22 +118,14 @@ pub fn main() -> failure::Fallible<()> {
_ => {}
}
}
if let Some(tex) = emu.texture.as_mut() {
tex.with_lock(None, |tex_buffer: &mut [u8], tex_pitch: usize| {
for i in 0..tex_buffer.len() {
tex_buffer[i] = x;
x = (x + 1) % 255;
}
}).unwrap();
//tex.update(None, data, pitch as usize).unwrap();
}
// The rest of the game loop goes here...
emu.run();
canvas.clear();
canvas.copy(emu.texture.as_ref().unwrap(), None, Some(Rect::new(0, 0, width, height))).map_err(failure::err_msg)?;
canvas.present();
::std::thread::sleep(Duration::new(0, 1_000_000_000u32 / 60));
target_frame_time.checked_sub(frame_begin.elapsed()).map(sleep);
}
Ok(())
}

View File

@ -189,7 +189,7 @@ pub enum EnvCmd {
// SetSerializationQuirks = ENVIRONMENT_SET_SERIALIZATION_QUIRKS,
}
pub trait Handler: 'static {
pub trait Handler: Unpin + '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() }
@ -235,3 +235,5 @@ pub trait Handler: 'static {
fn get_language(&mut self) -> Option<Language> { None }
// fn set_serialization_quirks(&mut self, quirks: &mut u64) -> bool { false }
}
// impl<T: Handler> Unpin for T {}

View File

@ -1,13 +1,10 @@
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;
use super::ffi::*;
use super::convert::*;
pub struct LibretroApi {
lib: libloading::Library, // for tying our lifetime to its own

View File

@ -4,10 +4,12 @@ use core::slice::from_raw_parts;
use std::ffi::CString;
use std::os::raw::{c_uint, c_char};
use std::ops::DerefMut;
use std::path::Path;
use std::pin::Pin;
use libretro_sys::{Message, PixelFormat, SystemAvInfo, GameGeometry};
use num_enum::{IntoPrimitive, TryFromPrimitive};
use num_enum::TryFromPrimitive;
use super::convert::*;
use super::loading::*;
@ -18,7 +20,7 @@ static mut CB_SINGLETON: StaticCallbacks = StaticCallbacks {
#[derive(Default)]
struct StaticCallbacks {
handler: Option<&'static mut dyn Handler>,
handler: Option<Pin<&'static mut dyn Handler>>,
}
unsafe impl Sync for StaticCallbacks {}
@ -135,11 +137,6 @@ impl StaticCallbacks {
None => 0,
}
}
pub(crate) fn register(cb: &'static mut dyn Handler) {
unsafe {
CB_SINGLETON.handler.replace(cb);
}
}
pub(crate) fn reset() {
unsafe {
CB_SINGLETON.handler.take();
@ -177,7 +174,9 @@ impl Drop for LibretroWrapper {
// 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)
pub fn register_handler(handler: &mut dyn Handler) {
let ptr: *mut dyn Handler = handler;
StaticCallbacks::register(unsafe { ptr.as_mut() }.unwrap());
pub fn register_handler(handler: Pin<&'_ mut (dyn Handler + '_)>) {
unsafe {
let mut ptr = handler.get_unchecked_mut() as *mut dyn Handler;
CB_SINGLETON.handler.replace(Pin::new_unchecked(ptr.as_mut().unwrap()));
}
}