round out a bit more of camera support

This commit is contained in:
lifning 2021-11-04 22:54:27 -07:00
parent bbee2b95dd
commit fd2eb03c07
9 changed files with 161 additions and 8 deletions

View File

@ -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),

View File

@ -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)

View File

@ -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<dyn std::error::Error>> {
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

View File

@ -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<Path>) -> 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<bool> {
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<bool> {
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<usize> {
self.components.iter_mut()
.map(|comp| comp.hw_get_current_framebuffer())

View File

@ -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};
}

View File

@ -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 {}

View File

@ -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<bool> {
if self.initialized {
Some(self.cap_raw_fb)
} else {
None
}
}
pub fn gl_tex(&self) -> Option<bool> {
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<bool> {
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<bool> {
self.started = true;
Some(true)
}
fn camera_stop(&mut self) -> Option<()> {
self.started = false;
Some(())
}
}

View File

@ -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) {

View File

@ -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;