Read shaders from disk instead of compiling them into the binary
This commit is contained in:
parent
c4c19076c7
commit
959293839f
|
@ -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 {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue