Add errors throughout

This commit is contained in:
Patrick Walton 2017-02-03 18:25:56 -08:00
parent 78c03a9594
commit 5453afa7a1
7 changed files with 79 additions and 25 deletions

View File

@ -8,6 +8,7 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use error::GlError;
use euclid::{Point2D, Rect, Size2D}; use euclid::{Point2D, Rect, Size2D};
use gl::types::{GLenum, GLsizei, GLsizeiptr, GLuint, GLvoid}; use gl::types::{GLenum, GLsizei, GLsizeiptr, GLuint, GLvoid};
use gl; 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. /// FIXME(pcwalton): Support the same glyph drawn at multiple point sizes.
pub fn pack_glyph(&mut self, pub fn pack_glyph(&mut self,
outline_builder: &OutlineBuilder, outline_builder: &OutlineBuilder,
@ -74,7 +77,7 @@ impl AtlasBuilder {
Ok(()) Ok(())
} }
pub fn create_atlas(&mut self, outline_builder: &OutlineBuilder) -> Result<Atlas, ()> { pub fn create_atlas(&mut self, outline_builder: &OutlineBuilder) -> Result<Atlas, GlError> {
self.image_metadata.sort_by(|a, b| a.glyph_index.cmp(&b.glyph_index)); 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![]); let (mut current_range, mut counts, mut start_indices) = (None, vec![], vec![]);

View File

@ -11,6 +11,7 @@
use compute_shader::buffer::Protection; use compute_shader::buffer::Protection;
use compute_shader::device::Device; use compute_shader::device::Device;
use compute_shader::image::{ExternalImage, Format, Image}; use compute_shader::image::{ExternalImage, Format, Image};
use error::InitError;
use euclid::size::Size2D; use euclid::size::Size2D;
use gl::types::{GLint, GLuint}; use gl::types::{GLint, GLuint};
use gl; use gl;
@ -21,15 +22,16 @@ pub struct CoverageBuffer {
} }
impl CoverageBuffer { impl CoverageBuffer {
pub fn new(device: &Device, size: &Size2D<u32>) -> Result<CoverageBuffer, ()> { pub fn new(device: &Device, size: &Size2D<u32>) -> Result<CoverageBuffer, InitError> {
let image = try!(device.create_image(Format::R32F, Protection::ReadWrite, size) let image = try!(device.create_image(Format::R32F, Protection::ReadWrite, size)
.map_err(drop)); .map_err(InitError::ComputeError));
let mut framebuffer = 0; let mut framebuffer = 0;
unsafe { unsafe {
let mut gl_texture = 0; let mut gl_texture = 0;
gl::GenTextures(1, &mut gl_texture); 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::BindTexture(gl::TEXTURE_RECTANGLE, gl_texture);
gl::TexParameteri(gl::TEXTURE_RECTANGLE, gl::TEXTURE_MIN_FILTER, gl::LINEAR as GLint); gl::TexParameteri(gl::TEXTURE_RECTANGLE, gl::TEXTURE_MIN_FILTER, gl::LINEAR as GLint);

40
src/error.rs Normal file
View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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),
}

View File

@ -27,6 +27,7 @@ extern crate test;
pub mod atlas; pub mod atlas;
pub mod charmap; pub mod charmap;
pub mod coverage; pub mod coverage;
pub mod error;
pub mod glyph_range; pub mod glyph_range;
pub mod otf; pub mod otf;
pub mod outline; pub mod outline;

View File

@ -8,6 +8,7 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use error::GlError;
use euclid::{Point2D, Rect, Size2D}; use euclid::{Point2D, Rect, Size2D};
use gl::types::{GLsizeiptr, GLuint}; use gl::types::{GLsizeiptr, GLuint};
use gl; use gl;
@ -95,7 +96,7 @@ impl OutlineBuilder {
self.descriptors[glyph_index as usize].glyph_id self.descriptors[glyph_index as usize].glyph_id
} }
pub fn create_buffers(&self) -> Result<OutlineBuffers, ()> { pub fn create_buffers(&self) -> Result<OutlineBuffers, GlError> {
// TODO(pcwalton): Try using `glMapBuffer` here. Requires precomputing contour types and // TODO(pcwalton): Try using `glMapBuffer` here. Requires precomputing contour types and
// counts. // counts.
unsafe { unsafe {

View File

@ -16,6 +16,7 @@ use compute_shader::profile_event::ProfileEvent;
use compute_shader::program::Program; use compute_shader::program::Program;
use compute_shader::queue::{Queue, Uniform}; use compute_shader::queue::{Queue, Uniform};
use coverage::CoverageBuffer; use coverage::CoverageBuffer;
use error::{InitError, RasterError};
use euclid::rect::Rect; use euclid::rect::Rect;
use gl::types::{GLchar, GLenum, GLint, GLsizei, GLuint, GLvoid}; use gl::types::{GLchar, GLenum, GLint, GLsizei, GLuint, GLvoid};
use gl; use gl;
@ -58,7 +59,7 @@ pub struct DrawAtlasProfilingEvents {
impl Rasterizer { impl Rasterizer {
pub fn new(instance: &Instance, device: Device, queue: Queue, options: RasterizerOptions) pub fn new(instance: &Instance, device: Device, queue: Queue, options: RasterizerOptions)
-> Result<Rasterizer, ()> { -> Result<Rasterizer, InitError> {
let (draw_program, draw_position_attribute, draw_glyph_index_attribute); let (draw_program, draw_position_attribute, draw_glyph_index_attribute);
let (draw_glyph_descriptors_uniform, draw_image_descriptors_uniform); let (draw_glyph_descriptors_uniform, draw_image_descriptors_uniform);
let draw_atlas_size_uniform; let draw_atlas_size_uniform;
@ -96,9 +97,8 @@ impl Rasterizer {
try!(check_gl_object_status(draw_program, try!(check_gl_object_status(draw_program,
gl::LINK_STATUS, gl::LINK_STATUS,
"Program",
gl::GetProgramiv, gl::GetProgramiv,
gl::GetProgramInfoLog)); gl::GetProgramInfoLog).map_err(InitError::LinkFailed));
gl::GenVertexArrays(1, &mut draw_vertex_array); gl::GenVertexArrays(1, &mut draw_vertex_array);
@ -124,7 +124,9 @@ impl Rasterizer {
ShadingLanguage::Cl => ACCUM_CL_SHADER, ShadingLanguage::Cl => ACCUM_CL_SHADER,
ShadingLanguage::Glsl => ACCUM_COMPUTE_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 { Ok(Rasterizer {
device: device, device: device,
@ -148,7 +150,7 @@ impl Rasterizer {
atlas: &Atlas, atlas: &Atlas,
outline_buffers: &OutlineBuffers, outline_buffers: &OutlineBuffers,
coverage_buffer: &CoverageBuffer) coverage_buffer: &CoverageBuffer)
-> Result<DrawAtlasProfilingEvents, ()> { -> Result<DrawAtlasProfilingEvents, RasterError> {
unsafe { unsafe {
gl::BindFramebuffer(gl::FRAMEBUFFER, coverage_buffer.framebuffer()); gl::BindFramebuffer(gl::FRAMEBUFFER, coverage_buffer.framebuffer());
gl::Viewport(0, 0, rect.size.width as GLint, rect.size.height as GLint); 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, let accum_event = try!(self.queue.submit_compute(&self.accum_program,
&[atlas.shelf_columns], &[atlas.shelf_columns],
&accum_uniforms, &accum_uniforms,
&[]).map_err(drop)); &[]).map_err(RasterError::ComputeError));
Ok(DrawAtlasProfilingEvents { Ok(DrawAtlasProfilingEvents {
draw: self.draw_query, draw: self.draw_query,
@ -239,26 +241,27 @@ impl Rasterizer {
} }
} }
fn compile_gl_shader(shader_type: GLuint, description: &str, source: &str) -> Result<GLuint, ()> { fn compile_gl_shader(shader_type: GLuint, description: &'static str, source: &str)
-> Result<GLuint, InitError> {
unsafe { unsafe {
let shader = gl::CreateShader(shader_type); let shader = gl::CreateShader(shader_type);
gl::ShaderSource(shader, 1, &(source.as_ptr() as *const GLchar), &(source.len() as GLint)); gl::ShaderSource(shader, 1, &(source.as_ptr() as *const GLchar), &(source.len() as GLint));
gl::CompileShader(shader); gl::CompileShader(shader);
try!(check_gl_object_status(shader, match check_gl_object_status(shader,
gl::COMPILE_STATUS, gl::COMPILE_STATUS,
description,
gl::GetShaderiv, gl::GetShaderiv,
gl::GetShaderInfoLog)); gl::GetShaderInfoLog) {
Ok(shader) Ok(_) => Ok(shader),
Err(info_log) => Err(InitError::CompileFailed(description, info_log)),
}
} }
} }
fn check_gl_object_status(object: GLuint, fn check_gl_object_status(object: GLuint,
parameter: GLenum, parameter: GLenum,
description: &str,
get_status: unsafe fn(GLuint, GLenum, *mut GLint), get_status: unsafe fn(GLuint, GLenum, *mut GLint),
get_log: unsafe fn(GLuint, GLsizei, *mut GLsizei, *mut GLchar)) get_log: unsafe fn(GLuint, GLsizei, *mut GLsizei, *mut GLchar))
-> Result<(), ()> { -> Result<(), String> {
unsafe { unsafe {
let mut status = 0; let mut status = 0;
get_status(object, parameter, &mut status); 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]; 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); 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 { impl RasterizerOptions {
pub fn from_env() -> Result<RasterizerOptions, ()> { pub fn from_env() -> Result<RasterizerOptions, InitError> {
let force_geometry_shader = match env::var("PATHFINDER_FORCE_GEOMETRY_SHADER") { let force_geometry_shader = match env::var("PATHFINDER_FORCE_GEOMETRY_SHADER") {
Ok(ref string) if string.eq_ignore_ascii_case("on") || Ok(ref string) if string.eq_ignore_ascii_case("on") ||
string.eq_ignore_ascii_case("yes") || string.eq_ignore_ascii_case("yes") ||
@ -301,7 +305,7 @@ impl RasterizerOptions {
string.eq_ignore_ascii_case("no") || string.eq_ignore_ascii_case("no") ||
string.eq_ignore_ascii_case("0") => false, string.eq_ignore_ascii_case("0") => false,
Err(_) => false, Err(_) => false,
Ok(_) => return Err(()), Ok(_) => return Err(InitError::InvalidSetting),
}; };
Ok(RasterizerOptions { Ok(RasterizerOptions {

View File

@ -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<u32>) -> Result<Point2D<u32>, ()> { pub fn pack(&mut self, size: &Size2D<u32>) -> Result<Point2D<u32>, ()> {
// Add a one-pixel border to prevent bleed. // Add a one-pixel border to prevent bleed.
let alloc_size = *size + Size2D::new(2, 2); let alloc_size = *size + Size2D::new(2, 2);