From 97ad18825b2047ebf49692e0ae8accee40df6264 Mon Sep 17 00:00:00 2001 From: Richard Dodd Date: Mon, 4 Sep 2017 16:01:35 +0100 Subject: [PATCH 1/2] Improve error handling --- amethyst_renderer/Cargo.toml | 1 + amethyst_renderer/examples/material.rs | 21 +-- amethyst_renderer/examples/sphere.rs | 21 +-- amethyst_renderer/examples/window.rs | 13 +- amethyst_renderer/src/error.rs | 165 ++++++++++++----------- amethyst_renderer/src/lib.rs | 45 +++++-- amethyst_renderer/src/pass/flat.rs | 7 +- amethyst_renderer/src/pass/pbm.rs | 17 ++- amethyst_renderer/src/pass/shaded.rs | 17 ++- amethyst_renderer/src/pipe/effect/mod.rs | 36 ++--- amethyst_renderer/src/pipe/pass.rs | 7 +- amethyst_renderer/src/pipe/stage.rs | 6 +- 12 files changed, 200 insertions(+), 156 deletions(-) diff --git a/amethyst_renderer/Cargo.toml b/amethyst_renderer/Cargo.toml index 61c0c55d2d..83efbddd1c 100644 --- a/amethyst_renderer/Cargo.toml +++ b/amethyst_renderer/Cargo.toml @@ -37,6 +37,7 @@ rayon = "0.8" serde = "1.0" serde_derive = "1.0" winit = "0.7" +error-chain = "0.10" gfx_device_gl = { version = "0.14", optional = true } gfx_window_glutin = { version = "0.17", optional = true } diff --git a/amethyst_renderer/examples/material.rs b/amethyst_renderer/examples/material.rs index c86f15f910..4571f5168e 100644 --- a/amethyst_renderer/examples/material.rs +++ b/amethyst_renderer/examples/material.rs @@ -1,5 +1,6 @@ //! Launches a new renderer window. +#[macro_use] extern crate error_chain; extern crate amethyst_renderer as renderer; extern crate cgmath; extern crate genmesh; @@ -11,13 +12,14 @@ use genmesh::{MapToVertices, Triangulate, Vertices}; use genmesh::generators::SphereUV; use renderer::prelude::*; use renderer::vertex::PosNormTangTex; +use renderer::Result; -fn main() { +fn run() -> Result<()> { use std::time::{Duration, Instant}; use winit::{Event, EventsLoop, WindowEvent}; let mut events = EventsLoop::new(); - let mut renderer = Renderer::new(&events).expect("Renderer create"); + let mut renderer = Renderer::new(&events)?; let pipe = renderer .create_pipe( Pipeline::build().with_stage( @@ -25,13 +27,10 @@ fn main() { .clear_target([0.0, 0.0, 0.0, 1.0], 2.0) .with_model_pass(pass::DrawShaded::::new()), ), - ) - .expect("Pipeline create"); + )?; let verts = gen_sphere(64, 64); - let mesh = renderer.create_mesh(Mesh::build(&verts)).expect( - "Mesh create", - ); + let mesh = renderer.create_mesh(Mesh::build(&verts))?; let mut scene = Scene::default(); let alb = Texture::from_color_val([1.0; 4]); @@ -52,8 +51,7 @@ fn main() { .with_albedo(alb.clone()) .with_roughness(rog) .with_metallic(met), - ) - .expect("Material create"); + )?; let model = Model { mesh: mesh.clone(), material: mtl, @@ -103,11 +101,14 @@ fn main() { _ => (), }); - renderer.draw(&scene, &pipe, delta); + renderer.draw(&scene, &pipe, delta)?; delta = Instant::now() - start; } + Ok(()) } +quick_main!(run); + fn gen_sphere(u: usize, v: usize) -> Vec { SphereUV::new(u, v) .vertex(|(x, y, z)| { diff --git a/amethyst_renderer/examples/sphere.rs b/amethyst_renderer/examples/sphere.rs index 09999c55c8..93704595ff 100644 --- a/amethyst_renderer/examples/sphere.rs +++ b/amethyst_renderer/examples/sphere.rs @@ -1,5 +1,6 @@ //! Launches a new renderer window. +#[macro_use] extern crate error_chain; extern crate amethyst_renderer as renderer; extern crate cgmath; extern crate genmesh; @@ -11,13 +12,14 @@ use genmesh::{MapToVertices, Triangulate, Vertices}; use genmesh::generators::SphereUV; use renderer::prelude::*; use renderer::vertex::PosNormTex; +use renderer::Result; -fn main() { +fn run() -> Result<()> { use std::time::{Duration, Instant}; use winit::{Event, EventsLoop, WindowEvent}; let mut events = EventsLoop::new(); - let mut renderer = Renderer::new(&events).expect("Renderer create"); + let mut renderer = Renderer::new(&events)?; let pipe = renderer .create_pipe( Pipeline::build().with_stage( @@ -25,18 +27,14 @@ fn main() { .clear_target([0.00196, 0.23726, 0.21765, 1.0], 1.0) .with_model_pass(pass::DrawFlat::::new()), ), - ) - .expect("Pipeline create"); + )?; let verts = gen_sphere(32, 32); - let mesh = renderer.create_mesh(Mesh::build(&verts)).expect( - "Mesh create", - ); + let mesh = renderer.create_mesh(Mesh::build(&verts))?; let tex = Texture::from_color_val([0.88235, 0.09412, 0.21569, 1.0]); let mtl = renderer - .create_material(MaterialBuilder::new().with_albedo(tex)) - .expect("Material create"); + .create_material(MaterialBuilder::new().with_albedo(tex))?; let model = Model { mesh: mesh, material: mtl, @@ -70,11 +68,14 @@ fn main() { _ => (), }); - renderer.draw(&scene, &pipe, delta); + renderer.draw(&scene, &pipe, delta)?; delta = Instant::now() - start; } + Ok(()) } +quick_main!(run); + fn gen_sphere(u: usize, v: usize) -> Vec { SphereUV::new(u, v) .vertex(|(x, y, z)| { diff --git a/amethyst_renderer/examples/window.rs b/amethyst_renderer/examples/window.rs index d808e323cd..0c3d53d4b6 100644 --- a/amethyst_renderer/examples/window.rs +++ b/amethyst_renderer/examples/window.rs @@ -1,5 +1,6 @@ //! Launches a new renderer window. +#[macro_use] extern crate error_chain; extern crate amethyst_renderer as renderer; extern crate winit; @@ -7,11 +8,12 @@ use std::time::{Duration, Instant}; use winit::{Event, EventsLoop, WindowEvent}; use renderer::prelude::*; +use renderer::Result; -fn main() { +fn run() -> Result<()> { let mut events = EventsLoop::new(); - let mut renderer = Renderer::new(&events).unwrap(); - let pipe = renderer.create_pipe(Pipeline::forward::()).unwrap(); + let mut renderer = Renderer::new(&events)?; + let pipe = renderer.create_pipe(Pipeline::forward::())?; let scene = Scene::default(); let mut delta = Duration::from_secs(0); @@ -30,7 +32,10 @@ fn main() { _ => (), }); - renderer.draw(&scene, &pipe, delta); + renderer.draw(&scene, &pipe, delta)?; delta = Instant::now() - start; } + Ok(()) } + +quick_main!(run); diff --git a/amethyst_renderer/src/error.rs b/amethyst_renderer/src/error.rs index d9d97e420c..f027bc2c36 100644 --- a/amethyst_renderer/src/error.rs +++ b/amethyst_renderer/src/error.rs @@ -1,126 +1,131 @@ //! Renderer error types. -use std::error::Error as StdError; -use std::fmt::{Display, Formatter}; -use std::fmt::Result as FmtResult; -use std::result::Result as StdResult; - use gfx; use gfx_core; +use glutin; -/// Renderer result type. -pub type Result = StdResult; - -/// Common renderer error type. -#[derive(Debug)] -pub enum Error { - /// Failed to create a buffer. - BufferCreation(gfx::buffer::CreationError), - /// A render target with the given name does not exist. - NoSuchTarget(String), - /// Failed to initialize a render pass. - PassInit(gfx::PipelineStateError), - /// Failed to create a pipeline state object (PSO). - PipelineCreation(gfx_core::pso::CreationError), - /// Failed to create thread pool. - PoolCreation(String), - /// Failed to create and link a shader program. - ProgramCreation(gfx::shade::ProgramError), - /// Failed to create a resource view. - ResViewCreation(gfx::ResourceViewError), - /// Failed to create a render target. - TargetCreation(gfx::CombinedError), - /// Failed to create a texture resource. - TextureCreation(gfx::texture::CreationError), - /// The window handle associated with the renderer has been destroyed. - WindowDestroyed, -} - -impl StdError for Error { - fn description(&self) -> &str { - match *self { - Error::BufferCreation(_) => "Failed to create buffer!", - Error::NoSuchTarget(_) => "Target with this name does not exist!", - Error::PassInit(_) => "Failed to initialize render pass!", - Error::PipelineCreation(_) => "Failed to create PSO!", - Error::PoolCreation(_) => "Failed to create thread pool!", - Error::ProgramCreation(_) => "Failed to create shader program!", - Error::ResViewCreation(_) => "Failed to create resource view!", - Error::TargetCreation(_) => "Failed to create render target!", - Error::TextureCreation(_) => "Failed to create texture!", - Error::WindowDestroyed => "Window has been destroyed!", +error_chain! { + errors { + /// Failed to create a buffer. + BufferCreation(e: gfx::buffer::CreationError) { + description("Failed to create buffer!") + display("Buffer creation failed: {}", e) } - } - - fn cause(&self) -> Option<&StdError> { - match *self { - Error::BufferCreation(ref e) => Some(e), - Error::PassInit(ref e) => Some(e), - Error::PipelineCreation(ref e) => Some(e), - Error::ProgramCreation(ref e) => Some(e), - Error::ResViewCreation(ref e) => Some(e), - Error::TargetCreation(ref e) => Some(e), - Error::TextureCreation(ref e) => Some(e), - _ => None, + /// A render target with the given name does not exist. + NoSuchTarget(e: String) { + description("Target with this name does not exist!") + display("Nonexistent target: {}", e) + } + /// Failed to initialize a render pass. + PassInit(e: gfx::PipelineStateError) { + description("Failed to initialize render pass!") + display("Pass initialization failed: {}", e) + } + /// Failed to create a pipeline state object (PSO). + PipelineCreation(e: gfx_core::pso::CreationError) { + description("Failed to create PSO!") + display("PSO creation failed: {}", e) + } + /// Failed to create thread pool. + PoolCreation(e: String) { + description("Failed to create thread pool!") + display("Thread pool creation failed: {}", e) + } + /// Failed to create and link a shader program. + ProgramCreation(e: gfx::shade::ProgramError) { + description("Failed to create shader program!") + display("Program compilation failed: {}", e) + } + /// Failed to create a resource view. + ResViewCreation(e: gfx::ResourceViewError) { + description("Failed to create resource view!") + display("Resource view creation failed: {}", e) } - } -} -impl Display for Error { - fn fmt(&self, fmt: &mut Formatter) -> FmtResult { - match *self { - Error::BufferCreation(ref e) => write!(fmt, "Buffer creation failed: {}", e), - Error::NoSuchTarget(ref e) => write!(fmt, "Nonexistent target: {}", e), - Error::PassInit(ref e) => write!(fmt, "Pass initialization failed: {}", e), - Error::PipelineCreation(ref e) => write!(fmt, "PSO creation failed: {}", e), - Error::PoolCreation(ref e) => write!(fmt, "Thread pool creation failed: {}", e), - Error::ProgramCreation(ref e) => write!(fmt, "Program compilation failed: {}", e), - Error::ResViewCreation(ref e) => write!(fmt, "Resource view creation failed: {}", e), - Error::TargetCreation(ref e) => write!(fmt, "Target creation failed: {}", e), - Error::TextureCreation(ref e) => write!(fmt, "Texture creation failed: {}", e), - Error::WindowDestroyed => write!(fmt, "Window has been destroyed"), + /// Failed to create a render target. + TargetCreation(e: gfx::CombinedError) { + description("Failed to create render target!") + display("Target creation failed: {}", e) + } + /// Failed to create a texture resource. + TextureCreation(e: gfx::texture::CreationError) { + description("Failed to create texture!") + display("Texture creation failed: {}", e) + } + /// An error occuring in buffer/texture updates. + BufTexUpdate { + description("An error occured during buffer/texture update") + } + /// No global with given name could be found. + MissingGlobal(name: String) { + description("No global was found with the given name") + display(r#"No global was found with the name "{}""#, name) + } + /// No buffer with given name could be found. + MissingBuffer(name: String) { + description("No buffer was found with the given name") + display(r#"No buffer was found with the name "{}""#, name) + } + /// No constant buffer with given name could be found. + MissingConstBuffer(name: String) { + description("No constant buffer was found with the given name") + display(r#"No constant buffer was found with the name "{}""#, name) + } + /// (GL only) An error occured swapping buffers + BufferSwapFailed(e: glutin::ContextError) { + description("An error occured swapping the buffers") + display("An error occured swapping the buffers: {}", e) + } + /// A list of all errors that occured during render + DrawErrors(errors: Vec) { + description("One or more errors occured during drawing") + display("One or more errors occured during drawing: {:?}", errors) + } + /// The window handle associated with the renderer has been destroyed. + WindowDestroyed { + description("Window has been destroyed!") } } } impl From for Error { fn from(e: gfx::CombinedError) -> Error { - Error::TargetCreation(e) + ErrorKind::TargetCreation(e).into() } } impl From> for Error { fn from(e: gfx::PipelineStateError) -> Error { - Error::PassInit(e) + ErrorKind::PassInit(e).into() } } impl From for Error { fn from(e: gfx::ResourceViewError) -> Error { - Error::ResViewCreation(e) + ErrorKind::ResViewCreation(e).into() } } impl From for Error { fn from(e: gfx::buffer::CreationError) -> Error { - Error::BufferCreation(e) + ErrorKind::BufferCreation(e).into() } } impl From for Error { fn from(e: gfx::shade::ProgramError) -> Error { - Error::ProgramCreation(e) + ErrorKind::ProgramCreation(e).into() } } impl From for Error { fn from(e: gfx::texture::CreationError) -> Error { - Error::TextureCreation(e) + ErrorKind::TextureCreation(e).into() } } impl From for Error { fn from(e: gfx_core::pso::CreationError) -> Error { - Error::PipelineCreation(e) + ErrorKind::PipelineCreation(e).into() } } diff --git a/amethyst_renderer/src/lib.rs b/amethyst_renderer/src/lib.rs index 97f0d3cfa1..7944504572 100644 --- a/amethyst_renderer/src/lib.rs +++ b/amethyst_renderer/src/lib.rs @@ -65,6 +65,11 @@ #![deny(missing_docs)] #![doc(html_logo_url = "https://tinyurl.com/jtmm43a")] +// for error-chain +#![recursion_limit="4096"] + +#[macro_use] +extern crate error_chain; extern crate cgmath; #[macro_use] extern crate derivative; @@ -104,7 +109,7 @@ extern crate gfx_window_vulkan; pub use cam::{Camera, Projection}; pub use color::Rgba; pub use config::Config; -pub use error::{Error, Result}; +pub use error::{Error, ErrorKind, Result}; pub use light::Light; pub use mesh::{Mesh, MeshBuilder}; pub use mtl::{Material, MaterialBuilder}; @@ -211,7 +216,7 @@ impl Renderer { } /// Draws a scene with the given pipeline. - pub fn draw(&mut self, scene: &Scene, pipe: &Pipeline, _delta: Duration) { + pub fn draw(&mut self, scene: &Scene, pipe: &Pipeline, _delta: Duration) -> Result<()> { use gfx::Device; #[cfg(feature = "opengl")] use glutin::GlContext; @@ -234,7 +239,7 @@ impl Renderer { { let mut encoders = self.encoders.iter_mut(); - self.pool.install(move || { + self.pool.install(move || -> Result<()> { let mut updates = Vec::new(); for stage in pipe.enabled_stages() { let needed = stage.encoders_required(num_threads); @@ -244,12 +249,29 @@ impl Renderer { updates.push(stage.apply(taken, scene)); } - updates.into_par_iter().flat_map(|update| update).for_each( - |(pass, models, enc)| for model in models { - pass.apply(enc, scene, model); + let errors = updates.into_par_iter().flat_map(|update| update).fold( + || Vec::new(), + |mut acc, (pass, models, enc)| { + for model in models { + if let Err(e) = pass.apply(enc, scene, model) { + acc.push(e); + }; + } + acc }, + ).reduce( + || Vec::new(), + |mut acc, res| { + acc.extend(res.into_iter()); + acc + } ); - }); + + if errors.len() > 0 { + bail!(ErrorKind::DrawErrors(errors)); + } + Ok(()) + })?; } for enc in self.encoders.iter_mut() { @@ -259,9 +281,8 @@ impl Renderer { self.device.cleanup(); #[cfg(feature = "opengl")] - self.window.swap_buffers().expect( - "OpenGL context has been lost", - ); + self.window.swap_buffers().map_err(|e| Error::from(ErrorKind::BufferSwapFailed(e)))?; + Ok(()) } } @@ -345,7 +366,7 @@ impl<'a> RendererBuilder<'a> { let pool = self.pool.clone().map(|p| Ok(p)).unwrap_or_else(|| { let cfg = rayon::Configuration::new().num_threads(num_cores); ThreadPool::new(cfg).map(|p| Arc::new(p)).map_err(|e| { - Error::PoolCreation(format!("{}", e)) + Error::from(ErrorKind::PoolCreation(format!("{}", e))) }) })?; @@ -428,7 +449,7 @@ fn init_backend(wb: WindowBuilder, el: &EventsLoop, config: &Config) -> Result(wb, ctx, el); - let size = win.get_inner_size_points().ok_or(Error::WindowDestroyed)?; + let size = win.get_inner_size_points().ok_or(Error::from(ErrorKind::WindowDestroyed))?; let main_target = Target::new( ColorBuffer { as_input: None, diff --git a/amethyst_renderer/src/pass/flat.rs b/amethyst_renderer/src/pass/flat.rs index c9d24274b9..405caa3cca 100644 --- a/amethyst_renderer/src/pass/flat.rs +++ b/amethyst_renderer/src/pass/flat.rs @@ -57,7 +57,9 @@ impl Pass for DrawFlat { .build() } - fn apply(&self, enc: &mut Encoder, effect: &mut Effect, scene: &Scene, model: &Model) { + fn apply(&self, enc: &mut Encoder, effect: &mut Effect, scene: &Scene, model: &Model) + -> Result<()> + { let vertex_args = scene .active_camera() .map(|cam| { @@ -75,7 +77,7 @@ impl Pass for DrawFlat { } }); - effect.update_constant_buffer("VertexArgs", &vertex_args, enc); + effect.update_constant_buffer("VertexArgs", &vertex_args, enc)?; effect.data.textures.push( model.material.albedo.view().clone(), ); @@ -84,5 +86,6 @@ impl Pass for DrawFlat { ); effect.draw(model, enc); + Ok(()) } } diff --git a/amethyst_renderer/src/pass/pbm.rs b/amethyst_renderer/src/pass/pbm.rs index 80b785b894..d59dea0f5c 100644 --- a/amethyst_renderer/src/pass/pbm.rs +++ b/amethyst_renderer/src/pass/pbm.rs @@ -100,7 +100,9 @@ impl Pass for DrawPbm { .build() } - fn apply(&self, enc: &mut Encoder, effect: &mut Effect, scene: &Scene, model: &Model) { + fn apply(&self, enc: &mut Encoder, effect: &mut Effect, scene: &Scene, model: &Model) + -> Result<()> + { use rayon::prelude::*; let vertex_args = scene @@ -119,7 +121,7 @@ impl Pass for DrawPbm { model: model.pos.into(), } }); - effect.update_constant_buffer("VertexArgs", &vertex_args, enc); + effect.update_constant_buffer("VertexArgs", &vertex_args, enc)?; let point_lights: Vec = scene .par_iter_lights() @@ -149,20 +151,20 @@ impl Pass for DrawPbm { directional_light_count: directional_lights.len() as i32, }; - effect.update_constant_buffer("FragmentArgs", &fragment_args, enc); - effect.update_buffer("PointLights", &point_lights[..], enc); - effect.update_buffer("DirectionalLights", &directional_lights[..], enc); + effect.update_constant_buffer("FragmentArgs", &fragment_args, enc)?; + effect.update_buffer("PointLights", &point_lights[..], enc)?; + effect.update_buffer("DirectionalLights", &directional_lights[..], enc)?; effect.update_global( "ambient_color", Into::<[f32; 3]>::into(scene.ambient_color()), - ); + )?; effect.update_global( "camera_position", scene.active_camera().map(|cam| cam.eye.into()).unwrap_or( [0.0; 3], ), - ); + )?; effect.data.textures.push( model.material.roughness.view().clone(), ); @@ -227,5 +229,6 @@ impl Pass for DrawPbm { ); effect.draw(model, enc); + Ok(()) } } diff --git a/amethyst_renderer/src/pass/shaded.rs b/amethyst_renderer/src/pass/shaded.rs index 22b5b799df..36275cde4b 100644 --- a/amethyst_renderer/src/pass/shaded.rs +++ b/amethyst_renderer/src/pass/shaded.rs @@ -93,7 +93,9 @@ impl Pass for DrawShaded { .build() } - fn apply(&self, enc: &mut Encoder, effect: &mut Effect, scene: &Scene, model: &Model) { + fn apply(&self, enc: &mut Encoder, effect: &mut Effect, scene: &Scene, model: &Model) + -> Result<()> + { use rayon::prelude::*; let vertex_args = scene @@ -112,7 +114,7 @@ impl Pass for DrawShaded { model: model.pos.into(), } }); - effect.update_constant_buffer("VertexArgs", &vertex_args, enc); + effect.update_constant_buffer("VertexArgs", &vertex_args, enc)?; let point_lights: Vec = scene .par_iter_lights() @@ -142,20 +144,20 @@ impl Pass for DrawShaded { directional_light_count: directional_lights.len() as i32, }; - effect.update_constant_buffer("FragmentArgs", &fragment_args, enc); - effect.update_buffer("PointLights", &point_lights[..], enc); - effect.update_buffer("DirectionalLights", &directional_lights[..], enc); + effect.update_constant_buffer("FragmentArgs", &fragment_args, enc)?; + effect.update_buffer("PointLights", &point_lights[..], enc)?; + effect.update_buffer("DirectionalLights", &directional_lights[..], enc)?; effect.update_global( "ambient_color", Into::<[f32; 3]>::into(scene.ambient_color()), - ); + )?; effect.update_global( "camera_position", scene.active_camera().map(|cam| cam.eye.into()).unwrap_or( [0.0; 3], ), - ); + )?; effect.data.textures.push( model.material.emission.view().clone(), ); @@ -174,5 +176,6 @@ impl Pass for DrawShaded { ); effect.draw(model, enc); + Ok(()) } } diff --git a/amethyst_renderer/src/pipe/effect/mod.rs b/amethyst_renderer/src/pipe/effect/mod.rs index 1a36d5f14d..1cb5bf930b 100644 --- a/amethyst_renderer/src/pipe/effect/mod.rs +++ b/amethyst_renderer/src/pipe/effect/mod.rs @@ -18,7 +18,7 @@ use gfx::traits::Pod; use self::pso::{Data, Init, Meta}; -use error::{Error, Result}; +use error::{Error, ErrorKind, Result, ResultExt}; use pipe::Target; use scene::Model; use types::{Encoder, Factory, PipelineState, Resources}; @@ -55,16 +55,16 @@ impl<'a> ProgramSource<'a> { match *self { ProgramSource::Simple(ref vs, ref ps) => { fac.create_shader_set(vs, ps).map_err( - |e| Error::ProgramCreation(e), + |e| Error::from(e), ) } ProgramSource::Geometry(ref vs, ref gs, ref ps) => { let v = fac.create_shader_vertex(vs).map_err( |e| ProgramError::Vertex(e), )?; - let g = fac.create_shader_geometry(gs).expect( - "Geometry shader creation failed", - ); + let g = fac.create_shader_geometry(gs).map_err( + |e| ProgramError::Geometry(e) + )?; let p = fac.create_shader_pixel(ps).map_err( |e| ProgramError::Pixel(e), )?; @@ -72,9 +72,7 @@ impl<'a> ProgramSource<'a> { } ProgramSource::Tessellated(ref vs, ref hs, ref ds, ref ps) => { fac.create_shader_set_tessellation(vs, hs, ds, ps).map_err( - |e| { - Error::ProgramCreation(e) - }, + |e| Error::from(e), ) } } @@ -91,16 +89,17 @@ pub struct Effect { } impl Effect { - pub fn update_global, T: ToUniform>(&mut self, name: N, data: T) { + pub fn update_global, T: ToUniform>(&mut self, name: N, data: T) -> Result<()> { if let Some(i) = self.globals.get(name.as_ref()) { self.data.globals[*i] = data.convert(); + Ok(()) + } else { + bail!(ErrorKind::MissingGlobal(name.as_ref().to_owned())) } - // FIXME: Don't silently ignore unknown update. - // maybe `.expect(...)` would fit here } /// FIXME: Update raw buffer without transmute, use `Result` somehow. - pub fn update_buffer(&self, name: N, data: &[T], enc: &mut Encoder) + pub fn update_buffer(&self, name: N, data: &[T], enc: &mut Encoder) -> Result<()> where N: AsRef, T: Pod, @@ -108,14 +107,14 @@ impl Effect { if let Some(i) = self.const_bufs.get(name.as_ref()) { let raw = &self.data.const_bufs[*i]; enc.update_buffer::(unsafe { mem::transmute(raw) }, &data[..], 0) - .expect("Failed to update buffer (TODO: replace expect)"); + .chain_err(|| ErrorKind::BufTexUpdate) + } else { + bail!(ErrorKind::MissingBuffer(name.as_ref().to_owned())) } - // FIXME: Don't silently ignore unknown update. - // maybe `.expect(...)` would fit here } /// FIXME: Update raw buffer without transmute. - pub fn update_constant_buffer(&self, name: N, data: &T, enc: &mut Encoder) + pub fn update_constant_buffer(&self, name: N, data: &T, enc: &mut Encoder) -> Result<()> where N: AsRef, T: Copy, @@ -123,9 +122,10 @@ impl Effect { if let Some(i) = self.const_bufs.get(name.as_ref()) { let raw = &self.data.const_bufs[*i]; enc.update_constant_buffer::(unsafe { mem::transmute(raw) }, &data); + Ok(()) + } else { + bail!(ErrorKind::MissingConstBuffer(name.as_ref().to_owned())) } - // FIXME: Don't silently ignore unknown update. - // maybe `.expect(...)` would fit here } /// FIXME: Add support for arbitrary materials and textures. diff --git a/amethyst_renderer/src/pipe/pass.rs b/amethyst_renderer/src/pipe/pass.rs index 6aa1ad3ebd..8215971fd2 100644 --- a/amethyst_renderer/src/pipe/pass.rs +++ b/amethyst_renderer/src/pipe/pass.rs @@ -12,7 +12,8 @@ use types::{Encoder, Factory}; pub trait Pass: Send + Sync { fn compile(&self, effect: NewEffect) -> Result; - fn apply(&self, enc: &mut Encoder, effect: &mut Effect, scene: &Scene, model: &Model); + fn apply(&self, enc: &mut Encoder, effect: &mut Effect, scene: &Scene, model: &Model) + -> Result<()>; } #[derive(Clone)] @@ -46,14 +47,14 @@ pub struct CompiledPass { } impl CompiledPass { - pub fn apply(&self, enc: &mut Encoder, scene: &Scene, model: &Model) { + pub fn apply(&self, enc: &mut Encoder, scene: &Scene, model: &Model) -> Result<()> { // TODO: Eliminate this clone. self.inner.apply( enc, &mut self.effect.clone(), scene, model, - ); + ) } } diff --git a/amethyst_renderer/src/pipe/stage.rs b/amethyst_renderer/src/pipe/stage.rs index 428dd79ba7..be56712cd4 100644 --- a/amethyst_renderer/src/pipe/stage.rs +++ b/amethyst_renderer/src/pipe/stage.rs @@ -5,7 +5,7 @@ use rayon::iter::internal::UnindexedConsumer; use rayon::slice::{Chunks, IterMut as ParIterMut}; use rayon::vec::IntoIter; -use error::{Error, Result}; +use error::{Error, ErrorKind, Result}; use pipe::{Target, Targets}; use pipe::pass::{CompiledPass, Description, Pass}; use scene::{Model, Scene}; @@ -161,9 +161,9 @@ impl StageBuilder { /// Builds and returns the stage. pub(crate) fn build(mut self, fac: &mut Factory, targets: &Targets) -> Result { let out = targets.get(&self.target_name).cloned().ok_or( - Error::NoSuchTarget( + Error::from(ErrorKind::NoSuchTarget( self.target_name, - ), + )), )?; let passes = self.passes From 9ee751df267eab4a1b7882790a16606439fc2313 Mon Sep 17 00:00:00 2001 From: Richard Dodd Date: Tue, 5 Sep 2017 23:47:16 +0100 Subject: [PATCH 2/2] Use foreign links for error --- amethyst_renderer/src/error.rs | 103 +++++++-------------------------- amethyst_renderer/src/lib.rs | 2 +- 2 files changed, 22 insertions(+), 83 deletions(-) diff --git a/amethyst_renderer/src/error.rs b/amethyst_renderer/src/error.rs index f027bc2c36..611602da45 100644 --- a/amethyst_renderer/src/error.rs +++ b/amethyst_renderer/src/error.rs @@ -5,53 +5,38 @@ use gfx_core; use glutin; error_chain! { + + foreign_links { + + BufferCreation(gfx::buffer::CreationError) + #[doc="Error occured during buffer creation"]; + PipelineState(gfx::PipelineStateError) + #[doc="Error occured in pipeline state"]; + PsoCreation(gfx_core::pso::CreationError) + #[doc="Error occured during pipeline state object creation"]; + ShaderProgram(gfx::shade::ProgramError) + #[doc="Error occured during shader compilation"]; + ResourceView(gfx::ResourceViewError) + #[doc="Error occured in resource view"]; + GfxCombined(gfx::CombinedError) + #[doc="Gfx combined error type"]; + TextureCreation(gfx::texture::CreationError) + #[doc="Error occured during texture creation"]; + GlutinContext(glutin::ContextError) // todo #[cfg(glutin)] only + #[doc="(gl specific) Error occured in gl context"]; + } + errors { - /// Failed to create a buffer. - BufferCreation(e: gfx::buffer::CreationError) { - description("Failed to create buffer!") - display("Buffer creation failed: {}", e) - } /// A render target with the given name does not exist. NoSuchTarget(e: String) { description("Target with this name does not exist!") display("Nonexistent target: {}", e) } - /// Failed to initialize a render pass. - PassInit(e: gfx::PipelineStateError) { - description("Failed to initialize render pass!") - display("Pass initialization failed: {}", e) - } - /// Failed to create a pipeline state object (PSO). - PipelineCreation(e: gfx_core::pso::CreationError) { - description("Failed to create PSO!") - display("PSO creation failed: {}", e) - } /// Failed to create thread pool. PoolCreation(e: String) { description("Failed to create thread pool!") display("Thread pool creation failed: {}", e) } - /// Failed to create and link a shader program. - ProgramCreation(e: gfx::shade::ProgramError) { - description("Failed to create shader program!") - display("Program compilation failed: {}", e) - } - /// Failed to create a resource view. - ResViewCreation(e: gfx::ResourceViewError) { - description("Failed to create resource view!") - display("Resource view creation failed: {}", e) - } - - /// Failed to create a render target. - TargetCreation(e: gfx::CombinedError) { - description("Failed to create render target!") - display("Target creation failed: {}", e) - } - /// Failed to create a texture resource. - TextureCreation(e: gfx::texture::CreationError) { - description("Failed to create texture!") - display("Texture creation failed: {}", e) - } /// An error occuring in buffer/texture updates. BufTexUpdate { description("An error occured during buffer/texture update") @@ -71,11 +56,6 @@ error_chain! { description("No constant buffer was found with the given name") display(r#"No constant buffer was found with the name "{}""#, name) } - /// (GL only) An error occured swapping buffers - BufferSwapFailed(e: glutin::ContextError) { - description("An error occured swapping the buffers") - display("An error occured swapping the buffers: {}", e) - } /// A list of all errors that occured during render DrawErrors(errors: Vec) { description("One or more errors occured during drawing") @@ -88,44 +68,3 @@ error_chain! { } } -impl From for Error { - fn from(e: gfx::CombinedError) -> Error { - ErrorKind::TargetCreation(e).into() - } -} - -impl From> for Error { - fn from(e: gfx::PipelineStateError) -> Error { - ErrorKind::PassInit(e).into() - } -} - -impl From for Error { - fn from(e: gfx::ResourceViewError) -> Error { - ErrorKind::ResViewCreation(e).into() - } -} - -impl From for Error { - fn from(e: gfx::buffer::CreationError) -> Error { - ErrorKind::BufferCreation(e).into() - } -} - -impl From for Error { - fn from(e: gfx::shade::ProgramError) -> Error { - ErrorKind::ProgramCreation(e).into() - } -} - -impl From for Error { - fn from(e: gfx::texture::CreationError) -> Error { - ErrorKind::TextureCreation(e).into() - } -} - -impl From for Error { - fn from(e: gfx_core::pso::CreationError) -> Error { - ErrorKind::PipelineCreation(e).into() - } -} diff --git a/amethyst_renderer/src/lib.rs b/amethyst_renderer/src/lib.rs index 7944504572..a337fee911 100644 --- a/amethyst_renderer/src/lib.rs +++ b/amethyst_renderer/src/lib.rs @@ -281,7 +281,7 @@ impl Renderer { self.device.cleanup(); #[cfg(feature = "opengl")] - self.window.swap_buffers().map_err(|e| Error::from(ErrorKind::BufferSwapFailed(e)))?; + self.window.swap_buffers()?; Ok(()) } }