diff --git a/src/core/app.rs b/src/core/app.rs index 7f2e1fc..53026cd 100644 --- a/src/core/app.rs +++ b/src/core/app.rs @@ -1,4 +1,6 @@ use std::{sync::Arc, time::Instant}; + +use anyhow::Result; use winit::{ dpi::PhysicalSize, event::{Event, WindowEvent}, @@ -18,16 +20,15 @@ pub struct App<'window> { } impl<'window> App<'window> { - pub async fn new(width: u32, height: u32, title: &str) -> Self { + pub async fn new(width: u32, height: u32, title: &str) -> Result { log::info!("Initialising window..."); let size = PhysicalSize::new(width, height); - let event_loop = EventLoop::new().unwrap(); + let event_loop = EventLoop::new()?; let window = Arc::new( winit::window::WindowBuilder::new() .with_title(title) .with_inner_size(size) - .build(&event_loop) - .unwrap(), + .build(&event_loop)?, ); let render_ctx = gfx::Context::new( @@ -38,16 +39,16 @@ impl<'window> App<'window> { ..Default::default() }, ) - .await; + .await?; - Self { + Ok(Self { title: title.to_owned(), event_loop, render_ctx, - } + }) } - pub fn run(mut self) { + pub fn run(mut self) -> Result<()> { let mut camera_controller = camera::CameraController::new( &self.render_ctx, camera::Camera::new( @@ -81,7 +82,7 @@ impl<'window> App<'window> { glam::uvec3(32, 32, 32), ); - let mut renderer = voxel::VoxelRenderer::new(&self.render_ctx, &camera_controller); + let mut renderer = voxel::VoxelRenderer::new(&self.render_ctx, &camera_controller)?; let mut cumulative_dt = 0.0; let mut frames_accumulated = 0.0; @@ -169,5 +170,7 @@ impl<'window> App<'window> { // } // } }); + + Ok(()) } } diff --git a/src/gfx/bind_group.rs b/src/gfx/bind_group.rs index ba1b213..0b09524 100644 --- a/src/gfx/bind_group.rs +++ b/src/gfx/bind_group.rs @@ -1,5 +1,7 @@ use std::num::NonZeroU32; +use anyhow::{Context as _, Result}; + use super::Context; #[derive(Debug, Default)] @@ -123,13 +125,13 @@ impl<'a> BindGroupBuilder<'a> { } #[inline] - pub fn build(self, context: &Context) -> wgpu::BindGroup { - context + pub fn build(self, context: &Context) -> Result { + Ok(context .device .create_bind_group(&wgpu::BindGroupDescriptor { label: self.label, - layout: self.layout.unwrap(), + layout: self.layout.context("BindGroupBuilder has no layout.")?, entries: self.entries.as_slice(), - }) + })) } } diff --git a/src/gfx/context.rs b/src/gfx/context.rs index a59244b..fa34ede 100644 --- a/src/gfx/context.rs +++ b/src/gfx/context.rs @@ -1,5 +1,6 @@ use std::sync::Arc; +use anyhow::{Context as _, Result}; use winit::{ dpi::PhysicalSize, event::WindowEvent, event_loop::EventLoopWindowTarget, window::Window, }; @@ -16,7 +17,7 @@ pub struct Context<'window> { } impl<'window> Context<'window> { - pub async fn new(window: Arc, limits: wgpu::Limits) -> Self { + pub async fn new(window: Arc, limits: wgpu::Limits) -> Result { log::info!("Initialising WGPU context..."); let instance = wgpu::Instance::new(wgpu::InstanceDescriptor { backends: wgpu::Backends::VULKAN, @@ -29,7 +30,7 @@ impl<'window> Context<'window> { // - A GPU device to draw to the surface // - A draw command queue log::info!("Initialising window surface..."); - let surface = instance.create_surface(window.clone()).unwrap(); + let surface = instance.create_surface(window.clone())?; log::info!("Requesting GPU adapter..."); let adapter = instance @@ -39,7 +40,7 @@ impl<'window> Context<'window> { compatible_surface: Some(&surface), }) .await - .unwrap(); + .context("Failed to find suitable GPU adapter")?; log::info!("Checking GPU adapter meets requirements"); log::info!("Requesting GPU device..."); @@ -52,17 +53,16 @@ impl<'window> Context<'window> { }, None, ) - .await - .unwrap(); + .await?; log::info!("Configuring window surface..."); let size = window.inner_size(); let surface_config = surface .get_default_config(&adapter, size.width, size.height) - .unwrap(); + .context("Surface configuration unsupported by adapter")?; surface.configure(&device, &surface_config); - Self { + Ok(Self { window, instance, size, @@ -71,7 +71,7 @@ impl<'window> Context<'window> { adapter, device, queue, - } + }) } pub fn resize_surface(&mut self, new_size: PhysicalSize) { diff --git a/src/gfx/renderer.rs b/src/gfx/renderer.rs index ff5363d..1329c23 100644 --- a/src/gfx/renderer.rs +++ b/src/gfx/renderer.rs @@ -1,6 +1,8 @@ use std::time::Duration; +use anyhow::Result; + pub trait Renderer { - fn update(&mut self, dt: &Duration, context: &super::Context); - fn render(&self, context: &super::Context); + fn update(&mut self, dt: &Duration, context: &super::Context) -> Result<()>; + fn render(&self, context: &super::Context) -> Result<()>; } diff --git a/src/gfx/texture.rs b/src/gfx/texture.rs index c0b87ba..182edd8 100644 --- a/src/gfx/texture.rs +++ b/src/gfx/texture.rs @@ -1,7 +1,8 @@ -// TODO: Support mip-mapping and multi-sampling +use anyhow::Result; use super::{BindGroupBuilder, BindGroupLayoutBuilder, Context}; +// TODO: Support mip-mapping and multi-sampling #[derive(Debug, Clone)] pub struct TextureAttributes { pub size: wgpu::Extent3d, @@ -98,7 +99,7 @@ impl TextureBuilder { } #[inline] - pub fn build(self, context: &Context) -> Texture { + pub fn build(self, context: &Context) -> Result { Texture::new(context, self.attributes) } } @@ -114,7 +115,7 @@ pub struct Texture { } impl Texture { - pub fn new(context: &Context, attributes: TextureAttributes) -> Self { + pub fn new(context: &Context, attributes: TextureAttributes) -> Result { let texture = context.device.create_texture(&wgpu::TextureDescriptor { label: None, size: attributes.size, @@ -163,16 +164,16 @@ impl Texture { .with_layout(&bind_group_layout) .with_entry(wgpu::BindingResource::TextureView(&view)) .with_entry(wgpu::BindingResource::Sampler(&sampler)) - .build(context); + .build(context)?; - Self { + Ok(Self { attributes, texture, view, sampler, bind_group_layout, bind_group, - } + }) } pub fn update(&self, context: &Context, data: &[u8]) { diff --git a/src/main.rs b/src/main.rs index 5f2fac1..a537ab1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,7 +3,10 @@ mod gfx; mod math; mod voxel; -fn main() { +use anyhow::Result; + +fn main() -> Result<()> { env_logger::init(); - pollster::block_on(core::App::new(1280, 720, "Epic")).run(); + pollster::block_on(core::App::new(1280, 720, "Epic"))?.run()?; + Ok(()) } diff --git a/src/voxel/voxel_renderer.rs b/src/voxel/voxel_renderer.rs index 3c508a8..54228cd 100644 --- a/src/voxel/voxel_renderer.rs +++ b/src/voxel/voxel_renderer.rs @@ -1,5 +1,7 @@ use std::time::Duration; +use anyhow::Result; + use crate::{core, gfx}; #[derive(Debug)] @@ -15,7 +17,7 @@ pub struct VoxelRenderer { } impl VoxelRenderer { - pub fn new(context: &gfx::Context, camera_controller: &core::CameraController) -> Self { + pub fn new(context: &gfx::Context, camera_controller: &core::CameraController) -> Result { log::info!("Creating render shader..."); let shader_descriptor = wgpu::include_wgsl!("../../assets/shaders/shader.wgsl"); let shader = context.device.create_shader_module(shader_descriptor); @@ -30,7 +32,7 @@ impl VoxelRenderer { | wgpu::TextureUsages::STORAGE_BINDING, ) .with_shader_visibility(wgpu::ShaderStages::FRAGMENT | wgpu::ShaderStages::COMPUTE) - .build(context); + .build(context)?; log::info!("Creating render pipeline..."); let render_pipeline = @@ -100,7 +102,7 @@ impl VoxelRenderer { .get_brickgrid_unpack_buffer() .as_entire_binding(), ) - .build(context); + .build(context)?; let unpack_pipeline = context .device @@ -147,7 +149,7 @@ impl VoxelRenderer { .with_entry(brickmap_manager.get_shading_buffer().as_entire_binding()) .with_entry(brickmap_manager.get_feedback_buffer().as_entire_binding()) .with_entry(camera_controller.get_buffer().as_entire_binding()) - .build(context); + .build(context)?; let raycast_pipeline = context .device @@ -164,7 +166,7 @@ impl VoxelRenderer { entry_point: "compute", }); - Self { + Ok(Self { clear_color: wgpu::Color::BLACK, render_texture, render_pipeline, @@ -173,13 +175,13 @@ impl VoxelRenderer { raycast_bind_group, unpack_pipeline, unpack_bind_group, - } + }) } } impl gfx::Renderer for VoxelRenderer { - fn render(&self, context: &gfx::Context) { - let frame = context.surface.get_current_texture().unwrap(); + fn render(&self, context: &gfx::Context) -> Result<()> { + let frame = context.surface.get_current_texture()?; let view = frame .texture .create_view(&wgpu::TextureViewDescriptor::default()); @@ -231,9 +233,12 @@ impl gfx::Renderer for VoxelRenderer { context.queue.submit(Some(encoder.finish())); frame.present(); + Ok(()) } - fn update(&mut self, _dt: &Duration, _context: &gfx::Context) {} + fn update(&mut self, _dt: &Duration, _context: &gfx::Context) -> Result<()> { + Ok(()) + } } impl VoxelRenderer {