add some QOL stuff to the SDL2 Simple video components
This commit is contained in:
parent
e95e13df1e
commit
56e070a30d
|
@ -33,6 +33,25 @@ impl<'a> VideoFrame<'a> {
|
|||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dimensions(&self) -> (c_uint, c_uint) {
|
||||
match self {
|
||||
VideoFrame::XRGB1555 { width, height, .. }
|
||||
| VideoFrame::RGB565 { width, height, .. }
|
||||
| VideoFrame::XRGB8888 { width, height, .. }
|
||||
| VideoFrame::Duplicate { width, height, .. }
|
||||
| VideoFrame::HardwareRender { width, height, .. } => (*width, *height),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pixel_format(&self) -> Option<PixelFormat> {
|
||||
match self {
|
||||
VideoFrame::XRGB1555 { .. } => Some(PixelFormat::ARGB1555),
|
||||
VideoFrame::RGB565 { .. } => Some(PixelFormat::RGB565),
|
||||
VideoFrame::XRGB8888 { .. } => Some(PixelFormat::ARGB8888),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
|
|
|
@ -32,6 +32,9 @@ struct Opt {
|
|||
/// Recorded video to write.
|
||||
#[structopt(short, long, parse(from_os_str))]
|
||||
video: Option<PathBuf>,
|
||||
/// Disable OpenGL context creation.
|
||||
#[structopt(long)]
|
||||
no_opengl: bool,
|
||||
}
|
||||
|
||||
pub fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
|
@ -54,8 +57,20 @@ pub fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
emu.register_component(ffmpeg_comp)?;
|
||||
}
|
||||
|
||||
let sdl2_ogl = SimpleSdl2OpenglComponent::new(&mut sdl_context, emu.libretro_core())?;
|
||||
emu.register_component(sdl2_ogl)?;
|
||||
let sdl2_ogl_res = if opt.no_opengl {
|
||||
Err("OpenGL disabled".into())
|
||||
} else {
|
||||
SimpleSdl2OpenglComponent::new(&mut sdl_context, emu.libretro_core())
|
||||
};
|
||||
|
||||
if let Ok(sdl2_ogl) = sdl2_ogl_res {
|
||||
emu.register_component(sdl2_ogl)?;
|
||||
} else {
|
||||
match SimpleSdl2CanvasComponent::new(&mut sdl_context, emu.libretro_core()) {
|
||||
Ok(sdl2_canvas) => emu.register_component(sdl2_canvas)?,
|
||||
Err(e) => eprintln!("Couldn't initialize SDL2 video component: {:?}", e),
|
||||
}
|
||||
}
|
||||
|
||||
emu.register_component(SimpleSdl2AudioComponent::new(&mut sdl_context)?)?;
|
||||
|
||||
|
|
|
@ -7,13 +7,42 @@ use sdl2::Sdl;
|
|||
use sdl2::rect::Rect;
|
||||
use sdl2::render::WindowCanvas;
|
||||
|
||||
pub(crate) fn paint_frame_on_canvas(frame: &VideoFrame, canvas: &mut WindowCanvas) -> bool {
|
||||
if let Some((pixel_data, pitch)) = frame.data_pitch_as_bytes() {
|
||||
let (width, height) = frame.dimensions();
|
||||
let pixel_format = frame.pixel_format().map(sdl2_pixfmt);
|
||||
|
||||
if let Ok(mut tex) = canvas
|
||||
.texture_creator()
|
||||
.create_texture_static(pixel_format, width, height)
|
||||
{
|
||||
let rect = Rect::new(0, 0, width, height);
|
||||
if tex.update(rect, pixel_data, pitch).is_ok() {
|
||||
canvas.clear();
|
||||
canvas.copy(&tex, None, None).unwrap();
|
||||
}
|
||||
}
|
||||
canvas.present();
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn sdl2_pixfmt(retro_fmt: PixelFormat) -> sdl2::pixels::PixelFormatEnum {
|
||||
match retro_fmt {
|
||||
PixelFormat::ARGB1555 => sdl2::pixels::PixelFormatEnum::ARGB1555,
|
||||
PixelFormat::ARGB8888 => sdl2::pixels::PixelFormatEnum::ARGB8888,
|
||||
PixelFormat::RGB565 => sdl2::pixels::PixelFormatEnum::RGB565,
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a root window in SDL2, then displays each 2D video frame provided by the core
|
||||
/// by converting it to a [sdl2::render::Texture] and copying it to the window's canvas.
|
||||
///
|
||||
/// This component has no public interface and manages the SDL2 window on its own.
|
||||
pub struct SimpleSdl2CanvasComponent {
|
||||
canvas: WindowCanvas,
|
||||
pixel_format: sdl2::pixels::PixelFormatEnum,
|
||||
}
|
||||
|
||||
impl SimpleSdl2CanvasComponent {
|
||||
|
@ -24,8 +53,6 @@ impl SimpleSdl2CanvasComponent {
|
|||
unsafe { CStr::from_ptr(sys_info.library_name) }.to_string_lossy()
|
||||
);
|
||||
|
||||
let pixel_format = sdl2::pixels::PixelFormatEnum::ARGB1555;
|
||||
|
||||
let window = sdl_context
|
||||
.video()?
|
||||
.window(title.as_str(), 256, 224)
|
||||
|
@ -35,7 +62,6 @@ impl SimpleSdl2CanvasComponent {
|
|||
|
||||
Ok(SimpleSdl2CanvasComponent {
|
||||
canvas,
|
||||
pixel_format,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -49,34 +75,10 @@ impl RetroComponent for SimpleSdl2CanvasComponent {
|
|||
|
||||
impl RetroCallbacks for SimpleSdl2CanvasComponent {
|
||||
fn video_refresh(&mut self, frame: &VideoFrame) {
|
||||
match frame {
|
||||
VideoFrame::XRGB1555 { width, height, .. }
|
||||
| VideoFrame::RGB565 { width, height, .. }
|
||||
| VideoFrame::XRGB8888 { width, height, .. } => {
|
||||
let rect = Rect::new(0, 0, *width, *height);
|
||||
|
||||
if let Ok(mut tex) = self.canvas
|
||||
.texture_creator()
|
||||
.create_texture_static(self.pixel_format, *width, *height)
|
||||
{
|
||||
let (pixel_data, pitch) = frame.data_pitch_as_bytes().unwrap();
|
||||
if tex.update(rect, pixel_data, pitch).is_ok() {
|
||||
self.canvas.clear();
|
||||
self.canvas.copy(&tex, None, None).unwrap();
|
||||
}
|
||||
}
|
||||
self.canvas.present();
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
paint_frame_on_canvas(frame, &mut self.canvas);
|
||||
}
|
||||
|
||||
fn set_pixel_format(&mut self, pix_fmt: PixelFormat) -> Option<bool> {
|
||||
self.pixel_format = match pix_fmt {
|
||||
PixelFormat::ARGB1555 => sdl2::pixels::PixelFormatEnum::RGB555,
|
||||
PixelFormat::ARGB8888 => sdl2::pixels::PixelFormatEnum::ARGB8888,
|
||||
PixelFormat::RGB565 => sdl2::pixels::PixelFormatEnum::RGB565,
|
||||
};
|
||||
fn set_pixel_format(&mut self, _pix_fmt: PixelFormat) -> Option<bool> {
|
||||
Some(true)
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,16 @@ pub struct SimpleSdl2FramerateLimitComponent {
|
|||
fps_manager: FPSManager,
|
||||
}
|
||||
|
||||
impl Default for SimpleSdl2FramerateLimitComponent {
|
||||
fn default() -> Self {
|
||||
SimpleSdl2FramerateLimitComponent {
|
||||
did_sleep: false,
|
||||
started_video: false,
|
||||
fps_manager: FPSManager::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RetroComponent for SimpleSdl2FramerateLimitComponent {
|
||||
fn pre_run(&mut self, _retro: &mut LibretroWrapper) -> ControlFlow {
|
||||
self.did_sleep = false;
|
||||
|
|
|
@ -5,9 +5,10 @@ use std::os::raw::c_uint;
|
|||
use std::path::Path;
|
||||
|
||||
use sdl2::Sdl;
|
||||
use sdl2::rect::Rect;
|
||||
use sdl2::render::WindowCanvas;
|
||||
|
||||
use super::canvas::paint_frame_on_canvas;
|
||||
|
||||
/// Create a root window in SDL2 with an OpenGL context and attaches libretro's
|
||||
/// `hw_get_proc_address` calls to that of the [sdl2::VideoSubsystem].
|
||||
///
|
||||
|
@ -20,7 +21,6 @@ use sdl2::render::WindowCanvas;
|
|||
pub struct SimpleSdl2OpenglComponent {
|
||||
canvas: WindowCanvas,
|
||||
window_fbo: c_uint,
|
||||
pixel_format: sdl2::pixels::PixelFormatEnum,
|
||||
hw_context_reset_fn: Option<HwContextResetFn>,
|
||||
hw_context_destroy_fn: Option<HwContextResetFn>,
|
||||
glGetIntegerv: unsafe extern "C" fn(c_uint, *mut c_uint),
|
||||
|
@ -35,8 +35,6 @@ impl SimpleSdl2OpenglComponent {
|
|||
unsafe { CStr::from_ptr(sys_info.library_name) }.to_string_lossy()
|
||||
);
|
||||
|
||||
let pixel_format = sdl2::pixels::PixelFormatEnum::ARGB1555;
|
||||
|
||||
let video = sdl_context.video()?;
|
||||
// default to old libsnes 256x224 window size until load_game (prereq of get_system_av_info)
|
||||
let window = video
|
||||
|
@ -65,7 +63,6 @@ impl SimpleSdl2OpenglComponent {
|
|||
Ok(SimpleSdl2OpenglComponent {
|
||||
canvas,
|
||||
window_fbo,
|
||||
pixel_format,
|
||||
hw_context_reset_fn: None,
|
||||
hw_context_destroy_fn: None,
|
||||
glGetIntegerv,
|
||||
|
@ -101,36 +98,16 @@ impl RetroComponent for SimpleSdl2OpenglComponent {
|
|||
impl RetroCallbacks for SimpleSdl2OpenglComponent {
|
||||
fn video_refresh(&mut self, frame: &VideoFrame) {
|
||||
match frame {
|
||||
VideoFrame::XRGB1555 { width, height, .. }
|
||||
| VideoFrame::RGB565 { width, height, .. }
|
||||
| VideoFrame::XRGB8888 { width, height, .. } => {
|
||||
let rect = Rect::new(0, 0, *width, *height);
|
||||
if let Ok(mut tex) = self.canvas
|
||||
.texture_creator()
|
||||
.create_texture_static(self.pixel_format, *width, *height)
|
||||
{
|
||||
let (pixel_data, pitch) = frame.data_pitch_as_bytes().unwrap();
|
||||
if tex.update(rect, pixel_data, pitch).is_ok() {
|
||||
self.canvas.clear();
|
||||
self.canvas.copy(&tex, None, None).unwrap();
|
||||
}
|
||||
}
|
||||
self.canvas.present();
|
||||
}
|
||||
VideoFrame::HardwareRender { .. } => {
|
||||
self.canvas.present();
|
||||
unsafe { (self.glClear)(gl::COLOR_BUFFER_BIT); }
|
||||
}
|
||||
VideoFrame::Duplicate { .. } => {}
|
||||
_ => { paint_frame_on_canvas(frame, &mut self.canvas); },
|
||||
}
|
||||
}
|
||||
|
||||
fn set_pixel_format(&mut self, pix_fmt: PixelFormat) -> Option<bool> {
|
||||
self.pixel_format = match pix_fmt {
|
||||
PixelFormat::ARGB1555 => sdl2::pixels::PixelFormatEnum::RGB555,
|
||||
PixelFormat::ARGB8888 => sdl2::pixels::PixelFormatEnum::ARGB8888,
|
||||
PixelFormat::RGB565 => sdl2::pixels::PixelFormatEnum::RGB565,
|
||||
};
|
||||
fn set_pixel_format(&mut self, _pix_fmt: PixelFormat) -> Option<bool> {
|
||||
Some(true)
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue