azul_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)]
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
22pub type ShaderFeatures = HashMap<&'static str, Vec<String>>;
23
24/// Builder for a list of features.
25#[derive(Clone)]
26struct FeatureList<'a> {
27    list: Vec<&'a str>,
28}
29
30impl<'a> FeatureList<'a> {
31    fn new() -> Self {
32        FeatureList {
33            list: Vec::new(),
34        }
35    }
36
37    fn add(&mut self, feature: &'a str) {
38        assert!(!feature.contains(','));
39        self.list.push(feature);
40    }
41
42    fn with(&self, feature: &'a str) -> Self {
43        let mut other = self.clone();
44        other.add(feature);
45        other
46    }
47
48    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
56    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.
63pub 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    if flags.contains(ShaderFeatureFlags::DEBUG) {
227        for name in &["debug_color", "debug_font"] {
228            shaders.insert(name, vec![String::new()]);
229        }
230    }
231
232    shaders
233}
234