wip messing around with SDL_GL as a possible hw render provider to later mix in with the existing 2D codepaths
This commit is contained in:
		
							parent
							
								
									e1c0670feb
								
							
						
					
					
						commit
						013cc247b9
					
				
					 8 changed files with 209 additions and 49 deletions
				
			
		| 
						 | 
				
			
			@ -6,5 +6,5 @@ pub mod prelude {
 | 
			
		|||
    pub use crate::retro::constants::*;
 | 
			
		||||
    pub use crate::retro::wrapped_types::*;
 | 
			
		||||
    pub use crate::retro::wrapper::{RetroCallbacks, LibretroWrapper, LibretroWrapperAccess};
 | 
			
		||||
    pub use crate::retro::ffi::{PixelFormat, GameGeometry, SystemAvInfo, SystemInfo};
 | 
			
		||||
    pub use crate::retro::ffi::{PixelFormat, GameGeometry, HwContextResetFn, HwRenderCallback, SystemAvInfo, SystemInfo};
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -152,5 +152,7 @@ pub enum EnvCmd {
 | 
			
		|||
    SetGeometry = ENVIRONMENT_SET_GEOMETRY,
 | 
			
		||||
    GetUsername = ENVIRONMENT_GET_USERNAME,
 | 
			
		||||
    GetLanguage = ENVIRONMENT_GET_LANGUAGE,
 | 
			
		||||
    GetCurrentSoftwareFramebuffer = ENVIRONMENT_GET_CURRENT_SOFTWARE_FRAMEBUFFER,
 | 
			
		||||
    GetHwRenderInterface = ENVIRONMENT_GET_HW_RENDER_INTERFACE,
 | 
			
		||||
    // SetSerializationQuirks = ENVIRONMENT_SET_SERIALIZATION_QUIRKS,
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -45,8 +45,10 @@ pub trait RetroCallbacks: Unpin + 'static {
 | 
			
		|||
    /// Certain graphic APIs, such as OpenGL ES, do not like textures
 | 
			
		||||
    /// that are not packed in memory.
 | 
			
		||||
    fn video_refresh(&mut self, data: &[u8], width: c_uint, height: c_uint, pitch: c_uint) {}
 | 
			
		||||
    /// Called instead of video_refresh when the core reports a duplicate frame (NULL).
 | 
			
		||||
    /// Called instead of video_refresh when a core reports a duplicate frame (NULL).
 | 
			
		||||
    fn video_refresh_dupe(&mut self, width: c_uint, height: c_uint, pitch: c_uint) {}
 | 
			
		||||
    /// Called instead of video_refresh when a core uses hardware rendering (HW_FRAMEBUFFER_VALID).
 | 
			
		||||
    fn video_refresh_hw(&mut self, width: c_uint, height: c_uint) {}
 | 
			
		||||
    /// Renders a single audio frame. Should only be used if implementation
 | 
			
		||||
    /// generates a single sample at a time.
 | 
			
		||||
    /// Format is signed 16-bit native endian.
 | 
			
		||||
| 
						 | 
				
			
			@ -342,28 +344,33 @@ pub trait RetroCallbacks: Unpin + 'static {
 | 
			
		|||
    fn set_rumble_state(&mut self, port: c_uint, effect: RumbleEffect, strength: u16) -> bool { false }
 | 
			
		||||
    /// Returns current time in microseconds.
 | 
			
		||||
    /// Tries to use the most accurate timer available.
 | 
			
		||||
    fn perf_get_time_usec_cb(&mut self) -> Time { 0 }
 | 
			
		||||
    fn perf_get_time_usec(&mut self) -> Time { 0 }
 | 
			
		||||
    /// A simple counter. Usually nanoseconds, but can also be CPU cycles.
 | 
			
		||||
    /// Can be used directly if desired (when creating a more sophisticated
 | 
			
		||||
    /// performance counter system).
 | 
			
		||||
    fn perf_get_counter_cb(&mut self) -> PerfTick { 0 }
 | 
			
		||||
    fn perf_get_counter(&mut self) -> PerfTick { 0 }
 | 
			
		||||
    /// Returns a bit-mask of detected CPU features ([libretro_sys]::SIMD_*).
 | 
			
		||||
    fn perf_get_cpu_features_cb(&mut self) -> u64 { 0 }
 | 
			
		||||
    fn perf_get_cpu_features(&mut self) -> u64 { 0 }
 | 
			
		||||
    /// Asks frontend to log and/or display the state of performance counters.
 | 
			
		||||
    /// Performance counters can always be poked into manually as well.
 | 
			
		||||
    fn perf_log_cb(&mut self) {}
 | 
			
		||||
    fn perf_log(&mut self) {}
 | 
			
		||||
    /// Register a performance counter.
 | 
			
		||||
    /// ident field must be set with a discrete value and other values in
 | 
			
		||||
    /// retro_perf_counter must be 0.
 | 
			
		||||
    /// Registering can be called multiple times. To avoid calling to
 | 
			
		||||
    /// frontend redundantly, you can check registered field first.
 | 
			
		||||
    fn perf_register_cb(&mut self, counter: &mut PerfCounter) {}
 | 
			
		||||
    fn perf_register(&mut self, counter: &mut PerfCounter) {}
 | 
			
		||||
    /// Starts a registered counter.
 | 
			
		||||
    fn perf_start_cb(&mut self, counter: &mut PerfCounter) {}
 | 
			
		||||
    fn perf_start(&mut self, counter: &mut PerfCounter) {}
 | 
			
		||||
    /// Stops a registered counter.
 | 
			
		||||
    fn perf_stop_cb(&mut self, counter: &mut PerfCounter) {}
 | 
			
		||||
    fn perf_stop(&mut self, counter: &mut PerfCounter) {}
 | 
			
		||||
    fn set_sensor_state(&mut self, port: c_uint, action: SensorAction, rate: c_uint) -> bool { false }
 | 
			
		||||
    fn get_sensor_input(&mut self, port: c_uint, id: c_uint) -> f32 { 0.0 }
 | 
			
		||||
    /// Gets current framebuffer which is to be rendered to.
 | 
			
		||||
    /// Could change every frame potentially.
 | 
			
		||||
    fn hw_get_current_framebuffer(&mut self) -> Option<usize> { None }
 | 
			
		||||
    /// Get a symbol from HW context.
 | 
			
		||||
    fn hw_get_proc_address(&mut self, sym: &str) -> Option<*const ()> { None }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub trait LibretroWrapperAccess {
 | 
			
		||||
| 
						 | 
				
			
			@ -486,7 +493,7 @@ impl StaticCallbacks {
 | 
			
		|||
                    .replace(hwr.context_destroy);
 | 
			
		||||
                hwr.get_current_framebuffer = Self::hw_get_current_framebuffer_fn;
 | 
			
		||||
                hwr.get_proc_address = Self::hw_get_proc_address_fn;
 | 
			
		||||
                false // TODO: finish
 | 
			
		||||
                handler.set_hw_render(hwr).unwrap_or(false)
 | 
			
		||||
            }
 | 
			
		||||
            EnvCmd::GetVariable => {
 | 
			
		||||
                let mut var = Self::from_void::<Variable>(data)?;
 | 
			
		||||
| 
						 | 
				
			
			@ -602,6 +609,8 @@ impl StaticCallbacks {
 | 
			
		|||
            }
 | 
			
		||||
            EnvCmd::GetUsername => Self::string_into_void(data, handler.get_username()?)?,
 | 
			
		||||
            EnvCmd::GetLanguage => Self::clone_into_void(data, &handler.get_language()?)?,
 | 
			
		||||
            // TODO EnvCmd::GetCurrentSoftwareFramebuffer => {}
 | 
			
		||||
            // TODO EnvCmd::GetHwRenderInterface => {}
 | 
			
		||||
            // TODO (not in libretro-sys) EnvCmd::SetSerializationQuirks => handler.set_serialization_quirks(Self::from_void(data)?),
 | 
			
		||||
            x => {
 | 
			
		||||
                if cfg!(debug) {
 | 
			
		||||
| 
						 | 
				
			
			@ -623,13 +632,16 @@ impl StaticCallbacks {
 | 
			
		|||
        pitch: usize,
 | 
			
		||||
    ) {
 | 
			
		||||
        if let Some(cb) = unsafe { CB_SINGLETON.handler.as_mut() } {
 | 
			
		||||
            if data.is_null() {
 | 
			
		||||
                cb.video_refresh_dupe(width, height, pitch as c_uint);
 | 
			
		||||
            } else if data != HW_FRAME_BUFFER_VALID {
 | 
			
		||||
                let data = data as *const u8;
 | 
			
		||||
                let len = pitch * (height as usize);
 | 
			
		||||
                let slice = unsafe { from_raw_parts(data, len) };
 | 
			
		||||
                cb.video_refresh(slice, width, height, pitch as c_uint);
 | 
			
		||||
            const NULL: *const c_void = std::ptr::null();
 | 
			
		||||
            match data {
 | 
			
		||||
                NULL => cb.video_refresh_dupe(width, height, pitch as c_uint),
 | 
			
		||||
                HW_FRAME_BUFFER_VALID => cb.video_refresh_hw(width, height),
 | 
			
		||||
                data => {
 | 
			
		||||
                    let data = data as *const u8;
 | 
			
		||||
                    let len = pitch * (height as usize);
 | 
			
		||||
                    let slice = unsafe { from_raw_parts(data, len) };
 | 
			
		||||
                    cb.video_refresh(slice, width, height, pitch as c_uint);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -681,27 +693,27 @@ impl StaticCallbacks {
 | 
			
		|||
    }
 | 
			
		||||
    extern "C" fn perf_get_time_usec_cb() -> Time {
 | 
			
		||||
        unsafe {
 | 
			
		||||
            CB_SINGLETON.handler.as_mut().map(|cb| cb.perf_get_time_usec_cb())
 | 
			
		||||
            CB_SINGLETON.handler.as_mut().map(|cb| cb.perf_get_time_usec())
 | 
			
		||||
        }.unwrap_or_default()
 | 
			
		||||
    }
 | 
			
		||||
    extern "C" fn perf_get_counter_cb() -> PerfTick {
 | 
			
		||||
        unsafe {
 | 
			
		||||
            CB_SINGLETON.handler.as_mut().map(|cb| cb.perf_get_counter_cb())
 | 
			
		||||
            CB_SINGLETON.handler.as_mut().map(|cb| cb.perf_get_counter())
 | 
			
		||||
        }.unwrap_or_default()
 | 
			
		||||
    }
 | 
			
		||||
    extern "C" fn perf_get_cpu_features_cb() -> u64 {
 | 
			
		||||
        unsafe {
 | 
			
		||||
            CB_SINGLETON.handler.as_mut().map(|cb| cb.perf_get_cpu_features_cb())
 | 
			
		||||
            CB_SINGLETON.handler.as_mut().map(|cb| cb.perf_get_cpu_features())
 | 
			
		||||
        }.unwrap_or_default()
 | 
			
		||||
    }
 | 
			
		||||
    extern "C" fn perf_log_cb() {
 | 
			
		||||
        unsafe { CB_SINGLETON.handler.as_mut().map(|cb| cb.perf_log_cb()); }
 | 
			
		||||
        unsafe { CB_SINGLETON.handler.as_mut().map(|cb| cb.perf_log()); }
 | 
			
		||||
    }
 | 
			
		||||
    extern "C" fn perf_register_cb(counter: *mut PerfCounter) {
 | 
			
		||||
        unsafe {
 | 
			
		||||
            match (CB_SINGLETON.handler.as_mut(), counter.as_mut()) {
 | 
			
		||||
                (Some(cb), Some(counter)) => {
 | 
			
		||||
                    cb.perf_register_cb(counter);
 | 
			
		||||
                    cb.perf_register(counter);
 | 
			
		||||
                }
 | 
			
		||||
                _ => {}
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -711,7 +723,7 @@ impl StaticCallbacks {
 | 
			
		|||
        unsafe {
 | 
			
		||||
            match (CB_SINGLETON.handler.as_mut(), counter.as_mut()) {
 | 
			
		||||
                (Some(cb), Some(counter)) => {
 | 
			
		||||
                    cb.perf_start_cb(counter);
 | 
			
		||||
                    cb.perf_start(counter);
 | 
			
		||||
                }
 | 
			
		||||
                _ => {}
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -721,7 +733,7 @@ impl StaticCallbacks {
 | 
			
		|||
        unsafe {
 | 
			
		||||
            match (CB_SINGLETON.handler.as_mut(), counter.as_mut()) {
 | 
			
		||||
                (Some(cb), Some(counter)) => {
 | 
			
		||||
                    cb.perf_stop_cb(counter);
 | 
			
		||||
                    cb.perf_stop(counter);
 | 
			
		||||
                }
 | 
			
		||||
                _ => {}
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -739,14 +751,21 @@ impl StaticCallbacks {
 | 
			
		|||
        }.unwrap_or_default()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // TODO: trait methods, etc.
 | 
			
		||||
    extern "C" fn hw_dummy_fn() {}
 | 
			
		||||
    extern "C" fn hw_get_proc_address_fn(_sym: *const c_char) -> ProcAddressFn {
 | 
			
		||||
        Self::hw_dummy_fn // FIXME: obvious hack
 | 
			
		||||
    extern "C" fn hw_get_proc_address_fn(sym: *const c_char) -> ProcAddressFn {
 | 
			
		||||
        unsafe {
 | 
			
		||||
            std::mem::transmute(
 | 
			
		||||
                CB_SINGLETON.handler.as_mut()
 | 
			
		||||
                    .and_then(|cb| cb.hw_get_proc_address(CStr::from_ptr(sym).to_str().unwrap()))
 | 
			
		||||
                    .unwrap_or(std::ptr::null())
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    // note: libretro.h claims this is obsolete
 | 
			
		||||
    // note: libretro.h claims this is obsolete, but (at least) paraLLEl-n64 uses it
 | 
			
		||||
    extern "C" fn hw_get_current_framebuffer_fn() -> usize {
 | 
			
		||||
        0
 | 
			
		||||
        unsafe {
 | 
			
		||||
            CB_SINGLETON.handler.as_mut()
 | 
			
		||||
                .and_then(|cb| cb.hw_get_current_framebuffer())
 | 
			
		||||
        }.unwrap_or_default()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -41,7 +41,8 @@ pub fn main() {
 | 
			
		|||
 | 
			
		||||
    let mut sdl_context = sdl2::init().unwrap();
 | 
			
		||||
 | 
			
		||||
    let sdl2_canvas = SimpleSdl2CanvasComponent::new(&mut sdl_context, emu.libretro_core());
 | 
			
		||||
    //let sdl2_canvas = SimpleSdl2CanvasComponent::new(&mut sdl_context, emu.libretro_core());
 | 
			
		||||
    let sdl2_canvas = SimpleSdl2OpenglComponent::new(&mut sdl_context, emu.libretro_core()).unwrap();
 | 
			
		||||
    emu.register_component(sdl2_canvas);
 | 
			
		||||
 | 
			
		||||
    let sdl2_audio = SimpleSdl2AudioComponent::new(&mut sdl_context, emu.libretro_core());
 | 
			
		||||
| 
						 | 
				
			
			@ -67,6 +68,7 @@ pub fn main() {
 | 
			
		|||
        emu.register_component(ffmpeg_comp);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    emu.init().unwrap();
 | 
			
		||||
    emu.load_game(&opt.rom).unwrap();
 | 
			
		||||
    if let Some(state) = opt.state {
 | 
			
		||||
        emu.unserialize_path(state).unwrap();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -36,10 +36,12 @@ pub type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
 | 
			
		|||
#[rustfmt::skip]
 | 
			
		||||
#[allow(unused_variables)]
 | 
			
		||||
pub trait RetroComponent: RetroCallbacks {
 | 
			
		||||
    fn pre_run(&mut self, retro: &mut LibretroWrapper) -> ControlFlow { ControlFlow::Continue }
 | 
			
		||||
    fn post_run(&mut self, retro: &mut LibretroWrapper) -> ControlFlow { ControlFlow::Continue }
 | 
			
		||||
    fn pre_init(&mut self, retro: &mut LibretroWrapper) -> Result<()> { Ok(()) }
 | 
			
		||||
    fn post_init(&mut self, retro: &mut LibretroWrapper) -> Result<()> { Ok(()) }
 | 
			
		||||
    fn pre_load_game(&mut self, retro: &mut LibretroWrapper, rom: &Path) -> Result<()> { Ok(()) }
 | 
			
		||||
    fn post_load_game(&mut self, retro: &mut LibretroWrapper, rom: &Path) -> Result<()> { Ok(()) }
 | 
			
		||||
    fn pre_run(&mut self, retro: &mut LibretroWrapper) -> ControlFlow { ControlFlow::Continue }
 | 
			
		||||
    fn post_run(&mut self, retro: &mut LibretroWrapper) -> ControlFlow { ControlFlow::Continue }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl RetroComponentBase {
 | 
			
		||||
| 
						 | 
				
			
			@ -68,10 +70,23 @@ impl RetroComponentBase {
 | 
			
		|||
 | 
			
		||||
        let mut pin_emu = Box::pin(emu);
 | 
			
		||||
        ferretro_base::retro::wrapper::set_handler(pin_emu.as_mut());
 | 
			
		||||
        pin_emu.retro.init();
 | 
			
		||||
        pin_emu
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn init(&mut self) -> Result<()> {
 | 
			
		||||
        for comp in &mut self.components {
 | 
			
		||||
            comp.pre_init(&mut self.retro)?;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        self.retro.init();
 | 
			
		||||
 | 
			
		||||
        for comp in &mut self.components {
 | 
			
		||||
            comp.post_init(&mut self.retro)?;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn register_component<T>(&mut self, comp: T) -> Option<()> // TODO: Result
 | 
			
		||||
        where T: RetroComponent
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -434,45 +449,45 @@ impl RetroCallbacks for RetroComponentBase {
 | 
			
		|||
            .fold(false, |x, y| x || y) // not "any" because we don't short-circuit
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn perf_get_time_usec_cb(&mut self) -> Time {
 | 
			
		||||
    fn perf_get_time_usec(&mut self) -> Time {
 | 
			
		||||
        self.components.first_mut()
 | 
			
		||||
            .map(|comp| comp.perf_get_time_usec_cb())
 | 
			
		||||
            .map(|comp| comp.perf_get_time_usec())
 | 
			
		||||
            .unwrap_or_default()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn perf_get_counter_cb(&mut self) -> PerfTick {
 | 
			
		||||
    fn perf_get_counter(&mut self) -> PerfTick {
 | 
			
		||||
        self.components.first_mut()
 | 
			
		||||
            .map(|comp| comp.perf_get_counter_cb())
 | 
			
		||||
            .map(|comp| comp.perf_get_counter())
 | 
			
		||||
            .unwrap_or_default()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn perf_get_cpu_features_cb(&mut self) -> u64 {
 | 
			
		||||
    fn perf_get_cpu_features(&mut self) -> u64 {
 | 
			
		||||
        self.components.first_mut()
 | 
			
		||||
            .map(|comp| comp.perf_get_cpu_features_cb())
 | 
			
		||||
            .map(|comp| comp.perf_get_cpu_features())
 | 
			
		||||
            .unwrap_or_default()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn perf_log_cb(&mut self) {
 | 
			
		||||
    fn perf_log(&mut self) {
 | 
			
		||||
         if let Some(comp) = self.components.first_mut() {
 | 
			
		||||
             comp.perf_log_cb()
 | 
			
		||||
             comp.perf_log()
 | 
			
		||||
         }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn perf_register_cb(&mut self, counter: &mut PerfCounter) {
 | 
			
		||||
    fn perf_register(&mut self, counter: &mut PerfCounter) {
 | 
			
		||||
         if let Some(comp) = self.components.first_mut() {
 | 
			
		||||
             comp.perf_register_cb(counter)
 | 
			
		||||
             comp.perf_register(counter)
 | 
			
		||||
         }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn perf_start_cb(&mut self, counter: &mut PerfCounter) {
 | 
			
		||||
    fn perf_start(&mut self, counter: &mut PerfCounter) {
 | 
			
		||||
         if let Some(comp) = self.components.first_mut() {
 | 
			
		||||
             comp.perf_start_cb(counter)
 | 
			
		||||
             comp.perf_start(counter)
 | 
			
		||||
         }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn perf_stop_cb(&mut self, counter: &mut PerfCounter) {
 | 
			
		||||
    fn perf_stop(&mut self, counter: &mut PerfCounter) {
 | 
			
		||||
         if let Some(comp) = self.components.first_mut() {
 | 
			
		||||
             comp.perf_stop_cb(counter)
 | 
			
		||||
             comp.perf_stop(counter)
 | 
			
		||||
         }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -489,6 +504,20 @@ impl RetroCallbacks for RetroComponentBase {
 | 
			
		|||
            .last()
 | 
			
		||||
            .unwrap_or_default()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn hw_get_current_framebuffer(&mut self) -> Option<usize> {
 | 
			
		||||
        self.components.iter_mut()
 | 
			
		||||
            .map(|comp| comp.hw_get_current_framebuffer())
 | 
			
		||||
            .flatten()
 | 
			
		||||
            .next()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn hw_get_proc_address(&mut self, sym: &str) -> Option<*const ()> {
 | 
			
		||||
        self.components.iter_mut()
 | 
			
		||||
            .map(|comp| comp.hw_get_proc_address(sym))
 | 
			
		||||
            .flatten()
 | 
			
		||||
            .next()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Drop for RetroComponentBase {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,5 +6,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, SystemAvInfo, SystemInfo};
 | 
			
		||||
    pub use ferretro_base::retro::ffi::{PixelFormat, GameGeometry, HwContextResetFn, HwRenderCallback, SystemAvInfo, SystemInfo};
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,7 +1,9 @@
 | 
			
		|||
mod canvas;
 | 
			
		||||
mod audio;
 | 
			
		||||
mod gamepad;
 | 
			
		||||
mod opengl;
 | 
			
		||||
 | 
			
		||||
pub use canvas::SimpleSdl2CanvasComponent;
 | 
			
		||||
pub use opengl::SimpleSdl2OpenglComponent;
 | 
			
		||||
pub use audio::SimpleSdl2AudioComponent;
 | 
			
		||||
pub use gamepad::SimpleSdl2GamepadComponent;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										106
									
								
								ferretro_components/src/provided/sdl2/opengl.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										106
									
								
								ferretro_components/src/provided/sdl2/opengl.rs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,106 @@
 | 
			
		|||
use crate::base::ControlFlow;
 | 
			
		||||
use crate::prelude::*;
 | 
			
		||||
 | 
			
		||||
use std::ffi::CStr;
 | 
			
		||||
use std::os::raw::c_uint;
 | 
			
		||||
 | 
			
		||||
use sdl2::Sdl;
 | 
			
		||||
use sdl2::video::{GLContext, Window};
 | 
			
		||||
 | 
			
		||||
pub struct SimpleSdl2OpenglComponent {
 | 
			
		||||
    window: Window,
 | 
			
		||||
    window_fbo: c_uint,
 | 
			
		||||
    gl_context: GLContext,
 | 
			
		||||
    pixel_format: sdl2::pixels::PixelFormatEnum,
 | 
			
		||||
    hw_context_reset_fn: Option<HwContextResetFn>,
 | 
			
		||||
    hw_context_destroy_fn: Option<HwContextResetFn>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl SimpleSdl2OpenglComponent {
 | 
			
		||||
    pub fn new(sdl_context: &mut Sdl, retro: &LibretroWrapper) -> Result<Self, Box<dyn std::error::Error>> {
 | 
			
		||||
        let sys_info = retro.get_system_info();
 | 
			
		||||
        let title = format!(
 | 
			
		||||
            "{} - ferretro",
 | 
			
		||||
            unsafe { CStr::from_ptr(sys_info.library_name) }.to_string_lossy()
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        let geometry = retro.get_system_av_info().geometry;
 | 
			
		||||
        let pixel_format = sdl2::pixels::PixelFormatEnum::ARGB1555;
 | 
			
		||||
 | 
			
		||||
        let video = sdl_context.video()?;
 | 
			
		||||
        let window = video
 | 
			
		||||
            .window(title.as_str(), geometry.base_width, geometry.base_height)
 | 
			
		||||
            .opengl()
 | 
			
		||||
            .build()?;
 | 
			
		||||
 | 
			
		||||
        // http://forums.libsdl.org/viewtopic.php?p=43353
 | 
			
		||||
        // likely to remain `0` on any platform that isn't iOS, but we'll do it anyhow
 | 
			
		||||
        let gl_context = window.gl_create_context()?;
 | 
			
		||||
        let mut window_fbo: c_uint = 0;
 | 
			
		||||
        unsafe {
 | 
			
		||||
            const GL_FRAMEBUFFER_BINDING: c_uint = 0x8CA6;
 | 
			
		||||
            #[allow(non_snake_case)]
 | 
			
		||||
            let glGetIntegerv: unsafe extern "C" fn(c_uint, *mut c_uint) = std::mem::transmute(
 | 
			
		||||
                video.gl_get_proc_address("glGetIntegerv")
 | 
			
		||||
            );
 | 
			
		||||
            glGetIntegerv(GL_FRAMEBUFFER_BINDING, &mut window_fbo);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Ok(SimpleSdl2OpenglComponent {
 | 
			
		||||
            window,
 | 
			
		||||
            window_fbo,
 | 
			
		||||
            gl_context,
 | 
			
		||||
            pixel_format,
 | 
			
		||||
            hw_context_reset_fn: None,
 | 
			
		||||
            hw_context_destroy_fn: None,
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl RetroCallbacks for SimpleSdl2OpenglComponent {
 | 
			
		||||
    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,
 | 
			
		||||
        };
 | 
			
		||||
        Some(true)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn set_hw_render(&mut self, hw_render_callback: &HwRenderCallback) -> Option<bool> {
 | 
			
		||||
        self.hw_context_reset_fn.replace(hw_render_callback.context_reset);
 | 
			
		||||
        self.hw_context_destroy_fn.replace(hw_render_callback.context_destroy);
 | 
			
		||||
 | 
			
		||||
        self.hw_context_reset_fn.map(|f| unsafe { f() });
 | 
			
		||||
 | 
			
		||||
        Some(true)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
    fn set_system_av_info(&mut self, av_info: &SystemAvInfo) -> Option<bool> {
 | 
			
		||||
        self.set_geometry(&av_info.geometry);
 | 
			
		||||
        Some(true)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn set_geometry(&mut self, geom: &GameGeometry) -> Option<bool> {
 | 
			
		||||
        let _ = self.canvas.window_mut().set_size(geom.base_width, geom.base_height);
 | 
			
		||||
        let _ = self.canvas.set_logical_size(geom.base_width, geom.base_height);
 | 
			
		||||
        Some(true)
 | 
			
		||||
    }
 | 
			
		||||
    */
 | 
			
		||||
 | 
			
		||||
    fn hw_get_current_framebuffer(&mut self) -> Option<usize> {
 | 
			
		||||
        Some(self.window_fbo as usize)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn hw_get_proc_address(&mut self, sym: &str) -> Option<*const ()> {
 | 
			
		||||
        Some(self.window.subsystem().gl_get_proc_address(sym))
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl RetroComponent for SimpleSdl2OpenglComponent {
 | 
			
		||||
    fn post_run(&mut self, _retro: &mut LibretroWrapper) -> ControlFlow {
 | 
			
		||||
        self.window.gl_swap_window();
 | 
			
		||||
        ControlFlow::Continue
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	Add table
		
		Reference in a new issue