tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

shader_features.rs (9283B)


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