refactor for resizable

This commit is contained in:
Alex Janka 2023-10-03 12:31:34 +11:00
parent 29a5c272b4
commit 5f7e7db307
4 changed files with 88 additions and 57 deletions

View file

@ -1,10 +1,10 @@
use pixels::{Pixels, SurfaceTexture};
use winit::window::Window;
pub struct WindowData {
pub struct Renderer {
pub pixels: Pixels,
}
impl WindowData {
impl Renderer {
pub fn new(factor: u32, window: &Window) -> Self {
let pixels = {
let window_size = window.inner_size();

View file

@ -9,7 +9,7 @@ use crate::window::ResolutionData;
use super::{
utils::{find_memorytype_index, record_submit_commandbuffer},
WindowDataManager,
RendererBackendManager,
};
#[derive(Clone, Debug, Copy)]
@ -37,7 +37,7 @@ pub(super) struct VulkanData {
}
impl VulkanData {
pub(super) unsafe fn new(manager: &WindowDataManager, surface: &SurfaceData) -> Self {
pub(super) unsafe fn new(manager: &RendererBackendManager, surface: &SurfaceData) -> Self {
let pdevices = manager
.instance
.enumerate_physical_devices()
@ -215,7 +215,7 @@ pub(super) struct SurfaceData {
}
impl SurfaceData {
pub(super) unsafe fn new(window: &Window, manager: &WindowDataManager) -> Self {
pub(super) unsafe fn new(window: &Window, manager: &RendererBackendManager) -> Self {
let surface = ash_window::create_surface(
&manager.entry,
&manager.instance,
@ -259,7 +259,7 @@ pub(super) struct SwapchainData {
impl SwapchainData {
pub(super) unsafe fn new(
resolutions: ResolutionData,
manager: &WindowDataManager,
manager: &RendererBackendManager,
surface: &SurfaceData,
vulkan: &VulkanData,

View file

@ -26,12 +26,12 @@ mod utils;
const SHADER: &[u8] = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/shaders/shader.spv"));
const VERTICES: [Vertex; 3] = [Vertex(-1.0, -1.0), Vertex(3.0, -1.0), Vertex(-1.0, 3.0)];
pub struct WindowDataManager {
pub struct RendererBackendManager {
entry: Entry,
instance: Instance,
}
impl WindowDataManager {
impl RendererBackendManager {
pub fn new(display_handle: RawDisplayHandle) -> Self {
let entry = Entry::linked();
let name = std::ffi::CString::new("gameboy").unwrap();
@ -71,28 +71,28 @@ impl WindowDataManager {
}
}
impl Drop for WindowDataManager {
impl Drop for RendererBackendManager {
fn drop(&mut self) {
unsafe { self.instance.destroy_instance(None) };
}
}
pub struct WindowData {
pub struct RendererBackend {
inner: VulkanWindowInner,
filter_chain: FilterChain,
manager: Arc<WindowDataManager>,
manager: Arc<RendererBackendManager>,
}
pub struct WindowOptions {
pub shader_path: PathBuf,
}
impl WindowData {
impl RendererBackend {
pub fn new(
resolutions: ResolutionData,
window: &Window,
options: WindowOptions,
manager: Arc<WindowDataManager>,
manager: Arc<RendererBackendManager>,
) -> Self {
let inner = unsafe { VulkanWindowInner::new(resolutions, window, manager.as_ref()) };
@ -129,23 +129,22 @@ impl WindowData {
unsafe { self.inner.new_frame(buffer) };
}
pub fn render(&mut self) {
unsafe { self.inner.render(&mut self.filter_chain) };
pub fn render(&mut self, resolutions: ResolutionData, manager: &RendererBackendManager) {
unsafe {
self.inner
.render(&mut self.filter_chain, resolutions, manager)
};
}
}
struct VulkanWindowInner {
vulkan_data: VulkanData,
vertex_input_buffer: vk::Buffer,
renderpass: vk::RenderPass,
pipeline_layout: vk::PipelineLayout,
graphics_pipelines: Vec<vk::Pipeline>,
shader_module: vk::ShaderModule,
vertex_input_buffer_memory: vk::DeviceMemory,
swapchain: SwapchainData,
surface: SurfaceData,
framebuffers: FramebufferData,
@ -155,7 +154,7 @@ impl VulkanWindowInner {
unsafe fn new(
resolutions: ResolutionData,
window: &Window,
manager: &WindowDataManager,
manager: &RendererBackendManager,
) -> Self {
let surface = SurfaceData::new(window, manager);
@ -411,7 +410,7 @@ impl VulkanWindowInner {
}
}
unsafe fn resize(&mut self, resolutions: ResolutionData, manager: &WindowDataManager) {
unsafe fn resize(&mut self, resolutions: ResolutionData, manager: &RendererBackendManager) {
self.swapchain.manual_drop(&self.vulkan_data);
for framebuffer in &self.framebuffers.framebuffers {
self.vulkan_data
@ -530,8 +529,13 @@ impl VulkanWindowInner {
}
#[allow(unused_variables, clippy::needless_pass_by_ref_mut)]
unsafe fn render(&mut self, filter_chain: &mut FilterChain) {
let (present_index, _) = self
unsafe fn render(
&mut self,
filter_chain: &mut FilterChain,
resolutions: ResolutionData,
manager: &RendererBackendManager,
) {
let (present_index, is_suboptimal) = self
.swapchain
.swapchain_loader
.acquire_next_image(
@ -541,6 +545,10 @@ impl VulkanWindowInner {
vk::Fence::null(),
)
.unwrap();
if is_suboptimal {
self.resize(resolutions, manager);
return;
}
let clear_values = [vk::ClearValue {
color: vk::ClearColorValue {
float32: [0.0, 0.0, 0.0, 0.0],

View file

@ -1,6 +1,6 @@
use std::{
collections::HashMap,
sync::{mpsc::Sender, Arc, Mutex},
sync::{mpsc::Sender, Arc, Mutex, RwLock},
};
use gb_emu_lib::connect::{EmulatorMessage, JoypadState, Renderer};
@ -22,9 +22,9 @@ use winit_input_helper::WinitInputHelper;
#[cfg_attr(feature = "vulkan", path = "renderer/vulkan/vulkan.rs")]
mod renderer;
use renderer::WindowData;
use renderer::RendererBackend;
use self::renderer::{WindowDataManager, WindowOptions};
use self::renderer::{RendererBackendManager, WindowOptions};
#[derive(Clone, Copy, Debug)]
pub struct ResolutionData {
@ -36,13 +36,19 @@ pub struct ResolutionData {
pub struct WindowInfo {
id: WindowId,
data: Arc<Mutex<WindowData>>,
data: Arc<WindowData>,
}
struct WindowData {
renderer: Mutex<RendererBackend>,
window: Window,
real_factor: RwLock<u32>,
}
pub struct WindowManager {
event_loop: EventLoop<()>,
windows: HashMap<WindowId, Arc<Mutex<WindowData>>>,
window_data_manager: Arc<WindowDataManager>,
windows: HashMap<WindowId, Arc<WindowData>>,
window_data_manager: Arc<RendererBackendManager>,
input: Arc<Mutex<WinitInputHelper>>,
sender: Sender<EmulatorMessage>,
}
@ -51,9 +57,10 @@ impl WindowManager {
pub(crate) fn new(sender: Sender<EmulatorMessage>) -> Self {
let event_loop = EventLoop::new();
#[cfg(feature = "vulkan")]
let window_data_manager = Arc::new(WindowDataManager::new(event_loop.raw_display_handle()));
let window_data_manager =
Arc::new(RendererBackendManager::new(event_loop.raw_display_handle()));
#[cfg(feature = "pixels")]
let window_data_manager = Arc::new(WindowDataManager::new());
let window_data_manager = Arc::new(RendererBackendManager::new());
Self {
event_loop,
windows: HashMap::new(),
@ -94,8 +101,19 @@ impl WindowManager {
}
Event::RedrawRequested(window_id) => {
if let Some(w) = self.windows.get(&window_id) {
if let Ok(mut data) = w.lock() {
data.render();
if let Ok(mut renderer) = w.renderer.lock() {
let inner_size = w.window.inner_size();
if let Ok(real_factor) = w.real_factor.read() {
renderer.render(
ResolutionData {
real_width: inner_size.width,
real_height: inner_size.height,
scaled_width: inner_size.width / *real_factor,
scaled_height: inner_size.height / *real_factor,
},
&self.window_data_manager,
);
}
}
}
}
@ -106,13 +124,11 @@ impl WindowManager {
}
pub struct WindowRenderer {
window: Window,
data: Arc<WindowData>,
input: Arc<Mutex<WinitInputHelper>>,
data: Arc<Mutex<WindowData>>,
width: usize,
height: usize,
factor: usize,
real_factor: u32,
gamepad_handler: Option<Gilrs>,
joypad_state: JoypadState,
current_rumble: bool,
@ -124,7 +140,7 @@ impl WindowRenderer {
gamepad_handler: Option<Gilrs>,
input: Arc<Mutex<WinitInputHelper>>,
event_loop: &EventLoop<()>,
manager: Arc<WindowDataManager>,
manager: Arc<RendererBackendManager>,
) -> (Self, WindowInfo) {
let window = WindowBuilder::new()
.with_title("Gameboy")
@ -147,26 +163,27 @@ impl WindowRenderer {
),
};
let data = Arc::new(Mutex::new(WindowData::new(
resolutions,
&window,
options,
manager,
)));
let renderer = Mutex::new(RendererBackend::new(resolutions, &window, options, manager));
let id = window.id();
let data = Arc::new(WindowData {
renderer,
window,
real_factor: RwLock::new(real_factor),
});
let info = WindowInfo {
id: window.id(),
id,
data: data.clone(),
};
(
Self {
window,
input,
data,
input,
width: 0,
height: 0,
factor,
real_factor,
gamepad_handler,
joypad_state: JoypadState::default(),
current_rumble: false,
@ -180,12 +197,18 @@ impl Renderer<[u8; 4]> for WindowRenderer {
fn prepare(&mut self, width: usize, height: usize) {
self.width = width;
self.height = height;
self.real_factor = (self.window.scale_factor() * self.factor as f64) as u32;
let real_width = (width as u32) * self.real_factor;
let real_height = (height as u32) * self.real_factor;
let real_factor = (self.data.window.scale_factor() * self.factor as f64) as u32;
self.window
let real_width = (width as u32) * real_factor;
let real_height = (height as u32) * real_factor;
if let Ok(mut f) = self.data.real_factor.write() {
*f = real_factor;
}
self.data
.window
.set_inner_size(PhysicalSize::new(real_width, real_height));
let resolutions = ResolutionData {
@ -195,21 +218,21 @@ impl Renderer<[u8; 4]> for WindowRenderer {
scaled_height: height as u32,
};
if let Ok(mut data) = self.data.lock() {
data.resize(resolutions, &self.window);
if let Ok(mut data) = self.data.renderer.lock() {
data.resize(resolutions, &self.data.window);
}
self.window.request_redraw();
self.data.window.request_redraw();
}
fn display(&mut self, buffer: &[[u8; 4]]) {
if let Ok(mut data) = self.data.lock() {
if let Ok(mut data) = self.data.renderer.lock() {
data.new_frame(buffer);
}
self.window.request_redraw();
self.data.window.request_redraw();
}
fn set_title(&mut self, title: String) {
self.window.set_title(&title);
self.data.window.set_title(&title);
}
fn latest_joypad_state(&mut self) -> JoypadState {