diff --git a/Cargo.lock b/Cargo.lock index 0d9709c..6d31d07 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1702,6 +1702,7 @@ dependencies = [ name = "gb-emu-lib" version = "0.5.1" dependencies = [ + "anyhow", "ash 0.38.0+1.3.281", "ash-molten", "ash-window", diff --git a/gui/src/macos/cacao_window_manager.rs b/gui/src/macos/cacao_window_manager.rs index 8083358..837ff74 100644 --- a/gui/src/macos/cacao_window_manager.rs +++ b/gui/src/macos/cacao_window_manager.rs @@ -335,7 +335,7 @@ impl WindowManager for CacaoWindowManager { factor: usize, shader_path: Option, resizable: bool, - ) -> RendererChannel { + ) -> anyhow::Result { let (w, receiver) = CacaoWindow::new( window_type, factor, @@ -364,7 +364,7 @@ impl WindowManager for CacaoWindowManager { window.show(); self.windows .insert(window.delegate.as_ref().unwrap().window_type, window); - receiver + Ok(receiver) } } diff --git a/lib/Cargo.toml b/lib/Cargo.toml index 0d1e356..c7413a7 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -54,6 +54,7 @@ lazy_static = "1.4" wgpu = { version = "0.20", optional = true } thiserror = { workspace = true } log = { workspace = true } +anyhow = "1.0.86" [build-dependencies] naga = { version = "0.19", optional = true, features = ["wgsl-in", "spv-out"] } diff --git a/lib/src/connect/mod.rs b/lib/src/connect/mod.rs index 161b218..5663f2a 100644 --- a/lib/src/connect/mod.rs +++ b/lib/src/connect/mod.rs @@ -3,12 +3,13 @@ use std::path::PathBuf; use std::sync::mpsc::Sender; use std::sync::{Arc, RwLock}; +pub use crate::error::RomHeaderError; pub use crate::processor::memory::mmio::gpu::Colour; pub use crate::processor::memory::mmio::joypad::{JoypadButtons, JoypadState}; pub use crate::processor::memory::mmio::serial::{SerialTarget, StdoutType}; use crate::processor::memory::rom::sram_save::SaveDataLocation; pub use crate::processor::memory::rom::{ - licensee::LicenseeCode, CartridgeType, CgbRomType, RamSize, RomHeader, RomHeaderError, RomSize, + licensee::LicenseeCode, CartridgeType, CgbRomType, RamSize, RomHeader, RomSize, }; pub use crate::processor::memory::Rom; pub use crate::{HEIGHT, WIDTH}; diff --git a/lib/src/error.rs b/lib/src/error.rs new file mode 100644 index 0000000..831e50f --- /dev/null +++ b/lib/src/error.rs @@ -0,0 +1,55 @@ +use thiserror::Error; + +#[derive(Debug, Error)] +pub enum RomHeaderError { + #[error("slice not long enough for rom file")] + SliceLength, + #[error(transparent)] + Utf8(#[from] std::str::Utf8Error), + #[error("invalid ROM size")] + InvalidRomSize, + #[error("invalid RAM size")] + InvalidRamSize, + #[error("invalid MBC")] + InvalidMBC, +} + +#[derive(Debug)] +pub(crate) enum AddressError { + OutOfBounds, +} + +#[cfg(feature = "pixels-renderer")] +#[derive(Debug, Error)] +pub enum PixelsError { + #[error("pixels error")] + Pixels(#[from] pixels::Error), +} + +#[cfg(feature = "wgpu-renderer")] +#[derive(Debug, Error)] +pub enum WgpuError { + #[error("no adapter")] + NoAdapter, + #[error("no texture format")] + NoTextureFormat, + #[error("rwh error")] + RawWindowHandle(#[from] raw_window_handle::HandleError), + #[error("create surface error")] + CreateSurface(#[from] wgpu::CreateSurfaceError), + #[error("wgpu surface error")] + Surface(#[from] wgpu::SurfaceError), + #[error("request device error")] + RequestDevice(#[from] wgpu::RequestDeviceError), + #[error("librashader filterchain error")] + FilterChain(#[from] librashader::runtime::wgpu::error::FilterChainError), + #[error("couldn't load")] + CouldntLoad, +} + +#[cfg(feature = "vulkan-renderer")] +#[derive(Debug, Error)] +pub enum VulkanError { + #[error("vulkan error")] + Vulkan, //(#[from] vk::Error), +} diff --git a/lib/src/lib.rs b/lib/src/lib.rs index 06d0413..5c8a12e 100644 --- a/lib/src/lib.rs +++ b/lib/src/lib.rs @@ -1,6 +1,7 @@ #![feature(let_chains, bigint_helper_methods)] use crate::processor::{memory::Memory, Flags}; +use anyhow::Context; use connect::{AudioOutput, EmulatorCoreTrait, EmulatorMessage, EmulatorOptions, RomFile}; use processor::{ memory::{mmio::gpu::Colour, rom::CgbRomType, OutputTargets}, @@ -8,6 +9,7 @@ use processor::{ }; use std::sync::mpsc::Receiver; +pub mod error; pub mod renderer; #[cfg(feature = "config")] @@ -31,13 +33,13 @@ where impl EmulatorCore where - ColourFormat: From + Copy, + ColourFormat: From + Copy + Sync + Send + 'static, { pub fn init( paused: bool, receiver: Receiver>, options: EmulatorOptions, - ) -> Self { + ) -> anyhow::Result { let rom = options.rom; let is_cgb_mode = rom.rom_type == CgbRomType::CgbOnly || options.cgb_mode; @@ -51,28 +53,24 @@ where )) } .load_data() - .expect("Error loading bootrom!"); + .context("couldn't load bootrom")?; if let Some(window) = &options.window { - window - .send(connect::RendererMessage::Prepare { - width: WIDTH, - height: HEIGHT, - }) - .expect("message error"); - window - .send(connect::RendererMessage::SetTitle { - title: format!( - "{} on {} on {}", - rom.get_title(), - rom.mbc_type(), - if is_cgb_mode { "CGB" } else { "DMG" } - ), - }) - .expect("message error"); + window.send(connect::RendererMessage::Prepare { + width: WIDTH, + height: HEIGHT, + })?; + window.send(connect::RendererMessage::SetTitle { + title: format!( + "{} on {} on {}", + rom.get_title(), + rom.mbc_type(), + if is_cgb_mode { "CGB" } else { "DMG" } + ), + })? } - Self::new( + Ok(Self::new( paused, receiver, Cpu::new( @@ -91,9 +89,14 @@ where options.show_bootrom, options.no_output, ), - ) + )) } +} +impl EmulatorCore +where + ColourFormat: From + Copy, +{ fn new( paused: bool, receiver: Receiver>, diff --git a/lib/src/processor/memory/addresses.rs b/lib/src/processor/memory/addresses.rs index a024117..8c0a834 100644 --- a/lib/src/processor/memory/addresses.rs +++ b/lib/src/processor/memory/addresses.rs @@ -3,6 +3,8 @@ use std::{ ops::{Add, Sub}, }; +use crate::error::AddressError; + pub(crate) use self::types::*; mod types; diff --git a/lib/src/processor/memory/addresses/types.rs b/lib/src/processor/memory/addresses/types.rs index 1f56b86..a55f64f 100644 --- a/lib/src/processor/memory/addresses/types.rs +++ b/lib/src/processor/memory/addresses/types.rs @@ -3,10 +3,7 @@ use std::{ ops::{Add, Sub}, }; -#[derive(Debug)] -pub(crate) enum AddressError { - OutOfBounds, -} +use crate::error::AddressError; #[derive(Copy, Clone, Debug)] pub(crate) struct BoundedAddress(u16); diff --git a/lib/src/processor/memory/rom.rs b/lib/src/processor/memory/rom.rs index 1572408..141195a 100644 --- a/lib/src/processor/memory/rom.rs +++ b/lib/src/processor/memory/rom.rs @@ -1,3 +1,5 @@ +use crate::error::RomHeaderError; + use self::{ licensee::LicenseeCode, mbcs::{Mbc, Mbc1, Mbc2, Mbc3, Mbc5, None, KB, ROM_BANK_SIZE}, @@ -5,7 +7,6 @@ use self::{ }; use serde::{Deserialize, Serialize}; use std::str::from_utf8; -use thiserror::Error; use super::addresses::{CartRamAddress, RomAddress}; @@ -323,20 +324,6 @@ impl RomHeader { } } -#[derive(Debug, Error)] -pub enum RomHeaderError { - #[error("slice not long enough for rom file")] - SliceLength, - #[error("parsing UTF-8")] - Utf8(#[from] std::str::Utf8Error), - #[error("invalid ROM size")] - InvalidRomSize, - #[error("invalid RAM size")] - InvalidRamSize, - #[error("invalid MBC")] - InvalidMBC, -} - impl Rom { pub(crate) fn load(data: Vec, sram_location: Option) -> Self { let header_data = RomHeader::parse(&data).unwrap(); diff --git a/lib/src/renderer/pixels.rs b/lib/src/renderer/pixels.rs index 4153771..2dbb94b 100644 --- a/lib/src/renderer/pixels.rs +++ b/lib/src/renderer/pixels.rs @@ -2,9 +2,8 @@ use std::{path::PathBuf, sync::Arc}; use pixels::{Pixels, SurfaceTexture}; use raw_window_handle::{DisplayHandle, HasDisplayHandle, HasWindowHandle}; -use thiserror::Error; -use crate::connect::ResolutionData; +use crate::{connect::ResolutionData, error::PixelsError}; use super::{RendererBackend, RendererBackendManager}; @@ -82,12 +81,6 @@ fn new_pixels( .build() } -#[derive(Debug, Error)] -pub enum PixelsError { - #[error("pixels error")] - Pixels(#[from] pixels::Error), -} - struct DummyHandle<'a> { window: raw_window_handle::WindowHandle<'a>, display: raw_window_handle::DisplayHandle<'a>, diff --git a/lib/src/renderer/vulkan/types.rs b/lib/src/renderer/vulkan/types.rs index 475e20c..508f589 100644 --- a/lib/src/renderer/vulkan/types.rs +++ b/lib/src/renderer/vulkan/types.rs @@ -13,12 +13,6 @@ use super::{ VulkanBackendManager, }; -#[derive(Debug, Error)] -pub enum VulkanError { - #[error("vulkan error")] - Vulkan, //(#[from] vk::Error), -} - pub(super) const SHADER_INPUT_FORMAT: vk::Format = vk::Format::R8G8B8A8_UNORM; #[derive(Clone, Debug, Copy)] diff --git a/lib/src/renderer/wgpu.rs b/lib/src/renderer/wgpu.rs index 6c3a4c9..dc323b9 100644 --- a/lib/src/renderer/wgpu.rs +++ b/lib/src/renderer/wgpu.rs @@ -3,11 +3,11 @@ use std::sync::Arc; use futures::executor::block_on; use librashader::runtime::wgpu::{FilterChain, FilterChainOptions}; use raw_window_handle::{DisplayHandle, HasDisplayHandle, HasWindowHandle}; -use thiserror::Error; use wgpu::{Device, Queue, Surface, SurfaceConfiguration}; use crate::{ connect::ResolutionData, + error::WgpuError, renderer::{RendererBackend, RendererBackendManager}, }; @@ -125,23 +125,23 @@ impl RendererBackend for WgpuBackend { let filter_chain_options = FilterChainOptions { force_no_mipmaps: false, }; - match shader_path { - Some(path) => FilterChain::load_from_path( - path, - device.clone(), - queue.clone(), - Some(&filter_chain_options), - ) - .unwrap(), //?, - None => { - FilterChain::load_from_preset( - default_preset(), + shader_path + .and_then(|path| { + FilterChain::load_from_path( + path, device.clone(), queue.clone(), Some(&filter_chain_options), ) - }?, - } + .inspect_err(|e| log::error!("couldn't load shader: {e:?}")) + .ok() + }) + .unwrap_or(FilterChain::load_from_preset( + default_preset(), + device.clone(), + queue.clone(), + Some(&filter_chain_options), + )?) }; let gb_framebuffer = Arc::new(device.create_texture(&wgpu::TextureDescriptor { @@ -268,21 +268,3 @@ impl RendererBackend for WgpuBackend { Ok(()) } } - -#[derive(Debug, Error)] -pub enum WgpuError { - #[error("no adapter")] - NoAdapter, - #[error("no texture format")] - NoTextureFormat, - #[error("rwh error")] - RawWindowHandle(#[from] raw_window_handle::HandleError), - #[error("create surface error")] - CreateSurface(#[from] wgpu::CreateSurfaceError), - #[error("wgpu surface error")] - Surface(#[from] wgpu::SurfaceError), - #[error("request device error")] - RequestDevice(#[from] wgpu::RequestDeviceError), - #[error("librashader filterchain error")] - FilterChain(#[from] librashader::runtime::wgpu::error::FilterChainError), -}