From 5453afa7a1fdb084447283bba8ce0c911a2f62df Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Fri, 3 Feb 2017 18:25:56 -0800 Subject: [PATCH] Add errors throughout --- src/atlas.rs | 5 ++++- src/coverage.rs | 8 +++++--- src/error.rs | 40 ++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 1 + src/outline.rs | 3 ++- src/rasterizer.rs | 44 ++++++++++++++++++++++++-------------------- src/rect_packer.rs | 3 +++ 7 files changed, 79 insertions(+), 25 deletions(-) create mode 100644 src/error.rs diff --git a/src/atlas.rs b/src/atlas.rs index 7ef3f444..17ec94b9 100644 --- a/src/atlas.rs +++ b/src/atlas.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use error::GlError; use euclid::{Point2D, Rect, Size2D}; use gl::types::{GLenum, GLsizei, GLsizeiptr, GLuint, GLvoid}; use gl; @@ -34,6 +35,8 @@ impl AtlasBuilder { } } + /// Returns an error if there is no space left for the glyph in the atlas. + /// /// FIXME(pcwalton): Support the same glyph drawn at multiple point sizes. pub fn pack_glyph(&mut self, outline_builder: &OutlineBuilder, @@ -74,7 +77,7 @@ impl AtlasBuilder { Ok(()) } - pub fn create_atlas(&mut self, outline_builder: &OutlineBuilder) -> Result { + pub fn create_atlas(&mut self, outline_builder: &OutlineBuilder) -> Result { self.image_metadata.sort_by(|a, b| a.glyph_index.cmp(&b.glyph_index)); let (mut current_range, mut counts, mut start_indices) = (None, vec![], vec![]); diff --git a/src/coverage.rs b/src/coverage.rs index 7bd48e3d..03afb8a8 100644 --- a/src/coverage.rs +++ b/src/coverage.rs @@ -11,6 +11,7 @@ use compute_shader::buffer::Protection; use compute_shader::device::Device; use compute_shader::image::{ExternalImage, Format, Image}; +use error::InitError; use euclid::size::Size2D; use gl::types::{GLint, GLuint}; use gl; @@ -21,15 +22,16 @@ pub struct CoverageBuffer { } impl CoverageBuffer { - pub fn new(device: &Device, size: &Size2D) -> Result { + pub fn new(device: &Device, size: &Size2D) -> Result { let image = try!(device.create_image(Format::R32F, Protection::ReadWrite, size) - .map_err(drop)); + .map_err(InitError::ComputeError)); let mut framebuffer = 0; unsafe { let mut gl_texture = 0; gl::GenTextures(1, &mut gl_texture); - try!(image.bind_to(&ExternalImage::GlTexture(gl_texture)).map_err(drop)); + try!(image.bind_to(&ExternalImage::GlTexture(gl_texture)) + .map_err(InitError::ComputeError)); gl::BindTexture(gl::TEXTURE_RECTANGLE, gl_texture); gl::TexParameteri(gl::TEXTURE_RECTANGLE, gl::TEXTURE_MIN_FILTER, gl::LINEAR as GLint); diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 00000000..398daa25 --- /dev/null +++ b/src/error.rs @@ -0,0 +1,40 @@ +// Copyright 2017 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Errors. + +use compute_shader; +use gl::types::GLenum; + +/// An OpenGL error with the given code. +/// +/// You cannot depend on these being reliably returned. Pathfinder does not call `glGetError()` +/// unless necessary, to avoid driver stalls. +#[derive(Clone, Copy, PartialEq, Debug)] +pub struct GlError(pub GLenum); + +/// An initialization error. This could be an OpenGL error or a shader compilation/link error. +#[derive(Debug)] +pub enum InitError { + GlError(GlError), + CompileFailed(&'static str, String), + LinkFailed(String), + ComputeError(compute_shader::error::Error), + /// One of the rasterization options had an invalid syntax. + InvalidSetting, +} + +/// A rasterization error. This could be an OpenGL error or a compute error. +#[derive(Debug)] +pub enum RasterError { + GlError(GlError), + ComputeError(compute_shader::error::Error), +} + diff --git a/src/lib.rs b/src/lib.rs index 4783d16d..0b74dcc7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -27,6 +27,7 @@ extern crate test; pub mod atlas; pub mod charmap; pub mod coverage; +pub mod error; pub mod glyph_range; pub mod otf; pub mod outline; diff --git a/src/outline.rs b/src/outline.rs index a5d13e80..061debf0 100644 --- a/src/outline.rs +++ b/src/outline.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use error::GlError; use euclid::{Point2D, Rect, Size2D}; use gl::types::{GLsizeiptr, GLuint}; use gl; @@ -95,7 +96,7 @@ impl OutlineBuilder { self.descriptors[glyph_index as usize].glyph_id } - pub fn create_buffers(&self) -> Result { + pub fn create_buffers(&self) -> Result { // TODO(pcwalton): Try using `glMapBuffer` here. Requires precomputing contour types and // counts. unsafe { diff --git a/src/rasterizer.rs b/src/rasterizer.rs index a9497b8c..84810ec8 100644 --- a/src/rasterizer.rs +++ b/src/rasterizer.rs @@ -16,6 +16,7 @@ use compute_shader::profile_event::ProfileEvent; use compute_shader::program::Program; use compute_shader::queue::{Queue, Uniform}; use coverage::CoverageBuffer; +use error::{InitError, RasterError}; use euclid::rect::Rect; use gl::types::{GLchar, GLenum, GLint, GLsizei, GLuint, GLvoid}; use gl; @@ -58,7 +59,7 @@ pub struct DrawAtlasProfilingEvents { impl Rasterizer { pub fn new(instance: &Instance, device: Device, queue: Queue, options: RasterizerOptions) - -> Result { + -> Result { let (draw_program, draw_position_attribute, draw_glyph_index_attribute); let (draw_glyph_descriptors_uniform, draw_image_descriptors_uniform); let draw_atlas_size_uniform; @@ -96,9 +97,8 @@ impl Rasterizer { try!(check_gl_object_status(draw_program, gl::LINK_STATUS, - "Program", gl::GetProgramiv, - gl::GetProgramInfoLog)); + gl::GetProgramInfoLog).map_err(InitError::LinkFailed)); gl::GenVertexArrays(1, &mut draw_vertex_array); @@ -124,7 +124,9 @@ impl Rasterizer { ShadingLanguage::Cl => ACCUM_CL_SHADER, ShadingLanguage::Glsl => ACCUM_COMPUTE_SHADER, }; - let accum_program = device.create_program(accum_source).unwrap(); + + let accum_program = try!(device.create_program(accum_source) + .map_err(InitError::ComputeError)); Ok(Rasterizer { device: device, @@ -148,7 +150,7 @@ impl Rasterizer { atlas: &Atlas, outline_buffers: &OutlineBuffers, coverage_buffer: &CoverageBuffer) - -> Result { + -> Result { unsafe { gl::BindFramebuffer(gl::FRAMEBUFFER, coverage_buffer.framebuffer()); gl::Viewport(0, 0, rect.size.width as GLint, rect.size.height as GLint); @@ -230,7 +232,7 @@ impl Rasterizer { let accum_event = try!(self.queue.submit_compute(&self.accum_program, &[atlas.shelf_columns], &accum_uniforms, - &[]).map_err(drop)); + &[]).map_err(RasterError::ComputeError)); Ok(DrawAtlasProfilingEvents { draw: self.draw_query, @@ -239,26 +241,27 @@ impl Rasterizer { } } -fn compile_gl_shader(shader_type: GLuint, description: &str, source: &str) -> Result { +fn compile_gl_shader(shader_type: GLuint, description: &'static str, source: &str) + -> Result { unsafe { let shader = gl::CreateShader(shader_type); gl::ShaderSource(shader, 1, &(source.as_ptr() as *const GLchar), &(source.len() as GLint)); gl::CompileShader(shader); - try!(check_gl_object_status(shader, - gl::COMPILE_STATUS, - description, - gl::GetShaderiv, - gl::GetShaderInfoLog)); - Ok(shader) + match check_gl_object_status(shader, + gl::COMPILE_STATUS, + gl::GetShaderiv, + gl::GetShaderInfoLog) { + Ok(_) => Ok(shader), + Err(info_log) => Err(InitError::CompileFailed(description, info_log)), + } } } fn check_gl_object_status(object: GLuint, parameter: GLenum, - description: &str, get_status: unsafe fn(GLuint, GLenum, *mut GLint), get_log: unsafe fn(GLuint, GLsizei, *mut GLsizei, *mut GLchar)) - -> Result<(), ()> { + -> Result<(), String> { unsafe { let mut status = 0; get_status(object, parameter, &mut status); @@ -271,10 +274,11 @@ fn check_gl_object_status(object: GLuint, let mut info_log = vec![0; info_log_length as usize]; get_log(object, info_log_length, ptr::null_mut(), info_log.as_mut_ptr() as *mut GLchar); - if let Ok(string) = String::from_utf8(info_log) { - println!("{} error:\n{}", description, string); + + match String::from_utf8(info_log) { + Ok(string) => Err(string), + Err(_) => Err("(not UTF-8)".to_owned()), } - Err(()) } } @@ -292,7 +296,7 @@ impl Default for RasterizerOptions { } impl RasterizerOptions { - pub fn from_env() -> Result { + pub fn from_env() -> Result { let force_geometry_shader = match env::var("PATHFINDER_FORCE_GEOMETRY_SHADER") { Ok(ref string) if string.eq_ignore_ascii_case("on") || string.eq_ignore_ascii_case("yes") || @@ -301,7 +305,7 @@ impl RasterizerOptions { string.eq_ignore_ascii_case("no") || string.eq_ignore_ascii_case("0") => false, Err(_) => false, - Ok(_) => return Err(()), + Ok(_) => return Err(InitError::InvalidSetting), }; Ok(RasterizerOptions { diff --git a/src/rect_packer.rs b/src/rect_packer.rs index bb4b5997..8bdc7546 100644 --- a/src/rect_packer.rs +++ b/src/rect_packer.rs @@ -31,6 +31,9 @@ impl RectPacker { } } + /// Packs a rectangle of the given size. + /// + /// Returns the top-left position of the rectangle or an error if there is no space left. pub fn pack(&mut self, size: &Size2D) -> Result, ()> { // Add a one-pixel border to prevent bleed. let alloc_size = *size + Size2D::new(2, 2);