diff --git a/webrender/Cargo.toml b/webrender/Cargo.toml index 4f51eaf484..f32342b64c 100644 --- a/webrender/Cargo.toml +++ b/webrender/Cargo.toml @@ -63,8 +63,6 @@ optional = true [dev-dependencies] mozangle = "0.1" -ron = "0.1.7" -serde = { version = "1.0", features = ["serde_derive"] } [target.'cfg(any(target_os = "android", all(unix, not(target_os = "macos"))))'.dependencies] freetype = { version = "0.4", default-features = false } @@ -76,7 +74,3 @@ dwrote = "0.4.1" core-foundation = "0.6" core-graphics = "0.14" core-text = { version = "10", default-features = false } - -[build-dependencies] -ron = "0.1.7" -serde = { version = "1.0", features = ["serde_derive"] } diff --git a/webrender/build.rs b/webrender/build.rs index 04e3c31a5f..53b7450e8f 100644 --- a/webrender/build.rs +++ b/webrender/build.rs @@ -2,33 +2,22 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -extern crate ron; -#[macro_use] -extern crate serde; - -use ron::de; use std::env; use std::fs::{canonicalize, read_dir, File}; use std::io::prelude::*; -use std::collections::HashMap; use std::path::{Path, PathBuf}; -const SHADER_IMPORT: &str = "#include "; -const SHADER_KIND_FRAGMENT: &str = "#define WR_FRAGMENT_SHADER\n"; -const SHADER_KIND_VERTEX: &str = "#define WR_VERTEX_SHADER\n"; -const SHADER_PREFIX: &str = "#define WR_MAX_VERTEX_TEXTURE_WIDTH 1024\n"; - -const SHADER_VERSION: &str = "#version 150\n"; - -#[derive(Deserialize)] -struct Shader { - name: String, - feature_sets: Vec, -} - -fn create_map(glsl_files: Vec) -> HashMap { - let mut shader_map: HashMap = HashMap::new(); - +fn write_shaders(glsl_files: Vec, shader_file_path: &Path) { + let mut shader_file = File::create(shader_file_path).unwrap(); + + write!(shader_file, "/// AUTO GENERATED BY build.rs\n\n").unwrap(); + write!(shader_file, "use std::collections::HashMap;\n").unwrap(); + write!(shader_file, "lazy_static! {{\n").unwrap(); + write!( + shader_file, + " pub static ref SHADERS: HashMap<&'static str, &'static str> = {{\n" + ).unwrap(); + write!(shader_file, " let mut h = HashMap::new();\n").unwrap(); for glsl in glsl_files { let shader_name = glsl.file_name().unwrap().to_str().unwrap(); // strip .glsl @@ -38,136 +27,22 @@ fn create_map(glsl_files: Vec) -> HashMap { // if someone is building on a network share, I'm sorry. let full_name = full_name.replace("\\\\?\\", ""); let full_name = full_name.replace("\\", "/"); - shader_map.insert(shader_name.clone(), full_name.clone()); - } - shader_map -} - -// Get a shader string by name -fn get_shader_source(shader_name: &str, shaders: &HashMap) -> String { - let shader_file_path = Path::new(&shaders[shader_name]); - let mut shader_source_file = - File::open(shader_file_path).expect(&format!("Unable to open shader file: {:?}", shader_file_path)); - let mut source = String::new(); - shader_source_file.read_to_string(&mut source).unwrap(); - source -} - -// Parse a shader string for imports. Imports are recursively processed, and -// prepended to the list of outputs. -fn parse_shader_source(source: String, shaders: &HashMap, output: &mut String) { - for line in source.lines() { - if line.starts_with(SHADER_IMPORT) { - let imports = line[SHADER_IMPORT.len() ..].split(','); - - // For each import, get the source, and recurse. - for import in imports { - let include = get_shader_source(import, shaders); - parse_shader_source(include, shaders, output); - } - } else { - output.push_str(line); - output.push_str("\n"); - } - } -} - -fn build_shader_strings( - gl_version_string: &str, - features: &str, - base_filename: &str, - shaders: &HashMap, -) -> (String, String) { - // Construct a list of strings to be passed to the shader compiler. - let mut vs_source = String::new(); - let mut fs_source = String::new(); - - // GLSL requires that the version number comes first. - vs_source.push_str(gl_version_string); - fs_source.push_str(gl_version_string); - - // Insert the shader name to make debugging easier. - let name_string = format!("// {}\n", base_filename); - vs_source.push_str(&name_string); - fs_source.push_str(&name_string); - - // Define a constant depending on whether we are compiling VS or FS. - vs_source.push_str(SHADER_KIND_VERTEX); - fs_source.push_str(SHADER_KIND_FRAGMENT); - - // Add any defines that were passed by the caller. - vs_source.push_str(features); - fs_source.push_str(features); - - // Parse the main .glsl file, including any imports - // and append them to the list of sources. - let mut shared_result = String::new(); - let shared_source = get_shader_source(base_filename, shaders); - parse_shader_source(shared_source, shaders, &mut shared_result); - - vs_source.push_str(&shared_result); - fs_source.push_str(&shared_result); - - (vs_source, fs_source) -} - -fn generate_shaders(out_dir: &str, shaders: HashMap) { - let file = File::open("res/shaders.ron").expect("Unable to open shaders.ron"); - let shader_configs: Vec = de::from_reader(file).expect("Unable to deserialize shaders.ron"); - - for shader in shader_configs { - let mut feature_variants: Vec = Vec::new(); - - // Building up possible permutations of features - for feature_set in shader.feature_sets { - if feature_variants.is_empty() { - feature_variants = feature_set.split(',').map(|s| s.to_owned()).collect(); - } else { - let prev_variants: Vec = feature_variants.drain(..).collect(); - for variant in prev_variants.iter() { - for feature in feature_set.split(',') { - feature_variants.push(format!("{},{}", variant, feature)); - } - } - } - } - - // Creating a shader file for each permutation - for variant in feature_variants { - let mut features = String::new(); - - features.push_str(SHADER_PREFIX); - features.push_str(format!("//Source: {}.glsl\n", shader.name).as_str()); - - let mut file_name_postfix = String::new(); - for feature in variant.split(',') { - if !feature.is_empty() { - features.push_str(&format!("#define WR_FEATURE_{}\n", feature)); - file_name_postfix - .push_str(&format!("_{}", feature.to_lowercase().as_str())); - } - } - - let (mut vs_source, mut fs_source) = - build_shader_strings(SHADER_VERSION, &features, &shader.name, &shaders); - - let (vs_file_path, fs_file_path) = ( - Path::new(out_dir).join(format!("{}{}.vert", &shader.name, &file_name_postfix)), - Path::new(out_dir).join(format!("{}{}.frag", &shader.name, &file_name_postfix)), - ); - let (mut vs_file, mut fs_file) = ( - File::create(vs_file_path).unwrap(), - File::create(fs_file_path).unwrap(), - ); - write!(vs_file, "{}", vs_source).unwrap(); - write!(fs_file, "{}", fs_source).unwrap(); - } + write!( + shader_file, + " h.insert(\"{}\", include_str!(\"{}\"));\n", + shader_name, + full_name + ).unwrap(); } + write!(shader_file, " h\n").unwrap(); + write!(shader_file, " }};\n").unwrap(); + write!(shader_file, "}}\n").unwrap(); } fn main() { let out_dir = env::var("OUT_DIR").unwrap_or("out".to_owned()); + let shaders_file = Path::new(&out_dir).join("shaders.rs"); let mut glsl_files = vec![]; println!("cargo:rerun-if-changed=res"); @@ -181,6 +56,10 @@ fn main() { glsl_files.push(path.to_owned()); } } - let shaders_map = create_map(glsl_files); - generate_shaders(&out_dir, shaders_map); + + // Sort the file list so that the shaders.rs file is filled + // deterministically. + glsl_files.sort_by(|a, b| a.file_name().cmp(&b.file_name())); + + write_shaders(glsl_files, &shaders_file); } diff --git a/webrender/res/shaders.ron b/webrender/res/shaders.ron deleted file mode 100644 index 1a7e6ca75e..0000000000 --- a/webrender/res/shaders.ron +++ /dev/null @@ -1,130 +0,0 @@ -[ - ( - name: "cs_blur", - feature_sets: [ - "ALPHA_TARGET,COLOR_TARGET", // cs_blur_a8 and cs_blur_rgba8 - ], - ),// [0] - ( - name: "cs_border_segment", - feature_sets: [ - "", - ], - ),// [1] - ( - name: "brush_solid", - feature_sets: [ - ",ALPHA_PASS", // Brush shader feature - ], - ),// [2] - ( - name: "brush_image", - feature_sets: [ - ",TEXTURE_2D,TEXTURE_RECT,TEXTURE_EXTERNAL",// Image buffer kinds - ",ALPHA_PASS", // Brush shader feature - ",DUAL_SOURCE_BLENDING", // Optional brush shader feature - ], - ),// [3] - ( - name: "brush_blend", - feature_sets: [ - ",ALPHA_PASS", // Brush shader feature - ], - ),// [4] - ( - name: "brush_mix_blend", - feature_sets: [ - ",ALPHA_PASS", // Brush shader feature - ], - ),// [5] - ( - name: "brush_yuv_image", - feature_sets: [ - ",TEXTURE_2D,TEXTURE_RECT,TEXTURE_EXTERNAL",// Image buffer kinds - "YUV_NV12,YUV_PLANAR,YUV_INTERLEAVED", // Yuv formats - "YUV_REC601,YUV_REC709", // Yuv color spaces - ",ALPHA_PASS", // Brush shader feature - ], - ),// [6] - ( - name: "brush_radial_gradient", - feature_sets: [ - ",DITHERING", // Dither feature - ",ALPHA_PASS", // Brush shader feature - ], - ),// [7] - ( - name: "brush_linear_gradient", - feature_sets: [ - ",DITHERING", // Dither feature - ",ALPHA_PASS", // Brush shader feature - ], - ),// [8] - ( - name: "cs_clip_rectangle", - feature_sets: [ - "TRANSFORM", // ClipCache shader feature - ], - ),// [9] - ( - name: "cs_clip_box_shadow", - feature_sets: [ - "TRANSFORM", // ClipCache shader feature - ], - ),// [10] - ( - name: "cs_clip_image", - feature_sets: [ - "TRANSFORM", // ClipCache shader feature - ], - ),// [11] - ( - name: "cs_clip_line", - feature_sets: [ - "TRANSFORM", // ClipCache shader feature - ], - ),// [12] - ( - name: "ps_text_run", - feature_sets: [ - ",DUAL_SOURCE_BLENDING", // ps_text_run_dual_source - ",GLYPH_TRANSFORM", // TextShader feature - ], - ),// [13] - ( - name: "ps_split_composite", - feature_sets: [ - "", - ], - ),// [14] - ( - name: "debug_color", - feature_sets: [ - "", - ], - ),// [15] - ( - name: "debug_font", - feature_sets: [ - "", - ], - ),// [16] - ( - name: "gpu_cache_update", - feature_sets: [ - "", - ], - ),// [17] - ( - name: "pf_vector_cover", - feature_sets: [ - "TEXTURE_2D", - ], - ),// [18] - ( - name: "pf_vector_stencil", - feature_sets: [ - "TEXTURE_2D", - ], - ),// [19] -] diff --git a/webrender/src/debug_render.rs b/webrender/src/debug_render.rs index 96992e7e2e..03161b5ef9 100644 --- a/webrender/src/debug_render.rs +++ b/webrender/src/debug_render.rs @@ -105,11 +105,11 @@ pub struct DebugRenderer { impl DebugRenderer { pub fn new(device: &mut Device) -> Self { - let font_program = device.create_program("debug_font", &[], &DESC_FONT).unwrap(); + let font_program = device.create_program("debug_font", "", &DESC_FONT).unwrap(); device.bind_shader_samplers(&font_program, &[("sColor0", DebugSampler::Font)]); let color_program = device - .create_program("debug_color", &[], &DESC_COLOR) + .create_program("debug_color", "", &DESC_COLOR) .unwrap(); let font_vao = device.create_vao(&DESC_FONT); diff --git a/webrender/src/device/gl.rs b/webrender/src/device/gl.rs index a87f4c70d8..5ce6b00b40 100644 --- a/webrender/src/device/gl.rs +++ b/webrender/src/device/gl.rs @@ -2,6 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +use super::super::shader_source; use api::{ColorF, ImageFormat}; use api::{DeviceIntPoint, DeviceIntRect, DeviceUintRect, DeviceUintSize}; use api::TextureTarget; @@ -53,6 +54,10 @@ const GL_FORMAT_BGRA_GLES: gl::GLuint = gl::BGRA_EXT; const SHADER_VERSION_GL: &str = "#version 150\n"; const SHADER_VERSION_GLES: &str = "#version 300 es\n"; +const SHADER_KIND_VERTEX: &str = "#define WR_VERTEX_SHADER\n"; +const SHADER_KIND_FRAGMENT: &str = "#define WR_FRAGMENT_SHADER\n"; +const SHADER_IMPORT: &str = "#include "; + pub struct TextureSlot(pub usize); // In some places we need to temporarily bind a texture to any slot. @@ -142,51 +147,83 @@ fn get_shader_version(gl: &gl::Gl) -> &'static str { } } -pub fn load_shader_sources( - gl_version_string: &str, - features: &[&str], - base_filename: &str, - override_path: &Option, -) -> (String, String) { +// Get a shader string by name, from the built in resources or +// an override path, if supplied. +fn get_shader_source(shader_name: &str, base_path: &Option) -> Option { + if let Some(ref base) = *base_path { + let shader_path = base.join(&format!("{}.glsl", shader_name)); + if shader_path.exists() { + let mut source = String::new(); + File::open(&shader_path) + .unwrap() + .read_to_string(&mut source) + .unwrap(); + return Some(source); + } + } + shader_source::SHADERS + .get(shader_name) + .map(|s| s.to_string()) +} - let (vs_path, fs_path) = { - let mut postfix = String::new(); - for feature in features { - if !feature.is_empty() { - postfix.push_str(&format!("_{}", &feature.to_lowercase())); +// Parse a shader string for imports. Imports are recursively processed, and +// prepended to the list of outputs. +fn parse_shader_source(source: String, base_path: &Option, output: &mut String) { + for line in source.lines() { + if line.starts_with(SHADER_IMPORT) { + let imports = line[SHADER_IMPORT.len() ..].split(','); + + // For each import, get the source, and recurse. + for import in imports { + if let Some(include) = get_shader_source(import, base_path) { + parse_shader_source(include, base_path, output); + } } + } else { + output.push_str(line); + output.push_str("\n"); } + } +} - let mut file_name = base_filename.to_owned(); - file_name.push_str(&postfix); +pub fn build_shader_strings( + gl_version_string: &str, + features: &str, + base_filename: &str, + override_path: &Option, +) -> (String, String) { + // Construct a list of strings to be passed to the shader compiler. + let mut vs_source = String::new(); + let mut fs_source = String::new(); - let mut vs_path = match *override_path { - Some(ref p) => PathBuf::from(p), - None => PathBuf::from(env!("OUT_DIR")), - }; + // GLSL requires that the version number comes first. + vs_source.push_str(gl_version_string); + fs_source.push_str(gl_version_string); - vs_path.push(file_name); - let mut fs_path = vs_path.clone(); - vs_path.set_extension("vert"); - fs_path.set_extension("frag"); - (vs_path, fs_path) + // Insert the shader name to make debugging easier. + let name_string = format!("// {}\n", base_filename); + vs_source.push_str(&name_string); + fs_source.push_str(&name_string); - }; + // Define a constant depending on whether we are compiling VS or FS. + vs_source.push_str(SHADER_KIND_VERTEX); + fs_source.push_str(SHADER_KIND_FRAGMENT); - let mut vs_file = - File::open(vs_path.as_path()).expect(&format!("Unable to open shader file: {:?}", vs_path)); - let mut vs_source = String::new(); - vs_file.read_to_string(&mut vs_source).unwrap(); + // Add any defines that were passed by the caller. + vs_source.push_str(features); + fs_source.push_str(features); - let mut fs_file = - File::open(fs_path.as_path()).expect(&format!("Unable to open shader file: {:?}", fs_path)); - let mut fs_source = String::new(); - fs_file.read_to_string(&mut fs_source).unwrap(); - if gl_version_string == SHADER_VERSION_GLES { - vs_source = vs_source.replacen(SHADER_VERSION_GL, SHADER_VERSION_GLES, 1); - fs_source = fs_source.replacen(SHADER_VERSION_GL, SHADER_VERSION_GLES, 1); + // Parse the main .glsl file, including any imports + // and append them to the list of sources. + let mut shared_result = String::new(); + if let Some(shared_source) = get_shader_source(base_filename, override_path) { + parse_shader_source(shared_source, override_path, &mut shared_result); } + + vs_source.push_str(&shared_result); + fs_source.push_str(&shared_result); + (vs_source, fs_source) } @@ -1375,17 +1412,19 @@ impl Device { pub fn create_program( &mut self, base_filename: &str, - features: &[&'static str], + features: &str, descriptor: &VertexDescriptor, ) -> Result { debug_assert!(self.inside_frame); - let (vs_source, fs_source) = - load_shader_sources( - get_shader_version(&*self.gl), - features, - base_filename, - &self.resource_override_path); + let gl_version_string = get_shader_version(&*self.gl); + + let (vs_source, fs_source) = build_shader_strings( + gl_version_string, + features, + base_filename, + &self.resource_override_path, + ); let sources = ProgramSources::new(self.renderer_name.clone(), vs_source, fs_source); diff --git a/webrender/src/lib.rs b/webrender/src/lib.rs index 9de4335eea..3e567adbeb 100644 --- a/webrender/src/lib.rs +++ b/webrender/src/lib.rs @@ -44,7 +44,7 @@ they're nestable. extern crate bitflags; #[macro_use] extern crate cfg_if; -#[cfg_attr(target_os = "windows", macro_use)] +#[macro_use] extern crate lazy_static; #[macro_use] extern crate log; @@ -104,6 +104,10 @@ mod texture_cache; mod tiling; mod util; +mod shader_source { + include!(concat!(env!("OUT_DIR"), "/shaders.rs")); +} + pub use record::{ApiRecordingReceiver, BinaryRecorder, WEBRENDER_RECORDING_HEADER}; mod platform { @@ -176,7 +180,7 @@ extern crate png; pub extern crate webrender_api; #[doc(hidden)] -pub use device::{load_shader_sources, ReadPixelsFormat, UploadMethod, VertexUsageHint}; +pub use device::{build_shader_strings, ReadPixelsFormat, UploadMethod, VertexUsageHint}; pub use device::{ProgramBinary, ProgramCache, ProgramCacheObserver, ProgramSources}; pub use frame_builder::ChasePrimitive; pub use renderer::{AsyncPropertySampler, CpuProfile, DebugFlags, OutputImageHandler, RendererKind}; diff --git a/webrender/src/renderer.rs b/webrender/src/renderer.rs index e038b66174..975fec04ae 100644 --- a/webrender/src/renderer.rs +++ b/webrender/src/renderer.rs @@ -966,7 +966,7 @@ impl CacheTexture { let bus = if use_scatter { let program = device - .create_program("gpu_cache_update", &[], &desc::GPU_CACHE_UPDATE)?; + .create_program("gpu_cache_update", "", &desc::GPU_CACHE_UPDATE)?; let buf_position = device.create_vbo(); let buf_value = device.create_vbo(); //Note: the vertex attributes have to be supplied in the same order diff --git a/webrender/src/shade.rs b/webrender/src/shade.rs index 6a9618f2a8..7549f92ff2 100644 --- a/webrender/src/shade.rs +++ b/webrender/src/shade.rs @@ -12,6 +12,7 @@ use euclid::{Transform3D}; use glyph_rasterizer::GlyphFormat; use renderer::{ desc, + MAX_VERTEX_TEXTURE_WIDTH, BlendMode, ImageBufferKind, RendererError, RendererOptions, TextureSampler, VertexArrayKind, }; @@ -318,6 +319,15 @@ fn create_prim_shader( features: &[&'static str], vertex_format: VertexArrayKind, ) -> Result { + let mut prefix = format!( + "#define WR_MAX_VERTEX_TEXTURE_WIDTH {}\n", + MAX_VERTEX_TEXTURE_WIDTH + ); + + for feature in features { + prefix.push_str(&format!("#define WR_FEATURE_{}\n", feature)); + } + debug!("PrimShader {}", name); let vertex_descriptor = match vertex_format { @@ -329,7 +339,7 @@ fn create_prim_shader( VertexArrayKind::Border => desc::BORDER, }; - let program = device.create_program(name, &features, &vertex_descriptor); + let program = device.create_program(name, &prefix, &vertex_descriptor); if let Ok(ref program) = program { device.bind_shader_samplers( @@ -355,9 +365,15 @@ fn create_prim_shader( } fn create_clip_shader(name: &'static str, device: &mut Device) -> Result { + let prefix = format!( + "#define WR_MAX_VERTEX_TEXTURE_WIDTH {}\n + #define WR_FEATURE_TRANSFORM\n", + MAX_VERTEX_TEXTURE_WIDTH + ); + debug!("ClipShader {}", name); - let program = device.create_program(name, &["TRANSFORM"], &desc::CLIP); + let program = device.create_program(name, &prefix, &desc::CLIP); if let Ok(ref program) = program { device.bind_shader_samplers( diff --git a/webrender/tests/angle_shader_validation.rs b/webrender/tests/angle_shader_validation.rs index 58bd5f5a36..5c0db40c7d 100644 --- a/webrender/tests/angle_shader_validation.rs +++ b/webrender/tests/angle_shader_validation.rs @@ -3,31 +3,103 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ extern crate mozangle; -extern crate ron; -#[macro_use] -extern crate serde; extern crate webrender; use mozangle::shaders::{BuiltInResources, Output, ShaderSpec, ShaderValidator}; -use ron::de; -use std::fs::File; -use std::path::PathBuf; // from glslang const FRAGMENT_SHADER: u32 = 0x8B30; const VERTEX_SHADER: u32 = 0x8B31; -const VERSION_STRING: &str = "#version 300 es\n"; - -// Extensions required by these features are not supported by the angle shader validator. -const EXCLUDED_FEATURES: &'static[&'static str] = &["DUAL_SOURCE_BLENDING", "TEXTURE_EXTERNAL", "TEXTURE_RECT"]; - -#[derive(Deserialize)] struct Shader { - name: String, - feature_sets: Vec, + name: &'static str, + features: &'static [&'static str], } +const SHADER_PREFIX: &str = "#define WR_MAX_VERTEX_TEXTURE_WIDTH 1024\n"; + +const BRUSH_FEATURES: &[&str] = &["", "ALPHA_PASS"]; +const CLIP_FEATURES: &[&str] = &["TRANSFORM"]; +const CACHE_FEATURES: &[&str] = &[""]; +const GRADIENT_FEATURES: &[&str] = &[ "", "DITHERING", "ALPHA_PASS", "DITHERING,ALPHA_PASS" ]; +const PRIM_FEATURES: &[&str] = &[""]; + +const SHADERS: &[Shader] = &[ + // Clip mask shaders + Shader { + name: "cs_clip_rectangle", + features: CLIP_FEATURES, + }, + Shader { + name: "cs_clip_image", + features: CLIP_FEATURES, + }, + Shader { + name: "cs_clip_box_shadow", + features: CLIP_FEATURES, + }, + Shader { + name: "cs_clip_line", + features: CLIP_FEATURES, + }, + // Cache shaders + Shader { + name: "cs_blur", + features: &[ "ALPHA_TARGET", "COLOR_TARGET" ], + }, + Shader { + name: "cs_border_segment", + features: CACHE_FEATURES, + }, + // Prim shaders + Shader { + name: "ps_split_composite", + features: PRIM_FEATURES, + }, + Shader { + name: "ps_text_run", + features: &[ "", "GLYPH_TRANSFORM" ], + }, + // Brush shaders + Shader { + name: "brush_yuv_image", + features: &[ + "", + "YUV_NV12", + "YUV_PLANAR", + "YUV_INTERLEAVED", + "TEXTURE_2D,YUV_NV12", + "YUV_NV12,ALPHA_PASS", + ], + }, + Shader { + name: "brush_solid", + features: BRUSH_FEATURES, + }, + Shader { + name: "brush_image", + features: BRUSH_FEATURES, + }, + Shader { + name: "brush_blend", + features: BRUSH_FEATURES, + }, + Shader { + name: "brush_mix_blend", + features: BRUSH_FEATURES, + }, + Shader { + name: "brush_radial_gradient", + features: GRADIENT_FEATURES, + }, + Shader { + name: "brush_linear_gradient", + features: GRADIENT_FEATURES, + }, +]; + +const VERSION_STRING: &str = "#version 300 es\n"; + #[test] fn validate_shaders() { mozangle::shaders::initialize().unwrap(); @@ -39,49 +111,25 @@ fn validate_shaders() { let fs_validator = ShaderValidator::new(FRAGMENT_SHADER, ShaderSpec::Gles3, Output::Essl, &resources).unwrap(); - let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - path.push("res"); - path.push("shaders.ron"); - - let file = File::open(&path).expect("Unable to open shaders.ron"); - let shaders: Vec = de::from_reader(file).expect("Unable to deserialize shaders.ron"); - - for shader in shaders { - let mut feature_variants: Vec = Vec::new(); - - // Building up possible permutations of features - for feature_set in shader.feature_sets { - if feature_variants.is_empty() { - feature_variants = feature_set.split(',').map(|s| s.to_owned()).collect(); - feature_variants.retain(|f| !EXCLUDED_FEATURES.contains(&f.as_str())); - } else { - let prev_variants: Vec = feature_variants.drain(..).collect(); - for variant in prev_variants.iter() { - for feature in feature_set.split(',') { - if !EXCLUDED_FEATURES.contains(&feature) { - feature_variants.push(format!("{},{}", variant, feature)); - } - } - } + for shader in SHADERS { + for config in shader.features { + let mut features = String::new(); + features.push_str(SHADER_PREFIX); + + for feature in config.split(",") { + features.push_str(&format!("#define WR_FEATURE_{}\n", feature)); } - } - for variant in feature_variants { - let features = variant.split(",").collect::>(); let (vs, fs) = - webrender::load_shader_sources(VERSION_STRING, - &features, - &shader.name, - &None); - - validate(&vs_validator, &shader.name, &features, vs); - validate(&fs_validator, &shader.name, &features, fs); + webrender::build_shader_strings(VERSION_STRING, &features, shader.name, &None); + validate(&vs_validator, shader.name, vs); + validate(&fs_validator, shader.name, fs); } } } -fn validate(validator: &ShaderValidator, name: &str, features: &[&str], source: String) { +fn validate(validator: &ShaderValidator, name: &str, source: String) { // Check for each `switch` to have a `default`, see // https://github.com/servo/webrender/wiki/Driver-issues#lack-of-default-case-in-a-switch assert_eq!(source.matches("switch").count(), source.matches("default:").count(), @@ -89,13 +137,12 @@ fn validate(validator: &ShaderValidator, name: &str, features: &[&str], source: // Run Angle validator match validator.compile_and_translate(&[&source]) { Ok(_) => { - println!("Shader translated succesfully: {}, features: {:?}", name, features); + println!("Shader translated succesfully: {}", name); } Err(_) => { panic!( - "Shader compilation failed: {}, features: {:?}\n{}", + "Shader compilation failed: {}\n{}", name, - features, validator.info_log() ); }