Read shaders from disk instead of compiling them into the binary

This commit is contained in:
Patrick Walton 2017-02-10 17:44:22 -08:00
parent c4c19076c7
commit 959293839f
5 changed files with 97 additions and 24 deletions

View File

@ -27,6 +27,7 @@ use pathfinder::otf::Font;
use pathfinder::rasterizer::{Rasterizer, RasterizerOptions};
use std::env;
use std::os::raw::c_void;
use std::path::PathBuf;
const ATLAS_SIZE: u32 = 2048;
const WIDTH: u32 = 512;
@ -35,6 +36,8 @@ const HEIGHT: u32 = 384;
const MIN_TIME_PER_SIZE: u64 = 300_000_000;
const MAX_TIME_PER_SIZE: u64 = 3_000_000_000;
static SHADER_PATH: &'static str = "resources/shaders/";
fn main() {
let mut glfw = glfw::init(glfw::LOG_ERRORS).unwrap();
glfw.window_hint(WindowHint::ContextVersion(3, 3));
@ -51,7 +54,11 @@ fn main() {
let device = instance.open_device().unwrap();
let queue = device.create_queue().unwrap();
let rasterizer_options = RasterizerOptions::from_env().unwrap();
let mut rasterizer_options = RasterizerOptions::from_env().unwrap();
if env::var("PATHFINDER_SHADER_PATH").is_err() {
rasterizer_options.shader_path = PathBuf::from(SHADER_PATH)
}
let rasterizer = Rasterizer::new(&instance, device, queue, rasterizer_options).unwrap();
for point_size in 6..201 {

View File

@ -24,12 +24,16 @@ use pathfinder::coverage::CoverageBuffer;
use pathfinder::outline::OutlineBuilder;
use pathfinder::otf::Font;
use pathfinder::rasterizer::{Rasterizer, RasterizerOptions};
use std::env;
use std::os::raw::c_void;
use std::path::PathBuf;
const DEFAULT_POINT_SIZE: f32 = 24.0;
const WIDTH: u32 = 512;
const HEIGHT: u32 = 384;
static SHADER_PATH: &'static str = "resources/shaders/";
fn main() {
let index_arg = Arg::with_name("index").short("i")
.long("index")
@ -60,7 +64,11 @@ fn main() {
let device = instance.open_device().unwrap();
let queue = device.create_queue().unwrap();
let rasterizer_options = RasterizerOptions::from_env().unwrap();
let mut rasterizer_options = RasterizerOptions::from_env().unwrap();
if env::var("PATHFINDER_SHADER_PATH").is_err() {
rasterizer_options.shader_path = PathBuf::from(SHADER_PATH)
}
let rasterizer = Rasterizer::new(&instance, device, queue, rasterizer_options).unwrap();
let file = Mmap::open_path(matches.value_of("FONT-FILE").unwrap(), Protection::Read).unwrap();

View File

@ -27,11 +27,12 @@ use pathfinder::outline::{OutlineBuilder, Outlines};
use pathfinder::rasterizer::{DrawAtlasProfilingEvents, Rasterizer, RasterizerOptions};
use pathfinder::shaper;
use std::char;
use std::env;
use std::fs::File;
use std::io::Read;
use std::mem;
use std::os::raw::c_void;
use std::path::Path;
use std::path::{Path, PathBuf};
const ATLAS_SIZE: u32 = 2048;
const WIDTH: u32 = 640;
@ -45,6 +46,8 @@ const MAX_POINT_SIZE: f32 = 256.0;
const FPS_DISPLAY_POINT_SIZE: f32 = 24.0;
const FPS_PADDING: i32 = 6;
static SHADER_PATH: &'static str = "resources/shaders/";
static FPS_BACKGROUND_COLOR: [f32; 4] = [0.0, 0.0, 0.0, 0.7];
static FPS_FOREGROUND_COLOR: [f32; 4] = [1.0, 1.0, 1.0, 1.0];
static TEXT_COLOR: [f32; 4] = [0.0, 0.0, 0.0, 1.0];
@ -290,7 +293,11 @@ impl Renderer {
let device = instance.open_device().unwrap();
let queue = device.create_queue().unwrap();
let rasterizer_options = RasterizerOptions::from_env().unwrap();
let mut rasterizer_options = RasterizerOptions::from_env().unwrap();
if env::var("PATHFINDER_SHADER_PATH").is_err() {
rasterizer_options.shader_path = PathBuf::from(SHADER_PATH)
}
let rasterizer = Rasterizer::new(&instance, device, queue, rasterizer_options).unwrap();
let (composite_program, composite_position_attribute, composite_tex_coord_attribute);

View File

@ -12,6 +12,7 @@
use compute_shader;
use gl::types::GLenum;
use std::io;
/// An OpenGL error with the given code.
///
@ -26,6 +27,9 @@ pub enum InitError {
/// An OpenGL error occurred.
GlError(GlError),
/// A shader could not be loaded.
ShaderUnreadable(io::Error),
/// Shader compilation failed.
///
/// The first string specifies the type of shader (vertex, fragment, etc.); the second holds

View File

@ -25,19 +25,20 @@ use gl;
use outline::{Outlines, Vertex};
use std::ascii::AsciiExt;
use std::env;
use std::fs::File;
use std::io::Read;
use std::mem;
use std::path::{Path, PathBuf};
use std::ptr;
// TODO(pcwalton): Don't force that these be compiled in.
static ACCUM_CL_SHADER: &'static str = include_str!("../resources/shaders/accum.cl");
static ACCUM_COMPUTE_SHADER: &'static str = include_str!("../resources/shaders/accum.cs.glsl");
static ACCUM_CL_SHADER_FILENAME: &'static str = "accum.cl";
static ACCUM_COMPUTE_SHADER_FILENAME: &'static str = "accum.cs.glsl";
static DRAW_VERTEX_SHADER: &'static str = include_str!("../resources/shaders/draw.vs.glsl");
static DRAW_TESS_CONTROL_SHADER: &'static str = include_str!("../resources/shaders/draw.tcs.glsl");
static DRAW_TESS_EVALUATION_SHADER: &'static str =
include_str!("../resources/shaders/draw.tes.glsl");
static DRAW_GEOMETRY_SHADER: &'static str = include_str!("../resources/shaders/draw.gs.glsl");
static DRAW_FRAGMENT_SHADER: &'static str = include_str!("../resources/shaders/draw.fs.glsl");
static DRAW_VERTEX_SHADER_FILENAME: &'static str = "draw.vs.glsl";
static DRAW_TESS_CONTROL_SHADER_FILENAME: &'static str = "draw.tcs.glsl";
static DRAW_TESS_EVALUATION_SHADER_FILENAME: &'static str = "draw.tes.glsl";
static DRAW_GEOMETRY_SHADER_FILENAME: &'static str = "draw.gs.glsl";
static DRAW_FRAGMENT_SHADER_FILENAME: &'static str = "draw.fs.glsl";
/// A GPU rasterizer for glyphs.
pub struct Rasterizer {
@ -92,27 +93,32 @@ impl Rasterizer {
let vertex_shader = try!(compile_gl_shader(gl::VERTEX_SHADER,
"Vertex shader",
DRAW_VERTEX_SHADER));
DRAW_VERTEX_SHADER_FILENAME,
&options.shader_path));
gl::AttachShader(draw_program, vertex_shader);
let fragment_shader = try!(compile_gl_shader(gl::FRAGMENT_SHADER,
"Fragment shader",
DRAW_FRAGMENT_SHADER));
DRAW_FRAGMENT_SHADER_FILENAME,
&options.shader_path));
gl::AttachShader(draw_program, fragment_shader);
if options.force_geometry_shader {
let geometry_shader = try!(compile_gl_shader(gl::GEOMETRY_SHADER,
"Geometry shader",
DRAW_GEOMETRY_SHADER));
DRAW_GEOMETRY_SHADER_FILENAME,
&options.shader_path));
gl::AttachShader(draw_program, geometry_shader);
} else {
let tess_control_shader = try!(compile_gl_shader(gl::TESS_CONTROL_SHADER,
"Tessellation control shader",
DRAW_TESS_CONTROL_SHADER));
DRAW_TESS_CONTROL_SHADER_FILENAME,
&options.shader_path));
gl::AttachShader(draw_program, tess_control_shader);
let tess_evaluation_shader =
try!(compile_gl_shader(gl::TESS_EVALUATION_SHADER,
"Tessellation evaluation shader",
DRAW_TESS_EVALUATION_SHADER));
DRAW_TESS_EVALUATION_SHADER_FILENAME,
&options.shader_path));
gl::AttachShader(draw_program, tess_evaluation_shader);
}
@ -144,12 +150,25 @@ impl Rasterizer {
// FIXME(pcwalton): Don't panic if this fails to compile; just return an error.
let shading_language = instance.shading_language();
let accum_source = match shading_language {
ShadingLanguage::Cl => ACCUM_CL_SHADER,
ShadingLanguage::Glsl => ACCUM_COMPUTE_SHADER,
let accum_filename = match shading_language {
ShadingLanguage::Cl => ACCUM_CL_SHADER_FILENAME,
ShadingLanguage::Glsl => ACCUM_COMPUTE_SHADER_FILENAME,
};
let accum_program = try!(device.create_program(accum_source)
let mut accum_path = options.shader_path.to_owned();
accum_path.push(accum_filename);
let mut accum_file = match File::open(&accum_path) {
Err(error) => return Err(InitError::ShaderUnreadable(error)),
Ok(file) => file,
};
let mut accum_source = String::new();
if accum_file.read_to_string(&mut accum_source).is_err() {
return Err(InitError::CompileFailed("Compute shader", "Invalid UTF-8".to_string()))
}
let accum_program = try!(device.create_program(&accum_source)
.map_err(InitError::ComputeError));
Ok(Rasterizer {
@ -296,9 +315,25 @@ impl Rasterizer {
}
}
fn compile_gl_shader(shader_type: GLuint, description: &'static str, source: &str)
fn compile_gl_shader(shader_type: GLuint,
description: &'static str,
filename: &str,
shader_path: &Path)
-> Result<GLuint, InitError> {
unsafe {
let mut path = shader_path.to_owned();
path.push(filename);
let mut file = match File::open(&path) {
Err(error) => return Err(InitError::ShaderUnreadable(error)),
Ok(file) => file,
};
let mut source = String::new();
if file.read_to_string(&mut source).is_err() {
return Err(InitError::CompileFailed(description, "Invalid UTF-8".to_string()))
}
let shader = gl::CreateShader(shader_type);
gl::ShaderSource(shader, 1, &(source.as_ptr() as *const GLchar), &(source.len() as GLint));
gl::CompileShader(shader);
@ -338,8 +373,13 @@ fn check_gl_object_status(object: GLuint,
}
/// Options that control Pathfinder's behavior.
#[derive(Clone, Copy, Debug)]
#[derive(Clone, Debug)]
pub struct RasterizerOptions {
/// The path to the shaders.
///
/// If not specified, then the current directory is used. This is probably not what you want.
/// The corresponding environment variable is `PATHFINDER_SHADER_PATH`.
pub shader_path: PathBuf,
/// If true, then a geometry shader is used instead of a tessellation shader.
///
/// This will probably negatively impact performance. This should be considered a debugging
@ -353,6 +393,7 @@ pub struct RasterizerOptions {
impl Default for RasterizerOptions {
fn default() -> RasterizerOptions {
RasterizerOptions {
shader_path: PathBuf::from("."),
force_geometry_shader: false,
}
}
@ -369,6 +410,11 @@ impl RasterizerOptions {
///
/// Environment variables not set cause their associated settings to take on default values.
pub fn from_env() -> Result<RasterizerOptions, InitError> {
let shader_path = match env::var("PATHFINDER_SHADER_PATH") {
Ok(ref string) => PathBuf::from(string),
Err(_) => PathBuf::from("."),
};
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") ||
@ -381,6 +427,7 @@ impl RasterizerOptions {
};
Ok(RasterizerOptions {
shader_path: shader_path,
force_geometry_shader: force_geometry_shader,
})
}