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