Skip to content

Commit

Permalink
move to separate crate
Browse files Browse the repository at this point in the history
  • Loading branch information
tompro committed Nov 13, 2024
1 parent c79d76d commit fff77c4
Show file tree
Hide file tree
Showing 11 changed files with 173 additions and 140 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ members = [
"kernel",
"macros",
"src/fs",
"src/graphics",
"src/llt",
"src/obconf",
"src/param",
Expand Down
1 change: 1 addition & 0 deletions gui/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ obconf = { path = "../src/obconf", features = ["serde", "virt"] }
obfw = { git = "https://github.com/obhq/firmware-dumper.git", features = ["read", "std"] }
param = { path = "../src/param" }
pkg = { path = "../src/pkg" }
graphics = { path = "../src/graphics" }
ciborium = "0.2.2"
serde = { version = "1.0.209", features = ["derive"] }
thiserror = "1.0"
Expand Down
6 changes: 3 additions & 3 deletions gui/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use args::CliArgs;
use clap::Parser;
use debug::DebugServer;
use screen::{GraphicsApi, PhysicalDevice};
use graphics::{GraphicsApi, PhysicalDevice};
use slint::{ComponentHandle, ModelExt, ModelRc, SharedString, VecModel};
use std::process::{ExitCode, Termination};
use thiserror::Error;
Expand Down Expand Up @@ -71,7 +71,7 @@ impl App {
fn new() -> Result<Self, ApplicationError> {
let main_window = ui::MainWindow::new().map_err(ApplicationError::CreateMainWindow)?;

let graphics_api = screen::DefaultApi::init().map_err(ApplicationError::InitGraphicsApi)?;
let graphics_api = graphics::DefaultApi::init().map_err(ApplicationError::InitGraphicsApi)?;

let devices: Vec<SharedString> = graphics_api
.enumerate_physical_devices()
Expand Down Expand Up @@ -184,7 +184,7 @@ pub enum ApplicationError {
CreateMainWindow(#[source] slint::PlatformError),

#[error("failed to initialize graphics API")]
InitGraphicsApi(#[source] <screen::DefaultApi as GraphicsApi>::InitError),
InitGraphicsApi(#[source] <graphics::DefaultApi as GraphicsApi>::InitError),

#[error("failed to run main window")]
RunMainWindow(#[source] slint::PlatformError),
Expand Down
30 changes: 0 additions & 30 deletions gui/src/screen/metal/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,32 +11,6 @@ use thiserror::Error;

mod buffer;

pub struct Metal {
devices: Vec<metal::Device>,
}

impl super::GraphicsApi for Metal {
type PhysicalDevice = metal::Device;

type InitError = MetalInitError;

fn init() -> Result<Self, Self::InitError> {
Ok(Self {
devices: Device::all(),
})
}

fn enumerate_physical_devices(&self) -> &[Self::PhysicalDevice] {
&self.devices
}
}

impl super::PhysicalDevice for metal::Device {
fn name(&self) -> &str {
self.name()
}
}

/// Implementation of [`Screen`] using Metal.
///
/// Fields in this struct need to be dropped in a correct order.
Expand Down Expand Up @@ -96,10 +70,6 @@ impl Screen for MetalScreen {
}
}

/// Represents an error when [`Metal::init()`] fails.
#[derive(Debug, Error)]
pub enum MetalInitError {}

/// Represents an error when [`MetalScreen::new()`] fails.
#[derive(Debug, Error)]
pub enum MetalError {
Expand Down
20 changes: 0 additions & 20 deletions gui/src/screen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,6 @@ use std::sync::Arc;
#[cfg_attr(not(target_os = "macos"), path = "vulkan/mod.rs")]
mod engine;

#[cfg(not(target_os = "macos"))]
pub type DefaultApi = self::engine::Vulkan;

#[cfg(target_os = "macos")]
pub type DefaultApi = self::engine::Metal;

#[cfg(not(target_os = "macos"))]
pub type Default = self::engine::VulkanScreen;

Expand All @@ -24,20 +18,6 @@ pub type ScreenError = self::engine::VulkanScreenError;
#[cfg(target_os = "macos")]
pub type ScreenError = self::engine::MetalError;

pub trait GraphicsApi: Sized + 'static {
type PhysicalDevice: PhysicalDevice;

type InitError: Error;

fn init() -> Result<Self, Self::InitError>;

fn enumerate_physical_devices(&self) -> &[Self::PhysicalDevice];
}

pub trait PhysicalDevice: Sized {
fn name(&self) -> &str;
}

/// Encapsulates a platform-specific surface for drawing a VM screen.
pub trait Screen: 'static {
type Buffer: ScreenBuffer;
Expand Down
87 changes: 1 addition & 86 deletions gui/src/screen/vulkan/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,84 +3,15 @@ use self::buffer::VulkanBuffer;
use super::{Screen, ScreenBuffer};
use crate::vmm::VmmScreen;
use ash::vk::{
ApplicationInfo, DeviceCreateInfo, DeviceQueueCreateInfo, Handle, InstanceCreateInfo,
DeviceCreateInfo, DeviceQueueCreateInfo, Handle,
QueueFlags,
};
use ash::Device;
use std::ffi::CStr;
use std::sync::Arc;
use thiserror::Error;

mod buffer;

pub struct Vulkan {
entry: ash::Entry,
instance: ash::Instance,
devices: Vec<VulkanPhysicalDevice>,
}

impl super::GraphicsApi for Vulkan {
type PhysicalDevice = VulkanPhysicalDevice;

type InitError = VulkanInitError;

fn init() -> Result<Self, Self::InitError> {
let entry = ash::Entry::linked();

let app_info = ApplicationInfo::default().application_name(c"Obliteration");

let create_info = InstanceCreateInfo::default().application_info(&app_info);

let instance = unsafe { entry.create_instance(&create_info, None) }
.map_err(VulkanInitError::CreateInstanceFailed)?;

let devices = unsafe { instance.enumerate_physical_devices() }
.map_err(VulkanInitError::EnumeratePhysicalDevicesFailed)?
.into_iter()
.map(|device| -> Result<VulkanPhysicalDevice, VulkanInitError> {
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(), 256)
})
.map_err(|_| VulkanInitError::DeviceNameInvalid)?
.to_str()
.map_err(VulkanInitError::DeviceNameInvalidUtf8)?
.to_owned();

Ok(VulkanPhysicalDevice { device, name })
})
.collect::<Result<_, VulkanInitError>>()?;

Ok(Self {
entry,
instance,
devices,
})
}

fn enumerate_physical_devices(&self) -> &[Self::PhysicalDevice] {
&self.devices
}
}

impl Drop for Vulkan {
fn drop(&mut self) {
unsafe { self.instance.destroy_instance(None) };
}
}

pub struct VulkanPhysicalDevice {
device: ash::vk::PhysicalDevice,
name: String,
}

impl super::PhysicalDevice for VulkanPhysicalDevice {
fn name(&self) -> &str {
&self.name
}
}

/// Implementation of [`Screen`] using Vulkan.
pub struct VulkanScreen {
buffer: Arc<VulkanBuffer>,
Expand Down Expand Up @@ -148,22 +79,6 @@ impl Screen for VulkanScreen {
}
}

/// Represents an error when [`Vulkan::init()`] fails.
#[derive(Debug, Error)]
pub enum VulkanInitError {
#[error("couldn't create Vulkan instance")]
CreateInstanceFailed(#[source] ash::vk::Result),

#[error("couldn't enumerate physical devices")]
EnumeratePhysicalDevicesFailed(#[source] ash::vk::Result),

#[error("no null byte in device name")]
DeviceNameInvalid,

#[error("device name is not valid UTF-8")]
DeviceNameInvalidUtf8(#[source] std::str::Utf8Error),
}

/// Represents an error when [`VulkanScreen::new()`] fails.
#[derive(Debug, Error)]
pub enum VulkanScreenError {
Expand Down
16 changes: 16 additions & 0 deletions src/graphics/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[package]
name = "graphics"
version = "0.1.0"
edition = "2021"

[dependencies]
thiserror = "2.0.3"

[target.'cfg(not(target_os = "macos"))'.dependencies]
ash = { version = "0.38.0", features = ["linked", "std"], default-features = false }

[target.'cfg(target_os = "macos")'.dependencies]
applevisor-sys = "0.1.3"
core-graphics-types = "0.1.3"
metal = "0.29.0"
objc = "0.2.7"
23 changes: 23 additions & 0 deletions src/graphics/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#[cfg_attr(target_os = "macos", path = "metal.rs")]
#[cfg_attr(not(target_os = "macos"), path = "vulkan.rs")]
mod api;

#[cfg(not(target_os = "macos"))]
pub type DefaultApi = self::api::Vulkan;

#[cfg(target_os = "macos")]
pub type DefaultApi = self::api::Metal;

pub trait GraphicsApi: Sized + 'static {
type PhysicalDevice: PhysicalDevice;

type InitError: core::error::Error;

fn init() -> Result<Self, Self::InitError>;

fn enumerate_physical_devices(&self) -> &[Self::PhysicalDevice];
}

pub trait PhysicalDevice: Sized {
fn name(&self) -> &str;
}
40 changes: 40 additions & 0 deletions src/graphics/src/metal.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
use self::buffer::MetalBuffer;
use super::{Screen, ScreenBuffer};
use crate::vmm::VmmScreen;
use metal::{CAMetalLayer, Device, MetalLayer};
use objc::runtime::{Object, NO, YES};
use objc::{msg_send, sel, sel_impl};
use std::ptr::null_mut;
use std::sync::Arc;
use thiserror::Error;

pub struct Metal {
devices: Vec<metal::Device>,
}

impl super::GraphicsApi for Metal {
type PhysicalDevice = metal::Device;

type InitError = MetalInitError;

fn init() -> Result<Self, Self::InitError> {
Ok(Self {
devices: Device::all(),
})
}

fn enumerate_physical_devices(&self) -> &[Self::PhysicalDevice] {
&self.devices
}
}

impl super::PhysicalDevice for metal::Device {
fn name(&self) -> &str {
self.name()
}
}

/// Represents an error when [`Metal::init()`] fails.
#[derive(Debug, Error)]
pub enum MetalInitError {}
87 changes: 87 additions & 0 deletions src/graphics/src/vulkan.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
use ash::vk::{ApplicationInfo, InstanceCreateInfo};
use std::ffi::CStr;
use thiserror::Error;

pub struct Vulkan {
entry: ash::Entry,
instance: ash::Instance,
devices: Vec<VulkanPhysicalDevice>,
}

impl super::GraphicsApi for Vulkan {
type PhysicalDevice = VulkanPhysicalDevice;

type InitError = VulkanInitError;

fn init() -> Result<Self, Self::InitError> {
let entry = ash::Entry::linked();

let app_info = ApplicationInfo::default().application_name(c"Obliteration");

let create_info = InstanceCreateInfo::default().application_info(&app_info);

let instance = unsafe { entry.create_instance(&create_info, None) }
.map_err(VulkanInitError::CreateInstanceFailed)?;

let devices = unsafe { instance.enumerate_physical_devices() }
.map_err(VulkanInitError::EnumeratePhysicalDevicesFailed)?
.into_iter()
.map(|device| -> Result<VulkanPhysicalDevice, VulkanInitError> {
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(), 256)
})
.map_err(|_| VulkanInitError::DeviceNameInvalid)?
.to_str()
.map_err(VulkanInitError::DeviceNameInvalidUtf8)?
.to_owned();

Ok(VulkanPhysicalDevice { device, name })
})
.collect::<Result<_, VulkanInitError>>()?;

Ok(Self {
entry,
instance,
devices,
})
}

fn enumerate_physical_devices(&self) -> &[Self::PhysicalDevice] {
&self.devices
}
}

impl Drop for Vulkan {
fn drop(&mut self) {
unsafe { self.instance.destroy_instance(None) };
}
}

pub struct VulkanPhysicalDevice {
device: ash::vk::PhysicalDevice,
name: String,
}

impl super::PhysicalDevice for VulkanPhysicalDevice {
fn name(&self) -> &str {
&self.name
}
}

/// Represents an error when [`Vulkan::init()`] fails.
#[derive(Debug, Error)]
pub enum VulkanInitError {
#[error("couldn't create Vulkan instance")]
CreateInstanceFailed(#[source] ash::vk::Result),

#[error("couldn't enumerate physical devices")]
EnumeratePhysicalDevicesFailed(#[source] ash::vk::Result),

#[error("no null byte in device name")]
DeviceNameInvalid,

#[error("device name is not valid UTF-8")]
DeviceNameInvalidUtf8(#[source] std::str::Utf8Error),
}
Loading

0 comments on commit fff77c4

Please sign in to comment.