add some QOL stuff to the SDL2 Simple video components
This commit is contained in:
		
							parent
							
								
									e95e13df1e
								
							
						
					
					
						commit
						56e070a30d
					
				
					 5 changed files with 82 additions and 59 deletions
				
			
		| 
						 | 
				
			
			@ -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…
	
	Add table
		
		Reference in a new issue