webrender_build/
shader_features.rs1use std::collections::HashMap;
6
7bitflags! {
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
23pub type ShaderFeatures = HashMap<&'static str, Vec<String>>;
24
25#[derive(Clone)]
27struct FeatureList<'a> {
28 list: Vec<&'a str>,
29}
30
31impl<'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
63pub fn get_shader_features(flags: ShaderFeatureFlags) -> ShaderFeatures {
65 let mut shaders = ShaderFeatures::new();
66
67 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 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",
82 "cs_svg_filter_node",
83 ] {
84 shaders.insert(name, vec![String::new()]);
85 }
86
87 for name in &[
88 "cs_linear_gradient",
89 "cs_radial_gradient",
90 "cs_conic_gradient",
91 ] {
92 let mut features = Vec::new();
93 features.push(String::new());
94 if flags.contains(ShaderFeatureFlags::DITHERING) {
95 features.push("DITHERING".to_string());
96 }
97 shaders.insert(name, features);
98 }
99
100 let mut base_prim_features = FeatureList::new();
101
102 let mut brush_alpha_features = base_prim_features.with("ALPHA_PASS");
104 for name in &["brush_solid", "brush_blend", "brush_mix_blend"] {
105 let features: Vec<String> = vec![
106 base_prim_features.finish(),
107 brush_alpha_features.finish(),
108 "DEBUG_OVERDRAW".to_string(),
109 ];
110 shaders.insert(name, features);
111 }
112
113 #[allow(clippy::single_element_loop)]
114 for name in &["brush_linear_gradient"] {
115 let mut list = FeatureList::new();
116 if flags.contains(ShaderFeatureFlags::DITHERING) {
117 list.add("DITHERING");
118 }
119 let features: Vec<String> = vec![
120 list.concat(&base_prim_features).finish(),
121 list.concat(&brush_alpha_features).finish(),
122 list.with("DEBUG_OVERDRAW").finish(),
123 ];
124 shaders.insert(name, features);
125 }
126
127 {
128 let features: Vec<String> = vec![
129 base_prim_features.finish(),
130 brush_alpha_features.finish(),
131 base_prim_features.with("ANTIALIASING").finish(),
132 brush_alpha_features.with("ANTIALIASING").finish(),
133 "ANTIALIASING,DEBUG_OVERDRAW".to_string(),
134 "DEBUG_OVERDRAW".to_string(),
135 ];
136 shaders.insert("brush_opacity", features);
137 }
138
139 let mut texture_types = vec!["TEXTURE_2D"];
141 if flags.contains(ShaderFeatureFlags::GL) {
142 texture_types.push("TEXTURE_RECT");
143 }
144 if flags.contains(ShaderFeatureFlags::TEXTURE_EXTERNAL) {
145 texture_types.push("TEXTURE_EXTERNAL");
146 }
147 if flags.contains(ShaderFeatureFlags::TEXTURE_EXTERNAL_BT709) {
148 texture_types.push("TEXTURE_EXTERNAL_BT709");
149 }
150 let mut image_features: Vec<String> = Vec::new();
151 for texture_type in &texture_types {
152 let mut fast = FeatureList::new();
153 if !texture_type.is_empty() {
154 fast.add(texture_type);
155 }
156 image_features.push(fast.concat(&base_prim_features).finish());
157 image_features.push(fast.concat(&brush_alpha_features).finish());
158 image_features.push(fast.with("DEBUG_OVERDRAW").finish());
159 let mut slow = fast.clone();
160 slow.add("REPETITION");
161 slow.add("ANTIALIASING");
162 image_features.push(slow.concat(&base_prim_features).finish());
163 image_features.push(slow.concat(&brush_alpha_features).finish());
164 image_features.push(slow.with("DEBUG_OVERDRAW").finish());
165 if flags.contains(ShaderFeatureFlags::ADVANCED_BLEND_EQUATION) {
166 let advanced_blend_features = brush_alpha_features.with("ADVANCED_BLEND");
167 image_features.push(fast.concat(&advanced_blend_features).finish());
168 image_features.push(slow.concat(&advanced_blend_features).finish());
169 }
170 if flags.contains(ShaderFeatureFlags::DUAL_SOURCE_BLENDING) {
171 let dual_source_features = brush_alpha_features.with("DUAL_SOURCE_BLENDING");
172 image_features.push(fast.concat(&dual_source_features).finish());
173 image_features.push(slow.concat(&dual_source_features).finish());
174 }
175 }
176 shaders.insert("brush_image", image_features);
177
178 let mut composite_texture_types = texture_types.clone();
179 if flags.contains(ShaderFeatureFlags::TEXTURE_EXTERNAL_ESSL1) {
180 composite_texture_types.push("TEXTURE_EXTERNAL_ESSL1");
181 }
182 let mut composite_features: Vec<String> = Vec::new();
183 for texture_type in &composite_texture_types {
184 let base = texture_type.to_string();
185 composite_features.push(base);
186 }
187 shaders.insert("cs_scale", composite_features.clone());
188
189 let mut yuv_features: Vec<String> = Vec::new();
191 for texture_type in &texture_types {
192 let mut list = FeatureList::new();
193 if !texture_type.is_empty() {
194 list.add(texture_type);
195 }
196 list.add("YUV");
197 composite_features.push(list.finish());
198 yuv_features.push(list.concat(&base_prim_features).finish());
199 yuv_features.push(list.concat(&brush_alpha_features).finish());
200 yuv_features.push(list.with("DEBUG_OVERDRAW").finish());
201 }
202 shaders.insert("brush_yuv_image", yuv_features);
203
204 for texture_type in &composite_texture_types {
206 let mut list = FeatureList::new();
207 if !texture_type.is_empty() {
208 list.add(texture_type);
209 }
210 list.add("FAST_PATH");
211 composite_features.push(list.finish());
212
213 if *texture_type == "TEXTURE_EXTERNAL_ESSL1" {
215 continue;
216 }
217
218 list.add("YUV");
219 composite_features.push(list.finish());
220 }
221 shaders.insert("composite", composite_features);
222
223 let mut text_types = vec![""];
225 if flags.contains(ShaderFeatureFlags::DUAL_SOURCE_BLENDING) {
226 text_types.push("DUAL_SOURCE_BLENDING");
227 }
228 let mut text_features: Vec<String> = Vec::new();
229 for text_type in &text_types {
230 let mut list = base_prim_features.with("TEXTURE_2D");
231 if !text_type.is_empty() {
232 list.add(text_type);
233 }
234 let mut alpha_list = list.with("ALPHA_PASS");
235 text_features.push(alpha_list.finish());
236 text_features.push(alpha_list.with("GLYPH_TRANSFORM").finish());
237 text_features.push(list.with("DEBUG_OVERDRAW").finish());
238 }
239 shaders.insert("ps_text_run", text_features);
240
241 shaders.insert("ps_split_composite", vec![base_prim_features.finish()]);
242
243 shaders.insert("ps_quad_textured", vec![base_prim_features.finish()]);
244
245 shaders.insert("ps_quad_radial_gradient", vec![base_prim_features.finish()]);
246
247 shaders.insert("ps_quad_conic_gradient", vec![base_prim_features.finish()]);
248
249 shaders.insert("ps_clear", vec![base_prim_features.finish()]);
250
251 shaders.insert("ps_copy", vec![base_prim_features.finish()]);
252
253 if flags.contains(ShaderFeatureFlags::DEBUG) {
254 for name in &["debug_color", "debug_font"] {
255 shaders.insert(name, vec![String::new()]);
256 }
257 }
258
259 shaders
260}
261