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
// 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<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));
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::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<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)
.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);

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 charmap;
pub mod coverage;
pub mod error;
pub mod glyph_range;
pub mod otf;
pub mod outline;

View File

@ -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<OutlineBuffers, ()> {
pub fn create_buffers(&self) -> Result<OutlineBuffers, GlError> {
// TODO(pcwalton): Try using `glMapBuffer` here. Requires precomputing contour types and
// counts.
unsafe {

View File

@ -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<Rasterizer, ()> {
-> Result<Rasterizer, InitError> {
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<DrawAtlasProfilingEvents, ()> {
-> Result<DrawAtlasProfilingEvents, RasterError> {
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<GLuint, ()> {
fn compile_gl_shader(shader_type: GLuint, description: &'static str, source: &str)
-> Result<GLuint, InitError> {
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,
match check_gl_object_status(shader,
gl::COMPILE_STATUS,
description,
gl::GetShaderiv,
gl::GetShaderInfoLog));
Ok(shader)
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<RasterizerOptions, ()> {
pub fn from_env() -> Result<RasterizerOptions, InitError> {
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 {

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>, ()> {
// Add a one-pixel border to prevent bleed.
let alloc_size = *size + Size2D::new(2, 2);