shader_features.rs (9283B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 use std::collections::HashMap; 6 7 bitflags! { 8 #[derive(Default, Debug, Copy, PartialEq, Eq, Clone, PartialOrd, Ord, Hash)] 9 pub struct ShaderFeatureFlags: u32 { 10 const GL = 1 << 0; 11 const GLES = 1 << 1; 12 13 const ADVANCED_BLEND_EQUATION = 1 << 8; 14 const DUAL_SOURCE_BLENDING = 1 << 9; 15 const DITHERING = 1 << 10; 16 const TEXTURE_EXTERNAL = 1 << 11; 17 const TEXTURE_EXTERNAL_ESSL1 = 1 << 12; 18 const TEXTURE_EXTERNAL_BT709 = 1 << 13; 19 const DEBUG = 1 << 14; 20 } 21 } 22 23 pub type ShaderFeatures = HashMap<&'static str, Vec<String>>; 24 25 /// Builder for a list of features. 26 #[derive(Clone)] 27 struct FeatureList<'a> { 28 list: Vec<&'a str>, 29 } 30 31 impl<'a> FeatureList<'a> { 32 fn new() -> Self { 33 FeatureList { 34 list: Vec::new(), 35 } 36 } 37 38 fn add(&mut self, feature: &'a str) { 39 assert!(!feature.contains(',')); 40 self.list.push(feature); 41 } 42 43 fn with(&self, feature: &'a str) -> Self { 44 let mut other = self.clone(); 45 other.add(feature); 46 other 47 } 48 49 fn concat(&self, other: &Self) -> Self { 50 let mut list = self.list.clone(); 51 list.extend_from_slice(&other.list); 52 FeatureList { 53 list 54 } 55 } 56 57 fn finish(&mut self) -> String { 58 self.list.sort_unstable(); 59 self.list.join(",") 60 } 61 } 62 63 /// Computes available shaders and their features for the given feature flags. 64 pub fn get_shader_features(flags: ShaderFeatureFlags) -> ShaderFeatures { 65 let mut shaders = ShaderFeatures::new(); 66 67 // Clip shaders 68 shaders.insert("cs_clip_rectangle", vec![String::new(), "FAST_PATH".to_string()]); 69 shaders.insert("cs_clip_box_shadow", vec!["TEXTURE_2D".to_string()]); 70 71 // Cache shaders 72 shaders.insert("cs_blur", vec!["ALPHA_TARGET".to_string(), "COLOR_TARGET".to_string()]); 73 74 shaders.insert("ps_quad_mask", vec![String::new(), "FAST_PATH".to_string()]); 75 76 for name in &[ 77 "cs_line_decoration", 78 "cs_fast_linear_gradient", 79 "cs_border_segment", 80 "cs_border_solid", 81 "cs_svg_filter_node", 82 ] { 83 shaders.insert(name, vec![String::new()]); 84 } 85 86 for name in &[ 87 "cs_linear_gradient", 88 "cs_radial_gradient", 89 "cs_conic_gradient", 90 ] { 91 let mut features = Vec::new(); 92 features.push(String::new()); 93 if flags.contains(ShaderFeatureFlags::DITHERING) { 94 features.push("DITHERING".to_string()); 95 } 96 shaders.insert(name, features); 97 } 98 99 let mut base_prim_features = FeatureList::new(); 100 101 // Brush shaders 102 let mut brush_alpha_features = base_prim_features.with("ALPHA_PASS"); 103 for name in &["brush_solid", "brush_blend", "brush_mix_blend"] { 104 let features: Vec<String> = vec![ 105 base_prim_features.finish(), 106 brush_alpha_features.finish(), 107 "DEBUG_OVERDRAW".to_string(), 108 ]; 109 shaders.insert(name, features); 110 } 111 112 #[allow(clippy::single_element_loop)] 113 for name in &["brush_linear_gradient"] { 114 let mut list = FeatureList::new(); 115 if flags.contains(ShaderFeatureFlags::DITHERING) { 116 list.add("DITHERING"); 117 } 118 let features: Vec<String> = vec![ 119 list.concat(&base_prim_features).finish(), 120 list.concat(&brush_alpha_features).finish(), 121 list.with("DEBUG_OVERDRAW").finish(), 122 ]; 123 shaders.insert(name, features); 124 } 125 126 { 127 let features: Vec<String> = vec![ 128 base_prim_features.finish(), 129 brush_alpha_features.finish(), 130 base_prim_features.with("ANTIALIASING").finish(), 131 brush_alpha_features.with("ANTIALIASING").finish(), 132 "ANTIALIASING,DEBUG_OVERDRAW".to_string(), 133 "DEBUG_OVERDRAW".to_string(), 134 ]; 135 shaders.insert("brush_opacity", features); 136 } 137 138 // Image brush shaders 139 let mut texture_types = vec!["TEXTURE_2D"]; 140 if flags.contains(ShaderFeatureFlags::GL) { 141 texture_types.push("TEXTURE_RECT"); 142 } 143 if flags.contains(ShaderFeatureFlags::TEXTURE_EXTERNAL) { 144 texture_types.push("TEXTURE_EXTERNAL"); 145 } 146 if flags.contains(ShaderFeatureFlags::TEXTURE_EXTERNAL_BT709) { 147 texture_types.push("TEXTURE_EXTERNAL_BT709"); 148 } 149 let mut image_features: Vec<String> = Vec::new(); 150 for texture_type in &texture_types { 151 let mut fast = FeatureList::new(); 152 if !texture_type.is_empty() { 153 fast.add(texture_type); 154 } 155 image_features.push(fast.concat(&base_prim_features).finish()); 156 image_features.push(fast.concat(&brush_alpha_features).finish()); 157 image_features.push(fast.with("DEBUG_OVERDRAW").finish()); 158 let mut slow = fast.clone(); 159 slow.add("REPETITION"); 160 slow.add("ANTIALIASING"); 161 image_features.push(slow.concat(&base_prim_features).finish()); 162 image_features.push(slow.concat(&brush_alpha_features).finish()); 163 image_features.push(slow.with("DEBUG_OVERDRAW").finish()); 164 if flags.contains(ShaderFeatureFlags::ADVANCED_BLEND_EQUATION) { 165 let advanced_blend_features = brush_alpha_features.with("ADVANCED_BLEND"); 166 image_features.push(fast.concat(&advanced_blend_features).finish()); 167 image_features.push(slow.concat(&advanced_blend_features).finish()); 168 } 169 if flags.contains(ShaderFeatureFlags::DUAL_SOURCE_BLENDING) { 170 let dual_source_features = brush_alpha_features.with("DUAL_SOURCE_BLENDING"); 171 image_features.push(fast.concat(&dual_source_features).finish()); 172 image_features.push(slow.concat(&dual_source_features).finish()); 173 } 174 } 175 shaders.insert("brush_image", image_features); 176 177 let mut composite_texture_types = texture_types.clone(); 178 if flags.contains(ShaderFeatureFlags::TEXTURE_EXTERNAL_ESSL1) { 179 composite_texture_types.push("TEXTURE_EXTERNAL_ESSL1"); 180 } 181 let mut composite_features: Vec<String> = Vec::new(); 182 for texture_type in &composite_texture_types { 183 let base = texture_type.to_string(); 184 composite_features.push(base); 185 } 186 shaders.insert("cs_scale", composite_features.clone()); 187 188 // YUV image brush and composite shaders 189 let mut yuv_features: Vec<String> = Vec::new(); 190 for texture_type in &texture_types { 191 let mut list = FeatureList::new(); 192 if !texture_type.is_empty() { 193 list.add(texture_type); 194 } 195 list.add("YUV"); 196 composite_features.push(list.finish()); 197 yuv_features.push(list.concat(&base_prim_features).finish()); 198 yuv_features.push(list.concat(&brush_alpha_features).finish()); 199 yuv_features.push(list.with("DEBUG_OVERDRAW").finish()); 200 } 201 shaders.insert("brush_yuv_image", yuv_features); 202 203 // Fast path composite shaders 204 for texture_type in &composite_texture_types { 205 let mut list = FeatureList::new(); 206 if !texture_type.is_empty() { 207 list.add(texture_type); 208 } 209 list.add("FAST_PATH"); 210 composite_features.push(list.finish()); 211 212 // YUV shaders are not compatible with ESSL1 213 if *texture_type == "TEXTURE_EXTERNAL_ESSL1" { 214 continue; 215 } 216 217 list.add("YUV"); 218 composite_features.push(list.finish()); 219 } 220 shaders.insert("composite", composite_features); 221 222 // Prim shaders 223 let mut text_types = vec![""]; 224 if flags.contains(ShaderFeatureFlags::DUAL_SOURCE_BLENDING) { 225 text_types.push("DUAL_SOURCE_BLENDING"); 226 } 227 let mut text_features: Vec<String> = Vec::new(); 228 for text_type in &text_types { 229 let mut list = base_prim_features.with("TEXTURE_2D"); 230 if !text_type.is_empty() { 231 list.add(text_type); 232 } 233 let mut alpha_list = list.with("ALPHA_PASS"); 234 text_features.push(alpha_list.finish()); 235 text_features.push(alpha_list.with("GLYPH_TRANSFORM").finish()); 236 text_features.push(list.with("DEBUG_OVERDRAW").finish()); 237 } 238 shaders.insert("ps_text_run", text_features); 239 240 shaders.insert("ps_split_composite", vec![base_prim_features.finish()]); 241 242 shaders.insert("ps_quad_textured", vec![base_prim_features.finish()]); 243 244 let mut maybe_dithering = FeatureList::new(); 245 if flags.contains(ShaderFeatureFlags::DITHERING) { 246 maybe_dithering.add("DITHERING"); 247 } 248 249 shaders.insert("ps_quad_gradient", vec![base_prim_features.concat(&maybe_dithering).finish()]); 250 251 shaders.insert("ps_quad_radial_gradient", vec![base_prim_features.concat(&maybe_dithering).finish()]); 252 253 shaders.insert("ps_quad_conic_gradient", vec![base_prim_features.concat(&maybe_dithering).finish()]); 254 255 shaders.insert("ps_clear", vec![base_prim_features.finish()]); 256 257 shaders.insert("ps_copy", vec![base_prim_features.finish()]); 258 259 if flags.contains(ShaderFeatureFlags::DEBUG) { 260 for name in &["debug_color", "debug_font"] { 261 shaders.insert(name, vec![String::new()]); 262 } 263 } 264 265 shaders 266 }