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)]
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 DEBUG = 1 << 13;
19     }
20 }
21 
22 pub type ShaderFeatures = HashMap<&'static str, Vec<String>>;
23 
24 /// Builder for a list of features.
25 #[derive(Clone)]
26 struct FeatureList<'a> {
27     list: Vec<&'a str>,
28 }
29 
30 impl<'a> FeatureList<'a> {
new() -> Self31     fn new() -> Self {
32         FeatureList {
33             list: Vec::new(),
34         }
35     }
36 
add(&mut self, feature: &'a str)37     fn add(&mut self, feature: &'a str) {
38         assert!(!feature.contains(','));
39         self.list.push(feature);
40     }
41 
with(&self, feature: &'a str) -> Self42     fn with(&self, feature: &'a str) -> Self {
43         let mut other = self.clone();
44         other.add(feature);
45         other
46     }
47 
concat(&self, other: &Self) -> Self48     fn concat(&self, other: &Self) -> Self {
49         let mut list = self.list.clone();
50         list.extend_from_slice(&other.list);
51         FeatureList {
52             list
53         }
54     }
55 
finish(&mut self) -> String56     fn finish(&mut self) -> String {
57         self.list.sort_unstable();
58         self.list.join(",")
59     }
60 }
61 
62 /// Computes available shaders and their features for the given feature flags.
get_shader_features(flags: ShaderFeatureFlags) -> ShaderFeatures63 pub fn get_shader_features(flags: ShaderFeatureFlags) -> ShaderFeatures {
64     let mut shaders = ShaderFeatures::new();
65 
66     // Clip shaders
67     shaders.insert("cs_clip_rectangle", vec![String::new(), "FAST_PATH".to_string()]);
68     shaders.insert("cs_clip_image", vec!["TEXTURE_2D".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     for name in &[
75         "cs_line_decoration",
76         "cs_fast_linear_gradient",
77         "cs_border_segment",
78         "cs_border_solid",
79         "cs_svg_filter",
80     ] {
81         shaders.insert(name, vec![String::new()]);
82     }
83 
84     for name in &[
85         "cs_linear_gradient",
86         "cs_radial_gradient",
87         "cs_conic_gradient",
88     ] {
89         let mut features = Vec::new();
90         features.push(String::new());
91         if flags.contains(ShaderFeatureFlags::DITHERING) {
92             features.push("DITHERING".to_string());
93         }
94         shaders.insert(name, features);
95     }
96 
97     let mut base_prim_features = FeatureList::new();
98 
99     // Brush shaders
100     let mut brush_alpha_features = base_prim_features.with("ALPHA_PASS");
101     for name in &["brush_solid", "brush_blend", "brush_mix_blend"] {
102         let mut features: Vec<String> = Vec::new();
103         features.push(base_prim_features.finish());
104         features.push(brush_alpha_features.finish());
105         features.push("DEBUG_OVERDRAW".to_string());
106         shaders.insert(name, features);
107     }
108     for name in &["brush_linear_gradient"] {
109         let mut features: Vec<String> = Vec::new();
110         let mut list = FeatureList::new();
111         if flags.contains(ShaderFeatureFlags::DITHERING) {
112             list.add("DITHERING");
113         }
114         features.push(list.concat(&base_prim_features).finish());
115         features.push(list.concat(&brush_alpha_features).finish());
116         features.push(list.with("DEBUG_OVERDRAW").finish());
117         shaders.insert(name, features);
118     }
119 
120     {
121         let mut features: Vec<String> = Vec::new();
122         features.push(base_prim_features.finish());
123         features.push(brush_alpha_features.finish());
124         features.push(base_prim_features.with("ANTIALIASING").finish());
125         features.push(brush_alpha_features.with("ANTIALIASING").finish());
126         features.push("ANTIALIASING,DEBUG_OVERDRAW".to_string());
127         features.push("DEBUG_OVERDRAW".to_string());
128         shaders.insert("brush_opacity", features);
129     }
130 
131     // Image brush shaders
132     let mut texture_types = vec!["TEXTURE_2D"];
133     if flags.contains(ShaderFeatureFlags::GL) {
134         texture_types.push("TEXTURE_RECT");
135     }
136     if flags.contains(ShaderFeatureFlags::TEXTURE_EXTERNAL) {
137         texture_types.push("TEXTURE_EXTERNAL");
138     }
139     let mut image_features: Vec<String> = Vec::new();
140     for texture_type in &texture_types {
141         let mut fast = FeatureList::new();
142         if !texture_type.is_empty() {
143             fast.add(texture_type);
144         }
145         image_features.push(fast.concat(&base_prim_features).finish());
146         image_features.push(fast.concat(&brush_alpha_features).finish());
147         image_features.push(fast.with("DEBUG_OVERDRAW").finish());
148         let mut slow = fast.clone();
149         slow.add("REPETITION");
150         slow.add("ANTIALIASING");
151         image_features.push(slow.concat(&base_prim_features).finish());
152         image_features.push(slow.concat(&brush_alpha_features).finish());
153         image_features.push(slow.with("DEBUG_OVERDRAW").finish());
154         if flags.contains(ShaderFeatureFlags::ADVANCED_BLEND_EQUATION) {
155             let advanced_blend_features = brush_alpha_features.with("ADVANCED_BLEND");
156             image_features.push(fast.concat(&advanced_blend_features).finish());
157             image_features.push(slow.concat(&advanced_blend_features).finish());
158         }
159         if flags.contains(ShaderFeatureFlags::DUAL_SOURCE_BLENDING) {
160             let dual_source_features = brush_alpha_features.with("DUAL_SOURCE_BLENDING");
161             image_features.push(fast.concat(&dual_source_features).finish());
162             image_features.push(slow.concat(&dual_source_features).finish());
163         }
164     }
165     shaders.insert("brush_image", image_features);
166 
167     let mut composite_texture_types = texture_types.clone();
168     if flags.contains(ShaderFeatureFlags::TEXTURE_EXTERNAL_ESSL1) {
169         composite_texture_types.push("TEXTURE_EXTERNAL_ESSL1");
170     }
171     let mut composite_features: Vec<String> = Vec::new();
172     for texture_type in &composite_texture_types {
173         let base = texture_type.to_string();
174         composite_features.push(base);
175     }
176     shaders.insert("cs_scale", composite_features.clone());
177 
178     // YUV image brush and composite shaders
179     let mut yuv_features: Vec<String> = Vec::new();
180     for texture_type in &texture_types {
181         let mut list = FeatureList::new();
182         if !texture_type.is_empty() {
183             list.add(texture_type);
184         }
185         list.add("YUV");
186         composite_features.push(list.finish());
187         yuv_features.push(list.concat(&base_prim_features).finish());
188         yuv_features.push(list.concat(&brush_alpha_features).finish());
189         yuv_features.push(list.with("DEBUG_OVERDRAW").finish());
190     }
191     shaders.insert("brush_yuv_image", yuv_features);
192 
193     // Fast path composite shaders
194     for texture_type in &composite_texture_types {
195         let mut list = FeatureList::new();
196         if !texture_type.is_empty() {
197             list.add(texture_type);
198         }
199         list.add("FAST_PATH");
200         composite_features.push(list.finish());
201     }
202     shaders.insert("composite", composite_features);
203 
204     // Prim shaders
205     let mut text_types = vec![""];
206     if flags.contains(ShaderFeatureFlags::DUAL_SOURCE_BLENDING) {
207         text_types.push("DUAL_SOURCE_BLENDING");
208     }
209     let mut text_features: Vec<String> = Vec::new();
210     for text_type in &text_types {
211         let mut list = base_prim_features.with("TEXTURE_2D");
212         if !text_type.is_empty() {
213             list.add(text_type);
214         }
215         let mut alpha_list = list.with("ALPHA_PASS");
216         text_features.push(alpha_list.finish());
217         text_features.push(alpha_list.with("GLYPH_TRANSFORM").finish());
218         text_features.push(list.with("DEBUG_OVERDRAW").finish());
219     }
220     shaders.insert("ps_text_run", text_features);
221 
222     shaders.insert("ps_split_composite", vec![base_prim_features.finish()]);
223 
224     shaders.insert("ps_clear", vec![base_prim_features.finish()]);
225 
226     shaders.insert("ps_copy", vec![base_prim_features.finish()]);
227 
228     if flags.contains(ShaderFeatureFlags::DEBUG) {
229         for name in &["debug_color", "debug_font"] {
230             shaders.insert(name, vec![String::new()]);
231         }
232     }
233 
234     shaders
235 }
236 
237