Support 2D video_refresh in the SDL+GL component
...and alter the behavior of ThreadSleep component a bit.
This commit is contained in:
parent
0c5d0b5338
commit
71240de38c
|
@ -43,9 +43,8 @@ pub fn main() {
|
|||
|
||||
emu.register_component(StderrLogComponent { prefix: "{log} ".to_string() });
|
||||
|
||||
//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_ogl = SimpleSdl2OpenglComponent::new(&mut sdl_context, emu.libretro_core()).unwrap();
|
||||
emu.register_component(sdl2_ogl);
|
||||
|
||||
let sdl2_audio = SimpleSdl2AudioComponent::new(&mut sdl_context, emu.libretro_core());
|
||||
emu.register_component(sdl2_audio);
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
use crate::base::ControlFlow;
|
||||
use crate::prelude::*;
|
||||
|
||||
use std::ffi::CStr;
|
||||
|
@ -40,12 +39,12 @@ impl SimpleSdl2CanvasComponent {
|
|||
}
|
||||
}
|
||||
|
||||
impl RetroComponent for SimpleSdl2CanvasComponent {}
|
||||
impl RetroCallbacks for SimpleSdl2CanvasComponent {
|
||||
fn video_refresh(&mut self, data: &[u8], width: u32, height: u32, pitch: u32) {
|
||||
let rect = Rect::new(0, 0, width, height);
|
||||
|
||||
if let Ok(mut tex) =
|
||||
self.canvas
|
||||
if let Ok(mut tex) = self.canvas
|
||||
.texture_creator()
|
||||
.create_texture_static(self.pixel_format, width, height)
|
||||
{
|
||||
|
@ -54,6 +53,7 @@ impl RetroCallbacks for SimpleSdl2CanvasComponent {
|
|||
self.canvas.copy(&tex, None, None).unwrap();
|
||||
}
|
||||
}
|
||||
self.canvas.present();
|
||||
}
|
||||
|
||||
fn set_pixel_format(&mut self, pix_fmt: PixelFormat) -> Option<bool> {
|
||||
|
@ -83,10 +83,3 @@ impl RetroCallbacks for SimpleSdl2CanvasComponent {
|
|||
Some(true)
|
||||
}
|
||||
}
|
||||
|
||||
impl RetroComponent for SimpleSdl2CanvasComponent {
|
||||
fn post_run(&mut self, _retro: &mut LibretroWrapper) -> ControlFlow {
|
||||
self.canvas.present();
|
||||
ControlFlow::Continue
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
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};
|
||||
use sdl2::rect::Rect;
|
||||
use sdl2::render::WindowCanvas;
|
||||
|
||||
// TODO: get these from somewhere better without pulling in too much of a mess for the sdl2 feature
|
||||
const GL_FRAMEBUFFER_BINDING: c_uint = 0x8CA6;
|
||||
|
@ -13,9 +13,8 @@ const GL_COLOR_BUFFER_BIT: c_uint = 0x00004000;
|
|||
|
||||
#[allow(non_snake_case)]
|
||||
pub struct SimpleSdl2OpenglComponent {
|
||||
window: Window,
|
||||
canvas: WindowCanvas,
|
||||
window_fbo: c_uint,
|
||||
gl_context: GLContext,
|
||||
pixel_format: sdl2::pixels::PixelFormatEnum,
|
||||
hw_context_reset_fn: Option<HwContextResetFn>,
|
||||
hw_context_destroy_fn: Option<HwContextResetFn>,
|
||||
|
@ -49,15 +48,18 @@ impl SimpleSdl2OpenglComponent {
|
|||
std::mem::transmute(video.gl_get_proc_address("glClear"))
|
||||
};
|
||||
|
||||
let canvas = window.into_canvas()
|
||||
.accelerated()
|
||||
.target_texture()
|
||||
.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()?;
|
||||
// likely to remain `0` on any platform that isn't iOS, but we'll do it anyhow.
|
||||
// SDL_CreateRenderer, called by CanvasBuilder::build, creates a new GL Context.
|
||||
let window_fbo = unsafe { let mut fbo = 0; glGetIntegerv(GL_FRAMEBUFFER_BINDING, &mut fbo); fbo };
|
||||
|
||||
Ok(SimpleSdl2OpenglComponent {
|
||||
window,
|
||||
canvas,
|
||||
window_fbo,
|
||||
gl_context,
|
||||
pixel_format,
|
||||
hw_context_reset_fn: None,
|
||||
hw_context_destroy_fn: None,
|
||||
|
@ -72,7 +74,6 @@ impl SimpleSdl2OpenglComponent {
|
|||
#[allow(non_snake_case)]
|
||||
(self.glGetIntegerv)(GL_FRAMEBUFFER_BINDING, &mut fbo);
|
||||
}
|
||||
eprintln!("get_framebuffer_binding: {}", fbo);
|
||||
fbo
|
||||
}
|
||||
|
||||
|
@ -85,8 +86,25 @@ impl SimpleSdl2OpenglComponent {
|
|||
}
|
||||
}
|
||||
|
||||
impl RetroComponent for SimpleSdl2OpenglComponent {}
|
||||
impl RetroCallbacks for SimpleSdl2OpenglComponent {
|
||||
fn video_refresh(&mut self, data: &[u8], width: u32, height: u32, pitch: u32) {
|
||||
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)
|
||||
{
|
||||
if tex.update(rect, data, pitch as usize).is_ok() {
|
||||
self.canvas.clear();
|
||||
self.canvas.copy(&tex, None, None).unwrap();
|
||||
}
|
||||
}
|
||||
self.canvas.present();
|
||||
}
|
||||
|
||||
fn video_refresh_hw(&mut self, _width: c_uint, _height: c_uint) {
|
||||
self.canvas.present();
|
||||
unsafe { (self.glClear)(GL_COLOR_BUFFER_BIT); }
|
||||
}
|
||||
|
||||
|
@ -99,12 +117,11 @@ impl RetroCallbacks for SimpleSdl2OpenglComponent {
|
|||
Some(true)
|
||||
}
|
||||
|
||||
// TODO: depth, stencil, cache_context, bottom_left_origin?
|
||||
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.call_context_reset();
|
||||
|
||||
Some(true)
|
||||
}
|
||||
|
||||
|
@ -121,11 +138,29 @@ impl RetroCallbacks for SimpleSdl2OpenglComponent {
|
|||
}
|
||||
|
||||
fn set_geometry(&mut self, geom: &GameGeometry) -> Option<bool> {
|
||||
self.window.set_size(geom.base_width, geom.base_height).ok()?;
|
||||
self.call_context_destroy()?;
|
||||
self.gl_context = self.window.gl_create_context().ok()?;
|
||||
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);
|
||||
self.window_fbo = self.current_framebuffer_binding();
|
||||
/*
|
||||
let mut old_canvas = unsafe { MaybeUninit::uninit().assume_init() };
|
||||
std::mem::swap(&mut old_canvas, &mut self.canvas);
|
||||
|
||||
// no funny ? operators here because we've got uninitialized memory in self.canvas!
|
||||
let mut window = old_canvas.into_window();
|
||||
window.set_size(geom.base_width, geom.base_height).unwrap();
|
||||
self.call_context_destroy().unwrap();
|
||||
let mut new_canvas = window.into_canvas()
|
||||
.accelerated()
|
||||
.target_texture()
|
||||
.build()
|
||||
.unwrap();
|
||||
self.window_fbo = self.current_framebuffer_binding();
|
||||
|
||||
std::mem::swap(&mut self.canvas, &mut new_canvas);
|
||||
std::mem::forget(new_canvas);
|
||||
|
||||
self.call_context_reset()?;
|
||||
*/
|
||||
Some(true)
|
||||
}
|
||||
|
||||
|
@ -134,13 +169,12 @@ impl RetroCallbacks for SimpleSdl2OpenglComponent {
|
|||
}
|
||||
|
||||
fn hw_get_proc_address(&mut self, sym: &str) -> Option<*const ()> {
|
||||
Some(self.window.subsystem().gl_get_proc_address(sym))
|
||||
Some(self.canvas.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
|
||||
impl Drop for SimpleSdl2OpenglComponent {
|
||||
fn drop(&mut self) {
|
||||
self.call_context_destroy();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use std::os::raw::c_uint;
|
||||
use std::path::PathBuf;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
|
@ -5,8 +6,6 @@ use crate::base::ControlFlow;
|
|||
use crate::prelude::*;
|
||||
use ferretro_base::retro::ffi::{Message, Language};
|
||||
|
||||
use std::os::raw::c_uint;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct PathBufComponent {
|
||||
pub sys_path: Option<PathBuf>,
|
||||
|
@ -210,23 +209,49 @@ impl RetroCallbacks for StderrCallTraceComponent {
|
|||
}
|
||||
|
||||
pub struct SleepFramerateLimitComponent {
|
||||
did_sleep: bool,
|
||||
fps: f64,
|
||||
frame_begin: Instant,
|
||||
}
|
||||
|
||||
impl RetroComponent for SleepFramerateLimitComponent {
|
||||
fn pre_run(&mut self, _retro: &mut LibretroWrapper) -> ControlFlow {
|
||||
self.did_sleep = false;
|
||||
ControlFlow::Continue
|
||||
}
|
||||
fn post_run(&mut self, _retro: &mut LibretroWrapper) -> ControlFlow {
|
||||
if !self.did_sleep {
|
||||
self.do_sleep();
|
||||
}
|
||||
ControlFlow::Continue
|
||||
}
|
||||
}
|
||||
impl RetroCallbacks for SleepFramerateLimitComponent {
|
||||
fn video_refresh(&mut self, _data: &[u8], _width: c_uint, _height: c_uint, _pitch: c_uint) {
|
||||
self.do_sleep();
|
||||
}
|
||||
fn video_refresh_dupe(&mut self, _width: c_uint, _height: c_uint, _pitch: c_uint) {
|
||||
self.do_sleep();
|
||||
}
|
||||
fn video_refresh_hw(&mut self, _width: c_uint, _height: c_uint) {
|
||||
self.do_sleep();
|
||||
}
|
||||
fn set_system_av_info(&mut self, system_av_info: &SystemAvInfo) -> Option<bool> {
|
||||
self.fps = system_av_info.timing.fps;
|
||||
Some(true)
|
||||
}
|
||||
}
|
||||
|
||||
impl RetroComponent for SleepFramerateLimitComponent {
|
||||
fn pre_run(&mut self, _retro: &mut LibretroWrapper) -> ControlFlow {
|
||||
self.frame_begin = Instant::now();
|
||||
ControlFlow::Continue
|
||||
impl SleepFramerateLimitComponent {
|
||||
pub fn new(retro: &mut LibretroWrapper) -> Self {
|
||||
SleepFramerateLimitComponent {
|
||||
did_sleep: false,
|
||||
fps: retro.get_system_av_info().timing.fps,
|
||||
frame_begin: Instant::now(),
|
||||
}
|
||||
fn post_run(&mut self, _retro: &mut LibretroWrapper) -> ControlFlow {
|
||||
}
|
||||
|
||||
fn do_sleep(&mut self) {
|
||||
// similar hack to the sample rate, make sure we don't divide by zero.
|
||||
let mut spf = 1.0 / self.fps;
|
||||
if spf.is_nan() || spf.is_infinite() {
|
||||
|
@ -235,15 +260,8 @@ impl RetroComponent for SleepFramerateLimitComponent {
|
|||
Duration::from_secs_f64(spf)
|
||||
.checked_sub(self.frame_begin.elapsed())
|
||||
.map(std::thread::sleep);
|
||||
ControlFlow::Continue
|
||||
}
|
||||
}
|
||||
|
||||
impl SleepFramerateLimitComponent {
|
||||
pub fn new(retro: &mut LibretroWrapper) -> Self {
|
||||
SleepFramerateLimitComponent {
|
||||
fps: retro.get_system_av_info().timing.fps,
|
||||
frame_begin: Instant::now(),
|
||||
}
|
||||
self.did_sleep = true;
|
||||
self.frame_begin = Instant::now();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue