From fd2eb03c077a80c9e4779087ba300de8508d3fbe Mon Sep 17 00:00:00 2001 From: lifning <> Date: Thu, 4 Nov 2021 22:54:27 -0700 Subject: [PATCH] round out a bit more of camera support --- ferretro_base/src/retro/wrapped_types.rs | 41 +++++++++++- ferretro_base/src/retro/wrapper.rs | 7 +- .../examples/multifunction_emulator.rs | 3 +- ferretro_components/src/base/mod.rs | 36 ++++++++++ ferretro_components/src/lib.rs | 2 +- .../src/provided/sdl2/surface.rs | 10 +++ .../src/provided/stdlib/camera.rs | 66 +++++++++++++++++++ .../src/provided/stdlib/logs.rs | 2 +- .../src/provided/stdlib/mod.rs | 2 + 9 files changed, 161 insertions(+), 8 deletions(-) create mode 100644 ferretro_components/src/provided/stdlib/camera.rs diff --git a/ferretro_base/src/retro/wrapped_types.rs b/ferretro_base/src/retro/wrapped_types.rs index 0c31ab0..b96dcdb 100644 --- a/ferretro_base/src/retro/wrapped_types.rs +++ b/ferretro_base/src/retro/wrapped_types.rs @@ -1,13 +1,14 @@ use core::convert::{TryFrom, TryInto}; use core::mem::size_of; use std::ffi::CStr; +use std::fmt::{Debug, Formatter}; use std::os::raw::{c_uint}; use std::slice::from_raw_parts; use super::constants::*; use super::ffi::*; -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy)] pub enum VideoFrame<'a> { XRGB1555 { data: &'a [u16], width: c_uint, height: c_uint, pitch_u16: usize }, RGB565 { data: &'a [u16], width: c_uint, height: c_uint, pitch_u16: usize }, @@ -54,6 +55,44 @@ impl<'a> VideoFrame<'a> { } } +impl<'a> Debug for VideoFrame<'a> { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + VideoFrame::XRGB1555 { data, width, height, pitch_u16 } => { + write!( + f, + "XRGB1555 {{ data: &[u16; {}], width: {}, height: {}, pitch_u16: {} }}", + data.len(), width, height, pitch_u16 + ) + } + VideoFrame::RGB565 { data, width, height, pitch_u16 } => { + write!( + f, + "RGB565 {{ data: &[u16; {}], width: {}, height: {}, pitch_u16: {} }}", + data.len(), width, height, pitch_u16 + ) + } + VideoFrame::XRGB8888 { data, width, height, pitch_u32 } => { + write!( + f, + "XRGB8888 {{ data: &[u32; {}], width: {}, height: {}, pitch_u32: {} }}", + data.len(), width, height, pitch_u32 + ) + } + VideoFrame::Duplicate { width, height, pitch_u8 } => { + write!( + f, + "Duplicate {{ width: {}, height: {}, pitch_u8: {} }}", + width, height, pitch_u8 + ) + } + VideoFrame::HardwareRender { width, height } => { + write!(f, "HardwareRender {{ width: {}, height: {} }}", width, height) + } + } + } +} + #[derive(Clone, Copy, Debug)] pub enum InputDeviceId { None(c_uint), diff --git a/ferretro_base/src/retro/wrapper.rs b/ferretro_base/src/retro/wrapper.rs index 3a51842..1c6e425 100644 --- a/ferretro_base/src/retro/wrapper.rs +++ b/ferretro_base/src/retro/wrapper.rs @@ -574,8 +574,8 @@ impl StaticCallbacks { } EnvCmd::GetCameraInterface => { let cc: &mut CameraCallback = Self::from_void(data)?; - let gl_tex = (cc.caps & 1 << (CameraBuffer::OpenGLTexture as u64)) != 0; - let raw_fb = (cc.caps & 1 << (CameraBuffer::RawFramebuffer as u64)) != 0; + let cap_gl_tex = (cc.caps & 1 << (CameraBuffer::OpenGLTexture as u64)) != 0; + let cap_raw_fb = (cc.caps & 1 << (CameraBuffer::RawFramebuffer as u64)) != 0; let wrapper = handler.libretro_core(); if !(cc.frame_raw_framebuffer as *const ()).is_null() { wrapper.camera_frame_raw_framebuffer_cb.replace(cc.frame_raw_framebuffer); @@ -591,7 +591,8 @@ impl StaticCallbacks { } cc.start = Self::camera_start; cc.stop = Self::camera_stop; - handler.get_camera_interface(cc.width, cc.height, gl_tex, raw_fb)? + handler.get_camera_interface(cc.width, cc.height, cap_raw_fb, cap_gl_tex) + .unwrap_or(true) // only say false if someone explicitly objected. TODO: is this okay? } EnvCmd::GetLogInterface => unsafe { c_ext_handle_get_log_interface(data as *mut LogCallback) diff --git a/ferretro_components/examples/multifunction_emulator.rs b/ferretro_components/examples/multifunction_emulator.rs index 97d05ba..dc5b2be 100644 --- a/ferretro_components/examples/multifunction_emulator.rs +++ b/ferretro_components/examples/multifunction_emulator.rs @@ -14,7 +14,6 @@ use ferretro_components::provided::{ stdlib::*, }; use ferretro_components::base::ControlFlow; -use ferretro_components::provided::stdlib::{StderrCallTraceComponent, StderrSysInfoLogComponent}; #[derive(StructOpt)] struct Opt { @@ -53,7 +52,7 @@ pub fn main() -> Result<(), Box> { emu.register_component(stderr_log)?; if opt.trace_api { - emu.register_component(StderrCallTraceComponent { prefix: "{trace} ".to_string() }); + emu.register_component(StderrCallTraceComponent { prefix: "{trace} ".to_string() })?; } // must register before opengl so it can have priority in queries about what N64 plugin to use diff --git a/ferretro_components/src/base/mod.rs b/ferretro_components/src/base/mod.rs index 9d9d769..a6bcfeb 100644 --- a/ferretro_components/src/base/mod.rs +++ b/ferretro_components/src/base/mod.rs @@ -12,6 +12,7 @@ use std::os::raw::c_uint; use std::path::{PathBuf, Path}; use std::io::Read; use std::collections::HashMap; +use std::ffi::c_void; pub struct RetroComponentBase { retro: LibretroWrapper, @@ -210,6 +211,17 @@ impl RetroComponentBase { ControlFlow::Continue } + pub fn serialize_buf(&mut self, mut state: impl AsMut<[u8]>) -> Result<()> { + let state = state.as_mut(); + let serialize_size = unsafe { (&self.retro.core_api.retro_serialize_size)() }; + if state.len() != serialize_size { + Err(format!("serialize_size mismatch: {} != {}", state.len(), serialize_size).into()) + } else { + unsafe { (&self.retro.core_api.retro_serialize)(state.as_mut_ptr() as *mut c_void, state.len()) } + Ok(()) // FIXME: make retro_serialize return bool in libretro-sys ffi + } + } + pub fn unserialize_path(&mut self, state: impl AsRef) -> Result<()> { let path = state.as_ref(); let mut v = Vec::new(); @@ -531,6 +543,30 @@ impl RetroCallbacks for RetroComponentBase { .unwrap_or_default() } + fn get_camera_interface(&mut self, width: c_uint, height: c_uint, cap_raw_fb: bool, cap_gl_tex: bool) -> Option { + self.components.iter_mut() + .map(|comp| comp.get_camera_interface(width, height, cap_raw_fb, cap_gl_tex)) + .flatten() + .fold(false, |x, y| x || y) // not "any" because we don't short-circuit + .into() + } + + fn camera_start(&mut self) -> Option { + self.components.iter_mut() + .map(|comp| comp.camera_start()) + .flatten() + .fold(true, |x, y| x && y) // not "all" because we don't short-circuit + .into() + } + + fn camera_stop(&mut self) -> Option<()> { + self.components.iter_mut() + .map(|comp| comp.camera_stop()) + .flatten() + .fold((), |_, _| {}) // not "all" because we don't short-circuit + .into() + } + fn hw_get_current_framebuffer(&mut self) -> Option { self.components.iter_mut() .map(|comp| comp.hw_get_current_framebuffer()) diff --git a/ferretro_components/src/lib.rs b/ferretro_components/src/lib.rs index b486886..b9df277 100644 --- a/ferretro_components/src/lib.rs +++ b/ferretro_components/src/lib.rs @@ -7,5 +7,5 @@ pub mod prelude { pub use ferretro_base::retro::constants::*; pub use ferretro_base::retro::wrapped_types::*; pub use ferretro_base::retro::wrapper::{RetroCallbacks, LibretroWrapper, LibretroWrapperAccess}; - pub use ferretro_base::retro::ffi::{PixelFormat, GameGeometry, HwContextResetFn, HwRenderCallback, SystemAvInfo, SystemInfo, MemoryMap}; + pub use ferretro_base::retro::ffi::{PixelFormat, GameGeometry, HwContextResetFn, HwRenderCallback, SystemAvInfo, SystemInfo, MemoryMap, LogLevel}; } diff --git a/ferretro_components/src/provided/sdl2/surface.rs b/ferretro_components/src/provided/sdl2/surface.rs index 0cab588..8e52968 100644 --- a/ferretro_components/src/provided/sdl2/surface.rs +++ b/ferretro_components/src/provided/sdl2/surface.rs @@ -24,6 +24,16 @@ impl Sdl2SurfaceComponent { pub fn surface(&self) -> &Surface { &self.surface } + + pub fn surface_owned(&self) -> Surface { + let mut clone = Surface::new( + self.surface.width(), + self.surface.height(), + self.surface.pixel_format_enum(), + ).unwrap(); + self.surface.blit(None, &mut clone, None).unwrap(); + clone + } } impl RetroComponent for Sdl2SurfaceComponent {} diff --git a/ferretro_components/src/provided/stdlib/camera.rs b/ferretro_components/src/provided/stdlib/camera.rs new file mode 100644 index 0000000..4d8e79e --- /dev/null +++ b/ferretro_components/src/provided/stdlib/camera.rs @@ -0,0 +1,66 @@ +use std::os::raw::c_uint; +use crate::base::RetroComponent; +use crate::prelude::RetroCallbacks; + +#[derive(Default)] +pub struct CameraInfoComponent { + initialized: bool, + started: bool, + width: c_uint, + height: c_uint, + cap_raw_fb: bool, + cap_gl_tex: bool, +} + +impl CameraInfoComponent { + pub fn dimensions(&self) -> Option<(c_uint, c_uint)> { + if self.initialized { + Some((self.width, self.height)) + } else { + None + } + } + + pub fn raw_fb(&self) -> Option { + if self.initialized { + Some(self.cap_raw_fb) + } else { + None + } + } + + pub fn gl_tex(&self) -> Option { + if self.initialized { + Some(self.cap_gl_tex) + } else { + None + } + } + + pub fn started(&self) -> bool { + self.started + } +} + +impl RetroComponent for CameraInfoComponent {} + +impl RetroCallbacks for CameraInfoComponent { + fn get_camera_interface(&mut self, width: c_uint, height: c_uint, cap_raw_fb: bool, cap_gl_tex: bool) -> Option { + self.initialized = true; + self.width = width; + self.height = height; + self.cap_raw_fb = cap_raw_fb; + self.cap_gl_tex = cap_gl_tex; + Some(true) + } + + fn camera_start(&mut self) -> Option { + self.started = true; + Some(true) + } + + fn camera_stop(&mut self) -> Option<()> { + self.started = false; + Some(()) + } +} diff --git a/ferretro_components/src/provided/stdlib/logs.rs b/ferretro_components/src/provided/stdlib/logs.rs index cf9d9f7..f919b25 100644 --- a/ferretro_components/src/provided/stdlib/logs.rs +++ b/ferretro_components/src/provided/stdlib/logs.rs @@ -79,7 +79,7 @@ impl RetroCallbacks for StderrCallTraceComponent { eprintln!("{}video_refresh({:?})", self.prefix, frame); } fn audio_samples(&mut self, stereo_pcm: &[i16]) -> usize { - eprintln!("{}audio_samples([i16; {}])", self.prefix, stereo_pcm.len()); + eprintln!("{}audio_samples(&[i16; {}])", self.prefix, stereo_pcm.len()); 0 } fn input_poll(&mut self) { diff --git a/ferretro_components/src/provided/stdlib/mod.rs b/ferretro_components/src/provided/stdlib/mod.rs index 10006ee..969fb87 100644 --- a/ferretro_components/src/provided/stdlib/mod.rs +++ b/ferretro_components/src/provided/stdlib/mod.rs @@ -1,10 +1,12 @@ //! Generally-useful [RetroComponent](crate::base::RetroComponent)s that have no dependencies //! outside of [std]. +mod camera; mod fps; mod logs; mod paths; +pub use camera::CameraInfoComponent; pub use fps::SleepFramerateLimitComponent; pub use logs::StderrCallTraceComponent; pub use logs::StderrLogComponent;