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 pathfinder::rasterizer::{Rasterizer, RasterizerOptions};
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::os::raw::c_void;
|
use std::os::raw::c_void;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
const ATLAS_SIZE: u32 = 2048;
|
const ATLAS_SIZE: u32 = 2048;
|
||||||
const WIDTH: u32 = 512;
|
const WIDTH: u32 = 512;
|
||||||
|
@ -35,6 +36,8 @@ const HEIGHT: u32 = 384;
|
||||||
const MIN_TIME_PER_SIZE: u64 = 300_000_000;
|
const MIN_TIME_PER_SIZE: u64 = 300_000_000;
|
||||||
const MAX_TIME_PER_SIZE: u64 = 3_000_000_000;
|
const MAX_TIME_PER_SIZE: u64 = 3_000_000_000;
|
||||||
|
|
||||||
|
static SHADER_PATH: &'static str = "resources/shaders/";
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut glfw = glfw::init(glfw::LOG_ERRORS).unwrap();
|
let mut glfw = glfw::init(glfw::LOG_ERRORS).unwrap();
|
||||||
glfw.window_hint(WindowHint::ContextVersion(3, 3));
|
glfw.window_hint(WindowHint::ContextVersion(3, 3));
|
||||||
|
@ -51,7 +54,11 @@ fn main() {
|
||||||
let device = instance.open_device().unwrap();
|
let device = instance.open_device().unwrap();
|
||||||
let queue = device.create_queue().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 rasterizer = Rasterizer::new(&instance, device, queue, rasterizer_options).unwrap();
|
||||||
|
|
||||||
for point_size in 6..201 {
|
for point_size in 6..201 {
|
||||||
|
|
|
@ -24,12 +24,16 @@ use pathfinder::coverage::CoverageBuffer;
|
||||||
use pathfinder::outline::OutlineBuilder;
|
use pathfinder::outline::OutlineBuilder;
|
||||||
use pathfinder::otf::Font;
|
use pathfinder::otf::Font;
|
||||||
use pathfinder::rasterizer::{Rasterizer, RasterizerOptions};
|
use pathfinder::rasterizer::{Rasterizer, RasterizerOptions};
|
||||||
|
use std::env;
|
||||||
use std::os::raw::c_void;
|
use std::os::raw::c_void;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
const DEFAULT_POINT_SIZE: f32 = 24.0;
|
const DEFAULT_POINT_SIZE: f32 = 24.0;
|
||||||
const WIDTH: u32 = 512;
|
const WIDTH: u32 = 512;
|
||||||
const HEIGHT: u32 = 384;
|
const HEIGHT: u32 = 384;
|
||||||
|
|
||||||
|
static SHADER_PATH: &'static str = "resources/shaders/";
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let index_arg = Arg::with_name("index").short("i")
|
let index_arg = Arg::with_name("index").short("i")
|
||||||
.long("index")
|
.long("index")
|
||||||
|
@ -60,7 +64,11 @@ fn main() {
|
||||||
let device = instance.open_device().unwrap();
|
let device = instance.open_device().unwrap();
|
||||||
let queue = device.create_queue().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 rasterizer = Rasterizer::new(&instance, device, queue, rasterizer_options).unwrap();
|
||||||
|
|
||||||
let file = Mmap::open_path(matches.value_of("FONT-FILE").unwrap(), Protection::Read).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::rasterizer::{DrawAtlasProfilingEvents, Rasterizer, RasterizerOptions};
|
||||||
use pathfinder::shaper;
|
use pathfinder::shaper;
|
||||||
use std::char;
|
use std::char;
|
||||||
|
use std::env;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::os::raw::c_void;
|
use std::os::raw::c_void;
|
||||||
use std::path::Path;
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
const ATLAS_SIZE: u32 = 2048;
|
const ATLAS_SIZE: u32 = 2048;
|
||||||
const WIDTH: u32 = 640;
|
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_DISPLAY_POINT_SIZE: f32 = 24.0;
|
||||||
const FPS_PADDING: i32 = 6;
|
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_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 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];
|
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 device = instance.open_device().unwrap();
|
||||||
let queue = device.create_queue().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 rasterizer = Rasterizer::new(&instance, device, queue, rasterizer_options).unwrap();
|
||||||
|
|
||||||
let (composite_program, composite_position_attribute, composite_tex_coord_attribute);
|
let (composite_program, composite_position_attribute, composite_tex_coord_attribute);
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
use compute_shader;
|
use compute_shader;
|
||||||
use gl::types::GLenum;
|
use gl::types::GLenum;
|
||||||
|
use std::io;
|
||||||
|
|
||||||
/// An OpenGL error with the given code.
|
/// An OpenGL error with the given code.
|
||||||
///
|
///
|
||||||
|
@ -26,6 +27,9 @@ pub enum InitError {
|
||||||
/// An OpenGL error occurred.
|
/// An OpenGL error occurred.
|
||||||
GlError(GlError),
|
GlError(GlError),
|
||||||
|
|
||||||
|
/// A shader could not be loaded.
|
||||||
|
ShaderUnreadable(io::Error),
|
||||||
|
|
||||||
/// Shader compilation failed.
|
/// Shader compilation failed.
|
||||||
///
|
///
|
||||||
/// The first string specifies the type of shader (vertex, fragment, etc.); the second holds
|
/// 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 outline::{Outlines, Vertex};
|
||||||
use std::ascii::AsciiExt;
|
use std::ascii::AsciiExt;
|
||||||
use std::env;
|
use std::env;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::Read;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
// TODO(pcwalton): Don't force that these be compiled in.
|
static ACCUM_CL_SHADER_FILENAME: &'static str = "accum.cl";
|
||||||
static ACCUM_CL_SHADER: &'static str = include_str!("../resources/shaders/accum.cl");
|
static ACCUM_COMPUTE_SHADER_FILENAME: &'static str = "accum.cs.glsl";
|
||||||
static ACCUM_COMPUTE_SHADER: &'static str = include_str!("../resources/shaders/accum.cs.glsl");
|
|
||||||
|
|
||||||
static DRAW_VERTEX_SHADER: &'static str = include_str!("../resources/shaders/draw.vs.glsl");
|
static DRAW_VERTEX_SHADER_FILENAME: &'static str = "draw.vs.glsl";
|
||||||
static DRAW_TESS_CONTROL_SHADER: &'static str = include_str!("../resources/shaders/draw.tcs.glsl");
|
static DRAW_TESS_CONTROL_SHADER_FILENAME: &'static str = "draw.tcs.glsl";
|
||||||
static DRAW_TESS_EVALUATION_SHADER: &'static str =
|
static DRAW_TESS_EVALUATION_SHADER_FILENAME: &'static str = "draw.tes.glsl";
|
||||||
include_str!("../resources/shaders/draw.tes.glsl");
|
static DRAW_GEOMETRY_SHADER_FILENAME: &'static str = "draw.gs.glsl";
|
||||||
static DRAW_GEOMETRY_SHADER: &'static str = include_str!("../resources/shaders/draw.gs.glsl");
|
static DRAW_FRAGMENT_SHADER_FILENAME: &'static str = "draw.fs.glsl";
|
||||||
static DRAW_FRAGMENT_SHADER: &'static str = include_str!("../resources/shaders/draw.fs.glsl");
|
|
||||||
|
|
||||||
/// A GPU rasterizer for glyphs.
|
/// A GPU rasterizer for glyphs.
|
||||||
pub struct Rasterizer {
|
pub struct Rasterizer {
|
||||||
|
@ -92,27 +93,32 @@ impl Rasterizer {
|
||||||
|
|
||||||
let vertex_shader = try!(compile_gl_shader(gl::VERTEX_SHADER,
|
let vertex_shader = try!(compile_gl_shader(gl::VERTEX_SHADER,
|
||||||
"Vertex shader",
|
"Vertex shader",
|
||||||
DRAW_VERTEX_SHADER));
|
DRAW_VERTEX_SHADER_FILENAME,
|
||||||
|
&options.shader_path));
|
||||||
gl::AttachShader(draw_program, vertex_shader);
|
gl::AttachShader(draw_program, vertex_shader);
|
||||||
let fragment_shader = try!(compile_gl_shader(gl::FRAGMENT_SHADER,
|
let fragment_shader = try!(compile_gl_shader(gl::FRAGMENT_SHADER,
|
||||||
"Fragment shader",
|
"Fragment shader",
|
||||||
DRAW_FRAGMENT_SHADER));
|
DRAW_FRAGMENT_SHADER_FILENAME,
|
||||||
|
&options.shader_path));
|
||||||
gl::AttachShader(draw_program, fragment_shader);
|
gl::AttachShader(draw_program, fragment_shader);
|
||||||
|
|
||||||
if options.force_geometry_shader {
|
if options.force_geometry_shader {
|
||||||
let geometry_shader = try!(compile_gl_shader(gl::GEOMETRY_SHADER,
|
let geometry_shader = try!(compile_gl_shader(gl::GEOMETRY_SHADER,
|
||||||
"Geometry shader",
|
"Geometry shader",
|
||||||
DRAW_GEOMETRY_SHADER));
|
DRAW_GEOMETRY_SHADER_FILENAME,
|
||||||
|
&options.shader_path));
|
||||||
gl::AttachShader(draw_program, geometry_shader);
|
gl::AttachShader(draw_program, geometry_shader);
|
||||||
} else {
|
} else {
|
||||||
let tess_control_shader = try!(compile_gl_shader(gl::TESS_CONTROL_SHADER,
|
let tess_control_shader = try!(compile_gl_shader(gl::TESS_CONTROL_SHADER,
|
||||||
"Tessellation control shader",
|
"Tessellation control shader",
|
||||||
DRAW_TESS_CONTROL_SHADER));
|
DRAW_TESS_CONTROL_SHADER_FILENAME,
|
||||||
|
&options.shader_path));
|
||||||
gl::AttachShader(draw_program, tess_control_shader);
|
gl::AttachShader(draw_program, tess_control_shader);
|
||||||
let tess_evaluation_shader =
|
let tess_evaluation_shader =
|
||||||
try!(compile_gl_shader(gl::TESS_EVALUATION_SHADER,
|
try!(compile_gl_shader(gl::TESS_EVALUATION_SHADER,
|
||||||
"Tessellation evaluation shader",
|
"Tessellation evaluation shader",
|
||||||
DRAW_TESS_EVALUATION_SHADER));
|
DRAW_TESS_EVALUATION_SHADER_FILENAME,
|
||||||
|
&options.shader_path));
|
||||||
gl::AttachShader(draw_program, tess_evaluation_shader);
|
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.
|
// FIXME(pcwalton): Don't panic if this fails to compile; just return an error.
|
||||||
let shading_language = instance.shading_language();
|
let shading_language = instance.shading_language();
|
||||||
let accum_source = match shading_language {
|
let accum_filename = match shading_language {
|
||||||
ShadingLanguage::Cl => ACCUM_CL_SHADER,
|
ShadingLanguage::Cl => ACCUM_CL_SHADER_FILENAME,
|
||||||
ShadingLanguage::Glsl => ACCUM_COMPUTE_SHADER,
|
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));
|
.map_err(InitError::ComputeError));
|
||||||
|
|
||||||
Ok(Rasterizer {
|
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> {
|
-> Result<GLuint, InitError> {
|
||||||
unsafe {
|
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);
|
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);
|
||||||
|
@ -338,8 +373,13 @@ fn check_gl_object_status(object: GLuint,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Options that control Pathfinder's behavior.
|
/// Options that control Pathfinder's behavior.
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct RasterizerOptions {
|
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.
|
/// 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
|
/// This will probably negatively impact performance. This should be considered a debugging
|
||||||
|
@ -353,6 +393,7 @@ pub struct RasterizerOptions {
|
||||||
impl Default for RasterizerOptions {
|
impl Default for RasterizerOptions {
|
||||||
fn default() -> RasterizerOptions {
|
fn default() -> RasterizerOptions {
|
||||||
RasterizerOptions {
|
RasterizerOptions {
|
||||||
|
shader_path: PathBuf::from("."),
|
||||||
force_geometry_shader: false,
|
force_geometry_shader: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -369,6 +410,11 @@ impl RasterizerOptions {
|
||||||
///
|
///
|
||||||
/// Environment variables not set cause their associated settings to take on default values.
|
/// Environment variables not set cause their associated settings to take on default values.
|
||||||
pub fn from_env() -> Result<RasterizerOptions, InitError> {
|
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") {
|
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") ||
|
||||||
|
@ -381,6 +427,7 @@ impl RasterizerOptions {
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(RasterizerOptions {
|
Ok(RasterizerOptions {
|
||||||
|
shader_path: shader_path,
|
||||||
force_geometry_shader: force_geometry_shader,
|
force_geometry_shader: force_geometry_shader,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue