ferretro/ferretro_components/src/provided/sdl2/opengl.rs

129 lines
4.2 KiB
Rust
Raw Normal View History

use crate::base::ControlFlow;
use crate::prelude::*;
use std::ffi::CStr;
use std::os::raw::c_uint;
use sdl2::{Sdl, VideoSubsystem};
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 SDL GL",
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 window_fbo = Self::current_framebuffer_binding(&video);
Ok(SimpleSdl2OpenglComponent {
window,
window_fbo,
gl_context,
pixel_format,
hw_context_reset_fn: None,
hw_context_destroy_fn: None,
})
}
fn current_framebuffer_binding(video: &VideoSubsystem) -> c_uint {
let mut 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 fbo);
}
eprintln!("get_framebuffer_binding: {}", fbo);
fbo
}
fn call_context_reset(&self) -> Option<()> {
self.hw_context_reset_fn.map(|f| unsafe { f(); })
}
fn call_context_destroy(&self) -> Option<()> {
self.hw_context_destroy_fn.map(|f| unsafe { f(); })
}
}
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.call_context_reset();
Some(true)
}
fn get_variable(&mut self, key: &str) -> Option<String> {
match key {
"parallel-n64-gfxplugin" => Some("glide64".to_string()),
_ => None,
}
}
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> {
self.window.set_size(geom.base_width, geom.base_height).ok()?;
self.call_context_destroy()?;
self.gl_context = self.window.gl_create_context().ok()?;
self.window_fbo = Self::current_framebuffer_binding(self.window.subsystem());
self.call_context_reset()?;
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
}
}