Skip to main content

webrender_build/
shader_features.rs

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
5use 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/// Builder for a list of features.
26#[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
63/// Computes available shaders and their features for the given feature flags.
64pub 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
70    // Cache shaders
71    shaders.insert("cs_blur", vec!["ALPHA_TARGET".to_string(), "COLOR_TARGET".to_string()]);
72
73    shaders.insert("ps_quad_mask", vec![String::new(), "FAST_PATH".to_string()]);
74
75    for name in &[
76        "cs_line_decoration",
77        "cs_border_segment",
78        "cs_border_solid",
79        "cs_svg_filter_node",
80    ] {
81        shaders.insert(name, vec![String::new()]);
82    }
83
84    let mut base_prim_features = FeatureList::new();
85
86    // Brush shaders
87    let mut brush_alpha_features = base_prim_features.with("ALPHA_PASS");
88    for name in &["brush_solid", "brush_blend", "brush_mix_blend"] {
89        let features: Vec<String> = vec![
90            base_prim_features.finish(),
91            brush_alpha_features.finish(),
92            "DEBUG_OVERDRAW".to_string(),
93        ];
94        shaders.insert(name, features);
95    }
96
97
98    {
99        let features: Vec<String> = vec![
100            base_prim_features.finish(),
101            brush_alpha_features.finish(),
102            base_prim_features.with("ANTIALIASING").finish(),
103            brush_alpha_features.with("ANTIALIASING").finish(),
104            "ANTIALIASING,DEBUG_OVERDRAW".to_string(),
105            "DEBUG_OVERDRAW".to_string(),
106        ];
107        shaders.insert("brush_opacity", features);
108    }
109
110    // Image brush shaders
111    let mut texture_types = vec!["TEXTURE_2D"];
112    if flags.contains(ShaderFeatureFlags::GL) {
113        texture_types.push("TEXTURE_RECT");
114    }
115    if flags.contains(ShaderFeatureFlags::TEXTURE_EXTERNAL) {
116        texture_types.push("TEXTURE_EXTERNAL");
117    }
118    if flags.contains(ShaderFeatureFlags::TEXTURE_EXTERNAL_BT709) {
119        texture_types.push("TEXTURE_EXTERNAL_BT709");
120    }
121    let mut image_features: Vec<String> = Vec::new();
122    for texture_type in &texture_types {
123        let mut fast = FeatureList::new();
124        if !texture_type.is_empty() {
125            fast.add(texture_type);
126        }
127        image_features.push(fast.concat(&base_prim_features).finish());
128        image_features.push(fast.concat(&brush_alpha_features).finish());
129        image_features.push(fast.with("DEBUG_OVERDRAW").finish());
130        let mut slow = fast.clone();
131        slow.add("REPETITION");
132        slow.add("ANTIALIASING");
133        image_features.push(slow.concat(&base_prim_features).finish());
134        image_features.push(slow.concat(&brush_alpha_features).finish());
135        image_features.push(slow.with("DEBUG_OVERDRAW").finish());
136        if flags.contains(ShaderFeatureFlags::ADVANCED_BLEND_EQUATION) {
137            let advanced_blend_features = brush_alpha_features.with("ADVANCED_BLEND");
138            image_features.push(fast.concat(&advanced_blend_features).finish());
139            image_features.push(slow.concat(&advanced_blend_features).finish());
140        }
141        if flags.contains(ShaderFeatureFlags::DUAL_SOURCE_BLENDING) {
142            let dual_source_features = brush_alpha_features.with("DUAL_SOURCE_BLENDING");
143            image_features.push(fast.concat(&dual_source_features).finish());
144            image_features.push(slow.concat(&dual_source_features).finish());
145        }
146    }
147    shaders.insert("brush_image", image_features);
148
149    let mut composite_texture_types = texture_types.clone();
150    if flags.contains(ShaderFeatureFlags::TEXTURE_EXTERNAL_ESSL1) {
151        composite_texture_types.push("TEXTURE_EXTERNAL_ESSL1");
152    }
153    let mut composite_features: Vec<String> = Vec::new();
154    for texture_type in &composite_texture_types {
155        let base = texture_type.to_string();
156        composite_features.push(base);
157    }
158    shaders.insert("cs_scale", composite_features.clone());
159
160    // YUV image brush and composite shaders
161    let mut yuv_features: Vec<String> = Vec::new();
162    for texture_type in &texture_types {
163        let mut list = FeatureList::new();
164        if !texture_type.is_empty() {
165            list.add(texture_type);
166        }
167        list.add("YUV");
168        composite_features.push(list.finish());
169        yuv_features.push(list.concat(&base_prim_features).finish());
170        yuv_features.push(list.concat(&brush_alpha_features).finish());
171        yuv_features.push(list.with("DEBUG_OVERDRAW").finish());
172    }
173    shaders.insert("brush_yuv_image", yuv_features);
174
175    // Fast path composite shaders
176    for texture_type in &composite_texture_types {
177        let mut list = FeatureList::new();
178        if !texture_type.is_empty() {
179            list.add(texture_type);
180        }
181        list.add("FAST_PATH");
182        composite_features.push(list.finish());
183
184        // YUV shaders are not compatible with ESSL1
185        if *texture_type == "TEXTURE_EXTERNAL_ESSL1" {
186            continue;
187        }
188
189        list.add("YUV");
190        composite_features.push(list.finish());
191    }
192    shaders.insert("composite", composite_features);
193
194    // Prim shaders
195    let mut text_types = vec![""];
196    if flags.contains(ShaderFeatureFlags::DUAL_SOURCE_BLENDING) {
197        text_types.push("DUAL_SOURCE_BLENDING");
198    }
199    let mut text_features: Vec<String> = Vec::new();
200    for text_type in &text_types {
201        let mut list = base_prim_features.with("TEXTURE_2D");
202        if !text_type.is_empty() {
203            list.add(text_type);
204        }
205        let mut alpha_list = list.with("ALPHA_PASS");
206        text_features.push(alpha_list.finish());
207        text_features.push(alpha_list.with("GLYPH_TRANSFORM").finish());
208        text_features.push(list.with("DEBUG_OVERDRAW").finish());
209    }
210    shaders.insert("ps_text_run", text_features);
211
212    shaders.insert("ps_split_composite", vec![base_prim_features.finish()]);
213
214    // ps_quad_textured needs per-texture-kind variants so that external image
215    // sources (e.g. ANGLE DXGI textures) are sampled with the correct sampler
216    // type.
217    let mut ps_quad_textured_features: Vec<String> = vec!["TEXTURE_2D".to_string()];
218    if flags.contains(ShaderFeatureFlags::GL) {
219        ps_quad_textured_features.push("TEXTURE_RECT".to_string());
220    }
221    if flags.contains(ShaderFeatureFlags::TEXTURE_EXTERNAL) {
222        ps_quad_textured_features.push("TEXTURE_EXTERNAL".to_string());
223    }
224    if flags.contains(ShaderFeatureFlags::TEXTURE_EXTERNAL_BT709) {
225        ps_quad_textured_features.push("TEXTURE_EXTERNAL_BT709".to_string());
226    }
227    shaders.insert("ps_quad_textured", ps_quad_textured_features);
228
229    shaders.insert("ps_quad_repeat", vec![base_prim_features.finish()]);
230
231    shaders.insert("ps_quad_box_shadow", vec![base_prim_features.finish()]);
232
233    let mut maybe_dithering = FeatureList::new();
234    if flags.contains(ShaderFeatureFlags::DITHERING) {
235        maybe_dithering.add("DITHERING");
236    }
237
238    shaders.insert("ps_quad_gradient", vec![base_prim_features.concat(&maybe_dithering).finish()]);
239
240    shaders.insert("ps_clear", vec![base_prim_features.finish()]);
241
242    shaders.insert("ps_copy", vec![base_prim_features.finish()]);
243
244    if flags.contains(ShaderFeatureFlags::DEBUG) {
245        for name in &["debug_color", "debug_font"] {
246            shaders.insert(name, vec![String::new()]);
247        }
248    }
249
250    shaders
251}