From 2f653746942117e7940f8a708a3c65f90a7a83b8 Mon Sep 17 00:00:00 2001 From: Putta Khunchalee Date: Sat, 23 Nov 2024 20:00:30 +0700 Subject: [PATCH] Merges VMM screen into graphics module (#1134) --- gui/core.h | 11 ---- gui/core.hpp | 9 --- gui/main_window.cpp | 43 ------------- gui/main_window.hpp | 2 - gui/src/{screen => graphics}/metal/buffer.rs | 2 +- gui/src/graphics/metal/mod.rs | 21 +++++-- .../metal/mod.rs => graphics/metal/screen.rs} | 6 +- gui/src/graphics/mod.rs | 10 +-- gui/src/{screen => graphics}/vulkan/buffer.rs | 2 +- gui/src/graphics/vulkan/mod.rs | 61 +++++++++++-------- .../mod.rs => graphics/vulkan/screen.rs} | 6 +- gui/src/lib.rs | 1 - gui/src/main.rs | 59 ++++++++---------- gui/src/screen/mod.rs | 16 ----- gui/src/vmm/ffi.rs | 17 ------ gui/src/vmm/mod.rs | 24 +++----- 16 files changed, 95 insertions(+), 195 deletions(-) rename gui/src/{screen => graphics}/metal/buffer.rs (83%) rename gui/src/{screen/metal/mod.rs => graphics/metal/screen.rs} (95%) rename gui/src/{screen => graphics}/vulkan/buffer.rs (83%) rename gui/src/{screen/vulkan/mod.rs => graphics/vulkan/screen.rs} (96%) delete mode 100644 gui/src/screen/mod.rs delete mode 100644 gui/src/vmm/ffi.rs diff --git a/gui/core.h b/gui/core.h index 691a25233..6113919c6 100644 --- a/gui/core.h +++ b/gui/core.h @@ -51,11 +51,6 @@ struct Profile; */ struct RustError; -/** - * Manage a virtual machine that run the kernel. - */ -struct Vmm; - #ifdef __cplusplus extern "C" { #endif // __cplusplus @@ -130,12 +125,6 @@ struct RustError *update_firmware(const char *root, void *cx, void (*status)(const char*, uint64_t, uint64_t, void*)); -void vmm_free(struct Vmm *vmm); - -void vmm_shutdown(struct Vmm *vmm); - -bool vmm_shutting_down(struct Vmm *vmm); - #ifdef __cplusplus } // extern "C" #endif // __cplusplus diff --git a/gui/core.hpp b/gui/core.hpp index debd951c7..160b72051 100644 --- a/gui/core.hpp +++ b/gui/core.hpp @@ -122,12 +122,3 @@ inline void Rust::free() m_ptr = nullptr; } } - -template<> -inline void Rust::free() -{ - if (m_ptr) { - vmm_free(m_ptr); - m_ptr = nullptr; - } -} diff --git a/gui/main_window.cpp b/gui/main_window.cpp index c116176ad..3646c1acb 100644 --- a/gui/main_window.cpp +++ b/gui/main_window.cpp @@ -218,26 +218,6 @@ void MainWindow::closeEvent(QCloseEvent *event) // This will set to accept by QMainWindow::closeEvent. event->ignore(); - // Ask user to confirm. - if (m_vmm) { - // Ask user to confirm only if we did not shutdown the VMM programmatically. - if (!vmm_shutting_down(m_vmm)) { - QMessageBox confirm(this); - - confirm.setText("Do you want to exit?"); - confirm.setInformativeText("The running game will be terminated."); - confirm.setStandardButtons(QMessageBox::Cancel | QMessageBox::Yes); - confirm.setDefaultButton(QMessageBox::Cancel); - confirm.setIcon(QMessageBox::Warning); - - if (confirm.exec() != QMessageBox::Yes) { - return; - } - } - - killVmm(); - } - // Save geometry. QSettings settings; @@ -484,27 +464,6 @@ void MainWindow::startDebug(const QString &addr) } } -bool MainWindow::requireVmmStopped() -{ - if (m_vmm) { - QMessageBox prompt(this); - - prompt.setText("Action requires VMM to be stopped to continue."); - prompt.setInformativeText("Do you want to kill the VMM?"); - prompt.setStandardButtons(QMessageBox::Cancel | QMessageBox::Yes); - prompt.setDefaultButton(QMessageBox::Cancel); - prompt.setIcon(QMessageBox::Warning); - - if (prompt.exec() != QMessageBox::Yes) { - return false; - } - - killVmm(); - } - - return true; -} - void MainWindow::stopDebug() { // We can't free the VMM here because the thread that trigger this method are waiting @@ -525,8 +484,6 @@ void MainWindow::stopDebug() void MainWindow::killVmm() { - m_vmm.free(); - delete m_debugNoti; m_debugNoti = nullptr; } diff --git a/gui/main_window.hpp b/gui/main_window.hpp index ec1f0e11f..1d377d6b5 100644 --- a/gui/main_window.hpp +++ b/gui/main_window.hpp @@ -46,7 +46,6 @@ private slots: void vmmError(const QString &msg); void waitKernelExit(bool success); bool loadGame(const QString &gameId); - bool requireVmmStopped(); void stopDebug(); void killVmm(); @@ -58,7 +57,6 @@ private slots: Screen *m_screen; Rust m_debugServer; QSocketNotifier *m_debugNoti; - Rust m_vmm; // Destroy first. }; namespace Args { diff --git a/gui/src/screen/metal/buffer.rs b/gui/src/graphics/metal/buffer.rs similarity index 83% rename from gui/src/screen/metal/buffer.rs rename to gui/src/graphics/metal/buffer.rs index af375c752..2fc55b1cc 100644 --- a/gui/src/screen/metal/buffer.rs +++ b/gui/src/graphics/metal/buffer.rs @@ -1,4 +1,4 @@ -use super::ScreenBuffer; +use crate::graphics::ScreenBuffer; /// Manages Metal off-screen buffers. pub struct MetalBuffer {} diff --git a/gui/src/graphics/metal/mod.rs b/gui/src/graphics/metal/mod.rs index cccc5b45b..b8f313580 100644 --- a/gui/src/graphics/metal/mod.rs +++ b/gui/src/graphics/metal/mod.rs @@ -1,18 +1,23 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 +use self::screen::MetalScreen; +use super::Graphics; use metal::Device; use std::ops::Deref; use thiserror::Error; +mod buffer; +mod screen; + pub struct Metal { devices: Vec, } -impl super::GraphicsApi for Metal { +impl Graphics for Metal { + type Err = MetalError; type PhysicalDevice = metal::Device; + type Screen = MetalScreen; - type CreateError = MetalCreateError; - - fn new() -> Result { + fn new() -> Result { Ok(Self { devices: Device::all(), }) @@ -21,6 +26,10 @@ impl super::GraphicsApi for Metal { fn physical_devices(&self) -> &[Self::PhysicalDevice] { &self.devices } + + fn create_screen(&mut self) -> Result { + todo!() + } } impl super::PhysicalDevice for metal::Device { @@ -29,6 +38,6 @@ impl super::PhysicalDevice for metal::Device { } } -/// Represents an error when [`Metal::new()`] fails. +/// Implementation of [`Graphics::Err`] for Metal. #[derive(Debug, Error)] -pub enum MetalCreateError {} +pub enum MetalError {} diff --git a/gui/src/screen/metal/mod.rs b/gui/src/graphics/metal/screen.rs similarity index 95% rename from gui/src/screen/metal/mod.rs rename to gui/src/graphics/metal/screen.rs index 7aae6e532..831eae1ac 100644 --- a/gui/src/screen/metal/mod.rs +++ b/gui/src/graphics/metal/screen.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 -use self::buffer::MetalBuffer; -use crate::graphics::{Screen, ScreenBuffer}; +use super::buffer::MetalBuffer; +use crate::graphics::Screen; use crate::vmm::VmmScreen; use metal::{CAMetalLayer, Device, MetalLayer}; use objc::runtime::{Object, NO, YES}; @@ -9,8 +9,6 @@ use std::ptr::null_mut; use std::sync::Arc; use thiserror::Error; -mod buffer; - /// Implementation of [`Screen`] using Metal. /// /// Fields in this struct need to be dropped in a correct order. diff --git a/gui/src/graphics/mod.rs b/gui/src/graphics/mod.rs index 1024658c1..0b8c08112 100644 --- a/gui/src/graphics/mod.rs +++ b/gui/src/graphics/mod.rs @@ -13,14 +13,14 @@ pub type DefaultApi = self::engine::Vulkan; pub type DefaultApi = self::engine::Metal; /// The underlying graphics engine (e.g. Vulkan). -pub trait GraphicsApi: Sized + 'static { +pub trait Graphics: Sized + 'static { + type Err: Error; type PhysicalDevice: PhysicalDevice; + type Screen: Screen; - type CreateError: core::error::Error; - - fn new() -> Result; - + fn new() -> Result; fn physical_devices(&self) -> &[Self::PhysicalDevice]; + fn create_screen(&mut self) -> Result; } pub trait PhysicalDevice: Sized { diff --git a/gui/src/screen/vulkan/buffer.rs b/gui/src/graphics/vulkan/buffer.rs similarity index 83% rename from gui/src/screen/vulkan/buffer.rs rename to gui/src/graphics/vulkan/buffer.rs index 7a1bcdfd7..6744c7e2a 100644 --- a/gui/src/screen/vulkan/buffer.rs +++ b/gui/src/graphics/vulkan/buffer.rs @@ -1,4 +1,4 @@ -use super::ScreenBuffer; +use crate::graphics::ScreenBuffer; /// Manages Vulkan off-screen buffers. pub struct VulkanBuffer {} diff --git a/gui/src/graphics/vulkan/mod.rs b/gui/src/graphics/vulkan/mod.rs index 5f5aacbec..5e64d7092 100644 --- a/gui/src/graphics/vulkan/mod.rs +++ b/gui/src/graphics/vulkan/mod.rs @@ -1,20 +1,25 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 +use self::screen::VulkanScreen; +use super::Graphics; use ash::vk::{ApplicationInfo, InstanceCreateInfo}; use std::ffi::CStr; use thiserror::Error; +mod buffer; +mod screen; + pub struct Vulkan { entry: ash::Entry, instance: ash::Instance, devices: Vec, } -impl super::GraphicsApi for Vulkan { +impl Graphics for Vulkan { + type Err = VulkanError; type PhysicalDevice = VulkanPhysicalDevice; + type Screen = VulkanScreen; - type CreateError = VulkanCreateError; - - fn new() -> Result { + fn new() -> Result { let entry = ash::Entry::linked(); let app_info = ApplicationInfo::default().application_name(c"Obliteration"); @@ -22,30 +27,28 @@ impl super::GraphicsApi for Vulkan { let create_info = InstanceCreateInfo::default().application_info(&app_info); let instance = unsafe { entry.create_instance(&create_info, None) } - .map_err(VulkanCreateError::CreateInstanceFailed)?; + .map_err(VulkanError::CreateInstanceFailed)?; let devices = unsafe { instance.enumerate_physical_devices() } - .map_err(VulkanCreateError::EnumeratePhysicalDevicesFailed)? + .map_err(VulkanError::EnumeratePhysicalDevicesFailed)? .into_iter() - .map( - |device| -> Result { - let properties = unsafe { instance.get_physical_device_properties(device) }; - - let name = CStr::from_bytes_until_nul(unsafe { - std::slice::from_raw_parts( - properties.device_name.as_ptr().cast(), - properties.device_name.len(), - ) - }) - .map_err(|_| VulkanCreateError::DeviceNameInvalid)? - .to_str() - .map_err(VulkanCreateError::DeviceNameInvalidUtf8)? - .to_owned(); - - Ok(VulkanPhysicalDevice { device, name }) - }, - ) - .collect::>()?; + .map(|device| -> Result { + let properties = unsafe { instance.get_physical_device_properties(device) }; + + let name = CStr::from_bytes_until_nul(unsafe { + std::slice::from_raw_parts( + properties.device_name.as_ptr().cast(), + properties.device_name.len(), + ) + }) + .map_err(|_| VulkanError::DeviceNameInvalid)? + .to_str() + .map_err(VulkanError::DeviceNameInvalidUtf8)? + .to_owned(); + + Ok(VulkanPhysicalDevice { device, name }) + }) + .collect::>()?; Ok(Self { entry, @@ -57,6 +60,10 @@ impl super::GraphicsApi for Vulkan { fn physical_devices(&self) -> &[Self::PhysicalDevice] { &self.devices } + + fn create_screen(&mut self) -> Result { + todo!() + } } impl Drop for Vulkan { @@ -76,9 +83,9 @@ impl super::PhysicalDevice for VulkanPhysicalDevice { } } -/// Represents an error when [`Vulkan::new()`] fails. +/// Implementation of [`Graphics::Err`] for Vulkan. #[derive(Debug, Error)] -pub enum VulkanCreateError { +pub enum VulkanError { #[error("couldn't create Vulkan instance")] CreateInstanceFailed(#[source] ash::vk::Result), diff --git a/gui/src/screen/vulkan/mod.rs b/gui/src/graphics/vulkan/screen.rs similarity index 96% rename from gui/src/screen/vulkan/mod.rs rename to gui/src/graphics/vulkan/screen.rs index 23d8e40cd..c7f0e1b68 100644 --- a/gui/src/screen/vulkan/mod.rs +++ b/gui/src/graphics/vulkan/screen.rs @@ -1,14 +1,12 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 -use self::buffer::VulkanBuffer; -use crate::graphics::{Screen, ScreenBuffer}; +use super::buffer::VulkanBuffer; +use crate::graphics::Screen; use crate::vmm::VmmScreen; use ash::vk::{DeviceCreateInfo, DeviceQueueCreateInfo, Handle, QueueFlags}; use ash::Device; use std::sync::Arc; use thiserror::Error; -mod buffer; - /// Implementation of [`Screen`] using Vulkan. pub struct VulkanScreen { buffer: Arc, diff --git a/gui/src/lib.rs b/gui/src/lib.rs index 9d036a7f3..d02f61265 100644 --- a/gui/src/lib.rs +++ b/gui/src/lib.rs @@ -8,7 +8,6 @@ mod hv; mod param; mod pkg; mod profile; -mod screen; mod string; mod system; mod vmm; diff --git a/gui/src/main.rs b/gui/src/main.rs index 9b03cd0be..69438483e 100644 --- a/gui/src/main.rs +++ b/gui/src/main.rs @@ -1,10 +1,9 @@ #![windows_subsystem = "windows"] -use self::graphics::{GraphicsApi, PhysicalDevice, Screen}; +use self::graphics::{Graphics, PhysicalDevice, Screen}; use self::profile::Profile; -use self::screen::DefaultScreen; use self::ui::ErrorDialog; -use self::vmm::{Vmm, VmmEvent}; +use self::vmm::VmmEvent; use args::CliArgs; use clap::Parser; use debug::DebugServer; @@ -25,7 +24,6 @@ mod pkg; mod profile; #[cfg(unix)] mod rlim; -mod screen; mod string; mod system; mod ui; @@ -47,10 +45,16 @@ fn run() -> Result<(), ApplicationError> { #[cfg(unix)] rlim::set_rlimit_nofile().map_err(ApplicationError::FdLimit)?; + // Initialize graphics engine. + let mut graphics = match graphics::DefaultApi::new() { + Ok(v) => v, + Err(e) => return Err(ApplicationError::InitGraphics(Box::new(e))), + }; + // TODO: check if already configured and skip wizard run_wizard().map_err(ApplicationError::RunWizard)?; - let vmm = if let Some(debug_addr) = args.debug_addr() { + let args = if let Some(debug_addr) = args.debug_addr() { let kernel_path = get_kernel_path(&args)?; let debug_server = DebugServer::new(debug_addr) @@ -60,9 +64,6 @@ fn run() -> Result<(), ApplicationError> { .accept() .map_err(ApplicationError::CreateDebugClient)?; - let _graphics_api = - graphics::DefaultApi::new().map_err(ApplicationError::InitGraphicsApi)?; - let profiles = load_profiles()?; // TODO: handle events @@ -73,29 +74,24 @@ fn run() -> Result<(), ApplicationError> { VmmEvent::Error { reason } => {} }; - let vmm = Vmm::new( - kernel_path, - todo!(), - &profiles[0], - Some(debug_client), - event_handler, - ) - .map_err(ApplicationError::RunVmm)?; - todo!() } else { - run_launcher()? + run_launcher(&graphics)? }; - let Some(vmm) = vmm else { + let Some(args) = args else { return Ok(()); }; // Setup VMM screen. - let mut screen = DefaultScreen::new().map_err(ApplicationError::CreateScreen)?; + let mut screen = graphics + .create_screen() + .map_err(|e| ApplicationError::CreateScreen(Box::new(e)))?; // TODO: Start VMM. - screen.run().map_err(ApplicationError::RunScreen)?; + screen + .run() + .map_err(|e| ApplicationError::RunScreen(Box::new(e)))?; Ok(()) } @@ -107,7 +103,7 @@ fn load_profiles() -> Result, ApplicationError> { Ok(profiles) } -fn run_launcher() -> Result, ApplicationError> { +fn run_launcher(graphics: &impl Graphics) -> Result, ApplicationError> { // Create window and register callback handlers. let win = ui::MainWindow::new().map_err(ApplicationError::CreateMainWindow)?; let start = Rc::new(RefCell::new(false)); @@ -122,8 +118,6 @@ fn run_launcher() -> Result, ApplicationError> { } }); - let graphics_api = graphics::DefaultApi::new().map_err(ApplicationError::InitGraphicsApi)?; - let profiles = load_profiles()?; setup_globals(&win); @@ -137,7 +131,7 @@ fn run_launcher() -> Result, ApplicationError> { win.set_profiles(profiles); let physical_devices = ModelRc::new(VecModel::from_iter( - graphics_api + graphics .physical_devices() .iter() .map(|p| SharedString::from(p.name())), @@ -274,6 +268,10 @@ fn run_wizard() -> Result<(), slint::PlatformError> { }) } +/// Encapsulates arguments for [`Vmm::new()`]. +struct VmmArgs {} + +/// Represents an error when [`run()`] fails. #[derive(Debug, Error)] enum ApplicationError { #[error(transparent)] @@ -301,18 +299,15 @@ enum ApplicationError { #[error("failed to create main window")] CreateMainWindow(#[source] slint::PlatformError), - #[error("failed to initialize graphics API")] - InitGraphicsApi(#[source] ::CreateError), - - #[error("failed to run vmm")] - RunVmm(#[source] vmm::VmmError), + #[error("couldn't initialize graphics engine")] + InitGraphics(#[source] Box), #[error("failed to run main window")] RunMainWindow(#[source] slint::PlatformError), #[error("couldn't create VMM screen")] - CreateScreen(#[source] screen::ScreenError), + CreateScreen(#[source] Box), #[error("couldn't run VMM screen")] - RunScreen(#[source] ::RunErr), + RunScreen(#[source] Box), } diff --git a/gui/src/screen/mod.rs b/gui/src/screen/mod.rs deleted file mode 100644 index 0a0d14083..000000000 --- a/gui/src/screen/mod.rs +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -#[cfg_attr(target_os = "macos", path = "metal/mod.rs")] -#[cfg_attr(not(target_os = "macos"), path = "vulkan/mod.rs")] -mod engine; - -#[cfg(not(target_os = "macos"))] -pub type DefaultScreen = self::engine::VulkanScreen; - -#[cfg(target_os = "macos")] -pub type DefaultScreen = self::engine::MetalScreen; - -#[cfg(not(target_os = "macos"))] -pub type ScreenError = self::engine::VulkanScreenError; - -#[cfg(target_os = "macos")] -pub type ScreenError = self::engine::MetalError; diff --git a/gui/src/vmm/ffi.rs b/gui/src/vmm/ffi.rs deleted file mode 100644 index b44a960be..000000000 --- a/gui/src/vmm/ffi.rs +++ /dev/null @@ -1,17 +0,0 @@ -use super::Vmm; -use std::sync::atomic::Ordering; - -#[no_mangle] -pub unsafe extern "C" fn vmm_free(vmm: *mut Vmm) { - drop(Box::from_raw(vmm)); -} - -#[no_mangle] -pub unsafe extern "C" fn vmm_shutdown(vmm: *mut Vmm) { - (*vmm).shutdown.store(true, Ordering::Relaxed); -} - -#[no_mangle] -pub unsafe extern "C" fn vmm_shutting_down(vmm: *mut Vmm) -> bool { - (*vmm).shutdown.load(Ordering::Relaxed) -} diff --git a/gui/src/vmm/mod.rs b/gui/src/vmm/mod.rs index b40d3a03b..b6fa3b57b 100644 --- a/gui/src/vmm/mod.rs +++ b/gui/src/vmm/mod.rs @@ -18,7 +18,7 @@ use kernel::{KernelError, ProgramHeaderError}; use obconf::{BootEnv, ConsoleType, Vm}; use std::cmp::max; use std::error::Error; -use std::ffi::{c_char, CStr}; +use std::ffi::CStr; use std::io::Read; use std::num::NonZero; use std::path::{Path, PathBuf}; @@ -31,8 +31,6 @@ use thiserror::Error; mod arch; mod cpu; mod debug; -#[cfg(feature = "qt")] -mod ffi; mod hw; mod kernel; mod ram; @@ -60,23 +58,17 @@ fn get_page_size() -> Result, std::io::Error> { } /// Manage a virtual machine that run the kernel. -pub struct Vmm { - cpu: CpuManager, // Drop first. - screen: crate::screen::DefaultScreen, - gdb: Option< - GdbStubStateMachine< - 'static, - CpuManager, - DebugClient, - >, - >, +pub struct Vmm { + cpu: CpuManager, // Drop first. + screen: S, + gdb: Option, DebugClient>>, shutdown: Arc, } -impl Vmm { +impl Vmm { pub fn new( kernel_path: impl AsRef, - screen: crate::screen::DefaultScreen, + screen: S, profile: &Profile, debugger: Option, event_handler: impl Fn(VmmEvent) + Send + Sync + 'static, @@ -398,7 +390,7 @@ impl Vmm { } } -impl Drop for Vmm { +impl Drop for Vmm { fn drop(&mut self) { // Set shutdown flag before dropping the other fields so their background thread can stop // before they try to join with it.