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 pixels::{Pixels, SurfaceTexture};
use winit::window::Window; use winit::window::Window;
pub struct WindowData { pub struct Renderer {
pub pixels: Pixels, pub pixels: Pixels,
} }
impl WindowData { impl Renderer {
pub fn new(factor: u32, window: &Window) -> Self { pub fn new(factor: u32, window: &Window) -> Self {
let pixels = { let pixels = {
let window_size = window.inner_size(); let window_size = window.inner_size();

View file

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

View file

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

View file

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